Greasy Fork

[MWI] Ultimate Enhancement Tracker v3.4.0

Now with XP and XP/hr tracking

目前为 2025-04-08 提交的版本。查看 最新版本

// ==UserScript==
// @name         [MWI] Ultimate Enhancement Tracker v3.4.0
// @namespace    http://tampermonkey.net/
// @version      3.4.8
// @description  Now with XP and XP/hr tracking
// @author       Truth_Light (modified by Nex, styled by Cosmic, cost tracking by Assistant)
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @license      MIT
// @grant        GM_registerMenuCommand
// @icon         https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com
// ==/UserScript==

/*
    Market price fetching relies on having MWI Tools installed, get it here:
    https://greasyfork.org/en/scripts/494467-mwitools

    获取市场价格取决于是否安装了 MWI 工具,在此获取:
    https://greasyfork.cc/zh-CN/scripts/494467-mwitools
*/

(function() {
    'use strict';
    // ======================
    // STYLE CONFIGURATION
    // ======================
    const STYLE = {
      colors: {
        primary: '#00ffe7', // Bright neon cyan
        background: 'rgba(5, 5, 15, 0.95)', // Deep black-blue
        border: '1px solid rgba(0, 255, 234, 0.4)', // Glowing border
        textPrimary: '#e0f7ff', // Soft neon white-blue
        textSecondary: '#9b9bff', // Neon purple tint
        accent: '#ff00d4', // Vibrant pink-magenta
        danger: '#ff0055', // Electric red
        success: '#00ff99', // Neon green
        headerBg: 'rgba(15, 5, 35, 0.7)', // Dark purple gradient tint
        epic: '#c63dff', // Deep neon purple
        legendary: '#ff6f1a', // Bright orange neon
        mythic: '#ff0033', // Intense mythic red
        blessed: 'linear-gradient(135deg, #ff00d4, #c63dff, #00ffe7)', // Trippy neon gradient
        gold: '#FFD700' // Gold color for cost display
      },
      fonts: {
        primary: '14px "Orbitron", "Segoe UI", Roboto, sans-serif', // Futuristic font
        secondary: '12px "Orbitron", "Segoe UI", Roboto, sans-serif',
        header: 'bold 16px "Orbitron", "Segoe UI", Roboto, sans-serif',
        milestone: 'bold 18px "Orbitron", "Segoe UI", Roboto, sans-serif',
        cost: 'bold 13px "Orbitron", "Segoe UI", Roboto, sans-serif'
      },
      shadows: {
        panel: '0 0 20px rgba(0, 255, 234, 0.3)', // Neon glow panel
        notification: '0 0 15px rgba(255, 0, 212, 0.3)', // Pink neon soft glow
        milestone: '0 0 25px rgba(198, 61, 255, 0.4)', // Epic purple glow
        text: '0 0 6px rgba(0, 255, 234, 0.3)', // Soft text glow
        gold: '0 0 8px rgba(255, 215, 0, 0.7)' // Gold glow
      },
      borderRadius: {
        medium: '14px', // Rounded with a modern edge
        small: '8px'
      },
      transitions: {
        fast: 'all 0.15s ease-in-out',
        medium: 'all 0.3s ease-in-out',
        slow: 'all 0.5s ease-in-out'
      },
    };

    STYLE.scrollable = {
        maxHeight: '50vh',  // Maximum height before scrolling kicks in
        overflowY: 'auto',
        scrollbarWidth: 'thin',
        scrollbarColor: `${STYLE.colors.primary} transparent`
    };

    // Core Variables
    const userLanguage = localStorage.getItem('i18nextLng');
    // Load enhancementData from localStorage if available
    let enhancementData = JSON.parse(localStorage.getItem('enhancementData')) || {};
    let currentTrackingIndex = parseInt(localStorage.getItem('enhancementCurrentTrackingIndex')) || 0;
    let currentViewingIndex = parseInt(localStorage.getItem('enhancementCurrentViewingIndex')) || 0;

    // Add session validation
    function validateSession(session) {
        if (!session) return;

        // Ensure all required fields exist
        if (!session["硬币消耗"]) session["硬币消耗"] = { count: 0, totalCost: 0 };
        if (!session["总成本"]) session["总成本"] = 0;

        // Reconstruct total from components if needed
        const calculatedTotal =
            Object.values(session["材料消耗"] || {}).reduce((sum, m) => sum + (m.totalCost || 0), 0) +
            (session["硬币消耗"]?.totalCost || 0) +
            (session["其他数据"]["保护总成本"] || 0);

        if (Math.abs(calculatedTotal - session["总成本"]) > 1) {
            console.log(`Correcting total cost drift: ${session["总成本"]} → ${calculatedTotal}`);
            session["总成本"] = calculatedTotal;
        }
    }

    // Validate all sessions on load
    Object.values(enhancementData).forEach(validateSession);

    // Add data migration for existing sessions
    Object.values(enhancementData).forEach(session => {
        if (!session["硬币消耗"]) {
            session["硬币消耗"] = { count: 0, totalCost: 0 };
        }
        // Recalculate total cost if needed
        if (session["总成本"] === undefined) {
            const materialsCost = Object.values(session["材料消耗"] || {}).reduce((sum, m) => sum + m.totalCost, 0);
            const coinsCost = session["硬币消耗"]?.totalCost || 0;
            const protectionCost = session["其他数据"]["保护总成本"] || 0;
            session["总成本"] = materialsCost + coinsCost + protectionCost;
        }
    });

    cleanSessionIndices();

    // Function to save enhancementData to localStorage
    function saveEnhancementData() {
        // Ensure all sessions have the correct structure
        Object.values(enhancementData).forEach(session => {
            if (!session["硬币消耗"]) session["硬币消耗"] = { count: 0, totalCost: 0 };
        });

        localStorage.setItem('enhancementData', JSON.stringify(enhancementData));
        localStorage.setItem('enhancementCurrentTrackingIndex', currentTrackingIndex);
        localStorage.setItem('enhancementCurrentViewingIndex', currentViewingIndex);
    }

    function clearAllSessions() {
    if (confirm(isZH ? "确定要清除所有强化会话数据吗?此操作不可撤销。" : "Are you sure you want to clear all enhancement sessions? This cannot be undone.")) {
        enhancementData = {};
        currentTrackingIndex = 0;
        currentViewingIndex = 0;
        localStorage.removeItem('enhancementData');
        debouncedUpdateFloatingUI();
        showUINotification(isZH ? "已清除所有会话数据" : "All session data cleared");
    }
}

    currentViewingIndex = currentTrackingIndex; // Start viewing current session
    let item_name_to_hrid;
    let item_hrid_to_name;

    var isZH = userLanguage.startsWith("zh");
    // Add this near your language detection
    let lastLangCheck = userLanguage;
    setInterval(() => {
        const currentLang = localStorage.getItem('i18nextLng');
        if (currentLang !== lastLangCheck) {
            lastLangCheck = currentLang;
            isZH = currentLang.startsWith("zh");

            // Force refresh all displayed names
            Object.keys(enhancementData).forEach(key => {
                const session = enhancementData[key];
                if (session["其他数据"]) {
                    session["其他数据"]["物品名称"] = translateItemName(
                        session["其他数据"]["物品HRID"],
                        session["其他数据"]["物品名称"]
                    );
                }
            });

            debouncedUpdateFloatingUI();
            saveEnhancementData(); // Save after updating names
        }
    }, 1000);

    cleanSessionIndices();

    function cleanSessionIndices() {
        const sortedIndices = Object.keys(enhancementData)
            .map(Number)
            .sort((a, b) => a - b);

        if (sortedIndices.some((v, i) => v !== i + 1)) {
            const newData = {};
            sortedIndices.forEach((oldIndex, i) => {
                newData[i + 1] = enhancementData[oldIndex];
            });
            enhancementData = newData;
            currentTrackingIndex = sortedIndices.length > 0 ?
                Math.max(...Object.keys(newData).map(Number)) : 1;
            currentViewingIndex = currentTrackingIndex;
            saveEnhancementData();
        }

        // Ensure loaded indices are valid
        if (!enhancementData[currentViewingIndex]) {
            currentViewingIndex = currentTrackingIndex;
        }
        if (!enhancementData[currentTrackingIndex]) {
            currentTrackingIndex = sortedIndices.length > 0 ? Math.max(...sortedIndices) : 0;
        }
    }

    // ======================
    // MARKET DATA HANDLING
    // ======================

    let MWITools_marketAPI_json = null;
    let lastMarketUpdate = 0;
    const MARKET_REFRESH_INTERVAL = 30000; // 30 seconds

    function loadMarketData() {
        try {
            // Try to load from localStorage
            const marketDataStr = localStorage.getItem('MWITools_marketAPI_json');
            if (marketDataStr) {
                MWITools_marketAPI_json = JSON.parse(marketDataStr);
                lastMarketUpdate = MWITools_marketAPI_json?.time || 0;
                // console.log('[Market] Loaded market data from storage', lastMarketUpdate);
            }

            // Set up periodic refresh
            setInterval(refreshMarketData, MARKET_REFRESH_INTERVAL);

            // Initial refresh
            refreshMarketData();
        } catch (e) {
            console.error('[Market] Error loading market data:', e);
        }
    }

    function refreshMarketData() {
        try {
            // Check if we have the market data object in memory
            if (typeof window.MWITools_marketAPI_json !== 'undefined') {
                MWITools_marketAPI_json = window.MWITools_marketAPI_json;
                lastMarketUpdate = MWITools_marketAPI_json?.time || 0;
                localStorage.setItem('MWITools_marketAPI_json', JSON.stringify(MWITools_marketAPI_json));
                // console.log('[Market] Updated market data from memory', lastMarketUpdate);
            }
        } catch (e) {
            console.error('[Market] Error refreshing market data:', e);
        }
    }

    function getMarketPrice(itemHRID) {
        try {
            // Special case for coins - always worth 1 gold
            if (itemHRID === '/items/coin' || itemHRID === '/items/coins') {
                return 1; // Coins are tracked separately
            }

            // Validate input
            if (!itemHRID || typeof itemHRID !== 'string') {
                console.log('[Market] Invalid item HRID:', itemHRID);
                return 0;
            }

            // Refresh market data if stale
            if (Date.now() - lastMarketUpdate > MARKET_REFRESH_INTERVAL) {
                refreshMarketData();
            }

            // Check if market data is available
            if (!MWITools_marketAPI_json?.market) {
                console.log('[Market] No market data available');
                return 0;
            }

            // Try to get the display name (either from dictionary or HRID)
            let itemName = item_hrid_to_name?.[itemHRID];
            if (!itemName) {
                // Extract from HRID format: /items/aqua_essence → Aqua Essence
                const parts = itemHRID.split('/');
                const lastPart = parts[parts.length - 1] || '';
                itemName = lastPart
                    .replace(/_/g, ' ')
                    .replace(/(^|\s)\S/g, t => t.toUpperCase())
                    .trim();
            }

            // Return 0 if we still don't have a name
            if (!itemName) {
                console.log('[Market] Could not determine item name for:', itemHRID);
                return 0;
            }

            // Find market entry (case insensitive)
            const marketEntry = Object.entries(MWITools_marketAPI_json.market).find(
                ([name]) => name.toLowerCase() === itemName.toLowerCase()
            );

            if (!marketEntry) {
                console.log('[Market] No entry for:', itemName);
                return 0;
            }

            // Use ask price if available, otherwise bid price
            const price = marketEntry[1]?.ask || marketEntry[1]?.bid || 0;
            // console.log('[Market] Price for', itemName, ':', price);

            return price;
        } catch (e) {
            console.error("[Market] Error getting price for", itemHRID, ":", e);
            return 0;
        }
    }

    // ======================
    // XP GAIN TRACKING
    // ======================

    function getBaseItemLevel(itemHRID) {
      try {
          // Get initClientData from localStorage
          const initClientData = JSON.parse(localStorage.getItem('initClientData'));
          if (!initClientData?.itemDetailMap) return 0;

          // Find the item in the detail map
          const itemDetails = initClientData.itemDetailMap[itemHRID];
          if (!itemDetails) return 0;

          // Return the item level if available
          return itemDetails.itemLevel || 0;

      } catch (e) {
          console.error("Error getting base item level:", e);
          return 0;
      }
    }

      function getWisdomBuff() {
          try {
              const charData = JSON.parse(localStorage.getItem('init_character_data'));
              if (!charData) return { flatBoost: 0 };

              let totalFlatBoost = 0;

              // 1. Community Buffs
              const communityEnhancingBuffs = charData.communityActionTypeBuffsMap?.["/action_types/enhancing"];
              if (Array.isArray(communityEnhancingBuffs)) {
                  communityEnhancingBuffs.forEach(buff => {
                      if (buff.typeHrid === "/buff_types/wisdom") {
                          totalFlatBoost += buff.flatBoost || 0;
                      }
                  });
              }

              // 2. Equipment Buffs
              const equipmentEnhancingBuffs = charData.equipmentActionTypeBuffsMap?.["/action_types/enhancing"];
              if (Array.isArray(equipmentEnhancingBuffs)) {
                  equipmentEnhancingBuffs.forEach(buff => {
                      if (buff.typeHrid === "/buff_types/wisdom") {
                          totalFlatBoost += buff.flatBoost || 0;
                      }
                  });
              }

              // 3. House Buffs
              const houseEnhancingBuffs = charData.houseActionTypeBuffsMap?.["/action_types/enhancing"];
              if (Array.isArray(houseEnhancingBuffs)) {
                  houseEnhancingBuffs.forEach(buff => {
                      if (buff.typeHrid === "/buff_types/wisdom") {
                          totalFlatBoost += buff.flatBoost || 0;
                      }
                  });
              }

              // 4. Consumable Buffs (NEW - from wisdom tea etc)
              const consumableEnhancingBuffs = charData.consumableActionTypeBuffsMap?.["/action_types/enhancing"];
              if (Array.isArray(consumableEnhancingBuffs)) {
                  consumableEnhancingBuffs.forEach(buff => {
                      if (buff.typeHrid === "/buff_types/wisdom") {
                          totalFlatBoost += buff.flatBoost || 0;
                      }
                  });
              }

              return { flatBoost: totalFlatBoost }

          } catch (e) {
              console.error("Error calculating wisdom buff:", e);
              return { flatBoost: 0 };
          }
      }

      function calculateSuccessXP(previousLevel, itemHrid) {
          const baseLevel = getBaseItemLevel(itemHrid);
          const wisdomBuff = getWisdomBuff();

          // Special handling for enhancement level 0 (base items)
          const enhancementMultiplier = previousLevel === 0
              ? 1.0  // Base value for unenhanced items
              : (previousLevel + 1);  // Normal progression

          return Math.floor(
              1.4 *
              (1 + (wisdomBuff?.flatBoost || 0)) *
              enhancementMultiplier *
              (10 + baseLevel)
          );
      }

    function calculateFailureXP(previousLevel, itemHrid) {
        return Math.floor(calculateSuccessXP(previousLevel, itemHrid) * 0.1); // 10% of success XP
    }

    // ======================
    // ENHANCEMENT COST TRACKING (updated to use new market functions)
    // ======================

    function getEnhancementMaterials(itemHRID) {
        try {
            const initData = JSON.parse(localStorage.getItem('initClientData'));
            const itemData = initData.itemDetailMap?.[itemHRID];

            if (!itemData) {
                console.log('[Materials] Item not found:', itemHRID);
                return null;
            }

            // Get the costs array (try different possible property names)
            const costs = itemData.enhancementCosts || itemData.upgradeCosts ||
                         itemData.enhanceCosts || itemData.enhanceCostArray;

            if (!costs) {
                console.log('[Materials] No enhancement costs found for:', itemHRID);
                return null;
            }

            // Convert to our desired format
            let materials = [];

            // Case 1: Array of objects (current format)
            if (Array.isArray(costs) && costs.length > 0 && typeof costs[0] === 'object') {
                materials = costs.map(cost => [cost.itemHrid, cost.count]);
            }
            // Case 2: Already in correct format [["/items/foo", 30], ["/items/bar", 20]]
            else if (Array.isArray(costs) && costs.length > 0 && Array.isArray(costs[0])) {
                materials = costs;
            }
            // Case 3: Simple array ["/items/foo", 30]
            else if (Array.isArray(costs) && costs.length === 2 && typeof costs[0] === 'string') {
                materials = [costs];
            }
            // Case 4: Object format {"/items/foo": 30, "/items/bar": 20}
            else if (typeof costs === 'object' && !Array.isArray(costs)) {
                materials = Object.entries(costs);
            }

            // Filter out any invalid entries
            materials = materials.filter(m =>
                Array.isArray(m) &&
                m.length === 2 &&
                typeof m[0] === 'string' &&
                typeof m[1] === 'number'
            );

            // console.log('[Materials] Processed costs:', materials);
            return materials.length > 0 ? materials : null;
        } catch (e) {
            console.error('[Materials] Error:', e);
            return null;
        }
    }

      // Updated trackMaterialCosts():
      function trackMaterialCosts(itemHRID) {
          const session = enhancementData[currentTrackingIndex];
          const materials = getEnhancementMaterials(itemHRID) || [];
          let materialCost = 0;
          let coinCost = 0;

          materials.forEach(([hrid, count]) => {
              if (hrid.includes('/items/coin')) {
                  // Track coins for THIS ATTEMPT ONLY
                  coinCost = count; // Coins are 1:1 value (1 coin = 1 gold)
                  session["硬币消耗"].count += count;
                  session["硬币消耗"].totalCost += count;
                  return;
              }

              const cost = getMarketPrice(hrid) * count;
              materialCost += cost;

              if (!session["材料消耗"][hrid]) {
                  session["材料消耗"][hrid] = {
                      name: item_hrid_to_name[hrid] || hrid,
                      count: 0,
                      totalCost: 0
                  };
              }

              session["材料消耗"][hrid].count += count;
              session["材料消耗"][hrid].totalCost += cost;
          });

          return { materialCost, coinCost }; // Return both values
      }

    // ======================
    // NOTIFICATION SYSTEM
    // ======================

    function createNotificationContainer(headerElement) {
        const container = document.createElement("div");
        container.id = "enhancementNotificationContainer";
        Object.assign(container.style, {
            position: "absolute",
            top: "calc(100% + 5px)",
            left: "50%",
            transform: "translateX(-50%)",
            zIndex: "9999",
            display: "flex",
            flexDirection: "column",
            gap: "5px",
            width: "220px",
            pointerEvents: "none"
        });

        if (getComputedStyle(headerElement).position === "static") {
            headerElement.style.position = "relative";
        }

        headerElement.appendChild(container);
        return container;
    }

    function showNotification(message, type, level, isBlessed = false) {
        const headerElement = document.querySelector('[class^="Header_myActions"]');
        if (!headerElement) return;

        let container = document.getElementById("enhancementNotificationContainer");
        if (!container) {
            container = createNotificationContainer(headerElement);
        }

        if (type === "success") {
            createStandardNotification(container, level, isBlessed);

            if (level >= 10) {
                setTimeout(() => {
                    createMilestoneNotification(container, level);
                }, 300);
            }
        } else {
            createFailureNotification(container);
        }
    }

    function createStandardNotification(container, level, isBlessed) {
        const notification = document.createElement("div");
        notification.className = "enhancement-notification standard";

        Object.assign(notification.style, {
            padding: "10px 15px",
            borderRadius: STYLE.borderRadius.small,
            color: "white",
            fontWeight: "bold",
            boxShadow: STYLE.shadows.notification,
            transform: "translateY(-20px)",
            opacity: "0",
            transition: STYLE.transitions.medium,
            textAlign: "center",
            marginBottom: "5px",
            position: "relative",
            overflow: "hidden",
            pointerEvents: "auto",
            textShadow: STYLE.shadows.text
        });

        if (isBlessed) {
            Object.assign(notification.style, {
                background: STYLE.colors.blessed,
                color: "#8B4513"
            });
            notification.textContent = isZH ? `祝福强化! +${level}` : `BLESSED! +${level}`;
            addHolyEffects(notification);
        } else {
            notification.style.background = getLevelGradient(level);
            notification.textContent = isZH ? `强化成功 +${level}` : `Success +${level}`;
        }

        animateNotification(notification, container, level, isBlessed);
    }

    function createMilestoneNotification(container, level) {
        const milestone = document.createElement("div");
        milestone.className = "enhancement-notification milestone";

        Object.assign(milestone.style, {
            padding: "12px 15px",
            borderRadius: STYLE.borderRadius.small,
            color: "white",
            fontWeight: "bolder",
            boxShadow: STYLE.shadows.milestone,
            transform: "translateY(-20px)",
            opacity: "0",
            transition: STYLE.transitions.medium,
            textAlign: "center",
            marginBottom: "5px",
            animation: "pulse 2s infinite",
            position: "relative",
            overflow: "hidden",
            pointerEvents: "auto",
            textShadow: STYLE.shadows.text,
            font: STYLE.fonts.milestone
        });

        if (level >= 20) {
            milestone.style.background = `
                linear-gradient(
                    135deg,
                    ${STYLE.colors.mythic},
                    #ff0044,
                    #ff2200,
                    #ff0055
                )
            `;
            milestone.style.backgroundSize = "400% 400%";
            milestone.style.animation = "mythicPulse 2.5s ease-in-out infinite";

            milestone.style.color = "#fff";
            milestone.style.fontWeight = "bold";
            milestone.style.textShadow = `
                0 0 4px #ff0044,
                0 0 8px #ff0044,
                0 0 12px #ff0044
            `;
            milestone.textContent = isZH ? "命中注定!" : "IT. IS. DESTINY.";
        }
        else if (level >= 15) {
            milestone.style.background = `linear-gradient(135deg, ${STYLE.colors.legendary}, #FF6600)`;
            milestone.style.textShadow = "0 0 8px rgba(255, 102, 0, 0.8)";
            milestone.textContent = isZH ? "奇迹发生!" : "IT'S A MIRACLE!";
        }
        else if (level >= 10) {
            milestone.style.background = `linear-gradient(135deg, ${STYLE.colors.epic}, #8000FF)`;
            milestone.style.textShadow = "0 0 8px rgba(153, 51, 255, 0.8)";
            milestone.textContent = isZH ? "运气不错!" : "NICE LUCK!";
        }

        animateNotification(milestone, container, level, false);
    }

    function createFailureNotification(container) {
        const notification = document.createElement("div");
        notification.className = "enhancement-notification failure";

        Object.assign(notification.style, {
            padding: "10px 15px",
            borderRadius: STYLE.borderRadius.small,
            color: "white",
            fontWeight: "bold",
            boxShadow: STYLE.shadows.notification,
            transform: "translateY(-20px)",
            opacity: "0",
            transition: STYLE.transitions.medium,
            textAlign: "center",
            marginBottom: "5px",
            position: "relative",
            overflow: "hidden",
            pointerEvents: "auto",
            textShadow: STYLE.shadows.text,
            backgroundColor: STYLE.colors.danger,
            borderTop: "3px solid #C62828"
        });
        notification.textContent = isZH ? "强化失败!" : "Failed!";

        animateNotification(notification, container, 0, false);
    }

    function animateNotification(notification, container, level, isBlessed) {
        container.appendChild(notification);

        setTimeout(() => {
            notification.style.transform = "translateY(0)";
            notification.style.opacity = "1";
        }, 10);

        setTimeout(() => {
            notification.style.transform = "translateY(20px)";
            notification.style.opacity = "0";
            setTimeout(() => notification.remove(), 300);
        }, getNotificationDuration(level, isBlessed));

        notification.addEventListener("click", () => {
            notification.style.transform = "translateY(20px)";
            notification.style.opacity = "0";
            setTimeout(() => notification.remove(), 300);
        });
    }

    function addHolyEffects(notification) {
        const rays = document.createElement("div");
        rays.className = "holy-rays";
        Object.assign(rays.style, {
            position: "absolute",
            top: "0",
            left: "0",
            width: "100%",
            height: "100%",
            background: "radial-gradient(circle, transparent 20%, rgba(255,215,0,0.3) 70%)",
            pointerEvents: "none",
            animation: "raysRotate 4s linear infinite"
        });
        notification.appendChild(rays);

        for (let i = 0; i < 4; i++) {
            const cross = document.createElement("div");
            cross.textContent = "✝";
            Object.assign(cross.style, {
                position: "absolute",
                fontSize: "16px",
                animation: `floatUp ${3 + Math.random() * 2}s linear infinite`,
                opacity: "0.7",
                left: `${10 + (i * 25)}%`,
                top: "100%"
            });
            notification.appendChild(cross);
        }
    }

    function getLevelGradient(level) {
        if (level >= 20) {
            return `linear-gradient(135deg, ${STYLE.colors.mythic}, #FF0000)`;
        }
        else if (level >= 15) {
            return `linear-gradient(135deg, ${STYLE.colors.legendary}, #FF6600)`;
        }
        else if (level >= 10) {
            return `linear-gradient(135deg, ${STYLE.colors.epic}, #8000FF)`;
        }
        else if (level >= 5) {
            return "linear-gradient(135deg, #3399FF, #0066FF)";
        }
        else if (level >= 1) {
            return "linear-gradient(135deg, #33CC33, #009900)";
        }
        else {
            return "linear-gradient(135deg, #CCCCCC, #999999)";
        }
    }

    function getNotificationDuration(level, isBlessed) {
        if (isBlessed) return 5000;
        if (level >= 20) return 5000;
        if (level >= 15) return 4000;
        if (level >= 10) return 3000;
        return 2500;
    }

    // ======================
    // ENHANCEMENT TRACKING
    // ======================

    function hookWS() {
        const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
        const oriGet = dataProperty.get;

        dataProperty.get = hookedGet;
        Object.defineProperty(MessageEvent.prototype, "data", dataProperty);

        function hookedGet() {
            const socket = this.currentTarget;
            if (!(socket instanceof WebSocket)) return oriGet.call(this);
            if (!socket.url.includes("api.milkywayidle.com/ws") && !socket.url.includes("api-test.milkywayidle.com/ws")) {
                return oriGet.call(this);
            }

            const message = oriGet.call(this);
            Object.defineProperty(this, "data", { value: message });
            return handleMessage(message);
        }
    }

    function handleMessage(message) {
        try {
            const obj = JSON.parse(message);
            if (!obj) return message;

            if (obj.type === "init_character_data") {
                handleInitData();
            } else if (obj.type === "action_completed" && obj.endCharacterAction?.actionHrid === "/actions/enhancing/enhance") {
                handleEnhancement(obj.endCharacterAction);
            }
        } catch (error) {
            console.error("Error processing message:", error);
        }
        return message;
    }

    function handleInitData() {
        const initClientData = localStorage.getItem('initClientData');
        if (!initClientData) {
            setTimeout(handleInitData, 500); // Retry if not ready
            return;
        }

        try {
            const data = JSON.parse(initClientData);
            item_hrid_to_name = {};

            // Properly map all item names
            for (const [hrid, details] of Object.entries(data.itemDetailMap)) {
                item_hrid_to_name[hrid] = details.name;
            }

            console.log("Translations loaded:", item_hrid_to_name);
        } catch (error) {
            console.error('Data parsing failed:', error);
        }
    }

    function parseItemHash(primaryItemHash) {
      try {
          // Handle different possible formats:
          // 1. "/item_locations/inventory::/items/enhancers_bottoms::0" (level 0)
          // 2. "161296::/item_locations/inventory::/items/enhancers_bottoms::5" (level 5)
          // 3. Direct HRID like "/items/enhancers_bottoms" (no level)

          let itemHrid = null;
          let enhancementLevel = 0; // Default to 0 if not specified

          // Split by :: to parse components
          const parts = primaryItemHash.split('::');

          // Find the part that starts with /items/
          const itemPart = parts.find(part => part.startsWith('/items/'));
          if (itemPart) {
              itemHrid = itemPart;
          }
          // If no /items/ found but it's a direct HRID
          else if (primaryItemHash.startsWith('/items/')) {
              itemHrid = primaryItemHash;
          }

          // Try to extract enhancement level (last part after ::)
          const lastPart = parts[parts.length - 1];
          if (lastPart && !isNaN(lastPart)) {
              enhancementLevel = parseInt(lastPart, 10);
          }

          if (!itemHrid) {
              console.log('[Parse] Could not find item HRID in:', primaryItemHash);
              return { hrid: null, level: 0 };
          }

          return {
              hrid: itemHrid,
              level: enhancementLevel
          };
      } catch (e) {
          console.error('[Parse] Error parsing primaryItemHash:', e);
          return { hrid: null, level: 0 };
      }
  }

  function calculateSessionDuration(session) {
      if (!session["会话数据"]?.开始时间) return 0;
      const now = Date.now();
      return now - session["会话数据"].开始时间;
  }

  function calculateXpPerHour(session) {

      // Don't calculate for completed sessions
      if (session["强化状态"] === "已完成") {
          return session["会话数据"]?.["每小时经验"] || 0;
      }

      const durationMs = calculateSessionDuration(session);
      const totalXP = session["会话数据"]?.["总经验"] || 0;

      // Don't show rate until we have meaningful data
      if (durationMs < 60000 || totalXP < 1000) { // First minute or <1k XP
          return 0; // Or return null and hide the display
      }

      // Weighted average that becomes more accurate over time
      const weight = Math.min(1, session["尝试历史"]?.length / 10); // 0-1 based on 10 attempts
      const rawRate = (totalXP / (durationMs / (1000 * 60 * 60)));

      // For first few attempts, blend with a conservative estimate
      if (session["尝试历史"]?.length < 5) {
          const baseRate = 50000; // Conservative base rate (adjust per your game)
          return Math.floor((rawRate * weight) + (baseRate * (1 - weight)));
      }

      return Math.floor(rawRate);
  }

  function formatDuration(ms) {
      const seconds = Math.floor((ms / 1000) % 60);
      const minutes = Math.floor((ms / (1000 * 60)) % 60);
      const hours = Math.floor(ms / (1000 * 60 * 60));

      return `${hours}h ${minutes}m ${seconds}s`;
  }

    // Updated handleEnhancement with cost tracking and localStorage saving
    function handleEnhancement(action) {
        'use strict';
        // console.log(action);

        // 1. Extract enhancement data
        const { hrid: itemHRID, level: newLevel } = parseItemHash(action.primaryItemHash);
        const currentCount = action.currentCount;

        if (!itemHRID) return;

        // 2. Check if this is a new item (which means new session)
        const isNewItemSession = currentCount === 1 ||
                               !enhancementData[currentTrackingIndex] ||
                               currentCount <= enhancementData[currentTrackingIndex]["强化次数"];

        // 3. Start new session if needed
        if (currentTrackingIndex === 0 || isNewItemSession) {
            startNewItemSession(action);
        }

        const session = enhancementData[currentTrackingIndex];

        // 4. Special case: First attempt should be a no-op (just record the initial state)
        if (currentCount === 1) {
            // Record initial state but don't count as success/failure
            session["尝试历史"].push({
                attemptNumber: currentCount,
                previousLevel: newLevel,
                newLevel: newLevel,
                timestamp: Date.now(),
                wasSuccess: false,
                wasBlessed: false,
                isInitialState: true  // New flag to mark initial state
            });

            // Initialize level data
            if (!session["强化数据"][newLevel]) {
                session["强化数据"][newLevel] = {
                    "成功次数": 0,
                    "失败次数": 0,
                    "成功率": 0
                };
            }

            // Update session metadata
            session["强化次数"] = currentCount;
            session["最后更新时间"] = Date.now();
            session["会话数据"].最后更新时间 = Date.now();
            session["会话数据"].持续时间 = calculateSessionDuration(session);

            saveEnhancementData();
            updateStatsOnly();
            return;  // Early return for first attempt
        }

        // 5. Determine previous level for subsequent attempts
        const previousLevel = session["尝试历史"]?.length > 0
            ? session["尝试历史"][session["尝试历史"].length - 1].newLevel
            : newLevel; // Fallback to current level

        // 6. Record this attempt
        const wasBlessed = (newLevel - previousLevel) >= 2;
        const isFailure = (newLevel < previousLevel) || (previousLevel === 0 && newLevel === 0);
        session["尝试历史"].push({
            attemptNumber: currentCount,
            previousLevel: previousLevel,
            newLevel: newLevel,
            timestamp: Date.now(),
            wasSuccess: newLevel > previousLevel,
            wasBlessed: wasBlessed
        });

        // 7. Initialize level data if needed
        if (!session["强化数据"][newLevel]) {
            session["强化数据"][newLevel] = {
                "成功次数": 0,
                "失败次数": 0,
                "成功率": 0
            };
        }

        // 8. Track costs
        const preUpdateTotal = session["总成本"];
        const { materialCost, coinCost } = trackMaterialCosts(itemHRID);
        const existingProtectionCost = session["其他数据"]["保护总成本"] || 0;

        // 9. Handle success/failure
        if (newLevel > previousLevel) {
            handleSuccess(session["强化数据"][previousLevel], newLevel, wasBlessed, session);
        } else if (isFailure) {
            handleFailure(action, session["强化数据"][previousLevel], session);
        }
        // No else case - if newLevel === previousLevel and not level 0, it's neither success nor failure

        // 10. Update protection costs if failure occurred
        const newProtectionCost = session["其他数据"]["保护总成本"] || 0;
        const protectionCostDelta = newProtectionCost - existingProtectionCost;

        // 11. Update session data
        session["总成本"] = preUpdateTotal + materialCost + coinCost + protectionCostDelta;
        session["强化次数"] = currentCount;
        session["最后更新时间"] = Date.now();
        session["会话数据"].最后更新时间 = Date.now();
        session["会话数据"].持续时间 = calculateSessionDuration(session);

        // 12. Check for target achievement
        if (newLevel >= session["其他数据"]["目标强化等级"]) {
            finalizeCurrentSession();
            showTargetAchievedCelebration(newLevel, session["其他数据"]["目标强化等级"]);
            session["强化状态"] = "已完成";
        }

        updateStats(session["强化数据"][previousLevel]);

        // 13. Save and update UI
        saveEnhancementData();
        updateStatsOnly();
    }

    function finalizeCurrentSession() {
        const session = enhancementData[currentTrackingIndex];
        if (!session) return;

        // Calculate final stats
        const lastAttempt = session["尝试历史"].slice(-1)[0];
        const finalDuration = lastAttempt.timestamp - session["会话数据"].开始时间;
        const totalXP = session["会话数据"].总经验 || 0;
        const xpPerHour = Math.floor(totalXP / (finalDuration / (1000 * 60 * 60))) || 0;

        // Freeze the session data
        session["会话数据"] = {
            ...session["会话数据"],
            "finalDuration": finalDuration,
            "finalXpPerHour": xpPerHour,
            "持续时间": finalDuration,
            "每小时经验": xpPerHour,
            "最后更新时间": Date.now()
        };

        session["强化状态"] = "已完成";
        session["isLive"] = false;

        saveEnhancementData();
    }

    function startNewItemSession(action) {
        // Finalize previous session if exists
        if (enhancementData[currentTrackingIndex]) {
            finalizeCurrentSession();
        }

        const { hrid: itemHRID, level: newLevel } = parseItemHash(action.primaryItemHash);
        if (!itemHRID) return;

        currentTrackingIndex++;
        enhancementData[currentTrackingIndex] = createItemSessionData(action, itemHRID, newLevel);
        currentViewingIndex = currentTrackingIndex;

        debouncedUpdateFloatingUI();
    }

    function createItemSessionData(action, itemHRID, initialLevel) {
        const protectionHrid = getProtectionItemHrid(action);
        const isProtected = protectionHrid !== null;
        const now = Date.now();

        return {
            "强化数据": {
                [initialLevel]: {
                    "成功次数": 0,
                    "失败次数": 0,
                    "成功率": 0
                }
            },
            "其他数据": {
                "物品HRID": itemHRID,
                "物品名称": item_hrid_to_name[itemHRID] || "Unknown",
                "目标强化等级": action.enhancingMaxLevel,
                "是否保护": isProtected,
                "保护物品HRID": protectionHrid,
                "保护物品名称": isProtected ? (item_hrid_to_name[protectionHrid] || protectionHrid) : null,
                "保护消耗总数": 0,
                "保护总成本": 0,
                "保护最小等级": action.enhancingProtectionMinLevel
            },
            "材料消耗": {},
            "硬币消耗": { count: 0, totalCost: 0 },
            "总成本": 0,
            "强化次数": 0,
            "尝试历史": [],
            "会话数据": {
                "开始时间": now,
                "最后更新时间": now,
                "总经验": 0,
                "持续时间": 0,
                "每小时经验": 0,  // Add this new field
                "finalDuration": null,  // Add this for completed sessions
                "finalXpPerHour": null  // Add this for completed sessions
            },
            "强化状态": "进行中",
            "isLive": true  // Add this flag to track live sessions
        };
    }

    // Keep handleSuccess as is but ensure it's safe
    function handleSuccess(levelData, newLevel, wasBlessed, session) {
        try {
            // 1. Update success count
            levelData["成功次数"] = (levelData["成功次数"] || 0) + 1;

            // 2. Calculate XP gain from last attempt
            const xpGain = session["尝试历史"]?.length > 0
                ? calculateSuccessXP(
                    session["尝试历史"][session["尝试历史"].length - 1].previousLevel,
                    session["其他数据"]["物品HRID"]
                  )
                : calculateSuccessXP(newLevel, session["其他数据"]["物品HRID"]); // Fallback for first attempt

            // 3. Update XP tracking (using new 会话数据 structure)
            session["会话数据"].总经验 = (session["会话数据"].总经验 || 0) + xpGain;

            // 4. Show appropriate notification
            showNotification(
                wasBlessed
                    ? (isZH ? `祝福强化! +${newLevel}` : `BLESSED! +${newLevel}`)
                    : (isZH ? `强化成功 +${newLevel}` : `Success +${newLevel}`),
                "success",
                newLevel,
                wasBlessed
            );

        } catch (e) {
            console.error("Error in handleSuccess:", e);
            showNotification(isZH ? "强化跟踪错误" : "Enhancement tracking error", "failure", 0);
        }
    }

    function handleFailure(action, levelData, session) {
        try {
            // 1. Update failure count
            levelData["失败次数"] = (levelData["失败次数"] || 0) + 1;

            // 2. Calculate XP gain from last attempt
            const xpGain = session["尝试历史"]?.length > 0
                ? calculateFailureXP(
                    session["尝试历史"][session["尝试历史"].length - 1].previousLevel,
                    session["其他数据"]["物品HRID"]
                  )
                : calculateFailureXP(0, session["其他数据"]["物品HRID"]); // Fallback for first attempt

            // 3. Update XP tracking
            session["会话数据"].总经验 = (session["会话数据"].总经验 || 0) + xpGain;
            const currentLevel = session["尝试历史"]?.slice(-1)[0]?.previousLevel || 0;

            // 4. Handle protection if enabled
            if (session["其他数据"]?.["是否保护"] &&
                currentLevel >= session["其他数据"]?.["保护最小等级"]) {

                const protectionHrid = session["其他数据"]["保护物品HRID"];
                if (protectionHrid) {
                    // Initialize protection tracking if needed
                    session["保护消耗"] = session["保护消耗"] || {};
                    session["保护消耗"][protectionHrid] = session["保护消耗"][protectionHrid] || {
                        name: session["其他数据"]["保护物品名称"] || protectionHrid,
                        count: 0,
                        totalCost: 0
                    };

                    // Update protection costs
                    const protectionCost = getMarketPrice(protectionHrid) || 0;
                    session["其他数据"]["保护消耗总数"] = (session["其他数据"]["保护消耗总数"] || 0) + 1;
                    session["其他数据"]["保护总成本"] = (session["其他数据"]["保护总成本"] || 0) + protectionCost;

                    session["保护消耗"][protectionHrid].count += 1;
                    session["保护消耗"][protectionHrid].totalCost += protectionCost;
                }
            }

            showNotification(isZH ? "强化失败!" : "Failed!", "failure", 0);
        } catch (e) {
            console.error("Error in handleFailure:", e);
            showNotification(isZH ? "强化跟踪错误" : "Enhancement tracking error", "failure", 0);
        }
    }

    function updateStats(levelData) {
        // Safe access with default values
        const success = levelData["成功次数"] || 0;
        const failure = levelData["失败次数"] || 0;
        levelData["成功率"] = (success + failure) > 0 ? success / (success + failure) : 0;
    }

    function getEnhancementState(currentItem) {
        const highestSuccessLevel = Math.max(...Object.keys(currentItem).filter(level => currentItem[level]["成功次数"] > 0));
        return (highestSuccessLevel + 1 >= enhancementData[currentTrackingIndex]["其他数据"]["目标强化等级"]) ? "强化成功" : "强化失败";
    }

    function getProtectionItemHrid(action) {
        // If protection is disabled (min level < 2)
        if (action.enhancingProtectionMinLevel < 2) {
            return null;
        }

        // Extract protection item from secondaryItemHash
        if (action.secondaryItemHash) {
            const parts = action.secondaryItemHash.split('::');
            if (parts.length >= 3 && parts[2].startsWith('/items/')) {
                return parts[2];
            }
        }

        // No protection being used
        return null;
    }

    function translateItemName(hrid, fallbackName) {

        if (!isZH) {
            return fallbackName;
        }

        try {
            const gameData = JSON.parse(localStorage.getItem('initClientData'));

            if (gameData?.itemDetailMap?.[hrid]?.name) {
                const translated = gameData.itemDetailMap[hrid].name;
                return translated;
            }
        } catch (e) {
            console.error("Translation error:", e);
        }

        return item_hrid_to_name?.[hrid] || fallbackName || "Unknown";
    }

    function getCurrentItemName(session) {
        if (!session["其他数据"] || !session["其他数据"]["物品HRID"]) return "Unknown";
        const itemHRID = session["其他数据"]["物品HRID"];

        // Always get fresh translation from game data
        if (item_hrid_to_name && item_hrid_to_name[itemHRID]) {
            return item_hrid_to_name[itemHRID];
        }

        // Fallback to English if needed
        const initData = JSON.parse(localStorage.getItem('initClientData') || '{}');
        if (initData.itemDetailMap && initData.itemDetailMap[itemHRID]) {
            return initData.itemDetailMap[itemHRID].name;
        }

        return "Unknown";
    }

    function showTargetAchievedCelebration(achievedLevel, targetLevel) {
        const celebration = document.createElement("div");
        celebration.id = "enhancementCelebration";
        Object.assign(celebration.style, {
            position: "fixed",
            top: "0",
            left: "0",
            width: "100%",
            height: "100%",
            zIndex: "99999",
            pointerEvents: "none",
            display: "flex",
            flexDirection: "column",
            justifyContent: "center",
            alignItems: "center",
            background: "radial-gradient(circle, rgba(0,0,0,0.7), transparent 70%)"
        });

        const text = document.createElement("div");
        text.textContent = isZH ? `目标达成! +${achievedLevel}` : `TARGET ACHIEVED! +${achievedLevel}`;
        Object.assign(text.style, {
            fontSize: "3rem",
            fontWeight: "900",
            color: "#FFD700",
            textShadow: "0 0 20px #FF0000, 0 0 30px #FF8C00",
            animation: "celebrateText 2s ease-out both"
        });
        celebration.appendChild(text);

        for (let i = 0; i < 100; i++) {
            const confetti = document.createElement("div");
            Object.assign(confetti.style, {
                position: "absolute",
                width: "10px",
                height: "10px",
                backgroundColor: getRandomColor(),
                borderRadius: "50%",
                left: "50%",
                top: "50%",
                opacity: "0",
                animation: `confettiFly ${Math.random() * 2 + 1}s ease-out ${Math.random() * 0.5}s both`
            });
            celebration.appendChild(confetti);
        }

        for (let i = 0; i < 8; i++) {
            setTimeout(() => {
                createFireworkBurst(celebration);
            }, i * 300);
        }

        document.body.appendChild(celebration);

        setTimeout(() => {
            celebration.style.opacity = "0";
            celebration.style.transition = "opacity 1s ease-out";
            setTimeout(() => celebration.remove(), 1000);
        }, 4000);
    }

    function createFireworkBurst(container) {
        const burst = document.createElement("div");
        Object.assign(burst.style, {
            position: "absolute",
            left: `${Math.random() * 80 + 10}%`,
            top: `${Math.random() * 80 + 10}%`,
            width: "5px",
            height: "5px",
            borderRadius: "50%",
            background: getRandomColor(),
            boxShadow: `0 0 10px 5px ${getRandomColor()}`,
            animation: `fireworkExpand 0.8s ease-out both`
        });
        container.appendChild(burst);

        for (let i = 0; i < 30; i++) {
            setTimeout(() => {
                const particle = document.createElement("div");
                Object.assign(particle.style, {
                    position: "absolute",
                    left: burst.style.left,
                    top: burst.style.top,
                    width: "3px",
                    height: "3px",
                    backgroundColor: burst.style.background,
                    borderRadius: "50%",
                    animation: `fireworkTrail ${Math.random() * 0.5 + 0.5}s ease-out both`
                });
                container.appendChild(particle);
            }, i * 20);
        }
    }

    function getRandomColor() {
        const colors = ["#FF0000", "#FF8C00", "#FFD700", "#4CAF50", "#2196F3", "#9C27B0"];
        return colors[Math.floor(Math.random() * colors.length)];
    }

    function renderStats(selectedKey) {
        const statsContainer = document.querySelector("#ultimateEnhancementStatsContainer");
        if (!statsContainer) return;
        statsContainer.innerHTML = "";

        const item = enhancementData[selectedKey];
        if (!item || !item["强化数据"]) return;

        const headers = ["等级", "成功", "失败", "概率"];
        headers.forEach(headerText => {
            const headerDiv = document.createElement("div");
            headerDiv.style.fontWeight = "bold";
            headerDiv.textContent = isZH ? headerText :
                headerText === "等级" ? "Level" :
                headerText === "成功" ? "Success" :
                headerText === "失败" ? "Failure" :
                "Success Rate";
            statsContainer.appendChild(headerDiv);
        });

        const totalSuccess = Object.values(item["强化数据"]).reduce((acc, val) => acc + (val["成功次数"] || 0), 0);
        const totalFailure = Object.values(item["强化数据"]).reduce((acc, val) => acc + (val["失败次数"] || 0), 0);
        const totalCount = totalSuccess + totalFailure;
        const totalRate = totalCount > 0 ? (totalSuccess / totalCount * 100).toFixed(2) : "0.00";

        ["总计", totalSuccess, totalFailure, `${totalRate}%`].forEach((totalText, index) => {
            const totalDiv = document.createElement("div");
            totalDiv.textContent = isZH ? totalText : index === 0 ? "Total" : totalText;
            statsContainer.appendChild(totalDiv);
        });

        Object.keys(item["强化数据"])
            .map(Number)
            .sort((a, b) => b - a)
            .forEach(level => {
                const levelData = item["强化数据"][level];
                const levelDivs = [
                    level,
                    levelData["成功次数"] || 0,
                    levelData["失败次数"] || 0,
                    `${((levelData["成功率"] || 0) * 100).toFixed(2)}%`
                ];

                levelDivs.forEach(data => {
                    const dataDiv = document.createElement("div");
                    dataDiv.textContent = data;
                    statsContainer.appendChild(dataDiv);
                });
            });
    }

    // ======================
    // FLOATING UI SYSTEM (F9 TOGGLE)
    // ======================

    let floatingUI = null;
    let cleanupFunctions = [];

    function createFloatingUI() {
        if (floatingUI && document.body.contains(floatingUI)) {
            return floatingUI;
        }

        // Create main container (existing code remains the same)
        floatingUI = document.createElement("div");
        floatingUI.id = "enhancementFloatingUI";
        Object.assign(floatingUI.style, {
            position: "fixed",
            top: "50px",
            left: "50px",
            zIndex: "9998",
            fontSize: "14px",
            padding: "0",
            borderRadius: STYLE.borderRadius.medium,
            boxShadow: '0 8px 32px rgba(0, 0, 0, 0.6)',
            overflow: "hidden",
            width: "350px",
            minHeight: "auto",
            background: 'rgba(25, 0, 35, 0.92)',
            backdropFilter: 'blur(12px)',
            border: `1px solid ${STYLE.colors.primary}`,
            color: STYLE.colors.textPrimary,
            willChange: "transform",
            transform: "translateZ(0)",
            backfaceVisibility: "hidden",
            perspective: "1000px",
            display: "flex",
            flexDirection: "column"
        });

        // Create header
        const header = document.createElement("div");
        header.id = "enhancementPanelHeader";
        Object.assign(header.style, {
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
            cursor: "move",
            padding: "10px 15px",
            background: STYLE.colors.headerBg,
            borderBottom: `1px solid ${STYLE.colors.border}`,
            userSelect: "none",
            WebkitUserSelect: "none",
            flexShrink: "0"
        });

        // Create title with session counter
        const titleContainer = document.createElement("div");
        titleContainer.style.display = "flex";
        titleContainer.style.alignItems = "center";
        titleContainer.style.gap = "10px";

        const title = document.createElement("span");
        title.textContent = isZH ? "强化追踪器" : "Enhancement Tracker";
        title.style.fontWeight = "bold";

        const sessionCounter = document.createElement("span");
        sessionCounter.id = "enhancementSessionCounter";
        sessionCounter.style.fontSize = "12px";
        sessionCounter.style.opacity = "0.7";
        sessionCounter.style.marginLeft = "5px";

        titleContainer.appendChild(title);
        titleContainer.appendChild(sessionCounter);

        // Create navigation arrows container
        const navContainer = document.createElement("div");
        Object.assign(navContainer.style, {
            display: "flex",
            gap: "5px",
            alignItems: "center",
            marginLeft: "auto"
        });

        // Create clear sessions button
         const clearButton = document.createElement("button");
         clearButton.innerHTML = "🗑️";
         clearButton.title = isZH ? "清除所有会话" : "Clear all sessions";
         Object.assign(clearButton.style, {
             background: "none",
             border: "none",
             color: STYLE.colors.textPrimary,
             cursor: "pointer",
             fontSize: "14px",
             padding: "2px 8px",
             borderRadius: "3px",
             transition: STYLE.transitions.fast,
             marginRight: "5px"
         });
         clearButton.addEventListener("mouseover", () => {
             clearButton.style.color = STYLE.colors.danger;
             clearButton.style.background = "rgba(255, 0, 0, 0.1)";
         });
         clearButton.addEventListener("mouseout", () => {
             clearButton.style.color = STYLE.colors.textPrimary;
             clearButton.style.background = "none";
         });
         clearButton.addEventListener("click", (e) => {
             e.stopPropagation();
             clearAllSessions();
         });

        // Create previous arrow
        const prevArrow = document.createElement("button");
        prevArrow.innerHTML = "&larr;";
        Object.assign(prevArrow.style, {
            background: "none",
            border: "none",
            color: STYLE.colors.textPrimary,
            cursor: "pointer",
            fontSize: "14px",
            padding: "2px 8px",
            borderRadius: "3px",
            transition: STYLE.transitions.fast
        });
        prevArrow.addEventListener("mouseover", () => {
            prevArrow.style.color = STYLE.colors.accent;
            prevArrow.style.background = "rgba(255, 255, 255, 0.1)";
        });
        prevArrow.addEventListener("mouseout", () => {
            prevArrow.style.color = STYLE.colors.textPrimary;
            prevArrow.style.background = "none";
        });
        prevArrow.addEventListener("click", (e) => {
            e.stopPropagation();
            navigateSessions(-1);
        });

        // Create next arrow
        const nextArrow = document.createElement("button");
        nextArrow.innerHTML = "&rarr;";
        Object.assign(nextArrow.style, {
            background: "none",
            border: "none",
            color: STYLE.colors.textPrimary,
            cursor: "pointer",
            fontSize: "14px",
            padding: "2px 8px",
            borderRadius: "3px",
            transition: STYLE.transitions.fast
        });
        nextArrow.addEventListener("mouseover", () => {
            nextArrow.style.color = STYLE.colors.accent;
            nextArrow.style.background = "rgba(255, 255, 255, 0.1)";
        });
        nextArrow.addEventListener("mouseout", () => {
            nextArrow.style.color = STYLE.colors.textPrimary;
            nextArrow.style.background = "none";
        });
        nextArrow.addEventListener("click", (e) => {
            e.stopPropagation();
            navigateSessions(1);
        });

        // Add toggle button
        const toggleButton = document.createElement("button");
        toggleButton.innerHTML = "👁️"; // Down arrow icon (will change based on state)
        toggleButton.title = isZH ? "切换面板显示" : "Toggle panel display";
        Object.assign(toggleButton.style, {
            background: "none",
            border: "none",
            color: STYLE.colors.textPrimary,
            cursor: "pointer",
            fontSize: "14px",
            padding: "2px 8px",
            borderRadius: "3px",
            transition: STYLE.transitions.fast,
            marginLeft: "5px"
        });
        toggleButton.addEventListener("mouseover", () => {
            toggleButton.style.color = STYLE.colors.accent;
            toggleButton.style.background = "rgba(255, 255, 255, 0.1)";
        });
        toggleButton.addEventListener("mouseout", () => {
            toggleButton.style.color = STYLE.colors.textPrimary;
            toggleButton.style.background = "none";
        });
        toggleButton.addEventListener("click", (e) => {
            e.stopPropagation();
            toggleFloatingUI();
        });


        // Add elements to header
        header.appendChild(clearButton);
        header.appendChild(titleContainer);
        navContainer.appendChild(toggleButton);
        navContainer.appendChild(prevArrow);
        navContainer.appendChild(nextArrow);
        header.appendChild(navContainer);

        // Rest of the existing code (drag functionality, content area, etc.) remains the same
        let isDragging = false;
        let offsetX, offsetY;
        let animationFrameId;

        header.addEventListener("mousedown", (e) => {
            isDragging = true;
            offsetX = e.clientX - floatingUI.offsetLeft;
            offsetY = e.clientY - floatingUI.offsetTop;
            floatingUI.classList.add("dragging");
            e.preventDefault();
        });

        const mouseMoveHandler = (e) => {
            if (!isDragging) return;
            cancelAnimationFrame(animationFrameId);
            animationFrameId = requestAnimationFrame(() => {
                floatingUI.style.left = `${e.clientX - offsetX}px`;
                floatingUI.style.top = `${e.clientY - offsetY}px`;
            });
        };

        const mouseUpHandler = () => {
            if (!isDragging) return;
            isDragging = false;
            floatingUI.classList.remove("dragging");
            cancelAnimationFrame(animationFrameId);
        };

        document.addEventListener("mousemove", mouseMoveHandler, { passive: true });
        document.addEventListener("mouseup", mouseUpHandler, { passive: true });

        cleanupFunctions.push(() => {
            document.removeEventListener("mousemove", mouseMoveHandler);
            document.removeEventListener("mouseup", mouseUpHandler);
        });

        floatingUI.appendChild(header);

        // Create content area
        const content = document.createElement("div");
        content.id = "enhancementPanelContent";
        Object.assign(content.style, {
            padding: "8px",
            overflowY: "hidden",
            flexGrow: "1",
            minHeight: "0",
            contain: "strict",
            boxSizing: "border-box",
            display: "flex",
            flexDirection: "column"
        });

        const resizeObserver = new ResizeObserver((entries) => {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = requestAnimationFrame(() => {
                    const headerHeight = header.offsetHeight;
                    const contentHeight = content.scrollHeight;
                    const newHeight = headerHeight + contentHeight;

                    // Disable transitions temporarily when shrinking
                    if (newHeight < parseInt(floatingUI.style.height || 0)) {
                        floatingUI.style.transition = 'none';
                        floatingUI.style.height = `${newHeight}px`;
                        // Force reflow before re-enabling transitions
                        void floatingUI.offsetHeight;
                        floatingUI.style.transition = STYLE.transitions.medium;
                    } else {
                        floatingUI.style.height = `${newHeight}px`;
                    }
                });
            });
            resizeObserver.observe(content);

        cleanupFunctions.push(() => resizeObserver.disconnect());
        floatingUI.appendChild(content);

        document.body.appendChild(floatingUI);
        // Initial class for empty state
        floatingUI.classList.toggle('has-data', false);
        return floatingUI;
    }

    function navigateSessions(direction) {
        const sessionKeys = Object.keys(enhancementData).map(Number).sort((a, b) => a - b);
        if (sessionKeys.length <= 1) return;

        const currentIndex = sessionKeys.indexOf(currentViewingIndex);
        const newIndex = currentIndex + direction;

        if (newIndex >= 0 && newIndex < sessionKeys.length) {
            currentViewingIndex = sessionKeys[newIndex];
            saveEnhancementData(); // Save the new viewing index
            updateSessionCounter();
            debouncedUpdateFloatingUI();
        }
    }

    function updateSessionCounter() {
        const sessionCounter = document.getElementById("enhancementSessionCounter");
        if (!sessionCounter) return;

        const sessionKeys = Object.keys(enhancementData).map(Number).sort((a, b) => a - b);
        const currentPosition = sessionKeys.indexOf(currentViewingIndex) + 1;
        const totalSessions = sessionKeys.length;

        sessionCounter.textContent = isZH
            ? `(${currentPosition}/${totalSessions})`
            : `(${currentPosition}/${totalSessions})`;

        // Visual indicator
        sessionCounter.style.color = currentViewingIndex === currentTrackingIndex ?
            STYLE.colors.accent : STYLE.colors.textSecondary;
        sessionCounter.style.fontWeight = currentViewingIndex === currentTrackingIndex ?
            "bold" : "normal";
    }


    // Define table styles
    const compactTableStyle = `
        width: 100%;
        border-collapse: separate;
        border-spacing: 0;
        font-size: 13px;
        margin: 5px 0;
        background: rgba(30, 0, 40, 0.6);
        border-radius: ${STYLE.borderRadius.small};
        overflow: hidden;
    `;

    const compactCellStyle = `
        padding: 4px 8px;
        line-height: 1.3;
        border-bottom: 1px solid rgba(126, 87, 194, 0.2);
    `;

    const compactHeaderStyle = `
        ${compactCellStyle}
        font-weight: bold;
        text-align: center;
        background: ${STYLE.colors.headerBg};
        color: ${STYLE.colors.textPrimary};
        border-bottom: 2px solid ${STYLE.colors.primary};
    `;

    let updateDebounce;

    function debouncedUpdateFloatingUI() {
        clearTimeout(updateDebounce);
        updateDebounce = setTimeout(updateFloatingUI, 100);
    }

    function updateFloatingUI() {
        updateSessionCounter();

        const floatingUI = document.getElementById("enhancementFloatingUI") || createFloatingUI();
        const content = document.getElementById("enhancementPanelContent");

        const UI_DIMENSIONS = {
            scrollAreaMinHeight: '450px',
            scrollAreaMaxHeight: '700px',
            floatingUIHeight: '750px',
            floatingUIMinHeight: '200px',
            floatingUIMaxHeight: '85vh'
        };

        // Save current scroll position before wiping content
        const scrollContainer = content.querySelector("div > div:last-child");
        const oldScrollTop = scrollContainer?.scrollTop || 0;

        // Clear previous content
        content.innerHTML = '';

        // No enhancement data to show
        if (currentViewingIndex === 0 || !enhancementData[currentViewingIndex]) {
            floatingUI.classList.toggle('has-data', false);
            content.innerHTML = `
                <div class="empty-state">
                    <div class="empty-icon">✧</div>
                    <div class="empty-text">${isZH ? "开始强化以记录数据" : "Begin enhancing to populate data"}</div>
                </div>
            `;
            floatingUI.style.height = 'auto';
            return;
        }

        const session = enhancementData[currentViewingIndex];
        if (!session || !session["其他数据"]) {
            content.innerHTML = isZH ? "没有活跃的强化数据" : "No active enhancement data";
            floatingUI.style.height = 'auto';
            return;
        }

        floatingUI.classList.toggle('has-data', true);

        // Build header info
        const marketStatus = lastMarketUpdate > 0
            ? `${isZH ? '市场数据' : 'Market data'} ${new Date(lastMarketUpdate * 1000).toLocaleTimeString()}`
            : `${isZH ? '无市场数据' : 'No market data'}`;

        const itemData = session["其他数据"] || {};
        const itemName = translateItemName(itemData["物品HRID"], itemData["物品名称"]) || "Unknown";
        const targetLevel = itemData["目标强化等级"] || 0;

        // Get the appropriate display data based on session state
        const displayData = getSessionDisplayData(session);

        // Main container
        const container = document.createElement("div");
        container.style.display = 'flex';
        container.style.flexDirection = 'column';
        container.style.height = '100%';

        // Header section
        const headerContent = document.createElement("div");
        headerContent.style.flexShrink = '0';


        // Status display logic
         const statusDisplay = session["强化状态"] === "已完成"
             ? `<div style="display: flex; justify-content: space-between; margin-top: 5px; color: ${STYLE.colors.success}">
                   <span>${isZH ? "状态" : "Status"}:</span>
                   <strong>${isZH ? "已完成" : "Completed"}</strong>
                </div>`
             : `<div style="display: flex; justify-content: space-between; margin-top: 5px; color: ${STYLE.colors.accent}">
                   <span>${isZH ? "状态" : "Status"}:</span>
                   <strong>${isZH ? "进行中" : "In Progress"}</strong>
                </div>`;

        headerContent.innerHTML = `
            <div style="margin-bottom: 5px; font-size: 12px; color: ${lastMarketUpdate > 0 ? STYLE.colors.success : STYLE.colors.danger};">
                ${marketStatus}
            </div>
            <div style="margin-bottom: 10px; font-size: 13px;">
                <div style="display: flex; justify-content: space-between;">
                    <span>${isZH ? "物品" : "Item"}:</span>
                    <strong>${itemName}</strong>
                </div>
                <div style="display: flex; justify-content: space-between;">
                    <span>${isZH ? "目标" : "Target"}:</span>
                    <span>+${targetLevel}</span>
                </div>
                ${statusDisplay}
            </div>
        `;

        // Scrollable data area
        const scrollContent = document.createElement("div");
        scrollContent.style.flexGrow = '1';
        scrollContent.style.overflowY = 'auto';
        scrollContent.style.minHeight = UI_DIMENSIONS.scrollAreaMinHeight;
        scrollContent.style.maxHeight = UI_DIMENSIONS.scrollAreaMaxHeight;
        scrollContent.style.paddingRight = '5px';

        // Stats container with proper session data
        const statsContainer = document.createElement("div");
        statsContainer.id = "ultimateEnhancementStatsContainer";

        const totalAttempts = session["强化次数"];
        const totalSuccess = Object.values(session["强化数据"]).reduce((sum, level) => sum + (level["成功次数"] || 0), 0);
        const totalFailure = Object.values(session["强化数据"]).reduce((sum, level) => sum + (level["失败次数"] || 0), 0);
        const totalRate = totalAttempts > 0 ? (totalSuccess / totalAttempts * 100).toFixed(2) : 0;
        const shouldDisplayRate = displayData.isLive ?
            (displayData.xpPerHour > 0) :
            (displayData.xpPerHour !== null);

        statsContainer.innerHTML = `
            <table style="${compactTableStyle}">
                <thead>
                    <tr>
                        <th style="${compactHeaderStyle}">${isZH ? "等级" : "Lvl"}</th>
                        <th style="${compactHeaderStyle}">${isZH ? "成功" : "Success"}</th>
                        <th style="${compactHeaderStyle}">${isZH ? "失败" : "Fail"}</th>
                        <th style="${compactHeaderStyle}">%</th>
                    </tr>
                </thead>
                <tbody>
                    ${Object.keys(session["强化数据"])
                        .sort((a, b) => b - a)
                        .map(level => {
                            const levelData = session["强化数据"][level];
                            const rate = ((levelData["成功率"] || 0) * 100).toFixed(1);
                            const sessionLevel = session["尝试历史"]?.slice(-1)[0]?.newLevel || 0;
                            const isCurrent = (level == sessionLevel) && (currentTrackingIndex == currentViewingIndex);
                            return `
                            <tr ${isCurrent ? `
                                style="
                                    background: linear-gradient(90deg, rgba(126, 87, 194, 0.25), rgba(0, 242, 255, 0.1));
                                    box-shadow: 0 0 12px rgba(126, 87, 194, 0.5), inset 0 0 6px rgba(0, 242, 255, 0.3);
                                    border-left: 3px solid ${STYLE.colors.accent};
                                    font-weight: bold;
                                "` : ''}>
                                <td style="${compactCellStyle} text-align: center;">${level}</td>
                                <td style="${compactCellStyle} text-align: right;">${levelData["成功次数"] || 0}</td>
                                <td style="${compactCellStyle} text-align: right;">${levelData["失败次数"] || 0}</td>
                                <td style="${compactCellStyle} text-align: right;">${rate}%</td>
                            </tr>`;
                        }).join('')}
                </tbody>
            </table>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                <div>
                    <span>${isZH ? "总计尝试次数" : "Total Attempts"}:</span>
                    <strong> ${totalAttempts}</strong>
                </div>
                <div>
                    <span>${isZH ? "保护石使用" : "Prots Used"}:</span>
                    <strong> ${session["其他数据"]["保护消耗总数"] || 0}</strong>
                </div>
            </div>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                <span>${isZH ? "总获得经验" : "Total XP Gained"}:</span>
                <strong>${formatNumber(displayData.totalXP)}</strong>
            </div>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                <span>${isZH ? "会话时长" : "Session Duration"}:</span>
                <strong>${formatDuration(displayData.duration)}</strong>
            </div>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                <span>${isZH ? "经验/小时" : "XP/Hour"}:</span>
                <strong>
                    ${shouldDisplayRate ? formatNumber(displayData.xpPerHour) : (isZH ? "计算中..." : "Calculating...")}
                </strong>
            </div>
        `;

        if (session["材料消耗"] && Object.keys(session["材料消耗"]).length > 0) {
            statsContainer.innerHTML += generateMaterialCostsHTML(session);
        }

        scrollContent.appendChild(statsContainer);

        // Build complete UI
        container.appendChild(headerContent);
        container.appendChild(scrollContent);
        content.appendChild(container);

        // Style the floating UI
        floatingUI.style.height = UI_DIMENSIONS.floatingUIHeight;
        floatingUI.style.minHeight = UI_DIMENSIONS.floatingUIMinHeight;
        floatingUI.style.maxHeight = UI_DIMENSIONS.floatingUIMaxHeight;
        floatingUI.style.overflow = 'hidden';

        // Restore previous scroll position (after DOM renders)
        setTimeout(() => {
            scrollContent.scrollTop = oldScrollTop;
        }, 0);
    }

    // Helper function to get proper display data
    function getSessionDisplayData(session) {
        if (session["强化状态"] === "已完成") {
            // For completed sessions, use frozen values
            return {
                duration: session["会话数据"].finalDuration || session["会话数据"].持续时间,
                xpPerHour: session["会话数据"].finalXpPerHour || session["会话数据"].每小时经验,
                totalXP: session["会话数据"].总经验 || 0,
                isLive: false
            };
        } else {
            // For live sessions, calculate current values
            return {
                duration: calculateSessionDuration(session),
                xpPerHour: calculateXpPerHour(session),
                totalXP: session["会话数据"].总经验 || 0,
                isLive: true
            };
        }
    }

    function updateStatsOnly() {
        const session = enhancementData[currentViewingIndex];
        if (!session || !session["其他数据"]) return;

        const statsContainer = document.getElementById("ultimateEnhancementStatsContainer");
        if (!statsContainer) return;

        statsContainer.innerHTML = buildTableHTML(session);

        if (session["材料消耗"] && Object.keys(session["材料消耗"]).length > 0) {
            statsContainer.innerHTML += generateMaterialCostsHTML(session);
        }
    }

    function getSessionDisplayData(session) {
        if (session["强化状态"] === "已完成") {
            // For completed sessions, always use frozen values
            return {
                duration: session["会话数据"].finalDuration,
                xpPerHour: session["会话数据"].finalXpPerHour,
                totalXP: session["会话数据"].总经验,
                isLive: false
            };
        } else {
            // For live sessions, calculate current values
            return {
                duration: calculateSessionDuration(session),
                xpPerHour: calculateXpPerHour(session),
                totalXP: session["会话数据"].总经验 || 0,
                isLive: true
            };
        }
    }


    function buildTableHTML(session) {
        const totalAttempts = session["强化次数"];
        const totalSuccess = Object.values(session["强化数据"]).reduce((sum, level) => sum + (level["成功次数"] || 0), 0);
        const totalFailure = Object.values(session["强化数据"]).reduce((sum, level) => sum + (level["失败次数"] || 0), 0);
        const totalRate = totalAttempts > 0 ? (totalSuccess / totalAttempts * 100).toFixed(2) : 0;

        // Get the appropriate display data
        const displayData = getSessionDisplayData(session);
        const shouldDisplayRate = displayData.isLive ?
            (displayData.xpPerHour > 0) :
            (displayData.xpPerHour !== null);


        return `
            <table style="${compactTableStyle}">
                <thead>
                    <tr>
                        <th style="${compactHeaderStyle}">${isZH ? "等级" : "Lvl"}</th>
                        <th style="${compactHeaderStyle}">${isZH ? "成功" : "Success"}</th>
                        <th style="${compactHeaderStyle}">${isZH ? "失败" : "Fail"}</th>
                        <th style="${compactHeaderStyle}">%</th>
                    </tr>
                </thead>
                <tbody>
                    ${Object.keys(session["强化数据"])
                        .sort((a, b) => b - a)
                        .map(level => {
                            const levelData = session["强化数据"][level];
                            const rate = ((levelData["成功率"] || 0) * 100).toFixed(1);
                            const sessionLevel = session["尝试历史"]?.slice(-1)[0]?.newLevel || 0;
                            const isCurrent = (level == sessionLevel) && (currentTrackingIndex == currentViewingIndex);
                            return `
                            <tr ${isCurrent ? `
                                style="
                                    background: linear-gradient(90deg, rgba(126, 87, 194, 0.25), rgba(0, 242, 255, 0.1));
                                    box-shadow: 0 0 12px rgba(126, 87, 194, 0.5), inset 0 0 6px rgba(0, 242, 255, 0.3);
                                    border-left: 3px solid ${STYLE.colors.accent};
                                    font-weight: bold;
                                "` : ''}>
                                <td style="${compactCellStyle} text-align: center;">${level}</td>
                                <td style="${compactCellStyle} text-align: right;">${levelData["成功次数"] || 0}</td>
                                <td style="${compactCellStyle} text-align: right;">${levelData["失败次数"] || 0}</td>
                                <td style="${compactCellStyle} text-align: right;">${rate}%</td>
                            </tr>`;
                        }).join('')}
                </tbody>
            </table>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                <div>
                    <span>${isZH ? "总计尝试次数" : "Total Attempts"}:</span>
                    <strong> ${totalAttempts}</strong>
                </div>
                <div>
                    <span>${isZH ? "保护石使用" : "Prots Used"}:</span>
                    <strong> ${session["其他数据"]["保护消耗总数"] || 0}</strong>
                </div>
            </div>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                <span>${isZH ? "总获得经验" : "Total XP Gained"}:</span>
                <strong>${formatNumber(session["会话数据"]?.["总经验"] || 0)}</strong>
            </div>

            <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                 <span>${isZH ? "会话时长" : "Session Duration"}:</span>
                 <strong>${formatDuration(displayData.duration)}</strong>
             </div>

             <div style="margin-top: 8px; display: flex; justify-content: space-between; font-size: 13px;">
                 <span>${isZH ? "经验/小时" : "XP/Hour"}:</span>
                 <strong>
                     ${shouldDisplayRate ? formatNumber(displayData.xpPerHour) : (isZH ? "计算中..." : "Calculating...")}
                 </strong>
             </div>
         `;
    }

    function formatNumber(num) {
        if (typeof num !== 'number') return '0';
        return num.toLocaleString('en-US', { maximumFractionDigits: 0 });
    }

    function toggleFloatingUI() {
        if (!floatingUI || !document.body.contains(floatingUI)) {
            createFloatingUI();
            debouncedUpdateFloatingUI();
            floatingUI.style.display = "block";
            showUINotification(
                isZH ? "强化追踪器已启用" : "Enhancement Tracker Enabled"
            );
        } else {
            const willShow = floatingUI.style.display === "none";
            floatingUI.style.display = willShow ? "flex" : "none";
            showUINotification(
                isZH ? `强化追踪器${willShow ? "已显示" : "已隐藏"}` :
                      `Enhancement Tracker ${willShow ? "Shown" : "Hidden"}`
            );
        }
        localStorage.setItem("enhancementUIVisible", floatingUI.style.display !== "none");
    }

    function generateMaterialCostsHTML(session) {
        const totalCost = session["总成本"] || 0;
        let html = `
            <div style="margin-top: 10px; border-top: 1px solid ${STYLE.colors.border}; padding-top: 8px;">
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <span>${isZH ? "材料成本" : "Material Costs"}:</span>
                    <strong style="color: ${STYLE.colors.gold}; text-shadow: ${STYLE.shadows.gold};">${formatNumber(totalCost)}</strong>
                </div>
                <table style="${compactTableStyle}">
                    <thead>
                        <tr>
                            <th style="${compactHeaderStyle}">${isZH ? "材料" : "Material"}</th>
                            <th style="${compactHeaderStyle}">${isZH ? "数量" : "Qty"}</th>
                            <th style="${compactHeaderStyle}">${isZH ? "成本" : "Cost"}</th>
                        </tr>
                    </thead>
                    <tbody>
        `;

        // 1. Add regular materials sorted by cost (descending)
        html += Object.entries(session["材料消耗"] || {})
            .sort(([hridA, dataA], [hridB, dataB]) => dataB.totalCost - dataA.totalCost)
            .map(([hrid, data]) => `
                <tr>
                    <td style="${compactCellStyle}">${translateItemName(hrid, data.name)}</td>
                    <td style="${compactCellStyle} text-align: right;">${formatNumber(data.count)}</td>
                    <td style="${compactCellStyle} text-align: right; color: ${STYLE.colors.gold}">${formatNumber(data.totalCost)}</td>
                </tr>
            `).join('');

        // 2. Add coins LAST if they exist
        if (session["硬币消耗"] && session["硬币消耗"].count > 0) {
            html += `
                <tr>
                    <td style="${compactCellStyle}">${isZH ? "金币" : "Coins"}</td>
                    <td style="${compactCellStyle} text-align: right;"></td>
                    <td style="${compactCellStyle} text-align: right; color: ${STYLE.colors.gold}">${formatNumber(session["硬币消耗"].totalCost)}</td>
                </tr>
            `;
        }

        html += `
                    </tbody>
                </table>
        `;

        // Protection cost display remains unchanged
        if (session["其他数据"]["保护消耗总数"] > 0) {
            html += `
                <div style="margin-top: 8px; padding-top: 8px; border-top: 1px dashed ${STYLE.colors.border}">
                    <div style="display: flex; justify-content: space-between;">
                        <span>${isZH ? "保护物品" : "Protection Item"}:</span>
                        <span>${translateItemName(
                            session["其他数据"]["保护物品HRID"],
                            session["其他数据"]["保护物品名称"]
                        )}</span>
                    </div>
                    <div style="display: flex; justify-content: space-between;">
                        <span>${isZH ? "使用数量" : "Used"}:</span>
                        <span>${session["其他数据"]["保护消耗总数"]}</span>
                    </div>
                    <div style="display: flex; justify-content: space-between;">
                        <span>${isZH ? "保护总成本" : "Protection Cost"}:</span>
                        <strong style="color: ${STYLE.colors.gold}">${formatNumber(session["其他数据"]["保护总成本"])}</strong>
                    </div>
                </div>
            `;
        }

        return html;
    }


function cleanupFloatingUI() {
    if (floatingUI && document.body.contains(floatingUI)) {
        floatingUI.remove();
    }
    cleanupFunctions.forEach(fn => fn());
    cleanupFunctions = [];
    floatingUI = null;
}

// Add this function to create/manage the toggle button
function addEnhancementPanelToggle() {
    // Find the target container
    const gamePanel = document.querySelector('[class^="EnhancingPanel_skillActionDetailContainer"]');
    if (!gamePanel) return;

    // Check if we already added our button
    if (gamePanel.querySelector('.floating-ui-toggle-button')) return;

    // Create the toggle button
    const toggleBtn = document.createElement('button');
    toggleBtn.className = 'floating-ui-toggle-button';
    toggleBtn.innerHTML = '📊'; // Icon indicating stats/UI
    toggleBtn.title = isZH ? "切换浮动面板" : "Toggle Enhancement Tracker";

    // Style the button to match the game's UI
    Object.assign(toggleBtn.style, {
        position: 'absolute',
        bottom: '5px',
        right: '5px',
        width: '24px',
        height: '24px',
        borderRadius: '4px',
        background: 'rgba(0, 0, 0, 0.7)',
        border: `1px solid ${STYLE.colors.primary}`,
        color: STYLE.colors.textPrimary,
        cursor: 'pointer',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '12px',
        zIndex: '10'
    });

    // Hover effects
    toggleBtn.addEventListener('mouseenter', () => {
        toggleBtn.style.background = 'rgba(0, 0, 0, 0.9)';
        toggleBtn.style.color = STYLE.colors.accent;
    });
    toggleBtn.addEventListener('mouseleave', () => {
        toggleBtn.style.background = 'rgba(0, 0, 0, 0.7)';
        toggleBtn.style.color = STYLE.colors.textPrimary;
    });

    // Click handler: Toggles our floating UI
    toggleBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        toggleFloatingUI(); // This is the existing function from your script
    });

    // Ensure the game panel has relative positioning
    if (getComputedStyle(gamePanel).position === 'static') {
        gamePanel.style.position = 'relative';
    }

    // Add the button to the game panel
    gamePanel.appendChild(toggleBtn);
}

// ======================
// UI NOTIFICATION SYSTEM
// ======================

function showUINotification(message, duration = 2000) {
    const notification = document.createElement("div");
    Object.assign(notification.style, {
        position: "fixed",
        bottom: "20px",
        left: "50%",
        transform: "translateX(-50%)",
        padding: '8px 12px',
        borderRadius: "4px",
        backdropFilter: 'blur(4px)',
        border: `1px solid ${STYLE.colors.primary}`,
        background: 'rgba(40, 0, 60, 0.9)',
        backgroundColor: "rgba(0, 0, 0, 0.8)",
        color: "white",
        zIndex: "10000",
        fontSize: "14px",
        animation: "fadeInOut 2s ease-in-out",
        pointerEvents: "none"
    });
    notification.textContent = message;
    document.body.appendChild(notification);

    setTimeout(() => {
        notification.style.opacity = "0";
        setTimeout(() => notification.remove(), 300);
    }, duration);
}

// ======================
// KEYBOARD SHORTCUT
// ======================

function setupKeyboardShortcut() {
    document.addEventListener("keydown", (e) => {
        if (e.key === "F9") {
            e.preventDefault();
            toggleFloatingUI();
        }
    });
}

    // ======================
    // TESTING SYSTEM
    // ======================

    function initializeTesting() {
        if (typeof GM_registerMenuCommand !== 'undefined') {
            GM_registerMenuCommand("🔧 Test Success Notifications", () => testNotifications("success"));
            GM_registerMenuCommand("🔧 Test Failure Notifications", () => testNotifications("failure"));
            GM_registerMenuCommand("✨ Test Blessed Success", () => testNotifications("blessed"));
            GM_registerMenuCommand("🌀 Test All Notifications", () => testNotifications("all"));

            GM_registerMenuCommand("💎 Test Hitting Target Level", () => {
                const level = 15;
                const type = "success";
                const targetLevel = 15;

                const isBlessed = type === "blessed";
                const isSuccess = type !== "failure";
                showNotification(
                    isBlessed ? "BLESSED!" : isSuccess ? "Success" : "Failed!",
                    isSuccess ? "success" : "failure",
                    level,
                    isBlessed
                );

                if (level >= targetLevel) {
                    showTargetAchievedCelebration(level, targetLevel);
                }
            });
        }

        window.testEnhancement = {
            success: () => testNotifications("success"),
            allSuccess: () => testNotifications("allSuccess"),
            failure: () => testNotifications("failure"),
            blessed: () => testNotifications("blessed"),
            all: () => testNotifications("all"),
            custom: (level, type, targetLevel) => {
                const isBlessed = type === "blessed";
                const isSuccess = type !== "failure";
                showNotification(
                    isBlessed ? "BLESSED!" : isSuccess ? "Success" : "Failed!",
                    isSuccess ? "success" : "failure",
                    level,
                    isBlessed
                );

                if (level >= targetLevel) {
                    showTargetAchievedCelebration(level, targetLevel);
                }
            }
        };
    }

    function testNotifications(type) {
        const tests = {
            success: [
                { level: 1, blessed: false },
                { level: 5, blessed: false },
                { level: 10, blessed: false },
                { level: 15, blessed: false },
                { level: 20, blessed: false }
            ],
            allSuccess: [
                { level: 1, blessed: false },
                { level: 2, blessed: false },
                { level: 3, blessed: false },
                { level: 4, blessed: false },
                { level: 5, blessed: false },
                { level: 6, blessed: false },
                { level: 7, blessed: false },
                { level: 8, blessed: false },
                { level: 9, blessed: false },
                { level: 10, blessed: false },
                { level: 11, blessed: false },
                { level: 12, blessed: false },
                { level: 13, blessed: false },
                { level: 14, blessed: false },
                { level: 15, blessed: false },
                { level: 16, blessed: false },
                { level: 17, blessed: false },
                { level: 18, blessed: false },
                { level: 19, blessed: false },
                { level: 20, blessed: false }
            ],
            blessed: [
                { level: 3, blessed: true },
                { level: 8, blessed: true },
                { level: 12, blessed: true },
                { level: 17, blessed: true },
                { level: 22, blessed: true }
            ],
            failure: [
                { level: 0, blessed: false }
            ],
            all: [
                { level: 1, blessed: false },
                { level: 0, blessed: false },
                { level: 3, blessed: true },
                { level: 0, blessed: false },
                { level: 10, blessed: false },
                { level: 12, blessed: true },
                { level: 15, blessed: false },
                { level: 0, blessed: false },
                { level: 20, blessed: false }
            ]
        };

        tests[type].forEach((test, i) => {
            setTimeout(() => {
                const message = test.blessed ?
                    (isZH ? `祝福强化! +${test.level}` : `BLESSED! +${test.level}`) :
                    (test.level > 0 ?
                        (isZH ? `强化成功 +${test.level}` : `Success +${test.level}`) :
                        (isZH ? "强化失败!" : "Failed!"));

                showNotification(
                    message,
                    test.level > 0 ? "success" : "failure",
                    test.level,
                    test.blessed
                );
            }, i * 800);
        });
    }

    // ======================
    // INITIALIZATION
    // ======================

    function addGlobalStyles() {
        const style = document.createElement("style");
        style.textContent = `
            @keyframes pulse {
                0% { transform: scale(1); }
                50% { transform: scale(1.05); }
                100% { transform: scale(1); }
            }
            @keyframes holyGlow {
                0% { box-shadow: 0 0 10px #FFD700; }
                50% { box-shadow: 0 0 25px #FFD700, 0 0 40px white; }
                100% { box-shadow: 0 0 10px #FFD700; }
            }
            @keyframes raysRotate {
                from { transform: rotate(0deg); }
                to { transform: rotate(360deg); }
            }
            @keyframes floatUp {
                0% { transform: translateY(0) rotate(0deg); opacity: 0; }
                10% { opacity: 0.7; }
                90% { opacity: 0.7; }
                100% { transform: translateY(-100px) rotate(20deg); opacity: 0; }
            }
            @keyframes celebrateText {
                0% { transform: scale(0.5); opacity: 0; }
                50% { transform: scale(1.2); opacity: 1; }
                100% { transform: scale(1); }
            }
            @keyframes confettiFly {
                0% { transform: translate(0,0) rotate(0deg); opacity: 1; }
                100% { transform: translate(${Math.random() > 0.5 ? '-' : ''}${Math.random() * 300 + 100}px, ${Math.random() * 300 + 100}px) rotate(360deg); opacity: 0; }
            }
            @keyframes fireworkExpand {
                0% { transform: scale(0); opacity: 1; }
                100% { transform: scale(20); opacity: 0; }
            }
            @keyframes fireworkTrail {
                0% { transform: translate(0,0); opacity: 1; }
                100% { transform: translate(${Math.random() > 0.5 ? '-' : ''}${Math.random() * 100 + 50}px, ${Math.random() * 100 + 50}px); opacity: 0; }
            }
            .enhancement-notification {
                position: relative;
                overflow: hidden;
                transition: ${STYLE.transitions.medium};
                backdrop-filter: blur(4px);
                -webkit-backdrop-filter: blur(4px);
                background: 'rgba(255, 255, 255, 0.1)',
                border: '1px solid rgba(255, 255, 255, 0.2)',
            }
            #enhancementFloatingUI {
              transition: height 0.15s ease-out, opacity 0.2s ease, transform 0.2s ease;
              height: auto;
              max-height: 80vh;
              backdrop-filter: blur(8px);
              -webkit-backdrop-filter: blur(8px);
              background: 'rgba(255, 255, 255, 0.1)',
              border: '1px solid rgba(255, 255, 255, 0.2)',
            }
            #enhancementFloatingUI.no-transition {
                transition: none !important;
            }
            #enhancementPanelContent {
                scrollbar-width: thin;
                scrollbar-color: ${STYLE.colors.border} transparent;
            }
            #enhancementPanelContent::-webkit-scrollbar {
                width: 6px;
            }

            #enhancementPanelContent::-webkit-scrollbar-thumb {
                background: ${STYLE.colors.primary};
                border-radius: 3px;
            }

            #enhancementPanelContent::-webkit-scrollbar-track {
                background: rgba(30, 0, 40, 0.4);
            }
            #enhancementFloatingUI[style*="display: none"] {
                display: block !important;
                opacity: 0;
                pointer-events: none;
                transform: translateY(10px);
            }
            #enhancementFloatingUI.dragging {
                cursor: grabbing;
                box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
                transition: none;
            }
            @keyframes floatIn {
                0% { opacity: 0; transform: translateY(10px); }
                100% { opacity: 1; transform: translateY(0); }
            }
            #enhancementFloatingUI:not([style*="display: none"]) {
                animation: floatIn 0.2s ease-out;
            }
            @keyframes fadeInOut {
                0% { opacity: 0; transform: translateX(-50%) translateY(10px); }
                20% { opacity: 1; transform: translateX(-50%) translateY(0); }
                80% { opacity: 1; transform: translateX(-50%) translateY(0); }
                100% { opacity: 0; transform: translateX(-50%) translateY(-10px); }
            }
            @keyframes mythicPulse {
                0% {
                    background-position: 0% 50%;
                    transform: scale(1);
                    box-shadow: 0 0 8px #ff0033;
                }
                50% {
                    background-position: 100% 50%;
                    transform: scale(1.05);
                    box-shadow: 0 0 16px #ff2200, 0 0 24px #ff2200;
                }
                100% {
                    background-position: 0% 50%;
                    transform: scale(1);
                    box-shadow: 0 0 8px #ff0033;
                }
            }
            #enhancementPanelHeader button {
                background: none;
                border: none;
                color: ${STYLE.colors.textPrimary};
                cursor: pointer;
                font-size: 14px;
                padding: 2px 8px;
                border-radius: 3px;
                transition: ${STYLE.transitions.fast};
                display: flex;
                align-items: center;
                justify-content: center;
                width: 24px;
                height: 24px;
            }
            #enhancementPanelHeader button:hover {
                color: ${STYLE.colors.accent};
                background: rgba(255, 255, 255, 0.1);
            }
            #enhancementPanelHeader button:active {
                transform: scale(0.9);
            }
            #enhancementPanelHeader .nav-arrows {
                display: flex;
                gap: 5px;
                margin-left: auto;
            }
            /* Enhanced scrollbar styling */
            #enhancementPanelContent > div::-webkit-scrollbar {
                width: 6px;
                height: 6px;
            }

            #enhancementPanelContent > div::-webkit-scrollbar-thumb {
                background-color: ${STYLE.colors.primary};
                border-radius: 3px;
            }

            #enhancementPanelContent > div::-webkit-scrollbar-track {
                background-color: rgba(30, 0, 40, 0.4);
                border-radius: 3px;
            }

            #enhancementPanelContent > div {
                scrollbar-width: thin;
                scrollbar-color: ${STYLE.colors.primary} rgba(30, 0, 40, 0.4);
            }

            /* Better empty state for scroll container */
            .empty-state {
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                height: 100px;
                color: ${STYLE.colors.textSecondary};
                padding: 20px;
                text-align: center;
            }
            .empty-icon {
                font-size: 32px;
                margin-bottom: 10px;
                opacity: 0.5;
            }

            .empty-text {
                font-size: 14px;
            }

            #enhancementFloatingUI:not(.has-data) {
                height: 150px !important; /* Fixed height for empty state */
            }
        `;
        document.head.appendChild(style);
    }

    function initializeFloatingUI() {
        const checkReady = setInterval(() => {
            if (document.body && typeof item_hrid_to_name !== "undefined") {
                clearInterval(checkReady);
                setupKeyboardShortcut();

                if (localStorage.getItem("enhancementUIVisible") !== "false") {
                    createFloatingUI();
                    debouncedUpdateFloatingUI();
                }
            }
        }, 500);
    }

    function initializeFloatingUIToggle() {
        // Try immediately in case the panel is already loaded
        addEnhancementPanelToggle();

        // Set up an observer to detect when the panel loads dynamically
        const observer = new MutationObserver((mutations) => {
            if (document.querySelector('[class^="EnhancingPanel_skillActionDetailContainer"]')) {
                addEnhancementPanelToggle();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // Start everything
    addGlobalStyles();
    initializeTesting();
    initializeFloatingUI();
    // Initialize market data loading when script starts
    loadMarketData();
    initializeFloatingUIToggle();
    hookWS();

    console.log("Enhancement Notifier v3.4.8 loaded");
})();