MWI Combat Suite

Tools to assist you in combat droning to appease the Queen RNG.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         MWI Combat Suite
// @namespace    http://tampermonkey.net/
// @version      0.9.36073
// @description  Tools to assist you in combat droning to appease the Queen RNG.
// @author       Frotty
// @license      MIB License
// @match        https://www.milkywayidle.com/*
// @match        https://shykai.github.io/MWICombatSimulatorTest/dist/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';
    const isShykaiSite = window.location.hostname === 'shykai.github.io';
    const isMWISite = window.location.hostname.includes('milkywayidle.com');

    window.MCS_MODULES_DISABLED = false;
    window.MCS_MODULES_INITIALIZED = false;
    window.MCS_ALL_PANEL_IDS = [];

    if (!window.MCS_CHARACTER_DATA_CACHE) {
        window.MCS_CHARACTER_DATA_CACHE = null;
    }

    if (!window.CharacterDataStorage) {
        window.CharacterDataStorage = {
        syncFromBridge() {
            try {
                const bridge = document.getElementById('equipspy-data-bridge');
                if (bridge) {
                    const fullData = bridge.getAttribute('data-character-full');
                    if (fullData) {
                        const parsed = JSON.parse(fullData);
                        const newCharName = parsed?.character?.name;
                        const cachedCharName = window.MCS_CHARACTER_DATA_CACHE?.character?.name;

                        if (!window.MCS_CHARACTER_DATA_CACHE || (newCharName && newCharName !== cachedCharName)) {
                            window.MCS_CHARACTER_DATA_CACHE = parsed;
                            console.log('[MCS] Character loaded:', newCharName);
                        }
                    }
                }
            } catch (e) {
                console.error('[CharacterDataStorage] Error syncing from bridge:', e);
            }
        },

        getCurrentCharacterName() {
            this.syncFromBridge();
            if (window.MCS_CHARACTER_DATA_CACHE?.character?.name) {
                return window.MCS_CHARACTER_DATA_CACHE.character.name;
            }
            return null;
        },

        get(characterName) {
            return window.MCS_CHARACTER_DATA_CACHE || null;
        },

        set(value, characterName) {
            if (typeof value === 'string') {
                try {
                    window.MCS_CHARACTER_DATA_CACHE = JSON.parse(value);
                } catch (e) {
                    console.error('[CharacterDataStorage] Error parsing data:', e);
                }
            } else if (value && typeof value === 'object') {
                window.MCS_CHARACTER_DATA_CACHE = value;
            }
        },

        getParsed(characterName) {
            return window.MCS_CHARACTER_DATA_CACHE || null;
        },

        setParsed(obj, characterName) {
            window.MCS_CHARACTER_DATA_CACHE = obj;
        }
        };
    }

    if (!window.ToolVisibilityStorage) {
        window.ToolVisibilityStorage = {
        getKey(characterName) {
            const charName = characterName || window.CharacterDataStorage.getCurrentCharacterName();
            return charName ? 'mcs__global_visibility_' + charName : 'mcs__global_visibility';
        },

        get(characterName) {
            const key = this.getKey(characterName);
            const data = localStorage.getItem(key);
            try {
                return data ? JSON.parse(data) : {};
            } catch (e) {
                console.error('[ToolVisibilityStorage] Error parsing visibility data:', e);
                return {};
            }
        },

        set(obj, characterName) {
            const key = this.getKey(characterName);
            try {
                localStorage.setItem(key, JSON.stringify(obj));
            } catch (e) {
                console.error('[ToolVisibilityStorage] Error saving visibility data:', e);
            }
        }
        };
    }

    if (!window.MCSEnabledStorage) {
        window.MCSEnabledStorage = {
            get(characterName) {
                try {
                    const data = JSON.parse(localStorage.getItem('mcs__global_enabled') || '{}');
                    return data[characterName] !== false;
                } catch (e) { return true; }
            },
            set(characterName, enabled) {
                try {
                    const data = JSON.parse(localStorage.getItem('mcs__global_enabled') || '{}');
                    data[characterName] = enabled;
                    localStorage.setItem('mcs__global_enabled', JSON.stringify(data));
                } catch (e) {}
            }
        };
    }

    if (!window.CharacterDataStorage) {
        window.CharacterDataStorage = CharacterDataStorage;
    }
    window.ToolVisibilityStorage = ToolVisibilityStorage;
    window.MCSEnabledStorage = MCSEnabledStorage;

    try {
        const currentCharacter = CharacterDataStorage.get();
        const characterName = currentCharacter?.character?.name || null;

        if (characterName) {
            const sessionKey = 'mcs__global_pause_session_' + characterName;
            const savedSession = localStorage.getItem(sessionKey);

            if (savedSession) {
                try {
                    const sessionData = JSON.parse(savedSession);
                    window.MCS_TOTAL_PAUSED_MS = sessionData.totalPausedMs ?? 0;
                } catch (e) {
                    window.MCS_TOTAL_PAUSED_MS = 0;
                }
            } else {
                window.MCS_TOTAL_PAUSED_MS = 0;
                localStorage.setItem(sessionKey, JSON.stringify({ totalPausedMs: 0 }));
            }
        } else {
            window.MCS_TOTAL_PAUSED_MS = 0;
        }
    } catch (e) {
        window.MCS_TOTAL_PAUSED_MS = 0;
    }
    window.MCS_PAUSE_START_TIME = null;
    window.MCS_TAB_HIDDEN_START = null;
    window.MCS_TOTAL_TAB_HIDDEN_MS = 0;

    function checkURL() {
        if (document.hidden) return;
        const currentURL = window.location.href;
        const isCharacterSelectOrHome = currentURL === 'https://www.milkywayidle.com/characterSelect' ||
                                         currentURL === 'https://www.milkywayidle.com/';

        if (isCharacterSelectOrHome && !window.MCS_MODULES_DISABLED) {
            if (window.MCS_MODULES_INITIALIZED) {
                window.MCS_MODULES_DISABLED = true;
                window.MCS_PAUSE_START_TIME = Date.now();
                window.MCS_ALL_PANEL_IDS.forEach(panelId => {
                    const panel = document.getElementById(panelId);
                    if (panel) {
                        if (panel.classList.contains('visible')) {
                            panel.dataset.hadVisibleClass = 'true';
                            panel.classList.remove('visible');
                        }
                        panel.style.setProperty('display', 'none', 'important');
                    }
                });
            }
        } else if (!isCharacterSelectOrHome && window.MCS_MODULES_DISABLED) {
            if (window.MCS_PAUSE_START_TIME) {
                const pauseDuration = Date.now() - window.MCS_PAUSE_START_TIME;
                window.MCS_TOTAL_PAUSED_MS += pauseDuration;
                try {
                    const currentCharacter = CharacterDataStorage.get();
                    const characterName = currentCharacter?.character?.name || null;
                    if (characterName) {
                        const sessionKey = 'mcs__global_pause_session_' + characterName;
                        localStorage.setItem(sessionKey, JSON.stringify({ totalPausedMs: window.MCS_TOTAL_PAUSED_MS }));
                    }
                } catch (e) {
                    console.error('[MCS] Failed to save pause time:', e);
                }
            }
            window.MCS_MODULES_DISABLED = false;
            window.MCS_PAUSE_START_TIME = null;
            window.MCS_ALL_PANEL_IDS.forEach(panelId => {
                const panel = document.getElementById(panelId);
                if (panel) {
                    if (panelId === 'mwi-combat-suite-panel') {
                        panel.classList.add('visible');
                        panel.style.removeProperty('display');
                    } else {
                        if (panel.dataset.hadVisibleClass === 'true') {
                            panel.classList.add('visible');
                            delete panel.dataset.hadVisibleClass;
                        }
                        panel.style.removeProperty('display');
                    }
                }
            });
        }

        return isCharacterSelectOrHome;
    }

    const isInitiallyPaused = checkURL();
    if (isInitiallyPaused) {
    }

    setInterval(checkURL, 500);

    window.mcs__global_equipment_tracker = {
        allCharacterItems: null,
        lastEquippedHash: null,
        playerName: null,
        processEquipmentTimeout: null,

        init() {
            console.log('[MCS] Initializing...');
            this.listenForEvents();
        },

        listenForEvents() {
            const tracker = this;

            tracker._wsListener = (e) => {
                const obj = e.detail;
                if (!obj) return;

                if (obj.type === 'battle_updated') {
                    window.MCS_IN_COMBAT = true;
                }

                try {
                    if (obj.type === 'items_updated' && obj.endCharacterItems && Array.isArray(obj.endCharacterItems)) {
                        const equippedUpdates = obj.endCharacterItems.filter(
                            item => item.itemLocationHrid && item.itemLocationHrid !== '/item_locations/inventory'
                        );

                        if (!tracker.allCharacterItems) {
                            tracker.allCharacterItems = [];
                        }

                        for (const updatedItem of obj.endCharacterItems) {
                            const existingIndex = tracker.allCharacterItems.findIndex(
                                item => item.itemHrid === updatedItem.itemHrid &&
                                        item.itemLocationHrid === updatedItem.itemLocationHrid
                            );

                            if (existingIndex >= 0) {
                                tracker.allCharacterItems[existingIndex] = updatedItem;
                            } else {
                                tracker.allCharacterItems.push(updatedItem);
                            }
                        }

                        if (equippedUpdates.length > 0) {
                            tracker.processEquipment();
                        }
                    }
                } catch (e) {
                }
            };
            window.addEventListener('EquipSpyWebSocketMessage', tracker._wsListener);

            tracker._charDataListener = (e) => {
                const obj = e.detail;
                if (!obj) return;

                try {
                    if (obj.characterItems && Array.isArray(obj.characterItems)) {
                        tracker.allCharacterItems = obj.characterItems;
                        if (obj.character && obj.character.name) {
                            tracker.playerName = obj.character.name;
                        }
                        tracker.processEquipment();
                    }
                } catch (e) {
                }
            };
            window.addEventListener('LootTrackerCharacterData', tracker._charDataListener);
        },

        removeListeners() {
            if (this._wsListener) {
                window.removeEventListener('EquipSpyWebSocketMessage', this._wsListener);
                this._wsListener = null;
            }
            if (this._charDataListener) {
                window.removeEventListener('LootTrackerCharacterData', this._charDataListener);
                this._charDataListener = null;
            }
        },

        getEquippedItems() {
            if (!this.allCharacterItems) return null;

            const equipped = [];
            for (const item of this.allCharacterItems) {
                if (item.itemLocationHrid &&
                    item.itemLocationHrid !== '/item_locations/inventory' &&
                    item.count > 0) {
                    equipped.push(item);
                }
            }

            return equipped;
        },

        buildEquipmentSlotMap() {
            const equipped = this.getEquippedItems();
            if (!equipped) return null;

            const equipmentSlots = {
                '/item_locations/head': 'Nothing',
                '/item_locations/body': 'Nothing',
                '/item_locations/legs': 'Nothing',
                '/item_locations/hands': 'Nothing',
                '/item_locations/feet': 'Nothing',
                '/item_locations/main_hand': 'Nothing',
                '/item_locations/off_hand': 'Nothing',
                '/item_locations/pouch': 'Nothing',
                '/item_locations/neck': 'Nothing',
                '/item_locations/earrings': 'Nothing',
                '/item_locations/ring': 'Nothing',
                '/item_locations/back': 'Nothing',
                '/item_locations/arrows': 'Nothing'
            };

            for (const item of equipped) {
                if (equipmentSlots.hasOwnProperty(item.itemLocationHrid)) {
                    let itemName = item.itemHrid?.split('/').pop() || 'Unknown';
                    if (item.enhancementLevel > 0) {
                        itemName += ` +${item.enhancementLevel}`;
                    }
                    equipmentSlots[item.itemLocationHrid] = itemName;
                }
            }

            return equipmentSlots;
        },

        processEquipment() {
            if (window.MCS_MODULES_DISABLED) return;

            if (this.processEquipmentTimeout) {
                clearTimeout(this.processEquipmentTimeout);
            }

            this.processEquipmentTimeout = setTimeout(() => {
                if (window.MCS_MODULES_DISABLED) return;

                this.processEquipmentTimeout = null;

                const equipped = this.getEquippedItems();
                if (!equipped || !this.playerName) return;

                const currentHash = JSON.stringify(equipped);

                if (currentHash !== this.lastEquippedHash) {
                    this.lastEquippedHash = currentHash;

                    const storageKey = `mcs__global_equipment_${this.playerName}`;
                    localStorage.setItem(storageKey, JSON.stringify(equipped));

                    window[storageKey] = equipped;

                    const slotMap = this.buildEquipmentSlotMap();

                    for (const [slot, item] of Object.entries(slotMap)) {
                        const slotName = slot.split('/').pop().padEnd(15);

                    }

                    window.dispatchEvent(new CustomEvent('MCS_EquipmentChanged', {
                        detail: { equipped, playerName: this.playerName }
                    }));
                }
            }, 50);
        }
    };

    window.mcs__global_equipment_tracker.init();

    const VisibilityManager = {
        intervals: new Map(),
        isVisible: !document.hidden,

        init() {
            document.addEventListener('visibilitychange', () => {
                this.isVisible = !document.hidden;
                if (this.isVisible) {
                    if (window.MCS_TAB_HIDDEN_START) {
                        const hiddenDuration = Date.now() - window.MCS_TAB_HIDDEN_START;
                        window.MCS_TOTAL_PAUSED_MS += hiddenDuration;
                        window.MCS_TOTAL_TAB_HIDDEN_MS += hiddenDuration;
                        window.MCS_TAB_HIDDEN_START = null;
                    }
                    this.resumeAll();
                } else {
                    window.MCS_TAB_HIDDEN_START = Date.now();
                    this.pauseAll();
                }
            });
        },

        register(name, callback, delay) {
            if (this.intervals.has(name)) {
                this.clear(name);
            }

            const wrappedCallback = PerformanceMonitor.wrap(name, callback);

            const interval = {
                callback: wrappedCallback,
                delay,
                intervalId: null,
                paused: false
            };

            if (this.isVisible) {
                interval.intervalId = setInterval(wrappedCallback, delay);
            } else {
                interval.paused = true;
            }

            this.intervals.set(name, interval);
            return name;
        },

        clear(name) {
            const interval = this.intervals.get(name);
            if (interval) {
                if (interval.intervalId) {
                    clearInterval(interval.intervalId);
                }
                this.intervals.delete(name);
            }
        },

        pauseAll() {
            for (const [name, interval] of this.intervals) {
                if (interval.intervalId) {
                    clearInterval(interval.intervalId);
                    interval.intervalId = null;
                    interval.paused = true;
                }
            }
        },

        resumeAll() {
            for (const [name, interval] of this.intervals) {
                if (interval.paused) {
                    interval.intervalId = setInterval(interval.callback, interval.delay);
                    interval.paused = false;
                }
            }
        }
    };

    VisibilityManager.init();

    const PerformanceMonitor = {
        enabled: false,
        modules: new Map(),
        measurementWindow: 5000,

        init() {
            setInterval(() => {
                if (document.hidden) return;
                if (this.enabled) this.cleanupOldMeasurements();
            }, 1000);
        },

        cleanupOldMeasurements() {
            const now = performance.now();
            const cutoff = now - this.measurementWindow;

            for (const [name, data] of this.modules) {
                data.measurements = data.measurements.filter(m => m.time >= cutoff);
            }
        },

        wrap(moduleName, fn) {
            return (...args) => {
                if (!this.enabled) return fn(...args);
                const start = performance.now();
                try {
                    const result = fn(...args);

                    if (result && typeof result.then === 'function') {
                        return result.finally(() => {
                            const elapsed = performance.now() - start;
                            this.record(moduleName, elapsed);
                        });
                    }

                    const elapsed = performance.now() - start;
                    this.record(moduleName, elapsed);
                    return result;
                } catch (error) {
                    const elapsed = performance.now() - start;
                    this.record(moduleName, elapsed);
                    throw error;
                }
            };
        },

        record(moduleName, elapsedMs) {
            if (!this.modules.has(moduleName)) {
                this.modules.set(moduleName, {
                    measurements: []
                });
            }
            const data = this.modules.get(moduleName);
            data.measurements.push({
                time: performance.now(),
                duration: elapsedMs
            });
        },

        getCpuPercent(moduleName) {
            const data = this.modules.get(moduleName);
            if (!data || data.measurements.length === 0) return 0;

            const totalTime = data.measurements.reduce((sum, m) => sum + m.duration, 0);

            const cpuPercent = (totalTime / this.measurementWindow) * 100;
            return Math.min(cpuPercent, 100);
        },

        getAllStats() {
            const stats = {};
            for (const [name, data] of this.modules) {
                const totalTime = data.measurements.reduce((sum, m) => sum + m.duration, 0);
                const callCount = data.measurements.length;

                stats[name] = {
                    cpuPercent: this.getCpuPercent(name),
                    totalTime: totalTime,
                    callCount: callCount,
                    avgTime: callCount > 0 ? totalTime / callCount : 0
                };
            }
            return stats;
        }
    };

    PerformanceMonitor.init();

    const StorageMonitor = {
        enabled: false,
        keys: new Map(),
        measurementWindow: 5000,

        init() {
            const originalGetItem = Storage.prototype.getItem;
            Storage.prototype.getItem = function(key) {
                if (StorageMonitor.enabled) StorageMonitor.recordRead(key);
                return originalGetItem.call(this, key);
            };

            const originalSetItem = Storage.prototype.setItem;
            Storage.prototype.setItem = function(key, value) {
                if (StorageMonitor.enabled) StorageMonitor.recordWrite(key);
                return originalSetItem.call(this, key, value);
            };

            if (typeof GM_getValue !== 'undefined') {
                const originalGMGet = GM_getValue;
                GM_getValue = function(key, defaultValue) {
                    if (StorageMonitor.enabled) StorageMonitor.recordRead('GM:' + key);
                    return originalGMGet(key, defaultValue);
                };
            }

            if (typeof GM_setValue !== 'undefined') {
                const originalGMSet = GM_setValue;
                GM_setValue = function(key, value) {
                    if (StorageMonitor.enabled) StorageMonitor.recordWrite('GM:' + key);
                    return originalGMSet(key, value);
                };
            }

            setInterval(() => {
                if (document.hidden) return;
                if (this.enabled) this.cleanupOldMeasurements();
            }, 1000);
        },

        recordRead(key) {
            if (!this.keys.has(key)) {
                this.keys.set(key, { reads: [], writes: [] });
            }
            this.keys.get(key).reads.push({ time: performance.now() });
        },

        recordWrite(key) {
            if (!this.keys.has(key)) {
                this.keys.set(key, { reads: [], writes: [] });
            }
            this.keys.get(key).writes.push({ time: performance.now() });
        },

        cleanupOldMeasurements() {
            const now = performance.now();
            const cutoff = now - this.measurementWindow;

            for (const [key, data] of this.keys) {
                data.reads = data.reads.filter(r => r.time >= cutoff);
                data.writes = data.writes.filter(w => w.time >= cutoff);

                if (data.reads.length === 0 && data.writes.length === 0) {
                    this.keys.delete(key);
                }
            }
        },

        getAllStats() {
            const stats = {};
            for (const [key, data] of this.keys) {
                stats[key] = {
                    reads: data.reads.length,
                    writes: data.writes.length
                };
            }
            return stats;
        }
    };

    StorageMonitor.init();

function mcsGoToMarketplace(itemHrid) {
    function getGameObject() {
        const rootEl = document.getElementById('root');
        const rootFiber = rootEl?._reactRootContainer?.current
                       || rootEl?._reactRootContainer?._internalRoot?.current;
        if (!rootFiber) return null;
        function find(fiber) {
            if (!fiber) return null;
            if (fiber.stateNode?.handleGoToMarketplace) return fiber.stateNode;
            return find(fiber.child) || find(fiber.sibling);
        }
        return find(rootFiber);
    }
    const game = getGameObject();
    if (game?.handleGoToMarketplace) {
        game.handleGoToMarketplace(itemHrid, 0);
    }
}

const StorageUtils = {
        save(key, value) {
try {
    localStorage.setItem(key, JSON.stringify(value));
    return true;
} catch (e) {
    return false;
}
        },
        load(key, defaultValue = null) {
try {
    const item = localStorage.getItem(key);
    return item ? JSON.parse(item) : defaultValue;
} catch (e) {
    return defaultValue;
}
        },
        remove(key) {
try {
    localStorage.removeItem(key);
    return true;
} catch (e) {
    return false;
}
        }
    };
    const DragHandler = {
        makeDraggable(pane, header, storageKey) {
let dragOffset = { x: 0, y: 0 };

const isModuleStorage = storageKey.match(/^mcs_[A-Z]{2}$/);
let savedPos;

if (isModuleStorage) {
    const modulePrefix = storageKey.replace('mcs_', '');
    const storage = createModuleStorage(modulePrefix);
    savedPos = storage.get('position');
} else {
    savedPos = CharacterStorageUtils.load(storageKey);
}

if (savedPos) {
    if (savedPos.top !== undefined) pane.style.top = savedPos.top + 'px';
    if (savedPos.left !== undefined) {
        pane.style.left = savedPos.left + 'px';
        pane.style.right = 'auto';
    }
}

header.classList.add('mcs-cursor-move');

const onDragMove = (e) => {
    let newLeft = e.clientX - dragOffset.x;
    let newTop = e.clientY - dragOffset.y;

    const headerRect = header.getBoundingClientRect();
    const headerHeight = headerRect.height;
    const paneRect = pane.getBoundingClientRect();

    const minLeft = -(paneRect.width - 50);
    const maxLeft = window.innerWidth - 50;
    const minTop = 0;
    const maxTop = window.innerHeight - headerHeight;

    newLeft = Math.max(minLeft, Math.min(maxLeft, newLeft));
    newTop = Math.max(minTop, Math.min(maxTop, newTop));

    pane.style.left = newLeft + 'px';
    pane.style.top = newTop + 'px';
    pane.style.right = 'auto';
};

const onDragUp = () => {
    document.removeEventListener('mousemove', onDragMove);
    document.removeEventListener('mouseup', onDragUp);
    header.classList.remove('mcs-cursor-grabbing');
    header.classList.add('mcs-cursor-move');
    const rect = pane.getBoundingClientRect();
    const posData = {
        top: rect.top,
        left: rect.left
    };

    if (isModuleStorage) {
        const modulePrefix = storageKey.replace('mcs_', '');
        const storage = createModuleStorage(modulePrefix);
        storage.set('position', posData);
    } else {
        CharacterStorageUtils.save(storageKey, posData);
    }
};

header.addEventListener('mousedown', (e) => {
    const rect = pane.getBoundingClientRect();
    dragOffset.x = e.clientX - rect.left;
    dragOffset.y = e.clientY - rect.top;
    header.classList.remove('mcs-cursor-move');
    header.classList.add('mcs-cursor-grabbing');
    document.addEventListener('mousemove', onDragMove);
    document.addEventListener('mouseup', onDragUp);
});
        }
    };

    const ResizeHandler = {
        makeResizable(pane, storageKey) {
            const corners = [
                { name: 'nw', cursor: 'nw-resize' },
                { name: 'ne', cursor: 'ne-resize' },
                { name: 'sw', cursor: 'sw-resize' },
                { name: 'se', cursor: 'se-resize' }
            ];

            corners.forEach(corner => {
                const handle = document.createElement('div');
                handle.className = `mcs-resize-handle mcs-resize-handle-${corner.name}`;
                pane.appendChild(handle);

                let startX, startY, startWidth, startHeight, startTop, startLeft;

                const onResizeMove = (e) => {
                    const dx = e.clientX - startX;
                    const dy = e.clientY - startY;

                    let newWidth = startWidth;
                    let newHeight = startHeight;
                    let newTop = startTop;
                    let newLeft = startLeft;

                    if (corner.name.includes('e')) {
                        newWidth = startWidth + dx;
                    } else if (corner.name.includes('w')) {
                        newWidth = startWidth - dx;
                        newLeft = startLeft + dx;
                    }

                    if (corner.name.includes('s')) {
                        newHeight = startHeight + dy;
                    } else if (corner.name.includes('n')) {
                        newHeight = startHeight - dy;
                        newTop = startTop + dy;
                    }

                    if (newWidth >= 200) {
                        pane.style.width = newWidth + 'px';
                        if (corner.name.includes('w')) {
                            pane.style.left = newLeft + 'px';
                            pane.style.right = 'auto';
                        }
                    }

                    if (newHeight >= 100) {
                        pane.style.height = newHeight + 'px';
                        if (corner.name.includes('n')) {
                            pane.style.top = newTop + 'px';
                        }
                    }
                };

                const onResizeUp = () => {
                    document.removeEventListener('mousemove', onResizeMove);
                    document.removeEventListener('mouseup', onResizeUp);
                    document.body.style.cursor = '';

                    const rect = pane.getBoundingClientRect();
                    const sizeKey = storageKey ? `${storageKey}_size` : null;
                    if (sizeKey) {
                        CharacterStorageUtils.save(sizeKey, {
                            width: rect.width,
                            height: rect.height
                        });
                    }

                    if (storageKey && (corner.name.includes('w') || corner.name.includes('n'))) {
                        CharacterStorageUtils.save(storageKey, {
                            top: rect.top,
                            left: rect.left
                        });
                    }
                };

                handle.addEventListener('mousedown', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    startX = e.clientX;
                    startY = e.clientY;
                    const rect = pane.getBoundingClientRect();
                    startWidth = rect.width;
                    startHeight = rect.height;
                    startTop = rect.top;
                    startLeft = rect.left;
                    document.body.style.cursor = corner.cursor;
                    document.addEventListener('mousemove', onResizeMove);
                    document.addEventListener('mouseup', onResizeUp);
                });
            });

            const sizeKey = storageKey ? `${storageKey}_size` : null;
            if (sizeKey) {
                const savedSize = StorageUtils.load(sizeKey);
                if (savedSize) {
                    if (savedSize.width !== undefined) pane.style.width = savedSize.width + 'px';
                    if (savedSize.height !== undefined) pane.style.height = savedSize.height + 'px';
                }
            }
        }
    };

    const CharacterStorageUtils = {
        _cachedPlayerKey: null,

        getPlayerKey() {
            try {
                const cachedData = CharacterDataStorage.get();
                if (cachedData) {
                    const name = cachedData?.character?.name;
                    if (name) {
                        if (this._cachedPlayerKey && this._cachedPlayerKey !== name) {
                            this._clearAllModuleCaches();
                        }
                        this._cachedPlayerKey = name;
                        return name;
                    }
                }

                if (typeof GM_getValue !== 'undefined') {
                    const gmCharData = GM_getValue('init_character_data', null);
                    if (gmCharData) {
                        const parsed = JSON.parse(gmCharData);
                        const name = parsed?.character?.name;
                        if (name) {
                            if (this._cachedPlayerKey && this._cachedPlayerKey !== name) {
                                this._clearAllModuleCaches();
                            }
                            this._cachedPlayerKey = name;
                            return name;
                        }
                    }
                }

                return 'default';
            } catch (e) {
                console.warn('[MCS] Failed to get player key:', e);
                return 'default';
            }
        },

        _clearAllModuleCaches() {
            if (window._moduleStorageInstances) {
                for (const key in window._moduleStorageInstances) {
                    if (window._moduleStorageInstances[key] && typeof window._moduleStorageInstances[key].clearCache === 'function') {
                        window._moduleStorageInstances[key].clearCache();
                    }
                }
            }
        },

        clearCache() {
            this._cachedPlayerKey = null;
        },

        save(key, value) {
            const playerKey = this.getPlayerKey();
            const fullKey = `${key}_${playerKey}`;
            return StorageUtils.save(fullKey, value);
        },

        load(key, defaultValue = null) {
            const playerKey = this.getPlayerKey();
            const fullKey = `${key}_${playerKey}`;
            return StorageUtils.load(fullKey, defaultValue);
        },

        remove(key) {
            const playerKey = this.getPlayerKey();
            const fullKey = `${key}_${playerKey}`;
            return StorageUtils.remove(fullKey);
        },

        setItem(key, value) {
            try {
                const playerKey = this.getPlayerKey();

                if (playerKey === 'default') {
                    localStorage.setItem(key, value);
                }

                const fullKey = `${key}_${playerKey}`;
                localStorage.setItem(fullKey, value);
                return true;
            } catch (e) {
                return false;
            }
        },

        getItem(key, defaultValue = null) {
            try {
                const playerKey = this.getPlayerKey();
                const fullKey = `${key}_${playerKey}`;
                const value = localStorage.getItem(fullKey);
                return value !== null ? value : defaultValue;
            } catch (e) {
                return defaultValue;
            }
        },

        removeItem(key) {
            try {
                const playerKey = this.getPlayerKey();
                const fullKey = `${key}_${playerKey}`;
                localStorage.removeItem(fullKey);
                return true;
            } catch (e) {
                return false;
            }
        }
    };

    if (!window._moduleStorageInstances) {
        window._moduleStorageInstances = {};
    }
    const _moduleStorageInstances = window._moduleStorageInstances;

    window.createModuleStorage = function(modulePrefix) {
        if (_moduleStorageInstances[modulePrefix]) {
            return _moduleStorageInstances[modulePrefix];
        }

        let cache = null;

        const instance = {
            _load() {
                if (!cache) {
                    const key = `mcs_${modulePrefix}`;
                    const data = CharacterStorageUtils.getItem(key);
                    cache = data ? JSON.parse(data) : {};
                }
                return cache;
            },

            get(key, defaultValue = null) {
                const data = this._load();
                return data[key] !== undefined ? data[key] : defaultValue;
            },

            set(key, value) {
                const data = this._load();
                data[key] = value;
                cache = data;
                CharacterStorageUtils.setItem(`mcs_${modulePrefix}`, JSON.stringify(data));
            },

            update(changes) {
                const data = this._load();
                Object.assign(data, changes);
                cache = data;
                CharacterStorageUtils.setItem(`mcs_${modulePrefix}`, JSON.stringify(data));
            },

            clearCache() {
                cache = null;
            }
        };

        _moduleStorageInstances[modulePrefix] = instance;
        return instance;
    };

    const InitClientDataCache = {
        _cachedData: null,

        get() {
            if (this._cachedData) {
                return this._cachedData;
            }

            try {
                if (typeof localStorageUtil === 'undefined' || !localStorageUtil) {
                    return null;
                }

                const clientData = localStorageUtil.getInitClientData();
                if (!clientData) return null;

                this._cachedData = clientData;
                return clientData;
            } catch (e) {
                console.error('[InitClientDataCache] Error loading initClientData:', e);
                return null;
            }
        },

        clearCache() {
            this._cachedData = null;
        },

        getAbilityDetailMap() {
            try {
                const clientData = this.get();
                return clientData?.abilityDetailMap || {};
            } catch (e) {
                console.error('[InitClientDataCache] Error loading abilityDetailMap:', e);
                return {};
            }
        },

        getLevelExperienceTable() {
            try {
                const clientData = this.get();
                return clientData?.levelExperienceTable || null;
            } catch (e) {
                console.error('[InitClientDataCache] Error loading levelExperienceTable:', e);
                return null;
            }
        },

        getItemDetailMap() {
            try {
                const clientData = this.get();
                return clientData?.itemDetailMap || {};
            } catch (e) {
                console.error('[InitClientDataCache] Error loading itemDetailMap:', e);
                return {};
            }
        },

        getHouseRoomDetailMap() {
            try {
                const clientData = this.get();
                return clientData?.houseRoomDetailMap || {};
            } catch (e) {
                console.error('[InitClientDataCache] Error loading houseRoomDetailMap:', e);
                return {};
            }
        },

        getActionDetailMap() {
            try {
                const clientData = this.get();
                return clientData?.actionDetailMap || {};
            } catch (e) {
                console.error('[InitClientDataCache] Error loading actionDetailMap:', e);
                return {};
            }
        },

        getCombatMonsterDetailMap() {
            try {
                const clientData = this.get();
                return clientData?.combatMonsterDetailMap || {};
            } catch (e) {
                console.error('[InitClientDataCache] Error loading combatMonsterDetailMap:', e);
                return {};
            }
        }
    };

    function registerPanel(panelId) {
        if (window.MCS_ALL_PANEL_IDS && !window.MCS_ALL_PANEL_IDS.includes(panelId)) {
            window.MCS_ALL_PANEL_IDS.push(panelId);
        }
    }

    function wrapPaneRemove(pane) {
        if (pane && !pane._mcsRemoveWrapped) {
            const originalRemove = pane.remove.bind(pane);
            pane.remove = function() {
                cleanupPaneListeners(pane);
                originalRemove();
            };
            pane._mcsRemoveWrapped = true;
        }
    }

    function cleanupPaneListeners(pane) {
        if (pane && pane._mcsCleanupListeners) {
            pane._mcsCleanupListeners.forEach(fn => fn());
            pane._mcsCleanupListeners = null;
        }
    }

    const FORMAT_PRESETS = {
        price:       { decimals: [2, 2, 1, 0], units: 'mixed', zero: '' },
        short:       { decimals: [1, 1, 1, 1], units: 'lower', zero: '-' },
        precise:     { decimals: [3, 3, 3, 3], units: 'upper', zero: '0' },
        abbreviated: { decimals: [1, 1, 1, 0], units: 'mixed', zero: '0' },
        cost:        { decimals: [2, 2, 1, 0], units: 'upper', zero: '0', localeSub: true },
        dps:         { decimals: [2, 2, 2, 0], units: 'upper', zero: '0', localeSub: true },
        compact:     { decimals: [0, 1, 1, 0], units: 'mixed', zero: '0' },
        detailed:    { decimals: [0, 3, 3, 3], units: 'upper', zero: '0' },
        gold:        { decimals: [0, 1, 0, 0], units: 'upper', zero: '0' },
        ihurt:       { decimals: [0, 2, 1, 0], units: 'upper', zero: '0' },
        ntally:      { decimals: [0, 2, 1, 0], units: 'upper', zero: '0', localeSub: true },
    };

    const UNIT_MAP = {
        upper: { b: 'B', m: 'M', k: 'K' },
        lower: { b: 'b', m: 'm', k: 'k' },
        mixed: { b: 'B', m: 'M', k: 'k' },
    };

    function mcsFormatCurrency(value, opts) {
        if (typeof opts === 'string') opts = FORMAT_PRESETS[opts] || FORMAT_PRESETS.price;
        const { decimals = [2, 2, 1, 0], units = 'mixed', zero = '', localeSub = false } = opts;
        const u = UNIT_MAP[units] || UNIT_MAP.mixed;

        if (value === null || value === undefined) return zero;
        if (!value) return zero;

        const abs = Math.abs(value);
        const sign = value < 0 ? '-' : '';

        if (abs >= 1e9) return sign + (abs / 1e9).toFixed(decimals[0]) + u.b;
        if (abs >= 1e6) return sign + (abs / 1e6).toFixed(decimals[1]) + u.m;
        if (abs >= 1e3) return sign + (abs / 1e3).toFixed(decimals[2]) + u.k;
        if (localeSub) return sign + Math.round(abs).toLocaleString();
        return sign + abs.toFixed(decimals[3]);
    }

    window.mcsFormatCurrency = mcsFormatCurrency;

    let _marketDataCache = null;
    let _marketDataRaw = null;
    function mcsGetMarketData() {
        try {
            const raw = localStorage.getItem('mcs__global_marketAPI_json');
            if (!raw) return _marketDataCache;
            if (raw === _marketDataRaw) return _marketDataCache;
            _marketDataRaw = raw;
            _marketDataCache = JSON.parse(raw);
        } catch (e) {
        }
        return _marketDataCache;
    }
    window.mcsGetMarketData = mcsGetMarketData;

    const _spriteCache = {};
    const _spriteDefaults = {
        items: '/game-icons/items.svg',
        items_sprite: '/static/media/items_sprite.328d6606.svg',
        skills: '/static/media/skills_sprite.3bb4d936.svg',
    };
    const _spriteSelectors = {
        items: 'svg use[href*="items"]',
        items_sprite: 'svg use[href*="items_sprite"]',
        skills: 'svg use[href*="skills_sprite"]',
    };
    function getIconSpriteUrl(sprite = 'items') {
        if (_spriteCache[sprite]) return _spriteCache[sprite];
        let url = _spriteDefaults[sprite] || _spriteDefaults.items;
        try {
            const existing = document.querySelector(_spriteSelectors[sprite] || _spriteSelectors.items);
            if (existing) {
                const href = existing.getAttribute('href');
                if (href && href.includes('#')) url = href.split('#')[0];
            }
        } catch (e) { /* DOM query for sprite URL may fail before game loads */ }
        _spriteCache[sprite] = url;
        return url;
    }

    function createItemIcon(iconId, { width = 20, height = 20, className, clickable = false, sprite = 'items', itemHrid, title } = {}) {
        const url = getIconSpriteUrl(sprite);
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('width', String(width));
        svg.setAttribute('height', String(height));
        if (className) svg.setAttribute('class', className);
        if (clickable) {
            svg.classList.add('mcs-clickable');
            if (itemHrid) svg.setAttribute('data-item-hrid', itemHrid);
            if (!title) title = 'Click to open in marketplace';
        }
        if (title) svg.setAttribute('title', title);
        const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
        use.setAttribute('href', url + '#' + iconId);
        svg.appendChild(use);
        return svg;
    }

    function createItemIconHtml(iconId, { width = 20, height = 20, className, clickable = false, sprite = 'items', itemHrid, style, title } = {}) {
        const url = getIconSpriteUrl(sprite);
        let attrs = `width="${width}" height="${height}"`;
        const classes = [];
        if (className) classes.push(className);
        if (clickable) classes.push('mcs-clickable');
        if (classes.length) attrs += ` class="${classes.join(' ')}"`;
        const styles = [];
        if (style) styles.push(style);
        if (styles.length) attrs += ` style="${styles.join('; ')}"`;
        if (clickable && itemHrid) attrs += ` data-item-hrid="${itemHrid}"`;
        if (clickable && !title) title = 'Click to open in marketplace';
        if (title) attrs += ` title="${title}"`;
        return `<svg ${attrs}><use href="${url}#${iconId}"></use></svg>`;
    }

    window.getIconSpriteUrl = getIconSpriteUrl;
    window.createItemIcon = createItemIcon;
    window.createItemIconHtml = createItemIconHtml;

    function mcsFormatDuration(seconds, format = 'clock') {
        if (seconds === null || seconds === undefined || isNaN(seconds) || seconds < 0) seconds = 0;
        const d = Math.floor(seconds / 86400);
        const h = Math.floor((seconds % 86400) / 3600);
        const m = Math.floor((seconds % 3600) / 60);
        const s = Math.floor(seconds % 60);

        if (format === 'eta') {
            if (seconds >= 86400) return (seconds / 86400).toFixed(1) + 'd';
            if (seconds >= 3600) return (seconds / 3600).toFixed(1) + 'h';
            return (seconds / 60).toFixed(1) + 'm';
        }
        if (format === 'short') {
            if (seconds < 60) return s + 's';
            if (seconds < 3600) return Math.floor(seconds / 60) + 'm';
            if (seconds < 86400) return Math.floor(seconds / 3600) + 'h';
            return Math.floor(seconds / 86400) + 'd';
        }
        if (format === 'compact') {
            if (seconds <= 0) return 'Ready!';
            const mo = Math.floor(seconds / (30 * 86400));
            const cd = Math.floor((seconds % (30 * 86400)) / 86400);
            const ch = Math.floor((seconds % 86400) / 3600);
            const cm = Math.floor((seconds % 3600) / 60);
            const parts = [];
            if (mo > 0) parts.push(mo + 'mo');
            if (cd > 0) parts.push(cd + 'd');
            if (ch > 0 && parts.length < 2) parts.push(ch + 'h');
            if (cm > 0 && parts.length < 2) parts.push(cm + 'm');
            return parts.slice(0, 2).join(' ');
        }
        if (format === 'elapsed') {
            const hp = String(h).padStart(2, '0');
            const mp = String(m).padStart(2, '0');
            const sp = String(s).padStart(2, '0');
            return d > 0 ? d + 'd ' + hp + ':' + mp + ':' + sp : hp + ':' + mp + ':' + sp;
        }
        return String(h + d * 24).padStart(2, '0') + ':' + String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0');
    }

    window.mcsFormatDuration = mcsFormatDuration;

    function mcsGetElapsedSeconds(startTime, endTime, savedPausedMs, accumulatedDuration, skipTabHidden, savedTabHiddenMs) {
        if (!startTime) return accumulatedDuration || 0;
        const now = endTime || Date.now();
        const saved = savedPausedMs ?? 0;
        let totalPausedMs = (window.MCS_TOTAL_PAUSED_MS ?? 0) - saved;
        const currentPausedMs = window.MCS_MODULES_DISABLED && window.MCS_PAUSE_START_TIME
            ? (Date.now() - window.MCS_PAUSE_START_TIME) : 0;
        let tabHiddenMs = 0;
        if (skipTabHidden) {
            const savedTH = savedTabHiddenMs ?? 0;
            totalPausedMs -= ((window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0) - savedTH);
        } else {
            tabHiddenMs = window.MCS_TAB_HIDDEN_START
                ? (Date.now() - window.MCS_TAB_HIDDEN_START) : 0;
        }
        const actualElapsedMs = (now - startTime) - totalPausedMs - currentPausedMs - tabHiddenMs;
        return (accumulatedDuration || 0) + Math.max(0, actualElapsedMs / 1000);
    }

    window.mcsGetElapsedSeconds = mcsGetElapsedSeconds;

    function mcsFormatHrid(hrid) {
        if (!hrid) return 'Unknown';
        return (hrid.split('/').pop() || '')
            .split('_')
            .map(w => w.charAt(0).toUpperCase() + w.slice(1))
            .join(' ');
    }

    window.mcsFormatHrid = mcsFormatHrid;

// Utility end

// Shykai start

const ShykaiSimulator = {
        isEnabled: false,
        isLoaded: false,
        websocketHooked: false,
        init() {
if (typeof GM_info === 'undefined') return;
this.isEnabled = GM_getValue('shykai_simulator_enabled', 'false') === 'true';
if (isShykaiSite) {
    this.loadSimulator();
} else if (this.isEnabled && isMWISite) {
    this.loadSimulator();
}
        },
        toggle() {
this.isEnabled = !this.isEnabled;
GM_setValue('shykai_simulator_enabled', String(this.isEnabled));
if (isMWISite && this.isEnabled && !this.isLoaded) {
    this.loadSimulator();
}
return this.isEnabled;
        },
        loadSimulator() {
if (this.isLoaded) {
    return;
}
if (isMWISite) {
    this.hookWebSocket();
    this.captureClientDataFromLocalStorage();
}
if (isShykaiSite) {
    this.addImportButton();
}
this.isLoaded = true;
        },
        hookWebSocket() {
if (this.websocketHooked) return;
const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
const oriGet = dataProperty.get;
dataProperty.get = function hookedGet() {
    const socket = this.currentTarget;
    if (!(socket instanceof WebSocket)) {
        return oriGet.call(this);
    }
    const msg = oriGet.call(this);
    let parsed = null;
    try {
        parsed = JSON.parse(msg);
    } catch (e) {
        return msg;
    }
    if (parsed?.type) {
        if (parsed.type === 'init_character_data') {
            GM_setValue("init_character_data", msg);
        }
        if (parsed.type === 'new_battle') {
            GM_setValue("new_battle", msg);
        }
        if (parsed.type === 'profile_shared') {
            let profileExportList = JSON.parse(GM_getValue("profile_export_list", "[]"));
            parsed.characterID = parsed.profile.characterSkills[0].characterID;
            parsed.characterName = parsed.profile.sharableCharacter.name;
            parsed.timestamp = Date.now();
            profileExportList = profileExportList.filter(
                item => item.characterID !== parsed.characterID
            );
            profileExportList.unshift(parsed);
            if (profileExportList.length > 20) {
                profileExportList.pop();
            }
            GM_setValue("profile_export_list", JSON.stringify(profileExportList));
        }
    }
    return msg;
};
Object.defineProperty(MessageEvent.prototype, "data", dataProperty);
this.websocketHooked = true;
        },
        _captureRetries: 0,
        captureClientDataFromLocalStorage: PerformanceMonitor.wrap('Shykai', function() {
const self = ShykaiSimulator;
try {
    const clientDataObj = InitClientDataCache.get();
    if (!clientDataObj) {
        if (self._captureRetries < 15) {
            self._captureRetries++;
            setTimeout(() => self.captureClientDataFromLocalStorage(), 2000);
        }
        return;
    }
    self._captureRetries = 0;
    if (clientDataObj?.type === 'init_client_data') {
        GM_setValue("init_client_data", JSON.stringify(clientDataObj));
    }
} catch (e) {
    if (self._captureRetries < 15) {
        self._captureRetries++;
        setTimeout(() => self.captureClientDataFromLocalStorage(), 2000);
    }
}
        }),
        addImportButton() {
if (this._importButtonTimer) return;
const checkElem = () => {
    if (!this.isEnabled) {
        return;
    }
    const selectedElement = document.querySelector('button#buttonImportExport');
    if (selectedElement) {
        clearInterval(this._importButtonTimer);
        this._importButtonTimer = null;
        const button = document.createElement('button');
        button.textContent = "Import solo/group";
        button.style.marginLeft = "10px";
        button.style.background = '#4CAF50';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.padding = '10px 20px';
        button.style.cursor = 'pointer';
        button.style.borderRadius = '4px';
        button.onclick = async () => {
            await this.importData(button);
        };
        selectedElement.parentNode.insertBefore(button, selectedElement.nextSibling);
    }
};
this._importButtonTimer = setInterval(checkElem, 200);
setTimeout(() => {
    clearInterval(this._importButtonTimer);
    this._importButtonTimer = null;
}, 30000);
        },
        async importData(button) {
const hasCharData = GM_getValue("init_character_data", null);
const hasClientData = GM_getValue("init_client_data", null);
if (!hasCharData || !hasClientData) {
    const missing = [];
    if (!hasCharData) missing.push('character data');
    if (!hasClientData) missing.push('client data');
    button.textContent = `Missing: ${missing.join(', ')}`;
    button.style.background = '#f44336';
    setTimeout(() => {
        button.textContent = "Import solo/group";
        button.style.background = '#4CAF50';
    }, 3000);
    return;
}
const [exportObj, playerIDs, importedPlayerPositions] = this.constructGroupExportObj();
const groupTab = document.querySelector('a#group-combat-tab');
if (groupTab) groupTab.click();
await new Promise(resolve => setTimeout(resolve, 100));
const importInputElem = document.querySelector('input#inputSetGroupCombatAll');
if (importInputElem) importInputElem.value = JSON.stringify(exportObj);
const importButton = document.querySelector('button#buttonImportSet');
if (importButton) importButton.click();
for (let i = 0; i < 5; i++) {
    const tab = document.querySelector(`a#player${i + 1}-tab`);
    if (tab) tab.textContent = playerIDs[i];
    const checkbox = document.querySelector(`input#player${i + 1}.form-check-input.player-checkbox`);
    if (checkbox) {
        checkbox.checked = importedPlayerPositions[i];
        checkbox.dispatchEvent(new Event("change"));
    }
}
const simTimeInput = document.querySelector('input#inputSimulationTime');
if (simTimeInput) simTimeInput.value = 24;
button.textContent = "Imported!";
        },
        constructGroupExportObj() {
const characterObj = JSON.parse(GM_getValue("init_character_data", "{}"));
const clientObj = JSON.parse(GM_getValue("init_client_data", "{}"));
let battleObj = null;
if (GM_getValue("new_battle", "")) {
    battleObj = JSON.parse(GM_getValue("new_battle", ""));
}
const storedProfileList = JSON.parse(GM_getValue("profile_export_list", "[]"));
const BLANK = `{"player":{"attackLevel":1,"magicLevel":1,"meleeLevel":1,"rangedLevel":1,"defenseLevel":1,"staminaLevel":1,"intelligenceLevel":1,"equipment":[]},"food":{"/action_types/combat":[{"itemHrid":""},{"itemHrid":""},{"itemHrid":""}]},"drinks":{"/action_types/combat":[{"itemHrid":""},{"itemHrid":""},{"itemHrid":""}]},"abilities":[{"abilityHrid":"","level":"1"},{"abilityHrid":"","level":"1"},{"abilityHrid":"","level":"1"},{"abilityHrid":"","level":"1"},{"abilityHrid":"","level":"1"}],"triggerMap":{},"zone":"/actions/combat/fly","simulationTime":"100","houseRooms":{"/house_rooms/dairy_barn":0,"/house_rooms/garden":0,"/house_rooms/log_shed":0,"/house_rooms/forge":0,"/house_rooms/workshop":0,"/house_rooms/sewing_parlor":0,"/house_rooms/kitchen":0,"/house_rooms/brewery":0,"/house_rooms/laboratory":0,"/house_rooms/observatory":0,"/house_rooms/dining_room":0,"/house_rooms/library":0,"/house_rooms/dojo":0,"/house_rooms/gym":0,"/house_rooms/armory":0,"/house_rooms/archery_range":0,"/house_rooms/mystical_study":0}}`;
const exportObj = {};
for (let i = 1; i <= 5; i++) exportObj[i] = BLANK;
const playerIDs = ["Player 1", "Player 2", "Player 3", "Player 4", "Player 5"];
const importedPlayerPositions = [false, false, false, false, false];
if (!characterObj?.partyInfo?.partySlotMap) {
    exportObj[1] = JSON.stringify(this.constructSelfPlayer(characterObj, clientObj));
    playerIDs[0] = characterObj.character?.name || "Player 1";
    importedPlayerPositions[0] = true;
} else {
    let i = 1;
    for (const member of Object.values(characterObj.partyInfo.partySlotMap)) {
        if (member.characterID) {
            if (member.characterID === characterObj.character.id) {
                exportObj[i] = JSON.stringify(this.constructSelfPlayer(characterObj, clientObj));
                playerIDs[i - 1] = characterObj.character.name;
                importedPlayerPositions[i - 1] = true;
            } else {
                const profile = storedProfileList.find(p => p.characterID === member.characterID);
                if (profile) {
                    exportObj[i] = JSON.stringify(this.constructPartyPlayer(profile, clientObj, battleObj));
                    playerIDs[i - 1] = profile.characterName;
                    importedPlayerPositions[i - 1] = true;
                } else {
                    playerIDs[i - 1] = "Open profile in game";
                }
            }
            i++;
        }
    }
}
return [exportObj, playerIDs, importedPlayerPositions];
        },
        constructSelfPlayer(char, client) {
const p = {
    player: { attackLevel: 1, magicLevel: 1, meleeLevel: 1, rangedLevel: 1, defenseLevel: 1, staminaLevel: 1, intelligenceLevel: 1, equipment: [] },
    food: { "/action_types/combat": [] }, drinks: { "/action_types/combat": [] }, abilities: [], triggerMap: {}, houseRooms: {}
};
for (const skill of (char.characterSkills ?? [])) {
    const type = skill.skillHrid?.split('/').pop();
    if (type) p.player[type + 'Level'] = skill.level || 1;
}
if (Array.isArray(char.characterItems)) {
    for (const item of char.characterItems) {
        if (item.itemLocationHrid && !item.itemLocationHrid.includes("/item_locations/inventory")) {
            p.player.equipment.push({
                itemLocationHrid: item.itemLocationHrid,
                itemHrid: item.itemHrid,
                enhancementLevel: item.enhancementLevel ?? 0
            });
        }
    }
} else if (char.characterEquipment) {
    for (const key in char.characterEquipment) {
        const item = char.characterEquipment[key];
        p.player.equipment.push({
            itemLocationHrid: item.itemLocationHrid,
            itemHrid: item.itemHrid,
            enhancementLevel: item.enhancementLevel ?? 0
        });
    }
}
for (let i = 0; i < 3; i++) {
    p.food["/action_types/combat"][i] = { itemHrid: "" };
    p.drinks["/action_types/combat"][i] = { itemHrid: "" };
}
const foods = char.actionTypeFoodSlotsMap?.["/action_types/combat"];
if (Array.isArray(foods)) {
    foods.forEach((item, i) => {
        if (i < 3 && item?.itemHrid) p.food["/action_types/combat"][i] = { itemHrid: item.itemHrid };
    });
}
const drinks = char.actionTypeDrinkSlotsMap?.["/action_types/combat"];
if (Array.isArray(drinks)) {
    drinks.forEach((item, i) => {
        if (i < 3 && item?.itemHrid) p.drinks["/action_types/combat"][i] = { itemHrid: item.itemHrid };
    });
}
for (let i = 0; i < 5; i++) p.abilities[i] = { abilityHrid: "", level: "1" };
let idx = 1;
const abilities = char.combatUnit?.combatAbilities ?? [];
for (const ab of abilities) {
    if (ab && client.abilityDetailMap?.[ab.abilityHrid]?.isSpecialAbility) {
        p.abilities[0] = { abilityHrid: ab.abilityHrid || "", level: String(ab.level || 1) };
    } else if (ab?.abilityHrid && idx < 5) {
        p.abilities[idx++] = { abilityHrid: ab.abilityHrid || "", level: String(ab.level || 1) };
    }
}
p.triggerMap = { ...(char.abilityCombatTriggersMap ?? {}), ...(char.consumableCombatTriggersMap ?? {}) };
for (const house of Object.values(char.characterHouseRoomMap ?? {})) {
    p.houseRooms[house.houseRoomHrid] = house.level;
}
p.achievements = {};
if (char.characterAchievements) {
    for (const achievement of char.characterAchievements) {
        if (achievement.achievementHrid && achievement.isCompleted) {
            p.achievements[achievement.achievementHrid] = true;
        }
    }
}
return p;
        },
        constructPartyPlayer(profile, client, battle) {
const p = {
    player: {
        attackLevel: 1, magicLevel: 1, meleeLevel: 1, rangedLevel: 1,
        defenseLevel: 1, staminaLevel: 1, intelligenceLevel: 1, equipment: []
    },
    food: { "/action_types/combat": [] },
    drinks: { "/action_types/combat": [] },
    abilities: [],
    triggerMap: {},
    houseRooms: {}
};
for (const skill of (profile.profile?.characterSkills ?? [])) {
    const type = skill.skillHrid?.split('/').pop();
    if (type) p.player[type + 'Level'] = skill.level || 1;
}
if (profile.profile?.wearableItemMap) {
    for (const key in profile.profile.wearableItemMap) {
        const item = profile.profile.wearableItemMap[key];
        p.player.equipment.push({
            itemLocationHrid: item.itemLocationHrid,
            itemHrid: item.itemHrid,
            enhancementLevel: item.enhancementLevel ?? 0
        });
    }
}
for (let i = 0; i < 3; i++) {
    p.food["/action_types/combat"][i] = { itemHrid: "" };
    p.drinks["/action_types/combat"][i] = { itemHrid: "" };
}
let battlePlayer = null;
if (battle?.players) {
    battlePlayer = battle.players.find(player => player.character?.id === profile.characterID
    );
}
if (battlePlayer?.combatConsumables) {
    let foodIndex = 0;
    let drinkIndex = 0;
    battlePlayer.combatConsumables.forEach(consumable => {
        const itemHrid = consumable.itemHrid;
        const isDrink = itemHrid.includes('/drinks/') ||
            itemHrid.includes('coffee') ||
            client.itemDetailMap?.[itemHrid]?.type === 'drink';
        if (isDrink && drinkIndex < 3) {
            p.drinks["/action_types/combat"][drinkIndex++] = { itemHrid: itemHrid };
        } else if (!isDrink && foodIndex < 3) {
            p.food["/action_types/combat"][foodIndex++] = { itemHrid: itemHrid };
        }
    });
}
for (let i = 0; i < 5; i++) {
    p.abilities[i] = { abilityHrid: "", level: "1" };
}
let idx = 1;
const abilities = profile.profile?.equippedAbilities ?? [];
for (const ab of abilities) {
    if (ab && client.abilityDetailMap?.[ab.abilityHrid]?.isSpecialAbility) {
        p.abilities[0] = {
            abilityHrid: ab.abilityHrid || "",
            level: String(ab.level || 1)
        };
    } else if (ab?.abilityHrid && idx < 5) {
        p.abilities[idx++] = {
            abilityHrid: ab.abilityHrid || "",
            level: String(ab.level || 1)
        };
    }
}
p.triggerMap = {
    ...((battlePlayer?.abilityCombatTriggersMap ?? profile.profile?.abilityCombatTriggersMap) ?? {}),
    ...((battlePlayer?.consumableCombatTriggersMap ?? profile.profile?.consumableCombatTriggersMap) ?? {})
};
if (profile.profile?.characterHouseRoomMap) {
    for (const house of Object.values(profile.profile.characterHouseRoomMap)) {
        p.houseRooms[house.houseRoomHrid] = house.level;
    }
}
p.achievements = {};
if (profile.profile?.characterAchievements) {
    for (const achievement of profile.profile.characterAchievements) {
        if (achievement.achievementHrid && achievement.isCompleted) {
            p.achievements[achievement.achievementHrid] = true;
        }
    }
}
return p;
        },
    };
    ShykaiSimulator.init();

// Shykai end

    // MWI start

    if (isMWISite) {

// Helper start

function createForceLoadEquipmentButton() {
return `
        <button id="spy-force-load-btn" class="mcs-helper-force-btn">
🔄 Force Load Equipment
        </button>
    `;
        }
        function forceExtractEquipmentData() {
const loadingMessage = document.getElementById('spy-content');
if (loadingMessage) {
    loadingMessage.innerHTML = `
<div class="mcs-helper-loading">
    <div class="mcs-helper-spinner">⚙️</div>
    <br><br>
    Force loading equipment data...<br>
    <small>Extracting from game UI...</small>
</div>
        `;
}
if (window.lootDropsTrackerInstance && typeof window.lootDropsTrackerInstance.extractEquipmentFromUI === 'function') {
    try {
        const extracted = window.lootDropsTrackerInstance.extractEquipmentFromUI();
        if (extracted && extracted.length > 0) {
            handleForceLoadSuccess(extracted);
            return;
        }
    } catch (e) {
        console.error('[EquipSpy FORCE LOAD] extractEquipmentFromUI error:', e);
    }
}
const reactItems = attemptReactFiberExtraction();
if (reactItems && reactItems.length > 0) {
    handleForceLoadSuccess(reactItems);
    return;
}
const bridgeItems = attemptBridgeDataExtraction();
if (bridgeItems && bridgeItems.length > 20) {
    handleForceLoadSuccess(bridgeItems);
    return;
}
setTimeout(() => {
    const deepItems = attemptDeepReactSearch();
    if (deepItems && deepItems.length > 0) {
        handleForceLoadSuccess(deepItems);
    } else {
        console.error('[EquipSpy FORCE LOAD] All methods FAILED');
        handleForceLoadFailure();
    }
}, 500);
        }
        function attemptReactFiberExtraction() {
try {
    const rootElement = document.querySelector('#root') || document.body;
    if (!rootElement) return null;
    const keys = Object.keys(rootElement);
    for (const key of keys) {
        if (key.startsWith('__reactContainer') || key.startsWith('__reactFiber') || key.startsWith('__reactInternalInstance')) {
            const reactData = rootElement[key];
            const items = deepSearchForCharacterItems(reactData, 0, 15);
            if (items && Array.isArray(items) && items.length > 0) {
                return items;
            }
        }
    }
} catch (e) {
    console.error('[EquipSpy FORCE LOAD] React Fiber extraction failed:', e);
}
return null;
        }
        function attemptDeepReactSearch() {
try {
    const rootSelectors = ['#root', 'body', '[data-reactroot]', '.app'];
    for (const selector of rootSelectors) {
        const element = document.querySelector(selector);
        if (!element) continue;
        const allKeys = Object.getOwnPropertyNames(element);
        for (const key of allKeys) {
            if (key.includes('react') || key.includes('fiber') || key.includes('React')) {
                try {
                    const items = deepSearchForCharacterItems(element[key], 0, 15);
                    if (items) return items;
                } catch (e) { /* React internals may throw on property access */ }
            }
        }
    }
} catch (e) {
    console.error('[EquipSpy FORCE LOAD] Deep search failed:', e);
}
return null;
        }
        function attemptBridgeDataExtraction() {
try {
    const bridge = document.getElementById('equipspy-data-bridge');
    if (!bridge) return null;
    const charData = bridge.getAttribute('data-character-items');
    if (!charData) return null;
    const items = JSON.parse(charData);
    if (Array.isArray(items) && items.length > 0) {
        return items;
    }
} catch (e) {
    console.error('[EquipSpy] Bridge extraction failed:', e);
}
return null;
        }
        function deepSearchForCharacterItems(node, depth, maxDepth, visited = new WeakSet()) {
if (depth > maxDepth || !node || typeof node !== 'object') return null;
if (visited.has(node)) return null;
visited.add(node);
if (node.characterItems && Array.isArray(node.characterItems)) {
    return node.characterItems;
}
const fiberProps = ['child', 'sibling', 'return', 'alternate', 'memoizedState', 'memoizedProps', 'pendingProps', 'stateNode', '_owner', 'type'];
for (const prop of fiberProps) {
    if (node[prop]) {
        const result = deepSearchForCharacterItems(node[prop], depth + 1, maxDepth, visited);
        if (result) return result;
    }
}
try {
    for (const key in node) {
        if (key === 'characterItems' && Array.isArray(node[key])) {
            return node[key];
        }
        if (typeof node[key] === 'object' && node[key] !== null && !key.startsWith('__') && depth < 10) {
            const result = deepSearchForCharacterItems(node[key], depth + 1, maxDepth, visited);
            if (result) return result;
        }
    }
} catch (e) { /* React fiber traversal may throw on circular refs */ }
return null;
        }
        function handleForceLoadSuccess(items) {
let characterData = null;
try {
    characterData = CharacterDataStorage.get();
} catch (e) {
    console.error('[EquipSpy] Error reading from storage:', e);
}
const sourceItems = characterData?.characterItems || items;
const equippedItems = [];
for (const item of sourceItems) {
    if (!item.itemLocationHrid.includes("/item_locations/inventory")) {
        equippedItems.push(item);
    }
}
const event = new CustomEvent('EquipSpyForceLoadSuccess', {
    detail: { items: equippedItems }
});
window.dispatchEvent(event);
        }
        function handleForceLoadFailure() {
const content = document.getElementById('spy-content');
if (!content) return;
content.innerHTML = `
        <div class="mcs-helper-failure">
<div class="mcs-helper-failure-icon">❌</div>
<strong>Force load failed</strong>
<br><br>
Unable to extract equipment data.
<br><br>
<strong>Try:</strong><br>
1. Refresh the page (F5)<br>
2. Change combat zones<br>
3. Equip/unequip an item<br>
<br>
${createForceLoadEquipmentButton()}
        </div>
    `;
setTimeout(() => {
    const btn = document.getElementById('spy-force-load-btn');
    if (btn) {
        btn.addEventListener('click', forceExtractEquipmentData);
    }
}, 100);
        }

// Helper end

        if (window._MCS_FLOOT_INITIALIZED) {
        } else {
            window._MCS_FLOOT_INITIALIZED = true;
        }

        if (!window._equipSpyPageLoadTime) {
        window._equipSpyPageLoadTime = Date.now();
                }
                const CUSTOM_SORT_KEY = 'lootDropsCustomSortPref';
                const SORT_MODES = ['name', 'value', 'quantity'];
                const fixedValueChests = new Set([
        'medium treasure chest', 'large treasure chest', 'small treasure chest'
                ]);
                let marketData = {};
                let chestValueCache = {};
                let itemPriceCache = {};
                let dollarThreshold = null;
                let dollarTagEnabled = false;
                const viewModeState = {};
                let inventoryPricesEnabled = true;
                let inventoryState = new Map();
                let marketWarningsEnabled = true;
                let inventoryWarningsEnabled = true;

                let _useAskPrice = false;

                const flStorage = createModuleStorage('FL');

                function initializePriceToggleButtons() {
                    const CONFIG = {
                        CONTAINER_ID: 'milt-loot-drops-display'
                    };

                    const priceToggleBtn = document.getElementById(`${CONFIG.CONTAINER_ID}-price-toggle`);
                    const priceToggleBtnHidden = document.getElementById(`${CONFIG.CONTAINER_ID}-price-toggle-hidden`);

                    function updateButtonAppearance(useAsk) {
                        const btnText = useAsk ? 'Showing Ask' : 'Showing Bid';
                        const btnColor = useAsk ? '#6495ED' : '#4CAF50';
                        const btnBg = useAsk ? 'rgba(100, 149, 237, 0.3)' : 'rgba(76, 175, 80, 0.3)';

                        if (priceToggleBtn) {
                            priceToggleBtn.textContent = btnText;
                            priceToggleBtn.style.color = btnColor;
                            priceToggleBtn.style.borderColor = btnColor;
                            priceToggleBtn.style.backgroundColor = btnBg;
                        }
                        if (priceToggleBtnHidden) {
                            priceToggleBtnHidden.textContent = btnText;
                            priceToggleBtnHidden.style.color = btnColor;
                            priceToggleBtnHidden.style.borderColor = btnColor;
                            priceToggleBtnHidden.style.backgroundColor = btnBg;
                        }
                    }

                    updateButtonAppearance(_useAskPrice);

                    if (priceToggleBtn) {
                        priceToggleBtn.onclick = () => {
                            _useAskPrice = !_useAskPrice;
                            flStorage.set('use_ask_price', _useAskPrice);
                            updateButtonAppearance(_useAskPrice);
                            recalculateAllPrices();
                            setTimeout(() => {
                                updateAllInventoryPrices(true);
                            }, 150);
                        };
                    }
                    if (priceToggleBtnHidden) {
                        priceToggleBtnHidden.onclick = () => {
                            _useAskPrice = !_useAskPrice;
                            flStorage.set('use_ask_price', _useAskPrice);
                            updateButtonAppearance(_useAskPrice);
                            recalculateAllPrices();
                            setTimeout(() => {
                                updateAllInventoryPrices(true);
                            }, 150);
                        };
                    }
                }

                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', () => {
                        setTimeout(initializePriceToggleButtons, 2500);
                    });
                } else {
                    setTimeout(initializePriceToggleButtons, 2500);
                }

                let useFullNumbers = true;

                function formatAbbreviated(value) {
                    return mcsFormatCurrency(value, 'abbreviated');
                }

                function formatCoins(value) {
                    const formatted = useFullNumbers ? Math.round(value).toLocaleString() : formatAbbreviated(value);
                    return `${formatted} coin`;
                }

                function formatNumberWithCommas(value) {
                    if (useFullNumbers) {
                        return Math.round(value).toLocaleString();
                    } else {
                        return formatAbbreviated(value);
                    }
                }

                function capitalizeEachWord(str) {
        return str.split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
                }
                async function loadMarketData() {
        try {
            const res = await fetch('https://www.milkywayidle.com/game_data/marketplace.json');
            const json = await res.json();
            marketData = json.marketData ?? {};
            localStorage.setItem('mcs__global_marketAPI_json', JSON.stringify(json));
            await calculateChestValues();
        } catch (e) {
            console.error('[Frotty Loot] Failed to load market data:', e);
            try {
                const cached = mcsGetMarketData();
                if (cached) {
                    marketData = cached.marketData ?? {};
                }
            } catch (cacheError) {
                console.error('[Floot] Failed to recover from cache:', cacheError);
            }
        }
                }
                async function calculateChestValues() {
        try {
            const initData = InitClientDataCache.get();
            if (!initData || !initData.openableLootDropMap) {
                console.warn('[Frotty Loot] No openableLootDropMap found');
                return;
            }
            const itemHridToName = {};
            if (initData.itemDetailMap) {
                for (const key in initData.itemDetailMap) {
                    const item = initData.itemDetailMap[key];
                    if (item && item.name) {
                        itemHridToName[key] = item.name;
                    }
                }
            }
            const useCowbell0 = typeof window.getTreasureUseCowbell0 === 'function' ? window.getTreasureUseCowbell0() : false;
            const specialItemPrices = {
                'Coin': {
                    ask: 1,
                    bid: 1
                },
                'Cowbell': {
                    ask: useCowbell0 ? 0 : ((marketData['/items/bag_of_10_cowbells']?.['0']?.a || 360000 * 0.82)) / 10,
                    bid: useCowbell0 ? 0 : ((marketData['/items/bag_of_10_cowbells']?.['0']?.b || 350000 * 0.82)) / 10
                }
            };
            const formattedChestDropData = {};
            for (let iteration = 0; iteration < 4; iteration++) {
                for (let [chestHrid, items] of Object.entries(initData.openableLootDropMap)) {
                    const chestName = itemHridToName[chestHrid] || formatItemName(chestHrid);
                    if (!formattedChestDropData[chestName]) {
                        formattedChestDropData[chestName] = { items: {} };
                    }
                    let totalAsk = 0;
                    let totalBid = 0;
                    items.forEach(item => {
                        const { itemHrid, dropRate, minCount, maxCount } = item;
                        if (dropRate < 0.01) return;
                        const itemName = itemHridToName[itemHrid] || formatItemName(itemHrid);
                        const expectedYield = ((minCount + maxCount) / 2) * dropRate;
                        let askPrice = 0;
                        let bidPrice = 0;
                        if (specialItemPrices[itemName]) {
                            askPrice = specialItemPrices[itemName].ask || 0;
                            bidPrice = specialItemPrices[itemName].bid || 0;
                        }
                        else if (marketData[itemHrid] && marketData[itemHrid]["0"]) {
                            askPrice = marketData[itemHrid]["0"].a || 0;
                            bidPrice = marketData[itemHrid]["0"].b || 0;
                        }
                        const taxFactor = (itemName in specialItemPrices) ? 1 : 0.98;
                        totalAsk += (askPrice * expectedYield) * taxFactor;
                        totalBid += (bidPrice * expectedYield) * taxFactor;
                    });
                    formattedChestDropData[chestName] = {
                        ...formattedChestDropData[chestName],
                        expectedAsk: totalAsk,
                        expectedBid: totalBid
                    };
                    specialItemPrices[chestName] = {
                        ask: totalAsk,
                        bid: totalBid
                    };
                }
            }
            for (let [chestHrid, items] of Object.entries(initData.openableLootDropMap)) {
                const chestName = itemHridToName[chestHrid] || formatItemName(chestHrid);
                if (formattedChestDropData[chestName]) {
                    chestValueCache[chestHrid] = formattedChestDropData[chestName];
                }
            }
        } catch (error) {
            console.error('[Frotty Loot] Error calculating chest values:', error);
        }
                }
                function formatItemName(hrid) {
        return mcsFormatHrid(hrid);
                }
                function getUnitValue(name, sessionKey = 'live', enhancementLevel = 0, priceType = null) {
        const normalized = name;
        if (normalized === '/items/coin') return 1;
        if (normalized === '/items/cowbell') {
            const useCowbell0 = typeof window.getTreasureUseCowbell0 === 'function' ? window.getTreasureUseCowbell0() : false;
            if (useCowbell0) return 0;
            const useAsk = (priceType !== null) ? (priceType === 'ask') : _useAskPrice;
            const bagPrice = marketData['/items/bag_of_10_cowbells']?.['0'];
            if (bagPrice) {
                const price = useAsk ? (bagPrice.a || 360000) : (bagPrice.b || 350000);
                return Math.floor((price / 10) * 0.98);
            }
            return useAsk ? 35280 : 34300;
        }
        const useAsk = (priceType !== null) ? (priceType === 'ask') : _useAskPrice;
        const cacheKey = `${sessionKey}|${normalized}|${enhancementLevel}|${useAsk ? 'ask' : 'bid'}`;
        if (itemPriceCache[cacheKey] !== undefined) {
            if (normalized.includes('treasure_chest')) {
            }
            return itemPriceCache[cacheKey];
        }
        let calculatedPrice;
        if (chestValueCache[normalized]) {
            const chestData = chestValueCache[normalized];
            calculatedPrice = useAsk ? chestData.expectedAsk : chestData.expectedBid;
        }
        else if (marketData[name] && marketData[name][enhancementLevel.toString()]) {
            const priceValue = useAsk ?
                marketData[name][enhancementLevel.toString()].a :
                marketData[name][enhancementLevel.toString()].b;
            if (priceValue <= 0) {
                return null;
            }
            if (priceValue < 900) {
                calculatedPrice = Math.floor(priceValue * 0.98);
            } else {
                calculatedPrice = Math.ceil(priceValue * 0.98);
            }
        } else {
            return null;
        }
        itemPriceCache[cacheKey] = calculatedPrice;
        return calculatedPrice;
                }
                window.getUnitValue = getUnitValue;
                window.formatFlootCoins = formatCoins;
                window.getFlootUseAskPrice = () => _useAskPrice;
                window.updateAllInventoryPrices = updateAllInventoryPrices;
                window.updateNtallyIndicators = updateNtallyIndicators;
                function clearSessionPriceCache(sessionKey) {
        if (!sessionKey) return;
        const keysToDelete = Object.keys(itemPriceCache).filter(key => key.startsWith(sessionKey + '|'));
        keysToDelete.forEach(key => delete itemPriceCache[key]);
                }
                let _cachedPlayerSections = null;
                let _playerSectionsCacheTime = 0;
                const PLAYER_SECTIONS_CACHE_TTL = 2000;

                function getCachedPlayerSections() {
                    const now = Date.now();
                    if (!_cachedPlayerSections || now - _playerSectionsCacheTime > PLAYER_SECTIONS_CACHE_TTL) {
                        _cachedPlayerSections = document.querySelectorAll('.ldt-player-stats-section');
                        _playerSectionsCacheTime = now;
                    }
                    return _cachedPlayerSections;
                }

                function invalidatePlayerSectionsCache() {
                    _cachedPlayerSections = null;
                    _playerSectionsCacheTime = 0;
                }

                function recalculateAllPrices() {
        itemPriceCache = {};
        if (window.lootDropsTrackerInstance) {
            window.lootDropsTrackerInstance.renderCurrentView();
        }
        setTimeout(() => {
            if (window.lootDropsTrackerInstance) {
                window.lootDropsTrackerInstance.updateSpyDisplay();
            }
        }, 100);
        window.dispatchEvent(new CustomEvent('FlootPricesUpdated'));
                }
                function updateGoldPerDay() {
        if (!window.lootDropsTrackerInstance) return;
        let hoursElapsed = 0;
        if (window.lootDropsTrackerInstance.startTime &&
            window.lootDropsTrackerInstance.isLiveSessionActive) {
            const elapsedMs = Date.now() - window.lootDropsTrackerInstance.startTime.getTime();
            hoursElapsed = elapsedMs / (1000 * 60 * 60);
        }
        if (hoursElapsed < 0.01) return;
        const userName = window.lootDropsTrackerInstance.userName;
        const playerStats = window.lootDropsTrackerInstance.playerDropStats;
        if (!playerStats) return;

        const playerRevenue = {};
        for (const playerName in playerStats) {
            const items = playerStats[playerName].items ?? {};
            let total = 0;
            for (const hrid in items) {
                const count = items[hrid];
                const unitValue = getUnitValue(hrid, 'live');
                if (unitValue !== null) {
                    total += unitValue * count;
                }
            }
            const perDay = total > 0 ? (total / hoursElapsed) * 24 : 0;
            playerRevenue[playerName] = { total, perDay };
        }
        window.lootDropsTrackerInstance.flootPlayerRevenue = playerRevenue;

        const userRevenue = playerRevenue[userName];
        if (userRevenue && userRevenue.total > 0) {
            window.lootDropsTrackerInstance.goldPerDay = userRevenue.perDay;
            window.lootDropsTrackerInstance.goldPerDayFormatted = formatCoins(userRevenue.perDay);
            if (window.lootDropsTrackerInstance.updateCoinHeader) {
                window.lootDropsTrackerInstance.updateCoinHeader();
            }
        }
                }
                function injectValuesAndSort() {
        updateGoldPerDay();
        if (window._isRendering) {
            return;
        }
        const sortPref = 'value';
        const playerSections = getCachedPlayerSections();
        let hoursElapsed = 0;

        const currentSession = window.lootDropsTrackerInstance?.getCurrentHistoryViewItem?.();
        if (currentSession && currentSession.duration) {
            hoursElapsed = currentSession.duration / (1000 * 60 * 60);
        } else if (window.lootDropsTrackerInstance &&
            window.lootDropsTrackerInstance.startTime &&
            window.lootDropsTrackerInstance.isLiveSessionActive) {
            const elapsedMs = Date.now() - window.lootDropsTrackerInstance.startTime.getTime();
            hoursElapsed = elapsedMs / (1000 * 60 * 60);
        }
        const currentSessionKey = window.lootDropsTrackerInstance?.viewingLive ?
            'live' :
            (window.lootDropsTrackerInstance?.domRefs?.historySelect?.value || 'live');

        let playerStats = window.lootDropsTrackerInstance?.playerDropStats ?? {};
        if (currentSession && currentSession.stats) {
            playerStats = currentSession.stats;
        } else if (!window.lootDropsTrackerInstance?.viewingLive) {
            const selectedValue = window.lootDropsTrackerInstance?.domRefs?.historySelect?.value;
            if (selectedValue === 'combined' && window.lootDropsTrackerInstance?.aggregatedHistoryData) {
                playerStats = window.lootDropsTrackerInstance.aggregatedHistoryData;
            } else if (selectedValue && selectedValue !== 'live') {
                const selectedSession = window.lootDropsTrackerInstance?.sessionHistory?.find(s => s.key === selectedValue);
                if (selectedSession && selectedSession.stats) {
                    playerStats = selectedSession.stats;
                }
            }
        }
        setTimeout(() => {
            const hiddenPlayersContainer = document.getElementById('milt-loot-drops-display-hidden-players');
            if (hiddenPlayersContainer && window.lootDropsTrackerInstance) {
                const userName = window.lootDropsTrackerInstance.userName;
                let html = '';
                if (playerStats && Object.keys(playerStats).length > 0) {
                    for (const playerName in playerStats) {
                        const items = playerStats[playerName].items ?? {};
                        let total = 0;
                        for (const hrid in items) {
                            const count = items[hrid];
                            const unitValue = getUnitValue(hrid, currentSessionKey);
                            if (unitValue !== null) {
                                total += unitValue * count;
                            }
                        }
                        const totalText = total > 0 ? formatCoins(total) : '--';
                        const goldPerDayText = (hoursElapsed > 0 && total > 0)
                            ? formatCoins(Math.round((total / hoursElapsed) * 24))
                            : '';
                        const playerClass = (playerName === userName) ? 'is-current' : '';
                        html += `
                    <div class="ldt-hidden-player-row">
                        <div class="ldt-hidden-player-name ${playerClass}">${playerName}</div>
                        <div class="ldt-hidden-player-stats">
                            <span class="ldt-hidden-coin-emoji">💰</span>
                            <span class="ldt-hidden-coin-amount">${totalText}</span>
                            <span class="ldt-hidden-coin-rate">${goldPerDayText ? goldPerDayText + '/day' : ''}</span>
                        </div>
                    </div>
                `;
                    }
                } else {
                    html = '<div class="ldt-hidden-player-row"><span>No loot tracked</span></div>';
                }
                hiddenPlayersContainer.innerHTML = html;
            }
        }, 0);
        playerSections.forEach((section) => {
            const header = section.querySelector('.ldt-player-name-header');
            header.querySelectorAll('span[data-value-injected]').forEach(el => el.remove());
            const playerName = header?.textContent?.split('(')[0]?.trim() || 'Unknown';
            const rows = Array.from(section.querySelectorAll('.ldt-loot-item-entry'));
            rows.forEach(row => {
                const nameEl = row.querySelector('.ldt-item-name');
                const valueEl = row.querySelector('.ldt-item-value');
                if (nameEl && valueEl) {
                    const name = nameEl.textContent.trim();
                    let unitValue = getUnitValue(name, currentSessionKey);
                    const scam = (!_useAskPrice && unitValue !== null) ? detectScamBid(name) : { isScamBid: false, isEqualToVendor: false };
                    if (scam.isScamBid) unitValue = scam.vendorValue;

                    valueEl.textContent = (unitValue !== null) ? formatNumberWithCommas(unitValue) : 'N/A';
                    if (scam.isScamBid) {
                        valueEl.style.color = '#ff1744';
                        valueEl.style.fontWeight = 'bold';
                    } else if (scam.isEqualToVendor) {
                        valueEl.style.color = '#FFD700';
                        valueEl.style.fontWeight = 'bold';
                    } else {
                        valueEl.style.color = '';
                        valueEl.style.fontWeight = '';
                    }
                }
            });
            let total = 0;
            const playerItems = playerStats[playerName]?.items ?? {};

            const itemData = rows.map((row) => {
                const nameEl = row.querySelector('.ldt-item-name');
                const valueEl = row.querySelector('.ldt-item-value');
                const countEl = row.querySelector('.ldt-item-count');
                const name = nameEl?.textContent.trim() || '';

                const count = playerItems[name] || 0;

                let unitValue = getUnitValue(name, currentSessionKey);
                const scam2 = (!_useAskPrice && unitValue !== null) ? detectScamBid(name) : { isScamBid: false, isEqualToVendor: false };
                if (scam2.isScamBid) unitValue = scam2.vendorValue;

                const itemValue = (unitValue !== null) ? (unitValue * count) : 0;

                if (valueEl) {
                    valueEl.textContent = (unitValue !== null ? formatNumberWithCommas(unitValue) : 'N/A');
                    if (scam2.isScamBid) {
                        valueEl.style.color = '#ff1744';
                        valueEl.style.fontWeight = 'bold';
                    } else if (scam2.isEqualToVendor) {
                        valueEl.style.color = '#FFD700';
                        valueEl.style.fontWeight = 'bold';
                    } else {
                        valueEl.style.color = '';
                        valueEl.style.fontWeight = '';
                    }
                }
                if (unitValue !== null) {
                    total += itemValue;
                }
                row.style.border = '';
                if (dollarTagEnabled && dollarThreshold && unitValue !== null && unitValue >= dollarThreshold) {
                    row.style.border = '3px solid rgba(0, 255, 0, 0.5)';
                }
                return { row, name, count, value: itemValue, nameEl, countEl, valueEl, unitValue };
            });
            const headerForTotal = header;
            const playerNameForTotal = playerName;

            itemData.sort((a, b) => {
                if (sortPref === 'value') {
                    if (b.value > a.value) return 1;
                    if (b.value < a.value) return -1;
                    if (b.count > a.count) return 1;
                    if (b.count < a.count) return -1;
                    return a.name.localeCompare(b.name);
                }
                if (sortPref === 'quantity') return b.count - a.count || a.name.localeCompare(b.name);
                return a.name.localeCompare(b.name);
            });
            itemData.forEach(({ valueEl, unitValue }) => {
                if (valueEl) {
                    valueEl.textContent = (unitValue !== null) ? formatNumberWithCommas(unitValue) : 'N/A';
                }
            });
            const list = section.querySelector('.ldt-loot-list');
            if (!list) return;
            itemData.forEach(({ row }) => list.appendChild(row));
            let existingTotalSpan = headerForTotal.querySelector('span[data-value-injected="total"]');
            if (existingTotalSpan) {
                existingTotalSpan.remove();
            }
            let existingRateSpan = headerForTotal.querySelector('span[data-value-injected="rate"]');
            if (existingRateSpan) {
                existingRateSpan.remove();
            }
            const span = document.createElement('span');
            span.setAttribute('data-value-injected', 'total');
            span.style.fontWeight = 'normal';
            span.style.cursor = 'pointer';
            let displayText = ` (${formatCoins(total)})`;
            span.style.color = 'gold';
            span.style.fontSize = '0.9em';
            if (hoursElapsed >= 0.01 && total > 0) {
                const avg = total / hoursElapsed * 24;
                displayText = ` ${formatCoins(total)}: ${formatCoins(avg)}/day`;
                span.style.color = 'lightgreen';
                if (playerName === window.lootDropsTrackerInstance.userName) {
                    window.lootDropsTrackerInstance.goldPerDay = avg;
                    window.lootDropsTrackerInstance.goldPerDayFormatted = formatCoins(avg);
                }
            }
            span.textContent = displayText;
            headerForTotal.appendChild(span);
        });
                }
                const CONFIG = {
        CONTAINER_ID: 'milt-loot-drops-display',
        TOOLTIP_ID: 'milt-loot-drops-tooltip',
        DEFAULT_POS: { top: '120px', right: '30px' },
        STORAGE: {
            sessionHistory: 'mcs__global_session_history'
        },
        PANEL_WIDTH_EXPANDED: '380px',
        PANEL_MAX_HEIGHT: '70vh',
        PLAYER_COLUMN_MIN_WIDTH: '160px',
        USERNAME_SELECTOR: ".CharacterName_name__1amXp[data-name]",
        SEARCH_DEBOUNCE_MS: 250,
        HISTORY_LIMIT: 40,
        DISPLAY_HISTORY_LIMIT: 10,
        INJECTION_FLAG: 'lootDropsInjected'
                };

                const savedValue = flStorage.get('use_ask_price', false);
                _useAskPrice = savedValue === true || savedValue === 'true';

                function readSessionHistory() {
        try {
            const stored = localStorage.getItem(CONFIG.STORAGE.sessionHistory);
            const parsed = stored ? JSON.parse(stored) : [];
            return Array.isArray(parsed) ? parsed.filter(item => item && typeof item === 'object' && item.start && item.key) : [];
        } catch (e) { console.error("LDT: Error reading session history", e); return []; }
                }
                function writeSessionHistory(history) {
        try {
            const MAX_SIZE = 4.0 * 1024 * 1024;
            let historyString = JSON.stringify(history);
            if (historyString.length > MAX_SIZE && history.length > 1) {
                let lo = 1, hi = history.length - 1, trimCount = hi;
                while (lo <= hi) {
                    const mid = (lo + hi) >>> 1;
                    const testString = JSON.stringify(history.slice(mid));
                    if (testString.length > MAX_SIZE) {
                        lo = mid + 1;
                    } else {
                        trimCount = mid;
                        hi = mid - 1;
                    }
                }
                history.splice(0, trimCount);
                historyString = JSON.stringify(history);
            }
            localStorage.setItem(CONFIG.STORAGE.sessionHistory, historyString);
        } catch (e) {
            console.error("LDT: Error writing session history", e);
            if (e.name === 'QuotaExceededError' && history.length > 0) {
                history.shift();
                try {
                    localStorage.setItem(CONFIG.STORAGE.sessionHistory, JSON.stringify(history));
                } catch (e2) {
                    console.error("LDT: Failed to write history even after trimming.", e2);
                }
            }
        }
                }
                function generateSessionKey(playerNames, startTimeString) {
        if (!playerNames || playerNames.length === 0 || !startTimeString) return null;
        const sortedNames = [...playerNames].sort().join(',');
        return `${sortedNames}@${startTimeString}`;
                }
                function formatLocationName(actionHrid) {
        if (!actionHrid || !actionHrid.startsWith('/actions/combat/')) {
            return 'Unknown Location';
        }
        return actionHrid.replace('/actions/combat/', '')
            .replace(/_/g, ' ')
            .split(' ')
            .map(word => word.charAt(0).toUpperCase() + word.slice(1))
            .join(' ');
                }
                function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => { clearTimeout(timeout); func.apply(this, args); };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
                };

                function formatPrice(value) {
                    return mcsFormatCurrency(value, 'price');
                }

                function getRealItemCount(itemHrid, enhancementLevel = 0) {
                    const items = window.lootDropsTrackerInstance?.spyCharacterItems
                               || CharacterDataStorage.get()?.characterItems;
                    if (!items) return null;
                    const match = items.find(i =>
                        i.itemHrid === itemHrid &&
                        (i.enhancementLevel ?? 0) === enhancementLevel &&
                        i.itemLocationHrid === '/item_locations/inventory'
                    );
                    return match ? match.count : null;
                }

                function getItemPrice(itemHrid, count, enhancementLevel = 0) {
                    if (!itemHrid) return null;

                    if (Object.keys(marketData).length === 0) {
                        console.warn('[Floot] Market data is empty, triggering reload...');
                        loadMarketData().then(() => {
                            if (inventoryPricesEnabled) {
                                setTimeout(() => updateAllInventoryPrices(true), 500);
                            }
                        });
                        return null;
                    }

                    const unitPrice = window.getUnitValue(itemHrid, 'live', enhancementLevel);

                    if (unitPrice !== null && unitPrice > 0) {
                        return unitPrice * (count || 1);
                    }

                    return null;
                }

                function detectScamBid(itemHrid) {
                    let isScamBid = false;
                    let isEqualToVendor = false;
                    let isNoBid = false;
                    let vendorValue = 0;
                    try {
                        const itemDetailMap = InitClientDataCache.getItemDetailMap();
                        vendorValue = itemDetailMap[itemHrid]?.sellPrice || 0;
                        if (marketData[itemHrid] && marketData[itemHrid]['0']) {
                            const rawBid = marketData[itemHrid]['0'].b || 0;
                            if (rawBid <= 0) {
                                isNoBid = true;
                            } else if (vendorValue > 0) {
                                const bidWithTax = rawBid < 900 ? Math.floor(rawBid * 0.98) : Math.ceil(rawBid * 0.98);
                                if (bidWithTax < vendorValue) {
                                    isScamBid = true;
                                } else if (bidWithTax === vendorValue) {
                                    isEqualToVendor = true;
                                }
                            }
                        }
                    } catch (e) {
                    }
                    return { isScamBid, isEqualToVendor, isNoBid, vendorValue };
                }

                function appendCenterOverlay(container, className, color, text) {
                    const el = document.createElement('div');
                    el.className = `${className} mcs-floot-center-overlay`;
                    el.style.color = color;
                    el.textContent = text;
                    container.classList.add('mcs-floot-overlay-container');
                    container.appendChild(el);
                }

                function addPriceOverlayToItem(itemElement) {
                    if (!itemElement) return;

                    if (itemElement.querySelector('.mcs-price-overlay') ||
                        itemElement.querySelector('.mcs-floot-center-overlay') ||
                        itemElement.querySelector('.mcs-ntally-indicator')) {
                        return;
                    }

                    const svgElement = itemElement.querySelector('svg');
                    if (!svgElement) {
                        return;
                    }

                    const ariaLabel = svgElement.getAttribute('aria-label') || '';
                    if (!ariaLabel) {
                        return;
                    }

                    const itemName = ariaLabel.toLowerCase().replace(/'/g, '').replace(/ /g, '_');
                    const fullItemHrid = '/items/' + itemName;

                    if (fullItemHrid === '/items/coins' || fullItemHrid === '/items/coin') {
                        return;
                    }

                    let enhancementLevel = 0;
                    const itemDiv = itemElement.querySelector('[class*="Item_item"]');
                    if (itemDiv) {
                        const enhancementDiv = itemDiv.querySelector('[class*="Item_enhancementLevel"]');
                        if (enhancementDiv) {
                            const enhancementText = enhancementDiv.textContent.trim();
                            const enhancementMatch = enhancementText.match(/\+(\d+)/);
                            if (enhancementMatch) {
                                enhancementLevel = parseInt(enhancementMatch[1], 10);
                            }
                        }
                    }

                    let count = getRealItemCount(fullItemHrid, enhancementLevel);
                    if (count === null) {
                        const countDiv = itemElement.querySelector('[class*="Item_count"]');
                        if (countDiv) {
                            const countMatch = countDiv.textContent.trim().match(/(\d+)/);
                            count = countMatch ? parseInt(countMatch[1], 10) : 1;
                        } else {
                            count = 1;
                        }
                    }

                    const totalPrice = getItemPrice(fullItemHrid, count, enhancementLevel);

                    let isTrackedByNtally = false;
                    try {
                        if (window.isItemTrackedByNtally) {
                            isTrackedByNtally = window.isItemTrackedByNtally(fullItemHrid);
                        }
                    } catch (e) {
                    }

                    const isMarketplace = !!itemElement.closest('[class*="Marketplace_"]');
                    const showWarnings = isMarketplace ? marketWarningsEnabled : inventoryWarningsEnabled;
                    const { isScamBid, isEqualToVendor, isNoBid } = (showWarnings && !_useAskPrice && enhancementLevel === 0)
                        ? detectScamBid(fullItemHrid)
                        : { isScamBid: false, isEqualToVendor: false, isNoBid: false };

                    if (isNoBid) {
                        appendCenterOverlay(itemElement, 'mcs-none-overlay', '#999', 'NONE');
                    } else if (isScamBid) {
                        appendCenterOverlay(itemElement, 'mcs-scam-overlay', '#ff1744', 'SCAM');
                    } else if (isEqualToVendor) {
                        appendCenterOverlay(itemElement, 'mcs-vendor-equal-overlay', '#FFD700', 'VEND');
                    }

                    if (isTrackedByNtally) {
                        const ntallyIndicator = document.createElement('div');
                        ntallyIndicator.className = 'mcs-ntally-indicator';
                        itemElement.style.position = 'relative';
                        itemElement.appendChild(ntallyIndicator);
                    }

                    const priceOverlay = document.createElement('div');
                    priceOverlay.className = 'mcs-price-overlay';
                    priceOverlay.style.color = _useAskPrice ? '#6495ED' : '#4CAF50';

                    if (totalPrice !== null) {
                        priceOverlay.textContent = formatPrice(totalPrice);
                    }

                    itemElement.style.position = 'relative';
                    itemElement.appendChild(priceOverlay);
                }

                function captureInventoryState() {
                    const newState = new Map();
                    const categoryLabels = document.querySelectorAll('[class*="Inventory_label"]');

                    categoryLabels.forEach(labelElement => {
                        const categoryName = labelElement.textContent.replace(/\d+.*$/, '').trim();

                        if (categoryName.toLowerCase() === 'currencies') {
                            return;
                        }

                        const itemGrid = labelElement.closest('[class*="Inventory_itemGrid"]');
                        if (!itemGrid) return;

                        const categoryItems = new Map();
                        const itemContainers = itemGrid.querySelectorAll('[class*="Item_itemContainer"]');

                        itemContainers.forEach(itemElement => {
                            const svgElement = itemElement.querySelector('svg');
                            if (!svgElement) return;

                            const ariaLabel = svgElement.getAttribute('aria-label') || '';
                            if (!ariaLabel) return;

                            const itemName = ariaLabel.toLowerCase().replace(/'/g, '').replace(/ /g, '_');
                            const fullItemHrid = '/items/' + itemName;

                            if (fullItemHrid === '/items/coins' || fullItemHrid === '/items/coin') return;

                            let enhancementLevel = 0;
                            const itemDiv = itemElement.querySelector('[class*="Item_item"]');
                            if (itemDiv) {
                                const enhancementDiv = itemDiv.querySelector('[class*="Item_enhancementLevel"]');
                                if (enhancementDiv) {
                                    const enhancementText = enhancementDiv.textContent.trim();
                                    const enhancementMatch = enhancementText.match(/\+(\d+)/);
                                    if (enhancementMatch) {
                                        enhancementLevel = parseInt(enhancementMatch[1], 10);
                                    }
                                }
                            }

                            const count = getRealItemCount(fullItemHrid, enhancementLevel) ?? 1;

                            const itemKey = `${fullItemHrid}|${enhancementLevel}`;

                            categoryItems.set(itemKey, {
                                hrid: fullItemHrid,
                                count: count,
                                enhLevel: enhancementLevel,
                                element: itemElement,
                                priceType: _useAskPrice ? 'ask' : 'bid'
                            });
                        });

                        if (categoryItems.size > 0) {
                            newState.set(categoryName, categoryItems);
                        }
                    });

                    return newState;
                }

                function compareInventoryStates(oldState, newState) {
                    const changedCategories = new Set();

                    for (const [categoryName, newItems] of newState) {
                        const oldItems = oldState.get(categoryName);

                        if (!oldItems) {
                            changedCategories.add(categoryName);
                            continue;
                        }

                        if (oldItems.size !== newItems.size) {
                            changedCategories.add(categoryName);
                            continue;
                        }

                        for (const [itemKey, newItemData] of newItems) {
                            const oldItemData = oldItems.get(itemKey);

                            if (!oldItemData ||
                                oldItemData.count !== newItemData.count ||
                                oldItemData.priceType !== newItemData.priceType ||
                                oldItemData.element !== newItemData.element ||
                                !newItemData.element.querySelector('.mcs-price-overlay')) {
                                changedCategories.add(categoryName);
                                break;
                            }
                        }
                    }

                    for (const categoryName of oldState.keys()) {
                        if (!newState.has(categoryName)) {
                            changedCategories.add(categoryName);
                        }
                    }

                    return changedCategories;
                }

                function updateCategoryTotals(changedCategoriesSet = null) {
                    const categoryLabels = document.querySelectorAll('[class*="Inventory_label"]');

                    categoryLabels.forEach(labelElement => {
                        const existingTotal = labelElement.querySelector('.mcs-category-total');
                        let categoryName = labelElement.textContent.trim();

                        if (existingTotal) {
                            const totalText = existingTotal.textContent;
                            categoryName = categoryName.replace(totalText, '').trim();
                        }

                        if (categoryName.toLowerCase() === 'currencies') {
                            return;
                        }

                        if (changedCategoriesSet && !changedCategoriesSet.has(categoryName)) {
                            return;
                        }

                        if (existingTotal) {
                            existingTotal.remove();
                        }

                        const itemGrid = labelElement.closest('[class*="Inventory_itemGrid"]');
                        if (!itemGrid) return;

                        const itemContainers = itemGrid.querySelectorAll('[class*="Item_itemContainer"]');
                        let categoryTotal = 0;

                        itemContainers.forEach(itemElement => {
                            const svgElement = itemElement.querySelector('svg');
                            if (!svgElement) return;

                            const ariaLabel = svgElement.getAttribute('aria-label') || '';
                            if (!ariaLabel) return;

                            const itemName = ariaLabel.toLowerCase().replace(/'/g, '').replace(/ /g, '_');
                            const fullItemHrid = '/items/' + itemName;

                            if (fullItemHrid === '/items/coins' || fullItemHrid === '/items/coin') return;

                            let count = 1;
                            const countDiv = itemElement.querySelector('[class*="Item_count"]');
                            if (countDiv) {
                                const countText = countDiv.textContent.trim();
                                const countMatch = countText.match(/(\d+)/);
                                if (countMatch) {
                                    count = parseInt(countMatch[1], 10);
                                }
                            }

                            let enhancementLevel = 0;
                            const itemDiv = itemElement.querySelector('[class*="Item_item"]');
                            if (itemDiv) {
                                const enhancementDiv = itemDiv.querySelector('[class*="Item_enhancementLevel"]');
                                if (enhancementDiv) {
                                    const enhancementText = enhancementDiv.textContent.trim();
                                    const enhancementMatch = enhancementText.match(/\+(\d+)/);
                                    if (enhancementMatch) {
                                        enhancementLevel = parseInt(enhancementMatch[1], 10);
                                    }
                                }
                            }

                            const itemPrice = getItemPrice(fullItemHrid, count, enhancementLevel);
                            if (itemPrice !== null && itemPrice > 0) {
                                categoryTotal += itemPrice;
                            }
                        });

                        if (categoryTotal > 0) {
                            const totalSpan = document.createElement('span');
                            totalSpan.className = 'mcs-category-total';
                            totalSpan.style.color = _useAskPrice ? '#6495ED' : '#4CAF50';
                            totalSpan.textContent = formatPrice(categoryTotal);
                            labelElement.appendChild(totalSpan);
                        }
                    });
                }

                function updateNtallyIndicators() {
                    const inventoryItems = document.querySelectorAll('[class*="Inventory_"] [class*="Item_itemContainer"], [class*="Marketplace_"] [class*="Item_itemContainer"]');
                    inventoryItems.forEach(itemElement => {
                        const svgElement = itemElement.querySelector('svg');
                        if (!svgElement) return;

                        const ariaLabel = svgElement.getAttribute('aria-label') || '';
                        if (!ariaLabel) return;

                        const itemName = ariaLabel.toLowerCase().replace(/'/g, '').replace(/ /g, '_');
                        const fullItemHrid = '/items/' + itemName;

                        let isTrackedByNtally = false;
                        try {
                            if (window.isItemTrackedByNtally) {
                                isTrackedByNtally = window.isItemTrackedByNtally(fullItemHrid);
                            }
                        } catch (e) {
                        }

                        const existingIndicator = itemElement.querySelector('.mcs-ntally-indicator');
                        if (existingIndicator) {
                            existingIndicator.remove();
                        }

                        if (isTrackedByNtally) {
                            const ntallyIndicator = document.createElement('div');
                            ntallyIndicator.className = 'mcs-ntally-indicator';
                            itemElement.style.position = 'relative';
                            itemElement.appendChild(ntallyIndicator);
                        }
                    });
                }

                function updateAllInventoryPrices(forceUpdate = false) {
                    if (!inventoryPricesEnabled) {
                        updateNtallyIndicators();
                        return;
                    }

                    if (Object.keys(marketData).length === 0) {
                        console.warn('[Floot] Market data unavailable during inventory update, attempting reload...');
                        loadMarketData().then(() => {
                            setTimeout(() => updateAllInventoryPrices(true), 500);
                        });
                        return;
                    }

                    const newState = captureInventoryState();

                    if (forceUpdate) {
                        inventoryState = newState;
                        let inventoryItems = document.querySelectorAll('[class*="Inventory_"] [class*="Item_itemContainer"], [class*="Marketplace_"] [class*="Item_itemContainer"]');
                        inventoryItems.forEach(itemElement => {
                            itemElement.querySelectorAll('.mcs-price-overlay, .mcs-floot-center-overlay, .mcs-ntally-indicator').forEach(el => el.remove());

                            const hasSvg = itemElement.querySelector('svg');
                            if (hasSvg) {
                                addPriceOverlayToItem(itemElement);
                            }
                        });

                        updateCategoryTotals();
                    } else {
                        const changedCategories = compareInventoryStates(inventoryState, newState);

                        if (changedCategories.size === 0) {
                            return;
                        }

                        inventoryState = newState;

                        changedCategories.forEach(categoryName => {
                            const categoryState = newState.get(categoryName);
                            if (categoryState) {
                                categoryState.forEach((itemData) => {
                                    const itemElement = itemData.element;
                                    if (itemElement) {
                                        itemElement.querySelectorAll('.mcs-price-overlay, .mcs-floot-center-overlay, .mcs-ntally-indicator').forEach(el => el.remove());

                                        addPriceOverlayToItem(itemElement);
                                    }
                                });
                            }
                        });

                        updateCategoryTotals(changedCategories);
                    }
                }

                let inventoryObserver = null;
                let observedInventoryPanel = null;

                function observeInventoryChanges() {
                    const debouncedUpdate = debounce(() => {
                        updateAllInventoryPrices();
                    }, 750);

                    if (inventoryObserver) {
                        inventoryObserver.disconnect();
                    }

                    inventoryObserver = new MutationObserver((mutations) => {
                        if (document.hidden) return;
                        if (!inventoryPricesEnabled) {
                            return;
                        }

                        let shouldUpdate = false;

                        for (const mutation of mutations) {
                            const target = mutation.target;

                            if (mutation.type === 'characterData') {
                                const parent = target.parentElement;
                                if (parent && parent.className && typeof parent.className === 'string' &&
                                    parent.className.includes('Item_count')) {
                                    shouldUpdate = true;
                                    break;
                                }
                                continue;
                            }

                            if (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0) {
                                shouldUpdate = true;
                                break;
                            }

                            if (target.className && typeof target.className === 'string') {
                                if (target.className.includes('Inventory_') || target.className.includes('Item_')) {
                                    shouldUpdate = true;
                                    break;
                                }
                            }
                        }

                        if (shouldUpdate) {
                            debouncedUpdate();
                        }
                    });

                    attachObserverToInventory();

                    setTimeout(() => updateAllInventoryPrices(true), 2000);
                }

                function attachObserverToInventory() {
                    const inventoryPanel = document.querySelector('[class*="Inventory_items"]');
                    if (inventoryPanel && inventoryPanel !== observedInventoryPanel) {
                        if (inventoryObserver) {
                            inventoryObserver.disconnect();
                        }
                        observedInventoryPanel = inventoryPanel;
                        inventoryObserver.observe(inventoryPanel, {
                            childList: true,
                            subtree: true,
                            characterData: true,
                            attributes: false
                        });
                    }
                }

                function checkAndRestoreInventoryValues() {
                    if (!inventoryPricesEnabled) {
                        return;
                    }

                    const inventoryPanel = document.querySelector('[class*="Inventory_items"]');
                    if (!inventoryPanel) {
                        observedInventoryPanel = null;
                        return;
                    }

                    if (inventoryPanel !== observedInventoryPanel) {
                        attachObserverToInventory();
                    }

                    const allItems = inventoryPanel.querySelectorAll('[class*="Item_itemContainer"] svg');
                    if (allItems.length === 0) {
                        return;
                    }

                    const itemsWithPrices = inventoryPanel.querySelectorAll('.mcs-price-overlay');

                    if (itemsWithPrices.length < allItems.length) {
                        inventoryState.clear();
                        updateAllInventoryPrices(true);
                    }

                    const categoryLabels = inventoryPanel.querySelectorAll('[class*="Inventory_label"]');
                    const labelsWithTotals = inventoryPanel.querySelectorAll('.mcs-category-total');

                    if (categoryLabels.length > 0 && labelsWithTotals.length < categoryLabels.length * 0.5) {
                        updateCategoryTotals();
                    }
                }

                window.toggleInventoryPrices = function(visible) {
                    inventoryPricesEnabled = visible;

                    if (visible) {
                        inventoryState.clear();
                        observeInventoryChanges();
                        updateAllInventoryPrices(true);
                    } else {
                        if (inventoryObserver) {
                            inventoryObserver.disconnect();
                            inventoryObserver = null;
                            observedInventoryPanel = null;
                        }

                        const priceOverlays = document.querySelectorAll('.mcs-price-overlay');
                        const categoryTotals = document.querySelectorAll('.mcs-category-total');

                        priceOverlays.forEach(overlay => {
                            overlay.remove();
                        });

                        categoryTotals.forEach(total => {
                            total.remove();
                        });

                        inventoryState.clear();
                    }
                };

                window.toggleFlootFullNumbers = function(showFull) {
                    useFullNumbers = showFull;
                    if (typeof injectValuesAndSort === 'function') {
                        injectValuesAndSort();
                    }
                    if (inventoryPricesEnabled) {
                        updateAllInventoryPrices(true);
                    }
                    if (window.skeletonInstance && typeof window.skeletonInstance.updateOPanelCombatRevenue === 'function') {
                        window.skeletonInstance.updateOPanelCombatRevenue();
                    }
                };

                window.toggleMarketWarnings = function(visible) {
                    marketWarningsEnabled = visible;
                    if (!visible) {
                        document.querySelectorAll('[class*="Marketplace_"] .mcs-floot-center-overlay').forEach(el => el.remove());
                        document.querySelectorAll('.mcs-nt-marketplace-scam-warning').forEach(el => el.remove());
                    }
                };

                window.toggleInventoryWarnings = function(visible) {
                    inventoryWarningsEnabled = visible;
                    if (!visible) {
                        document.querySelectorAll('[class*="Inventory_"] .mcs-floot-center-overlay').forEach(el => el.remove());
                    } else if (inventoryPricesEnabled) {
                        inventoryState.clear();
                        updateAllInventoryPrices(true);
                    }
                };

                const initMarketWarningsState = () => {
                    const savedStates = ToolVisibilityStorage.get();
                    marketWarningsEnabled = savedStates['floot-market-warnings'] !== false;
                };

                const initInventoryWarningsState = () => {
                    const savedStates = ToolVisibilityStorage.get();
                    inventoryWarningsEnabled = savedStates['floot-inventory-warnings'] !== false;
                };

                const initInventoryPriceVisibility = () => {
                    const savedStates = ToolVisibilityStorage.get();
                    const isVisible = savedStates['floot-inventory-value'] !== false;
                    inventoryPricesEnabled = isVisible;
                    if (!isVisible) {
                        const priceOverlays = document.querySelectorAll('.mcs-price-overlay');
                        const categoryTotals = document.querySelectorAll('.mcs-category-total');
                        priceOverlays.forEach(overlay => overlay.remove());
                        categoryTotals.forEach(total => total.remove());
                    }
                };

                const initFullNumbersState = () => {
                    const savedStates = ToolVisibilityStorage.get();
                    useFullNumbers = savedStates['floot-full-numbers'] !== false;
                };

                let lastWebSocketCheckTime = Date.now();
                let webSocketReconnectDetected = false;

                function flootHandleWsReconnect(event) {
                    if (window.MCS_MODULES_DISABLED) return;
                    const now = Date.now();
                    const timeSinceLastCheck = now - lastWebSocketCheckTime;
                    if (event.detail?.type === 'init_client_data' || event.detail?.type === 'init_character_data') {
                        if (timeSinceLastCheck > 30000 && !webSocketReconnectDetected) {
                            webSocketReconnectDetected = true;
                            loadMarketData().then(() => {
                                if (inventoryPricesEnabled) {
                                    setTimeout(() => {
                                        inventoryState.clear();
                                        updateAllInventoryPrices(true);
                                    }, 1000);
                                }
                                webSocketReconnectDetected = false;
                            });
                        }
                    }
                    lastWebSocketCheckTime = now;
                }

                function setupWebSocketReconnectHandler() {
                    window.addEventListener('EquipSpyWebSocketMessage', flootHandleWsReconnect);
                }

                function wrapRenderCurrentView() {
                    if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.renderCurrentView) {
                        const originalRender = window.lootDropsTrackerInstance.renderCurrentView;
                        window.lootDropsTrackerInstance.renderCurrentView = function(...args) {
                            invalidatePlayerSectionsCache();
                            const result = originalRender.apply(this, args);
                            setTimeout(() => {
                                if (typeof injectValuesAndSort === 'function') {
                                    injectValuesAndSort();
                                }
                            }, 50);
                            return result;
                        };
                    }
                }

                function tryWrapRenderCurrentView() {
                    if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.renderCurrentView) {
                        wrapRenderCurrentView();
                    } else {
                        setTimeout(tryWrapRenderCurrentView, 500);
                    }
                }

                async function flootHandlePricesUpdated() {
                    await calculateChestValues();
                    itemPriceCache = {};
                    if (window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.renderCurrentView();
                    }
                    if (inventoryPricesEnabled) {
                        updateAllInventoryPrices(true);
                    }
                }
                window.addEventListener('FlootPricesUpdated', flootHandlePricesUpdated);

                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', () => {
                        setTimeout(() => {
                            initFullNumbersState();
                            initMarketWarningsState();
                            initInventoryWarningsState();
                            observeInventoryChanges();
                            initInventoryPriceVisibility();
                            setupWebSocketReconnectHandler();
                            loadMarketData();
                            tryWrapRenderCurrentView();
                            VisibilityManager.register('floot-inventory-check', () => {
                                checkAndRestoreInventoryValues();
                            }, 10000);
                        }, 2000);
                    });
                } else {
                    setTimeout(() => {
                        initFullNumbersState();
                        initMarketWarningsState();
                        initInventoryWarningsState();
                        observeInventoryChanges();
                        initInventoryPriceVisibility();
                        setupWebSocketReconnectHandler();
                        loadMarketData();
                        tryWrapRenderCurrentView();
                        VisibilityManager.register('floot-inventory-check', () => {
                            checkAndRestoreInventoryValues();
                        }, 10000);
                    }, 2000);
                }

// Class start

        class LootDropsTracker {
            constructor() {
                if (document.getElementById(CONFIG.CONTAINER_ID)) {
                    return;
                }
                this.spyOpenComparisons = new Set();
                this.marketDataCache = null;
                this.marketDataCacheTime = 0;
                this.CACHE_DURATION = 3000;
                this.partyConsumableTracker = {};
                this.lastMinTimes = {};
                this.isUpdatingMinimizedSummary = false;
                this.hwhatCowbellPollInterval = null;
                this.sessionInitialCoins = {};
                this.totalPerDay = 0;
                this.totalPerDayFormatted = '';
                this.consumableResetPending = false;
                this.consumableResetBattleCount = 0;
                this.consumableWaitingForFreshData = false;
                this.userName = null;
                this.playerDropStats = {};
                this.encounterCount = 0;
                this.sessionStartTime = null;
                this.firstBattleSeenTime = null;
                this.lastBattleTimestamp = 0;
                this.sessionHistory = readSessionHistory();
                this.viewingLive = true;
                const startHiddenVal = flStorage.get('start_hidden');
                this.startHiddenEnabled = startHiddenVal === true || startHiddenVal === 'true';
                const minimizedVal = flStorage.get('minimized');
                this.isHidden = this.startHiddenEnabled || minimizedVal === true || minimizedVal === 'true';
                this.isMoving = false;
                this.moveOffset = { x: 0, y: 0 };
                this.initialRight = 0;
                this.initialClientX = 0;
                this.domRefs = {
                    panel: null, header: null, content: null, showButton: null, hideButton: null,
                    exportButton: null, tooltip: null, timerDisplay: null, searchInput: null,
                    settingsButton: null, settingsMenu: null, startHiddenCheckbox: null,
                    clearButton: null,
                    historySelect: null,
                    headerTopRow: null, headerControls: null, headerBottomRow: null
                };
                this.startTime = null;
                this.sessionEndTime = null;
                this.lastKnownActionHrid = null;
                this.purchaseTimerInterval = null;
                this.purchaseTimerIntervals = {};
                this.coinHeaderInterval = null;
                this.timerInterval = null;
                this.isLiveSessionActive = false;
                this.sortPreference = flStorage.get('sort', 'count');
                this.currentSearchTerm = '';
                this.currentSessionKey = null;
                this.isSettingsMenuVisible = false;
                this.aggregatedHistoryData = null;
                this.aggregatedHistoryDuration = 0;
                this.debouncedRender = debounce(this.renderCurrentView, CONFIG.SEARCH_DEBOUNCE_MS);
                this.goldPerDay = 0;
                this.ignoreNextStorageEvent = false;
                this.spyMarketDataTimestamp = null;
                this.spySimpleMode = false;
                window.MCS_IN_COMBAT = false;
                this.init();
                this.comparisonOrder = [];
                this.draggedSlot = null;
            }
            get spyCharacterItems() {
                return this._spyCharacterItems ?? [];
            }
            set spyCharacterItems(value) {
                if (this._spyCharacterItems && this._spyCharacterItems.length > 10 && value.length < 10) {
                    console.warn('[EquipSpy] WARNING: Character items being reduced from', this._spyCharacterItems.length, 'to', value.length);
                    console.warn('[EquipSpy] This looks like loot drops overwriting equipment!');
                    const oldEquipped = this._spyCharacterItems.filter(item => {
                        if (!item.itemLocationHrid) return false;
                        if (item.itemLocationHrid === '/item_locations/inventory') return false;
                        const slot = item.itemLocationHrid.replace('/item_locations/', '');
                        return this.spyConfig?.ALLOWED_SLOTS?.includes(slot);
                    });
                    const newInventory = value.filter(item => !item.itemLocationHrid || item.itemLocationHrid === '/item_locations/inventory'
                    );
                    const merged = [...oldEquipped, ...newInventory];
                    this._spyCharacterItems = merged;
                    const bridge = document.getElementById('equipspy-data-bridge');
                    if (bridge) {
                        bridge.setAttribute('data-character-items', JSON.stringify(merged));
                    }
                    return;
                }
                this._spyCharacterItems = value;
                const bridge = document.getElementById('equipspy-data-bridge');
                if (bridge) {
                    bridge.setAttribute('data-character-items', JSON.stringify(value));
                }
            }
            createEquipSpyBridge() {
                if (document.getElementById('equipspy-data-bridge')) return;
                const bridge = document.createElement('div');
                bridge.id = 'equipspy-data-bridge';
                bridge.className = 'mcs-data-bridge';
                document.body.appendChild(bridge);
            }
            init() {
                this.injectCss();
                this.createPanel();
                this.setInitialCheckboxState();
                this.createTooltipElement();
                this.findUserName();
                this.bindUiEvents();
                this.createEquipSpyBridge();
                this.setupFeedListener();
                this.initFCB();
                if (!this.isHidden) {
                    this.renderCurrentView();
                    this.updateTimerDisplay();
                }
            }
            injectCss() {
                const styleId = `${CONFIG.CONTAINER_ID}-style`;
                if (document.getElementById(styleId)) return;
                const css = `
                #${CONFIG.CONTAINER_ID} {
                    --ldt-bg-primary: #333; --ldt-bg-header: #444; --ldt-bg-input: #222; --ldt-bg-hidden: #222; --ldt-bg-highlight: rgba(76, 175, 80, 0.18); --ldt-bg-settings-menu: #4a4a4a; --ldt-bg-select: #555; --ldt-bg-button-show: #4CAF50; --ldt-bg-button-show-hover: #5cb860; --ldt-bg-button-export: #0d6efd; --ldt-bg-button-export-border: #0b5ed7; --ldt-bg-button-hide: #6c757d; --ldt-bg-button-hide-border: #5c636a; --ldt-bg-button-sort: #7b4caf; --ldt-bg-button-sort-border: #6a3f9a; --ldt-bg-button-sort-hover: #8a5cb9; --ldt-bg-button-copied: #4CAF50; --ldt-bg-button-copied-border: #45a049; --ldt-bg-button-error: #f44336; --ldt-bg-button-error-border: #d32f2f; --ldt-bg-button-settings: #555; --ldt-bg-button-settings-border: #444; --ldt-bg-button-clear: #dc3545; --ldt-bg-button-clear-border: #b02a37;
                    --ldt-text-primary: #eee; --ldt-text-secondary: #bbb; --ldt-text-header: #fff; --ldt-text-button: #eee; --ldt-text-button-dark-bg: #fff; --ldt-text-player-current: #4CAF50; --ldt-text-player-other: #ddd; --ldt-text-select: #eee;
                    --ldt-border-primary: #555; --ldt-border-separator: #555; --ldt-border-header-bottom: #555; --ldt-border-item-dotted: #666; --ldt-border-item-dashed: #555; --ldt-border-settings-menu: #666; --ldt-border-select: #777;
                    --ldt-font-size-base: 13px; --ldt-font-size-small: 0.9em; --ldt-font-size-smaller: 0.85em; --ldt-font-size-large: 1.1em;
                    --ldt-radius: 5px; --ldt-radius-small: 3px;
                    --ldt-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); --ldt-transition-duration: 0.25s; --ldt-transition-timing: ease-out;
                }
                #${CONFIG.CONTAINER_ID} { position: fixed; top: 0; right: 30px; left: auto; background-color: var(--ldt-bg-primary); color: var(--ldt-text-primary); font-family: sans-serif; font-size: var(--ldt-font-size-base); border: none; border-radius: var(--ldt-radius); z-index: 99997; user-select: none; box-shadow: var(--ldt-shadow); display: flex; flex-direction: column; overflow: hidden; transition: width var(--ldt-transition-duration) var(--ldt-transition-timing), height var(--ldt-transition-duration) var(--ldt-transition-timing), min-width var(--ldt-transition-duration) var(--ldt-transition-timing), opacity var(--ldt-transition-duration) var(--ldt-transition-timing); box-sizing: border-box; cursor: default; }
                #${CONFIG.CONTAINER_ID}:not(.is-hidden) { width: auto; min-width: ${CONFIG.PANEL_WIDTH_EXPANDED}; height: auto; max-height: ${CONFIG.PANEL_MAX_HEIGHT}; opacity: 1; }
                #${CONFIG.CONTAINER_ID}:not(.is-hidden) .hidden-state-only { display: none; }
                #${CONFIG.CONTAINER_ID}:not(.is-hidden) .visible-state-only { display: flex; }
                #${CONFIG.CONTAINER_ID}.is-hidden { width: auto; height: auto; min-width: 0; background: var(--ldt-bg-hidden); border-radius: var(--ldt-radius); padding: 4px 8px; cursor: move !important; flex-direction: row; align-items: center; opacity: 0.95; overflow: visible; max-height: none; }
                #${CONFIG.CONTAINER_ID}.is-hidden:hover { opacity: 1; }
                #${CONFIG.CONTAINER_ID}.is-hidden .visible-state-only { display: none; }
                #${CONFIG.CONTAINER_ID}.is-hidden .hidden-state-only { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
                .ldt-hidden-header { display: flex; justify-content: space-between; align-items: center; width: 100%; margin-bottom: 5px; border-bottom: 1px solid var(--ldt-border-primary); padding-bottom: 3px; }
                .ldt-hidden-title-row { display: flex; align-items: center; gap: 8px; flex: 1; }
                .ldt-hidden-title { font-weight: bold; font-size: 1em; color: var(--ldt-text-header); }
                .ldt-hidden-player-row { display: flex; align-items: center; gap: 8px; min-width: 250px; white-space: nowrap; }
                .ldt-hidden-player-name { color: var(--ldt-text-primary); font-size: 0.9em; width: 100px; flex-shrink: 0; }
                .ldt-hidden-player-name.is-current { color: var(--ldt-text-player-current); font-weight: bold; }
                .ldt-hidden-player-stats { display: flex; align-items: center; gap: 4px; font-size: 0.85em; white-space: nowrap; }
                .ldt-hidden-coin-emoji { flex-shrink: 0; }
                .ldt-hidden-coin-amount { color: #cccccc; font-weight: bold; min-width: 60px; text-align: left; flex-shrink: 0; }
                .ldt-hidden-coin-rate { color: #90EE90; font-weight: bold; min-width: 80px; text-align: right; flex-shrink: 0; }
                #${CONFIG.CONTAINER_ID}.is-hidden .ldt-hide-label { font-weight: normal; color: var(--ldt-text-primary); font-size: 1em; cursor: move; user-select: none; }
                #${CONFIG.CONTAINER_ID}.is-hidden .ldt-show-btn { color: var(--ldt-text-button-dark-bg); padding: 2px 5px; border-radius: var(--ldt-radius-small); text-decoration: none; font-size: var(--ldt-font-size-small); cursor: pointer; border: none; line-height: normal; vertical-align: middle; font-weight: normal; }
                #${CONFIG.CONTAINER_ID}.is-hidden .ldt-show-btn:hover { filter: brightness(1.1); }
                .ldt-panel-header { flex-direction: column; padding: 5px 8px 8px 8px; background: var(--ldt-bg-header); border-bottom: 1px solid var(--ldt-border-header-bottom); flex-shrink: 0; user-select: none; }
                .ldt-header-top-row { display: flex; justify-content: space-between; align-items: center; width: 100%; margin-bottom: 5px; cursor: move; gap: 8px; }
                .ldt-panel-title-area { display: flex; align-items: center; gap: 6px; margin-right: auto; min-width: 0; }
                .ldt-timer { color: var(--ldt-text-primary); font-size: var(--ldt-font-size-small); font-weight: normal; white-space: nowrap; margin-left: auto; }
                .ldt-hidden-timer { color: var(--ldt-text-primary); font-size: 0.85em; font-weight: normal; white-space: nowrap; }
                .ldt-panel-title { font-weight: bold; font-size: var(--ldt-font-size-large); color: var(--ldt-text-header); flex-shrink: 0; }
                .ldt-history-select { background-color: var(--ldt-bg-select); color: var(--ldt-text-select); border: 1px solid var(--ldt-border-select); border-radius: var(--ldt-radius-small); padding: 2px 4px; font-size: var(--ldt-font-size-smaller); max-width: 150px; cursor: pointer; flex-shrink: 1; }
                .ldt-history-select optgroup { font-style: italic; font-weight: bold; }
                .ldt-header-controls { position: relative; display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
                .ldt-header-controls button { position: relative; border-radius: var(--ldt-radius-small); padding: 3px 7px; font-size: var(--ldt-font-size-small); font-weight: normal; cursor: pointer; transition: filter 0.15s, background-color 0.15s, border-color 0.15s, color 0.15s; font-family: inherit; line-height: 1.2; border: 1px solid var(--ldt-border-primary); color: var(--ldt-text-button); display: inline-flex; align-items: center; justify-content: center; }
                .ldt-header-controls button:hover { filter: brightness(1.15); }
                .ldt-clear-btn { background-color: var(--ldt-bg-button-clear); border-color: var(--ldt-bg-button-clear-border); color: var(--ldt-text-button-dark-bg); }
                .ldt-export-btn { background-color: var(--ldt-bg-button-export); border-color: var(--ldt-bg-button-export-border); color: var(--ldt-text-button-dark-bg); }
                .ldt-hide-btn { background-color: var(--ldt-bg-button-hide); border-color: var(--ldt-bg-button-hide-border); color: var(--ldt-text-button-dark-bg); }
                .ldt-btn-copied { background-color: var(--ldt-bg-button-copied) !important; border-color: var(--ldt-bg-button-copied-border) !important; color: var(--ldt-text-button-dark-bg) !important; }
                .ldt-btn-error { background-color: var(--ldt-bg-button-error) !important; border-color: var(--ldt-bg-button-error-border) !important; color: var(--ldt-text-button-dark-bg) !important; }
                .ldt-header-bottom-row { position: relative; display: flex; justify-content: space-between; align-items: center; width: 100%; gap: 8px; }
                .ldt-search-input { background-color: var(--ldt-bg-input); color: var(--ldt-text-primary); border: 1px solid var(--ldt-border-primary); border-radius: var(--ldt-radius-small); padding: 3px 5px; font-size: var(--ldt-font-size-small); flex-grow: 1; min-width: 90px; max-width: 140px; cursor: text; }
                .ldt-settings-btn { background-color: var(--ldt-bg-button-settings); border-color: var(--ldt-bg-button-settings-border); color: var(--ldt-text-button); padding: 3px 5px; margin-left: auto; order: 1; }
                .ldt-settings-btn svg { width: 1em; height: 1em; fill: currentColor; display: block; }
                .ldt-sort-btn { background-color: var(--ldt-bg-button-sort); border-color: var(--ldt-bg-button-sort-border); color: var(--ldt-text-button); padding: 3px 7px; font-size: var(--ldt-font-size-smaller); flex-shrink: 0; order: 2; }
                .ldt-sort-btn:hover { filter: brightness(1.15); background-color: var(--ldt-bg-button-sort-hover); border-color: var(--ldt-bg-button-sort-border);}
                .ldt-timer { font-size: var(--ldt-font-size-small); color: var(--ldt-text-secondary); flex-shrink: 0; padding: 0 5px; white-space: nowrap; min-width: 85px; text-align: right; order: 3; }
                .ldt-settings-menu {display: none; position: absolute; top: 100%; left: 0; background-color: var(--ldt-bg-settings-menu); border: 1px solid var(--ldt-border-settings-menu); border-radius: var(--ldt-radius-small); padding: 8px; z-index: 10; box-shadow: 0 2px 5px rgba(0,0,0,0.3); margin-top: 4px; white-space: nowrap; }
                .ldt-settings-menu.visible { display: block; }
                .ldt-settings-menu label { display: flex; align-items: center; cursor: pointer; color: var(--ldt-text-primary); font-size: var(--ldt-font-size-small); }
                .ldt-settings-menu input[type="checkbox"] { margin-right: 6px; cursor: pointer; }
                .ldt-panel-body { display: flex; flex-direction: row; flex-grow: 1; overflow-y: auto; overflow-x: auto; background-color: var(--ldt-bg-primary); cursor: auto; padding: 0; }
                .ldt-body-empty { padding: 15px; text-align: center; color: var(--ldt-text-secondary); font-style: italic; width: 100%; line-height: 1.4; }
                .ldt-player-stats-section { flex: 1 1 auto; min-width: ${CONFIG.PLAYER_COLUMN_MIN_WIDTH}; padding: 8px 10px; box-sizing: border-box; }
                .ldt-player-stats-section:not(:first-child) { border-left: 1px solid var(--ldt-border-separator); padding-left: 10px; }
                .ldt-player-name-header { font-weight: bold; color: var(--ldt-text-player-other); background-color: transparent; padding: 4px 0 5px 0; margin-bottom: 5px; border-bottom: 1px dotted var(--ldt-border-item-dotted); font-size: 0.95em; }
                .ldt-player-name-header.is-current-player { color: var(--ldt-text-player-current); }
                .ldt-loot-list { padding: 0; list-style: none; margin: 0; }
                .ldt-loot-item-entry { display: flex; justify-content: space-between; align-items: center; margin-bottom: 3px; padding: 2px 0px; font-size: 1em; border-bottom: 1px dashed var(--ldt-border-item-dashed); color: var(--ldt-text-primary); transition: background-color 0.2s linear; }
                .ldt-loot-item-entry:last-child { border-bottom: none; }
                .ldt-item-name { display:none; color: var(--ldt-text-primary); flex-grow: 1; margin-right: 10px; word-break: break-word; }
                .ldt-vis-name { color: var(--ldt-text-primary); flex-grow: 1; margin-right: 10px; word-break: break-word; }
                .ldt-item-value { color: yellow; margin-right:5px; font-weight: normal; white-space: nowrap; }
                .ldt-item-count { color: var(--ldt-text-primary); font-weight: normal; white-space: nowrap; }
                .ldt-loot-item-entry.highlight-match { background-color: var(--ldt-bg-highlight); }
                #${CONFIG.TOOLTIP_ID} { position: fixed; background-color: #222; color: #eee; padding: 4px 8px; font-size: 11px; border-radius: var(--ldt-radius-small); white-space: nowrap; opacity: 0; visibility: hidden; pointer-events: none; z-index: 100002; transition: opacity 0.2s ease-out, visibility 0s linear 0.2s; will-change: transform, opacity; }
                #${CONFIG.TOOLTIP_ID}.visible { opacity: 0.9; visibility: visible; transition: opacity 0.2s ease-out, visibility 0s linear 0s; }`;
                const styleElement = document.createElement('style');
                styleElement.id = styleId;
                styleElement.textContent = css;
                document.head.appendChild(styleElement);
            }
            createPanel() {
                const panel = document.createElement('div');
                panel.id = CONFIG.CONTAINER_ID;
                registerPanel(CONFIG.CONTAINER_ID);
                this.domRefs.panel = panel;
                let savedPosition = {};
                try {
                    savedPosition = flStorage.get('position') ?? {};
                } catch (e) { console.error("LDT: Error parsing saved position", e); }
                if (savedPosition.top || savedPosition.left || savedPosition.right) {
                    panel.style.top = savedPosition.top || CONFIG.DEFAULT_POS.top;
                    if (savedPosition.left) {
                        panel.style.left = savedPosition.left;
                        panel.style.right = 'auto';
                    } else {
                        panel.style.right = savedPosition.right || CONFIG.DEFAULT_POS.right;
                        panel.style.left = 'auto';
                    }
                }
                if (this.isHidden) panel.classList.add('is-hidden');
                const settingsIconSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.858 2.929 2.929 0 0 1 0 5.858z"/></svg>`;
                const clearIconSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16"><path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/><path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/></svg>`;
                panel.innerHTML = `
                <div class="hidden-state-only">
                <div class="ldt-hidden-header">
                <div class="ldt-hidden-title-row">
                <span class="ldt-hidden-title">FLoot</span>
                <span class="ldt-hidden-timer" id="${CONFIG.CONTAINER_ID}-timer-hidden">--:--:--</span>
                <button class="ldt-price-toggle-btn-hidden" id="${CONFIG.CONTAINER_ID}-price-toggle-hidden">Showing Bid</button>
                </div>
                <button class="ldt-show-btn ldt-content-toggle-btn" id="${CONFIG.CONTAINER_ID}-minbtn-minimized">+</button>
                </div>
                <div id="${CONFIG.CONTAINER_ID}-hidden-players"></div>
                </div>
                <div class="visible-state-only ldt-panel-header" id="${CONFIG.CONTAINER_ID}-header">
                <div class="ldt-header-top-row" id="${CONFIG.CONTAINER_ID}-header-top">
                <div class="ldt-panel-title-area">
                <span class="ldt-panel-title">FLoot</span>
                <span class="ldt-timer" id="${CONFIG.CONTAINER_ID}-timer">--:--:--</span>
                <select class="ldt-history-select" id="${CONFIG.CONTAINER_ID}-history-select" title="View session history"></select>
                </div>
                <div class="ldt-header-controls" id="${CONFIG.CONTAINER_ID}-header-controls-top">
                <button class="ldt-price-toggle-btn" id="${CONFIG.CONTAINER_ID}-price-toggle" data-tooltip="Toggle between Bid and Ask prices">Showing Bid</button>
                <button class="ldt-settings-btn" id="${CONFIG.CONTAINER_ID}-settingsbtn" data-tooltip="Settings">${settingsIconSvg}</button>
                <div class="ldt-settings-menu" id="${CONFIG.CONTAINER_ID}-settings-menu">
                <label>
                <input type="checkbox" id="${CONFIG.CONTAINER_ID}-starthidden-check"> Start Hidden
                </label>
                </div>
                <button class="ldt-clear-btn" id="${CONFIG.CONTAINER_ID}-clearbtn" data-tooltip="Clear Your History">${clearIconSvg}</button>
                <button class="ldt-export-btn" id="${CONFIG.CONTAINER_ID}-exportbtn" data-tooltip="Copy loot as CSV to clipboard">Export</button>
                </div>
                <button class="ldt-minimize-content-btn ldt-content-toggle-btn" id="${CONFIG.CONTAINER_ID}-minimize-content-btn">−</button>
                </div>
                </div>
                <div class="visible-state-only ldt-panel-body" id="${CONFIG.CONTAINER_ID}-content"></div>`;
                document.body.appendChild(panel);
                Object.assign(this.domRefs, {
                    panel: panel,
                    header: panel.querySelector(`#${CONFIG.CONTAINER_ID}-header`),
                    headerTopRow: panel.querySelector(`#${CONFIG.CONTAINER_ID}-header-top`),
                    headerControls: panel.querySelector(`#${CONFIG.CONTAINER_ID}-header-controls-top`),
                    content: panel.querySelector(`#${CONFIG.CONTAINER_ID}-content`),
                    showButton: panel.querySelector(`#${CONFIG.CONTAINER_ID}-minbtn-minimized`),
                    minimizeContentButton: panel.querySelector(`#${CONFIG.CONTAINER_ID}-minimize-content-btn`),
                    settingsButton: panel.querySelector(`#${CONFIG.CONTAINER_ID}-settingsbtn`),
                    settingsMenu: panel.querySelector(`#${CONFIG.CONTAINER_ID}-settings-menu`),
                    clearButton: panel.querySelector(`#${CONFIG.CONTAINER_ID}-clearbtn`),
                    exportButton: panel.querySelector(`#${CONFIG.CONTAINER_ID}-exportbtn`),
                    historySelect: panel.querySelector(`#${CONFIG.CONTAINER_ID}-history-select`),
                    timerDisplay: panel.querySelector(`#${CONFIG.CONTAINER_ID}-timer`),
                    timerDisplayHidden: panel.querySelector(`#${CONFIG.CONTAINER_ID}-timer-hidden`),
                    startHiddenCheckbox: panel.querySelector(`#${CONFIG.CONTAINER_ID}-starthidden-check`)
                });
            }
            aggregateSessionHistory() {
                if (!this.userName) {
                    this.aggregatedHistoryData = {};
                    this.aggregatedHistoryDuration = 0;
                    return;
                }
                const aggregatedStats = {
                    [this.userName]: { items: {} }
                };
                let totalDuration = 0;
                const allRelevantHistory = this.sessionHistory.filter(s => s.key.split('@')[0].split(',').includes(this.userName)
                );
                const sortedRelevantHistory = allRelevantHistory.sort((a, b) => b.start - a.start);
                const sessionsToCombine = sortedRelevantHistory.slice(0, CONFIG.DISPLAY_HISTORY_LIMIT);
                sessionsToCombine.forEach(session => {
                    totalDuration += session.duration ?? 0;
                    if (session.stats && session.stats[this.userName] && session.stats[this.userName].items) {
                        Object.entries(session.stats[this.userName].items).forEach(([hrid, count]) => {
                            aggregatedStats[this.userName].items[hrid] = (aggregatedStats[this.userName].items[hrid] ?? 0) + count;
                        });
                    }
                });
                const liveSessionHasData = this.userName &&
                    this.playerDropStats[this.userName]?.items &&
                    Object.keys(this.playerDropStats[this.userName].items).length > 0;
                if (liveSessionHasData && this.currentSessionKey) {
                    const liveSessionKey = this.currentSessionKey;
                    const liveSessionAlreadyIncluded = sessionsToCombine.some(s => s.key === liveSessionKey);
                    if (!liveSessionAlreadyIncluded) {
                        Object.entries(this.playerDropStats[this.userName].items).forEach(([hrid, count]) => {
                            aggregatedStats[this.userName].items[hrid] = (aggregatedStats[this.userName].items[hrid] ?? 0) + count;
                        });
                        if (this.startTime) {
                            const liveEndTime = this.sessionEndTime || Date.now();
                            const liveDuration = Math.max(0, liveEndTime - this.startTime.getTime());
                            totalDuration += liveDuration;
                        }
                    }
                }
                this.aggregatedHistoryData = aggregatedStats;
                this.aggregatedHistoryDuration = totalDuration;
            }
            updateHistoryDropdown() {
                if (!this.domRefs.historySelect || !this.userName) return;
                const select = this.domRefs.historySelect;
                const previousValue = select.value;
                select.innerHTML = '';
                const liveOption = document.createElement('option');
                liveOption.value = 'live';
                liveOption.textContent = 'Live Session';
                select.appendChild(liveOption);
                const relevantHistory = this.sessionHistory
                    .filter(s => s.key.split('@')[0].split(',').includes(this.userName))
                    .sort((a, b) => b.start - a.start)
                    .slice(0, CONFIG.DISPLAY_HISTORY_LIMIT);
                if (relevantHistory.length > 0) {
                    const historyGroup = document.createElement('optgroup');
                    historyGroup.label = 'Past Sessions';
                    relevantHistory.forEach((session) => {
                        const option = document.createElement('option');
                        option.value = session.key;
                        const startTime = new Date(session.start).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
                        const durationStr = this.formatElapsedTime(session.duration).replace(/^00:/, '');
                        option.textContent = `${startTime} (${durationStr})`;
                        const locationStr = session.location ? `Location: ${session.location}\n` : '';
                        const playersStr = `Players: ${session.key.split('@')[0] || '?'}\n`;
                        option.title = `${locationStr}${playersStr}Started: ${new Date(session.start).toLocaleString()}\nEnded: ${new Date(session.end).toLocaleString()}`;
                        historyGroup.appendChild(option);
                    });
                    select.appendChild(historyGroup);
                    const combinedOption = document.createElement('option');
                    combinedOption.value = 'combined';
                    combinedOption.textContent = 'Combined History';
                    select.appendChild(combinedOption);
                }
                if (select.querySelector(`option[value="${previousValue}"]`)) {
                    select.value = previousValue;
                } else {
                    select.value = 'live';
                }
                this.viewingLive = (select.value === 'live');
            }
            setInitialCheckboxState() {
                if (this.domRefs.startHiddenCheckbox) {
                    this.domRefs.startHiddenCheckbox.checked = this.startHiddenEnabled;
                }
            }
            createTooltipElement() {
                const tooltip = document.createElement('div');
                tooltip.id = CONFIG.TOOLTIP_ID;
                document.body.appendChild(tooltip);
                this.domRefs.tooltip = tooltip;
            }
            toggleVisibility() {
                this.isHidden = !this.isHidden;
                this.domRefs.panel.classList.toggle('is-hidden', this.isHidden);
                flStorage.set('minimized', this.isHidden);
                this.hideSettingsMenu();
                if (!this.isHidden) {
                    this.renderCurrentView();
                    this.updateTimerDisplay();
                    if (this.viewingLive && this.isLiveSessionActive) {
                        this.startTimer();
                    }
                    setTimeout(() => {
                        const panel = this.domRefs.panel;
                        const rect = panel.getBoundingClientRect();
                        const winWidth = window.innerWidth;
                        const winHeight = window.innerHeight;
                        let needsAdjustment = false;
                        let newTop = parseFloat(panel.style.top) || rect.top;
                        let newRight = parseFloat(panel.style.right) || (winWidth - rect.right);
                        if (rect.right > winWidth) {
                            newRight = 10;
                            needsAdjustment = true;
                        }
                        if (rect.left < 0) {
                            const newLeft = 10;
                            newRight = winWidth - newLeft - rect.width;
                            needsAdjustment = true;
                        }
                        if (rect.bottom > winHeight) {
                            newTop = winHeight - rect.height - 10;
                            needsAdjustment = true;
                        }
                        if (rect.top < 0) {
                            newTop = 10;
                            needsAdjustment = true;
                        }
                        if (needsAdjustment) {
                            panel.style.top = newTop + 'px';
                            panel.style.right = newRight + 'px';
                            panel.style.left = 'auto';
                            const position = {
                                top: newTop + 'px',
                                right: newRight + 'px'
                            };
                            flStorage.set('position', position);
                        }
                    }, 50);
                }
                if (this.domRefs.minimizeContentButton) {
                    this.domRefs.minimizeContentButton.textContent = this.isHidden ? '+' : '−';
                }
            }
            toggleContentMinimize() {
                const content = this.domRefs.content;
                const btn = this.domRefs.minimizeContentButton;
                if (!content || !btn) return;
                const isMinimized = content.style.display === 'none';
                content.style.display = isMinimized ? 'block' : 'none';
                btn.textContent = isMinimized ? '−' : '+';
                localStorage.setItem('floot_contentMinimized', !isMinimized);
            }
            updatePlayerStats(playerInfo) {
                const name = playerInfo.name;
                if (!name) return;
                if (!this.playerDropStats[name]) {
                    this.playerDropStats[name] = { items: {} };
                }
                const pStats = this.playerDropStats[name];
                const currentLootMap = playerInfo.totalLootMap ?? {};
                pStats.items = {};
                for (const key in currentLootMap) {
                    const { itemHrid, count } = currentLootMap[key];
                    if (itemHrid && typeof count === 'number' && count > 0) {
                        pStats.items[itemHrid] = count;
                    }
                }
            }
            renderLootSections(dataSource) {
                window._isRendering = true;
                if (!this.domRefs.content || this.isHidden) {
                    window._isRendering = false;
                    return;
                }
                const currentSessionKey = this.viewingLive ?
                    'live' :
                    (this.domRefs.historySelect?.value || 'live');
                const playerNames = Object.keys(dataSource).sort((a, b) => {
                    if (a === this.userName) return -1;
                    if (b === this.userName) return 1;
                    return a.localeCompare(b);
                });
                this.domRefs.content.innerHTML = '';
                if (playerNames.length === 0 || (this.isViewingCombined() && (!dataSource[this.userName] || Object.keys(dataSource[this.userName].items).length === 0))) {
                    let message = 'No active combat session.<br><small class="ldt-empty-help-text">If drops are happening but loot is not showing up here<br>Try refreshing the window<br><b>Browser</b>: F5 or Reload Button<br><b>Steam Client</b>: Top Menu > View > Reload</small>';
                    if (this.viewingLive && this.isLiveSessionActive) {
                        message = 'Waiting for loot data...';
                    } else if (this.viewingLive && !this.isLiveSessionActive && this.startTime) {
                        message = 'Session ended. No loot collected.';
                    } else if (!this.viewingLive && !this.isViewingCombined()) {
                        message = 'No data in selected session for this character.';
                    } else if (this.isViewingCombined()) {
                        message = `No loot found for ${this.userName} in the combined history view.`;
                    }
                    this.domRefs.content.innerHTML = `<div class="ldt-body-empty">${message}</div>`;
                    window._isRendering = false;
                    return;
                }
                const fragment = document.createDocumentFragment();
                const searchTerm = this.currentSearchTerm.toLowerCase();
                playerNames.forEach(playerName => {
                    if (this.isViewingCombined() && playerName !== this.userName) return;
                    const pStats = dataSource[playerName];
                    if (!pStats) return;
                    const items = pStats.items;
                    const sectionDiv = document.createElement('div');
                    sectionDiv.className = 'ldt-player-stats-section';
                    const headerDiv = document.createElement('div');
                    headerDiv.className = 'ldt-player-name-header';
                    headerDiv.textContent = playerName;
                    if (playerName === this.userName) {
                        headerDiv.classList.add('is-current-player');
                    }
                    const listDiv = document.createElement('ul');
                    listDiv.className = 'ldt-loot-list';
                    let sortedItems = Object.entries(items ?? {}).filter(([, count]) => count > 0);
                    if (this.sortPreference === 'name') {
                        sortedItems.sort((a, b) => a[0].localeCompare(b[0]));
                    } else {
                        sortedItems.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
                    }
                    if (sortedItems.length === 0) {
                        listDiv.innerHTML = `<li class="ldt-body-empty ldt-body-empty-item">No items collected.</li>`;
                    } else {
                        sortedItems.forEach(([hrid, count]) => {
                            const name = hrid;
                            const visname = hrid.replace("/items/",
                                "").replace(/_/g, " ");
                            const itemLi = document.createElement('li');
                            itemLi.className = 'ldt-loot-item-entry';
                            const visnameSpan = document.createElement('span');
                            visnameSpan.className = 'ldt-vis-name';
                            visnameSpan.textContent = visname;
                            const nameSpan = document.createElement('span');
                            nameSpan.className = 'ldt-item-name';
                            nameSpan.textContent = name;
                            const valueSpan = document.createElement('span');
                            valueSpan.className = 'ldt-item-value';
                            const calculatedValue = getUnitValue(name, currentSessionKey);
                            valueSpan.textContent = (calculatedValue !== null) ? calculatedValue : 'N/A';
                            const countSpan = document.createElement('span');
                            countSpan.className = 'ldt-item-count';
                            countSpan.textContent = ` × ${formatNumberWithCommas(count)}`;
                            if (searchTerm && name.toLowerCase().includes(searchTerm)) {
                                itemLi.classList.add('highlight-match');
                            }
                            itemLi.appendChild(visnameSpan);
                            itemLi.appendChild(nameSpan);
                            itemLi.appendChild(valueSpan);
                            itemLi.appendChild(countSpan);
                            listDiv.appendChild(itemLi);
                            setTimeout(() => {
                            }, 0);
                        });
                    }
                    sectionDiv.appendChild(headerDiv);
                    sectionDiv.appendChild(listDiv);
                    fragment.appendChild(sectionDiv);
                });
                this.domRefs.content.appendChild(fragment);
                window._isRendering = false;
                injectValuesAndSort();
            }
            renderCurrentView() {
                if (this.isHidden) return;
                const selectedValue = this.domRefs.historySelect?.value;
                if (this.viewingLive || selectedValue === 'live' || !selectedValue) {
                    this.renderLootSections(this.playerDropStats);
                } else if (selectedValue === 'combined') {
                    if (this.aggregatedHistoryData === null) {
                        this.aggregateSessionHistory();
                    }
                    this.renderLootSections(this.aggregatedHistoryData);
                } else {
                    const selectedSession = this.sessionHistory.find(s => s.key === selectedValue);
                    if (selectedSession && selectedSession.key.split('@')[0].split(',').includes(this.userName)) {
                        this.renderLootSections(selectedSession.stats);
                    } else {
                        this.renderLootSections({});
                    }
                }
            }
            exportLootCsv() {
                let dataSource = {};
                let sourceDescription = "Unknown View";
                const selectedValue = this.domRefs.historySelect?.value;
                if (this.viewingLive || selectedValue === 'live') {
                    dataSource = this.playerDropStats;
                    sourceDescription = "Live / Last Session";
                    if (this.lastKnownActionHrid) {
                        sourceDescription += ` (${formatLocationName(this.lastKnownActionHrid)})`;
                    }
                } else if (selectedValue === 'combined') {
                    if (this.aggregatedHistoryData === null) this.aggregateSessionHistory();
                    dataSource = this.aggregatedHistoryData;
                    sourceDescription = `Combined History (${this.userName || 'Current User'})`;
                } else {
                    const selectedSession = this.sessionHistory.find(s => s.key === selectedValue);
                    if (selectedSession && selectedSession.key.split('@')[0].split(',').includes(this.userName)) {
                        dataSource = selectedSession.stats;
                        const startTimeStr = new Date(selectedSession.start).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
                        const locationStr = selectedSession.location ? ` - ${selectedSession.location}` : '';
                        sourceDescription = `Session @ ${startTimeStr}${locationStr}`;
                    } else {
                        this.flashExportButtonState('Error', 'ldt-btn-error', 2500);
                        return;
                    }
                }
                const playerNames = Object.keys(dataSource);
                const button = this.domRefs.exportButton;
                button.disabled = true;
                if (playerNames.length === 0 || (selectedValue === 'combined' && (!dataSource[this.userName] || Object.keys(dataSource[this.userName].items).length === 0))) {
                    this.flashExportButtonState('No Data', 'ldt-btn-error', 1500);
                    return;
                }
                let csvRows = [];
                let hasItems = false;
                playerNames.forEach(playerName => {
                    if (selectedValue === 'combined' && playerName !== this.userName) return;
                    const pStats = dataSource[playerName]; if (!pStats) return;
                    const items = pStats.items ?? {};
                    const sortedItems = Object.entries(items)
                        .filter(([, count]) => count > 0)
                        .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
                    sortedItems.forEach(([hrid, count]) => {
                        const itemName = hrid;
                        const visitemName = hrid.replace("/items/",
                            "").replace(/_/g, " ");
                        const safePlayerName = `"${playerName.replace(/"/g, '""')}"`;
                        const safeItemName = `"${itemName.replace(/"/g, '""')}"`;
                        csvRows.push(`${safePlayerName},${itemName},${count}`);
                        hasItems = true;
                    });
                });
                if (!hasItems) {
                    this.flashExportButtonState('No Items', 'ldt-btn-error', 1500);
                    return;
                }
                const csvHeader = "Player,Item Name,Count\n";
                const csvContent = csvHeader + csvRows.join("\n");
                navigator.clipboard.writeText(csvContent).then(() => {
                    this.flashExportButtonState('Copied!', 'ldt-btn-copied', 1800);
                }).catch(err => {
                    console.error("LDT: Failed to copy CSV data to clipboard:", err);
                    this.flashExportButtonState('Error', 'ldt-btn-error', 2500);
                });
            }
            flashExportButtonState(text, className, duration) {
                const button = this.domRefs.exportButton;
                if (!button) return;
                const originalText = button.textContent;
                const originalClasses = button.className;
                button.textContent = text;
                button.className = `ldt-export-btn ${className}`;
                setTimeout(() => {
                    if (button) {
                        button.textContent = originalText;
                        button.className = originalClasses;
                        button.disabled = false;
                    }
                }, duration);
            }
            ensureCombatSuiteVisible() {
                const suiteBtn = document.getElementById('mwi-combat-suite-btn');
                if (!suiteBtn) return;
                const rect = suiteBtn.getBoundingClientRect();
                const windowWidth = window.innerWidth;
                if (rect.left > windowWidth - 100) {
                    const newLeft = Math.max(20, (windowWidth / 2) - 75);
                    suiteBtn.style.left = newLeft + 'px';
                    suiteBtn.style.right = 'auto';
                    localStorage.setItem('mcs__global_combat_suite_btn_position', JSON.stringify({
                        left: newLeft
                    }));
                }
            }
            createEquipmentSpy() {
                this.initializeGlobalStyles();

                window.equipmentSpyInstance = this;
                this.pageLoadTime = Date.now();
                this.spyMarketData = {};
                this._spyCharacterItems = [];
                this.spyItemDetailMap = {};
                const savedMinimized = this.ewStorage.get('minimized');
                this.spyIsMinimized = savedMinimized === true || savedMinimized === 'true';
                this.spyLockedComparisons = {};
                this.spyPriceType = 'bid';
                const CONFIG_SPY = {
                    PANE_ID: 'equipment-spy-pane',
                    MAIN_COLOR: '#4CAF50',
                    BG_COLOR: 'rgba(30, 30, 30, 0.95)',
                    BORDER_COLOR: '#555',
                    ALLOWED_SLOTS: [
                        'body', 'charm', 'earrings', 'feet', 'hands',
                        'head', 'legs', 'main_hand', 'neck', 'off_hand',
                        'pouch', 'ring', 'two_hand'
                    ]
                };
                this.spyConfig = CONFIG_SPY;
                this.loadSpyMarketData();
                const savedTimestamp = localStorage.getItem('mcs__global_EW_market_timestamp');
                if (savedTimestamp) {
                    this.spyMarketDataTimestamp = parseInt(savedTimestamp);
                }
                this.loadSpySettings();
                const savedSimpleMode = this.ewStorage.get('simple_mode');
                if (savedSimpleMode === true || savedSimpleMode === 'true') {
                    this.spySimpleMode = true;
                }
                this.spyNoSellMode = false;
                const savedNoSellMode = this.ewStorage.get('no_sell_mode');
                if (savedNoSellMode === true || savedNoSellMode === 'true') {
                    this.spyNoSellMode = true;
                }
                this.extractItemDetailMapFromPage();
                this.setupPageContextBridge();
                this.createSpyPane();
                this.createConsumablesPane();
                this.createJHousePane();
                this.createKOllectionPane();
                this.mcs_nt_createPane();
                this.createPFormancePane();
                this.createQCharmPane();
                this.createTReasurePane();
                this.createOPanel();
                this.createBReadPane();
                this.createGWhizPane();
                this.createAMazingPane();
                this.createDPsPane();
                this.createMEatersPane();
                this.createHWhatPanel();
                this.createIHurtPane();
                this.createMAnaPane();
                this.createLuckyPanel();
                setTimeout(() => {
                    this.ensureCombatSuiteVisible();
                }, 500);
                this.startEquipmentPolling();
                this.interceptNetworkRequests();
                this.waitForCharacterData();
            }
            startEquipmentPolling() {
                const self = this;

                self._equipChangedListener = (event) => {
                    if (window.MCS_MODULES_DISABLED) return;

                    const playerName = event.detail?.playerName;

                    if (self.spyIsInteracting) {
                        return;
                    }

                    const spyPane = document.getElementById('equipment-spy-pane');
                    if (!spyPane || spyPane.style.display === 'none') {
                        return;
                    }

                    try {
                        const newData = window.mcs__global_equipment_tracker?.allCharacterItems;
                        if (!newData) return;

                        self.spyCharacterItems = newData;

                        self.updateSpyDisplay();
                        self.updateCoinHeader();
                    } catch (e) {
                        console.error('[EWatch] Error updating from equipment change:', e);
                    }
                };
                window.addEventListener('MCS_EquipmentChanged', self._equipChangedListener);

                VisibilityManager.register('ewatch-display-update', () => {
                    if (window.MCS_MODULES_DISABLED) return;
                    if (self.spyIsInteracting) return;

                    const spyPane = document.getElementById('equipment-spy-pane');
                    if (!spyPane || spyPane.style.display === 'none') return;

                    self.updateCoinHeader();
                }, 2000);
            }
            equipmentHasChanged(newEquipment) {
                const currentEquipped = this.spyCharacterItems.filter(item => item.itemLocationHrid && item.itemLocationHrid !== '/item_locations/inventory'
                );
                if (currentEquipped.length !== newEquipment.length) {
                    return true;
                }
                for (const newItem of newEquipment) {
                    const existing = currentEquipped.find(item => item.itemLocationHrid === newItem.itemLocationHrid
                    );
                    if (!existing || existing.hash !== newItem.hash) {
                        return true;
                    }
                }
                return false;
            }
            waitForCharacterData() {
                let attempts = 0;
                const maxAttempts = 200;
                const checkInterval = setInterval(() => {
                    attempts++;
                    if (this.spyCharacterItems && this.spyCharacterItems.length > 0) {
                        clearInterval(checkInterval);
                        this.updateSpyDisplay();
                        if (!this.coinHeaderInterval) {
                            VisibilityManager.register('ewatch-coin-header', () => {
                                this.updateCoinHeader();
                            }, 1000);
                            this.coinHeaderInterval = true;
                        }
                        return;
                    }
                    const bridge = document.getElementById('equipspy-data-bridge');
                    if (bridge) {
                        const dataAttr = bridge.getAttribute('data-character-items');
                        if (dataAttr) {
                            try {
                                const items = JSON.parse(dataAttr);
                                if (items && items.length > 0) {
                                    this.spyCharacterItems = items;
                                    clearInterval(checkInterval);
                                    this.updateSpyDisplay();
                                    if (!this.coinHeaderInterval) {
                                        VisibilityManager.register('ewatch-coin-header', () => {
                                            this.updateCoinHeader();
                                        }, 1000);
                                        this.coinHeaderInterval = true;
                                    }
                                    return;
                                }
                            } catch (e) {
                                console.error('[EquipSpy] Error parsing bridge data:', e);
                            }
                        }
                    }
                    if (attempts >= maxAttempts) {
                        console.warn('[EquipSpy] Timed out waiting for character data');
                        clearInterval(checkInterval);
                        this.updateSpyDisplay();
                    }
                }, 500);
            }
            constrainPanelToBoundaries(paneId, storageKey = null, useLeftTop = true) {
                const pane = document.getElementById(paneId);
                if (!pane) return;
                requestAnimationFrame(() => {
                    const rect = pane.getBoundingClientRect();
                    const winWidth = window.innerWidth;
                    const winHeight = window.innerHeight;
                    let needsAdjustment = false;
                    let newLeft = rect.left;
                    let newTop = rect.top;
                    let newRight = winWidth - rect.right;
                    if (rect.right > winWidth) {
                        if (useLeftTop) {
                            newLeft = winWidth - rect.width;
                        } else {
                            newRight = 0;
                        }
                        needsAdjustment = true;
                    }
                    if (rect.left < 0 || newLeft < 0) {
                        newLeft = 0;
                        needsAdjustment = true;
                    }
                    if (rect.bottom > winHeight) {
                        newTop = winHeight - rect.height;
                        needsAdjustment = true;
                    }
                    if (newTop < 0) {
                        newTop = 0;
                        needsAdjustment = true;
                    }
                    if (useLeftTop) {
                        pane.style.left = newLeft + 'px';
                        pane.style.top = newTop + 'px';
                        pane.style.right = 'auto';
                    } else {
                        pane.style.right = newRight + 'px';
                        pane.style.top = newTop + 'px';
                        pane.style.left = 'auto';
                    }
                    if (storageKey) {
                        const positionData = useLeftTop
                            ? { top: newTop, left: newLeft }
                            : { top: newTop, right: newRight };

                        if (storageKey.match(/^mcs_[A-Z]{2}$/)) {
                            const modulePrefix = storageKey.replace('mcs_', '');
                            const storage = createModuleStorage(modulePrefix);
                            storage.set('position', positionData);
                        } else {
                            CharacterStorageUtils.setItem(storageKey, JSON.stringify(positionData));
                        }
                    }
                });
            }
            loadSpySettings() {
                try {
                    const savedLocked = this.ewStorage.get('locked');
                    if (savedLocked) {
                        this.spyLockedComparisons = typeof savedLocked === 'string' ? JSON.parse(savedLocked) : savedLocked;
                    }
                    const savedMin = this.ewStorage.get('minimized');
                    if (savedMin === true || savedMin === 'true') {
                        this.spyIsMinimized = true;
                    }
                    const savedHeaderSlot = this.ewStorage.get('selected_header_slot');
                    if (savedHeaderSlot) {
                        this.spySelectedHeaderSlot = savedHeaderSlot;
                    }
                    this.loadComparisonOrder();
                } catch (e) {
                    console.error('[EquipSpy] Failed to load settings:', e);
                }
            }
            saveComparisonOrder() {
                if (!this.comparisonOrder) return;
                this.ewStorage.set('comparison_order', this.comparisonOrder);
            }
            loadComparisonOrder() {
                try {
                    const saved = this.ewStorage.get('comparison_order');
                    if (saved) {
                        this.comparisonOrder = typeof saved === 'string' ? JSON.parse(saved) : saved;
                    } else {
                        this.comparisonOrder = [];
                    }
                } catch (e) {
                    console.error('[EquipSpy] Failed to load comparison order:', e);
                    this.comparisonOrder = [];
                }
            }
            getOrderedSlots(slots) {
                const availableSlots = Object.keys(slots);
                const orderedSlots = this.comparisonOrder.filter(slot => availableSlots.includes(slot));
                availableSlots.forEach(slot => {
                    if (!orderedSlots.includes(slot)) {
                        orderedSlots.push(slot);
                    }
                });
                return orderedSlots;
            }

            // css start

            initializeGlobalStyles() {
                    if (this.cssStyleSheet) return;

                    const styleElement = document.createElement('style');
                    styleElement.id = 'mcs-global-styles';
                    document.head.appendChild(styleElement);
                    this.cssStyleSheet = styleElement.sheet;
                    this.cssStyleElement = styleElement;

                    this.addGlobalStyles();
                }

                addGlobalStyles() {
        const baseStyles = `
            .mcs-pane {
                position: fixed;
                top: 0;
                left: 0;
                background: #2b2b2b;
                border-radius: 6px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                z-index: 99999;
                font-family: sans-serif;
                display: flex;
                flex-direction: column;
            }

            .mcs-pane-dark {
                background: #1a1a1a;
            }

            .mcs-pane-header {
                background: #333333;
                color: #eeeeee;
                padding: 8px 12px;
                font-weight: bold;
                cursor: move;
                border-radius: 6px 6px 0 0;
                display: flex;
                justify-content: space-between;
                align-items: center;
                user-select: none;
                gap: 10px;
            }

            .mcs-pane-header.minimized {
                border-radius: 6px;
            }

            .mcs-pane-title {
                font-size: 14px;
                white-space: nowrap;
            }

            .mcs-pane-content {
                padding: 10px;
                color: #e0e0e0;
                font-size: 11px;
                display: flex;
                flex-direction: column;
                gap: 8px;
                align-items: stretch;
            }

            .mcs-pane-content-dark {
                background: #0a0a0a;
            }

            /* Base button shared across all modules */
            .mcs-btn,
            .mcs-filter-btn,
            .mcs-crack-reset-btn,
            .mcs-crack-minimize-btn,
            .mcs-dps-filter-btn,
            .mcs-dps-reset-btn,
            .mcs-qcharm-btn {
                background: #555;
                color: #fff;
                border: 1px solid #666;
                border-radius: 3px;
                cursor: pointer;
                font-weight: bold;
                transition: background 0.2s;
            }

            /* Hover state for all base buttons */
            .mcs-btn:hover,
            .mcs-filter-btn:hover,
            .mcs-crack-reset-btn:hover,
            .mcs-crack-minimize-btn:hover,
            .mcs-dps-filter-btn:hover,
            .mcs-dps-reset-btn:hover,
            .mcs-qcharm-btn:hover {
                background: #666;
            }

            /* Size variants */
            .mcs-btn {
                padding: 6px 12px;
                font-size: 12px;
            }

            .mcs-btn-small,
            .mcs-filter-btn,
            .mcs-dps-filter-btn,
            .mcs-dps-reset-btn {
                padding: 4px 8px;
                font-size: 11px;
            }

            .mcs-btn-minimize,
            .mcs-crack-minimize-btn,
            .mcs-qcharm-btn {
                padding: 4px 10px;
                font-size: 14px;
                line-height: 1;
            }

            .mcs-crack-reset-btn {
                padding: 4px 8px;
                font-size: 11px;
            }

            .mcs-btn-active {
                background: #4CAF50;
                color: #fff;
            }

            .mcs-btn-active:hover {
                background: #66BB6A;
            }

            .mcs-btn-warning {
                background: #DC143C;
                color: #fff;
            }

            .mcs-btn-warning:hover {
                background: #FF1744;
            }

            .mcs-btn-alert {
                background: #FFA500;
                color: #000;
            }

            .mcs-btn-alert:hover {
                background: #FFB52E;
            }

            .mcs-container {
                display: flex;
                flex-direction: column;
                gap: 8px;
                padding: 8px;
                background: #333;
                border-radius: 4px;
            }

            .mcs-row {
                display: flex;
                align-items: center;
                gap: 10px;
            }

            .mcs-text {
                color: #e0e0e0;
                font-size: 11px;
            }

            .mcs-text-description {
                color: #bbb;
                font-size: 11px;
                flex: 1;
            }

            .mcs-text-highlight {
                color: #FFD700;
            }

            .mcs-text-success {
                color: #4CAF50;
            }

            .mcs-filter-container {
                display: flex;
                gap: 4px;
                align-items: center;
            }

            /* Filter button states (base style now consolidated above) */
            .mcs-filter-btn.active {
                background: #4CAF50;
                color: #fff;
            }

            .mcs-filter-btn.inactive {
                background: #333333;
                color: #888;
            }

            .mcs-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: #1a1a1a;
                z-index: 99996;
                pointer-events: none;
            }

            .mcs-meaters-info-dialog {
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                background: rgba(30, 30, 40, 0.98);
                border: 2px solid #4CAF50;
                border-radius: 8px;
                padding: 16px 20px;
                z-index: 100000;
                box-shadow: 0 4px 20px rgba(0,0,0,0.8);
                max-width: 500px;
                color: #fff;
                font-family: sans-serif;
            }

            .mcs-hidden {
                display: none !important;
            }

            .mcs-display-flex {
                display: flex;
            }

            /* Gap utilities (sequential order) */
            .mcs-gap-4 {
                gap: 4px;
            }

            .mcs-gap-6 {
                gap: 6px;
            }

            .mcs-gap-8 {
                gap: 8px;
            }

            .mcs-gap-10 {
                gap: 10px;
            }

            .mcs-gap-15 {
                gap: 15px;
            }

            /* Font-size utilities (sequential order) */
            .mcs-font-9 {
                font-size: 9px;
            }

            .mcs-font-14 {
                font-size: 14px;
            }

            .mcs-font-16 {
                font-size: 16px;
            }

            .mcs-font-22 {
                font-size: 22px;
            }

            /* Size utilities */
            .mcs-width-fit {
                width: fit-content;
            }

            .mcs-height-auto {
                height: auto;
            }

            .mcs-amazing-pane {
                width: auto;
            }

            .mcs-meaters-pane {
                width: 700px;
            }

            .mcs-meaters-content {
                padding: 10px;
                overflow-y: auto;
                overflow-x: hidden;
            }

            .mcs-meaters-empty {
                color: #666;
                text-align: center;
                padding: 20px;
            }

            .mcs-meaters-info-title {
                font-size: 14px;
                font-weight: bold;
                margin-bottom: 8px;
            }

            .mcs-meaters-info-text {
                font-size: 12px;
                line-height: 1.6;
                color: #ddd;
            }

            .mcs-meaters-info-close {
                margin-top: 12px;
            }

            .mcs-meaters-log-entry {
                margin-bottom: 2px;
                padding: 3px 8px;
                background: rgba(255,255,255,0.02);
                border-radius: 3px;
                font-size: 11px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
                line-height: 16px;
                min-height: 22px;
                display: flex;
                align-items: center;
            }

            .mcs-meaters-log-player {
                border-left: 3px solid transparent;
            }

            .mcs-meaters-log-enemy {
                border-right: 3px solid transparent;
                text-align: right;
                justify-content: flex-end;
            }

            .mcs-meaters-timestamp {
                color: #87CEEB;
                font-weight: bold;
            }

            .mcs-meaters-separator {
                color: #666;
            }

            .mcs-meaters-player-name {
                color: #90EE90;
            }

            .mcs-meaters-ability {
                color: #FFA500;
            }

            .mcs-meaters-damage {
                font-weight: bold;
            }

            .mcs-meaters-monster-name {
                color: #FF6B9D;
            }

            .mcs-bread-pane {
                width: fit-content;
                height: auto;
                max-height: 80vh;
                max-width: 95vw;
                min-width: 200px;
            }

            .mcs-bread-content {
                overflow-y: auto;
                overflow-x: visible;
                flex: 1 1 auto;
            }

            .mcs-bread-item {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 10px;
                padding: 3px;
                min-width: 0;
                flex-shrink: 0;
            }

            .mcs-bread-level {
                color: #FFD700;
                font-weight: bold;
                text-align: right;
                min-width: 35px;
                flex-shrink: 0;
            }

            .mcs-bread-icon {
                flex-shrink: 0;
            }

            .mcs-bread-exp-container {
                display: flex;
                flex-direction: column;
                gap: 2px;
                min-width: 60px;
                flex: 0 1 auto;
            }

            .mcs-bread-exp {
                color: #4CAF50;
                font-weight: bold;
                text-align: left;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            .mcs-bread-rate {
                color: #90EE90;
                text-align: left;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            .mcs-bread-time {
                color: #87CEEB;
                font-weight: bold;
                text-align: center;
                min-width: 50px;
                flex: 0 0 60px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            .mcs-bread-books {
                color: #FFA500;
                font-weight: bold;
                text-align: right;
                min-width: 60px;
                flex: 0 0 auto;
                white-space: nowrap;
                overflow: visible;
            }

            .mcs-bread-market {
                color: #FFD700;
                font-weight: bold;
                text-align: right;
                min-width: 55px;
                flex: 0 0 auto;
                white-space: nowrap;
                overflow: visible;
            }

            .mcs-bread-input {
                width: 45px;
                min-width: 45px;
                padding: 2px 4px;
                background: #333;
                color: #fff;
                border: 1px solid #555;
                border-radius: 3px;
                flex: 0 0 45px;
            }

            .mcs-bread-no-abilities {
                padding: 20px;
                text-align: center;
                color: #999;
            }

            .mcs-button-section {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-bread-header {
                gap: 15px;
                flex-shrink: 0;
            }

            .mcs-bread-title-section {
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-bread-header-info {
                display: flex;
                align-items: center;
                gap: 4px;
                font-size: 11px;
            }

            .mcs-bread-header-books {
                color: #4CAF50;
                font-weight: bold;
            }

            .mcs-bread-header-label {
                color: #aaa;
            }

            .mcs-bread-header-cost {
                color: #FFD700;
            }

            .mcs-bread-range-calc {
                display: flex;
                align-items: center;
                gap: 8px;
                padding: 6px 12px;
                background: #2a2a2a;
                border-bottom: 1px solid #444;
                font-size: 11px;
            }

            .mcs-bread-range-input {
                width: 50px;
                padding: 4px 6px;
                background: #333;
                color: #fff;
                border: 1px solid #555;
                border-radius: 3px;
                font-size: 11px;
                text-align: center;
            }

            .mcs-bread-range-result {
                display: flex;
                flex-direction: column;
                gap: 2px;
                font-size: 10px;
                color: #aaa;
                margin-left: 8px;
            }

            .mcs-bread-range-result div {
                white-space: nowrap;
            }

            .mcs-bread-range-result strong {
                color: #4CAF50;
                font-weight: bold;
            }

            /* Pane header when minimized */
            .mcs-pane-header-minimized {
                border-radius: 6px;
            }

            .mcs-crack-pane {
                position: fixed;
                top: 0;
                left: 0;
                width: fit-content;
                min-width: 380px;
                max-width: 600px;
                max-height: 80vh;
                background: #1a1a1a;
                border: none;
                border-radius: 8px;
                z-index: 10001;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                display: flex;
                flex-direction: column;
                overflow: hidden;
            }

            .mcs-crack-header {
                background: #2a2a2a;
                padding: 6px 10px;
                cursor: move;
                user-select: none;
                border-bottom: 1px solid #4a4a4a;
                display: flex;
                justify-content: space-between;
                align-items: center;
                font-size: 11px;
                color: #90EE90;
                font-weight: bold;
            }

            .mcs-crack-header-left {
                display: flex;
                align-items: center;
                gap: 15px;
            }

            .mcs-crack-title {
                font-size: 14px;
                color: white;
                font-weight: bold;
            }

            .mcs-crack-eta-container {
                font-size: 14px;
            }

            .mcs-crack-eta-container #consumables-days-left {
                color: inherit;
            }

            .mcs-crack-party-eta-container {
                font-size: 14px;
            }

            .mcs-crack-button-container {
                display: flex;
                gap: 6px;
                align-items: center;
            }

            /* CRack button overrides (base styles consolidated above) */
            .mcs-crack-reset-btn {
                background: #444;
                padding: 2px 8px;
                font-size: 14px;
                line-height: 1;
            }

            .mcs-crack-reset-btn:hover {
                background: #555;
            }

            .mcs-crack-content {
                padding: 8px;
                color: white;
                font-size: 12px;
                overflow-y: auto;
                flex: 1;
            }

            .mcs-crack-minimized-summary {
                padding: 8px 10px;
                display: flex;
                justify-content: space-between;
                align-items: center;
                border-top: 1px solid #4a4a4a;
                background: #1a1a1a;
            }

            .mcs-crack-summary-left {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-crack-summary-count {
                color: #ff6666;
                font-weight: bold;
                font-size: 12px;
            }

            .mcs-crack-summary-name {
                color: #e0e0e0;
                font-size: 11px;
            }

            .mcs-crack-summary-right {
                text-align: right;
                font-size: 9px;
            }

            .mcs-crack-summary-cost-label {
                color: #90EE90;
                font-weight: bold;
            }

            .mcs-crack-summary-cost-value {
                color: white;
            }

            /* CRack consumable row styles */
            .mcs-crack-consumable-row {
                display: flex;
                align-items: center;
                gap: 8px;
            }

            .mcs-crack-consumable-container {
                display: flex;
                flex-direction: column;
                padding: 4px 0;
                gap: 2px;
            }

            .mcs-crack-consumable-count {
                min-width: 35px;
                text-align: right;
                font-size: 12px;
                font-weight: bold;
            }

            .mcs-crack-consumable-icon {
                flex-shrink: 0;
                cursor: pointer;
            }

            .mcs-crack-consumable-name {
                font-size: 12px;
                flex: 1;
                min-width: 0;
            }

            .mcs-crack-consumable-name-warning {
                color: #ff6666;
            }

            .mcs-crack-count-placeholder {
                color: #666;
            }

            .mcs-crack-name-placeholder {
                color: #666;
            }

            .mcs-crack-stack-container {
                display: flex;
                flex-direction: column;
                gap: 2px;
            }

            .mcs-crack-stack-row {
                display: flex;
                gap: 8px;
            }

            .mcs-crack-stat-actual {
                color: #4CAF50;
                font-size: 9px;
                min-width: 45px;
                text-align: right;
            }

            .mcs-crack-stat-combined {
                color: #888;
                font-size: 8px;
                min-width: 45px;
                text-align: right;
            }

            .mcs-crack-stat-count {
                min-width: 35px;
                text-align: right;
            }

            .mcs-crack-per-day {
                color: white;
                font-size: 10px;
                min-width: 60px;
                text-align: right;
            }

            .mcs-crack-time-remaining {
                font-size: 10px;
                min-width: 45px;
                text-align: right;
            }

            .mcs-crack-waiting {
                color: #999;
                font-size: 10px;
                min-width: 100px;
                text-align: center;
                font-style: italic;
            }

            .mcs-crack-tracker-error {
                color: #f88;
                font-size: 10px;
                min-width: 100px;
                text-align: center;
                font-style: italic;
            }

            .mcs-crack-total-cost {
                margin-top: 10px;
                padding-top: 8px;
                border-top: 1px solid #555;
                font-size: 10px;
                text-align: right;
            }

            .mcs-crack-party-section {
                margin-top: 15px;
                padding-top: 10px;
                border-top: 1px solid #555;
            }

            .mcs-crack-party-name {
                font-weight: bold;
                margin-bottom: 8px;
                color: #90EE90;
                font-size: 11px;
            }

            .mcs-crack-reset-complete {
                text-align: center;
                color: #4CAF50;
                padding: 10px;
                background: #2a2a2a;
                border-radius: 4px;
                margin-bottom: 10px;
            }

            .mcs-crack-reset-title {
                font-size: 14px;
                font-weight: bold;
            }

            .mcs-crack-reset-waiting {
                font-size: 12px;
                margin-top: 5px;
            }

            .mcs-crack-reset-subtitle {
                font-size: 11px;
                margin-top: 3px;
                color: #888;
            }

            .mcs-crack-no-data {
                text-align: center;
                color: #888;
                padding: 10px;
            }

            .mcs-crack-price-text {
                color: white;
                font-size: 9px;
                margin-left: 4px;
                white-space: nowrap;
                display: flex;
                flex-direction: column;
                line-height: 1.2;
                text-align: right;
                min-width: 80px;
            }

            /* Color states for ETA warnings */
            .mcs-crack-eta-critical {
                color: #c42323;
            }

            .mcs-crack-eta-warning {
                color: #e8a738;
            }

            .mcs-crack-eta-good {
                color: #65b83e;
            }

            .mcs-crack-time-critical {
                color: #FF6B6B;
            }

            .mcs-crack-time-warning {
                color: #FFA500;
            }

            .mcs-crack-time-normal {
                color: #4CAF50;
            }

            .mcs-crack-count-critical {
                color: #ff6666;
            }

            .mcs-crack-count-warning {
                color: #FFA500;
            }

            /* Party ETA color states */
            .mcs-crack-party-eta-disabled {
                color: grey;
            }

            .mcs-crack-party-eta-critical {
                color: #FF6B6B;
            }

            .mcs-crack-party-eta-warning {
                color: #FFA500;
            }

            .mcs-crack-party-eta-good {
                color: #90EE90;
            }

            .mcs-dps-pane {
                width: auto;
            }

            .mcs-dps-header {
                gap: 10px;
            }

            .mcs-dps-inactivity-timer {
                margin-left: 10px;
                font-size: 12px;
                opacity: 0.7;
            }

            .mcs-dps-title {
                font-size: 14px;
                white-space: nowrap;
            }

            .mcs-dps-button-container {
                display: flex;
                gap: 6px;
                align-items: center;
            }

            /* DPs button states (base styles consolidated above) */
            .mcs-dps-filter-btn.enabled {
                background: #4CAF50;
            }

            /* DPs info button (unique style) */
            .mcs-dps-info-btn {
                background: #2196F3;
                color: #fff;
                border: 1px solid #666;
                border-radius: 3px;
                padding: 4px 10px;
                font-size: 11px;
                cursor: pointer;
            }

            .mcs-dps-content {
                padding: 10px;
                color: #e0e0e0;
                font-size: 11px;
                display: flex;
                flex-direction: column;
                gap: 8px;
                align-items: stretch;
                max-height: 600px;
                overflow-y: auto;
            }

            .mcs-dps-info-panel {
                display: none;
                padding: 12px;
                background: rgba(33, 150, 243, 0.1);
                border: 1px solid #2196F3;
                border-radius: 4px;
                color: #e0e0e0;
                font-size: 12px;
                line-height: 1.6;
                margin-bottom: 10px;
            }

            .mcs-dps-info-title {
                font-weight: bold;
                font-size: 13px;
                margin-bottom: 8px;
                color: #2196F3;
            }

            .mcs-dps-info-text {
                margin-bottom: 6px;
            }

            .mcs-dps-waiting {
                padding: 40px 20px;
                text-align: center;
                color: #999;
                display: flex;
                flex-direction: column;
                align-items: center;
                gap: 12px;
            }

            .mcs-dps-waiting.minimized {
                padding: 10px 20px;
                gap: 6px;
            }

            .mcs-dps-waiting-icon {
                font-size: 32px;
            }

            .mcs-dps-waiting-icon.minimized {
                font-size: 16px;
            }

            .mcs-dps-waiting-text {
                font-size: 13px;
            }

            .mcs-dps-waiting-text.minimized {
                font-size: 11px;
            }

            .mcs-dps-header-row {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 8px;
                padding: 5px 3px;
                font-weight: bold;
                color: #FFD700;
                border-bottom: 2px solid #555;
                margin-bottom: 5px;
                font-size: 10px;
            }

            .mcs-dps-header-col {
                text-align: left;
            }

            .mcs-dps-header-char {
                min-width: 120px;
            }

            .mcs-dps-header-dps {
                min-width: 60px;
                text-align: right;
            }

            .mcs-dps-header-damage {
                min-width: 80px;
                text-align: right;
            }

            .mcs-dps-header-atks {
                min-width: 45px;
                text-align: right;
            }

            .mcs-dps-header-hits {
                min-width: 50px;
                text-align: right;
            }

            .mcs-dps-header-crits {
                min-width: 50px;
                text-align: right;
            }

            .mcs-dps-header-misses {
                min-width: 50px;
                text-align: right;
            }

            .mcs-dps-player-item {
                display: flex;
                flex-direction: column;
                gap: 2px;
                padding: 5px 0;
            }

            .mcs-dps-player-item.bordered {
                border-bottom: 1px solid #444;
            }

            .mcs-dps-player-row {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 8px;
                padding: 3px;
                cursor: pointer;
            }

            .mcs-dps-player-row.minimized {
                cursor: default;
            }

            .mcs-dps-expand-arrow {
                font-size: 10px;
                color: #FFD700;
                min-width: 15px;
            }

            .mcs-dps-name-label {
                font-size: 13px;
                color: #87CEEB;
                font-weight: bold;
                text-align: left;
                min-width: 105px;
            }

            .mcs-dps-dps-label {
                font-size: 14px;
                color: #4CAF50;
                font-weight: bold;
                text-align: right;
                min-width: 60px;
            }

            .mcs-dps-accuracy-span {
                color: #FF9800;
            }

            .mcs-dps-damage-label {
                font-size: 13px;
                color: #4CAF50;
                font-weight: bold;
                text-align: right;
                min-width: 80px;
            }

            .mcs-dps-total-attacks-label {
                font-size: 11px;
                color: #CCC;
                font-weight: bold;
                text-align: right;
                min-width: 45px;
            }

            .mcs-dps-total-hits-label {
                font-size: 11px;
                color: #90EE90;
                font-weight: bold;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-total-crits-label {
                font-size: 11px;
                color: #FFD700;
                font-weight: bold;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-total-misses-label {
                font-size: 11px;
                color: #FF6B6B;
                font-weight: bold;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-ability-container {
                display: flex;
                flex-direction: column;
                gap: 1px;
                padding-left: 15px;
            }

            .mcs-dps-ability-row {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 8px;
                padding: 2px 3px;
                font-size: 10px;
            }

            .mcs-dps-ability-name {
                font-size: 11px;
                color: #AAA;
                text-align: left;
                min-width: 120px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            .mcs-dps-ability-dps {
                font-size: 10px;
                color: #FFA500;
                text-align: right;
                min-width: 60px;
            }

            .mcs-dps-ability-damage {
                font-size: 10px;
                color: #90EE90;
                text-align: right;
                min-width: 80px;
            }

            .mcs-dps-ability-attacks {
                font-size: 10px;
                color: #CCC;
                text-align: right;
                min-width: 45px;
            }

            .mcs-dps-ability-hits {
                font-size: 10px;
                color: #90EE90;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-ability-crits {
                font-size: 10px;
                color: #FFD700;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-ability-misses {
                font-size: 10px;
                color: #FF6B6B;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-monster-header {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 8px;
                padding: 4px 3px;
                margin-top: 8px;
                font-size: 10px;
                background: rgba(255, 255, 255, 0.05);
                border-radius: 3px;
                cursor: pointer;
            }

            .mcs-dps-monster-arrow {
                font-size: 9px;
                color: #FF6B6B;
                min-width: 12px;
            }

            .mcs-dps-monster-name {
                font-size: 11px;
                color: #FF6B6B;
                font-weight: bold;
                text-align: left;
                min-width: 108px;
            }

            .mcs-dps-monster-dps {
                font-size: 10px;
                color: #FFA500;
                text-align: right;
                min-width: 60px;
            }

            .mcs-dps-monster-damage {
                font-size: 10px;
                color: #90EE90;
                text-align: right;
                min-width: 80px;
            }

            .mcs-dps-monster-attacks {
                font-size: 10px;
                color: #CCC;
                text-align: right;
                min-width: 45px;
            }

            .mcs-dps-monster-hits {
                font-size: 10px;
                color: #90EE90;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-monster-crits {
                font-size: 10px;
                color: #FFD700;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-monster-misses {
                font-size: 10px;
                color: #FF6B6B;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-monster-ability-container {
                display: flex;
                flex-direction: column;
                gap: 1px;
            }

            .mcs-dps-monster-ability-row {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 8px;
                padding: 2px 3px 2px 25px;
                font-size: 10px;
            }

            .mcs-dps-monster-ability-name {
                font-size: 10px;
                color: #999;
                text-align: left;
                min-width: 120px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            .mcs-dps-monster-ability-dps {
                font-size: 9px;
                color: #FFA500;
                text-align: right;
                min-width: 60px;
            }

            .mcs-dps-monster-ability-damage {
                font-size: 9px;
                color: #90EE90;
                text-align: right;
                min-width: 80px;
            }

            .mcs-dps-monster-ability-attacks {
                font-size: 9px;
                color: #CCC;
                text-align: right;
                min-width: 45px;
            }

            .mcs-dps-monster-ability-hits {
                font-size: 9px;
                color: #90EE90;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-monster-ability-crits {
                font-size: 9px;
                color: #FFD700;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-monster-ability-misses {
                font-size: 9px;
                color: #FF6B6B;
                text-align: right;
                min-width: 50px;
            }

            .mcs-dps-truedps-section {
                margin-top: 12px;
                padding: 10px;
                background: rgba(255, 215, 0, 0.05);
                border-radius: 4px;
                border: 2px solid #FFD700;
            }

            .mcs-dps-truedps-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 8px;
            }

            .mcs-dps-truedps-title {
                font-weight: bold;
                color: #FFD700;
                font-size: 13px;
            }

            .mcs-dps-truedps-container {
                display: flex;
                gap: 15px;
                align-items: center;
            }

            .mcs-dps-truedps-value-container {
                display: flex;
                flex-direction: column;
                align-items: flex-end;
            }

            .mcs-dps-truedps-value {
                color: #FFD700;
                font-weight: bold;
                font-size: 18px;
            }

            .mcs-dps-truedps-label {
                color: #999;
                font-size: 9px;
                font-style: italic;
            }

            .mcs-dps-loss-value {
                color: #FF6B6B;
                font-weight: bold;
                font-size: 18px;
            }

            .mcs-dps-truedps-subtitle {
                color: #999;
                font-size: 9px;
                margin-bottom: 8px;
            }

            .mcs-dps-truedps-stats {
                display: flex;
                justify-content: space-between;
                margin-bottom: 8px;
                font-size: 10px;
                gap: 10px;
            }

            .mcs-dps-stat-label {
                color: #aaa;
            }

            .mcs-dps-stat-time {
                color: #4CAF50;
                font-weight: bold;
            }

            .mcs-dps-stat-damage {
                color: #87CEEB;
                font-weight: bold;
            }

            .mcs-dps-stat-kills {
                color: #90EE90;
                font-weight: bold;
            }

            .mcs-dps-enemy-grid {
                display: flex;
                flex-wrap: wrap;
                gap: 6px;
            }

            .mcs-dps-enemy-box {
                flex: 1 1 calc(50% - 3px);
                min-width: 200px;
                padding: 6px 8px;
                background: rgba(255, 107, 157, 0.1);
                border-radius: 3px;
                border-left: 3px solid #FF6B9D;
                font-size: 10px;
            }

            .mcs-dps-enemy-name {
                color: #FF6B9D;
                font-weight: bold;
                margin-bottom: 2px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }

            .mcs-dps-enemy-stats {
                color: #ccc;
                font-size: 9px;
            }

            .mcs-dps-enemy-damage {
                color: #90EE90;
                font-weight: bold;
            }

            .mcs-dps-title-highlight {
                color: white;
            }

            .mcs-dps-title-subtitle {
                color: #888;
                font-size: 10px;
            }

            .mcs-ew-pane {
                position: fixed;
                top: 0;
                left: 0;
                width: 450px;
                border: none;
                border-radius: 8px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                z-index: 99998;
                font-family: sans-serif;
                display: flex;
                flex-direction: column;
                max-height: 85vh;
            }

            .mcs-ew-header {
                background: #333333;
                color: white;
                padding: 8px 12px;
                font-weight: bold;
                cursor: move;
                border-radius: 6px 6px 0 0;
                display: flex;
                justify-content: space-between;
                align-items: center;
                user-select: none;
            }

            .mcs-ew-header-left {
                display: flex;
                align-items: center;
                gap: 8px;
                flex: 1;
            }

            .mcs-ew-header-title {
                font-size: 14px;
            }

            .mcs-ew-header-status {
                font-size: 11px;
                color: #aaa;
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-ew-header-buttons {
                display: flex;
                gap: 5px;
            }

            .mcs-ew-btn {
                padding: 2px 8px;
                border-radius: 3px;
                cursor: pointer;
                font-size: 11px;
                border: 1px solid #6495ED;
            }

            .mcs-ew-btn-minimize {
                background: rgba(255,255,255,0.2);
                border: none;
                color: white;
                padding: 2px 8px;
                border-radius: 3px;
                cursor: pointer;
                font-size: 14px;
            }

            .mcs-ew-content {
                padding: 10px;
                overflow-y: auto;
                overflow-x: hidden;
                max-height: 80vh;
                color: #e0e0e0;
                min-height: 200px;
            }

            .mcs-ew-status-msg {
                text-align: center;
                color: #888;
                padding: 10px;
                font-size: 12px;
            }

            .mcs-ew-error-msg {
                text-align: center;
                color: #ff6666;
                padding: 20px;
                font-size: 12px;
            }

            .mcs-ew-profit-section {
                padding: 8px 12px;
                background: rgba(0,0,0,0.2);
                font-size: 11px;
                display: none;
                grid-template-columns: auto auto auto;
                gap: 4px 8px;
                align-items: center;
            }

            .mcs-ew-profit-label {
                text-align: left;
                font-weight: bold;
            }
            .mcs-ew-profit-type {
                text-align: left;
                color: #aaa;
                font-size: 10px;
            }
            .mcs-ew-profit-value {
                text-align: left;
                font-weight: bold;
            }
            .mcs-ew-profit-empty {
                text-align: left;
            }

            .mcs-ew-status-col {
                display: flex;
                flex-direction: column;
                gap: 2px;
            }

            .mcs-ew-status-row {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-ew-header-bar-track {
                width: 255px;
                height: 2px;
                background: rgba(255,255,255,0.2);
                border-radius: 1px;
                overflow: hidden;
                position: relative;
            }

            .mcs-ew-tick-mark {
                position: absolute;
                top: 0;
                width: 1px;
                height: 100%;
                background: rgba(255,255,255,0.5);
            }

            .mcs-ew-nc-label {
                color: #f44336;
                font-weight: bold;
            }

            .mcs-ew-nc-time {
                color: #999;
                font-weight: normal;
            }

            .mcs-ew-gold-needed {
                color: white;
                font-weight: normal;
            }

            .mcs-ew-no-combat {
                color: #f44336;
            }

            .mcs-ew-comparison {
                margin-top: 4px;
                padding: 6px;
                background: rgba(0,0,0,0.3);
                border-radius: 3px;
            }

            .mcs-ew-compare-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 4px;
            }

            .mcs-ew-compare-label {
                font-size: 10px;
                color: #aaa;
            }

            .mcs-ew-watch-btn {
                background: rgba(255,215,0,0.3);
                border: 1px solid #FFD700;
                color: #FFD700;
                padding: 1px 6px;
                border-radius: 2px;
                cursor: pointer;
                font-size: 10px;
            }

            .mcs-ew-item-select {
                width: 100%;
                padding: 3px;
                background: rgba(50,50,50,0.9);
                color: #fff;
                border: 1px solid #666;
                border-radius: 2px;
                font-size: 11px;
                margin-bottom: 4px;
            }

            .mcs-ew-enh-container {
                margin-top: 4px;
            }
            .mcs-ew-price-display {
                margin-top: 4px;
                font-size: 11px;
                color: #FFD700;
                font-weight: bold;
            }
            .mcs-ew-eta-display {
                padding-top: 4px;
            }

            .mcs-ew-enh-row {
                display: flex;
                flex-wrap: wrap;
                gap: 3px;
            }
            .mcs-ew-enh-col {
                display: flex;
                flex-direction: column;
                gap: 3px;
            }

            .mcs-ew-enh-btn {
                color: #fff;
                padding: 2px 6px;
                border-radius: 2px;
                cursor: pointer;
                font-size: 10px;
                opacity: 1;
            }

            .mcs-ew-eta-text {
                font-size: 10px;
                text-align: right;
            }
            .mcs-ew-eta-nc {
                font-size: 10px;
                font-weight: bold;
                color: #f44336;
                text-align: right;
            }
            .mcs-ew-eta-waiting {
                font-size: 10px;
                font-style: italic;
                color: #999;
                text-align: right;
            }
            .mcs-ew-eta-affordable {
                font-size: 10px;
                font-weight: bold;
                color: #66ff66;
                text-align: right;
            }
            .mcs-ew-eta-timer {
                font-size: 10px;
                color: #6495ED;
                text-align: right;
                font-weight: bold;
            }
            .mcs-ew-eta-countdown {
                font-size: 10px;
                color: #f5a623;
            }
            .mcs-ew-eta-affordable-inline {
                font-size: 10px;
                color: #66ff66;
            }
            .mcs-ew-eta-nodata {
                font-size: 10px;
                font-style: italic;
                color: #999;
            }

            .mcs-ew-price-lastseen {
                color: white;
                font-size: 9px;
                font-style: italic;
            }
            .mcs-ew-price-nodata {
                color: #FFD700;
                font-size: 9px;
                font-style: italic;
            }

            .mcs-ew-eye-btn {
                padding: 2px 6px;
                border-radius: 2px;
                cursor: pointer;
                font-size: 12px;
                line-height: 1;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            .mcs-ew-progress-row {
                display: flex;
                align-items: center;
                gap: 6px;
                margin-top: 4px;
            }

            .mcs-ew-progress-track {
                flex: 1;
                background: rgba(0,0,0,0.3);
                border-radius: 2px;
                height: 4px;
                overflow: hidden;
            }

            .mcs-ew-progress-text {
                font-size: 10px;
                min-width: 80px;
                text-align: right;
            }

            .mcs-ew-content-wrap {
                font-size: 11px;
                line-height: 1.3;
            }

            .mcs-ew-gold-bar {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 6px 8px;
                margin-bottom: 8px;
                background: rgba(64, 64, 64, 0.1);
                border: 1px solid rgba(255, 215, 0, 0.3);
                border-radius: 3px;
            }

            .mcs-ew-gold-coin {
                display: flex;
                align-items: center;
                gap: 4px;
                color: #cccccc;
                font-weight: bold;
                font-size: 11px;
            }

            .mcs-ew-coin-icon {
                width: 11px;
                height: 11px;
                display: inline-flex;
            }

            .mcs-ew-gold-stat {
                display: flex;
                align-items: center;
                gap: 4px;
                font-size: 11px;
            }

            .mcs-ew-market-bar {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 4px 8px;
                margin-bottom: 8px;
                background: rgba(64, 64, 64, 0.05);
                border: 1px solid rgba(100, 149, 237, 0.2);
                border-radius: 3px;
                font-size: 10px;
            }

            .mcs-ew-market-label {
                color: #999;
            }

            .mcs-ew-refresh-btn {
                background: rgba(100, 149, 237, 0.3);
                border: 1px solid #6495ED;
                color: #6495ED;
                padding: 2px 6px;
                border-radius: 2px;
                cursor: pointer;
                font-size: 10px;
            }

            .mcs-ew-market-value-bar {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 4px 8px;
                margin-bottom: 8px;
                background: rgba(64, 64, 64, 0.05);
                border: 1px solid rgba(100, 100, 100, 0.2);
                border-radius: 3px;
                font-size: 10px;
            }

            .mcs-ew-toggle-btn {
                padding: 2px 6px;
                border-radius: 2px;
                border: 1px solid;
                cursor: pointer;
                font-size: 10px;
            }

            .mcs-ew-equip-row {
                display: flex;
                justify-content: space-between;
                padding: 3px 6px;
                background: rgba(255,255,255,0.03);
                border-radius: 2px;
            }

            .mcs-ew-slot-name {
                color: #999;
                font-size: 10px;
                min-width: 70px;
            }

            .mcs-ew-slot-item {
                color: #ddd;
                flex: 1;
                padding: 0 6px;
            }

            .mcs-ew-slot-bid {
                color: #FFD700;
                font-weight: bold;
                white-space: nowrap;
            }

            .mcs-ew-slot {
                margin-bottom: 6px;
            }

            .mcs-ew-locked-nodata {
                margin-top: 4px;
                padding: 6px 6px 2px 6px;
                background: rgba(100, 100, 100, 0.1);
                border-radius: 3px;
                border-left: 2px solid #999;
            }

            .mcs-ew-flex-between {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 4px;
            }

            .mcs-ew-flex-col {
                display: flex;
                flex-direction: column;
            }

            .mcs-ew-flex-row {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-ew-locked-name-nodata {
                font-size: 11px;
                color: #ddd;
                font-weight: bold;
            }

            .mcs-ew-waiting-market {
                font-size: 9px;
                color: #FFD700;
                font-style: italic;
            }

            .mcs-ew-never-seen {
                font-size: 10px;
                color: #999;
            }

            .mcs-ew-watching-label {
                font-size: 10px;
                color: #999;
                font-weight: bold;
            }

            .mcs-ew-unwatch-btn {
                background: rgba(255,100,100,0.3);
                border: 1px solid #ff6666;
                color: #ff6666;
                padding: 1px 6px;
                border-radius: 2px;
                cursor: pointer;
                font-size: 10px;
            }

            .mcs-ew-locked-name {
                font-size: 11px;
                color: #ddd;
                margin-bottom: 6px;
            }

            .mcs-ew-waiting-centered {
                font-size: 10px;
                color: #FFD700;
                font-style: italic;
                text-align: center;
                padding: 8px 0;
            }

            .mcs-ew-locked-gold-name {
                font-size: 11px;
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-ew-last-price-note {
                font-size: 8px;
                color: #999;
                font-style: italic;
            }

            .mcs-ew-locked-eta {
                font-size: 10px;
                color: #f5a623;
            }

            .mcs-ew-watching-title {
                font-size: 10px;
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-ew-locked-gold-name-mb {
                font-size: 11px;
                color: #FFD700;
                font-weight: bold;
                margin-bottom: 2px;
            }

            .mcs-ew-price-change {
                font-size: 9px;
                color: white;
                margin-bottom: 4px;
                font-style: italic;
            }

            .mcs-ew-price-row {
                display: flex;
                justify-content: space-between;
                font-size: 10px;
                margin-bottom: 2px;
            }
            .mcs-ew-price-row-mb6 {
                display: flex;
                justify-content: space-between;
                font-size: 10px;
                margin-bottom: 6px;
            }

            .mcs-ew-price-label {
                color: #aaa;
            }

            .mcs-ew-ask-price-group {
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-ew-price-gold {
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-ew-last-known-note {
                color: #999;
                font-size: 8px;
                font-style: italic;
            }

            .mcs-ew-default-panel {
                margin-top: 4px;
                padding: 6px;
                background: rgba(0,0,0,0.3);
                border-radius: 3px;
                cursor: pointer;
            }

            .mcs-ew-default-inner {
                font-size: 10px;
                color: #aaa;
                text-align: center;
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 6px;
            }

            .mcs-ew-total-row {
                margin-top: 8px;
                padding-top: 6px;
                display: flex;
                justify-content: space-between;
                font-weight: bold;
                font-size: 12px;
            }

            .mcs-ew-everything {
                margin-top: 8px;
                padding: 6px 6px 2px 6px;
                border-radius: 3px;
                cursor: default;
            }

            .mcs-ew-everything-title {
                font-size: 11px;
                color: #FFA500;
                font-weight: bold;
            }

            .mcs-ew-everything-timer {
                font-size: 10px;
                color: #f5a623;
            }

            .mcs-ew-everything-affordable {
                font-size: 10px;
                font-weight: bold;
                color: #66ff66;
            }

            .mcs-ew-everything-progress {
                display: flex;
                align-items: center;
                gap: 6px;
                margin-top: 4px;
            }

            .mcs-ew-everything-track {
                flex: 1;
                background: rgba(0,0,0,0.3);
                border-radius: 2px;
                height: 8px;
                overflow: hidden;
                position: relative;
            }

            .mcs-ew-no-equip {
                text-align: center;
                color: #888;
                padding: 20px;
                font-size: 12px;
            }
            .mcs-ew-no-equip-mb {
                margin-bottom: 15px;
            }

            .mcs-ew-simple-empty {
                text-align: center;
                color: #888;
                padding: 20px 10px;
                font-size: 12px;
            }

            .mcs-ew-drop-zone {
                height: 20px;
                background: rgba(200, 200, 200, 0.3);
                border: 1px dashed #999;
                margin: 2px 0;
                border-radius: 2px;
                transition: all 0.2s ease;
                position: relative;
                z-index: 100;
            }

            .mcs-helper-force-btn {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                border: none;
                color: white;
                padding: 10px 20px;
                border-radius: 6px;
                cursor: pointer;
                font-size: 13px;
                font-weight: bold;
                margin-top: 10px;
                width: 90%;
                transition: all 0.3s ease;
                box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
            }
            .mcs-helper-force-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.5);
            }

            .mcs-helper-loading {
                text-align: center;
                color: #667eea;
                padding: 20px;
                font-size: 12px;
            }

            .mcs-helper-spinner {
                animation: spin 1s linear infinite;
                display: inline-block;
                font-size: 24px;
            }
            @keyframes spin {
                from { transform: rotate(0deg); }
                to { transform: rotate(360deg); }
            }

            .mcs-helper-failure {
                text-align: center;
                color: #ff6666;
                padding: 20px;
                font-size: 12px;
            }

            .mcs-helper-failure-icon {
                font-size: 24px;
                margin-bottom: 10px;
            }

            .floating-text-dps-container {
                display: flex;
                justify-content: space-around;
                margin-top: 5px;
                font-size: 12px;
                font-weight: bold;
                min-height: 18px;
            }

            .floating-text-player-dps-current {
                text-align: center;
                font-size: 11px;
                font-weight: bold;
                white-space: nowrap;
            }

            .floating-text-player-dps-total {
                margin-bottom: 5px;
                text-align: center;
                font-size: 11px;
                font-weight: bold;
                white-space: nowrap;
            }

            .mcs-fcb-dps-column {
                flex: 1;
                text-align: center;
                padding: 2px;
            }

            .fcb-floating-text {
                position: fixed;
                transform: translate(-50%, -50%);
                pointer-events: none;
                z-index: 10000;
                font-family: sans-serif;
                font-weight: bold;
                font-size: 16.8px;
                text-shadow:
                    -2px -2px 0 #000,
                    2px -2px 0 #000,
                    -2px 2px 0 #000,
                    2px 2px 0 #000,
                    0 0 12px rgba(0,0,0,0.9);
                white-space: nowrap;
                opacity: 1;
            }

            .mcs-fcb-text-shadow {
                text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
            }

            .mcs-floot-overlay-container {
                position: relative !important;
            }

            .mcs-floot-center-overlay {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                font-size: 10pt;
                font-weight: bold;
                text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
                pointer-events: none;
                z-index: 11;
                line-height: 1;
            }

            .mcs-ntally-indicator {
                position: absolute;
                top: 2px;
                left: 2px;
                width: 8px;
                height: 8px;
                border-radius: 50%;
                background-color: #4CAF50;
                box-shadow: 0 0 3px rgba(76, 175, 80, 0.8);
                pointer-events: none;
                z-index: 12;
            }

            .mcs-price-overlay {
                position: absolute;
                top: 2px;
                right: 2px;
                font-size: 8pt;
                font-weight: bold;
                text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
                pointer-events: none;
                z-index: 10;
                line-height: 1;
            }

            .mcs-category-total {
                margin-left: 8px;
                font-size: 10pt;
                font-weight: bold;
            }

            .mcs-gw-pane {
                width: auto;
            }

            .mcs-gw-left-section {
                display: flex;
                align-items: center;
                gap: 10px;
            }

            .mcs-gw-total-exp {
                font-size: 12px;
                color: #90EE90;
                font-weight: normal;
            }

            .mcs-gw-content {
                align-items: stretch;
            }

            .mcs-gw-reset-btn {
                padding: 4px 8px;
                font-size: 11px;
            }

            .mcs-gw-section {
                display: flex;
                flex-direction: column;
                gap: 4px;
                padding: 6px;
                background: #333;
                border-radius: 4px;
            }

            .mcs-gw-section-mt {
                margin-top: 8px;
            }

            .mcs-gw-section-mb {
                margin-bottom: 8px;
            }

            .mcs-gw-session-row {
                display: flex;
                flex-wrap: wrap;
                align-items: center;
                gap: 4px 8px;
                font-size: 11px;
            }

            .mcs-gw-session-label {
                color: #999;
            }

            .mcs-gw-session-val {
                color: #ddd;
                font-weight: bold;
                margin-right: 6px;
            }

            .mcs-gw-session-rate {
                color: #90EE90;
            }

            .mcs-gw-top-row {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 10px;
            }

            .mcs-gw-level-container {
                display: flex;
                flex-direction: column;
                align-items: flex-end;
                min-width: 35px;
            }

            .mcs-gw-combat-level-value {
                font-size: 16px;
                color: #ffa500;
                font-weight: bold;
                text-align: right;
            }

            .mcs-gw-name-container {
                display: flex;
                flex-direction: column;
                gap: 2px;
                flex: 1;
            }

            .mcs-gw-name-label {
                font-size: 12px;
                color: #fff;
                font-weight: bold;
            }

            .mcs-gw-equation {
                font-size: 18px;
                color: #aaa;
                font-family: monospace;
                line-height: 1.2;
            }

            .mcs-gw-exp-label {
                font-size: 11px;
                color: #4CAF50;
                font-weight: bold;
                text-align: right;
                flex: 1;
            }

            .mcs-gw-time-label {
                font-size: 11px;
                color: #87CEEB;
                font-weight: bold;
                text-align: right;
                min-width: 80px;
            }

            .mcs-gw-progress-row {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 8px;
            }

            .mcs-gw-progress-container {
                flex: 1;
                height: 10px;
                background: #1a1a1a;
                border-radius: 5px;
                overflow: hidden;
                position: relative;
            }

            .mcs-gw-combat-progress-bar {
                height: 100%;
                background: #ffa500;
                width: 0%;
                transition: width 0.3s ease;
                position: relative;
            }

            .mcs-gw-combat-projected {
                position: absolute;
                left: 0;
                top: 0;
                height: 100%;
                background: #259c85;
                width: 0%;
                transition: width 0.3s ease, background 0.3s ease, left 0.3s ease;
            }

            .mcs-gw-tickmark {
                position: absolute;
                top: 0;
                height: 100%;
                width: 1px;
                background: #888;
                pointer-events: none;
                z-index: 100;
            }

            .mcs-gw-combat-progress-text {
                font-size: 18px;
                color: #ffa500;
                font-weight: bold;
                min-width: 60px;
                text-align: right;
            }

            .mcs-gw-stat-item {
                display: none;
                flex-direction: column;
                gap: 4px;
                padding: 6px;
                background: #333;
                border-radius: 4px;
            }

            .mcs-gw-stat-level {
                font-size: 16px;
                font-weight: bold;
                text-align: right;
                min-width: 35px;
            }

            .mcs-gw-stat-name {
                font-size: 12px;
                color: #fff;
                font-weight: bold;
                min-width: 80px;
            }

            .mcs-gw-stat-progress-bar {
                height: 100%;
                width: 0%;
                transition: width 0.3s ease;
            }

            .mcs-gw-stat-progress-text {
                font-size: 18px;
                font-weight: bold;
                min-width: 60px;
                text-align: right;
            }

            .mcs-gw-rate-label {
                font-size: 9px;
                color: #90EE90;
                text-align: left;
            }

            .mcs-gw-section-title {
                font-size: 12px;
                color: #90EE90;
                font-weight: bold;
                text-align: left;
                margin-bottom: 4px;
                cursor: pointer;
                user-select: none;
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-gw-ttl-title {
                margin-bottom: 4px;
            }

            .mcs-gw-charms-title {
                margin-bottom: 2px;
            }

            .mcs-gw-section-arrow {
                font-size: 10px;
                transition: transform 0.2s;
            }

            .mcs-gw-ttl-table {
                display: flex;
                flex-direction: column;
                gap: 4px;
            }

            .mcs-gw-ttl-header {
                display: grid;
                grid-template-columns: 1fr 0.8fr 1fr 0.8fr 1fr;
                gap: 4px;
                padding: 4px;
                font-size: 10px;
                font-weight: bold;
                color: #ccc;
                border-bottom: 1px solid #555;
                align-items: center;
            }

            .mcs-gw-ttl-time-header {
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding-right: 4px;
            }

            .mcs-gw-ttl-time-text {
                flex: 1;
                text-align: center;
            }

            .mcs-gw-bulwark-container {
                display: flex;
                align-items: center;
                gap: 2px;
                font-size: 9px;
                white-space: nowrap;
            }

            .mcs-gw-bulwark-checkbox {
                cursor: pointer;
                margin: 0;
                width: 12px;
                height: 12px;
            }

            .mcs-gw-bulwark-label {
                cursor: pointer;
                color: #95E1D3;
            }

            .mcs-gw-ttl-row {
                display: grid;
                grid-template-columns: 1fr 0.8fr 1fr 0.8fr 1fr;
                gap: 4px;
                padding: 4px;
                font-size: 10px;
                align-items: center;
            }

            .mcs-gw-ttl-name {
                font-weight: bold;
                text-align: left;
                font-size: 12px;
            }

            .mcs-gw-ttl-current {
                text-align: center;
                color: #fff;
                font-size: 12px;
            }

            .mcs-gw-ttl-exphr {
                text-align: center;
                color: #90EE90;
                font-size: 11px;
            }

            .mcs-gw-ttl-target-cell {
                text-align: center;
            }

            .mcs-gw-ttl-input {
                width: 50px;
                background: #2a2a2a;
                border: 1px solid #555;
                border-radius: 3px;
                color: #fff;
                padding: 2px 4px;
                font-size: 12px;
                text-align: center;
            }

            .mcs-gw-ttl-time {
                text-align: center;
                color: #87CEEB;
                font-weight: bold;
                font-size: 12px;
            }

            .mcs-gw-charms-grid {
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 4px;
            }

            .mcs-gw-charm-item {
                display: flex;
                flex-direction: row;
                align-items: center;
                gap: 4px;
                padding: 3px 6px;
                background: #2a2a2a;
                border-radius: 3px;
            }

            .mcs-gw-charm-level {
                font-size: 12px;
                font-weight: bold;
                min-width: 30px;
                text-align: right;
            }

            .mcs-gw-charm-name {
                font-size: 10px;
                color: #ccc;
            }

            .mcs-gw-charm-percent {
                font-size: 10px;
                color: #90EE90;
                margin-left: auto;
            }

            .gwhiz-combat-progress-bar-projected {
                position: absolute;
                top: 0;
                height: 100%;
                transition: width 0.3s ease, left 0.3s ease;
            }

            .mcs-hw-pane {
                min-width: 300px;
            }

            .mcs-hw-header-left {
                display: flex;
                align-items: center;
                gap: 10px;
                flex: 1;
                min-width: 0;
            }

            .mcs-hw-title {
                white-space: nowrap;
            }

            .mcs-hw-combat-status {
                font-size: 11px;
                color: #ffa500;
                display: none;
            }

            .mcs-hw-header-calc {
                font-size: 11px;
                white-space: nowrap;
            }

            .mcs-hw-color-green { color: #4CAF50; }
            .mcs-hw-color-white { color: white; }
            .mcs-hw-color-red { color: #f44336; }
            .mcs-hw-color-blue { color: #2196F3; }
            .mcs-hw-color-tax { color: #dc3545; }
            .mcs-hw-color-gold { color: #FFD700; }

            .mcs-hw-header-tax-section {
                display: none;
            }

            .mcs-hw-header-tax-icon {
                display: inline-block;
                width: 16px;
                height: 16px;
                vertical-align: middle;
            }

            .mcs-hw-toggle-btn {
                background: rgba(255, 255, 255, 0.1);
                color: white;
                border: 1px solid rgba(255, 255, 255, 0.3);
                border-radius: 4px;
                padding: 2px 8px;
                cursor: pointer;
                font-size: 11px;
                white-space: nowrap;
            }

            .mcs-hw-content {
                padding: 12px;
                background: #2b2b2b;
                border-radius: 0 0 6px 6px;
            }

            .mcs-hw-tax-section {
                margin-bottom: 12px;
                padding: 10px;
                background: rgba(220, 53, 69, 0.1);
                border: 1px solid rgba(220, 53, 69, 0.3);
                border-radius: 6px;
                display: flex;
                align-items: center;
                gap: 12px;
            }

            .mcs-hw-tax-icon {
                width: 80px;
                height: 80px;
                flex-shrink: 0;
            }

            .mcs-hw-tax-details {
                flex: 1;
            }

            .mcs-hw-tax-header-text {
                font-weight: bold;
                color: #dc3545;
                margin-bottom: 6px;
            }

            .mcs-hw-tax-toggle {
                padding: 6px 12px;
                align-self: center;
            }

            .mcs-hw-profit-box {
                margin-bottom: 12px;
                padding: 10px;
                border-radius: 6px;
            }

            .mcs-hw-lazy-box {
                background: rgba(76, 175, 80, 0.1);
                border: 1px solid rgba(76, 175, 80, 0.3);
            }

            .mcs-hw-mid-box {
                background: rgba(33, 150, 243, 0.1);
                border: 1px solid rgba(33, 150, 243, 0.3);
            }

            .mcs-hw-diff-box {
                padding: 10px;
                background: rgba(255, 215, 0, 0.1);
                border: 1px solid rgba(255, 215, 0, 0.3);
                border-radius: 6px;
                margin-bottom: 0;
            }

            .mcs-hw-profit-title {
                font-weight: bold;
                margin-bottom: 6px;
            }

            .mcs-hw-profit-value {
                font-size: 18px;
            }

            .mcs-hw-info-text {
                font-size: 11px;
                color: rgba(255, 255, 255, 0.6);
                margin-top: 4px;
            }

            .mcs-hw-equation {
                font-size: 10px;
                font-family: monospace;
                margin-top: 6px;
            }

            .mcs-hw-lazy-equation {
                color: rgba(76, 175, 80, 0.7);
            }

            .mcs-hw-mid-equation {
                color: rgba(33, 150, 243, 0.7);
            }

            .mcs-hw-diff-message {
                font-size: 13px;
                color: #FFD700;
                margin-top: 6px;
                font-weight: bold;
            }

            .mcs-hw-bags-needed {
                color: #ffa500;
            }

            .mcs-jh-pane {
                width: auto;
                font-family: sans-serif;
            }

            .mcs-jh-header {
                gap: 15px;
            }

            .mcs-jh-title-section {
                display: flex;
                align-items: center;
                gap: 8px;
                flex-wrap: wrap;
            }

            .mcs-jh-affordable-status {
                font-size: 14px;
                font-weight: bold;
                display: none;
            }

            .mcs-jh-cheapest-status {
                font-size: 11px;
                color: #999;
                display: none;
            }

            .mcs-jh-cheapest-room-name {
                color: #FFD700;
            }

            .mcs-jh-status-pane {
                padding: 20px;
                color: #e0e0e0;
                font-size: 12px;
                display: flex;
                flex-direction: column;
                gap: 8px;
                min-width: 300px;
            }

            .mcs-jh-status-line {
                color: #FFA500;
                font-family: monospace;
            }

            .mcs-jh-content {
                padding: 10px;
                color: #e0e0e0;
                font-size: 11px;
                display: none;
                flex-direction: column;
                gap: 8px;
                align-items: stretch;
            }

            .mcs-jh-no-data {
                padding: 10px;
                text-align: center;
                color: #999;
            }

            .mcs-jh-main-grid {
                display: grid;
                grid-template-columns: repeat(3, 60px) 1fr;
                gap: 8px;
            }

            .mcs-jh-room-grid {
                display: grid;
                grid-template-columns: repeat(3, 60px);
                gap: 8px;
                grid-column: 1 / 4;
                align-content: start;
            }

            .mcs-jh-room {
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                gap: 2px;
                padding: 4px;
                background: #333;
                border-radius: 4px;
                cursor: pointer;
                border: 1px solid transparent;
                transition: all 0.2s ease;
                width: 60px;
                height: 60px;
                min-width: 60px;
                min-height: 60px;
                max-width: 60px;
                max-height: 60px;
                position: relative;
            }

            .mcs-jh-room-level {
                color: #90EE90;
                font-size: 10px;
                font-weight: bold;
                text-align: center;
            }

            .mcs-jh-room-checkbox {
                position: absolute;
                bottom: 2px;
                right: 2px;
                width: 12px;
                height: 12px;
                cursor: pointer;
                margin: 0;
                z-index: 10;
            }

            .mcs-jh-detail-panel {
                background: #2a2a2a;
                border-radius: 4px;
                padding: 12px;
                border: 1px solid #444;
                grid-column: 4;
                display: flex;
                flex-direction: column;
                gap: 8px;
                overflow-y: auto;
                min-width: 220px;
            }

            .mcs-jh-detail-title {
                font-size: 16px;
                font-weight: bold;
                color: #4CAF50;
                text-align: left;
                margin-bottom: 4px;
            }

            .mcs-jh-recipe-title {
                font-size: 13px;
                font-weight: bold;
                color: #FFA500;
                text-align: left;
                margin-bottom: 4px;
            }

            .mcs-jh-section-label {
                font-weight: bold;
                font-size: 12px;
                margin-bottom: 0px;
                text-align: left;
                line-height: 1;
            }

            .mcs-jh-label-materials-cost {
                color: #FFA500;
            }

            .mcs-jh-label-gold {
                color: #FFD700;
            }

            .mcs-jh-cost-values {
                display: flex;
                justify-content: flex-start;
                gap: 16px;
                font-size: 11px;
                margin-bottom: 4px;
                line-height: 1;
            }

            .mcs-jh-ask-value {
                color: #ff6b6b;
                font-weight: bold;
            }

            .mcs-jh-bid-value {
                color: #4CAF50;
                font-weight: bold;
            }

            .mcs-jh-gold-value {
                font-weight: bold;
                font-size: 11px;
                margin-bottom: 2px;
                text-align: left;
                line-height: 1;
            }

            .mcs-jh-materials-title {
                font-size: 12px;
                font-weight: bold;
                color: #90EE90;
                margin-top: 0px;
                margin-bottom: 4px;
            }

            .mcs-jh-materials-list {
                display: flex;
                flex-direction: column;
                gap: 4px;
            }

            .mcs-jh-material-row {
                display: flex;
                justify-content: space-between;
                padding: 4px 8px;
                background: #333;
                border-radius: 3px;
                font-size: 11px;
                cursor: pointer;
            }

            .mcs-jh-material-row:hover {
                background: #444;
            }

            .mcs-jh-material-name {
                color: #e0e0e0;
            }

            .mcs-jh-material-amount {
                font-weight: bold;
            }

            .mcs-jh-max-level {
                font-size: 14px;
                color: #FFD700;
                text-align: center;
                padding: 20px;
                font-weight: bold;
            }

            .mcs-jh-no-recipe {
                font-size: 12px;
                color: #888;
                text-align: center;
                padding: 20px;
            }

            .mcs-nt-pane {
                min-width: 320px;
                min-height: 300px;
            }

            .mcs-nt-title-section {
                display: flex;
                align-items: center;
                gap: 8px;
            }

            .mcs-nt-column-header {
                display: flex;
                align-items: center;
                padding: 8px 15px;
                background: rgba(0,0,0,0.3);
                border-bottom: 1px solid rgba(255,255,255,0.2);
                gap: 8px;
            }

            .mcs-nt-col-icon-spacer {
                width: 40px;
            }

            .mcs-nt-col-sort-name {
                flex: 1;
                cursor: pointer;
                user-select: none;
                color: #e0e0e0;
                font-weight: bold;
                font-size: 11px;
            }

            .mcs-nt-col-sort-value {
                min-width: 160px;
                text-align: right;
                cursor: pointer;
                user-select: none;
                color: #999;
                font-weight: bold;
                font-size: 11px;
                padding-right: 4px;
            }

            .mcs-nt-col-x-spacer {
                min-width: 20px;
            }

            .mcs-nt-content {
                padding: 10px 15px;
                color: #e0e0e0;
                font-size: 12px;
                line-height: 1.6;
                overflow-y: auto;
                overflow-x: hidden;
                height: calc(100% - 75px);
            }

            .mcs-nt-empty-state {
                color: #999;
                text-align: center;
                padding: 20px;
            }

            .mcs-nt-section {
                margin-bottom: 10px;
                border: 1px solid #444;
                border-radius: 4px;
                background: #333;
            }

            .mcs-nt-section-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 8px 10px;
                cursor: pointer;
                user-select: none;
            }

            .mcs-nt-section-title-gold {
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-nt-section-title-purple {
                color: #9C27B0;
                font-weight: bold;
            }

            .mcs-nt-section-summary {
                font-size: 11px;
            }

            .mcs-nt-sell-value {
                color: #4CAF50;
            }

            .mcs-nt-separator {
                color: #888;
                margin: 0 4px;
            }

            .mcs-nt-buy-value {
                color: #FF6B6B;
            }

            .mcs-nt-total-value {
                color: #FFD700;
            }

            .mcs-nt-expanded-content {
                border-top: 1px solid #444;
                max-height: 250px;
                overflow-y: auto;
            }

            .mcs-nt-sell-orders-header {
                padding: 4px 10px;
                background: rgba(76, 175, 80, 0.1);
                color: #4CAF50;
                font-size: 10px;
                font-weight: bold;
            }

            .mcs-nt-buy-orders-header {
                padding: 4px 10px;
                background: rgba(255, 107, 107, 0.1);
                color: #FF6B6B;
                font-size: 10px;
                font-weight: bold;
            }

            .mcs-nt-order-row {
                display: flex;
                align-items: center;
                padding: 6px 10px;
                border-bottom: 1px solid rgba(255,255,255,0.05);
                gap: 8px;
            }

            .mcs-nt-order-icon {
                width: 32px;
                height: 32px;
                border: 1px solid rgba(255,255,255,0.2);
                border-radius: 4px;
                background: rgba(0,0,0,0.3);
                padding: 2px;
            }

            .mcs-nt-order-details {
                flex: 1;
                min-width: 0;
            }

            .mcs-nt-order-name {
                color: #e0e0e0;
                font-size: 11px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }

            .mcs-nt-order-unit-price {
                font-size: 10px;
                color: #888;
            }

            .mcs-nt-order-totals {
                text-align: right;
                min-width: 130px;
            }

            .mcs-nt-order-listing-total {
                font-size: 11px;
            }

            .mcs-nt-order-market-totals {
                font-size: 10px;
            }

            .mcs-nt-color-green {
                color: #4CAF50;
            }

            .mcs-nt-color-blue {
                color: #6495ED;
            }

            .mcs-nt-color-muted {
                color: #888;
            }

            .mcs-nt-color-gold {
                color: #FFD700;
            }

            .mcs-nt-section-content {
                border-top: 1px solid #444;
                padding: 8px 10px;
            }

            .mcs-nt-toggle-grid {
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 6px;
            }

            .mcs-nt-toggle-item {
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-nt-toggle-switch {
                position: relative;
                display: inline-block;
                width: 28px;
                height: 14px;
                flex-shrink: 0;
            }

            .mcs-nt-toggle-checkbox {
                opacity: 0;
                width: 0;
                height: 0;
            }

            .mcs-nt-toggle-slider {
                position: absolute;
                cursor: pointer;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                transition: 0.3s;
                border-radius: 14px;
            }

            .mcs-nt-toggle-knob {
                position: absolute;
                height: 10px;
                width: 10px;
                bottom: 2px;
                background-color: white;
                transition: 0.3s;
                border-radius: 50%;
            }

            .mcs-nt-toggle-label {
                font-size: 10px;
                cursor: pointer;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }

            .mcs-nt-item-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 6px;
                border-bottom: 1px solid rgba(255,255,255,0.1);
                gap: 8px;
            }

            .mcs-nt-item-icon {
                width: 40px;
                height: 40px;
                border: 1px solid rgba(255,255,255,0.2);
                border-radius: 4px;
                background: rgba(0,0,0,0.3);
                padding: 4px;
            }

            .mcs-nt-item-info {
                flex: 1;
                min-width: 0;
            }

            .mcs-nt-item-name {
                color: #e0e0e0;
                font-weight: bold;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }

            .mcs-nt-item-qty {
                color: #999;
                font-size: 10px;
            }

            .mcs-nt-item-prices {
                display: flex;
                flex-direction: column;
                align-items: flex-end;
                gap: 2px;
                min-width: 160px;
            }

            .mcs-nt-item-unit-price {
                font-size: 10px;
                color: #999;
            }

            .mcs-nt-item-total-price {
                font-weight: bold;
                color: #e0e0e0;
            }

            .mcs-nt-delete-btn {
                background: #d32f2f;
                color: white;
                border: none;
                border-radius: 3px;
                padding: 2px 6px;
                cursor: pointer;
                font-size: 11px;
                min-width: 20px;
            }

            .mcs-nt-market-info {
                background: #424242;
                color: #E0E0E0;
                padding: 6px 8px;
                border-radius: 4px;
                text-align: center;
                margin-top: 4px;
                font-size: 11px;
                font-family: monospace;
            }

            .mcs-nt-scam-warning {
                background: #ff1744;
                color: white;
                padding: 8px;
                border-radius: 4px;
                font-weight: bold;
                text-align: center;
                margin-top: 4px;
                font-size: 12px;
                border: 2px solid #ff5252;
            }

            .mcs-nt-tally-btn {
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                cursor: pointer;
                font-weight: bold;
                width: 100%;
                margin-top: 4px;
            }

            .mcs-nt-marketplace-warning {
                font-weight: bold;
                font-size: 11px;
                margin-top: 2px;
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 4px;
            }

            .mcs-nt-scam-bid {
                color: #ff1744;
                font-weight: bold;
            }

            .mcs-nt-equal-vendor {
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-nt-scam-total {
                color: #ff1744;
            }

            .mcs-nt-equal-vendor-total {
                color: #FFD700;
            }

            .mcs-ko-pane {
                display: flex;
                flex-direction: column;
                width: 280px;
            }

            .mcs-ko-title-section {
                display: flex;
                align-items: center;
                gap: 8px;
            }

            .mcs-ko-content {
                display: flex;
                flex-direction: column;
                padding: 10px 15px;
                color: #e0e0e0;
                font-size: 12px;
                line-height: 1.6;
            }

            .mcs-ko-player-name {
                font-size: 13px;
                font-weight: bold;
                color: #4CAF50;
            }

            .mcs-ko-score-container {
                margin-bottom: 5px;
            }

            .mcs-ko-score-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                cursor: pointer;
                gap: 4px;
            }

            .mcs-ko-toggle-indicator {
                color: #4CAF50;
                font-weight: bold;
                flex-shrink: 0;
            }

            .mcs-ko-label-value {
                display: flex;
                justify-content: space-between;
                flex: 1;
            }

            .mcs-ko-score-label {
                color: #FFA500;
            }

            .mcs-ko-score-value {
                color: #4CAF50;
                font-weight: bold;
            }

            .mcs-ko-details {
                display: none;
                margin-left: 20px;
                margin-top: 5px;
                font-size: 10px;
                max-height: 200px;
                overflow-y: auto;
            }

            .mcs-ko-total-row {
                display: flex;
                justify-content: space-between;
                font-size: 13px;
                margin-top: 5px;
                padding-top: 5px;
                border-top: 1px solid #444;
            }

            .mcs-ko-total-label {
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-ko-total-value {
                color: #FFD700;
                font-weight: bold;
            }

            .mcs-ko-networth-container {
                margin-top: 10px;
                font-size: 12px;
            }

            .mcs-ko-networth-header {
                display: flex;
                justify-content: space-between;
                cursor: pointer;
                font-weight: bold;
                color: #4CAF50;
            }

            .mcs-ko-networth-details {
                display: none;
                margin-left: 15px;
                margin-top: 5px;
                color: #aaa;
            }

            .mcs-ko-networth-row {
                display: flex;
                justify-content: space-between;
            }

            .mcs-ko-inspected-section {
                margin-top: 15px;
                border-top: 1px solid #444;
                padding-top: 10px;
            }

            .mcs-ko-inspected-header {
                cursor: pointer;
                font-weight: bold;
                color: #4CAF50;
                font-size: 12px;
                margin-bottom: 5px;
            }

            .mcs-ko-inspected-list {
                display: none;
                font-size: 11px;
                max-height: 200px;
                overflow-y: auto;
            }

            .mcs-ko-side-panel {
                position: fixed;
                background: rgba(30, 30, 30, 0.98);
                border: 1px solid #444;
                border-radius: 8px;
                padding: 12px;
                min-width: 180px;
                max-width: 220px;
                font-size: 0.875rem;
                z-index: 10001;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
            }

            .mcs-ko-score-section {
                text-align: left;
                color: #4CAF50;
            }

            .mcs-ko-side-name-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 6px;
            }

            .mcs-ko-side-player-name {
                font-weight: bold;
                color: #FFD700;
                font-size: 0.9rem;
            }

            .mcs-ko-close-btn {
                cursor: pointer;
                font-size: 18px;
                color: #aaa;
                padding: 0 5px;
                line-height: 1;
            }
            .mcs-ko-close-btn:hover {
                color: #fff;
            }

            .mcs-ko-build-score-toggle {
                cursor: pointer;
                font-weight: bold;
                margin-bottom: 8px;
            }

            .mcs-ko-side-score-details {
                display: none;
                margin-left: 10px;
                margin-bottom: 10px;
            }

            .mcs-ko-buttons-container {
                display: flex;
                flex-direction: column;
                gap: 8px;
                margin-top: 10px;
            }

            .mcs-ko-action-btn {
                border-radius: 5px;
                height: 30px;
                box-shadow: none;
                border: 0px;
                cursor: pointer;
                margin-top: 10px;
                padding: 0 12px;
                font-weight: bold;
            }

            .mcs-ko-player-container {
                border-bottom: 1px solid #333;
                padding: 3px 0;
            }

            .mcs-ko-player-row {
                color: #e0e0e0;
                display: flex;
                justify-content: space-between;
                align-items: center;
                gap: 4px;
            }

            .mcs-ko-delete-btn {
                background: #ff5555;
                color: #fff;
                border: none;
                border-radius: 3px;
                padding: 0 6px;
                font-size: 16px;
                cursor: pointer;
                line-height: 1;
                font-weight: bold;
                flex-shrink: 0;
            }
            .mcs-ko-delete-btn:hover {
                background: #ff7777;
            }

            .mcs-ko-player-info {
                display: flex;
                justify-content: space-between;
                flex: 1;
                cursor: pointer;
            }

            .mcs-ko-player-details {
                display: none;
                margin-left: 20px;
                margin-top: 5px;
                font-size: 10px;
            }

            .mcs-ko-detail-subsection {
                margin-bottom: 5px;
            }

            .mcs-ko-detail-sub-header {
                display: flex;
                align-items: center;
                gap: 5px;
                cursor: pointer;
                color: #e0e0e0;
            }

            .mcs-ko-detail-sub-content {
                display: none;
                margin-left: 15px;
                margin-top: 3px;
                font-size: 9px;
            }

            .mcs-ko-detail-sub-content-scroll {
                display: none;
                margin-left: 15px;
                margin-top: 3px;
                font-size: 9px;
                max-height: 150px;
                overflow-y: auto;
            }

            .mcs-ko-detail-item {
                padding: 1px 0;
                margin-right: 4px;
            }

            .mcs-ko-detail-item-value {
                color: #4CAF50;
                margin-left: 5px;
            }

            .mcs-ko-detail-row {
                display: flex;
                justify-content: space-between;
                color: #e0e0e0;
                padding: 2px 0;
                margin-right: 4px;
            }

            .mcs-ko-empty-message {
                color: #888;
                padding: 5px;
            }

            .mcs-ko-error-message {
                color: #ff5555;
                padding: 5px;
            }

            .lucky-panel {
                position: fixed;
                top: 0;
                left: 0;
                width: 80vw;
                height: 80vh;
                background: rgba(30, 30, 30, 0.98);
                border: 1px solid rgba(80, 80, 80, 0.8);
                border-radius: 0px;
                z-index: 10100;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                color: white;
                overflow: hidden;
                min-width: 50px;
                min-height: 50px;
            }

            .lucky-content {
                overflow: hidden;
                padding: 0;
                position: relative;
                width: 100%;
                height: 100%;
            }

            .lucky-content-spacer {
                position: absolute;
                left: 0;
                width: 100px;
                height: 100px;
                pointer-events: none;
                opacity: 0;
            }

            .lucky-floating-panel {
                position: absolute;
                background: rgba(30, 30, 30, 0.95);
                border: 1px solid transparent;
                border-radius: 0px;
                padding: 8px 12px 12px 12px;
                z-index: 10001;
                overflow: hidden;
                display: flex;
                flex-direction: column;
                transition: border-color 0.2s;
            }

            .lucky-floating-panel:hover {
                border-color: rgba(80, 80, 80, 0.8);
            }

            .lucky-resize-handle {
                position: absolute;
                user-select: none;
                z-index: 10;
            }

            .lucky-resize-handle-right {
                right: 0;
                top: 0;
                width: 10px;
                height: 100%;
                cursor: ew-resize;
            }

            .lucky-resize-handle-left {
                left: 0;
                top: 0;
                width: 10px;
                height: 100%;
                cursor: ew-resize;
            }

            .lucky-resize-handle-bottom {
                bottom: 0;
                left: 0;
                width: 100%;
                height: 10px;
                cursor: ns-resize;
            }

            .lucky-resize-handle-top {
                top: 0;
                left: 0;
                width: 100%;
                height: 10px;
                cursor: ns-resize;
            }

            .lucky-resize-handle-corner {
                right: 0;
                bottom: 0;
                width: 20px;
                height: 20px;
                cursor: nwse-resize;
            }

            .lucky-resize-handle-corner-topleft {
                left: 0;
                top: 0;
                width: 20px;
                height: 20px;
                cursor: nwse-resize;
            }

            .lucky-resize-handle-corner-topright {
                right: 0;
                top: 0;
                width: 20px;
                height: 20px;
                cursor: nesw-resize;
            }

            .lucky-resize-handle-corner-bottomleft {
                left: 0;
                bottom: 0;
                width: 20px;
                height: 20px;
                cursor: nesw-resize;
            }

            .lucky-stats-section {
                top: 60px;
                right: 20px;
                min-width: 50px;
                max-width: 400px;
                width: fit-content;
            }

            .lucky-data-panel {
                min-width: 50px;
                max-width: 800px;
                width: 400px;
                min-height: 50px;
                max-height: 80vh;
            }

            .lucky-panel-header {
                flex-shrink: 0;
                overflow: visible;
            }

            .lucky-panel-content-scrollable {
                flex: 1;
                overflow-y: auto;
                overflow-x: hidden;
                min-height: 0;
            }

            .lucky-panel-header .lucky-drop-table {
                margin-bottom: 0;
            }

            .lucky-panel-content-scrollable .lucky-drop-table {
                margin-top: 0;
            }

            .lucky-panel-content-scrollable .lucky-drop-table tbody tr:first-child td {
                border-top: none;
            }

            .lucky-player-stats-info {
                font-size: 9px;
                color: #a0b9ff;
                margin-bottom: 8px;
                padding-bottom: 8px;
                border-bottom: 1px solid rgba(80, 80, 80, 0.3);
            }

            .lucky-revenue-panel {
                min-width: 50px;
                min-height: 50px;
                width: fit-content;
                height: fit-content;
            }

            .lucky-big-expected-panel {
                min-width: 50px;
                min-height: 50px;
                max-width: 600px;
                width: 400px;
                height: fit-content;
            }

            .lucky-big-expected-header {
                display: block;
                margin-bottom: 8px;
            }

            .lucky-big-expected-content {
                display: flex;
                flex-wrap: wrap;
                gap: 12px;
                row-gap: 3px;
                align-items: center;
            }

            .lucky-big-expected-item {
                display: flex;
                align-items: center;
                gap: 8px;
                font-size: 16px;
                white-space: nowrap;
            }

            .lucky-big-expected-name {
                color: #b0b0b0;
                font-weight: 500;
            }

            .lucky-big-expected-percent {
                font-weight: 600;
            }

            .lucky-big-expected-total {
                font-weight: 600;
            }

            .lucky-big-luck-panel {
                min-width: 50px;
                min-height: 50px;
                max-width: 600px;
                width: 400px;
                height: fit-content;
            }

            .lucky-big-luck-header {
                display: block;
                margin-bottom: 8px;
            }

            .lucky-big-luck-content {
                display: flex;
                flex-wrap: wrap;
                gap: 12px;
                row-gap: 3px;
                align-items: center;
            }

            .lucky-big-luck-item {
                display: flex;
                align-items: center;
                gap: 8px;
                font-size: 16px;
                white-space: nowrap;
            }

            .lucky-big-luck-name {
                color: #b0b0b0;
                font-weight: 500;
            }

            .lucky-big-luck-percent {
                font-weight: 600;
            }

            .lucky-big-luck-total {
                font-weight: 600;
            }

            .lucky-content-controls {
                position: absolute;
                top: 8px;
                right: 8px;
                display: flex;
                gap: 8px;
                z-index: 10102;
                opacity: 0;
                transition: opacity 0.2s;
            }

            .lucky-panel:hover .lucky-content-controls {
                opacity: 1;
            }

            .lucky-control-icon {
                width: 24px;
                height: 24px;
                background: rgba(40, 40, 40, 0.9);
                border: 1px solid rgba(80, 80, 80, 0.6);
                border-radius: 0px;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                color: rgba(255, 255, 255, 0.7);
                font-size: 14px;
                transition: all 0.2s;
                user-select: none;
            }

            .lucky-control-icon:hover {
                background: rgba(60, 60, 60, 0.9);
                color: rgba(255, 255, 255, 0.9);
                border-color: rgba(100, 100, 100, 0.8);
            }

            .lucky-control-icon.active {
                background: rgba(84, 109, 219, 0.3);
                border-color: rgba(84, 109, 219, 0.6);
                color: #4ade80;
            }

            .lucky-options-panel {
                position: fixed;
                background: rgba(30, 30, 30, 0.98);
                border: 1px solid rgba(80, 80, 80, 0.8);
                border-radius: 0px;
                padding: 12px;
                z-index: 10103;
                display: none;
            }

            .lucky-options-panel.visible {
                display: block;
            }

            .lucky-options-title {
                font-size: 14px;
                font-weight: 600;
                color: #e8e8e8;
                margin-bottom: 12px;
                border-bottom: 1px solid rgba(80, 80, 80, 0.5);
                padding-bottom: 8px;
            }

            .lucky-options-title-mt {
                margin-top: 12px;
            }

            .lucky-option-row {
                display: flex;
                align-items: center;
                gap: 4px;
                background: rgba(255,255,255,0.05);
                padding: 4px 8px;
                border-radius: 0px;
                white-space: nowrap;
            }

            .lucky-option-checkbox {
                cursor: pointer;
            }

            .lucky-option-label {
                color: #e0e0e0;
                font-size: 10px;
                cursor: pointer;
                user-select: none;
            }

            .lucky-stats-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 8px;
                user-select: none;
                cursor: move;
                padding: 2px 0;
            }

            .lucky-stats-header:hover {
                background: rgba(255, 255, 255, 0.05);
            }

            .lucky-stats-title {
                font-size: 13px;
                font-weight: 600;
                flex-grow: 1;
                color: #e8e8e8;
            }

            .lucky-stat-row {
                display: flex;
                flex-wrap: wrap;
                align-items: baseline;
                gap: 4px;
                font-size: 12px;
                padding: 3px 0;
                color: #a8aed4;
            }

            .lucky-stat-label {
                color: #b0b0b0;
                white-space: nowrap;
            }

            .lucky-stat-value {
                color: #4ade80;
                font-weight: 500;
                white-space: nowrap;
            }

            .lucky-revenue-row-container {
                margin-bottom: 8px;
            }

            .lucky-revenue-row-container:last-child {
                margin-bottom: 0;
            }

            .lucky-revenue-row-container:last-child .lucky-revenue-row {
                font-weight: 600;
                padding-top: 8px;
                border-top: 1px solid rgba(80, 80, 80, 0.3);
            }

            .lucky-revenue-row {
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                row-gap: 2px;
                align-items: baseline;
                font-size: 11px;
            }

            .lucky-revenue-name {
                color: #b0b0b0;
                min-width: 100px;
                flex-shrink: 0;
            }

            .lucky-revenue-stat {
                display: flex;
                gap: 4px;
                align-items: baseline;
                white-space: nowrap;
            }

            .lucky-revenue-stats-group {
                display: flex;
                gap: 8px;
                flex-wrap: nowrap;
                white-space: nowrap;
            }

            .lucky-revenue-stat-label {
                color: #888;
                font-size: 9px;
            }

            .lucky-revenue-stat-value {
                color: #e0e0e0;
                font-weight: 500;
            }

            .lucky-revenue-stat-value.colored {
                color: inherit;
            }

            .lucky-player-section {
                background: rgba(40, 40, 40, 0.6);
                border: 1px solid rgba(80, 80, 80, 0.4);
                border-radius: 0px;
                margin-bottom: 12px;
                overflow: hidden;
            }

            .lucky-player-header {
                background: rgba(50, 50, 50, 0.8);
                padding: 8px 12px;
                font-weight: 600;
                font-size: 13px;
                border-bottom: 1px solid rgba(80, 80, 80, 0.3);
            }

            .lucky-drop-table {
                width: 100%;
                border-collapse: collapse;
                table-layout: fixed;
            }

            .lucky-drop-table th {
                padding: 8px;
                text-align: left;
                font-size: 11px;
                color: #b0b0b0;
                font-weight: 600;
                border-bottom: 1px solid rgba(80, 80, 80, 0.3);
                background: rgba(40, 40, 40, 0.8);
            }

            .lucky-drop-table td {
                padding: 6px 8px;
                font-size: 11px;
                border-bottom: 1px solid rgba(80, 80, 80, 0.15);
            }

            .lucky-drop-table tr:hover {
                background: rgba(60, 60, 60, 0.4);
            }

            .lucky-item-name {
                color: #d0d0d0;
                font-weight: 500;
            }

            .lucky-value-positive {
                color: #4ade80;
            }

            .lucky-value-negative {
                color: #f87171;
            }

            .lucky-value-neutral {
                color: #a8aed4;
            }

            .lucky-no-data {
                text-align: center;
                padding: 30px;
                color: #a8aed4;
                font-size: 14px;
            }

            .lucky-grid-overlay {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                min-height: 1000px;
                background-image:
                    repeating-linear-gradient(0deg, transparent, transparent 9px, rgba(200, 200, 200, 0.3) 9px, rgba(200, 200, 200, 0.3) 10px),
                    repeating-linear-gradient(90deg, transparent, transparent 9px, rgba(200, 200, 200, 0.3) 9px, rgba(200, 200, 200, 0.3) 10px);
                pointer-events: none;
                display: none;
                z-index: 1000;
            }

            .lucky-options-container {
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                align-items: center;
            }

            .lucky-reset-btn {
                margin-top: 12px;
                padding: 6px 12px;
                background: rgba(60, 60, 60, 0.9);
                border: 1px solid rgba(80, 80, 80, 0.6);
                border-radius: 0px;
                color: #e8e8e8;
                cursor: pointer;
                font-size: 11px;
            }

            .lucky-auto-grid-btn {
                margin-top: 8px;
                padding: 8px;
                width: 100%;
                background: #22c55e;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: bold;
            }

            .lucky-empty-state {
                color: #888;
                padding: 8px;
                text-align: center;
            }

            .lucky-total-row {
                background: rgba(84, 109, 219, 0.15);
                font-weight: 600;
                border-top: 2px solid rgba(113, 123, 169, 0.8);
            }

            .mcs-ma-pane {
                width: 600px;
                height: 550px;
                resize: both;
                overflow: hidden;
                min-height: 300px;
            }

            .mcs-ma-title-section {
                display: flex;
                align-items: center;
                gap: 12px;
            }

            .mcs-ma-time-display {
                font-size: 12px;
                color: #aaa;
                padding: 4px 8px;
                background: rgba(0, 0, 0, 0.3);
                border-radius: 3px;
            }

            .mcs-ma-mana-display {
                font-size: 12px;
                color: #64b5f6;
                padding: 4px 8px;
                background: rgba(0, 0, 0, 0.3);
                border-radius: 3px;
            }

            .mcs-ma-content {
                padding: 10px 15px;
                color: #e0e0e0;
                font-size: 12px;
                line-height: 1.6;
                overflow-y: auto;
                overflow-x: hidden;
                height: calc(100% - 40px);
            }

            .mcs-ma-waiting {
                color: #999;
                text-align: center;
                padding: 40px 20px;
                font-size: 14px;
            }

            .mcs-ma-waiting-icon {
                font-size: 18px;
                margin-bottom: 10px;
            }

            .mcs-ma-waiting-sub {
                font-size: 11px;
                margin-top: 8px;
                color: #666;
            }

            .mcs-ma-table-wrapper {
                padding: 12px;
            }

            .mcs-ma-table {
                width: 100%;
                border-collapse: collapse;
            }

            .mcs-ma-th {
                padding: 8px;
                color: #aaa;
                font-size: 11px;
                font-weight: normal;
            }

            .mcs-ma-th-left {
                text-align: left;
            }

            .mcs-ma-th-right {
                text-align: right;
            }

            .mcs-ma-thead-row {
                border-bottom: 1px solid rgba(255, 255, 255, 0.1);
            }

            .mcs-ma-changes-section {
                margin-top: 16px;
                padding-top: 16px;
                border-top: 1px solid rgba(74, 144, 226, 0.3);
            }

            .mcs-ma-ability-row {
                border-bottom: 1px solid rgba(255, 255, 255, 0.05);
            }

            .mcs-ma-td {
                padding: 8px;
            }

            .mcs-ma-td-right {
                text-align: right;
                padding: 8px;
            }

            .mcs-ma-ability-name {
                padding: 8px;
                color: #e0e0e0;
                text-transform: capitalize;
            }

            .mcs-ma-color-green {
                color: #81c784;
            }

            .mcs-ma-color-orange {
                color: #ffb74d;
            }

            .mcs-ma-color-red {
                color: #ef5350;
            }

            .mcs-ma-color-blue {
                color: #64b5f6;
            }

            .mcs-ma-color-purple {
                color: #9c27b0;
            }

            .mcs-ma-change-row {
                border-bottom: 1px solid rgba(255, 255, 255, 0.05);
            }

            .mcs-ma-net-row {
                border-top: 2px solid rgba(74, 144, 226, 0.3);
                font-weight: bold;
            }

            .mcs-ma-full-mana-row {
                border-top: 1px solid rgba(255, 255, 255, 0.1);
            }

            .mcs-ih-pane {
                min-width: 400px;
                max-width: 600px;
                width: fit-content;
                max-height: 80vh;
            }

            .mcs-ih-title-section {
                display: flex;
                align-items: center;
                gap: 12px;
            }

            .mcs-ih-title {
                color: #FF4444;
            }

            .mcs-ih-time-display {
                font-size: 12px;
                color: #aaa;
                padding: 4px 8px;
                background: rgba(0, 0, 0, 0.3);
                border-radius: 3px;
            }

            .mcs-ih-deaths-display {
                font-size: 12px;
                color: #FFA07A;
                padding: 4px 8px;
                background: rgba(0, 0, 0, 0.3);
                border-radius: 3px;
            }

            .mcs-ih-content {
                padding: 12px;
                color: white;
                font-size: 12px;
                overflow-y: auto;
                flex: 1;
                max-height: 600px;
            }

            .mcs-ih-waiting {
                color: #999;
                text-align: center;
                padding: 40px 20px;
                font-size: 14px;
            }

            .mcs-ih-waiting-icon {
                font-size: 18px;
                margin-bottom: 10px;
            }

            .mcs-ih-waiting-sub {
                font-size: 11px;
                margin-top: 8px;
                color: #666;
            }

            .mcs-ih-main {
                margin-bottom: 12px;
            }

            .mcs-ih-deaths-row {
                display: flex;
                align-items: center;
                gap: 8px;
                margin-bottom: 6px;
                padding: 4px 8px;
                background: rgba(255, 68, 68, 0.1);
                border-radius: 4px;
                font-size: 11px;
                flex-wrap: wrap;
            }

            .mcs-ih-deaths-label {
                color: #FFA07A;
                font-weight: bold;
            }

            .mcs-ih-player-name {
                color: #FFD700;
            }

            .mcs-ih-death-count {
                color: #FF4444;
                font-weight: bold;
            }

            .mcs-ih-separator {
                color: #555;
            }

            .mcs-ih-total-label {
                color: #aaa;
            }

            .mcs-ih-dph-row {
                display: flex;
                align-items: center;
                gap: 8px;
                margin-bottom: 10px;
                padding: 4px 8px;
                background: rgba(255, 160, 122, 0.1);
                border-radius: 4px;
                font-size: 11px;
                flex-wrap: wrap;
            }

            .mcs-ih-dph-value {
                color: #FFA07A;
            }

            .mcs-ih-dph-total {
                color: #FFA07A;
                font-weight: bold;
            }

            .mcs-ih-player-grid {
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 8px;
            }

            .mcs-ih-player-card {
                background: rgba(255, 255, 255, 0.05);
                padding: 10px;
                border-radius: 4px;
                border: 1px solid rgba(255, 255, 255, 0.1);
            }

            .mcs-ih-player-card-name {
                color: #FFD700;
                font-weight: bold;
                margin-bottom: 8px;
                text-align: center;
                font-size: 13px;
            }

            .mcs-ih-player-stats {
                display: flex;
                flex-direction: column;
                gap: 4px;
            }

            .mcs-ih-stat-row {
                display: flex;
                justify-content: space-between;
            }

            .mcs-ih-stat-label {
                color: #aaa;
                font-size: 10px;
            }

            .mcs-ih-damage-value {
                color: #FF4444;
                font-weight: bold;
            }

            .mcs-ih-regen-value {
                color: #4CAF50;
                font-weight: bold;
            }

            .mcs-ih-total-section {
                margin-top: 4px;
                padding-top: 4px;
                border-top: 1px solid rgba(255, 255, 255, 0.1);
            }

            .mcs-ih-total-label-sm {
                color: #888;
                font-size: 9px;
            }

            .mcs-ih-total-dmg {
                color: #FF6666;
                font-size: 10px;
            }

            .mcs-ih-total-regen {
                color: #4CAF50;
                font-size: 10px;
            }

            .mcs-ih-death-section {
                margin-top: 6px;
                padding-top: 6px;
                border-top: 1px solid rgba(255, 255, 255, 0.1);
            }

            .mcs-ih-death-count-sm {
                color: #FF4444;
                font-size: 10px;
                font-weight: bold;
            }

            .mcs-ih-dph-value-sm {
                color: #FFA07A;
                font-size: 10px;
            }

            .mcs-ih-section {
                margin-top: 16px;
                padding-top: 12px;
                border-top: 1px solid rgba(255, 255, 255, 0.1);
            }

            .mcs-ih-section-toggle {
                display: flex;
                align-items: center;
                gap: 6px;
                margin-bottom: 8px;
                cursor: pointer;
                padding: 4px;
                border-radius: 3px;
                background: rgba(255, 255, 255, 0.02);
            }

            .mcs-ih-enemy-toggle {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 8px;
                cursor: pointer;
                padding: 4px;
                border-radius: 3px;
                background: rgba(255, 255, 255, 0.02);
            }

            .mcs-ih-toggle-left {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-ih-toggle-arrow {
                font-size: 9px;
                min-width: 12px;
            }

            .mcs-ih-toggle-arrow-red {
                color: #FF6B6B;
            }

            .mcs-ih-toggle-arrow-gold {
                color: #FFD700;
            }

            .mcs-ih-toggle-arrow-blue {
                color: #87CEEB;
            }

            .mcs-ih-section-label {
                color: #aaa;
                font-size: 11px;
                font-weight: bold;
            }

            .mcs-ih-enemy-total {
                color: #FF6B6B;
                font-weight: bold;
                font-size: 14px;
            }

            .mcs-ih-enemy-grid {
                display: grid;
                grid-template-columns: repeat(2, 1fr);
                gap: 8px;
            }

            .mcs-ih-enemy-card {
                padding: 8px;
                background: rgba(255, 107, 107, 0.1);
                border-radius: 4px;
                border-left: 3px solid #FF6B6B;
            }

            .mcs-ih-enemy-name {
                font-weight: bold;
                color: #FF6B6B;
                margin-bottom: 6px;
                font-size: 11px;
            }

            .mcs-ih-enemy-total-dmg {
                font-size: 10px;
                color: #FF8888;
                margin-bottom: 4px;
            }

            .mcs-ih-enemy-range {
                font-size: 9px;
                color: #FFB6C1;
                margin-bottom: 6px;
            }

            .mcs-ih-enemy-players {
                display: flex;
                flex-direction: column;
                gap: 2px;
                margin-top: 6px;
            }

            .mcs-ih-enemy-player-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                font-size: 9px;
                background: rgba(255, 255, 255, 0.03);
                padding: 3px 6px;
                border-radius: 3px;
            }

            .mcs-ih-enemy-player-name {
                color: #FF6666;
                font-weight: bold;
            }

            .mcs-ih-enemy-player-dmg {
                color: #FF8888;
            }

            .mcs-ih-enemy-player-range {
                color: #FFB6C1;
                font-size: 8px;
            }

            .mcs-ih-profile-card {
                margin-bottom: 8px;
                padding: 8px;
                background: rgba(0, 0, 0, 0.2);
                border-radius: 4px;
            }

            .mcs-ih-profile-name {
                color: #FFD700;
                font-size: 11px;
                margin-bottom: 4px;
            }

            .mcs-ih-profile-stats {
                font-size: 10px;
                color: #aaa;
            }

            .mcs-ih-encounters-total {
                color: #87CEEB;
                font-weight: bold;
                font-size: 12px;
            }

            .mcs-ih-kills-grid {
                display: grid;
                grid-template-columns: repeat(2, 1fr);
                gap: 6px;
            }

            .mcs-ih-kill-card {
                padding: 6px 8px;
                background: rgba(135, 206, 235, 0.08);
                border-radius: 4px;
                border-left: 3px solid #87CEEB;
            }

            .mcs-ih-kill-card-dim {
                padding: 6px 8px;
                background: rgba(135, 206, 235, 0.05);
                border-radius: 4px;
                border-left: 3px solid #555;
                opacity: 0.6;
            }

            .mcs-ih-kill-name {
                font-weight: bold;
                color: #87CEEB;
                font-size: 11px;
                margin-bottom: 4px;
            }

            .mcs-ih-kill-stats {
                display: flex;
                justify-content: space-between;
                font-size: 10px;
            }

            .mcs-ih-kill-actual {
                color: #ddd;
            }

            .mcs-ih-kill-expected {
                color: #888;
            }

            .mcs-qcharm-pane {
                position: fixed;
                top: 0;
                left: 0;
                background: #2b2b2b;
                border-radius: 6px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                z-index: 99999;
                font-family: sans-serif;
                resize: both;
                overflow: hidden;
                min-width: 400px;
                min-height: 250px;
            }

            /* QCharm pane when minimized */
            .mcs-qcharm-pane-minimized {
                min-height: 0;
                resize: none;
            }

            .mcs-qcharm-title-section {
                display: flex;
                align-items: center;
                gap: 8px;
            }

            .mcs-qcharm-title {
                font-size: 14px;
            }

            .mcs-qcharm-button-section {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-qcharm-content {
                padding: 10px;
                color: #e0e0e0;
                font-size: 12px;
                overflow-y: auto;
                overflow-x: hidden;
                height: calc(100% - 40px);
            }

            .mcs-qcharm-empty {
                display: flex;
                align-items: center;
                justify-content: center;
                height: 100%;
                color: #999;
                font-size: 14px;
            }

            .mcs-qcharm-table {
                width: 100%;
                border-collapse: collapse;
                background: #1a1a1a;
                border-radius: 4px;
                overflow: hidden;
            }

            .mcs-qcharm-th {
                background: #333;
                color: #fff;
                padding: 8px 10px;
                text-align: left;
                font-weight: bold;
                font-size: 11px;
                border-bottom: 2px solid #444;
            }

            .mcs-qcharm-sortable {
                cursor: pointer;
                user-select: none;
                position: relative;
            }

            .mcs-qcharm-sortable:hover {
                background: #3a3a3a;
            }

            .mcs-qcharm-sorted-asc::after {
                content: ' ▲';
                font-size: 10px;
                color: #4CAF50;
            }

            .mcs-qcharm-sorted-desc::after {
                content: ' ▼';
                font-size: 10px;
                color: #4CAF50;
            }

            .mcs-qcharm-row {
                border-bottom: 1px solid #2a2a2a;
            }

            .mcs-qcharm-row:hover {
                background: #252525;
            }

            .mcs-qcharm-equipped {
                background: rgba(255, 152, 0, 0.15);
            }

            .mcs-qcharm-equipped:hover {
                background: rgba(255, 152, 0, 0.25);
            }

            .mcs-qcharm-td {
                padding: 8px 10px;
                color: #e0e0e0;
                font-size: 12px;
            }

            /* QCharm Guide Section */
            .mcs-qcharm-guide-section {
                margin-bottom: 12px;
                border: 1px solid #444;
                border-radius: 4px;
                background: rgba(0, 0, 0, 0.3);
            }

            .mcs-qcharm-guide-header {
                padding: 8px 12px;
                background: rgba(0, 0, 0, 0.4);
                cursor: pointer;
                display: flex;
                justify-content: space-between;
                align-items: center;
                font-weight: 600;
                color: #ffd700;
                font-size: 13px;
                user-select: none;
            }

            .mcs-qcharm-guide-header:hover {
                background: rgba(0, 0, 0, 0.5);
            }

            .mcs-qcharm-guide-toggle {
                font-size: 10px;
                color: #999;
            }

            .mcs-qcharm-guide-content {
                padding: 10px;
                max-height: 500px;
                overflow: hidden;
                transition: max-height 0.3s ease;
            }

            .mcs-qcharm-guide-collapsed {
                max-height: 0;
                padding: 0 10px;
            }

            .mcs-qcharm-guide-row {
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                margin-bottom: 10px;
            }

            .mcs-qcharm-guide-item {
                padding: 4px 10px;
                background: rgba(50, 50, 50, 0.6);
                border: 1px solid #555;
                border-radius: 3px;
                font-size: 12px;
                color: #e0e0e0;
                white-space: nowrap;
            }

            .mcs-qcharm-guide-enh-table {
                display: flex;
                flex-direction: column;
                gap: 4px;
            }

            .mcs-qcharm-guide-enh-row {
                display: grid;
                grid-template-columns: repeat(4, 1fr);
                gap: 6px;
            }

            .mcs-qcharm-guide-enh-cell {
                padding: 4px 8px;
                background: rgba(40, 40, 40, 0.6);
                border: 1px solid #555;
                border-radius: 3px;
                font-size: 11px;
                color: #d0d0d0;
                text-align: center;
            }

            .mcs-qcharm-guide-enh-cell:empty {
                visibility: hidden;
            }

            .mcs-qcharm-table-container {
                /* Container for the actual table, separate from guide */
            }

            .mcs-qcharm-last-seen {
                font-size: 11px;
                color: #999;
                font-style: italic;
            }

            /* QCharm Collapsible Table Sections */
            .mcs-qcharm-section {
                margin-bottom: 12px;
                border: 1px solid #444;
                border-radius: 4px;
                background: rgba(0, 0, 0, 0.3);
            }

            .mcs-qcharm-section-header {
                padding: 8px 12px;
                background: rgba(0, 0, 0, 0.4);
                cursor: pointer;
                display: flex;
                justify-content: space-between;
                align-items: center;
                font-weight: 600;
                color: #87CEEB;
                font-size: 12px;
                user-select: none;
            }

            .mcs-qcharm-section-header:hover {
                background: rgba(0, 0, 0, 0.5);
            }

            .mcs-qcharm-section-toggle {
                font-size: 10px;
                color: #999;
            }

            .mcs-qcharm-section-content {
                max-height: 2000px;
                overflow: hidden;
                transition: max-height 0.3s ease;
            }

            .mcs-qcharm-section-collapsed {
                max-height: 0;
                overflow: hidden;
            }

            .mcs-resize-handle {
                position: absolute;
                width: 12px;
                height: 12px;
                z-index: 10;
            }

            .mcs-resize-handle-nw {
                top: 0;
                left: 0;
                cursor: nw-resize;
            }

            .mcs-resize-handle-ne {
                top: 0;
                right: 0;
                cursor: ne-resize;
            }

            .mcs-resize-handle-sw {
                bottom: 0;
                left: 0;
                cursor: sw-resize;
            }

            .mcs-resize-handle-se {
                bottom: 0;
                right: 0;
                cursor: se-resize;
            }

            .mcs-cursor-move {
                cursor: move;
            }

            .mcs-cursor-grabbing {
                cursor: grabbing;
            }

            .mcs-clickable {
                cursor: pointer;
            }

            .mcs-tr-pane {
                min-width: 400px;
                min-height: 200px;
                resize: both;
                overflow: hidden;
            }

            .mcs-tr-title-section {
                display: flex;
                align-items: center;
                gap: 8px;
            }

            .mcs-tr-title {
                color: #FFD700;
            }

            .mcs-tr-header-btn {
                cursor: pointer;
                font-size: 11px;
                padding: 2px 6px;
                border-radius: 3px;
                margin-left: 8px;
            }

            .mcs-tr-reset-all-btn {
                color: #F44336;
                background: #444;
            }

            .mcs-tr-reset-all-btn:hover {
                background: #555;
            }

            .mcs-tr-configure-btn {
                font-size: 14px;
                color: #aaa;
                background: #444;
            }

            .mcs-tr-configure-btn:hover {
                background: #555;
                color: #fff;
            }

            .mcs-tr-configure-btn.active {
                background: #666;
                color: #FFD700;
            }

            .mcs-tr-minimize-btn {
                cursor: pointer;
                font-size: 18px;
                color: #aaa;
                padding: 0 5px;
            }

            .mcs-tr-minimize-btn:hover {
                color: #fff;
            }

            .mcs-tr-content {
                padding: 10px;
                color: #ddd;
                font-size: 12px;
                overflow-y: auto;
                flex: 1;
            }

            .mcs-tr-content-minimized {
                padding: 6px 10px;
                color: #ddd;
                font-size: 11px;
                display: flex;
                flex-wrap: wrap;
                gap: 6px;
                align-items: center;
            }

            .mcs-tr-side-panel {
                position: fixed;
                background: rgba(30, 30, 30, 0.98);
                border: 1px solid #444;
                border-radius: 8px;
                padding: 12px;
                min-width: 200px;
                max-width: 280px;
                z-index: 100000;
                font-size: 11px;
                color: #ddd;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                max-height: 80vh;
                overflow-y: auto;
            }

            .mcs-tr-side-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 8px;
            }

            .mcs-tr-side-title {
                font-weight: bold;
                color: #FFD700;
                font-size: 12px;
            }

            .mcs-tr-close-btn {
                cursor: pointer;
                font-size: 18px;
                color: #aaa;
                padding: 0 5px;
                line-height: 1;
            }

            .mcs-tr-close-btn:hover {
                color: #fff;
            }

            .mcs-tr-no-data {
                color: #888;
                text-align: center;
                padding: 10px;
            }

            .mcs-tr-side-section {
                margin-bottom: 8px;
                padding-bottom: 8px;
                border-bottom: 1px solid #444;
            }

            .mcs-tr-side-section-title {
                color: #87CEEB;
                font-weight: bold;
                margin-bottom: 4px;
            }

            .mcs-tr-side-value-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
            }

            .mcs-tr-side-item-row {
                display: flex;
                align-items: center;
                gap: 4px;
                margin-bottom: 3px;
            }

            .mcs-tr-side-item-details {
                display: flex;
                flex-direction: column;
                flex: 1;
            }

            .mcs-tr-side-item-values {
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-tr-min-30 {
                min-width: 30px;
            }

            .mcs-tr-min-45 {
                min-width: 45px;
                font-size: 9px;
            }

            .mcs-tr-font-9 {
                font-size: 9px;
            }

            .mcs-tr-side-expected-row {
                display: flex;
                align-items: center;
                gap: 4px;
                color: #666;
                font-size: 9px;
            }

            .mcs-tr-side-total {
                margin-top: 8px;
                padding-top: 8px;
                border-top: 1px solid #444;
            }

            .mcs-tr-side-total-text {
                color: #888;
                font-size: 10px;
            }

            .mcs-tr-side-action-row {
                margin-top: 10px;
                text-align: center;
            }

            .mcs-tr-view-stats-btn {
                background: #444;
                border: 1px solid #666;
                color: #FFD700;
                padding: 6px 12px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 10px;
                width: 100%;
            }

            .mcs-tr-view-stats-btn:hover {
                background: #555;
            }

            .mcs-tr-loading {
                text-align: center;
                color: #888;
                padding: 20px;
            }

            .mcs-tr-configure-header {
                background: #444;
                padding: 8px;
                margin-bottom: 10px;
                border-radius: 4px;
                text-align: center;
                color: #FFD700;
            }

            .mcs-tr-reset-btn {
                background: #555;
                border: none;
                color: #ddd;
                padding: 4px 8px;
                border-radius: 3px;
                cursor: pointer;
                font-size: 11px;
                margin-left: 8px;
            }

            .mcs-tr-reset-btn:hover {
                background: #666;
            }

            .mcs-tr-visibility-btn {
                border: none;
                padding: 4px 8px;
                border-radius: 3px;
                cursor: pointer;
                font-size: 14px;
                margin-left: auto;
            }

            .mcs-tr-visibility-btn-visible {
                background: #4a6a4a;
                color: #fff;
            }

            .mcs-tr-visibility-btn-hidden {
                background: #555;
                color: #888;
            }

            .mcs-tr-chest-row {
                background: #3a3a3a;
                border-radius: 4px;
                margin-bottom: 8px;
                overflow: hidden;
            }

            .mcs-tr-chest-header {
                display: flex;
                align-items: center;
                padding: 8px;
                gap: 8px;
            }

            .mcs-tr-chest-header-clickable {
                cursor: pointer;
            }

            .mcs-tr-expand-icon {
                font-weight: bold;
                width: 15px;
            }

            .mcs-tr-expand-icon-green {
                color: #4CAF50;
            }

            .mcs-tr-expand-icon-purple {
                color: #9370DB;
            }

            .mcs-tr-chest-name {
                flex: 1;
                font-weight: bold;
            }

            .mcs-tr-chest-ev {
                color: #87CEEB;
                font-weight: normal;
                font-size: 11px;
            }

            .mcs-tr-chest-count {
                color: #888;
                margin-right: 8px;
            }

            .mcs-tr-section-container {
                margin-bottom: 12px;
                border-bottom: 2px solid #555;
                padding-bottom: 10px;
            }

            .mcs-tr-keys-grid {
                display: grid;
                grid-template-columns: repeat(4, 1fr);
                gap: 4px;
            }

            .mcs-tr-key-item {
                display: flex;
                align-items: center;
                gap: 3px;
                padding: 3px;
                background: #3a3a3a;
                border-radius: 3px;
            }

            .mcs-tr-key-details {
                flex: 1;
                min-width: 0;
            }

            .mcs-tr-key-name {
                font-size: 9px;
                color: #aaa;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }

            .mcs-tr-key-price {
                font-size: 10px;
                font-weight: bold;
            }

            .mcs-tr-token-row {
                background: #3a3a3a;
                border-radius: 4px;
                margin-bottom: 6px;
                overflow: hidden;
            }

            .mcs-tr-token-header {
                display: flex;
                align-items: center;
                padding: 6px 8px;
                cursor: pointer;
                gap: 6px;
            }

            .mcs-tr-token-name {
                flex: 1;
                font-weight: bold;
                font-size: 12px;
            }

            .mcs-tr-token-value {
                font-size: 11px;
            }

            .mcs-tr-token-items {
                padding: 6px 8px 8px 30px;
                border-top: 1px solid #555;
                font-size: 11px;
            }

            .mcs-tr-token-item-row {
                display: flex;
                align-items: center;
                gap: 6px;
                margin-bottom: 4px;
            }

            .mcs-tr-best-value {
                background: rgba(76, 175, 80, 0.2);
                border-radius: 3px;
                padding: 2px 4px;
                margin: -2px -4px;
            }

            .mcs-tr-best-badge {
                color: #4CAF50;
                font-size: 9px;
                margin-left: 4px;
            }

            .mcs-tr-token-item-name {
                flex: 1;
            }

            .mcs-tr-token-item-cost {
                color: #888;
                min-width: 50px;
                text-align: right;
            }

            .mcs-tr-token-item-price {
                min-width: 60px;
                text-align: right;
            }

            .mcs-tr-token-item-vpt {
                color: #aaa;
                min-width: 55px;
                text-align: right;
            }

            .mcs-tr-mini-item {
                display: flex;
                align-items: center;
                gap: 3px;
                background: #3a3a3a;
                padding: 3px 6px;
                border-radius: 3px;
            }

            .mcs-tr-no-chests {
                color: #888;
            }

            .mcs-tr-no-loot {
                padding: 10px;
                color: #888;
            }

            .mcs-tr-expanded {
                padding: 10px;
                border-top: 1px solid #555;
            }

            .mcs-tr-col-header {
                font-weight: bold;
                color: #87CEEB;
                margin-bottom: 2px;
                text-align: center;
            }

            .mcs-tr-grid-3col {
                display: grid;
                grid-template-columns: 1fr 1fr 1fr;
                gap: 10px;
                font-size: 11px;
            }

            .mcs-tr-col-value {
                text-align: center;
                margin-bottom: 6px;
                font-size: 10px;
            }

            .mcs-tr-loot-row {
                display: flex;
                align-items: center;
                gap: 4px;
                margin-bottom: 3px;
            }

            .mcs-tr-loot-count {
                min-width: 35px;
            }

            .mcs-tr-loot-value {
                font-size: 10px;
                min-width: 40px;
            }

            .mcs-tr-loot-diff {
                font-size: 10px;
            }

            .mcs-tr-expected-row {
                display: flex;
                align-items: center;
                gap: 3px;
                margin-bottom: 3px;
                font-size: 10px;
            }

            .mcs-tr-expected-count {
                color: #888;
                min-width: 28px;
            }

            .mcs-tr-expected-value {
                min-width: 32px;
            }

            .mcs-tr-expected-sep {
                color: #666;
            }

            .mcs-tr-expected-row-single {
                display: flex;
                align-items: center;
                gap: 4px;
                margin-bottom: 3px;
            }

            .mcs-tr-expected-count-single {
                color: #888;
                min-width: 35px;
            }

            .mcs-tr-expected-value-single {
                font-size: 10px;
            }

            .mcs-data-bridge {
                display: none;
            }

            .ldt-price-toggle-btn,
            .ldt-price-toggle-btn-hidden {
                background-color: rgba(76, 175, 80, 0.3);
                border: 1px solid #4CAF50;
                color: #4CAF50;
                padding: 2px 6px;
                border-radius: 3px;
                cursor: pointer;
                font-size: 11px;
            }

            .ldt-price-toggle-btn-hidden {
                margin-left: 6px;
            }

            .ldt-content-toggle-btn {
                background: rgba(255, 255, 255, 0.1);
                color: white;
                border: 1px solid rgba(255, 255, 255, 0.3);
                border-radius: 4px;
                padding: 2px 8px;
                cursor: pointer;
                font-size: 12px;
                font-weight: bold;
            }

            .ldt-minimize-content-btn {
                margin-left: auto;
            }

            .ldt-body-empty-item {
                font-size: var(--ldt-font-size-small);
                padding: 5px 0;
                color: var(--ldt-text-secondary);
            }

            .ldt-empty-help-text {
                color: var(--ldt-text-secondary);
            }

            .mcs-suite-header {
                grid-column: 1 / -1;
                display: flex;
                justify-content: center;
                align-items: center;
                gap: 8px;
                padding: 6px 8px 2px 8px;
                background: rgba(0, 0, 0, 0.3);
                border-radius: 4px 4px 0 0;
                font-size: 11px;
                text-align: center;
            }

            .mcs-suite-char-mode {
                color: #87CEEB;
                font-weight: 600;
            }

            .mcs-suite-char-name {
                grid-column: 1 / -1;
                margin-bottom: 8px;
                padding: 2px 8px 6px 8px;
                background: rgba(0, 0, 0, 0.3);
                border-radius: 0 0 4px 4px;
                font-size: 11px;
                color: #FFD700;
                text-align: center;
            }

            .mcs-suite-toggle-row {
                grid-column: 1 / -1;
                display: flex;
                justify-content: center;
                align-items: center;
                padding: 6px 0;
                margin-bottom: 6px;
                border-bottom: 1px solid #444;
            }
            .mcs-suite-toggle-label {
                display: flex;
                align-items: center;
                gap: 6px;
                cursor: pointer;
                font-size: 12px;
            }
            .mcs-suite-toggle-text {
                color: #ccc;
            }
            .mcs-suite-refresh-msg {
                color: #f44336;
                font-size: 11px;
                margin-left: 10px;
            }

            .mcs-suite-gm-available {
                color: #4CAF50;
            }

            .mcs-suite-gm-unavailable {
                color: #f44336;
            }

            .mcs-suite-columns {
                display: flex;
                gap: 16px;
            }

            .mcs-suite-col {
                flex: 1;
            }

            .mcs-suite-separator {
                margin: 10px 0;
                border: none;
                border-top: 1px solid #444;
            }

            .mcs-suite-tool-label {
                display: flex;
                align-items: center;
                margin-bottom: 2px;
                cursor: pointer;
                user-select: none;
            }

            .mcs-suite-sub-label {
                display: flex;
                align-items: center;
                margin-bottom: 3px;
                cursor: pointer;
                user-select: none;
                margin-left: 16px;
                font-size: 11px;
            }

            .mcs-suite-checkbox {
                margin-right: 8px;
                cursor: pointer;
            }

            .mcs-suite-tool-name {
                font-size: 13px;
            }

            .mcs-pf-pane {
                position: fixed;
                top: 0;
                left: 0;
                background: #2b2b2b;
                border-radius: 6px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                z-index: 99999;
                font-family: sans-serif;
                resize: both;
                overflow: hidden;
                min-width: 320px;
                min-height: 300px;
            }

            .mcs-pf-header {
                background: #333333;
                color: #eeeeee;
                padding: 8px 12px;
                font-weight: bold;
                cursor: move;
                border-radius: 6px 6px 0 0;
                display: flex;
                justify-content: space-between;
                align-items: center;
                user-select: none;
            }

            .mcs-pf-title-section {
                display: flex;
                align-items: center;
                gap: 8px;
            }

            .mcs-pf-title {
                font-size: 14px;
            }

            .mcs-pf-button-section {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .mcs-pf-btn {
                background: #555;
                color: #fff;
                border: 1px solid #666;
                border-radius: 3px;
                padding: 4px 8px;
                font-size: 14px;
                cursor: pointer;
                line-height: 1;
            }

            .mcs-pf-btn:hover {
                background: #666;
            }

            .mcs-pf-minimize-btn {
                padding: 4px 10px;
            }

            .mcs-pf-content {
                padding: 10px 15px;
                color: #e0e0e0;
                font-size: 12px;
                line-height: 1.6;
                overflow-y: auto;
                overflow-x: hidden;
                height: calc(100% - 40px);
            }

            .mcs-pf-loading {
                color: #999;
            }

            .mcs-pf-header-minimized {
                border-radius: 6px;
            }

            .mcs-pf-summary {
                margin-bottom: 10px;
                padding-bottom: 10px;
                border-bottom: 1px solid #444;
            }

            .mcs-pf-total {
                font-size: 13px;
                font-weight: bold;
                color: #4CAF50;
                margin-bottom: 5px;
            }

            .mcs-pf-items-count {
                font-size: 11px;
                color: #999;
            }

            .mcs-pf-section {
                margin-bottom: 10px;
            }

            .mcs-pf-section-bordered {
                padding-bottom: 10px;
                border-bottom: 1px solid #444;
            }

            .mcs-pf-toggle-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                cursor: pointer;
                padding: 4px;
                border-radius: 3px;
                background: rgba(255,255,255,0.03);
            }

            .mcs-pf-toggle-indicator {
                color: #4CAF50;
                font-weight: bold;
                margin-right: 4px;
            }

            .mcs-pf-cpu-label {
                color: #FF9800;
                font-weight: bold;
            }

            .mcs-pf-io-label {
                color: #2196F3;
                font-weight: bold;
            }

            .mcs-pf-section-subtitle {
                color: #999;
                font-size: 10px;
                margin-left: 4px;
            }

            .mcs-pf-section-details {
                margin-left: 20px;
                margin-top: 5px;
            }

            .mcs-pf-category-label {
                color: #FFA500;
                font-weight: bold;
            }

            .mcs-pf-item-count {
                color: #999;
                font-size: 10px;
                margin-left: 4px;
            }

            .mcs-pf-category-total {
                color: #4CAF50;
                font-weight: bold;
            }

            .mcs-pf-category-percent {
                color: #999;
                font-size: 10px;
            }

            .mcs-pf-category-items {
                margin-left: 20px;
                margin-top: 5px;
                font-size: 10px;
            }

            .mcs-pf-item-row {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 2px 0;
                gap: 8px;
                border-bottom: 1px solid rgba(255,255,255,0.05);
            }

            .mcs-pf-item-key-active {
                color: #4CAF50;
                white-space: nowrap;
            }

            .mcs-pf-item-key-inactive {
                color: #ccc;
                white-space: nowrap;
            }

            .mcs-pf-item-size {
                color: #888;
                white-space: nowrap;
                margin-left: auto;
            }

            .mcs-pf-delete-btn {
                background: #d32f2f;
                color: white;
                border: none;
                border-radius: 3px;
                padding: 2px 6px;
                cursor: pointer;
                font-size: 10px;
                font-weight: bold;
                flex-shrink: 0;
            }

            .mcs-pf-quota-container {
                margin-top: 10px;
                padding-top: 10px;
                border-top: 1px solid #444;
            }

            .mcs-pf-quota-title {
                font-size: 11px;
                color: #999;
                margin-bottom: 5px;
            }

            .mcs-pf-quota-details {
                font-size: 10px;
                color: #ccc;
            }

            .mcs-pf-stat-row {
                display: flex;
                justify-content: space-between;
                padding: 3px 0;
                font-size: 11px;
            }

            .mcs-pf-stat-label {
                color: #ccc;
            }

            .mcs-pf-cpu-percent {
                font-weight: bold;
            }

            .mcs-pf-stat-meta {
                color: #666;
                margin-left: 8px;
                font-size: 9px;
            }

            .mcs-pf-no-activity {
                color: #999;
                font-size: 11px;
            }

            .mcs-pf-ops-count {
                font-weight: bold;
            }

            .mcs-opanel-pane {
                position: fixed;
                top: 0;
                left: 0;
                width: 500px;
                height: 550px;
                background: #1a1a1a;
                border: 1px solid #4a4a4a;
                border-radius: 4px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                z-index: 8000;
                display: flex;
                flex-direction: column;
                overflow: hidden;
                min-width: 10px;
                min-height: 10px;
            }

            .mcs-opanel-icons-bg {
                position: absolute;
                top: 2px;
                right: 2px;
                width: 96px;
                height: 24px;
                background: rgba(0, 0, 0, 0.7);
                border-radius: 3px;
                z-index: 9;
                opacity: 0;
                transition: opacity 0.2s ease;
            }

            .mcs-opanel-icon {
                position: absolute;
                top: 2px;
                background: transparent;
                border: none;
                color: #aaa;
                cursor: pointer;
                font-size: 16px;
                padding: 4px;
                display: flex;
                align-items: center;
                justify-content: center;
                z-index: 10;
                transition: opacity 0.2s ease, color 0.2s ease;
                opacity: 0;
            }

            .mcs-opanel-icon:hover {
                color: #fff;
            }

            .mcs-opanel-computer-icon {
                right: 74px;
            }

            .mcs-opanel-lock-icon {
                right: 50px;
            }

            .mcs-opanel-gear-icon {
                right: 26px;
            }

            .mcs-opanel-drag-handle {
                right: 2px;
                cursor: move;
                user-select: none;
            }

            .mcs-opanel-config-menu {
                display: none;
                position: fixed;
                background: #2a2a2a;
                border: 1px solid #4a4a4a;
                border-radius: 4px;
                padding: 8px;
                z-index: 8001;
                box-shadow: 0 2px 8px rgba(0,0,0,0.5);
            }

            .mcs-opanel-close-btn {
                position: absolute;
                top: 4px;
                right: 4px;
                width: 20px;
                height: 20px;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                color: #aaa;
                font-size: 20px;
                line-height: 1;
                border-radius: 2px;
                user-select: none;
            }

            .mcs-opanel-close-btn:hover {
                background: rgba(255,255,255,0.1);
                color: #fff;
            }

            .mcs-opanel-import-export-panel {
                display: none;
                position: fixed;
                background: #2a2a2a;
                border: 1px solid #4a4a4a;
                border-radius: 4px;
                padding: 4px 8px;
                z-index: 8001;
                box-shadow: 0 2px 8px rgba(0,0,0,0.5);
                align-items: center;
                gap: 6px;
                box-sizing: border-box;
            }

            .mcs-opanel-ie-title {
                color: #aaa;
                font-size: 11px;
                font-weight: bold;
                white-space: nowrap;
            }

            .mcs-opanel-ie-btn {
                padding: 3px 10px;
                background: #3a3a3a;
                border: 1px solid #555;
                border-radius: 3px;
                color: #ddd;
                font-size: 11px;
                cursor: pointer;
                white-space: nowrap;
            }

            .mcs-opanel-ie-btn:hover {
                background: #4a4a4a;
                color: #fff;
            }

            .mcs-opanel-options-container {
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                align-items: center;
                padding-right: 24px;
            }

            .mcs-opanel-checkbox-container {
                display: flex;
                align-items: center;
                gap: 4px;
                background: rgba(255,255,255,0.05);
                padding: 4px 8px;
                border-radius: 3px;
                white-space: nowrap;
            }

            .mcs-opanel-checkbox {
                cursor: pointer;
            }

            .mcs-opanel-label {
                color: #e0e0e0;
                font-size: 10px;
                cursor: pointer;
                user-select: none;
            }

            .mcs-opanel-action-btn-container {
                display: flex;
                align-items: center;
                background: rgba(144,238,144,0.1);
                padding: 4px 8px;
                border-radius: 3px;
            }

            .mcs-opanel-action-btn {
                padding: 4px 12px;
                background: #3a3a3a;
                border: 1px solid #5a5a5a;
                border-radius: 3px;
                color: #90EE90;
                font-size: 10px;
                cursor: pointer;
                font-weight: bold;
            }

            .mcs-opanel-action-btn:hover {
                background: #4a4a4a;
            }

            .mcs-opanel-reset-btn-container {
                display: flex;
                align-items: center;
                background: rgba(255,100,100,0.1);
                padding: 4px 8px;
                border-radius: 3px;
            }

            .mcs-opanel-reset-btn {
                padding: 4px 12px;
                background: #3a3a3a;
                border: 1px solid #5a5a5a;
                border-radius: 3px;
                color: #ff6b6b;
                font-size: 10px;
                cursor: pointer;
                font-weight: bold;
            }

            .mcs-opanel-reset-btn:hover {
                background: #4a4a4a;
            }

            .mcs-opanel-content {
                flex: 1 1 auto;
                padding: 0;
                color: #e0e0e0;
                font-size: 11px;
                overflow: hidden;
                min-height: 0;
                max-height: 100%;
                position: relative;
            }

            .mcs-opanel-content-grid {
                position: relative;
                width: 100%;
                min-height: 1000px;
                height: auto;
            }

            .mcs-opanel-grid-shim {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 1000px;
                pointer-events: none;
                opacity: 0;
                z-index: 0;
            }

            .mcs-opanel-grid-overlay {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 1000px;
                min-height: 1000px;
                background-image:
                    repeating-linear-gradient(0deg, transparent, transparent 9px, rgba(200, 200, 200, 0.3) 9px, rgba(200, 200, 200, 0.3) 10px),
                    repeating-linear-gradient(90deg, transparent, transparent 9px, rgba(200, 200, 200, 0.3) 9px, rgba(200, 200, 200, 0.3) 10px);
                pointer-events: none;
                display: none;
                z-index: 1000;
            }

            .mcs-opanel-spacer-wrapper {
                position: relative;
                width: 0;
                height: 0;
                overflow: visible;
                pointer-events: none;
            }

            .mcs-opanel-spacer-box {
                position: absolute;
                left: 0px;
                width: 100px;
                height: 100px;
                background: transparent;
                border: 1px solid transparent;
                box-sizing: border-box;
                padding: 8px;
                pointer-events: none;
                z-index: 0;
                opacity: 0;
            }

            .mcs-opanel-spacer-content {
                color: #555;
                font-size: 10px;
                line-height: 1;
                white-space: pre;
            }

            .mcs-opanel-height-forcer {
                position: absolute;
                top: 0;
                left: 0;
                height: 1000px;
                width: 1px;
                visibility: hidden;
                pointer-events: none;
            }

            .mcs-opanel-corner-handle {
                position: absolute;
                width: 15px;
                height: 15px;
                z-index: 8001;
            }

            .mcs-opanel-option-box {
                position: absolute;
                background: transparent;
                font-family: Arial, sans-serif;
                box-sizing: border-box;
                resize: none;
                overflow: hidden;
                cursor: move;
                border: 1px solid transparent;
                border-top: 1px solid #4a4a4a;
                z-index: 1;
                display: block;
                visibility: visible;
                transition: background 0.2s, border-color 0.2s;
            }

            .mcs-opanel-box-padded {
                padding: 4px 0 0 0;
            }

            .mcs-opanel-spacer {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                border: 1px solid transparent;
                box-sizing: border-box;
                pointer-events: none;
            }

            .mcs-opanel-widget-wrapper {
                position: absolute;
                top: 4px;
                left: 0;
                right: 0;
                pointer-events: none;
            }

            .mcs-opanel-timer-display {
                color: #ffffff;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
            }

            .mcs-opanel-revenue-display {
                color: #e0e0e0;
                font-size: 10px;
                line-height: 1;
                pointer-events: none;
                overflow: visible;
            }

            .mcs-opanel-consumables-display {
                color: #e0e0e0;
                font-size: 10px;
                line-height: 1;
                pointer-events: auto;
                overflow: visible;
            }

            .mcs-opanel-exp-display {
                color: #90EE90;
                font-size: 11px;
                line-height: 1;
                gap: 4px;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
            }

            .mcs-opanel-profit-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                gap: 4px;
                font-family: Arial, sans-serif;
                pointer-events: none;
                display: flex;
                flex-wrap: wrap;
                align-items: center;
            }

            .mcs-opanel-dps-display {
                color: #e0e0e0;
                font-size: 10px;
                line-height: 1;
                pointer-events: none;
                overflow: visible;
                gap: 4px;
            }

            .mcs-opanel-over-expected-display {
                color: #e0e0e0;
                font-size: 10px;
                line-height: 1;
                gap: 4px;
                pointer-events: none;
                overflow: visible;
            }

            .mcs-opanel-luck-display {
                color: #e0e0e0;
                font-size: 10px;
                line-height: 1;
                gap: 4px;
                pointer-events: none;
                overflow: visible;
            }

            .mcs-opanel-deaths-display {
                color: #FFA07A;
                font-size: 11px;
                line-height: 1;
                gap: 4px;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
            }

            .mcs-opanel-houses-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                display: flex;
                flex-wrap: wrap;
                align-items: center;
                gap: 4px;
            }

            .mcs-opanel-ewatch-display {
                color: #e0e0e0;
                font-size: 10px;
                line-height: 1;
                gap: 4px;
                pointer-events: none;
            }

            .mcs-opanel-combat-status-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                font-weight: bold;
                gap: 4px;
            }

            .mcs-opanel-ntally-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-opanel-build-score-display {
                color: #FFD700;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                font-weight: bold;
            }

            .mcs-opanel-net-worth-display {
                color: #4CAF50;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                font-weight: bold;
            }

            .mcs-opanel-coins-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-opanel-market-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-opanel-skill-books-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-opanel-treasure-display {
                color: #e0e0e0;
                font-size: 11px;
                line-height: 1;
                font-family: Arial, sans-serif;
                pointer-events: none;
                white-space: nowrap;
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .mcs-opanel-box-resize-handle {
                position: absolute;
                bottom: 0;
                right: 0;
                width: 15px;
                height: 15px;
                cursor: se-resize;
                opacity: 0;
                transition: opacity 0.2s;
                z-index: 10;
                pointer-events: all;
            }

            .mcs-opanel-zoom-controls {
                position: absolute;
                bottom: 2px;
                left: 2px;
                display: flex;
                gap: 2px;
                opacity: 0;
                transition: opacity 0.2s;
                z-index: 10;
                pointer-events: all;
            }

            .mcs-opanel-zoom-btn {
                background: #3a3a3a;
                border: 1px solid #555;
                color: #e0e0e0;
                width: 18px;
                height: 18px;
                font-size: 14px;
                cursor: pointer;
                border-radius: 2px;
                display: flex;
                align-items: center;
                justify-content: center;
                padding: 0;
                line-height: 1;
            }

            .mcs-opanel-zoom-btn:hover {
                background: #4a4a4a;
            }

                    `;

                    if (this.cssStyleElement) {
                        this.cssStyleElement.textContent += baseStyles;
                    }
                }

                insertRule(cssText) {
                    try {
                        if (!this.cssStyleSheet) {
                            this.initializeGlobalStyles();
                        }
                        this.cssStyleSheet.insertRule(cssText, this.cssStyleSheet.cssRules.length);
                    } catch (e) {
                        console.error('[CSS] Failed to insert rule:', e);
                    }
                }

                createClass(styles, baseName = 'dynamic') {
                    const styleKey = JSON.stringify(styles);
                    if (this.cssClassMap.has(styleKey)) {
                        return this.cssClassMap.get(styleKey);
                    }

                    const className = `mcs-${baseName}-${this.cssClassCounter++}`;
                    const cssText = this.stylesToCSS(styles, className);

                    this.insertRule(cssText);
                    this.cssClassMap.set(styleKey, className);

                    return className;
                }

                stylesToCSS(styles, className) {
                    const cssProperties = Object.entries(styles)
                        .map(([key, value]) => {
                            const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
                            return `    ${cssKey}: ${value};`;
                        })
                        .join('\n');

                    return `.${className} {\n${cssProperties}\n}`;
                }

                applyClass(element, className) {
                    if (element && className) {
                        element.classList.add(className);
                    }
                }

                applyClasses(element, ...classNames) {
                    if (element) {
                        element.classList.add(...classNames.filter(Boolean));
                    }
                }

                removeAllStyles() {
                    const styleElement = document.getElementById('mcs-global-styles');
                    if (styleElement) {
                        styleElement.remove();
                        this.cssStyleSheet = null;
                        this.cssClassCounter = 0;
                        this.cssClassMap.clear();
                    }
                }

// css end

// IHurt Start

                get ihStorage() {
                    if (!this._ihStorage) {
                        this._ihStorage = createModuleStorage('IH');
                    }
                    return this._ihStorage;
                }

                createIHurtPane() {
                if (document.getElementById('ihurt-pane')) return;
                const pane = document.createElement('div');
                pane.id = 'ihurt-pane';
                registerPanel('ihurt-pane');
                pane.className = 'mcs-pane mcs-ih-pane';
                const header = document.createElement('div');
                header.className = 'mcs-pane-header';
                const titleSection = document.createElement('div');
                titleSection.className = 'mcs-ih-title-section';

                const title = document.createElement('span');
                title.className = 'mcs-pane-title mcs-ih-title';
                title.textContent = 'IHurt';

                const timeDisplay = document.createElement('div');
                timeDisplay.id = 'ihurt-time-display';
                timeDisplay.className = 'mcs-ih-time-display';
                timeDisplay.textContent = '00:00:00';

                const deathsDisplay = document.createElement('div');
                deathsDisplay.id = 'ihurt-deaths-per-hour';
                deathsDisplay.className = 'mcs-ih-deaths-display';
                deathsDisplay.textContent = '0.0 deaths/hr';

                titleSection.appendChild(title);
                titleSection.appendChild(timeDisplay);
                titleSection.appendChild(deathsDisplay);

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'ihurt-minimize-btn';
                minimizeBtn.textContent = '−';
                minimizeBtn.className = 'mcs-btn';
                header.appendChild(titleSection);
                header.appendChild(minimizeBtn);
                const content = document.createElement('div');
                content.id = 'ihurt-content';
                content.className = 'mcs-ih-content';
                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);
                const spyContent = document.getElementById('spy-content');
                if (spyContent && !this._ihWheelListener) {
                    let isScrolling = false;
                    this._ihWheelListener = function (e) {
                        if (isScrolling) return;
                        e.preventDefault();
                        e.stopPropagation();
                        const scrollAmount = e.deltaY / 3;
                        isScrolling = true;
                        spyContent.scrollTop += scrollAmount;
                        setTimeout(() => {
                            isScrolling = false;
                        }, 10);
                    };
                    spyContent.addEventListener('wheel', this._ihWheelListener, { passive: false });
                }
                const self = this;

                const handleWebSocketMessage = PerformanceMonitor.wrap('IHurt', (event) => {
                    const data = event.detail;

                    if (data?.type === 'battle_updated') {
                        self.handleIHurtBattleUpdate(data);
                        if (self.lastBattleData) {
                            self.lastBattleData.pMap = data.pMap;
                            self.lastBattleData.mMap = data.mMap;
                        }
                    }

                    if (data?.type === 'new_battle') {
                        self.initializeIHurtTracking(data.players, data.monsters);
                        self.lastBattleData = data;
                        if (data.combatStartTime) {
                            self.ihurtTracking.combatStartTime = new Date(data.combatStartTime).getTime() / 1000;
                        }
                        if (data.players) {
                            self.ihurtTracking.serverDeathCounts = data.players.map(p => p.deathCount ?? 0);
                        }
                    }
                });

                window.addEventListener('EquipSpyWebSocketMessage', handleWebSocketMessage);

                if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.lastBattleData) {
                    const battleData = window.lootDropsTrackerInstance.lastBattleData;
                    if (battleData.players && battleData.monsters) {
                        self.initializeIHurtTracking(battleData.players, battleData.monsters);
                    }
                }
                this.ihurtIsMinimized = false;
                minimizeBtn.onclick = () => {
                    this.ihurtIsMinimized = !this.ihurtIsMinimized;
                    if (this.ihurtIsMinimized) {
                        content.style.display = 'none';
                        minimizeBtn.textContent = '+';
                        header.style.borderBottom = 'none';
                        header.style.borderRadius = '8px';
                        this.ihStorage.set('minimized', true);
                    } else {
                        content.style.display = 'block';
                        minimizeBtn.textContent = '−';
                        header.style.borderBottom = '1px solid rgba(255, 255, 255, 0.1)';
                        header.style.borderRadius = '';
                        this.ihStorage.set('minimized', false);
                        setTimeout(() => {
                            const rect = pane.getBoundingClientRect();
                            const winWidth = window.innerWidth;
                            const winHeight = window.innerHeight;
                            let needsAdjustment = false;
                            let newTop = rect.top;
                            let newLeft = rect.left;
                            if (rect.right > winWidth) {
                                newLeft = winWidth - rect.width - 10;
                                needsAdjustment = true;
                            }
                            if (rect.left < 0 || newLeft < 0) {
                                newLeft = 10;
                                needsAdjustment = true;
                            }
                            if (rect.bottom > winHeight) {
                                newTop = winHeight - rect.height - 10;
                                needsAdjustment = true;
                            }
                            if (rect.top < 0 || newTop < 0) {
                                newTop = 10;
                                needsAdjustment = true;
                            }
                            if (needsAdjustment) {
                                pane.style.top = newTop + 'px';
                                pane.style.left = newLeft + 'px';
                                pane.style.right = 'auto';
                                this.ihStorage.set('position', {
                                    top: newTop,
                                    left: newLeft
                                });
                            }
                        }, 50);
                    }
                };
                const savedPos = this.ihStorage.get('position');
                if (savedPos) {
                    pane.style.top = savedPos.top + 'px';
                    pane.style.left = savedPos.left + 'px';
                    pane.style.right = 'auto';
                }
                DragHandler.makeDraggable(pane, header, 'mcs_IH');
                const savedIHurtMinimized = this.ihStorage.get('minimized');
                this.ihurtIsMinimized = savedIHurtMinimized === true || savedIHurtMinimized === 'true';
                if (this.ihurtIsMinimized) {
                    content.style.display = 'none';
                    minimizeBtn.textContent = '+';
                    header.style.borderBottom = 'none';
                    header.style.borderRadius = '8px';
                }
                this.ihurtTracking = {
                    players: [],
                    playerDamageTaken: [],
                    playerHealthRegen: [],
                    enemyDamageToPlayers: new Map(),
                    startTime: null,
                    endTime: null,
                    lastUpdateTime: null,
                    totalDuration: 0,
                    playersHP: [],
                    enemyAttackLog: [],
                    maxLogEntries: 100,
                    expandedEnemies: new Set(),
                    expandedProfiles: new Set(),
                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                };
                this.updateIHurtContent();
            }
                initializeIHurtTracking(players, monsters) {
                if (!this.ihurtTracking.players || this.ihurtTracking.players.length === 0) {
                    this.ihurtTracking.players = players.map(p => p.name);
                    this.ihurtTracking.playerDamageTaken = new Array(players.length).fill(0);
                    this.ihurtTracking.playerHealthRegen = new Array(players.length).fill(0);
                    this.ihurtTracking.playerDeaths = new Array(players.length).fill(0);
                    this.ihurtTracking.enemyDamageToPlayers = new Map();
                    this.ihurtTracking.enemyHitStats = new Map();
                    this.ihurtTracking.damageProfiles = new Map();
                    this.ihurtTracking.startTime = Date.now();
                    this.ihurtTracking.totalDuration = 0;
                    this.ihurtTracking.enemyDamageExpanded = true;
                    this.ihurtTracking.profilesExpanded = true;
                    this.ihurtTracking.expandedEnemies = new Set();
                    this.ihurtTracking.expandedProfiles = new Set();
                    this.ihurtTracking.encounterCount = 0;
                } else {
                    if (this.ihurtTracking.startTime) {
                        this.ihurtTracking.totalDuration = mcsGetElapsedSeconds(
                            this.ihurtTracking.startTime,
                            this.ihurtTracking.endTime,
                            this.ihurtTracking.savedPausedMs,
                            this.ihurtTracking.totalDuration
                        );
                    }
                    this.ihurtTracking.savedPausedMs = window.MCS_TOTAL_PAUSED_MS ?? 0;
                    this.ihurtTracking.startTime = Date.now();
                }
                const profileKey = this.createProfileKey(monsters);
                if (!this.ihurtTracking.damageProfiles.has(profileKey)) {
                    this.ihurtTracking.damageProfiles.set(profileKey, {
                        composition: profileKey,
                        encounters: 0,
                        totalDamage: new Array(players.length).fill(0),
                        minHit: Infinity,
                        maxHit: 0,
                        playerMinHits: new Array(players.length).fill(Infinity),
                        playerMaxHits: new Array(players.length).fill(0)
                    });
                }
                this.ihurtTracking.damageProfiles.get(profileKey).encounters++;
                if (this.ihurtTracking.encounterCount === undefined) this.ihurtTracking.encounterCount = 0;
                this.ihurtTracking.encounterCount++;
                this.ihurtTracking.currentProfile = profileKey;
                monsters.forEach(monster => {
                    const enemyName = monster.name || 'Unknown Enemy';
                    if (!this.ihurtTracking.enemyDamageToPlayers.has(enemyName)) {
                        this.ihurtTracking.enemyDamageToPlayers.set(enemyName, new Array(players.length).fill(0));
                    }
                    if (!this.ihurtTracking.enemyHitStats.has(enemyName)) {
                        this.ihurtTracking.enemyHitStats.set(enemyName, {
                            minHit: Infinity,
                            maxHit: 0,
                            playerMinHits: new Array(players.length).fill(Infinity),
                            playerMaxHits: new Array(players.length).fill(0)
                        });
                    }
                });
                this.ihurtTracking.monsters = monsters;
                this.ihurtTracking.playersHP = undefined;
                this.ihurtTracking.monstersMP = undefined;
                this.ihurtTracking.monstersDmgCounter = undefined;
                this.ihurtTracking.playersDmgCounter = undefined;
                this.ihurtTracking.endTime = null;
                this.ihurtTracking.lastUpdateTime = Date.now();
            }
                createProfileKey(monsters) {
                const enemyCounts = {};
                monsters.forEach(monster => {
                    const name = monster.name || 'Unknown';
                    enemyCounts[name] = (enemyCounts[name] ?? 0) + 1;
                });
                const parts = Object.keys(enemyCounts)
                    .sort()
                    .map(name => {
                        const count = enemyCounts[name];
                        return count > 1 ? `${name} x${count}` : name;
                    });
                return parts.join(' + ');
            }
                handleIHurtBattleUpdate(data) {
                if (!this.ihurtTracking.players || this.ihurtTracking.players.length === 0) {
                    return;
                }
                const pMap = data.pMap;
                const mMap = data.mMap;
                const currentTime = Date.now();
                if (!pMap || !mMap) {
                    return;
                }
                if (!this.ihurtTracking.monstersMP || !this.ihurtTracking.monstersDmgCounter) {
                    this.ihurtTracking.monstersMP = [];
                    this.ihurtTracking.monstersDmgCounter = [];
                    for (const mIndex of Object.keys(mMap)) {
                        this.ihurtTracking.monstersMP[mIndex] = mMap[mIndex].cMP;
                        this.ihurtTracking.monstersDmgCounter[mIndex] = mMap[mIndex].dmgCounter ?? 0;
                    }
                }
                if (!this.ihurtTracking.playersHP || !this.ihurtTracking.playersDmgCounter) {
                    this.ihurtTracking.playersHP = [];
                    this.ihurtTracking.playersDmgCounter = [];
                    for (const pIndex of Object.keys(pMap)) {
                        this.ihurtTracking.playersHP[pIndex] = pMap[pIndex].cHP;
                        this.ihurtTracking.playersDmgCounter[pIndex] = pMap[pIndex].dmgCounter ?? 0;
                    }
                }
                let castMonster = -1;
                Object.keys(mMap).forEach((mIndex) => {
                    const monster = mMap[mIndex];
                    if (!monster) return;
                    const prevMP = this.ihurtTracking.monstersMP[mIndex];
                    if (prevMP !== undefined && monster.cMP < prevMP) {
                        castMonster = mIndex;
                    }
                    this.ihurtTracking.monstersMP[mIndex] = monster.cMP;
                });
                Object.keys(pMap).forEach(pIndex => {
                    const player = pMap[pIndex];
                    if (!player) return;
                    const prevHP = this.ihurtTracking.playersHP[pIndex];
                    if (prevHP === undefined) {
                        this.ihurtTracking.playersHP[pIndex] = player.cHP;
                        return;
                    }
                    const hpDiff = prevHP - player.cHP;
                    if (prevHP > 0 && player.cHP === 0) {
                        if (!this.ihurtTracking.playerDeaths) {
                            this.ihurtTracking.playerDeaths = new Array(this.ihurtTracking.players.length).fill(0);
                        }
                        this.ihurtTracking.playerDeaths[pIndex]++;
                    }
                    let dmgSplat = false;
                    const prevDmgCounter = this.ihurtTracking.playersDmgCounter[pIndex] || 0;
                    const currentDmgCounter = player.dmgCounter ?? 0;
                    if (currentDmgCounter > prevDmgCounter) {
                        dmgSplat = true;
                    }
                    this.ihurtTracking.playersDmgCounter[pIndex] = currentDmgCounter;
                    if (dmgSplat && hpDiff > 0) {
                        if (!this.ihurtTracking.playerDamageTaken[pIndex]) {
                            this.ihurtTracking.playerDamageTaken[pIndex] = 0;
                        }
                        this.ihurtTracking.playerDamageTaken[pIndex] += hpDiff;
                        let monsterName;
                        if (this.ihurtTracking.monsters && this.ihurtTracking.monsters.length > 0) {
                            if (castMonster !== -1 && this.ihurtTracking.monsters[castMonster]) {
                                monsterName = this.ihurtTracking.monsters[castMonster].name || `Monster ${parseInt(castMonster) + 1}`;
                            }
                            else if (this.ihurtTracking.monsters.length === 1) {
                                monsterName = this.ihurtTracking.monsters[0].name || 'Monster 1';
                            }
                            else {
                                let attackingMonster = -1;
                                Object.keys(mMap).forEach((mIndex) => {
                                    const monster = mMap[mIndex];
                                    if (!monster) return;
                                    const prevMonsterDmgCounter = this.ihurtTracking.monstersDmgCounter[mIndex] || 0;
                                    const currentMonsterDmgCounter = monster.dmgCounter ?? 0;
                                    if (currentMonsterDmgCounter > prevMonsterDmgCounter) {
                                        attackingMonster = mIndex;
                                    }
                                    this.ihurtTracking.monstersDmgCounter[mIndex] = currentMonsterDmgCounter;
                                });
                                if (attackingMonster !== -1 && this.ihurtTracking.monsters[attackingMonster]) {
                                    monsterName = this.ihurtTracking.monsters[attackingMonster].name || `Monster ${parseInt(attackingMonster) + 1}`;
                                } else {
                                    monsterName = 'Unknown Enemy';
                                }
                            }
                            if (monsterName) {
                                if (!this.ihurtTracking.enemyDamageToPlayers.has(monsterName)) {
                                    this.ihurtTracking.enemyDamageToPlayers.set(monsterName, new Array(this.ihurtTracking.players.length).fill(0));
                                }
                                const damages = this.ihurtTracking.enemyDamageToPlayers.get(monsterName);
                                if (damages && damages[pIndex] !== undefined) {
                                    damages[pIndex] = (damages[pIndex] ?? 0) + hpDiff;
                                }
                                if (!this.ihurtTracking.enemyHitStats.has(monsterName)) {
                                    this.ihurtTracking.enemyHitStats.set(monsterName, {
                                        minHit: Infinity,
                                        maxHit: 0,
                                        playerMinHits: new Array(this.ihurtTracking.players.length).fill(Infinity),
                                        playerMaxHits: new Array(this.ihurtTracking.players.length).fill(0)
                                    });
                                }
                                const hitStats = this.ihurtTracking.enemyHitStats.get(monsterName);
                                hitStats.minHit = Math.min(hitStats.minHit, hpDiff);
                                hitStats.maxHit = Math.max(hitStats.maxHit, hpDiff);
                                hitStats.playerMinHits[pIndex] = Math.min(hitStats.playerMinHits[pIndex], hpDiff);
                                hitStats.playerMaxHits[pIndex] = Math.max(hitStats.playerMaxHits[pIndex], hpDiff);
                                if (this.ihurtTracking.currentProfile && this.ihurtTracking.damageProfiles.has(this.ihurtTracking.currentProfile)) {
                                    const profile = this.ihurtTracking.damageProfiles.get(this.ihurtTracking.currentProfile);
                                    profile.totalDamage[pIndex] = (profile.totalDamage[pIndex] ?? 0) + hpDiff;
                                    profile.minHit = Math.min(profile.minHit, hpDiff);
                                    profile.maxHit = Math.max(profile.maxHit, hpDiff);
                                    profile.playerMinHits[pIndex] = Math.min(profile.playerMinHits[pIndex], hpDiff);
                                    profile.playerMaxHits[pIndex] = Math.max(profile.playerMaxHits[pIndex], hpDiff);
                                }
                                let attackingMonsterIndex = castMonster;
                                if (attackingMonsterIndex === -1) {
                                    Object.keys(mMap).forEach((mIndex) => {
                                        const monster = mMap[mIndex];
                                        if (!monster) return;
                                        const prevDmg = this.ihurtTracking.monstersDmgCounter[mIndex] || 0;
                                        if ((monster.dmgCounter ?? 0) > prevDmg) {
                                            attackingMonsterIndex = mIndex;
                                        }
                                    });
                                }
                                let abilityName = 'Unknown';
                                if (attackingMonsterIndex !== -1 && mMap[attackingMonsterIndex]) {
                                    const monsterData = mMap[attackingMonsterIndex];
                                    if (monsterData.preparingAbilityHrid) {
                                        abilityName = monsterData.preparingAbilityHrid.split('/').pop().replace(/_/g, ' ');
                                    } else if (monsterData.isPreparingAutoAttack) {
                                        abilityName = 'Auto Attack';
                                    }
                                }
                                const playerName = this.ihurtTracking.players[pIndex] || `Player ${parseInt(pIndex) + 1}`;
                                const isMiss = hpDiff === 0;
                                this.addIHurtAttackEntry(monsterName, playerName, abilityName, hpDiff, false, isMiss);
                            }
                        }
                    }
                    if (hpDiff < 0) {
                        if (!this.ihurtTracking.playerHealthRegen[pIndex]) {
                            this.ihurtTracking.playerHealthRegen[pIndex] = 0;
                        }
                        this.ihurtTracking.playerHealthRegen[pIndex] += Math.abs(hpDiff);
                    }
                    this.ihurtTracking.playersHP[pIndex] = player.cHP;
                });
                this.ihurtTracking.endTime = currentTime;
                this.ihurtTracking.lastUpdateTime = currentTime;
                this.updateIHurtContent();
            }
                addIHurtAttackEntry(enemyName, playerName, abilityName, damage, isCrit, isMiss) {
                const timestamp = new Date().toLocaleTimeString();
                this.ihurtTracking.enemyAttackLog.push({
                    timestamp,
                    enemyName,
                    playerName,
                    abilityName,
                    damage,
                    isCrit,
                    isMiss
                });
                if (this.ihurtTracking.enemyAttackLog.length > this.ihurtTracking.maxLogEntries) {
                    this.ihurtTracking.enemyAttackLog.shift();
                }
                this.updateIHurtContent();
            }
                updateIHurtContent() {
                const content = document.getElementById('ihurt-content');
                if (!content) return;
                const tracking = this.ihurtTracking;
                if (!tracking.players || tracking.players.length === 0) {
        content.innerHTML = `<div class="mcs-ih-waiting">
<div class="mcs-ih-waiting-icon">⏳</div>
<div>Waiting for combat data</div>
<div class="mcs-ih-waiting-sub">IHurt will begin tracking shortly </div>
                    </div>`;
                    return;
                }
                let elapsedSeconds = tracking.startTime
                    ? mcsGetElapsedSeconds(tracking.startTime, tracking.endTime, tracking.savedPausedMs, tracking.totalDuration || 0)
                    : (tracking.totalDuration || 0);
                if (elapsedSeconds === 0) elapsedSeconds = 1;
                const elapsedHours = elapsedSeconds / 3600;
                let totalPartyDeaths = 0;
                if (tracking.playerDeaths) {
                    totalPartyDeaths = tracking.playerDeaths.reduce((sum, deaths) => sum + deaths, 0);
                }

                const timeDisplay = document.getElementById('ihurt-time-display');
                if (timeDisplay) {
                    const timeStr = mcsFormatDuration(elapsedSeconds, 'clock');

                    if (timeDisplay.textContent !== timeStr) {
                        timeDisplay.textContent = timeStr;
                    }
                }

                const headerServerDuration = tracking.combatStartTime ? (Date.now() / 1000 - tracking.combatStartTime) : 0;
                const headerServerDeaths = (tracking.serverDeathCounts ?? []).reduce((s, d) => s + d, 0);
                const headerDph = headerServerDuration > 0 ? (3600 * headerServerDeaths / headerServerDuration).toFixed(1) : '0.0';
                const deathsPerHourSpan = document.getElementById('ihurt-deaths-per-hour');
                if (deathsPerHourSpan) {
                    const deathsText = `${headerDph} deaths/hr`;
                    if (deathsPerHourSpan.textContent !== deathsText) {
                        deathsPerHourSpan.textContent = deathsText;
                    }
                }
                let html = '';
                html += `<div class="mcs-ih-main">`;
                const deathParts = tracking.players.map((name, i) => {
                    const d = tracking.playerDeaths ? (tracking.playerDeaths[i] ?? 0) : 0;
                    return `<span class="mcs-ih-player-name">${name}:</span> <span class="mcs-ih-death-count">${d}</span>`;
                });
                html += `<div class="mcs-ih-deaths-row">`;
                html += `<span class="mcs-ih-deaths-label">Session Deaths:</span>`;
                html += deathParts.join(`<span class="mcs-ih-separator"> | </span>`);
                html += `<span class="mcs-ih-separator"> | </span><span class="mcs-ih-total-label">Total:</span> <span class="mcs-ih-death-count">${totalPartyDeaths}</span>`;
                html += `</div>`;
                const serverDuration = tracking.combatStartTime ? (Date.now() / 1000 - tracking.combatStartTime) : 0;
                const serverDeathCounts = tracking.serverDeathCounts ?? [];
                let totalServerDeaths = 0;
                serverDeathCounts.forEach(d => { totalServerDeaths += d; });
                const serverTotalDph = serverDuration > 0 ? (3600 * totalServerDeaths / serverDuration).toFixed(1) : '0.0';
                const deathHrParts = tracking.players.map((name, i) => {
                    const d = serverDeathCounts[i] ?? 0;
                    const dhr = serverDuration > 0 ? (3600 * d / serverDuration).toFixed(1) : '0.0';
                    return `<span class="mcs-ih-player-name">${name}:</span> <span class="mcs-ih-dph-value">${dhr}</span>`;
                });
                html += `<div class="mcs-ih-dph-row">`;
                html += `<span class="mcs-ih-deaths-label">Session Deaths/hr:</span>`;
                html += deathHrParts.join(`<span class="mcs-ih-separator"> | </span>`);
                html += `<span class="mcs-ih-separator"> | </span><span class="mcs-ih-total-label">Total:</span> <span class="mcs-ih-dph-total">${serverTotalDph}</span>`;
                html += `</div>`;
                html += `<div class="mcs-ih-player-grid">`;
                tracking.players.forEach((playerName, index) => {
                    const damageTaken = tracking.playerDamageTaken[index] ?? 0;
                    const healthRegen = tracking.playerHealthRegen[index] ?? 0;
                    const deaths = tracking.playerDeaths ? (tracking.playerDeaths[index] ?? 0) : 0;
                    const dps = (damageTaken / elapsedSeconds).toFixed(1);
                    const hps = (healthRegen / elapsedSeconds).toFixed(1);
                    const deathsPerHour = elapsedHours > 0 ? (deaths / elapsedHours).toFixed(1) : '0.0';
                    html += `<div class="mcs-ih-player-card">`;
                    html += `<div class="mcs-ih-player-card-name">${playerName}</div>`;
                    html += `<div class="mcs-ih-player-stats">`;
                    html += `<div class="mcs-ih-stat-row">`;
                    html += `<span class="mcs-ih-stat-label">Damage/s:</span>`;
                    html += `<span class="mcs-ih-damage-value">${dps}</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-ih-stat-row">`;
                    html += `<span class="mcs-ih-stat-label">Regen/s:</span>`;
                    html += `<span class="mcs-ih-regen-value">${hps}</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-ih-stat-row mcs-ih-total-section">`;
                    html += `<span class="mcs-ih-total-label-sm">Total dmg:</span>`;
                    html += `<span class="mcs-ih-total-dmg">${this.formatIHurtNumber(damageTaken)}</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-ih-stat-row">`;
                    html += `<span class="mcs-ih-total-label-sm">Total regen:</span>`;
                    html += `<span class="mcs-ih-total-regen">${this.formatIHurtNumber(healthRegen)}</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-ih-death-section">`;
                    html += `<div class="mcs-ih-stat-row">`;
                    html += `<span class="mcs-ih-total-label-sm">Deaths:</span>`;
                    html += `<span class="mcs-ih-death-count-sm">${deaths}</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-ih-stat-row">`;
                    html += `<span class="mcs-ih-total-label-sm">Deaths/hr:</span>`;
                    html += `<span class="mcs-ih-dph-value-sm">${deathsPerHour}</span>`;
                    html += `</div>`;
                    html += `</div>`;
                    html += `</div>`;
                    html += `</div>`;
                });
                html += `</div>`;
                html += `</div>`;
                if (tracking.enemyDamageToPlayers.size > 0) {
                    let totalEnemyDamageDealt = 0;
                    tracking.enemyDamageToPlayers.forEach((damages) => {
                        totalEnemyDamageDealt += damages.reduce((sum, dmg) => sum + dmg, 0);
                    });
                    const isExpanded = tracking.enemyDamageExpanded !== false;
                    html += `<div class="mcs-ih-section">`;
                    html += `<div class="ihurt-enemy-toggle mcs-ih-enemy-toggle">`;
                    html += `<div class="mcs-ih-toggle-left">`;
                    html += `<span class="mcs-ih-toggle-arrow mcs-ih-toggle-arrow-red">${isExpanded ? '▼' : '▶'}</span>`;
                    html += `<span class="mcs-ih-section-label">Enemy Damage to Party:</span>`;
                    html += `</div>`;
                    html += `<span class="mcs-ih-enemy-total">Total: ${this.formatIHurtNumber(totalEnemyDamageDealt)}</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-ih-enemy-grid" style="display: ${isExpanded ? 'grid' : 'none'};">`;
                    const sortedEnemies = Array.from(tracking.enemyDamageToPlayers.entries()).sort((a, b) => {
                        const totalA = a[1].reduce((sum, dmg) => sum + dmg, 0);
                        const totalB = b[1].reduce((sum, dmg) => sum + dmg, 0);
                        return totalB - totalA;
                    });
                    sortedEnemies.forEach(([enemyName, damages]) => {
                        const totalDamage = damages.reduce((sum, dmg) => sum + dmg, 0);
                        const hitStats = tracking.enemyHitStats.get(enemyName);
                        html += `<div class="mcs-ih-enemy-card">`;
                        html += `<div class="mcs-ih-enemy-name">${enemyName}</div>`;
                        html += `<div class="mcs-ih-enemy-total-dmg">Total: ${this.formatIHurtNumber(totalDamage)}</div>`;
                        if (hitStats && hitStats.minHit !== Infinity && hitStats.maxHit > 0) {
                            html += `<div class="mcs-ih-enemy-range">Range: [${hitStats.minHit}-${hitStats.maxHit}]</div>`;
                        }
                        html += `<div class="mcs-ih-enemy-players">`;
                        damages.forEach((dmg, pIndex) => {
                            if (dmg > 0) {
                                const playerName = tracking.players[pIndex] || `Player ${parseInt(pIndex) + 1}`;
                                const playerMinHit = hitStats?.playerMinHits[pIndex];
                                const playerMaxHit = hitStats?.playerMaxHits[pIndex];
                                html += `<div class="mcs-ih-enemy-player-row">`;
                                html += `<span class="mcs-ih-enemy-player-name">${playerName}:</span>`;
                                html += `<span class="mcs-ih-enemy-player-dmg">${this.formatIHurtNumber(dmg)}</span>`;
                                if (playerMinHit !== undefined && playerMaxHit !== undefined && playerMinHit !== Infinity) {
                                    html += `<span class="mcs-ih-enemy-player-range">[${playerMinHit}-${playerMaxHit}]</span>`;
                                }
                                html += `</div>`;
                            }
                        });
                        html += `</div>`;
                        html += `</div>`;
                    });
                    html += `</div>`;
                    html += `</div>`;
                }
                if (tracking.damageProfiles && tracking.damageProfiles.size > 0) {
                    const isExpanded = tracking.profilesExpanded !== false;
                    html += `<div class="mcs-ih-section">`;
                    html += `<div class="ihurt-profiles-toggle mcs-ih-section-toggle">`;
                    html += `<span class="mcs-ih-toggle-arrow mcs-ih-toggle-arrow-gold">${isExpanded ? '▼' : '▶'}</span>`;
                    html += `<span class="mcs-ih-section-label">Damage Profiles (Enemy Group Compositions):</span>`;
                    html += `</div>`;
                    html += `<div style="display: ${isExpanded ? 'block' : 'none'};">`;
                    const sortedProfiles = Array.from(tracking.damageProfiles.entries()).sort((a, b) => {
                        const totalA = a[1].totalDamage.reduce((sum, dmg) => sum + dmg, 0);
                        const totalB = b[1].totalDamage.reduce((sum, dmg) => sum + dmg, 0);
                        const avgA = a[1].encounters > 0 ? (totalA / a[1].encounters) : 0;
                        const avgB = b[1].encounters > 0 ? (totalB / b[1].encounters) : 0;
                        return avgB - avgA;
                    });
                    sortedProfiles.forEach(([profileKey, profile]) => {
                        const totalDamage = profile.totalDamage.reduce((sum, dmg) => sum + dmg, 0);
                        const avgDamagePerEncounter = profile.encounters > 0 ? (totalDamage / profile.encounters) : 0;
                        html += `<div class="mcs-ih-profile-card">`;
                        html += `<div class="mcs-ih-profile-name">${profileKey}</div>`;
                        html += `<div class="mcs-ih-profile-stats">`;
                        html += `Encounters: ${profile.encounters} | Total Damage: ${this.formatIHurtNumber(totalDamage)} | Avg/Encounter: <span style="color:red">${this.formatIHurtNumber(avgDamagePerEncounter)}</span>`;
                        if (profile.minHit !== Infinity && profile.maxHit > 0) {
                            html += ` | Hit Range: [${profile.minHit}-${profile.maxHit}]`;
                        }
                        html += `</div>`;
                        html += `</div>`;
                    });
                    html += `</div>`;
                    html += `</div>`;
                }
                const enemyKillEntries = this.trueDPSTracking?.enemyKills ? Object.entries(this.trueDPSTracking.enemyKills) : [];
                if (enemyKillEntries.length > 0) {
                    const encounterKillsExpanded = tracking.encounterKillsExpanded !== false;
                    const battleCount = tracking.encounterCount ?? 0;
                    let totalActualKills = 0;
                    for (const [, e] of enemyKillEntries) { totalActualKills += e.kills; }

                    const expectedKillsPerName = {};
                    try {
                        if (typeof LuckyGameData !== 'undefined' && LuckyGameData.currentMapHrid && typeof LuckyDropAnalyzer !== 'undefined') {
                            const mapData = LuckyGameData.mapData[LuckyGameData.currentMapHrid];
                            if (mapData && mapData.spawnInfo && mapData.spawnInfo.spawns && mapData.spawnInfo.spawns.length > 0) {
                                const expectedSpawns = LuckyDropAnalyzer.computeExpectedSpawns(mapData.spawnInfo);
                                const monsterDetailMap = InitClientDataCache.getCombatMonsterDetailMap();

                                let bossWave = mapData.spawnInfo.bossWave ?? 0;
                                if (!bossWave && mapData.type === 'dungeon') {
                                    bossWave = 1;
                                } else if (!bossWave && mapData.type === 'group' && mapData.bossDrops && Object.keys(mapData.bossDrops).length > 0) {
                                    bossWave = 10;
                                }
                                const bossCount = bossWave ? Math.floor((battleCount - 1) / bossWave) : 0;
                                const normalCount = bossWave ?
                                    bossCount * (bossWave - 1) + (battleCount - 1) % bossWave :
                                    battleCount - 1;

                                for (const [hrid, countPerEncounter] of Object.entries(expectedSpawns)) {
                                    const monsterDetail = monsterDetailMap[hrid];
                                    const name = monsterDetail ? monsterDetail.name : hrid.split('/').pop().replace(/_/g, ' ');
                                    expectedKillsPerName[name] = (expectedKillsPerName[name] ?? 0) + countPerEncounter * normalCount;
                                }

                                if (mapData.bossDrops && bossCount > 0) {
                                    for (const bossHrid of Object.keys(mapData.bossDrops)) {
                                        if (bossHrid === '_dungeon') continue;
                                        const monsterDetail = monsterDetailMap[bossHrid];
                                        const name = monsterDetail ? monsterDetail.name : bossHrid.split('/').pop().replace(/_/g, ' ');
                                        expectedKillsPerName[name] = (expectedKillsPerName[name] ?? 0) + bossCount;
                                    }
                                }
                            }
                        }
                    } catch (e) { /* silently ignore if Lucky not available */ }

                    let totalExpectedKills = 0;
                    Object.values(expectedKillsPerName).forEach(v => { totalExpectedKills += v; });
                    const hasExpected = totalExpectedKills > 0;

                    html += `<div class="mcs-ih-section">`;
                    html += `<div class="ihurt-encounters-toggle mcs-ih-enemy-toggle">`;
                    html += `<div class="mcs-ih-toggle-left">`;
                    html += `<span class="mcs-ih-toggle-arrow mcs-ih-toggle-arrow-blue">${encounterKillsExpanded ? '▼' : '▶'}</span>`;
                    html += `<span class="mcs-ih-section-label">Encounters & Kills:</span>`;
                    html += `</div>`;
                    html += `<span class="mcs-ih-encounters-total">Encounters: ${battleCount} | Kills: ${totalActualKills}</span>`;
                    html += `</div>`;
                    html += `<div style="display: ${encounterKillsExpanded ? 'block' : 'none'};">`;
                    const sortedKills = enemyKillEntries.sort((a, b) => b[1].kills - a[1].kills);
                    html += `<div class="mcs-ih-kills-grid">`;
                    sortedKills.forEach(([enemyName, data]) => {
                        const expected = expectedKillsPerName[enemyName] ?? 0;
                        const diffColor = data.kills >= expected ? '#4CAF50' : '#F44336';
                        const percentDiff = expected > 0 ? (((data.kills - expected) / expected) * 100).toFixed(1) : '';
                        const percentStr = percentDiff !== '' ? ` (${data.kills >= expected ? '+' : ''}${percentDiff}%)` : '';
                        html += `<div class="mcs-ih-kill-card">`;
                        html += `<div class="mcs-ih-kill-name">${enemyName}</div>`;
                        html += `<div class="mcs-ih-kill-stats">`;
                        html += `<span class="mcs-ih-kill-actual">Actual: <span style="font-weight: bold;">${data.kills}</span></span>`;
                        if (hasExpected) {
                            html += `<span class="mcs-ih-kill-expected">Expected: ${expected.toFixed(1)}</span>`;
                            html += `<span style="color: ${diffColor}; font-weight: bold;">${percentStr}</span>`;
                        }
                        html += `</div>`;
                        html += `</div>`;
                    });
                    if (hasExpected) {
                        for (const [name, expected] of Object.entries(expectedKillsPerName)) {
                            if (!this.trueDPSTracking.enemyKills[name] && expected > 0) {
                                html += `<div class="mcs-ih-kill-card-dim">`;
                                html += `<div class="mcs-ih-kill-name">${name}</div>`;
                                html += `<div class="mcs-ih-kill-stats">`;
                                html += `<span class="mcs-ih-kill-actual">Actual: <span style="font-weight: bold;">0</span></span>`;
                                html += `<span class="mcs-ih-kill-expected">Expected: ${expected.toFixed(1)}</span>`;
                                html += `<span style="color: #F44336; font-weight: bold;">(-100.0%)</span>`;
                                html += `</div>`;
                                html += `</div>`;
                            }
                        }
                    }
                    html += `</div>`;
                    html += `</div>`;
                    html += `</div>`;
                }
                content.innerHTML = html;
                const enemyToggle = content.querySelector('.ihurt-enemy-toggle');
                if (enemyToggle) {
                    enemyToggle.addEventListener('click', () => {
                        this.ihurtTracking.enemyDamageExpanded = !this.ihurtTracking.enemyDamageExpanded;
                        this.updateIHurtContent();
                    });
                }
                const profilesToggle = content.querySelector('.ihurt-profiles-toggle');
                if (profilesToggle) {
                    profilesToggle.addEventListener('click', () => {
                        this.ihurtTracking.profilesExpanded = !this.ihurtTracking.profilesExpanded;
                        this.updateIHurtContent();
                    });
                }
                const encountersToggle = content.querySelector('.ihurt-encounters-toggle');
                if (encountersToggle) {
                    encountersToggle.addEventListener('click', () => {
                        this.ihurtTracking.encounterKillsExpanded = !this.ihurtTracking.encounterKillsExpanded;
                        this.updateIHurtContent();
                    });
                }
            }
                toggleIHurtEnemySection() {
                if (!this.ihurtTracking.expandedEnemies) {
                    this.ihurtTracking.expandedEnemies = new Set();
                }
                if (this.ihurtTracking.expandedEnemies.has('enemy-damage')) {
                    this.ihurtTracking.expandedEnemies.delete('enemy-damage');
                } else {
                    this.ihurtTracking.expandedEnemies.add('enemy-damage');
                }
                this.updateIHurtContent();
            }
                toggleIHurtProfilesSection() {
                if (!this.ihurtTracking.expandedProfiles) {
                    this.ihurtTracking.expandedProfiles = new Set();
                }
                if (this.ihurtTracking.expandedProfiles.has('damage-profiles')) {
                    this.ihurtTracking.expandedProfiles.delete('damage-profiles');
                } else {
                    this.ihurtTracking.expandedProfiles.add('damage-profiles');
                }
                this.updateIHurtContent();
            }
                formatIHurtNumber(num) {
                return mcsFormatCurrency(num, 'ihurt');
            }

// IHurt End

                        get gwStorage() {
                            if (!this._gwStorage) {
                                this._gwStorage = createModuleStorage('GW');
                            }
                            return this._gwStorage;
                        }

                        gwhizHandleCombatEnded() {
                            this.gwhizExpTracking = {};
                            this.updateGWhizExperience();
                        }

                        gwhizHandleWebSocketMessage(event) {
                            if (window.MCS_MODULES_DISABLED) return;
                            const data = event.detail;
                            if (data?.type === 'action_completed' && data.endCharacterSkills) {
                                for (const skill of data.endCharacterSkills) {
                                    this.gwhizCurrentStatExp[skill.skillHrid] = {
                                        level: skill.level,
                                        experience: skill.experience,
                                        skillHrid: skill.skillHrid
                                    };
                                }
                                try {
                                    const charData = CharacterDataStorage.get();
                                    if (charData) {
                                        if (charData.characterSkills) {
                                            for (const skill of data.endCharacterSkills) {
                                                const existingSkill = charData.characterSkills.find(s => s.skillHrid === skill.skillHrid);
                                                if (existingSkill) {
                                                    existingSkill.level = skill.level;
                                                    existingSkill.experience = skill.experience;
                                                }
                                            }
                                            CharacterDataStorage.set(charData);
                                        }
                                    }
                                } catch (e) {
                                    console.error('[GWhiz] Failed to update localStorage:', e);
                                }
                                setTimeout(() => this.updateGWhizExperience(), 100);
                            }
                            if (data?.type === 'init_character_data' && data.characterSkills) {
                                this.gwhizExpTracking = {};
                                for (const skill of data.characterSkills) {
                                    this.gwhizCurrentStatExp[skill.skillHrid] = {
                                        level: skill.level,
                                        experience: skill.experience,
                                        skillHrid: skill.skillHrid
                                    };
                                }
                                setTimeout(() => this.updateGWhizExperience(), 100);
                            }
                            if (data?.type === 'new_battle') {
                                if (data.combatStartTime) {
                                    this.gwhizCombatStartTime = new Date(data.combatStartTime).getTime();
                                }
                                const playerData = data.players?.[0];
                                if (playerData?.totalSkillExperienceMap && typeof playerData.totalSkillExperienceMap === 'object') {
                                    this.gwhizSessionExpMap = { ...playerData.totalSkillExperienceMap };
                                    this.gwhizSessionExpSnapshot = {};
                                    for (const skillHrid in this.gwhizCurrentStatExp) {
                                        this.gwhizSessionExpSnapshot[skillHrid] = this.gwhizCurrentStatExp[skillHrid].experience;
                                    }
                                }
                            }
                            if (data?.characterSkills && data.type !== 'init_character_data' && data.type !== 'action_completed') {
                                for (const skill of data.characterSkills) {
                                    this.gwhizCurrentStatExp[skill.skillHrid] = {
                                        level: skill.level,
                                        experience: skill.experience,
                                        skillHrid: skill.skillHrid
                                    };
                                }
                                setTimeout(() => this.updateGWhizExperience(), 100);
                            }
                        }

                        createGWhizPane() {
                            if (document.getElementById('gwhiz-pane')) return;
                            const pane = document.createElement('div');
                            pane.id = 'gwhiz-pane';
                            registerPanel('gwhiz-pane');
                            pane.className = 'mcs-pane mcs-gw-pane';
                            const header = document.createElement('div');
                            header.className = 'mcs-pane-header';
                            const leftSection = document.createElement('div');
                            leftSection.className = 'mcs-gw-left-section';
                            const titleSpan = document.createElement('span');
                            titleSpan.className = 'mcs-pane-title';
                            titleSpan.textContent = 'GWhiz';
                            const totalExpSpan = document.createElement('span');
                            totalExpSpan.id = 'gwhiz-total-exp-hr';
                            totalExpSpan.className = 'mcs-gw-total-exp';
                            totalExpSpan.textContent = '0 exp/hr';
                            leftSection.appendChild(titleSpan);
                            leftSection.appendChild(totalExpSpan);
                            const buttonSection = document.createElement('div');
                            buttonSection.className = 'mcs-button-section';
                            const minimizeBtn = document.createElement('button');
                            minimizeBtn.id = 'gwhiz-minimize-btn';
                            minimizeBtn.textContent = '−';
                            minimizeBtn.className = 'mcs-btn';
                            const resetBtn = document.createElement('button');
                            resetBtn.id = 'gwhiz-reset-btn';
                            resetBtn.textContent = 'Reset';
                            resetBtn.className = 'mcs-btn mcs-gw-reset-btn';
                            buttonSection.appendChild(resetBtn);
                            buttonSection.appendChild(minimizeBtn);
                            header.appendChild(leftSection);
                            header.appendChild(buttonSection);
                            const content = document.createElement('div');
                            content.id = 'gwhiz-content';
                            content.className = 'mcs-pane-content mcs-gw-content';
                            pane.appendChild(header);
                            pane.appendChild(content);
                            document.body.appendChild(pane);
                            this.makeGWhizDraggable(pane, header);
                            this.gwhizExpTracking = {};
                            this.gwhizCurrentStatExp = {};
                            this.gwhizCombatStartTime = this.gwhizCombatStartTime || null;
                            this.gwhizSessionExpMap = this.gwhizSessionExpMap || null;
                            this.gwhizSessionExpSnapshot = this.gwhizSessionExpSnapshot || {};
                            this.gwhizLastCombatLevel = 0;
                            this.gwhizCachedLevelExpTable = null;
                            const savedGWhizMinimized = this.gwStorage.get('minimized');
                            this.gwhizIsMinimized = savedGWhizMinimized === true || savedGWhizMinimized === 'true';
                            if (this.gwhizIsMinimized) {
                                minimizeBtn.textContent = '+';
                                content.style.display = 'none';
                                header.style.borderRadius = '6px';
                            }
                            this.updateGWhizContent();
                            minimizeBtn.onclick = () => {
                                this.gwhizIsMinimized = !this.gwhizIsMinimized;
                                if (this.gwhizIsMinimized) {
                                    content.style.display = 'none';
                                    minimizeBtn.textContent = '+';
                                    header.style.borderRadius = '6px';
                                    this.gwStorage.set('minimized', true);
                                } else {
                                    content.style.display = 'flex';
                                    minimizeBtn.textContent = '−';
                                    header.style.borderRadius = '6px 6px 0 0';
                                    this.gwStorage.set('minimized', false);
                                    this.constrainPanelToBoundaries('gwhiz-pane', 'mcs_GW', true);
                                    this.updateGWhizExperience();
                                }
                            };
                            resetBtn.onclick = () => {
                                this.gwhizExpTracking = {};
                                this.updateGWhizExperience();
                            };
                            this._gwhizCombatEndedListener = this.gwhizHandleCombatEnded.bind(this);
                            this._gwhizWsListener = this.gwhizHandleWebSocketMessage.bind(this);
                            window.addEventListener('LootTrackerCombatEnded', this._gwhizCombatEndedListener);
                            window.addEventListener('EquipSpyWebSocketMessage', this._gwhizWsListener);
                            VisibilityManager.register('gwhiz-update', () => {
                                this.updateGWhizExperience();
                            }, 2000);
                        }

                        updateGWhizContent() {
                            const content = document.getElementById('gwhiz-content');
                            if (!content) return;
                            content.innerHTML = '';

                            const sessionDiv = document.createElement('div');
                            sessionDiv.id = 'gwhiz-session';
                            sessionDiv.className = 'mcs-gw-section mcs-gw-section-mb';
                            const sessionRow = document.createElement('div');
                            sessionRow.className = 'mcs-gw-session-row';
                            const sessionStartLabel = document.createElement('span');
                            sessionStartLabel.id = 'gwhiz-session-start';
                            sessionStartLabel.className = 'mcs-gw-session-val';
                            sessionStartLabel.textContent = '--';
                            const sessionDurLabel = document.createElement('span');
                            sessionDurLabel.id = 'gwhiz-session-duration';
                            sessionDurLabel.className = 'mcs-gw-session-val';
                            sessionDurLabel.textContent = '--';
                            const sessionExpLabel = document.createElement('span');
                            sessionExpLabel.id = 'gwhiz-session-exp';
                            sessionExpLabel.className = 'mcs-gw-session-val';
                            sessionExpLabel.textContent = '--';
                            const sessionRateLabel = document.createElement('span');
                            sessionRateLabel.id = 'gwhiz-session-rate';
                            sessionRateLabel.className = 'mcs-gw-session-val mcs-gw-session-rate';
                            sessionRateLabel.textContent = '--';
                            const mkLabel = (text) => { const s = document.createElement('span'); s.className = 'mcs-gw-session-label'; s.textContent = text; return s; };
                            sessionRow.appendChild(mkLabel('Start: '));
                            sessionRow.appendChild(sessionStartLabel);
                            sessionRow.appendChild(mkLabel('Duration: '));
                            sessionRow.appendChild(sessionDurLabel);
                            sessionRow.appendChild(mkLabel('Exp: '));
                            sessionRow.appendChild(sessionExpLabel);
                            sessionRow.appendChild(mkLabel('Exp/Hr: '));
                            sessionRow.appendChild(sessionRateLabel);
                            sessionDiv.appendChild(sessionRow);
                            content.appendChild(sessionDiv);

                            const combatLevelDiv = document.createElement('div');
                            combatLevelDiv.id = 'gwhiz-combat-level';
                            combatLevelDiv.className = 'mcs-gw-section mcs-gw-section-mb';
                            const combatTopRow = document.createElement('div');
                            combatTopRow.className = 'mcs-gw-top-row';
                            const combatLevelContainer = document.createElement('div');
                            combatLevelContainer.className = 'mcs-gw-level-container';
                            const combatLevelLabel = document.createElement('div');
                            combatLevelLabel.id = 'gwhiz-combat-level-value';
                            combatLevelLabel.className = 'mcs-gw-combat-level-value';
                            combatLevelLabel.textContent = '0.000';
                            combatLevelContainer.appendChild(combatLevelLabel);
                            const combatNameContainer = document.createElement('div');
                            combatNameContainer.className = 'mcs-gw-name-container';
                            const combatNameLabel = document.createElement('div');
                            combatNameLabel.className = 'mcs-gw-name-label';
                            combatNameLabel.textContent = 'Combat!';
                            const flooredEquationRow = document.createElement('div');
                            flooredEquationRow.id = 'gwhiz-floored-equation';
                            flooredEquationRow.className = 'mcs-gw-equation';
                            combatNameContainer.appendChild(combatNameLabel);
                            combatNameContainer.appendChild(flooredEquationRow);
                            const combatExpLabel = document.createElement('div');
                            combatExpLabel.className = 'mcs-gw-exp-label';
                            combatExpLabel.textContent = '';
                            const combatTimeLabel = document.createElement('div');
                            combatTimeLabel.id = 'gwhiz-combat-time-label';
                            combatTimeLabel.className = 'mcs-gw-time-label';
                            combatTimeLabel.textContent = '';
                            combatTopRow.appendChild(combatLevelContainer);
                            combatTopRow.appendChild(combatNameContainer);
                            combatTopRow.appendChild(combatExpLabel);
                            combatTopRow.appendChild(combatTimeLabel);
                            const combatProgressRow = document.createElement('div');
                            combatProgressRow.className = 'mcs-gw-progress-row';
                            const combatProgressContainer = document.createElement('div');
                            combatProgressContainer.className = 'mcs-gw-progress-container';
                            const combatProgressBar = document.createElement('div');
                            combatProgressBar.id = 'gwhiz-combat-progress-bar';
                            combatProgressBar.className = 'mcs-gw-combat-progress-bar';
                            const combatProgressBarProjected = document.createElement('div');
                            combatProgressBarProjected.id = 'gwhiz-combat-progress-bar-projected';
                            combatProgressBarProjected.className = 'mcs-gw-combat-projected';
                            combatProgressContainer.appendChild(combatProgressBar);
                            combatProgressContainer.appendChild(combatProgressBarProjected);
                            for (let i = 10; i <= 90; i += 10) {
                                const tickmark = document.createElement('div');
                                tickmark.className = 'mcs-gw-tickmark';
                                tickmark.style.left = `${i}%`;
                                combatProgressContainer.appendChild(tickmark);
                            }
                            const combatProgressText = document.createElement('div');
                            combatProgressText.id = 'gwhiz-combat-progress-text';
                            combatProgressText.className = 'mcs-gw-combat-progress-text';
                            combatProgressText.textContent = '0%';
                            combatProgressRow.appendChild(combatProgressContainer);
                            combatProgressRow.appendChild(combatProgressText);
                            combatLevelDiv.appendChild(combatTopRow);
                            combatLevelDiv.appendChild(combatProgressRow);
                            content.appendChild(combatLevelDiv);
                            const combatStats = [
                                { name: 'Stamina', key: 'stamina', color: '#FF6B6B' },
                                { name: 'Intelligence', key: 'intelligence', color: '#4ECDC4' },
                                { name: 'Attack', key: 'attack', color: '#FFD93D' },
                                { name: 'Defense', key: 'defense', color: '#95E1D3' },
                                { name: 'Melee', key: 'melee', color: '#a62830' },
                                { name: 'Ranged', key: 'ranged', color: '#259c85' },
                                { name: 'Magic', key: 'magic', color: '#7445b8' }
                            ];
                            combatStats.forEach(stat => {
                                const itemDiv = document.createElement('div');
                                itemDiv.className = 'gwhiz-stat-item mcs-gw-stat-item';
                                itemDiv.setAttribute('data-stat-key', stat.key);
                                const topRow = document.createElement('div');
                                topRow.className = 'mcs-gw-top-row';
                                const levelLabel = document.createElement('div');
                                levelLabel.className = 'gwhiz-level-label';
                                levelLabel.className = 'gwhiz-level-label mcs-gw-stat-level';
                                levelLabel.style.color = stat.color;
                                levelLabel.textContent = '...';
                                const nameLabel = document.createElement('div');
                                nameLabel.className = 'mcs-gw-stat-name';
                                nameLabel.textContent = stat.name;
                                const expLabel = document.createElement('div');
                                expLabel.className = 'gwhiz-exp-label';
                                expLabel.className = 'gwhiz-exp-label mcs-gw-exp-label';
                                expLabel.textContent = '0.0000000000';
                                const timeLabel = document.createElement('div');
                                timeLabel.className = 'gwhiz-time-label';
                                timeLabel.className = 'gwhiz-time-label mcs-gw-time-label';
                                timeLabel.textContent = '';
                                topRow.appendChild(levelLabel);
                                topRow.appendChild(nameLabel);
                                topRow.appendChild(expLabel);
                                topRow.appendChild(timeLabel);
                                const progressRow = document.createElement('div');
                                progressRow.className = 'mcs-gw-progress-row';
                                const progressContainer = document.createElement('div');
                                progressContainer.className = 'mcs-gw-progress-container';
                                const progressBar = document.createElement('div');
                                progressBar.className = 'gwhiz-progress-bar';
                                progressBar.className = 'gwhiz-progress-bar mcs-gw-stat-progress-bar';
                                progressBar.style.background = stat.color;
                                const progressText = document.createElement('div');
                                progressText.className = 'gwhiz-progress-text';
                                progressText.className = 'gwhiz-progress-text mcs-gw-stat-progress-text';
                                progressText.style.color = stat.color;
                                progressText.textContent = '0%';
                                progressContainer.appendChild(progressBar);
                                progressRow.appendChild(progressContainer);
                                progressRow.appendChild(progressText);
                                const rateLabel = document.createElement('div');
                                rateLabel.className = 'gwhiz-rate-label';
                                rateLabel.className = 'gwhiz-rate-label mcs-gw-rate-label';
                                rateLabel.textContent = 'Charms rule!';
                                itemDiv.appendChild(topRow);
                                itemDiv.appendChild(progressRow);
                                itemDiv.appendChild(rateLabel);
                                content.appendChild(itemDiv);
                            });

                            const timeToLevelSection = document.createElement('div');
                            timeToLevelSection.id = 'gwhiz-time-to-level-section';
                            timeToLevelSection.className = 'mcs-gw-section mcs-gw-section-mt';

                            const timeToLevelTitle = document.createElement('div');
                            timeToLevelTitle.className = 'mcs-gw-section-title mcs-gw-ttl-title';

                            const timeToLevelArrow = document.createElement('span');
                            timeToLevelArrow.id = 'gwhiz-ttl-arrow';
                            timeToLevelArrow.textContent = '▼';
                            timeToLevelArrow.className = 'mcs-gw-section-arrow';

                            const timeToLevelText = document.createElement('span');
                            timeToLevelText.textContent = 'Time to Level (given same charm level as current)';

                            timeToLevelTitle.appendChild(timeToLevelArrow);
                            timeToLevelTitle.appendChild(timeToLevelText);

                            const timeToLevelTable = document.createElement('div');
                            timeToLevelTable.id = 'gwhiz-time-to-level-table';
                            timeToLevelTable.className = 'mcs-gw-ttl-table';

                            const headerRow = document.createElement('div');
                            headerRow.className = 'mcs-gw-ttl-header';

                            const skillHeader = document.createElement('div');
                            skillHeader.style.textAlign = 'left';
                            skillHeader.textContent = 'Skill';

                            const currentHeader = document.createElement('div');
                            currentHeader.style.textAlign = 'center';
                            currentHeader.textContent = 'Current';

                            const expHrHeader = document.createElement('div');
                            expHrHeader.style.textAlign = 'center';
                            expHrHeader.textContent = 'Exp/Hr';

                            const targetHeader = document.createElement('div');
                            targetHeader.style.textAlign = 'center';
                            targetHeader.textContent = 'Target';

                            const timeHeader = document.createElement('div');
                            timeHeader.className = 'mcs-gw-ttl-time-header';

                            const timeText = document.createElement('span');
                            timeText.textContent = 'Time';
                            timeText.className = 'mcs-gw-ttl-time-text';

                            const bulwarkContainer = document.createElement('div');
                            bulwarkContainer.className = 'mcs-gw-bulwark-container';

                            const bulwarkCheckbox = document.createElement('input');
                            bulwarkCheckbox.type = 'checkbox';
                            bulwarkCheckbox.id = 'gwhiz-bulwark-checkbox';
                            bulwarkCheckbox.className = 'mcs-gw-bulwark-checkbox';

                            const bulwarkLabel = document.createElement('label');
                            bulwarkLabel.htmlFor = 'gwhiz-bulwark-checkbox';
                            bulwarkLabel.textContent = 'Bulwark';
                            bulwarkLabel.className = 'mcs-gw-bulwark-label';

                            bulwarkContainer.appendChild(bulwarkCheckbox);
                            bulwarkContainer.appendChild(bulwarkLabel);

                            timeHeader.appendChild(timeText);
                            timeHeader.appendChild(bulwarkContainer);

                            headerRow.appendChild(skillHeader);
                            headerRow.appendChild(currentHeader);
                            headerRow.appendChild(expHrHeader);
                            headerRow.appendChild(targetHeader);
                            headerRow.appendChild(timeHeader);

                            timeToLevelTable.appendChild(headerRow);

                            const ttlStats = [
                                { name: 'Stamina', key: 'stamina', color: '#FF6B6B' },
                                { name: 'Intelligence', key: 'intelligence', color: '#4ECDC4' },
                                { name: 'Attack', key: 'attack', color: '#FFD93D' },
                                { name: 'Defense', key: 'defense', color: '#95E1D3' },
                                { name: 'Melee', key: 'melee', color: '#a62830' },
                                { name: 'Ranged', key: 'ranged', color: '#259c85' },
                                { name: 'Magic', key: 'magic', color: '#7445b8' }
                            ];

                            ttlStats.forEach(stat => {
                                const row = document.createElement('div');
                                row.className = 'gwhiz-ttl-row mcs-gw-ttl-row';
                                row.setAttribute('data-stat-key', stat.key);

                                const nameCell = document.createElement('div');
                                nameCell.className = 'mcs-gw-ttl-name';
                                nameCell.style.color = stat.color;
                                nameCell.textContent = stat.name;

                                const currentLevelCell = document.createElement('div');
                                currentLevelCell.className = 'gwhiz-ttl-current mcs-gw-ttl-current';
                                currentLevelCell.textContent = '0';

                                const expHrCell = document.createElement('div');
                                expHrCell.className = 'gwhiz-ttl-exphr mcs-gw-ttl-exphr';
                                expHrCell.textContent = '--';

                                const targetLevelCell = document.createElement('div');
                                targetLevelCell.className = 'mcs-gw-ttl-target-cell';
                                const targetInput = document.createElement('input');
                                targetInput.type = 'number';
                                targetInput.className = 'gwhiz-ttl-target';
                                targetInput.min = '1';
                                targetInput.max = '200';
                                targetInput.value = '1';
                                targetInput.className = 'gwhiz-ttl-target mcs-gw-ttl-input';
                                targetLevelCell.appendChild(targetInput);

                                const timeCell = document.createElement('div');
                                timeCell.className = 'gwhiz-ttl-time mcs-gw-ttl-time';
                                timeCell.textContent = '--';

                                row.appendChild(nameCell);
                                row.appendChild(currentLevelCell);
                                row.appendChild(expHrCell);
                                row.appendChild(targetLevelCell);
                                row.appendChild(timeCell);

                                timeToLevelTable.appendChild(row);

                                targetInput.addEventListener('input', () => {
                                    this.updateTimeToLevel(stat.key);
                                });
                            });

                            timeToLevelSection.appendChild(timeToLevelTitle);
                            timeToLevelSection.appendChild(timeToLevelTable);
                            content.appendChild(timeToLevelSection);

                            const bulwarkEnabled = this.gwStorage.get('bulwark_enabled');
                            bulwarkCheckbox.checked = bulwarkEnabled === true || bulwarkEnabled === 'true';

                            bulwarkCheckbox.addEventListener('change', () => {
                                this.gwStorage.set('bulwark_enabled', bulwarkCheckbox.checked);
                                this.updateTimeToLevelSection();
                            });

                            timeToLevelTitle.addEventListener('click', () => {
                                const isCollapsed = timeToLevelTable.style.display === 'none';
                                timeToLevelTable.style.display = isCollapsed ? 'flex' : 'none';
                                timeToLevelArrow.style.transform = isCollapsed ? 'rotate(0deg)' : 'rotate(-90deg)';
                                this.gwStorage.set('ttl_collapsed', !isCollapsed);
                            });

                            const ttlCollapsed = this.gwStorage.get('ttl_collapsed');
                            if (ttlCollapsed === true || ttlCollapsed === 'true') {
                                timeToLevelTable.style.display = 'none';
                                timeToLevelArrow.style.transform = 'rotate(-90deg)';
                            }

                            const charmsSection = document.createElement('div');
                            charmsSection.id = 'gwhiz-charms-section';
                            charmsSection.className = 'mcs-gw-section mcs-gw-section-mt';
                            const charmsTitle = document.createElement('div');
                            charmsTitle.className = 'mcs-gw-section-title mcs-gw-charms-title';

                            const charmsArrow = document.createElement('span');
                            charmsArrow.id = 'gwhiz-charms-arrow';
                            charmsArrow.textContent = '▼';
                            charmsArrow.className = 'mcs-gw-section-arrow';

                            const charmsText = document.createElement('span');
                            charmsText.textContent = 'Charms rule!';

                            charmsTitle.appendChild(charmsArrow);
                            charmsTitle.appendChild(charmsText);

                            const charmsGrid = document.createElement('div');
                            charmsGrid.id = 'gwhiz-charms-grid';
                            charmsGrid.className = 'mcs-gw-charms-grid';
                            charmsSection.appendChild(charmsTitle);
                            charmsSection.appendChild(charmsGrid);
                            content.appendChild(charmsSection);

                            charmsTitle.addEventListener('click', () => {
                                const isCollapsed = charmsGrid.style.display === 'none';
                                charmsGrid.style.display = isCollapsed ? 'grid' : 'none';
                                charmsArrow.style.transform = isCollapsed ? 'rotate(0deg)' : 'rotate(-90deg)';
                                this.gwStorage.set('charms_collapsed', !isCollapsed);
                            });

                            const charmsCollapsed = this.gwStorage.get('charms_collapsed');
                            if (charmsCollapsed === true || charmsCollapsed === 'true') {
                                charmsGrid.style.display = 'none';
                                charmsArrow.style.transform = 'rotate(-90deg)';
                            }
                            this.updateGWhizExperience();
                        }

                        updateGWhizExperience() {
                            if (this.gwhizIsMinimized) {
                                const currentTime = Date.now();
                                let totalExpPerHour = 0;

                                if (Object.keys(this.gwhizCurrentStatExp).length === 0) {
                                    let characterSkills = null;
                                    try {
                                        const charData = CharacterDataStorage.get();
                                        if (charData) {
                                            characterSkills = charData.characterSkills;
                                        }
                                    } catch (e) {
                                        console.error('[GWhiz] Failed to load character data:', e);
                                    }

                                    if (characterSkills) {
                                        for (const skill of characterSkills) {
                                            this.gwhizCurrentStatExp[skill.skillHrid] = {
                                                level: skill.level,
                                                experience: skill.experience,
                                                skillHrid: skill.skillHrid
                                            };
                                        }
                                    }
                                }

                                const statMapping = {
                                    'stamina': 'stamina',
                                    'intelligence': 'intelligence',
                                    'attack': 'attack',
                                    'defense': 'defense',
                                    'melee': 'melee',
                                    'ranged': 'ranged',
                                    'magic': 'magic'
                                };

                                for (const skillHrid in this.gwhizCurrentStatExp) {
                                    const statData = this.gwhizCurrentStatExp[skillHrid];
                                    let statKey = null;

                                    for (const key in statMapping) {
                                        if (skillHrid.includes(key)) {
                                            statKey = key;
                                            break;
                                        }
                                    }

                                    if (statKey && !this.gwhizExpTracking[statKey]) {
                                        this.gwhizExpTracking[statKey] = {
                                            startExp: statData.experience,
                                            startTime: currentTime,
                                            lastExp: statData.experience,
                                            lastUpdateTime: currentTime,
                                            savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                                            savedTabHiddenMs: window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0
                                        };
                                    }
                                }

                                for (const statKey in this.gwhizExpTracking) {
                                    const tracking = this.gwhizExpTracking[statKey];
                                    if (!tracking) continue;

                                    let currentExp = null;
                                    for (const skillHrid in this.gwhizCurrentStatExp) {
                                        if (skillHrid.includes(statKey)) {
                                            currentExp = this.gwhizCurrentStatExp[skillHrid].experience;
                                            break;
                                        }
                                    }

                                    if (currentExp !== null) {
                                        const expGained = currentExp - tracking.startExp;
                                        const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                                        tracking.lastExp = currentExp;
                                        tracking.lastUpdateTime = currentTime;
                                        if (expGained > 0 && timeElapsed > 0) {
                                            totalExpPerHour += (expGained / timeElapsed) * 3600;
                                        }
                                    }
                                }

                                this.gwhizTotalExpPerHour = totalExpPerHour;

                                const totalExpSpan = document.getElementById('gwhiz-total-exp-hr');
                                if (totalExpSpan) {
                                    if (totalExpPerHour > 0) {
                                        totalExpSpan.textContent = Math.floor(totalExpPerHour).toLocaleString() + ' exp/hr';
                                    } else {
                                        totalExpSpan.textContent = '0 exp/hr';
                                    }
                                }
                                return;
                            }

                            let characterSkills = null;
                            const levelExperienceTable = InitClientDataCache.getLevelExperienceTable();
                            try {
                                const charData = CharacterDataStorage.get();
                                if (charData) {
                                    characterSkills = charData.characterSkills;
                                }
                            } catch (e) {
                                console.error('[GWhiz] Failed to load character data:', e);
                            }
                            if (!characterSkills || !levelExperienceTable) {
                                console.error('[GWhiz] Missing required data - characterSkills:', !!characterSkills, 'levelExperienceTable:', !!levelExperienceTable);
                                return;
                            }
                            if (Object.keys(this.gwhizCurrentStatExp).length > 0) {
                                for (const skill of characterSkills) {
                                    const cached = this.gwhizCurrentStatExp[skill.skillHrid];
                                    if (cached) {
                                        skill.level = cached.level;
                                        skill.experience = cached.experience;
                                    }
                                }
                            }
                            const characterCombatStats = {};
                            for (const skill of characterSkills) {
                                if (skill.skillHrid.includes('stamina')) {
                                    characterCombatStats.stamina = skill;
                                } else if (skill.skillHrid.includes('intelligence')) {
                                    characterCombatStats.intelligence = skill;
                                } else if (skill.skillHrid.includes('attack')) {
                                    characterCombatStats.attack = skill;
                                } else if (skill.skillHrid.includes('defense')) {
                                    characterCombatStats.defense = skill;
                                } else if (skill.skillHrid.includes('melee')) {
                                    characterCombatStats.melee = skill;
                                } else if (skill.skillHrid.includes('ranged')) {
                                    characterCombatStats.ranged = skill;
                                } else if (skill.skillHrid.includes('magic')) {
                                    characterCombatStats.magic = skill;
                                }
                            }
                            const statItems = document.querySelectorAll('.gwhiz-stat-item');
                            const currentTime = Date.now();
                            const levels = {
                                stamina: 0,
                                intelligence: 0,
                                attack: 0,
                                defense: 0,
                                melee: 0,
                                ranged: 0,
                                magic: 0
                            };
                            const levelDecimals = {
                                stamina: 0,
                                intelligence: 0,
                                attack: 0,
                                defense: 0,
                                melee: 0,
                                ranged: 0,
                                magic: 0
                            };
                            const progressPercents = {
                                stamina: 0,
                                intelligence: 0,
                                attack: 0,
                                defense: 0,
                                melee: 0,
                                ranged: 0,
                                magic: 0
                            };
                            const statColors = {
                                stamina: '#FF6B6B',
                                intelligence: '#4ECDC4',
                                attack: '#FFD93D',
                                defense: '#95E1D3',
                                melee: '#a62830',
                                ranged: '#259c85',
                                magic: '#7445b8'
                            };
                            const activelylevelingStats = new Set();
                            let totalExpPerHour = 0;
                            const statExpPerHour = {};
                            const statExpGained = {};
                            const statTimeElapsed = {};

                            statItems.forEach(item => {
                                const statKey = item.getAttribute('data-stat-key');
                                const levelLabel = item.querySelector('.gwhiz-level-label');
                                const expLabel = item.querySelector('.gwhiz-exp-label');
                                const timeLabel = item.querySelector('.gwhiz-time-label');
                                const rateLabel = item.querySelector('.gwhiz-rate-label');
                                const progressBar = item.querySelector('.gwhiz-progress-bar');
                                const progressText = item.querySelector('.gwhiz-progress-text');
                                if (!levelLabel || !expLabel || !timeLabel || !rateLabel || !progressBar || !progressText) {
                                    return;
                                }
                                const statData = characterCombatStats[statKey];
                                if (!statData) {
                                    levelLabel.textContent = '0';
                                    expLabel.textContent = '0.0000000000';
                                    rateLabel.textContent = 'Charms rule!';
                                    timeLabel.textContent = '';
                                    progressBar.style.width = '0%';
                                    progressText.textContent = '0%';
                                    return;
                                }
                                const currentLevel = statData.level;
                                const currentExp = statData.experience;
                                levels[statKey] = currentLevel;
                                try {
                                    const minExpAtLevel = levelExperienceTable[currentLevel];
                                    const maxExpAtLevel = levelExperienceTable[currentLevel + 1];
                                    const expSpanInLevel = maxExpAtLevel - minExpAtLevel;
                                    const expIntoLevel = currentExp - minExpAtLevel;
                                    const expNeeded = maxExpAtLevel - currentExp;
                                    const progressPercent = (expIntoLevel / expSpanInLevel) * 100;
                                    const levelWithDecimal = currentLevel + (progressPercent / 100);
                                    levelDecimals[statKey] = levelWithDecimal;
                                    progressPercents[statKey] = progressPercent;
                                    levelLabel.textContent = currentLevel.toString();
                                    progressBar.style.width = progressPercent.toFixed(2) + '%';
                                    progressText.textContent = (Math.floor(progressPercent * 10) / 10).toFixed(1) + '%';
                                    expLabel.textContent = 'Remaining: ' + Math.ceil(expNeeded);
                                    const trackingKey = statKey;
                                    if (!this.gwhizExpTracking[trackingKey]) {
                                        this.gwhizExpTracking[trackingKey] = {
                                            startExp: currentExp,
                                            startTime: currentTime,
                                            lastExp: currentExp,
                                            lastUpdateTime: currentTime,
                                            savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                                            savedTabHiddenMs: window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0
                                        };
                                        rateLabel.textContent = 'Charms rule!';
                                        timeLabel.textContent = '';
                                         item.style.display = 'flex';
                                    } else {
                                        const tracking = this.gwhizExpTracking[trackingKey];
                                        const expGained = currentExp - tracking.startExp;
                                        const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                                        tracking.lastExp = currentExp;
                                        tracking.lastUpdateTime = currentTime;
                                        if (expGained > 0 && timeElapsed > 0) {
                                            const expPerHour = (expGained / timeElapsed) * 3600;
                                            totalExpPerHour += expPerHour;
                                            statExpPerHour[statKey] = expPerHour;
                                            statExpGained[statKey] = expGained;
                                            statTimeElapsed[statKey] = timeElapsed;
                                            rateLabel.textContent = Math.floor(expPerHour) + '/hr';
                                            activelylevelingStats.add(statKey);
                                            item.style.display = 'flex';
                                            const hoursNeeded = expNeeded / expPerHour;
                                            if (hoursNeeded < 1) {
                                                const minutes = Math.ceil(hoursNeeded * 60);
                                                timeLabel.textContent = minutes + 'm';
                                            } else if (hoursNeeded < 24) {
                                                const hours = Math.floor(hoursNeeded);
                                                const minutes = Math.ceil((hoursNeeded - hours) * 60);
                                                timeLabel.textContent = hours + 'h ' + minutes + 'm';
                                            } else {
                                                const days = Math.floor(hoursNeeded / 24);
                                                const hours = Math.floor(hoursNeeded % 24);
                                                timeLabel.textContent = days + 'd ' + hours + 'h';
                                            }
                                        } else {
                                            rateLabel.textContent = 'Charms rule!';
                                            timeLabel.textContent = '';
                                            item.style.display = 'none';
                                        }
                                    }
                                } catch (error) {
                                    console.error('[GWhiz]', statKey, 'error in calculation:', error);
                                    levelLabel.textContent = currentLevel.toString();
                                    expLabel.textContent = 'Error';
                                    rateLabel.textContent = 'Charms rule!';
                                    timeLabel.textContent = '';
                                    item.style.display = 'none';
                                }
                            });

                            if (totalExpPerHour > 0) {
                                statItems.forEach(item => {
                                    const statKey = item.getAttribute('data-stat-key');
                                    const rateLabel = item.querySelector('.gwhiz-rate-label');
                                    if (!rateLabel) return;

                                    if (statExpPerHour[statKey]) {
                                        const expPerHour = statExpPerHour[statKey];
                                        const percentage = (expPerHour / totalExpPerHour * 100).toFixed(1);
                                        const gained = statExpGained[statKey] || 0;
                                        const elapsed = statTimeElapsed[statKey] || 0;
                                        const mins = Math.floor(elapsed / 60);
                                        const secs = Math.floor(elapsed % 60);
                                        const timeStr = mins > 0 ? mins + 'm ' + secs + 's' : secs + 's';
                                        rateLabel.textContent = Math.floor(expPerHour) + '/hr (' + percentage + '%) Exp: ' + gained.toLocaleString() + ' Time: ' + timeStr;
                                    }
                                });
                            }

                            this.gwhizTotalExpPerHour = totalExpPerHour;

                            const totalExpSpan = document.getElementById('gwhiz-total-exp-hr');
                            if (totalExpSpan) {
                                if (totalExpPerHour > 0) {
                                    totalExpSpan.textContent = Math.floor(totalExpPerHour).toLocaleString() + ' exp/hr';
                                } else {
                                    totalExpSpan.textContent = '0 exp/hr';
                                }
                            }

                            const sessionStartEl = document.getElementById('gwhiz-session-start');
                            const sessionDurEl = document.getElementById('gwhiz-session-duration');
                            const sessionExpEl = document.getElementById('gwhiz-session-exp');
                            const sessionRateEl = document.getElementById('gwhiz-session-rate');
                            if (sessionStartEl && sessionDurEl && sessionExpEl && sessionRateEl) {
                                const combatStart = this.gwhizCombatStartTime;
                                if (combatStart) {
                                    const startDate = new Date(combatStart);
                                    sessionStartEl.textContent = startDate.toLocaleDateString([], { month: 'short', day: 'numeric' }) + ' ' + startDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });

                                    const serverDurMs = Date.now() - combatStart;
                                    const serverDurSec = serverDurMs / 1000;
                                    const durDays = Math.floor(serverDurSec / 86400);
                                    const durHours = Math.floor((serverDurSec % 86400) / 3600);
                                    const durMins = Math.floor((serverDurSec % 3600) / 60);
                                    if (durDays > 0) {
                                        sessionDurEl.textContent = durDays + 'd ' + durHours + 'h ' + durMins + 'm';
                                    } else if (durHours > 0) {
                                        sessionDurEl.textContent = durHours + 'h ' + durMins + 'm';
                                    } else {
                                        sessionDurEl.textContent = durMins + 'm';
                                    }

                                    let totalSessionExp = 0;
                                    const sessionMap = this.gwhizSessionExpMap;
                                    if (sessionMap) {
                                        for (const skillHrid in sessionMap) {
                                            totalSessionExp += sessionMap[skillHrid] || 0;
                                        }
                                        const snapshot = this.gwhizSessionExpSnapshot;
                                        for (const skillHrid in snapshot) {
                                            const currentExp = this.gwhizCurrentStatExp[skillHrid]?.experience;
                                            if (currentExp != null) {
                                                const delta = currentExp - snapshot[skillHrid];
                                                if (delta > 0) totalSessionExp += delta;
                                            }
                                        }
                                    }

                                    sessionExpEl.textContent = Math.floor(totalSessionExp).toLocaleString();

                                    if (serverDurSec > 0 && totalSessionExp > 0) {
                                        const sessionExpPerHour = (totalSessionExp / serverDurSec) * 3600;
                                        sessionRateEl.textContent = Math.floor(sessionExpPerHour).toLocaleString() + '/hr';
                                    } else {
                                        sessionRateEl.textContent = '--';
                                    }
                                } else {
                                    sessionStartEl.textContent = '--';
                                    sessionDurEl.textContent = '--';
                                    sessionExpEl.textContent = '--';
                                    sessionRateEl.textContent = '--';
                                }
                            }

                            const charmsGrid = document.getElementById('gwhiz-charms-grid');
                            if (charmsGrid) {
                                charmsGrid.innerHTML = '';
                                const allStats = ['stamina', 'intelligence', 'attack', 'defense', 'melee', 'ranged', 'magic'];
                                const nonlevelingStats = allStats.filter(stat => !activelylevelingStats.has(stat));
                                nonlevelingStats.forEach(statKey => {
                                    const statData = characterCombatStats[statKey];
                                    if (!statData) return;
                                    const statName = statKey.charAt(0).toUpperCase() + statKey.slice(1);
                                    const statColor = statColors[statKey];
                                    const statItem = document.createElement('div');
                                    statItem.className = 'mcs-gw-charm-item';
                                    const levelSpan = document.createElement('span');
                                    levelSpan.className = 'mcs-gw-charm-level';
                                    levelSpan.style.color = statColor;
                                    levelSpan.textContent = levels[statKey].toString();
                                    const nameSpan = document.createElement('span');
                                    nameSpan.className = 'mcs-gw-charm-name';
                                    nameSpan.textContent = statName;
                                    const percentSpan = document.createElement('span');
                                    percentSpan.className = 'mcs-gw-charm-percent';
                                    percentSpan.textContent = Math.floor(progressPercents[statKey]) + '%';
                                    statItem.appendChild(levelSpan);
                                    statItem.appendChild(nameSpan);
                                    statItem.appendChild(percentSpan);
                                    charmsGrid.appendChild(statItem);
                                });
                            }
                            const maxCombatStyle = Math.max(levels.melee, levels.ranged, levels.magic);
                            const maxOffensiveDefensive = Math.max(levels.attack, levels.defense, levels.melee, levels.ranged, levels.magic);
                            const combatLevel = 0.1 * (levels.stamina + levels.intelligence + levels.attack + levels.defense + maxCombatStyle) +
                                0.5 * maxOffensiveDefensive;
                            const combatLevelValueDiv = document.getElementById('gwhiz-combat-level-value');
                            if (combatLevelValueDiv) {
                                combatLevelValueDiv.textContent = Math.floor(combatLevel).toString();
                            }
                            const flooredEquationDiv = document.getElementById('gwhiz-floored-equation');
                            if (flooredEquationDiv) {
                                const colorSpan = (value, color) => `<span style="color: ${color};">${value}</span>`;
                                const maxStyleName = levels.melee >= levels.ranged && levels.melee >= levels.magic ? 'melee' :
                                    levels.ranged >= levels.magic ? 'ranged' : 'magic';
                                const maxOffDefName = levels.attack >= levels.defense && levels.attack >= levels.melee &&
                                    levels.attack >= levels.ranged && levels.attack >= levels.magic ? 'attack' :
                                    levels.defense >= levels.melee && levels.defense >= levels.ranged &&
                                        levels.defense >= levels.magic ? 'defense' : maxStyleName;
                                const flooredEq = `0.1×(${colorSpan(levels.stamina, statColors.stamina)}+${colorSpan(levels.intelligence, statColors.intelligence)}+${colorSpan(levels.attack, statColors.attack)}+${colorSpan(levels.defense, statColors.defense)}+${colorSpan(levels[maxStyleName], statColors[maxStyleName])})+0.5×${colorSpan(levels[maxOffDefName], statColors[maxOffDefName])}=${colorSpan(combatLevel.toFixed(3), '#ffa500')}`;
                                flooredEquationDiv.innerHTML = flooredEq;
                            }
                            const nextCombatLevel = Math.floor(combatLevel) + 1;
                            const combatProgress = ((combatLevel - Math.floor(combatLevel)) * 100);
                           const combatProgressBar = document.getElementById('gwhiz-combat-progress-bar');
                            const combatProgressText = document.getElementById('gwhiz-combat-progress-text');

                            const oldProjected = document.querySelectorAll('.gwhiz-combat-progress-bar-projected');
                            oldProjected.forEach(bar => bar.remove());

                            let combatMinTimeHours = Infinity;
                            const targetCombatLevel = Math.floor(combatLevel) + 1;
                            const combatLevelGap = targetCombatLevel - combatLevel;
                            const combatLevelFloorChanged = Math.floor(combatLevel) !== Math.floor(this.gwhizLastCombatLevel);

                            this.gwhizLastCombatLevel = combatLevel;

                            const calcExpNeededToLevelNTimes = (statKey, numLevels) => {
                                const statData = characterCombatStats[statKey];
                                if (!statData) return Infinity;

                                const currentLevel = statData.level;
                                const currentExp = statData.experience;

                                let totalExpNeeded = 0;
                                const maxExpAtLevel = levelExperienceTable[currentLevel + 1];
                                totalExpNeeded += maxExpAtLevel - currentExp;

                                for (let i = 1; i < numLevels && currentLevel + i < 199; i++) {
                                    const levelExp = levelExperienceTable[currentLevel + i + 1] - levelExperienceTable[currentLevel + i];
                                    totalExpNeeded += levelExp;
                                }

                                return totalExpNeeded;
                            };

                            if (combatLevelGap > 0.001 && activelylevelingStats.size > 0 && (combatLevelFloorChanged || !this.gwhizCachedCombatStrategy)) {
                                const mainStatKeys = ['melee', 'ranged', 'magic'].filter(k => activelylevelingStats.has(k));
                                const secondaryStatKeys = ['stamina', 'intelligence', 'attack', 'defense'].filter(k => activelylevelingStats.has(k));

                                const mainStatLevelsNeeded = Math.ceil(combatLevelGap / 0.6);
                                const secondaryLevelsAfterMain = Math.ceil(Math.max(0, combatLevelGap - 0.6) / 0.1);
                                const secondaryLevelsOnly = Math.ceil(combatLevelGap / 0.1);

                                let bestStrategy = null;
                                let minExpNeeded = Infinity;

                                if (mainStatKeys.length > 0) {
                                    for (const mainStat of mainStatKeys) {
                                        const expNeeded = calcExpNeededToLevelNTimes(mainStat, mainStatLevelsNeeded);
                                        if (expNeeded < minExpNeeded) {
                                            minExpNeeded = expNeeded;
                                            bestStrategy = { type: 1, stat: mainStat, levels: mainStatLevelsNeeded };
                                        }
                                    }
                                }

                                if (mainStatKeys.length > 0 && secondaryStatKeys.length > 0 && secondaryLevelsAfterMain > 0) {
                                    for (const mainStat of mainStatKeys) {
                                        const expNeeded = calcExpNeededToLevelNTimes(mainStat, mainStatLevelsNeeded);

                                        if (expNeeded < minExpNeeded) {
                                            minExpNeeded = expNeeded;
                                            bestStrategy = { type: 2, stat: mainStat, levels: mainStatLevelsNeeded };
                                        }
                                    }
                                }

                                if (secondaryStatKeys.length > 0) {
                                    for (const secStat of secondaryStatKeys) {
                                        const expNeeded = calcExpNeededToLevelNTimes(secStat, secondaryLevelsOnly);
                                        if (expNeeded < minExpNeeded) {
                                            minExpNeeded = expNeeded;
                                            bestStrategy = { type: 3, stat: secStat, levels: secondaryLevelsOnly };
                                        }
                                    }
                                }

                                this.gwhizCachedCombatStrategy = bestStrategy;
                            }

                            if (combatLevelGap > 0.001 && this.gwhizCachedCombatStrategy) {
                                const strategy = this.gwhizCachedCombatStrategy;
                                const tracking = this.gwhizExpTracking[strategy.stat];

                                if (tracking) {
                                    const expGained = tracking.lastExp - tracking.startExp;
                                    const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);

                                    if (expGained > 0 && timeElapsed > 0) {
                                        const expPerHour = (expGained / timeElapsed) * 3600;
                                        const expNeeded = calcExpNeededToLevelNTimes(strategy.stat, strategy.levels);
                                        combatMinTimeHours = expNeeded / expPerHour;
                                    }
                                }
                            }

                            const contributingStats = [];

                            if (combatLevelGap > 0.001 && combatMinTimeHours < Infinity) {
                                for (const statKey of activelylevelingStats) {
                                    const tracking = this.gwhizExpTracking[statKey];
                                    if (!tracking) continue;
                                    const expGained = tracking.lastExp - tracking.startExp;
                                    const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                                    if (expGained <= 0 || timeElapsed <= 0) continue;

                                    const statData = characterCombatStats[statKey];
                                    if (!statData) continue;

                                    let contribution = 0;
                                    if (statKey === 'melee' || statKey === 'ranged' || statKey === 'magic') {
                                        if (levels[statKey] === maxCombatStyle) {
                                            contribution += 0.1;
                                        }
                                    } else {
                                        contribution += 0.1;
                                    }
                                    if ((statKey === 'attack' || statKey === 'defense' || statKey === 'melee' ||
                                        statKey === 'ranged' || statKey === 'magic') &&
                                        levels[statKey] === maxOffensiveDefensive) {
                                        contribution += 0.5;
                                    }

                                    if (contribution === 0) continue;

                                    const currentLevel = statData.level;
                                    const currentExp = statData.experience;
                                    const minExpAtLevel = levelExperienceTable[currentLevel];
                                    const maxExpAtLevel = levelExperienceTable[currentLevel + 1];
                                    const expNeeded = maxExpAtLevel - currentExp;
                                    const expPerHour = (expGained / timeElapsed) * 3600;
                                    const hoursToLevel = expNeeded / expPerHour;

                                    if (hoursToLevel > combatMinTimeHours * 1.01) continue;

                                    const expSpanInLevel = maxExpAtLevel - minExpAtLevel;
                                    const expIntoLevel = currentExp - minExpAtLevel;
                                    const statProgress = (expIntoLevel / expSpanInLevel) * 100;

                                    contributingStats.push({
                                        key: statKey,
                                        contribution: contribution,
                                        progress: statProgress,
                                        hoursToLevel: hoursToLevel
                                    });
                                }
                            }

                            if (combatProgressBar && combatProgressText) {
                                combatProgressBar.style.width = combatProgress.toFixed(2) + '%';

                                if (contributingStats.length > 0) {
                                    const container = combatProgressBar.parentElement;

                                    contributingStats.sort((a, b) => a.hoursToLevel - b.hoursToLevel);

                                    const totalContribution = contributingStats.reduce((sum, s) => sum + s.contribution, 0);

                                    let currentLeft = combatProgress;
                                    let remainingSpace = 100 - combatProgress;

                                    for (const stat of contributingStats) {
                                        const statFullContribution = stat.contribution * 100;
                                        const statSegment = (stat.progress / 100) * statFullContribution;
                                        const segmentWidth = Math.min(statSegment, (stat.progress / 100) * remainingSpace);

                                        remainingSpace -= segmentWidth;

                                        const projectedBar = document.createElement('div');
                                        projectedBar.className = 'gwhiz-combat-progress-bar-projected';
                                        projectedBar.className = 'gwhiz-combat-progress-bar-projected';
                                        projectedBar.style.left = `${currentLeft.toFixed(2)}%`;
                                        projectedBar.style.background = statColors[stat.key] || '#259c85';
                                        projectedBar.style.width = `${segmentWidth.toFixed(2)}%`;
                                        container.appendChild(projectedBar);

                                        currentLeft += segmentWidth;
                                    }

                                    combatProgressText.textContent = (Math.floor(currentLeft * 10) / 10).toFixed(1) + '%';
                                } else {
                                    combatProgressText.textContent = (Math.floor(combatProgress * 10) / 10).toFixed(1) + '%';
                                }
                            }
                            const combatTimeLabel = document.getElementById('gwhiz-combat-time-label');
                            if (combatTimeLabel) {
                                if (combatMinTimeHours < Infinity) {
                                    if (combatMinTimeHours < 1 / 60) {
                                        const seconds = Math.ceil(combatMinTimeHours * 3600);
                                        combatTimeLabel.textContent = seconds + 's';
                                    } else if (combatMinTimeHours < 1) {
                                        const minutes = Math.ceil(combatMinTimeHours * 60);
                                        combatTimeLabel.textContent = minutes + 'm';
                                    } else if (combatMinTimeHours < 24) {
                                        const hours = Math.floor(combatMinTimeHours);
                                        const minutes = Math.ceil((combatMinTimeHours - hours) * 60);
                                        combatTimeLabel.textContent = hours + 'h ' + minutes + 'm';
                                    } else {
                                        const days = Math.floor(combatMinTimeHours / 24);
                                        const hours = Math.floor(combatMinTimeHours % 24);
                                        combatTimeLabel.textContent = days + 'd ' + hours + 'h';
                                    }
                                } else {
                                    combatTimeLabel.textContent = '';
                                }
                            }

                            this.updateTimeToLevelSection();
                        }

                        updateTimeToLevelSection() {
                            const timeToLevelTable = document.getElementById('gwhiz-time-to-level-table');
                            if (!timeToLevelTable || timeToLevelTable.style.display === 'none') {
                                return;
                            }

                            const rows = document.querySelectorAll('.gwhiz-ttl-row');
                            if (!rows || rows.length === 0) return;

                            let characterSkills = null;
                            let levelExperienceTable = null;

                            levelExperienceTable = InitClientDataCache.getLevelExperienceTable();

                            try {
                                const charData = CharacterDataStorage.get();
                                if (charData) {
                                    characterSkills = charData.characterSkills;
                                }
                            } catch (e) {
                                console.error('[GWhiz] Failed to load character data:', e);
                            }

                            if (!characterSkills || !levelExperienceTable) {
                                return;
                            }

                            if (Object.keys(this.gwhizCurrentStatExp).length > 0) {
                                for (const skill of characterSkills) {
                                    const cached = this.gwhizCurrentStatExp[skill.skillHrid];
                                    if (cached) {
                                        skill.level = cached.level;
                                        skill.experience = cached.experience;
                                    }
                                }
                            }

                            const characterCombatStats = {};
                            for (const skill of characterSkills) {
                                if (skill.skillHrid.includes('stamina')) {
                                    characterCombatStats.stamina = skill;
                                } else if (skill.skillHrid.includes('intelligence')) {
                                    characterCombatStats.intelligence = skill;
                                } else if (skill.skillHrid.includes('attack')) {
                                    characterCombatStats.attack = skill;
                                } else if (skill.skillHrid.includes('defense')) {
                                    characterCombatStats.defense = skill;
                                } else if (skill.skillHrid.includes('melee')) {
                                    characterCombatStats.melee = skill;
                                } else if (skill.skillHrid.includes('ranged')) {
                                    characterCombatStats.ranged = skill;
                                } else if (skill.skillHrid.includes('magic')) {
                                    characterCombatStats.magic = skill;
                                }
                            }

                            const currentTime = Date.now();

                            const supportStats = ['stamina', 'intelligence', 'attack', 'defense'];
                            const combatStyles = ['melee', 'ranged', 'magic'];

                            let supportExpPerHour = 0;
                            let supportCount = 0;
                            let combatStyleExpPerHour = 0;
                            let combatStyleCount = 0;

                            for (const statKey of supportStats) {
                                const tracking = this.gwhizExpTracking[statKey];
                                if (tracking) {
                                    const expGained = tracking.lastExp - tracking.startExp;
                                    const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                                    if (expGained > 0 && timeElapsed > 0) {
                                        supportExpPerHour += (expGained / timeElapsed) * 3600;
                                        supportCount++;
                                    }
                                }
                            }

                            for (const statKey of combatStyles) {
                                const tracking = this.gwhizExpTracking[statKey];
                                if (tracking) {
                                    const expGained = tracking.lastExp - tracking.startExp;
                                    const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                                    if (expGained > 0 && timeElapsed > 0) {
                                        combatStyleExpPerHour += (expGained / timeElapsed) * 3600;
                                        combatStyleCount++;
                                    }
                                }
                            }

                            const avgSupportExpPerHour = supportCount > 0 ? supportExpPerHour / supportCount : 0;
                            const avgCombatStyleExpPerHour = combatStyleCount > 0 ? combatStyleExpPerHour / combatStyleCount : 0;

                            const bulwarkCheckbox = document.getElementById('gwhiz-bulwark-checkbox');
                            const isBulwarkEnabled = bulwarkCheckbox ? bulwarkCheckbox.checked : false;

                            const defenseTracking = this.gwhizExpTracking['defense'];
                            const staminaTracking = this.gwhizExpTracking['stamina'];
                            const defenseGaining = defenseTracking && (defenseTracking.lastExp - defenseTracking.startExp) > 0;
                            const staminaGaining = staminaTracking && (staminaTracking.lastExp - staminaTracking.startExp) > 0;
                            const hasDefenseCharm = defenseGaining && !staminaGaining;

                            rows.forEach(row => {
                                const statKey = row.getAttribute('data-stat-key');
                                const currentLevelCell = row.querySelector('.gwhiz-ttl-current');
                                const expHrCell = row.querySelector('.gwhiz-ttl-exphr');
                                const targetInput = row.querySelector('.gwhiz-ttl-target');
                                const timeCell = row.querySelector('.gwhiz-ttl-time');

                                const statData = characterCombatStats[statKey];
                                if (!statData || !currentLevelCell || !expHrCell || !targetInput || !timeCell) return;

                                const currentLevel = statData.level;
                                const currentExp = statData.experience;
                                currentLevelCell.textContent = currentLevel.toString();

                                const minLevel = currentLevel + 1;
                                targetInput.min = minLevel.toString();

                                if (!targetInput.dataset.initialized) {
                                    targetInput.value = minLevel.toString();
                                    targetInput.dataset.initialized = 'true';
                                }

                                let expPerHour = 0;
                                if (statKey === 'defense' && isBulwarkEnabled && hasDefenseCharm) {
                                    expPerHour = supportExpPerHour + combatStyleExpPerHour;
                                } else if (statKey === 'defense' && isBulwarkEnabled) {
                                    expPerHour = avgCombatStyleExpPerHour;
                                } else if (supportStats.includes(statKey)) {
                                    expPerHour = avgSupportExpPerHour;
                                } else if (combatStyles.includes(statKey)) {
                                    expPerHour = avgCombatStyleExpPerHour;
                                }

                                if (expPerHour > 0) {
                                    expHrCell.textContent = Math.floor(expPerHour).toLocaleString();
                                } else {
                                    expHrCell.textContent = '--';
                                }

                                const targetLevel = parseInt(targetInput.value);

                                if (expPerHour <= 0) {
                                    timeCell.textContent = '--';
                                    return;
                                }

                                let targetLevelClamped;
                                if (isNaN(targetLevel) || targetLevel === 0) {
                                    targetLevelClamped = minLevel;
                                } else {
                                    targetLevelClamped = Math.max(minLevel, Math.min(targetLevel, 200));
                                }

                                let totalExpNeeded = 0;

                                const maxExpAtCurrentLevel = levelExperienceTable[currentLevel + 1];
                                const remainingInCurrentLevel = maxExpAtCurrentLevel - currentExp;
                                totalExpNeeded += remainingInCurrentLevel;

                                for (let lvl = currentLevel + 1; lvl < targetLevelClamped; lvl++) {
                                    const expForLevel = levelExperienceTable[lvl + 1] - levelExperienceTable[lvl];
                                    totalExpNeeded += expForLevel;
                                }

                                const hoursNeeded = totalExpNeeded / expPerHour;

                                if (hoursNeeded < 1 / 60) {
                                    const seconds = Math.ceil(hoursNeeded * 3600);
                                    timeCell.textContent = seconds + 's';
                                } else if (hoursNeeded < 1) {
                                    const minutes = Math.ceil(hoursNeeded * 60);
                                    timeCell.textContent = minutes + 'm';
                                } else if (hoursNeeded < 24) {
                                    const hours = Math.floor(hoursNeeded);
                                    const minutes = Math.ceil((hoursNeeded - hours) * 60);
                                    timeCell.textContent = hours + 'h ' + minutes + 'm';
                                } else {
                                    const days = Math.floor(hoursNeeded / 24);
                                    const hours = Math.floor(hoursNeeded % 24);
                                    timeCell.textContent = days + 'd ' + hours + 'h';
                                }
                            });
                        }

                        updateTimeToLevel(statKey) {
                            this.updateTimeToLevelSection();
                        }

                        makeGWhizDraggable(pane, header) {
                            DragHandler.makeDraggable(pane, header, 'mcs_GW');
                        }

                        destroyGWhiz() {
                            VisibilityManager.clear('gwhiz-update');
                            if (this._gwhizCombatEndedListener) { window.removeEventListener('LootTrackerCombatEnded', this._gwhizCombatEndedListener); this._gwhizCombatEndedListener = null; }
                            if (this._gwhizWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._gwhizWsListener); this._gwhizWsListener = null; }
                            const pane = document.getElementById('gwhiz-pane');
                            if (pane) pane.remove();
                        }

// GWhiz End

// AMazing Start

            get amStorage() {
                if (!this._amStorage) {
                    this._amStorage = createModuleStorage('AM');
                }
                return this._amStorage;
            }

            createAMazingPane() {
                if (document.getElementById('amazing-pane')) return;
                const pane = document.createElement('div');
                pane.id = 'amazing-pane';
                registerPanel('amazing-pane');
                this.applyClasses(pane, 'mcs-pane', 'mcs-amazing-pane');

                const header = document.createElement('div');
                this.applyClasses(header, 'mcs-pane-header', 'mcs-gap-15');

                const titleSpan = document.createElement('span');
                this.applyClass(titleSpan, 'mcs-pane-title');
                titleSpan.textContent = 'AMazing';

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'amazing-minimize-btn';
                minimizeBtn.textContent = '−';
                this.applyClasses(minimizeBtn, 'mcs-btn', 'mcs-btn-minimize');

                header.appendChild(titleSpan);
                header.appendChild(minimizeBtn);

                const content = document.createElement('div');
                content.id = 'amazing-content';
                this.applyClasses(content, 'mcs-pane-content', 'mcs-gap-8');
                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);
                this.makeAMazingDraggable(pane, header);
                this.amazingTracking = {};
                this.mwiHideEnabled = false;
                this.updateAMazingContent();
                const savedAmazingMinimized = window.lootDropsTrackerInstance.amStorage.get('minimized') === 'true';
                this.amazingIsMinimized = savedAmazingMinimized;
                if (savedAmazingMinimized) {
                    content.classList.add('mcs-hidden');
                    minimizeBtn.textContent = '+';
                    header.classList.add('minimized');
                }
                minimizeBtn.onclick = () => {
                    this.amazingIsMinimized = !this.amazingIsMinimized;
                    if (this.amazingIsMinimized) {
                        content.classList.add('mcs-hidden');
                        minimizeBtn.textContent = '+';
                        header.classList.add('minimized');
                        window.lootDropsTrackerInstance.amStorage.set('minimized', 'true');
                    } else {
                        content.classList.remove('mcs-hidden');
                        minimizeBtn.textContent = '−';
                        header.classList.remove('minimized');
                        window.lootDropsTrackerInstance.amStorage.set('minimized', 'false');
                        this.constrainPanelToBoundaries('amazing-pane', 'mcs_AM', true);
                    }
                };
            }

            updateAMazingContent() {
                const content = document.getElementById('amazing-content');
                if (!content) return;
                content.innerHTML = '';

                const hideMWIContainer = document.createElement('div');
                this.applyClass(hideMWIContainer, 'mcs-container');

                const buttonRow = document.createElement('div');
                this.applyClasses(buttonRow, 'mcs-row', 'mcs-gap-10');

                const hideMWIBtn = document.createElement('button');
                hideMWIBtn.id = 'amazing-hide-mwi-btn';
                hideMWIBtn.textContent = 'Hide MWI';
                this.applyClass(hideMWIBtn, 'mcs-btn');

                const descriptionText = document.createElement('span');
                this.applyClass(descriptionText, 'mcs-text-description');
                descriptionText.innerHTML = 'Hide everything besides <span class="mcs-text-highlight">MWI Combat Suite</span>';

                buttonRow.appendChild(hideMWIBtn);
                buttonRow.appendChild(descriptionText);
                hideMWIContainer.appendChild(buttonRow);
                content.appendChild(hideMWIContainer);

                hideMWIBtn.onclick = () => {
                    this.toggleMWIHide();
                };
                const farOutContainer = document.createElement('div');
                this.applyClass(farOutContainer, 'mcs-container');

                const farOutButtonRow = document.createElement('div');
                this.applyClasses(farOutButtonRow, 'mcs-row', 'mcs-gap-10');

                const farOutBtn = document.createElement('button');
                farOutBtn.id = 'amazing-far-out-btn';
                farOutBtn.textContent = 'Far Out';
                this.applyClass(farOutBtn, 'mcs-btn');

                const farOutDescriptionText = document.createElement('span');
                this.applyClass(farOutDescriptionText, 'mcs-text-description');
                farOutDescriptionText.textContent = 'This will be useful one day';

                farOutButtonRow.appendChild(farOutBtn);
                farOutButtonRow.appendChild(farOutDescriptionText);
                farOutContainer.appendChild(farOutButtonRow);
                content.appendChild(farOutContainer);

                farOutBtn.onclick = () => {
                    this.farOutRandomizeColors();
                };
            }

            toggleMWIHide() {
                this.mwiHideEnabled = !this.mwiHideEnabled;
                const btn = document.getElementById('amazing-hide-mwi-btn');
                if (this.mwiHideEnabled) {
                    this.applyMWIHide();
                    btn.textContent = 'Show MWI';
                    btn.classList.add('mcs-btn-active');
                } else {
                    this.removeMWIHide();
                    btn.textContent = 'Hide MWI';
                    btn.classList.remove('mcs-btn-active');
                }
            }

            applyMWIHide() {
                const suitePanel = document.getElementById('mwi-combat-suite-panel');
                if (suitePanel && suitePanel.classList.contains('visible')) {
                    suitePanel.classList.remove('visible');
                }
                if (!document.getElementById('mwi-hide-overlay')) {
                    const overlay = document.createElement('div');
                    overlay.id = 'mwi-hide-overlay';
                    this.applyClass(overlay, 'mcs-overlay');
                    document.body.appendChild(overlay);
                }
                const elementsToKeep = [
                    'amazing-pane',
                    'bread-pane',
                    'dps-pane',
                    'consumables-pane',
                    'equipment-spy-pane',
                    'hwhat-pane',
                    'milt-loot-drops-display',
                    'milt-loot-drops-tooltip',
                    'mwi-hide-overlay',
                    'gwhiz-pane',
                    'truedps-pane',
                    'ihurt-pane',
                    'meaters-pane',
                    'mwi-combat-suite-btn',
                    'mwi-combat-suite-panel',
                    'jhouse-pane',
                    'jhouse-status-pane',
                    'opanel-pane',
                    'kollection-pane',
                    'kollection-side-panel',
                    'lucky-panel',
                    'lucky-options-panel',
                    'lucky-stats-panel',
                    'lucky-revenue-panel',
                    'lucky-big-expected-panel',
                    'lucky-big-luck-panel',
                    'lucky-totals-panel',
                    'mana-pane',
                    'mcs_nt_pane',
                    'pformance-pane',
                    'qcharm-pane',
                    'treasure-pane',
                    'treasure-chest-side-panel'
                ];

                if (document.getElementById('mwi-profitwatch-panel')) {
                    elementsToKeep.push('mwi-profitwatch-panel');
                }
                Array.from(document.body.children).forEach(child => {
                    if (!elementsToKeep.includes(child.id)) {
                        if (!child.getAttribute('data-mwi-original-display')) {
                            child.setAttribute('data-mwi-original-display', child.style.display || 'block');
                        }
                        child.style.display = 'none';
                    }
                });
                elementsToKeep.forEach(id => {
                    const panel = document.getElementById(id);
                    if (panel && id !== 'mwi-hide-overlay') {
                        if (!panel.getAttribute('data-mwi-original-zindex')) {
                            panel.setAttribute('data-mwi-original-zindex', panel.style.zIndex || '');
                        }
                        panel.style.zIndex = '100001';
                    }
                });
            }

            removeMWIHide() {
                const overlay = document.getElementById('mwi-hide-overlay');
                if (overlay) {
                    overlay.remove();
                }
                Array.from(document.body.children).forEach(child => {
                    const originalDisplay = child.getAttribute('data-mwi-original-display');
                    if (originalDisplay) {
                        child.style.display = originalDisplay;
                        child.removeAttribute('data-mwi-original-display');
                    }
                    const originalZIndex = child.getAttribute('data-mwi-original-zindex');
                    if (originalZIndex !== null) {
                        child.style.zIndex = originalZIndex;
                        child.removeAttribute('data-mwi-original-zindex');
                    }
                });
            }

            makeAMazingDraggable(pane, header) {
                DragHandler.makeDraggable(pane, header, 'mcs_AM');
            }

            farOutRandomizeColors() {
                const farOutBtn = document.getElementById('amazing-far-out-btn');
                if (this.farOutInterval) {
                    clearInterval(this.farOutInterval);
                    this.farOutInterval = null;
                    farOutBtn.textContent = 'FIX IT';
                    farOutBtn.classList.remove('mcs-btn-warning');
                    farOutBtn.classList.add('mcs-btn-alert');
                    return;
                }
                if (this.farOutSpans && this.farOutSpans.length > 0) {
                    const spans = document.querySelectorAll('.far-out-span');
                    spans.forEach(span => {
                        const textNode = document.createTextNode(span.textContent);
                        span.parentNode.replaceChild(textNode, span);
                    });
                    document.body.normalize();
                    this.farOutSpans = [];
                    farOutBtn.textContent = 'Far Out';
                    farOutBtn.classList.remove('mcs-btn-alert', 'mcs-btn-warning');
                    return;
                }
                this.farOutSpans = [];
                const getRandomColor = () => {
                    const r = Math.floor(Math.random() * 256);
                    const g = Math.floor(Math.random() * 256);
                    const b = Math.floor(Math.random() * 256);
                    return `rgb(${r}, ${g}, ${b})`;
                };
                const isASCII = (char) => {
                    const code = char.charCodeAt(0);
                    return code >= 0 && code <= 127;
                };
                const colorizeText = (node) => {
                    if (node.nodeType === Node.ELEMENT_NODE && node.id === 'amazing-far-out-btn') {
                        return;
                    }
                    if (node.nodeType === Node.ELEMENT_NODE && node.querySelector('#amazing-far-out-btn')) {
                        const children = Array.from(node.childNodes);
                        children.forEach(child => {
                            if (child.nodeType === Node.ELEMENT_NODE) {
                                colorizeText(child);
                            }
                        });
                        return;
                    }
                    if (node.nodeType === Node.TEXT_NODE) {
                        const text = node.textContent;
                        if (!text || text.trim().length === 0) return;
                        let hasASCII = false;
                        for (let char of text) {
                            if (isASCII(char)) {
                                hasASCII = true;
                                break;
                            }
                        }
                        if (!hasASCII) return;
                        const fragment = document.createDocumentFragment();
                        for (let char of text) {
                            if (isASCII(char)) {
                                const span = document.createElement('span');
                                span.textContent = char;
                                span.style.color = getRandomColor();
                                span.classList.add('far-out-span');
                                this.farOutSpans.push(span);
                                fragment.appendChild(span);
                            } else {
                                fragment.appendChild(document.createTextNode(char));
                            }
                        }
                        node.parentNode.replaceChild(fragment, node);
                    } else if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE' ||
                            node.tagName === 'INPUT' || node.tagName === 'TEXTAREA') {
                            return;
                        }
                        const children = Array.from(node.childNodes);
                        children.forEach(child => colorizeText(child));
                    }
                };
                try {
                    colorizeText(document.body);
                    farOutBtn.textContent = 'MAKE IT STOP';
                    farOutBtn.classList.add('mcs-btn-warning');
                    VisibilityManager.register('amazing-farout', () => {
                        this.farOutSpans.forEach(span => {
                            span.style.color = getRandomColor();
                        });
                    }, 100);
                } catch (e) {
                    console.error('[AMazing] Far Out - Error occurred:', e);
                }
            }

// AMazing end

// SCroll start

            get scStorage() {
                if (!this._scStorage) {
                    this._scStorage = createModuleStorage('SC');
                }
                return this._scStorage;
            }

            meatersHandleWebSocketMessage(event) {
                if (window.MCS_MODULES_DISABLED) return;
                const data = event.detail;
                if (data?.type === 'battle_updated') {
                    this.handleMEatersBattleUpdate(data);
                }
                if (data?.type === 'new_battle') {
                    this.handleMEatersNewBattle(data);
                }
            }

            createMEatersPane() {
                if (document.getElementById('meaters-pane')) {
                    return;
                }
                this.meatersLog = [];
                this.meatersEnemyLog = [];
                this.meatersMaxLogEntries = 100;
                this.meatersFilters = {
                    player1: true,
                    player2: true,
                    player3: true,
                    enemy: true,
                    showAbilities: false
                };
                const pane = document.createElement('div');
                pane.id = 'meaters-pane';
                this.applyClasses(pane, 'mcs-pane', 'mcs-pane-dark', 'mcs-meaters-pane');

                const header = document.createElement('div');
                this.applyClasses(header, 'mcs-pane-header', 'mcs-gap-10');

                const titleSpan = document.createElement('span');
                this.applyClass(titleSpan, 'mcs-pane-title');
                titleSpan.textContent = 'MEaters - Combat Log (Compact)';

                const filterContainer = document.createElement('div');
                this.applyClasses(filterContainer, 'mcs-filter-container', 'mcs-gap-4');
                const createToggleBtn = (text, filterKey) => {
                    const btn = document.createElement('button');
                    btn.textContent = text;
                    btn.dataset.filterKey = filterKey;
                    this.applyClass(btn, 'mcs-filter-btn');

                    const updateButtonStyle = () => {
                        if (this.meatersFilters[filterKey]) {
                            btn.classList.remove('inactive');
                            btn.classList.add('active');
                        } else {
                            btn.classList.remove('active');
                            btn.classList.add('inactive');
                        }
                    };
                    updateButtonStyle();

                    btn.onclick = (e) => {
                        e.stopPropagation();
                        this.meatersFilters[filterKey] = !this.meatersFilters[filterKey];
                        updateButtonStyle();
                        this.updateMEatersContent();
                    };
                    return btn;
                };
                const player1Btn = createToggleBtn('P1', 'player1');
                const player2Btn = createToggleBtn('P2', 'player2');
                const player3Btn = createToggleBtn('P3', 'player3');
                const enemyBtn = createToggleBtn('Enemy', 'enemy');
                const clownBtn = document.createElement('button');
                clownBtn.textContent = '🤡';
                this.applyClasses(clownBtn, 'mcs-filter-btn', 'inactive', 'mcs-font-14');

                clownBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.meatersFilters.showAbilities = !this.meatersFilters.showAbilities;
                    if (this.meatersFilters.showAbilities) {
                        clownBtn.classList.remove('inactive');
                        clownBtn.classList.add('active');
                    } else {
                        clownBtn.classList.remove('active');
                        clownBtn.classList.add('inactive');
                    }
                    this.updateMEatersContent();
                };

                const infoBtn = document.createElement('button');
                infoBtn.textContent = 'ℹ️';
                this.applyClasses(infoBtn, 'mcs-filter-btn', 'mcs-font-14');

                infoBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.showMEatersInfo();
                };
                filterContainer.appendChild(player1Btn);
                filterContainer.appendChild(player2Btn);
                filterContainer.appendChild(player3Btn);
                filterContainer.appendChild(enemyBtn);
                filterContainer.appendChild(clownBtn);
                filterContainer.appendChild(infoBtn);
                const buttonContainer = document.createElement('div');
                this.applyClasses(buttonContainer, 'mcs-row', 'mcs-gap-6');

                const clearBtn = document.createElement('button');
                clearBtn.id = 'meaters-clear-btn';
                clearBtn.textContent = 'Clear';
                this.applyClasses(clearBtn, 'mcs-btn', 'mcs-btn-small');

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'meaters-minimize-btn';
                minimizeBtn.textContent = '−';
                this.applyClasses(minimizeBtn, 'mcs-btn', 'mcs-btn-minimize');

                buttonContainer.appendChild(clearBtn);
                buttonContainer.appendChild(minimizeBtn);
                header.appendChild(titleSpan);
                header.appendChild(filterContainer);
                header.appendChild(buttonContainer);

                const content = document.createElement('div');
                content.id = 'meaters-content';
                this.applyClasses(content, 'mcs-pane-content', 'mcs-pane-content-dark', 'mcs-meaters-content');
                content.style.maxHeight = '400px';
                content.style.minHeight = '200px';
                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);
                registerPanel('meaters-pane');
                this.makeMEatersDraggable(pane, header);
                this.meatersLog = [];
                this.meatersMaxLogEntries = 100;
                const savedMeatersMinimized = this.scStorage.get('minimized');
                this.meatersIsMinimized = savedMeatersMinimized === true || savedMeatersMinimized === 'true';
                if (this.meatersIsMinimized) {
                    minimizeBtn.textContent = '+';
                    content.classList.add('mcs-hidden');
                    header.classList.add('minimized');
                }
                minimizeBtn.onclick = () => {
                    this.meatersIsMinimized = !this.meatersIsMinimized;
                    if (this.meatersIsMinimized) {
                        content.classList.add('mcs-hidden');
                        minimizeBtn.textContent = '+';
                        header.classList.add('minimized');
                        this.scStorage.set('minimized', true);
                    } else {
                        content.classList.remove('mcs-hidden');
                        minimizeBtn.textContent = '−';
                        header.classList.remove('minimized');
                        this.scStorage.set('minimized', false);
                        this.constrainPanelToBoundaries('meaters-pane', 'mcs_SC', true);
                    }
                };
                clearBtn.onclick = () => {
                    this.meatersLog = [];
                    this.updateMEatersContent();
                };
                this._meatersWsListener = this.meatersHandleWebSocketMessage.bind(this);
                window.addEventListener('EquipSpyWebSocketMessage', this._meatersWsListener);
                this.updateMEatersContent();
            }

            showMEatersInfo() {
                let infoDialog = document.getElementById('meaters-info-dialog');
                if (infoDialog) {
                    infoDialog.remove();
                    return;
                }
                infoDialog = document.createElement('div');
                infoDialog.id = 'meaters-info-dialog';
                this.applyClass(infoDialog, 'mcs-meaters-info-dialog');

                const content = document.createElement('div');
    content.innerHTML = `
        <div class="mcs-meaters-info-title mcs-text-success">MEaters Combat Log</div>
        <div class="mcs-meaters-info-text">
            <strong>Filter Buttons:</strong><br>
            • <strong>P1, P2, P3</strong> - Toggle player attacks<br>
            • <strong>Enemy</strong> - Toggle enemy attacks & heals<br>
            • <strong>🤡</strong> - Toggle ability names (off by default)<br>
            • <strong>ℹ️</strong> - Show this info<br><br>
            <strong>Display:</strong><br>
            • Left border = Player attacks (green)<br>
            • Right border = Enemy attacks (red) or heals (green)<br>
            • Format: timestamp:attacker:ability:damage:target
        </div>
        <button id="meaters-info-close" class="mcs-btn mcs-btn-small mcs-meaters-info-close">Close</button>
                `;
                infoDialog.appendChild(content);
                document.body.appendChild(infoDialog);
                document.getElementById('meaters-info-close').onclick = () => {
                    infoDialog.remove();
                };
                setTimeout(() => {
                    document.addEventListener('click', function closeInfo(e) {
                        if (!infoDialog.contains(e.target)) {
                            infoDialog.remove();
                            document.removeEventListener('click', closeInfo);
                        }
                    });
                }, 100);
            }

            handleMEatersNewBattle(data) {
                if (!this.meatersTracking) {
                    this.meatersTracking = {
                        monstersHP: [],
                        monstersDmgCounter: [],
                        monstersCritCounter: [],
                        playersMP: [],
                        players: [],
                        monsters: [],
                        monstersMP: [],
                        monstersPreparing: {},
                        playersHP: [],
                        playersDmgCounter: []
                    };
                }
                this.meatersTracking.monsters = data.monsters || [];
                this.meatersTracking.players = data.players || [];
                this.meatersTracking.monstersHP = data.monsters.map((monster) => monster.currentHitpoints);
                this.meatersTracking.monstersDmgCounter = data.monsters.map((monster) => monster.damageSplatCounter);
                this.meatersTracking.monstersCritCounter = data.monsters.map((monster) => monster.criticalHitCounter ?? 0);
                this.meatersTracking.playersMP = data.players.map((player) => player.currentManapoints);
                this.meatersTracking.monstersMP = data.monsters.map((monster) => monster.currentManapoints);
                this.meatersTracking.playersHP = data.players.map((player) => player.currentHitpoints);
                this.meatersTracking.playersDmgCounter = data.players.map((player) => player.damageSplatCounter);
                this.meatersTracking.monstersPreparing = {};
            }

            getPlayerNumber(playerName) {
                if (!this.meatersTracking || !this.meatersTracking.players) return '1';
                for (let i = 0; i < this.meatersTracking.players.length; i++) {
                    const player = this.meatersTracking.players[i];
                    if (player && player.username === playerName) {
                        return (parseInt(i) + 1).toString();
                    }
                }
                return '1';
            }

            handleMEatersBattleUpdate(data) {
                if (!this.meatersTracking || !this.meatersTracking.monstersHP || this.meatersTracking.monstersHP.length === 0) {
                    return;
                }
                const mMap = data.mMap;
                const pMap = data.pMap;
                const playerIndices = Object.keys(pMap);
                if (!this.meatersTracking.monstersPreparing) {
                    this.meatersTracking.monstersPreparing = {};
                }
                Object.keys(mMap).forEach((mIndex) => {
                    const monster = mMap[mIndex];
                    if (!monster) return;
                    if (monster.preparingAbilityHrid) {
                        this.meatersTracking.monstersPreparing[mIndex] = monster.preparingAbilityHrid;
                    } else if (monster.isPreparingAutoAttack) {
                        this.meatersTracking.monstersPreparing[mIndex] = 'auto_attack';
                    }
                });
                let castPlayer = -1;
                playerIndices.forEach((userIndex) => {
                    if (pMap[userIndex].cMP < this.meatersTracking.playersMP[userIndex]) {
                        castPlayer = userIndex;
                    }
                    this.meatersTracking.playersMP[userIndex] = pMap[userIndex].cMP;
                });
                let castMonster = -1;
                Object.keys(mMap).forEach((mIndex) => {
                    const monster = mMap[mIndex];
                    if (!monster) return;
                    const prevMP = this.meatersTracking.monstersMP?.[mIndex];
                    if (prevMP !== undefined && monster.cMP < prevMP) {
                        castMonster = mIndex;
                    }
                    if (!this.meatersTracking.monstersMP) {
                        this.meatersTracking.monstersMP = [];
                    }
                    this.meatersTracking.monstersMP[mIndex] = monster.cMP;
                });
                this.meatersTracking.monstersHP.forEach((mHP, mIndex) => {
                    const monster = mMap[mIndex];
                    if (!monster) return;
                    const hpDiff = mHP - monster.cHP;
                    let dmgSplat = false;
                    if (this.meatersTracking.monstersDmgCounter[mIndex] < monster.dmgCounter) {
                        dmgSplat = true;
                    }
                    let isCrit = false;
                    if (this.meatersTracking.monstersCritCounter[mIndex] < monster.critCounter) {
                        isCrit = true;
                    }
                    this.meatersTracking.monstersHP[mIndex] = monster.cHP;
                    this.meatersTracking.monstersDmgCounter[mIndex] = monster.dmgCounter;
                    this.meatersTracking.monstersCritCounter[mIndex] = monster.critCounter;
                    const monsterName = this.meatersTracking.monsters[mIndex]?.name || `Monster ${mIndex + 1}`;
                    if (dmgSplat && playerIndices.length > 0) {
                        const isMiss = hpDiff === 0;
                        let playerIndex = castPlayer;
                        if (playerIndices.length === 1) {
                            playerIndex = playerIndices[0];
                        }
                        if (playerIndex !== -1 && this.meatersTracking.players[playerIndex]) {
                            const player = this.meatersTracking.players[playerIndex];
                            const playerName = (player.character && player.character.name) || player.username || `Player ${parseInt(playerIndex) + 1}`;
                            let abilityName = 'Unknown';
                            if (player.preparingAbilityHrid) {
                                abilityName = player.preparingAbilityHrid.split('/').pop().replace(/_/g, ' ');
                            } else if (player.isPreparingAutoAttack) {
                                abilityName = 'Auto Attack';
                            } else {
                                abilityName = 'Idle';
                            }
                            this.addMEatersLogEntry(playerName, monsterName, abilityName, hpDiff, isCrit, isMiss);
                        }
                    }
                    if (hpDiff < 0) {
                        const healAmount = Math.abs(hpDiff);
                        let healerName = 'Unknown Healer';
                        let healerIndex = -1;
                        let targetName = monsterName;
                        let abilityName = 'Unknown Heal';
                        if (castMonster !== -1 && this.meatersTracking.monsters[castMonster]) {
                            healerIndex = castMonster;
                            healerName = this.meatersTracking.monsters[castMonster].name;
                        }
                        else if (this.meatersTracking.monsters.length === 1) {
                            healerIndex = 0;
                            healerName = this.meatersTracking.monsters[0].name;
                        }
                        else {
                            healerIndex = mIndex;
                            healerName = monsterName;
                        }
                        if (healerIndex !== -1) {
                            const healerData = mMap[healerIndex];
                            if (healerData && healerData.preparingAbilityHrid) {
                                abilityName = healerData.preparingAbilityHrid.split('/').pop().replace(/_/g, ' ');
                            }
                            else if (this.meatersTracking.monstersPreparing && this.meatersTracking.monstersPreparing[healerIndex]) {
                                const storedAbility = this.meatersTracking.monstersPreparing[healerIndex];
                                abilityName = storedAbility.split('/').pop().replace(/_/g, ' ');
                            }
                            else {
                                abilityName = 'Regeneration';
                            }
                        }
                        this.addMEatersEnemyHealEntry(healerName, targetName, abilityName, healAmount);
                    }
                });
                if (!this.meatersTracking.playersDmgCounter) {
                    this.meatersTracking.playersDmgCounter = [];
                    Object.keys(pMap).forEach(pIndex => {
                        this.meatersTracking.playersDmgCounter[pIndex] = pMap[pIndex].dmgCounter ?? 0;
                    });
                }
                if (!this.meatersTracking.playersHP) {
                    this.meatersTracking.playersHP = [];
                    Object.keys(pMap).forEach(pIndex => {
                        this.meatersTracking.playersHP[pIndex] = pMap[pIndex].cHP;
                    });
                }
                Object.keys(pMap).forEach(pIndex => {
                    const player = pMap[pIndex];
                    if (!player) return;
                    const prevHP = this.meatersTracking.playersHP[pIndex];
                    if (prevHP === undefined) {
                        this.meatersTracking.playersHP[pIndex] = player.cHP;
                        return;
                    }
                    const hpDiff = prevHP - player.cHP;
                    let dmgSplat = false;
                    const prevDmgCounter = this.meatersTracking.playersDmgCounter[pIndex] ?? 0;
                    const currentDmgCounter = player.dmgCounter ?? 0;
                    if (currentDmgCounter > prevDmgCounter) {
                        dmgSplat = true;
                    }
                    this.meatersTracking.playersDmgCounter[pIndex] = currentDmgCounter;
                    if (dmgSplat && hpDiff > 0) {
                        let actualAttacker = -1;
                        Object.keys(mMap).forEach((mIndex) => {
                        });
                    }
                    if (dmgSplat && hpDiff > 0) {
                        let monsterName = null;
                        let attackingMonsterIndex = -1;
                        let abilityName = 'Unknown';
                        if (castMonster !== -1 && this.meatersTracking.monsters[castMonster]) {
                            attackingMonsterIndex = castMonster;
                            monsterName = this.meatersTracking.monsters[castMonster].name;
                        }
                        if (!monsterName && this.meatersTracking.monsters.length === 1) {
                            attackingMonsterIndex = 0;
                            monsterName = this.meatersTracking.monsters[0].name;
                        }
                        if (!monsterName) {
                            Object.keys(mMap).forEach((mIndex) => {
                                const monster = mMap[mIndex];
                                if (!monster) return;
                                if (this.meatersTracking.monstersDmgCounter[mIndex] === undefined) {
                                    this.meatersTracking.monstersDmgCounter[mIndex] = monster.dmgCounter ?? 0;
                                }
                                const prevDmg = this.meatersTracking.monstersDmgCounter[mIndex];
                                const currentDmg = monster.dmgCounter ?? 0;
                                if (currentDmg > prevDmg) {
                                    attackingMonsterIndex = mIndex;
                                    if (this.meatersTracking.monsters[mIndex]) {
                                        monsterName = this.meatersTracking.monsters[mIndex].name;
                                    }
                                }
                            });
                        }
                        if (!monsterName) {
                            for (let i = 0; i < this.meatersTracking.monsters.length; i++) {
                                const monster = mMap[i];
                                if (monster && monster.cHP > 0) {
                                    attackingMonsterIndex = i;
                                    monsterName = this.meatersTracking.monsters[i].name;
                                    break;
                                }
                            }
                        }
                        if (!monsterName) {
                            monsterName = 'Unknown Enemy';
                        }
                        if (attackingMonsterIndex !== -1) {
                            const monsterData = mMap[attackingMonsterIndex];
                            if (monsterData && monsterData.preparingAbilityHrid) {
                                abilityName = monsterData.preparingAbilityHrid.split('/').pop().replace(/_/g, ' ');
                            }
                            else if (this.meatersTracking.monstersPreparing && this.meatersTracking.monstersPreparing[attackingMonsterIndex]) {
                                const storedAbility = this.meatersTracking.monstersPreparing[attackingMonsterIndex];
                                if (storedAbility === 'auto_attack') {
                                    abilityName = 'Auto Attack';
                                } else {
                                    abilityName = storedAbility.split('/').pop().replace(/_/g, ' ');
                                }
                            }
                            else if (monsterData && monsterData.isPreparingAutoAttack) {
                                abilityName = 'Auto Attack';
                            }
                            else if (this.meatersTracking.monsters[attackingMonsterIndex]) {
                                const monsterInfo = this.meatersTracking.monsters[attackingMonsterIndex];
                                if (monsterInfo.combatAbilities && monsterInfo.combatAbilities.length > 0) {
                                    abilityName = monsterInfo.combatAbilities[0].abilityHrid.split('/').pop().replace(/_/g, ' ');
                                } else {
                                    abilityName = 'Basic Attack';
                                }
                            } else {
                                abilityName = 'Basic Attack';
                            }
                        }
                        const playerName = this.meatersTracking.players[pIndex]?.character?.name ||
                            this.meatersTracking.players[pIndex]?.username ||
                            `Player ${parseInt(pIndex) + 1}`;
                        const isMiss = false;
                        this.addMEatersEnemyLogEntry(monsterName, playerName, abilityName, hpDiff, false, isMiss);
                    }
                    if (dmgSplat && hpDiff === 0) {
                        let monsterName = null;
                        let attackingMonsterIndex = -1;
                        let abilityName = 'Unknown';
                        if (castMonster !== -1 && this.meatersTracking.monsters[castMonster]) {
                            attackingMonsterIndex = castMonster;
                            monsterName = this.meatersTracking.monsters[castMonster].name;
                        }
                        if (!monsterName && this.meatersTracking.monsters.length === 1) {
                            attackingMonsterIndex = 0;
                            monsterName = this.meatersTracking.monsters[0].name;
                        }
                        if (!monsterName) {
                            Object.keys(mMap).forEach((mIndex) => {
                                const monster = mMap[mIndex];
                                if (!monster) return;
                                if (this.meatersTracking.monstersDmgCounter[mIndex] === undefined) {
                                    this.meatersTracking.monstersDmgCounter[mIndex] = monster.dmgCounter ?? 0;
                                }
                                const prevDmg = this.meatersTracking.monstersDmgCounter[mIndex];
                                const currentDmg = monster.dmgCounter ?? 0;
                                if (currentDmg > prevDmg) {
                                    attackingMonsterIndex = mIndex;
                                    if (this.meatersTracking.monsters[mIndex]) {
                                        monsterName = this.meatersTracking.monsters[mIndex].name;
                                    }
                                }
                            });
                        }
                        if (!monsterName) {
                            for (let i = 0; i < this.meatersTracking.monsters.length; i++) {
                                const monster = mMap[i];
                                if (monster && monster.cHP > 0) {
                                    attackingMonsterIndex = i;
                                    monsterName = this.meatersTracking.monsters[i].name;
                                    break;
                                }
                            }
                        }
                        if (!monsterName) {
                            monsterName = 'Unknown Enemy';
                        }
                        if (attackingMonsterIndex !== -1) {
                            const monsterData = mMap[attackingMonsterIndex];
                            if (monsterData && monsterData.preparingAbilityHrid) {
                                abilityName = monsterData.preparingAbilityHrid.split('/').pop().replace(/_/g, ' ');
                            }
                            else if (this.meatersTracking.monstersPreparing && this.meatersTracking.monstersPreparing[attackingMonsterIndex]) {
                                const storedAbility = this.meatersTracking.monstersPreparing[attackingMonsterIndex];
                                if (storedAbility === 'auto_attack') {
                                    abilityName = 'Auto Attack';
                                } else {
                                    abilityName = storedAbility.split('/').pop().replace(/_/g, ' ');
                                }
                            }
                            else if (monsterData && monsterData.isPreparingAutoAttack) {
                                abilityName = 'Auto Attack';
                            }
                            else if (this.meatersTracking.monsters[attackingMonsterIndex]) {
                                const monsterInfo = this.meatersTracking.monsters[attackingMonsterIndex];
                                if (monsterInfo.combatAbilities && monsterInfo.combatAbilities.length > 0) {
                                    abilityName = monsterInfo.combatAbilities[0].abilityHrid.split('/').pop().replace(/_/g, ' ');
                                } else {
                                    abilityName = 'Basic Attack';
                                }
                            } else {
                                abilityName = 'Basic Attack';
                            }
                        }
                        const playerName = this.meatersTracking.players[pIndex]?.character?.name ||
                            this.meatersTracking.players[pIndex]?.username ||
                            `Player ${parseInt(pIndex) + 1}`;
                        this.addMEatersEnemyLogEntry(monsterName, playerName, abilityName, 0, false, true);
                    }
                    this.meatersTracking.playersHP[pIndex] = player.cHP;
                });
            }

            addMEatersLogEntry(playerName, monsterName, abilityName, damage, isCrit, isMiss) {
                const timestamp = new Date().toLocaleTimeString();
                this.meatersLog.push({
                    timestamp,
                    playerName,
                    monsterName,
                    abilityName,
                    damage,
                    isCrit,
                    isMiss
                });
                if (this.meatersLog.length > this.meatersMaxLogEntries) {
                    this.meatersLog.shift();
                }
                this.updateMEatersContent();
            }

            addMEatersEnemyLogEntry(enemyName, playerName, abilityName, damage, isCrit, isMiss) {
                const timestamp = new Date().toLocaleTimeString();
                this.meatersEnemyLog.push({
                    timestamp,
                    enemyName,
                    playerName,
                    abilityName,
                    damage,
                    isCrit,
                    isMiss
                });
                if (this.meatersEnemyLog.length > this.meatersMaxLogEntries) {
                    this.meatersEnemyLog.shift();
                }
                this.updateMEatersContent();
            }

            addMEatersEnemyHealEntry(healerName, targetName, abilityName, healAmount) {
                const timestamp = new Date().toLocaleTimeString();
                this.meatersEnemyLog.push({
                    timestamp,
                    enemyName: healerName,
                    playerName: targetName,
                    abilityName,
                    damage: healAmount,
                    isCrit: false,
                    isMiss: false,
                    isHeal: true
                });
                if (this.meatersEnemyLog.length > this.meatersMaxLogEntries) {
                    this.meatersEnemyLog.shift();
                }
                this.updateMEatersContent();
            }

            updateMEatersContent() {
                const content = document.getElementById('meaters-content');
                if (!content) return;
                if (this.meatersLog.length === 0 && this.meatersEnemyLog.length === 0) {
                    content.innerHTML = '<div class="mcs-meaters-empty">No combat activity yet...</div>';
                    return;
                }
                const allLogs = [
                    ...this.meatersLog.map(entry => ({ ...entry, type: 'player' })),
                    ...this.meatersEnemyLog.map(entry => ({ ...entry, type: 'enemy' }))
                ].sort((a, b) => {
                    return a.timestamp.localeCompare(b.timestamp);
                });
                const displayCount = 20;
                const startIdx = Math.max(0, allLogs.length - displayCount);
                let html = '';
                for (let i = allLogs.length - 1; i >= startIdx; i--) {
                    const entry = allLogs[i];
                    if (entry.type === 'player') {
                        const playerIndex = this.meatersTracking.players?.findIndex(p => (p.character && p.character.name === entry.playerName) ||
                            p.username === entry.playerName
                        );
                        const playerSlot = playerIndex !== -1 ? playerIndex + 1 : 1;
                        if (playerSlot === 1 && !this.meatersFilters.player1) continue;
                        if (playerSlot === 2 && !this.meatersFilters.player2) continue;
                        if (playerSlot === 3 && !this.meatersFilters.player3) continue;
                        if (playerSlot > 3 && !this.meatersFilters.player1) continue;
                    } else if (entry.type === 'enemy') {
                        if (!this.meatersFilters.enemy) continue;
                    }
                    let borderColor = entry.type === 'player' ? '#90EE90' : '#FF6B6B';
                    let damageText = entry.damage.toString();
                    let damageColor = entry.type === 'player' ? '#90EE90' : '#FF6B6B';
                    if (entry.isMiss) {
                        borderColor = entry.type === 'player' ? '#FF6B6B' : '#90EE90';
                        damageColor = entry.type === 'player' ? '#FF6B6B' : '#90EE90';
                        damageText = 'MISS';
                    } else if (entry.isCrit) {
                        borderColor = '#FFD700';
                        damageColor = '#FFD700';
                        damageText = '⚡' + entry.damage;
                    }
                    if (entry.type === 'player') {
                        html += `<div class="mcs-meaters-log-entry mcs-meaters-log-player" style="border-left-color: ${borderColor};">`;
                        html += `<span class="mcs-meaters-timestamp">${entry.timestamp}</span>`;
                        html += `<span class="mcs-meaters-separator">:</span>`;
                        html += `<span class="mcs-meaters-player-name">${entry.playerName}</span>`;
                        if (this.meatersFilters.showAbilities) {
                            html += `<span class="mcs-meaters-separator">:</span>`;
                            html += `<span class="mcs-meaters-ability">${entry.abilityName}</span>`;
                        }
                        html += `<span class="mcs-meaters-separator">:</span>`;
                        html += `<span class="mcs-meaters-damage" style="color: ${damageColor};">${damageText}</span>`;
                        html += `<span class="mcs-meaters-separator">:</span>`;
                        html += `<span class="mcs-meaters-monster-name">${entry.monsterName}</span>`;
                        html += `</div>`;
                    } else {
                        const isHeal = entry.isHeal || false;
                        if (isHeal) {
                            borderColor = '#4CAF50';
                            damageColor = '#4CAF50';
                            damageText = '+' + entry.damage;
                        }
                        html += `<div class="mcs-meaters-log-entry mcs-meaters-log-enemy" style="border-right-color: ${borderColor};">`;
                        html += `<span class="mcs-meaters-timestamp">${entry.timestamp}</span>`;
                        html += `<span class="mcs-meaters-separator">:</span>`;
                        if (isHeal) {
                            html += `<span class="mcs-meaters-monster-name">${entry.enemyName}</span>`;
                            html += `<span class="mcs-meaters-separator">→</span>`;
                            html += `<span class="mcs-meaters-monster-name">${entry.playerName}</span>`;
                        } else {
                            html += `<span class="mcs-meaters-monster-name">${entry.enemyName}</span>`;
                        }
                        if (this.meatersFilters.showAbilities) {
                            html += `<span class="mcs-meaters-separator">:</span>`;
                            html += `<span class="mcs-meaters-ability">${entry.abilityName}</span>`;
                        }
                        html += `<span class="mcs-meaters-separator">:</span>`;
                        html += `<span class="mcs-meaters-damage" style="color: ${damageColor};">${damageText}</span>`;
                        if (!isHeal) {
                            html += `<span class="mcs-meaters-separator">:</span>`;
                            html += `<span class="mcs-meaters-player-name">${entry.playerName}</span>`;
                        }
                        html += `</div>`;
                    }
                }
                content.innerHTML = html;
            }

            makeMEatersDraggable(pane, header) {
                DragHandler.makeDraggable(pane, header, 'mcs_SC');
            }

            destroySCroll() {
                if (this._meatersWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._meatersWsListener); this._meatersWsListener = null; }
                const pane = document.getElementById('meaters-pane');
                if (pane) pane.remove();
            }

// SCroll end

// DPs start

                get dpStorage() {
                    if (!this._dpStorage) {
                        this._dpStorage = createModuleStorage('DP');
                    }
                    return this._dpStorage;
                }

                dpsGetContent() {
                    if (!this._dpsCachedContent || !this._dpsCachedContent.isConnected) {
                        this._dpsCachedContent = document.getElementById('dps-content');
                    }
                    return this._dpsCachedContent;
                }

                dpsGetPlayerItems() {
                    const content = this.dpsGetContent();
                    if (!content) return [];
                    if (this._dpsCachedPlayerItems && this._dpsLastCacheVersion === this._dpsCacheVersion) {
                        return this._dpsCachedPlayerItems;
                    }
                    this._dpsCachedPlayerItems = content.querySelectorAll('.mcs-dps-player-item');
                    this._dpsLastCacheVersion = this._dpsCacheVersion;
                    return this._dpsCachedPlayerItems;
                }

                dpsInvalidatePlayerCache() {
                    if (!this._dpsCacheVersion) this._dpsCacheVersion = 0;
                    this._dpsCacheVersion++;
                    this._dpsCachedPlayerItems = null;
                }

                dpsHandleWebSocketMessage(event) {
                    if (window.MCS_MODULES_DISABLED) return;
                    const data = event.detail;
                    if (data?.type === 'new_battle') {
                        this.handleDPsNewBattle(data);
                        this.handleTrueDPSNewBattle(data);
                    }
                    if (data?.type === 'battle_updated') {
                        this.handleDPsBattleUpdate(data);
                        this.handleTrueDPSBattleUpdate(data);
                    }
                    if (data?.type === 'battle_ended') {
                        this.handleDPsBattleEnded(data);
                    }
                }

                createDPsPane() {
                if (document.getElementById('dps-pane')) return;
                const pane = document.createElement('div');
                pane.id = 'dps-pane';
                registerPanel('dps-pane');
                pane.className = 'mcs-pane mcs-dps-pane';
                const header = document.createElement('div');
                header.className = 'mcs-pane-header mcs-dps-header';
                const titleSpan = document.createElement('span');
                titleSpan.id = 'dps-title-span';
                titleSpan.className = 'mcs-pane-title mcs-dps-title';
                titleSpan.innerHTML = 'DPs';

                const inactivityTimer = document.createElement('span');
                inactivityTimer.id = 'dps-inactivity-timer';
                inactivityTimer.className = 'mcs-dps-inactivity-timer';
                inactivityTimer.textContent = '0.000s';

                const buttonContainer = document.createElement('div');
                buttonContainer.className = 'mcs-dps-button-container';
                if (this.dpsFilterNondamage === undefined) {
                    this.dpsFilterNondamage = true;
                }
                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'dps-minimize-btn';
                minimizeBtn.textContent = '−';
                minimizeBtn.className = 'mcs-btn mcs-btn-minimize';

                minimizeBtn.onclick = () => {
                    this.dpsIsMinimized = !this.dpsIsMinimized;
                    const filterBtn = document.getElementById('dps-filter-btn');
                    const resetBtn = document.getElementById('dps-reset-btn');
                    if (this.dpsIsMinimized) {
                        minimizeBtn.textContent = '+';
                        if (filterBtn) filterBtn.classList.add('mcs-hidden');
                        if (resetBtn) resetBtn.classList.add('mcs-hidden');
                        const headerDiv = this.dpsGetContent()?.querySelector(':scope > div:first-child');
                        if (headerDiv) {
                            headerDiv.classList.add('mcs-hidden');
                        }
                        this.dpsGetPlayerItems().forEach(item => {
                            const abilityContainer = item.querySelector('.mcs-dps-ability-container');
                            if (abilityContainer) {
                                abilityContainer.classList.add('mcs-hidden');
                            }
                            const playerRow = item.querySelector('.mcs-dps-player-row');
                            if (playerRow) {
                                const children = Array.from(playerRow.children);
                                children.forEach((child, index) => {
                                    if (index === 0 || index >= 3) {
                                        child.classList.add('mcs-hidden');
                                    }
                                });
                                playerRow.classList.add('minimized');
                                playerRow.onclick = null;
                            }
                        });
                        const truedpsSection = document.getElementById('dps-truedps-section');
                        if (truedpsSection) truedpsSection.classList.add('mcs-hidden');
                        header.classList.add('minimized');
                        this.dpStorage.set('minimized', true);
                    } else {
                        minimizeBtn.textContent = '-';
                        if (filterBtn) filterBtn.classList.remove('mcs-hidden');
                        if (resetBtn) resetBtn.classList.remove('mcs-hidden');
                        header.classList.remove('minimized');
                        this.dpStorage.set('minimized', false);

                        this.updateDPsDisplay();

                        const headerDiv = this.dpsGetContent()?.querySelector(':scope > div:first-child');
                        if (headerDiv) {
                            headerDiv.classList.remove('mcs-hidden');
                        }
                        this.dpsGetPlayerItems().forEach(item => {
                            const abilityContainer = item.querySelector('.mcs-dps-ability-container');
                            const playerRow = item.querySelector('.mcs-dps-player-row');
                            const expandArrow = item.querySelector('.mcs-dps-expand-arrow');

                            if (abilityContainer) {
                                const playerIndex = parseInt(item.getAttribute('data-player-index'));
                                const isExpanded = this.dpsTracking.expandedPlayers.has(playerIndex);
                                if (isExpanded) {
                                    abilityContainer.classList.remove('mcs-hidden');
                                } else {
                                    abilityContainer.classList.add('mcs-hidden');
                                }
                            }

                            if (playerRow) {
                                const children = Array.from(playerRow.children);
                                children.forEach(child => {
                                    child.classList.remove('mcs-hidden');
                                });
                                playerRow.classList.remove('minimized');

                                const playerIndex = parseInt(item.getAttribute('data-player-index'));
                                playerRow.onclick = () => {
                                    const isExpanded = !abilityContainer.classList.contains('mcs-hidden');
                                    if (isExpanded) {
                                        abilityContainer.classList.add('mcs-hidden');
                                        if (expandArrow) expandArrow.textContent = '▶';
                                        this.dpsTracking.expandedPlayers.delete(playerIndex);
                                    } else {
                                        abilityContainer.classList.remove('mcs-hidden');
                                        if (expandArrow) expandArrow.textContent = '▼';
                                        this.dpsTracking.expandedPlayers.add(playerIndex);
                                    }
                                };
                            }
                        });

                        const truedpsSection = document.getElementById('dps-truedps-section');
                        if (truedpsSection) truedpsSection.classList.remove('mcs-hidden');

                        this.constrainPanelToBoundaries('dps-pane', 'mcs_DP', true);
                    }
                };
                const filterBtn = document.createElement('button');
                filterBtn.id = 'dps-filter-btn';
                filterBtn.textContent = this.dpsFilterNondamage ? 'Filter Nondamage: Enabled' : 'Filter Nondamage: Disabled';
                filterBtn.className = 'mcs-dps-filter-btn';
                if (this.dpsFilterNondamage) {
                    filterBtn.classList.add('enabled');
                }

                filterBtn.onclick = () => {
                    this.dpsFilterNondamage = !this.dpsFilterNondamage;
                    if (this.dpsFilterNondamage) {
                        filterBtn.classList.add('enabled');
                    } else {
                        filterBtn.classList.remove('enabled');
                    }
                    filterBtn.textContent = this.dpsFilterNondamage ? 'Filter Nondamage: Enabled' : 'Filter Nondamage: Disabled';
                };

                const resetBtn = document.createElement('button');
                resetBtn.id = 'dps-reset-btn';
                resetBtn.textContent = 'Reset';
                resetBtn.className = 'mcs-dps-reset-btn';

                buttonContainer.appendChild(filterBtn);
                buttonContainer.appendChild(resetBtn);
                buttonContainer.appendChild(minimizeBtn);
                header.appendChild(titleSpan);
                header.appendChild(inactivityTimer);
                header.appendChild(buttonContainer);
                const content = document.createElement('div');
                content.id = 'dps-content';
                content.className = 'mcs-dps-content';
                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);
                this.makeDPsDraggable(pane, header);
                this.dpsTracking = {
                    players: [],
                    monsters: [],
                    totalDamage: [],
                    monstersHP: [],
                    monstersDmgCounter: [],
                    monstersCritCounter: [],
                    playersMP: [],
                    startTime: null,
                    endTime: null,
                    totalDuration: 0,
                    lastCombatUpdate: null,
                    expandedPlayers: new Set(),
                    expandedMonsters: new Map(),
                    filteredDamage: [],
                    unfilteredDamage: [],
                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                };
                this.trueDPSTracking = {
                    startTime: Date.now(),
                    enemyKills: {},
                    monsterMaxHP: {},
                    monstersHP: [],
                    monstersDmgCounter: [],
                    monsters: [],
                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                };
                this.updateDPsContent();
                resetBtn.onclick = () => {
                    this.dpsTracking = {
                        players: [],
                        monsters: [],
                        totalDamage: [],
                        monstersHP: [],
                        monstersDmgCounter: [],
                        monstersCritCounter: [],
                        playersMP: [],
                        startTime: null,
                        endTime: null,
                        totalDuration: 0,
                        lastCombatUpdate: null,
                        expandedPlayers: new Set(),
                        expandedMonsters: new Map(),
                        filteredDamage: [],
                        unfilteredDamage: [],
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                    };
                    this.trueDPSTracking = {
                        startTime: Date.now(),
                        enemyKills: {},
                        monsterMaxHP: {},
                        monstersHP: [],
                        monstersDmgCounter: [],
                        monsters: [],
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                    };
                    if (this.dpsStateCache) this.dpsStateCache.clear();
                    this.updateDPsContent();
                };
                if (!this._dpsWsListener) {
                    this._dpsWsListener = this.dpsHandleWebSocketMessage.bind(this);
                    window.addEventListener('EquipSpyWebSocketMessage', this._dpsWsListener);
                }
                VisibilityManager.register('dps-update', () => {
                    this.updateDPsDisplay();
                }, 2000);

                VisibilityManager.register('dps-inactivity-timer', () => {
                    this.updateInactivityTimer();
                }, 100);
                const savedDpsMinimized = this.dpStorage.get('minimized');
                this.dpsIsMinimized = savedDpsMinimized === true || savedDpsMinimized === 'true';
                if (this.dpsIsMinimized) {
                    minimizeBtn.textContent = '+';
                    header.classList.add('minimized');
                    const filterBtn = document.getElementById('dps-filter-btn');
                    const infoBtn = document.getElementById('dps-info-btn');
                    const resetBtn = document.getElementById('dps-reset-btn');
                    if (filterBtn) filterBtn.classList.add('mcs-hidden');
                    if (infoBtn) infoBtn.classList.add('mcs-hidden');
                    if (resetBtn) resetBtn.classList.add('mcs-hidden');
                    setTimeout(() => {
                        const headerDiv = this.dpsGetContent()?.querySelector(':scope > div:first-child');
                        if (headerDiv && headerDiv.classList.contains('mcs-dps-header-row')) {
                            headerDiv.classList.add('mcs-hidden');
                        }
                        this.dpsGetPlayerItems().forEach(item => {
                            const abilityContainer = item.querySelector('.mcs-dps-ability-container');
                            if (abilityContainer) abilityContainer.classList.add('mcs-hidden');
                            const playerRow = item.querySelector('.mcs-dps-player-row');
                            if (playerRow) {
                                const children = Array.from(playerRow.children);
                                children.forEach((child, index) => {
                                    if (index === 0 || index >= 3) {
                                        child.classList.add('mcs-hidden');
                                    }
                                });
                                playerRow.classList.add('minimized');
                                playerRow.onclick = null;
                            }
                        });
                        const truedpsSection = document.getElementById('dps-truedps-section');
                        if (truedpsSection) truedpsSection.classList.add('mcs-hidden');
                    }, 150);
                }
            }

            isNonDamagingAbility(abilityHrid) {
                const nonDamagingAbilities = [
                    '/abilities/minor_heal',
                    '/abilities/heal',
                    '/abilities/quick_aid',
                    '/abilities/rejuvenate',
                    '/abilities/taunt',
                    '/abilities/provoke',
                    '/abilities/toughness',
                    '/abilities/elusiveness',
                    '/abilities/precision',
                    '/abilities/berserk',
                    '/abilities/elemental_affinity',
                    '/abilities/frenzy',
                    '/abilities/vampirism',
                    '/abilities/revive',
                    '/abilities/insanity',
                    '/abilities/invincible',
                    '/abilities/speed_aura',
                    '/abilities/critical_aura',
                    '/abilities/guardian_aura',
                    '/abilities/fierce_aura',
                    '/abilities/mystic_aura',
                    '/abilities/spike_shell'
                ];
                return nonDamagingAbilities.includes(abilityHrid);
            }

            handleDPsNewBattle(data) {
                let isNewSession = false;

                if (this.dpsTracking.lastCombatUpdate) {
                    const timeSinceLastUpdate = (Date.now() - this.dpsTracking.lastCombatUpdate) / 1000;
                    if (timeSinceLastUpdate > 5) {
                        isNewSession = true;
                    }
                }

                this.dpsTracking.lastCombatUpdate = Date.now();

                if (isNewSession) {
                    this.dpsTracking = {
                        players: data.players,
                        monsters: [],
                        totalDamage: new Array(data.players.length).fill(0),
                        filteredDamage: new Array(data.players.length).fill(0),
                        unfilteredDamage: new Array(data.players.length).fill(0),
                        monstersHP: [],
                        monstersDmgCounter: [],
                        monstersCritCounter: [],
                        playersMP: [],
                        startTime: Date.now(),
                        endTime: null,
                        totalDuration: 0,
                        lastCombatUpdate: Date.now(),
                        expandedPlayers: this.dpsTracking.expandedPlayers || new Set(),
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                    };
                } else {
                    if (this.dpsTracking.startTime) {
                        this.dpsTracking.totalDuration = mcsGetElapsedSeconds(
                            this.dpsTracking.startTime,
                            this.dpsTracking.endTime,
                            this.dpsTracking.savedPausedMs,
                            this.dpsTracking.totalDuration
                        );
                    }
                    this.dpsTracking.savedPausedMs = window.MCS_TOTAL_PAUSED_MS ?? 0;
                    this.dpsTracking.startTime = Date.now();
                }

                this.dpsTracking.endTime = null;
                this.dpsTracking.monstersHP = data.monsters.map((monster) => monster.currentHitpoints);
                this.dpsTracking.monstersDmgCounter = data.monsters.map((monster) => monster.damageSplatCounter);
                this.dpsTracking.monstersCritCounter = data.monsters.map((monster) => monster.criticalHitCounter ?? 0);
                this.dpsTracking.playersMP = data.players.map((player) => player.currentManapoints);
                this.dpsTracking.monsters = data.monsters;

                if (!this.dpsTracking.players || this.dpsTracking.players.length === 0) {
                    this.dpsTracking.players = data.players;
                }
                if (!this.dpsTracking.totalDamage.length) {
                    this.dpsTracking.totalDamage = new Array(this.dpsTracking.players.length).fill(0);
                }
                if (!this.dpsTracking.filteredDamage.length) {
                    this.dpsTracking.filteredDamage = new Array(this.dpsTracking.players.length).fill(0);
                }
                if (!this.dpsTracking.unfilteredDamage.length) {
                    this.dpsTracking.unfilteredDamage = new Array(this.dpsTracking.players.length).fill(0);
                }
                const playerIndices = Object.keys(this.dpsTracking.players);
                playerIndices.forEach((userIndex) => {
                    this.dpsTracking.players[userIndex].currentAction = this.dpsTracking.players[userIndex].preparingAbilityHrid
                        ? this.dpsTracking.players[userIndex].preparingAbilityHrid
                        : this.dpsTracking.players[userIndex].isPreparingAutoAttack
                            ? "auto"
                            : "idle";
                });
                setTimeout(() => this.updateDPsContent(), 100);
            }

            handleDPsBattleUpdate(data) {
                if (!this.dpsTracking.monstersHP || this.dpsTracking.monstersHP.length === 0) {
                    return;
                }

                this.dpsTracking.lastCombatUpdate = Date.now();

                const mMap = data.mMap;
                const pMap = data.pMap;
                const playerIndices = Object.keys(pMap);
                let castPlayer = -1;
                playerIndices.forEach((userIndex) => {
                    if (pMap[userIndex].cMP < this.dpsTracking.playersMP[userIndex]) {
                        castPlayer = userIndex;
                    }
                    this.dpsTracking.playersMP[userIndex] = pMap[userIndex].cMP;
                });
                this.dpsTracking.monstersHP.forEach((mHP, mIndex) => {
                    const monster = mMap[mIndex];
                    if (monster) {
                        const hpDiff = mHP - monster.cHP;
                        let dmgSplat = false;
                        if (this.dpsTracking.monstersDmgCounter[mIndex] < monster.dmgCounter) {
                            dmgSplat = true;
                        }
                        let isCrit = false;
                        if (this.dpsTracking.monstersCritCounter[mIndex] < monster.critCounter) {
                            isCrit = true;
                        }
                        this.dpsTracking.monstersHP[mIndex] = monster.cHP;
                        this.dpsTracking.monstersDmgCounter[mIndex] = monster.dmgCounter;
                        this.dpsTracking.monstersCritCounter[mIndex] = monster.critCounter;
                        const monsterName = this.dpsTracking.monsters[mIndex]?.name || `Monster ${mIndex + 1}`;
                        if (dmgSplat && playerIndices.length > 0) {
                            const isMiss = hpDiff === 0;
                            if (playerIndices.length > 1) {
                                playerIndices.forEach((userIndex) => {
                                    if (userIndex === castPlayer) {
                                        const currentAction = this.dpsTracking.players[userIndex].currentAction;
                                        this.dpsTracking.unfilteredDamage[userIndex] += hpDiff;
                                        const isNonDamaging = this.isNonDamagingAbility(currentAction);
                                        if (this.dpsFilterNondamage && isNonDamaging) {
                                            return;
                                        }
                                        if (!isNonDamaging) {
                                            this.dpsTracking.filteredDamage[userIndex] += hpDiff;
                                        }
                                        if (!this.dpsTracking.players[userIndex].damageMap) {
                                            this.dpsTracking.players[userIndex].damageMap = new Map();
                                        }
                                        if (!this.dpsTracking.players[userIndex].hitStatsMap) {
                                            this.dpsTracking.players[userIndex].hitStatsMap = new Map();
                                        }
                                        if (!this.dpsTracking.players[userIndex].monsterDamageMap) {
                                            this.dpsTracking.players[userIndex].monsterDamageMap = new Map();
                                        }
                                        if (!this.dpsTracking.players[userIndex].monsterHitStatsMap) {
                                            this.dpsTracking.players[userIndex].monsterHitStatsMap = new Map();
                                        }
                                        const currentDamage = this.dpsTracking.players[userIndex].damageMap.get(currentAction) ?? 0;
                                        this.dpsTracking.players[userIndex].damageMap.set(currentAction, currentDamage + hpDiff);
                                        const stats = this.dpsTracking.players[userIndex].hitStatsMap.get(currentAction) ?? {
                                            attacks: 0,
                                            hits: 0,
                                            crits: 0,
                                            misses: 0
                                        };
                                        stats.attacks++;
                                        if (isMiss) {
                                            stats.misses++;
                                        } else if (isCrit) {
                                            stats.crits++;
                                        } else {
                                            stats.hits++;
                                        }
                                        this.dpsTracking.players[userIndex].hitStatsMap.set(currentAction, stats);
                                        if (!this.dpsTracking.players[userIndex].monsterDamageMap.has(monsterName)) {
                                            this.dpsTracking.players[userIndex].monsterDamageMap.set(monsterName, new Map());
                                        }
                                        if (!this.dpsTracking.players[userIndex].monsterHitStatsMap.has(monsterName)) {
                                            this.dpsTracking.players[userIndex].monsterHitStatsMap.set(monsterName, new Map());
                                        }
                                        const monsterDmgMap = this.dpsTracking.players[userIndex].monsterDamageMap.get(monsterName);
                                        const currentMonsterDamage = monsterDmgMap.get(currentAction) ?? 0;
                                        monsterDmgMap.set(currentAction, currentMonsterDamage + hpDiff);
                                        const monsterStatsMap = this.dpsTracking.players[userIndex].monsterHitStatsMap.get(monsterName);
                                        const monsterStats = monsterStatsMap.get(currentAction) ?? {
                                            attacks: 0,
                                            hits: 0,
                                            crits: 0,
                                            misses: 0
                                        };
                                        monsterStats.attacks++;
                                        if (isMiss) {
                                            monsterStats.misses++;
                                        } else if (isCrit) {
                                            monsterStats.crits++;
                                        } else {
                                            monsterStats.hits++;
                                        }
                                        monsterStatsMap.set(currentAction, monsterStats);
                                        this.dpsTracking.totalDamage[userIndex] += hpDiff;
                                    }
                                });
                            } else {
                                const userIndex = playerIndices[0];
                                const currentAction = this.dpsTracking.players[userIndex].currentAction;
                                this.dpsTracking.unfilteredDamage[userIndex] += hpDiff;
                                const isNonDamaging = this.isNonDamagingAbility(currentAction);
                                if (this.dpsFilterNondamage && isNonDamaging) {
                                    return;
                                }
                                if (!isNonDamaging) {
                                    this.dpsTracking.filteredDamage[userIndex] += hpDiff;
                                }
                                if (!this.dpsTracking.players[userIndex].damageMap) {
                                    this.dpsTracking.players[userIndex].damageMap = new Map();
                                }
                                if (!this.dpsTracking.players[userIndex].hitStatsMap) {
                                    this.dpsTracking.players[userIndex].hitStatsMap = new Map();
                                }
                                if (!this.dpsTracking.players[userIndex].monsterDamageMap) {
                                    this.dpsTracking.players[userIndex].monsterDamageMap = new Map();
                                }
                                if (!this.dpsTracking.players[userIndex].monsterHitStatsMap) {
                                    this.dpsTracking.players[userIndex].monsterHitStatsMap = new Map();
                                }
                                const currentDamage = this.dpsTracking.players[userIndex].damageMap.get(currentAction) ?? 0;
                                this.dpsTracking.players[userIndex].damageMap.set(currentAction, currentDamage + hpDiff);
                                const stats = this.dpsTracking.players[userIndex].hitStatsMap.get(currentAction) ?? {
                                    attacks: 0,
                                    hits: 0,
                                    crits: 0,
                                    misses: 0
                                };
                                stats.attacks++;
                                if (isMiss) {
                                    stats.misses++;
                                } else if (isCrit) {
                                    stats.crits++;
                                } else {
                                    stats.hits++;
                                }
                                this.dpsTracking.players[userIndex].hitStatsMap.set(currentAction, stats);
                                if (!this.dpsTracking.players[userIndex].monsterDamageMap.has(monsterName)) {
                                    this.dpsTracking.players[userIndex].monsterDamageMap.set(monsterName, new Map());
                                }
                                if (!this.dpsTracking.players[userIndex].monsterHitStatsMap.has(monsterName)) {
                                    this.dpsTracking.players[userIndex].monsterHitStatsMap.set(monsterName, new Map());
                                }
                                const monsterDmgMap = this.dpsTracking.players[userIndex].monsterDamageMap.get(monsterName);
                                const currentMonsterDamage = monsterDmgMap.get(currentAction) ?? 0;
                                monsterDmgMap.set(currentAction, currentMonsterDamage + hpDiff);
                                const monsterStatsMap = this.dpsTracking.players[userIndex].monsterHitStatsMap.get(monsterName);
                                const monsterStats = monsterStatsMap.get(currentAction) ?? {
                                    attacks: 0,
                                    hits: 0,
                                    crits: 0,
                                    misses: 0
                                };
                                monsterStats.attacks++;
                                if (isMiss) {
                                    monsterStats.misses++;
                                } else if (isCrit) {
                                    monsterStats.crits++;
                                } else {
                                    monsterStats.hits++;
                                }
                                monsterStatsMap.set(currentAction, monsterStats);
                                this.dpsTracking.totalDamage[userIndex] += hpDiff;
                            }
                        }
                    }
                });
                playerIndices.forEach((userIndex) => {
                    this.dpsTracking.players[userIndex].currentAction = pMap[userIndex].abilityHrid
                        ? pMap[userIndex].abilityHrid
                        : pMap[userIndex].isAutoAtk
                            ? "auto"
                            : "idle";
                });

                this.dpsTracking.endTime = Date.now();

                setTimeout(() => this.updateDPsDisplay(), 50);
            }

            handleDPsBattleEnded(data) {
                this.dpsTracking.endTime = Date.now();
                setTimeout(() => this.updateDPsDisplay(), 100);
            }

            updateDPsContent() {
                const content = this.dpsGetContent();
                if (!content) return;
                this.dpsInvalidatePlayerCache();
                let players = this.dpsTracking.players;

                const savedMinimized = this.dpStorage.get('minimized');
                const isMinimized = savedMinimized === true || savedMinimized === 'true';
                if (this.dpsIsMinimized !== isMinimized) {
                    this.dpsIsMinimized = isMinimized;
                }

                if (!players || players.length === 0) {
                    const padding = this.dpsIsMinimized ? '10px 20px' : '40px 20px';
                    const iconSize = this.dpsIsMinimized ? '16px' : '32px';
                    const textSize = this.dpsIsMinimized ? '11px' : '13px';

                    let waitingDiv = content.querySelector('.mcs-dps-waiting');
                    if (!waitingDiv) {
                        waitingDiv = document.createElement('div');
                        waitingDiv.className = `mcs-dps-waiting ${this.dpsIsMinimized ? 'minimized' : ''}`;
                        const iconDiv = document.createElement('div');
                        iconDiv.className = `mcs-dps-waiting-icon ${this.dpsIsMinimized ? 'minimized' : ''}`;
                        iconDiv.textContent = '⏳';
                        const textDiv = document.createElement('div');
                        textDiv.className = `mcs-dps-waiting-text ${this.dpsIsMinimized ? 'minimized' : ''}`;
                        textDiv.textContent = 'Waiting for first battle to start';
                        waitingDiv.appendChild(iconDiv);
                        waitingDiv.appendChild(textDiv);

                        content.innerHTML = '';
                        content.appendChild(waitingDiv);
                    }
                    return;
                }

                const existingWaiting = content.querySelector('.mcs-dps-waiting');
                if (existingWaiting) {
                    existingWaiting.remove();
                }

                let headerDiv = content.querySelector('.mcs-dps-header-row');
                if (!headerDiv) {
                    headerDiv = document.createElement('div');
                    headerDiv.className = 'mcs-dps-header-row';

                    const charHeader = document.createElement('div');
                    charHeader.className = 'mcs-dps-header-col mcs-dps-header-char';
                    charHeader.textContent = 'Character / Ability';
                    const dpsHeader = document.createElement('div');
                    dpsHeader.className = 'mcs-dps-header-col mcs-dps-header-dps';
                    dpsHeader.textContent = 'DPS';
                    const damageHeader = document.createElement('div');
                    damageHeader.className = 'mcs-dps-header-col mcs-dps-header-damage';
                    damageHeader.textContent = 'Damage';
                    const attacksHeader = document.createElement('div');
                    attacksHeader.className = 'mcs-dps-header-col mcs-dps-header-atks';
                    attacksHeader.textContent = 'Atks';
                    const hitsHeader = document.createElement('div');
                    hitsHeader.className = 'mcs-dps-header-col mcs-dps-header-hits';
                    hitsHeader.textContent = 'Hit';
                    const critsHeader = document.createElement('div');
                    critsHeader.className = 'mcs-dps-header-col mcs-dps-header-crits';
                    critsHeader.textContent = 'Crit';
                    const missesHeader = document.createElement('div');
                    missesHeader.className = 'mcs-dps-header-col mcs-dps-header-misses';
                    missesHeader.textContent = 'Miss';
                    headerDiv.appendChild(charHeader);
                    headerDiv.appendChild(dpsHeader);
                    headerDiv.appendChild(damageHeader);
                    headerDiv.appendChild(attacksHeader);
                    headerDiv.appendChild(hitsHeader);
                    headerDiv.appendChild(critsHeader);
                    headerDiv.appendChild(missesHeader);
                    content.appendChild(headerDiv);
                }

                if (this.dpsIsMinimized) {
                    headerDiv.classList.add('mcs-hidden');
                } else {
                    headerDiv.classList.remove('mcs-hidden');
                }

                const currentUserName = this.dpsTracking.currentUserName || window.playerName || '';
                players = [...players].sort((a, b) => {
                    if (!a || !b) return 0;
                    const aIsCurrentUser = a.name === currentUserName;
                    const bIsCurrentUser = b.name === currentUserName;
                    if (aIsCurrentUser && !bIsCurrentUser) return -1;
                    if (!aIsCurrentUser && bIsCurrentUser) return 1;
                    return 0;
                });

                const validPlayers = players.filter(p => p !== null && p !== undefined);

                validPlayers.forEach((player, index) => {
                    const playerIndex = players.indexOf(player);

                    let itemDiv = content.querySelector(`[data-player-index="${playerIndex}"]`);

                    if (!itemDiv) {
                        itemDiv = document.createElement('div');
                        itemDiv.className = 'mcs-dps-player-item';
                        itemDiv.setAttribute('data-player-index', playerIndex);

                        const playerRow = document.createElement('div');
                        playerRow.className = 'mcs-dps-player-row';

                        const expandArrow = document.createElement('div');
                        expandArrow.className = 'mcs-dps-expand-arrow';

                        const nameLabel = document.createElement('div');
                        nameLabel.className = 'mcs-dps-name-label';

                        const dpsLabel = document.createElement('div');
                        dpsLabel.className = 'mcs-dps-dps-label';

                        const damageLabel = document.createElement('div');
                        damageLabel.className = 'mcs-dps-damage-label';

                        const totalAttacksLabel = document.createElement('div');
                        totalAttacksLabel.className = 'mcs-dps-total-attacks-label';

                        const totalHitsLabel = document.createElement('div');
                        totalHitsLabel.className = 'mcs-dps-total-hits-label';

                        const totalCritsLabel = document.createElement('div');
                        totalCritsLabel.className = 'mcs-dps-total-crits-label';

                        const totalMissesLabel = document.createElement('div');
                        totalMissesLabel.className = 'mcs-dps-total-misses-label';

                        playerRow.appendChild(expandArrow);
                        playerRow.appendChild(nameLabel);
                        playerRow.appendChild(dpsLabel);
                        playerRow.appendChild(damageLabel);
                        playerRow.appendChild(totalAttacksLabel);
                        playerRow.appendChild(totalHitsLabel);
                        playerRow.appendChild(totalCritsLabel);
                        playerRow.appendChild(totalMissesLabel);
                        itemDiv.appendChild(playerRow);

                        const abilityContainer = document.createElement('div');
                        abilityContainer.className = 'mcs-dps-ability-container';
                        itemDiv.appendChild(abilityContainer);

                        content.appendChild(itemDiv);
                    }

                    const playerRow = itemDiv.querySelector('.mcs-dps-player-row');
                    const expandArrow = itemDiv.querySelector('.mcs-dps-expand-arrow');
                    const nameLabel = itemDiv.querySelector('.mcs-dps-name-label');
                    const abilityContainer = itemDiv.querySelector('.mcs-dps-ability-container');

                    if (this.dpsIsMinimized) {
                        playerRow.classList.add('minimized');
                    } else {
                        playerRow.classList.remove('minimized');
                    }

                    const isLastPlayer = index === validPlayers.length - 1;
                    if (!isLastPlayer) {
                        itemDiv.classList.add('bordered');
                    } else {
                        itemDiv.classList.remove('bordered');
                    }

                    if (this.dpsIsMinimized) {
                        expandArrow.classList.add('mcs-hidden');
                    } else {
                        expandArrow.classList.remove('mcs-hidden');
                    }

                    const isPlayerExpanded = this.dpsTracking.expandedPlayers.has(playerIndex);
                    expandArrow.textContent = isPlayerExpanded ? '▼' : '▶';
                    if (!isPlayerExpanded) {
                        abilityContainer.classList.add('mcs-hidden');
                    } else {
                        abilityContainer.classList.remove('mcs-hidden');
                    }

                    if (!this.dpsIsMinimized) {
                        playerRow.onclick = () => {
                            const isExpanded = !abilityContainer.classList.contains('mcs-hidden');
                            if (isExpanded) {
                                abilityContainer.classList.add('mcs-hidden');
                                expandArrow.textContent = '▶';
                                this.dpsTracking.expandedPlayers.delete(playerIndex);
                            } else {
                                abilityContainer.classList.remove('mcs-hidden');
                                expandArrow.textContent = '▼';
                                this.dpsTracking.expandedPlayers.add(playerIndex);
                            }
                        };
                    } else {
                        playerRow.onclick = null;
                    }

                    nameLabel.textContent = player.name || 'Unknown';

                    const damageLabel = itemDiv.querySelector('.mcs-dps-damage-label');
                    const totalAttacksLabel = itemDiv.querySelector('.mcs-dps-total-attacks-label');
                    const totalHitsLabel = itemDiv.querySelector('.mcs-dps-total-hits-label');
                    const totalCritsLabel = itemDiv.querySelector('.mcs-dps-total-crits-label');
                    const totalMissesLabel = itemDiv.querySelector('.mcs-dps-total-misses-label');

                    if (this.dpsIsMinimized) {
                        damageLabel.classList.add('mcs-hidden');
                        totalAttacksLabel.classList.add('mcs-hidden');
                        totalHitsLabel.classList.add('mcs-hidden');
                        totalCritsLabel.classList.add('mcs-hidden');
                        totalMissesLabel.classList.add('mcs-hidden');
                    } else {
                        damageLabel.classList.remove('mcs-hidden');
                        totalAttacksLabel.classList.remove('mcs-hidden');
                        totalHitsLabel.classList.remove('mcs-hidden');
                        totalCritsLabel.classList.remove('mcs-hidden');
                        totalMissesLabel.classList.remove('mcs-hidden');
                    }
                });

                if (this.dpsIsMinimized) {
                    this.dpsGetPlayerItems().forEach(item => {
                        const abilityContainer = item.querySelector('.mcs-dps-ability-container');
                        if (abilityContainer) {
                            abilityContainer.classList.add('mcs-hidden');
                        }
                    });
                }

                this.updateDPsDisplay();
            }

            updateCellIfChanged(element, newValue, cacheKey, useHTML = false) {
                if (!this.dpsStateCache) {
                    this.dpsStateCache = new Map();
                }

                const cached = this.dpsStateCache.get(cacheKey);
                if (cached !== newValue) {
                    if (useHTML) {
                        element.innerHTML = newValue;
                    } else {
                        element.textContent = newValue;
                    }
                    this.dpsStateCache.set(cacheKey, newValue);
                    return true;
                }
                return false;
            }

            updateInactivityTimer() {
                const pane = document.getElementById('dps-pane');
                if (!pane || pane.classList.contains('mcs-hidden')) return;

                const timerElement = document.getElementById('dps-inactivity-timer');
                if (!timerElement) return;

                if (!this.dpsTracking.lastCombatUpdate) {
                    timerElement.textContent = '0.000s';
                    return;
                }

                const timeSinceLastUpdate = (Date.now() - this.dpsTracking.lastCombatUpdate) / 1000;
                timerElement.textContent = timeSinceLastUpdate.toFixed(3) + 's';
            }

            updateDPsDisplay() {
                const players = this.dpsTracking.players;
                const totalDamage = this.dpsTracking.totalDamage;
                if (!players || players.length === 0) {
                    const content = this.dpsGetContent();
                    if (content && content.children.length === 0) {
                        const padding = this.dpsIsMinimized ? '10px 20px' : '40px 20px';
                        const iconSize = this.dpsIsMinimized ? '16px' : '32px';
                        const textSize = this.dpsIsMinimized ? '11px' : '13px';

                        const waitingDiv = document.createElement('div');
                    waitingDiv.className = `mcs-dps-waiting ${this.dpsIsMinimized ? 'minimized' : ''}`;
                    const iconDiv = document.createElement('div');
                    iconDiv.className = `mcs-dps-waiting-icon ${this.dpsIsMinimized ? 'minimized' : ''}`;
                    iconDiv.textContent = '⏳';
                    const textDiv = document.createElement('div');
                    textDiv.className = `mcs-dps-waiting-text ${this.dpsIsMinimized ? 'minimized' : ''}`;
                    textDiv.textContent = 'Waiting for first battle to start';
                    waitingDiv.appendChild(iconDiv);
                    waitingDiv.appendChild(textDiv);
                    content.innerHTML = '';
                    content.appendChild(waitingDiv);
                    }
                    return;
                }
                let totalTime = this.dpsTracking.totalDuration;
                if (this.dpsTracking.startTime) {
                    totalTime = mcsGetElapsedSeconds(this.dpsTracking.startTime, this.dpsTracking.endTime, this.dpsTracking.savedPausedMs, totalTime);
                }
                const totalGroupDamage = totalDamage.reduce((acc, dmg) => acc + dmg, 0);
                const overallGroupDPS = totalTime > 0 ? (totalGroupDamage / totalTime).toFixed(1) : '0.0';
                const titleSpan = document.getElementById('dps-title-span');
                if (titleSpan) {
                    const titleHTML = `DPs <span class="mcs-dps-title-highlight">${overallGroupDPS}</span> <span class="mcs-dps-title-subtitle">Total Damage: ${this.formatDPsNumber(totalGroupDamage)}</span>`;
                    this.updateCellIfChanged(titleSpan, titleHTML, 'title', true);
                }

                if (this.dpsIsMinimized) {
                    const playerItems = this.dpsGetPlayerItems();
                    playerItems.forEach((item, index) => {
                        const dpsLabel = item.querySelector('.mcs-dps-dps-label');
                        if (!dpsLabel) return;

                        const damage = totalDamage[index] ?? 0;
                        const dps = totalTime > 0 ? (damage / totalTime).toFixed(1) : '0.0';

                        let accuracyStr = '--';
                        if (players[index] && players[index].hitStatsMap) {
                            let totalAttacks = 0;
                            let totalMisses = 0;

                            players[index].hitStatsMap.forEach((stats) => {
                                totalAttacks += stats.attacks ?? 0;
                                totalMisses += stats.misses ?? 0;
                            });

                            if (totalAttacks > 0) {
                                const missPercent = (totalMisses / totalAttacks) * 100;
                                accuracyStr = (100 - missPercent).toFixed(1) + '%';
                            }
                        }

                        const dpsHTML = `${dps} <span class="mcs-dps-accuracy-span">${accuracyStr}</span>`;
                        this.updateCellIfChanged(dpsLabel, dpsHTML, `min_dps_${index}`, true);
                    });
                    return;
                }

                const playerItems = this.dpsGetPlayerItems();
                playerItems.forEach((item, index) => {
                    const dpsLabel = item.querySelector('.mcs-dps-dps-label');
                    const damageLabel = item.querySelector('.mcs-dps-damage-label');
                    const totalAttacksLabel = item.querySelector('.mcs-dps-total-attacks-label');
                    const totalHitsLabel = item.querySelector('.mcs-dps-total-hits-label');
                    const totalCritsLabel = item.querySelector('.mcs-dps-total-crits-label');
                    const totalMissesLabel = item.querySelector('.mcs-dps-total-misses-label');
                    const abilityContainer = item.querySelector('.mcs-dps-ability-container');
                    if (!dpsLabel || !damageLabel || !abilityContainer) return;
                    const damage = totalDamage[index] ?? 0;
                    const dps = totalTime > 0 ? (damage / totalTime).toFixed(1) : '0.0';
                    let playerTotalAttacks = 0;
                    let playerTotalHits = 0;
                    let playerTotalCrits = 0;
                    let playerTotalMisses = 0;
                    if (players[index].hitStatsMap) {
                        players[index].hitStatsMap.forEach((stats) => {
                            playerTotalAttacks += stats.attacks;
                            playerTotalHits += stats.hits;
                            playerTotalCrits += stats.crits;
                            playerTotalMisses += stats.misses;
                        });
                    }
                    let accuracyStr = '--';
                    if (playerTotalAttacks > 0) {
                        accuracyStr = (100 - ((playerTotalMisses / playerTotalAttacks) * 100)).toFixed(1) + '%';
                    }
                    const dpsHTML = `${dps} <span class="mcs-dps-accuracy-span">${accuracyStr}</span>`;
                    this.updateCellIfChanged(dpsLabel, dpsHTML, `p${index}_dps`, true);
                    this.updateCellIfChanged(damageLabel, this.formatDPsNumber(damage), `p${index}_dmg`);
                    this.updateCellIfChanged(totalAttacksLabel, playerTotalAttacks.toString(), `p${index}_atks`);
                    const hitPercent = playerTotalAttacks > 0 ? ((playerTotalHits / playerTotalAttacks) * 100).toFixed(1) : 0;
                    this.updateCellIfChanged(totalHitsLabel, `${playerTotalHits} (${hitPercent}%)`, `p${index}_hits`);
                    const critPercent = playerTotalAttacks > 0 ? ((playerTotalCrits / playerTotalAttacks) * 100).toFixed(1) : 0;
                    this.updateCellIfChanged(totalCritsLabel, `${playerTotalCrits} (${critPercent}%)`, `p${index}_crits`);
                    const missPercent = playerTotalAttacks > 0 ? ((playerTotalMisses / playerTotalAttacks) * 100).toFixed(1) : 0;
                    this.updateCellIfChanged(totalMissesLabel, `${playerTotalMisses} (${missPercent}%)`, `p${index}_miss`);

                    if (players[index].damageMap && players[index].damageMap.size > 0) {
                        const sortedAbilities = Array.from(players[index].damageMap.entries())
                            .filter(([abilityHrid, damage]) => damage > 0)
                            .sort((a, b) => b[1] - a[1]);

                        sortedAbilities.forEach(([abilityHrid, abilityDamage]) => {
                            let abilityRow = abilityContainer.querySelector(`[data-ability="${abilityHrid}"]`);

                            if (!abilityRow) {
                                abilityRow = document.createElement('div');
                                abilityRow.className = 'mcs-dps-ability-row';
                                abilityRow.setAttribute('data-ability', abilityHrid);

                                const abilityName = document.createElement('div');
                                abilityName.className = 'mcs-dps-ability-name';
                                const displayName = abilityHrid === 'auto' ? 'Auto Attack' :
                                    abilityHrid === 'idle' ? 'Idle' :
                                        abilityHrid.split('/').pop().replace(/_/g, ' ');
                                abilityName.textContent = '  • ' + displayName;

                                const abilityDps = document.createElement('div');
                                abilityDps.className = 'mcs-dps-ability-dps';

                                const abilityDamageLabel = document.createElement('div');
                                abilityDamageLabel.className = 'mcs-dps-ability-damage';

                                const attacksLabel = document.createElement('div');
                                attacksLabel.className = 'mcs-dps-ability-attacks';

                                const hitsLabel = document.createElement('div');
                                hitsLabel.className = 'mcs-dps-ability-hits';

                                const critsLabel = document.createElement('div');
                                critsLabel.className = 'mcs-dps-ability-crits';

                                const missesLabel = document.createElement('div');
                                missesLabel.className = 'mcs-dps-ability-misses';

                                abilityRow.appendChild(abilityName);
                                abilityRow.appendChild(abilityDps);
                                abilityRow.appendChild(abilityDamageLabel);
                                abilityRow.appendChild(attacksLabel);
                                abilityRow.appendChild(hitsLabel);
                                abilityRow.appendChild(critsLabel);
                                abilityRow.appendChild(missesLabel);

                                const firstMonster = abilityContainer.querySelector('[data-monster-header]');
                                if (firstMonster) {
                                    abilityContainer.insertBefore(abilityRow, firstMonster);
                                } else {
                                    abilityContainer.appendChild(abilityRow);
                                }
                            }

                            const abilityDps = abilityRow.querySelector('.mcs-dps-ability-dps');
                            const abilityDamageLabel = abilityRow.querySelector('.mcs-dps-ability-damage');
                            const attacksLabel = abilityRow.querySelector('.mcs-dps-ability-attacks');
                            const hitsLabel = abilityRow.querySelector('.mcs-dps-ability-hits');
                            const critsLabel = abilityRow.querySelector('.mcs-dps-ability-crits');
                            const missesLabel = abilityRow.querySelector('.mcs-dps-ability-misses');

                            const abilityDpsValue = totalTime > 0 ? (abilityDamage / totalTime).toFixed(1) : '0.0';
                            this.updateCellIfChanged(abilityDps, abilityDpsValue, `p${index}_ability_${abilityHrid}_dps`);

                            const hitStats = players[index].hitStatsMap?.get(abilityHrid) ?? {
                                attacks: 0,
                                hits: 0,
                                crits: 0,
                                misses: 0
                            };

                            const damagePercent = damage > 0 ? ((abilityDamage / damage) * 100).toFixed(1) : 0;
                            const damageText = this.formatDPsNumber(abilityDamage) + ` (${damagePercent}%)`;
                            this.updateCellIfChanged(abilityDamageLabel, damageText, `p${index}_ability_${abilityHrid}_dmg`);

                            this.updateCellIfChanged(attacksLabel, hitStats.attacks.toString(), `p${index}_ability_${abilityHrid}_atks`);

                            const hitPercent = hitStats.attacks > 0 ? ((hitStats.hits / hitStats.attacks) * 100).toFixed(1) : 0;
                            const hitsText = `${hitStats.hits} (${hitPercent}%)`;
                            this.updateCellIfChanged(hitsLabel, hitsText, `p${index}_ability_${abilityHrid}_hits`);

                            const critPercent = hitStats.attacks > 0 ? ((hitStats.crits / hitStats.attacks) * 100).toFixed(1) : 0;
                            const critsText = `${hitStats.crits} (${critPercent}%)`;
                            this.updateCellIfChanged(critsLabel, critsText, `p${index}_ability_${abilityHrid}_crits`);

                            const missPercent = hitStats.attacks > 0 ? ((hitStats.misses / hitStats.attacks) * 100).toFixed(1) : 0;
                            const missesText = `${hitStats.misses} (${missPercent}%)`;
                            this.updateCellIfChanged(missesLabel, missesText, `p${index}_ability_${abilityHrid}_miss`);
                        });
                    }

                    if (players[index].monsterDamageMap && players[index].monsterDamageMap.size > 0) {

                        players[index].monsterDamageMap.forEach((abilityMap, monsterName) => {
                            let monsterHeaderRow = abilityContainer.querySelector(`[data-monster-header="${monsterName}"]`);
                            let monsterAbilityContainer = abilityContainer.querySelector(`[data-monster-container="${monsterName}"]`);

                            let monsterTotalDamage = 0;
                            let monsterTotalAttacks = 0;
                            let monsterTotalHits = 0;
                            let monsterTotalCrits = 0;
                            let monsterTotalMisses = 0;
                            abilityMap.forEach((dmg) => {
                                monsterTotalDamage += dmg;
                            });
                            const monsterHitStatsMap = players[index].monsterHitStatsMap?.get(monsterName);
                            if (monsterHitStatsMap) {
                                monsterHitStatsMap.forEach((stats) => {
                                    monsterTotalAttacks += stats.attacks;
                                    monsterTotalHits += stats.hits;
                                    monsterTotalCrits += stats.crits;
                                    monsterTotalMisses += stats.misses;
                                });
                            }

                            if (!monsterHeaderRow) {
                                monsterHeaderRow = document.createElement('div');
                                monsterHeaderRow.className = 'mcs-dps-monster-header';
                                monsterHeaderRow.setAttribute('data-monster-header', monsterName);

                                const monsterExpandArrow = document.createElement('div');
                                monsterExpandArrow.className = 'mcs-dps-monster-arrow';

                                const monsterNameLabel = document.createElement('div');
                                monsterNameLabel.className = 'mcs-dps-monster-name';
                                monsterNameLabel.textContent = monsterName;

                                const monsterDpsLabel = document.createElement('div');
                                monsterDpsLabel.className = 'mcs-dps-monster-dps';

                                const monsterDamageLabel = document.createElement('div');
                                monsterDamageLabel.className = 'mcs-dps-monster-damage';

                                const monsterAttacksLabel = document.createElement('div');
                                monsterAttacksLabel.className = 'mcs-dps-monster-attacks';

                                const monsterHitsLabel = document.createElement('div');
                                monsterHitsLabel.className = 'mcs-dps-monster-hits';

                                const monsterCritsLabel = document.createElement('div');
                                monsterCritsLabel.className = 'mcs-dps-monster-crits';

                                const monsterMissesLabel = document.createElement('div');
                                monsterMissesLabel.className = 'mcs-dps-monster-misses';

                                monsterHeaderRow.appendChild(monsterExpandArrow);
                                monsterHeaderRow.appendChild(monsterNameLabel);
                                monsterHeaderRow.appendChild(monsterDpsLabel);
                                monsterHeaderRow.appendChild(monsterDamageLabel);
                                monsterHeaderRow.appendChild(monsterAttacksLabel);
                                monsterHeaderRow.appendChild(monsterHitsLabel);
                                monsterHeaderRow.appendChild(monsterCritsLabel);
                                monsterHeaderRow.appendChild(monsterMissesLabel);
                                abilityContainer.appendChild(monsterHeaderRow);

                                monsterAbilityContainer = document.createElement('div');
                                monsterAbilityContainer.className = 'mcs-dps-monster-ability-container';
                                monsterAbilityContainer.setAttribute('data-monster-container', monsterName);

                                if (!this.dpsTracking.expandedMonsters.has(index)) {
                                    this.dpsTracking.expandedMonsters.set(index, new Set());
                                }
                                const isMonsterExpanded = this.dpsTracking.expandedMonsters.get(index).has(monsterName);
                                if (!isMonsterExpanded) {
                                    monsterAbilityContainer.classList.add('mcs-hidden');
                                }
                                monsterExpandArrow.textContent = isMonsterExpanded ? '▼' : '▶';

                                monsterHeaderRow.onclick = (e) => {
                                    e.stopPropagation();
                                    const isExpanded = !monsterAbilityContainer.classList.contains('mcs-hidden');
                                    const arrow = monsterHeaderRow.querySelector('.mcs-dps-monster-arrow');
                                    if (isExpanded) {
                                        monsterAbilityContainer.classList.add('mcs-hidden');
                                        arrow.textContent = '▶';
                                    } else {
                                        monsterAbilityContainer.classList.remove('mcs-hidden');
                                        arrow.textContent = '▼';
                                    }
                                    const playerMonsters = this.dpsTracking.expandedMonsters.get(index);
                                    if (isExpanded) {
                                        playerMonsters.delete(monsterName);
                                    } else {
                                        playerMonsters.add(monsterName);
                                    }
                                };

                                abilityContainer.appendChild(monsterAbilityContainer);
                            }

                            const monsterDpsLabel = monsterHeaderRow.querySelector('.mcs-dps-monster-dps');
                            const monsterDamageLabel = monsterHeaderRow.querySelector('.mcs-dps-monster-damage');
                            const monsterAttacksLabel = monsterHeaderRow.querySelector('.mcs-dps-monster-attacks');
                            const monsterHitsLabel = monsterHeaderRow.querySelector('.mcs-dps-monster-hits');
                            const monsterCritsLabel = monsterHeaderRow.querySelector('.mcs-dps-monster-crits');
                            const monsterMissesLabel = monsterHeaderRow.querySelector('.mcs-dps-monster-misses');

                            const monsterDpsValue = totalTime > 0 ? (monsterTotalDamage / totalTime).toFixed(1) : '0.0';
                            this.updateCellIfChanged(monsterDpsLabel, monsterDpsValue, `p${index}_monster_${monsterName}_dps`);

                            const monsterDamagePercent = damage > 0 ? ((monsterTotalDamage / damage) * 100).toFixed(1) : 0;
                            const monsterDamageText = this.formatDPsNumber(monsterTotalDamage) + ` (${monsterDamagePercent}%)`;
                            this.updateCellIfChanged(monsterDamageLabel, monsterDamageText, `p${index}_monster_${monsterName}_dmg`);

                            this.updateCellIfChanged(monsterAttacksLabel, monsterTotalAttacks.toString(), `p${index}_monster_${monsterName}_atks`);

                            const monsterHitPercent = monsterTotalAttacks > 0 ? ((monsterTotalHits / monsterTotalAttacks) * 100).toFixed(1) : 0;
                            const monsterHitsText = `${monsterTotalHits} (${monsterHitPercent}%)`;
                            this.updateCellIfChanged(monsterHitsLabel, monsterHitsText, `p${index}_monster_${monsterName}_hits`);

                            const monsterCritPercent = monsterTotalAttacks > 0 ? ((monsterTotalCrits / monsterTotalAttacks) * 100).toFixed(1) : 0;
                            const monsterCritsText = `${monsterTotalCrits} (${monsterCritPercent}%)`;
                            this.updateCellIfChanged(monsterCritsLabel, monsterCritsText, `p${index}_monster_${monsterName}_crits`);

                            const monsterMissPercent = monsterTotalAttacks > 0 ? ((monsterTotalMisses / monsterTotalAttacks) * 100).toFixed(1) : 0;
                            const monsterMissesText = `${monsterTotalMisses} (${monsterMissPercent}%)`;
                            this.updateCellIfChanged(monsterMissesLabel, monsterMissesText, `p${index}_monster_${monsterName}_miss`);
                            const sortedMonsterAbilities = Array.from(abilityMap.entries())
                                .filter(([abilityHrid, damage]) => damage > 0)
                                .sort((a, b) => b[1] - a[1]);

                            const activeAbilityHrids = new Set(sortedMonsterAbilities.map(([h]) => h));

                            const existingRows = monsterAbilityContainer.querySelectorAll('[data-monster-ability]');
                            existingRows.forEach(row => {
                                if (!activeAbilityHrids.has(row.getAttribute('data-monster-ability'))) {
                                    row.remove();
                                }
                            });

                            sortedMonsterAbilities.forEach(([abilityHrid, abilityDamage]) => {
                                let monsterAbilityRow = monsterAbilityContainer.querySelector(`[data-monster-ability="${abilityHrid}"]`);

                                if (!monsterAbilityRow) {
                                    monsterAbilityRow = document.createElement('div');
                                    monsterAbilityRow.className = 'mcs-dps-monster-ability-row';
                                    monsterAbilityRow.setAttribute('data-monster-ability', abilityHrid);

                                    const abilityName = document.createElement('div');
                                    abilityName.className = 'mcs-dps-monster-ability-name';
                                    const displayName = abilityHrid === 'auto' ? 'Auto Attack' :
                                        abilityHrid === 'idle' ? 'Idle' :
                                            abilityHrid.split('/').pop().replace(/_/g, ' ');
                                    abilityName.textContent = '    • ' + displayName;

                                    const abilityDpsEl = document.createElement('div');
                                    abilityDpsEl.className = 'mcs-dps-monster-ability-dps';

                                    const abilityDamageLabel = document.createElement('div');
                                    abilityDamageLabel.className = 'mcs-dps-monster-ability-damage';

                                    const attacksLabel = document.createElement('div');
                                    attacksLabel.className = 'mcs-dps-monster-ability-attacks';

                                    const hitsLabel = document.createElement('div');
                                    hitsLabel.className = 'mcs-dps-monster-ability-hits';

                                    const critsLabel = document.createElement('div');
                                    critsLabel.className = 'mcs-dps-monster-ability-crits';

                                    const missesLabel = document.createElement('div');
                                    missesLabel.className = 'mcs-dps-monster-ability-misses';

                                    monsterAbilityRow.appendChild(abilityName);
                                    monsterAbilityRow.appendChild(abilityDpsEl);
                                    monsterAbilityRow.appendChild(abilityDamageLabel);
                                    monsterAbilityRow.appendChild(attacksLabel);
                                    monsterAbilityRow.appendChild(hitsLabel);
                                    monsterAbilityRow.appendChild(critsLabel);
                                    monsterAbilityRow.appendChild(missesLabel);
                                    monsterAbilityContainer.appendChild(monsterAbilityRow);
                                }

                                const cachePrefix = `p${index}_ma_${monsterName}_${abilityHrid}`;
                                const abilityDpsEl = monsterAbilityRow.querySelector('.mcs-dps-monster-ability-dps');
                                const abilityDamageLabel = monsterAbilityRow.querySelector('.mcs-dps-monster-ability-damage');
                                const attacksLabel = monsterAbilityRow.querySelector('.mcs-dps-monster-ability-attacks');
                                const hitsLabel = monsterAbilityRow.querySelector('.mcs-dps-monster-ability-hits');
                                const critsLabel = monsterAbilityRow.querySelector('.mcs-dps-monster-ability-crits');
                                const missesLabel = monsterAbilityRow.querySelector('.mcs-dps-monster-ability-misses');

                                const abilityDpsValue = totalTime > 0 ? (abilityDamage / totalTime).toFixed(1) : '0.0';
                                this.updateCellIfChanged(abilityDpsEl, abilityDpsValue, `${cachePrefix}_dps`);

                                const damagePercent = monsterTotalDamage > 0 ? ((abilityDamage / monsterTotalDamage) * 100).toFixed(1) : 0;
                                this.updateCellIfChanged(abilityDamageLabel, this.formatDPsNumber(abilityDamage) + ` (${damagePercent}%)`, `${cachePrefix}_dmg`);

                                const monsterHitStatsMap = players[index].monsterHitStatsMap?.get(monsterName);
                                const hitStats = monsterHitStatsMap?.get(abilityHrid) ?? {
                                    attacks: 0, hits: 0, crits: 0, misses: 0
                                };

                                this.updateCellIfChanged(attacksLabel, hitStats.attacks.toString(), `${cachePrefix}_atks`);

                                const hitPercent = hitStats.attacks > 0 ? ((hitStats.hits / hitStats.attacks) * 100).toFixed(1) : 0;
                                this.updateCellIfChanged(hitsLabel, `${hitStats.hits} (${hitPercent}%)`, `${cachePrefix}_hits`);

                                const critPercent = hitStats.attacks > 0 ? ((hitStats.crits / hitStats.attacks) * 100).toFixed(1) : 0;
                                this.updateCellIfChanged(critsLabel, `${hitStats.crits} (${critPercent}%)`, `${cachePrefix}_crits`);

                                const missPercent = hitStats.attacks > 0 ? ((hitStats.misses / hitStats.attacks) * 100).toFixed(1) : 0;
                                this.updateCellIfChanged(missesLabel, `${hitStats.misses} (${missPercent}%)`, `${cachePrefix}_miss`);
                            });
                        });
                    }
                });
                if (this.dpsIsMinimized) {
                    const filterBtn = document.getElementById('dps-filter-btn');
                    const infoBtn = document.getElementById('dps-info-btn');
                    const resetBtn = document.getElementById('dps-reset-btn');
                    if (filterBtn) filterBtn.classList.add('mcs-hidden');
                    if (infoBtn) infoBtn.classList.add('mcs-hidden');
                    if (resetBtn) resetBtn.classList.add('mcs-hidden');
                    const headerDiv = this.dpsGetContent()?.querySelector(':scope > div:first-child');
                    if (headerDiv) {
                        headerDiv.classList.add('mcs-hidden');
                    }
                    this.dpsGetPlayerItems().forEach(item => {
                        const abilityContainer = item.querySelector('.mcs-dps-ability-container');
                        if (abilityContainer) {
                            abilityContainer.classList.add('mcs-hidden');
                        }
                        const playerRow = item.querySelector('.mcs-dps-player-row');
                        if (playerRow) {
                            const children = Array.from(playerRow.children);
                            children.forEach((child, index) => {
                                if (index === 0 || index >= 3) {
                                    child.classList.add('mcs-hidden');
                                }
                            });
                            playerRow.classList.add('minimized');
                            playerRow.onclick = null;
                        }
                    });
                }
                const content = this.dpsGetContent();
                if (content) {
                    if (!this.dpsIsMinimized) {
                        this.renderTrueDPSSection(content);
                    } else {
                        const truedpsSection = document.getElementById('dps-truedps-section');
                        if (truedpsSection) truedpsSection.classList.add('mcs-hidden');
                    }
                }
            }

            formatDPsNumber(num) {
                return mcsFormatCurrency(num, 'dps');
            }

            handleTrueDPSNewBattle(data) {
                if (!this.trueDPSTracking.startTime) {
                    this.trueDPSTracking.startTime = Date.now();
                }
                this.trueDPSTracking.monsters = data.monsters ?? [];
                this.trueDPSTracking.monstersHP = data.monsters.map((monster) => monster.currentHitpoints);
                this.trueDPSTracking.monstersDmgCounter = data.monsters.map((monster) => monster.damageSplatCounter);
                data.monsters.forEach((monster, index) => {
                    const monsterName = monster.name || `Monster ${index + 1}`;
                    this.trueDPSTracking.monsterMaxHP[index] = monster.maxHitpoints;
                    if (!this.trueDPSTracking.enemyKills[monsterName]) {
                        this.trueDPSTracking.enemyKills[monsterName] = {
                            kills: 0,
                            maxHP: monster.maxHitpoints,
                            totalDamage: 0
                        };
                    }
                });
            }

            handleTrueDPSBattleUpdate(data) {
                if (!this.trueDPSTracking.monstersHP || this.trueDPSTracking.monstersHP.length === 0) {
                    return;
                }
                const mMap = data.mMap;
                this.trueDPSTracking.monstersHP.forEach((prevHP, mIndex) => {
                    const monster = mMap[mIndex];
                    if (!monster) return;
                    const currentHP = monster.cHP;
                    const monsterName = this.trueDPSTracking.monsters[mIndex]?.name || `Monster ${mIndex + 1}`;
                    if (prevHP > 0 && currentHP === 0) {
                        if (!this.trueDPSTracking.enemyKills[monsterName]) {
                            this.trueDPSTracking.enemyKills[monsterName] = {
                                kills: 0,
                                maxHP: this.trueDPSTracking.monsterMaxHP[mIndex] ?? prevHP,
                                totalDamage: 0
                            };
                        }
                        const maxHP = this.trueDPSTracking.monsterMaxHP[mIndex] ?? prevHP;
                        this.trueDPSTracking.enemyKills[monsterName].kills++;
                        this.trueDPSTracking.enemyKills[monsterName].totalDamage += maxHP;
                        this.trueDPSTracking.enemyKills[monsterName].maxHP = maxHP;
                    }
                    this.trueDPSTracking.monstersHP[mIndex] = currentHP;
                    this.trueDPSTracking.monstersDmgCounter[mIndex] = monster.dmgCounter;
                });
            }

            renderTrueDPSSection(content) {
                let existingSection = document.getElementById('dps-truedps-section');
                if (existingSection) {
                    existingSection.remove();
                }

                const tracking = this.trueDPSTracking;
                let elapsedSeconds = mcsGetElapsedSeconds(tracking.startTime, null, tracking.savedPausedMs, 0);

                let totalKills = 0;
                let totalDamage = 0;
                Object.values(tracking.enemyKills).forEach(enemy => {
                    totalKills += enemy.kills;
                    totalDamage += enemy.totalDamage;
                });

                const trueDPS = elapsedSeconds > 0 ? (totalDamage / elapsedSeconds) : 0;

                const section = document.createElement('div');
                section.id = 'dps-truedps-section';
                section.className = 'mcs-dps-truedps-section';

                const headerRow = document.createElement('div');
                headerRow.className = 'mcs-dps-truedps-header';

                const title = document.createElement('span');
                title.textContent = 'DPS based off enemy HPs';
                title.className = 'mcs-dps-truedps-title';

                let battleTime = this.dpsTracking.totalDuration;
                if (this.dpsTracking.startTime) {
                    battleTime = mcsGetElapsedSeconds(this.dpsTracking.startTime, this.dpsTracking.endTime, this.dpsTracking.savedPausedMs, battleTime);
                }

                const battleDPS = battleTime > 0 ? (totalDamage / battleTime) : 0;

                const dpsContainer = document.createElement('div');
                dpsContainer.className = 'mcs-dps-truedps-container';

                const totalTimeDPSContainer = document.createElement('div');
                totalTimeDPSContainer.className = 'mcs-dps-truedps-value-container';

                const totalTimeDPSValue = document.createElement('div');
                totalTimeDPSValue.textContent = trueDPS.toFixed(1);
                totalTimeDPSValue.className = 'mcs-dps-truedps-value';

                const totalTimeLabel = document.createElement('div');
                totalTimeLabel.textContent = 'total time DPS';
                totalTimeLabel.className = 'mcs-dps-truedps-label';

                totalTimeDPSContainer.appendChild(totalTimeDPSValue);
                totalTimeDPSContainer.appendChild(totalTimeLabel);

                const battleTimeDPSContainer = document.createElement('div');
                battleTimeDPSContainer.className = 'mcs-dps-truedps-value-container';

                const battleTimeDPSValue = document.createElement('div');
                battleTimeDPSValue.textContent = battleDPS.toFixed(1);
                battleTimeDPSValue.className = 'mcs-dps-truedps-value';

                const battleTimeLabel = document.createElement('div');
                battleTimeLabel.textContent = 'battle time DPS';
                battleTimeLabel.className = 'mcs-dps-truedps-label';

                battleTimeDPSContainer.appendChild(battleTimeDPSValue);
                battleTimeDPSContainer.appendChild(battleTimeLabel);

                const dpsLoss = battleDPS - trueDPS;

                const dpsLossContainer = document.createElement('div');
                dpsLossContainer.className = 'mcs-dps-truedps-value-container';

                const dpsLossValue = document.createElement('div');
                dpsLossValue.textContent = dpsLoss.toFixed(1);
                dpsLossValue.className = 'mcs-dps-loss-value';

                const dpsLossLabel = document.createElement('div');
                dpsLossLabel.textContent = 'DPS loss between battles';
                dpsLossLabel.className = 'mcs-dps-truedps-label';

                dpsLossContainer.appendChild(dpsLossValue);
                dpsLossContainer.appendChild(dpsLossLabel);

                dpsContainer.appendChild(totalTimeDPSContainer);
                dpsContainer.appendChild(battleTimeDPSContainer);
                dpsContainer.appendChild(dpsLossContainer);

                headerRow.appendChild(title);
                headerRow.appendChild(dpsContainer);
                section.appendChild(headerRow);

                const subtitle = document.createElement('div');
                subtitle.textContent = 'Based on Enemy\'s max HP only';
                subtitle.className = 'mcs-dps-truedps-subtitle';
                section.appendChild(subtitle);

                const statsRow = document.createElement('div');
                statsRow.className = 'mcs-dps-truedps-stats';

                const timeDiv = document.createElement('div');
                timeDiv.innerHTML = `<span class="mcs-dps-stat-label">Time Logging:</span> <span class="mcs-dps-stat-time">${elapsedSeconds.toFixed(1)}s</span>`;

                const battleTimeDiv = document.createElement('div');
                battleTimeDiv.innerHTML = `<span class="mcs-dps-stat-label">Time in Battle:</span> <span class="mcs-dps-stat-time">${battleTime.toFixed(1)}s</span>`;

                const damageDiv = document.createElement('div');
                damageDiv.innerHTML = `<span class="mcs-dps-stat-label">Total Damage:</span> <span class="mcs-dps-stat-damage">${this.formatDPsNumber(totalDamage)}</span>`;

                const killsDiv = document.createElement('div');
                killsDiv.innerHTML = `<span class="mcs-dps-stat-label">Total Enemies Killed:</span> <span class="mcs-dps-stat-kills">${totalKills}</span>`;

                statsRow.appendChild(timeDiv);
                statsRow.appendChild(battleTimeDiv);
                statsRow.appendChild(damageDiv);
                statsRow.appendChild(killsDiv);
                section.appendChild(statsRow);

                if (Object.keys(tracking.enemyKills).length > 0) {
                    const enemyGrid = document.createElement('div');
                    enemyGrid.className = 'mcs-dps-enemy-grid';

                    const sortedEnemies = Object.entries(tracking.enemyKills).sort((a, b) => b[1].totalDamage - a[1].totalDamage);

                    sortedEnemies.forEach(([enemyName, data]) => {
                        const enemyBox = document.createElement('div');
                        enemyBox.className = 'mcs-dps-enemy-box';

                        const nameDiv = document.createElement('div');
                        nameDiv.textContent = enemyName;
                        nameDiv.className = 'mcs-dps-enemy-name';

                        const statsDiv = document.createElement('div');
                        statsDiv.className = 'mcs-dps-enemy-stats';
                        statsDiv.innerHTML = `${data.kills} kills × ${this.formatDPsNumber(data.maxHP)} HP = <span class="mcs-dps-enemy-damage">${this.formatDPsNumber(data.totalDamage)}</span>`;

                        enemyBox.appendChild(nameDiv);
                        enemyBox.appendChild(statsDiv);
                        enemyGrid.appendChild(enemyBox);
                    });

                    section.appendChild(enemyGrid);
                }

                content.appendChild(section);
            }

            makeDPsDraggable(pane, header) {
                DragHandler.makeDraggable(pane, header, 'mcs_DP');
            }

            destroyDPs() {
                VisibilityManager.clear('dps-update');
                VisibilityManager.clear('dps-inactivity-timer');
                if (this._dpsWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._dpsWsListener); this._dpsWsListener = null; }
                const pane = document.getElementById('dps-pane');
                if (pane) pane.remove();
            }

// DPs end

// BRead start

            get brStorage() {
                if (!this._brStorage) {
                    this._brStorage = createModuleStorage('BR');
                }
                return this._brStorage;
            }

            breadGetAbilityItems() {
                const content = document.getElementById('bread-content');
                if (!content) return [];
                if (this._breadCachedAbilityItems && this._breadLastCacheVersion === this._breadAbilityCacheVersion) {
                    return this._breadCachedAbilityItems;
                }
                this._breadCachedAbilityItems = content.querySelectorAll('.bread-ability-item');
                this._breadLastCacheVersion = this._breadAbilityCacheVersion;
                return this._breadCachedAbilityItems;
            }

            breadInvalidateAbilityCache() {
                if (!this._breadAbilityCacheVersion) this._breadAbilityCacheVersion = 0;
                this._breadAbilityCacheVersion++;
                this._breadCachedAbilityItems = null;
            }

            breadHandleWebSocketMessage(event) {
                if (window.MCS_MODULES_DISABLED) return;
                const data = event.detail;
                if (data?.type === 'action_completed' && data.endCharacterAbilities) {
                    for (const ability of data.endCharacterAbilities) {
                        this.breadCurrentAbilityExp[ability.abilityHrid] = {
                            level: ability.level,
                            experience: ability.experience
                        };
                    }
                    setTimeout(() => this.updateBReadExperience(), 100);
                }
                if (data?.type === 'init_character_data' && data.characterAbilities) {
                    for (const ability of Object.values(data.characterAbilities)) {
                        this.breadCurrentAbilityExp[ability.abilityHrid] = {
                            level: ability.level,
                            experience: ability.experience
                        };
                    }
                    setTimeout(() => this.updateBReadExperience(), 100);
                }
                if (data?.characterAbilities && data.type !== 'init_character_data') {
                    for (const ability of Object.values(data.characterAbilities)) {
                        this.breadCurrentAbilityExp[ability.abilityHrid] = {
                            level: ability.level,
                            experience: ability.experience
                        };
                    }
                    setTimeout(() => this.updateBReadExperience(), 100);
                }
                if (data?.type === 'abilities_updated' && data.endCharacterAbilities) {
                    const currentAbilityHrids = new Set(
                        Array.from(document.querySelectorAll('#bread-content .bread-ability-item[data-ability-hrid]'))
                            .map(el => el.getAttribute('data-ability-hrid'))
                    );

                    for (const ability of data.endCharacterAbilities) {
                        this.breadCurrentAbilityExp[ability.abilityHrid] = {
                            level: ability.level,
                            experience: ability.experience
                        };
                    }

                    const cachedData = CharacterDataStorage.get();
                    if (cachedData?.combatUnit) {
                        const abilityMap = new Map();
                        for (const a of (cachedData.combatUnit.combatAbilities || [])) {
                            abilityMap.set(a.abilityHrid, a);
                        }
                        for (const ability of data.endCharacterAbilities) {
                            if (ability.slotNumber > 0) {
                                abilityMap.set(ability.abilityHrid, ability);
                            } else {
                                abilityMap.delete(ability.abilityHrid);
                            }
                        }
                        cachedData.combatUnit.combatAbilities = Array.from(abilityMap.values());
                    }

                    const updatedHrids = new Set(
                        (cachedData?.combatUnit?.combatAbilities || []).map(a => a.abilityHrid)
                    );
                    const abilitiesActuallyChanged = currentAbilityHrids.size !== updatedHrids.size ||
                        [...currentAbilityHrids].some(h => !updatedHrids.has(h));

                    if (abilitiesActuallyChanged) {
                        this.breadExpTracking = {};
                        setTimeout(() => {
                            this.updateBReadContent();
                            this.updateBReadExperience();
                        }, 100);
                    } else {
                        for (const ability of data.endCharacterAbilities) {
                            if (this.breadExpTracking[ability.abilityHrid]) {
                                this.breadExpTracking[ability.abilityHrid] = {
                                    startExp: ability.experience,
                                    startTime: Date.now(),
                                    lastExp: ability.experience,
                                    lastUpdateTime: Date.now(),
                                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                                    savedTabHiddenMs: window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0
                                };
                            }
                        }
                        setTimeout(() => this.updateBReadExperience(), 100);
                    }
                }
                if (data?.type === 'new_battle' && data.players) {
                    const cachedData = CharacterDataStorage.get();
                    const myName = cachedData?.character?.name;
                    if (myName) {
                        const me = data.players.find(p => p.character?.name === myName);
                        if (me?.combatDetails?.combatAbilities) {
                            const newAbilities = me.combatDetails.combatAbilities;
                            const currentAbilityHrids = new Set(
                                Array.from(document.querySelectorAll('#bread-content .bread-ability-item[data-ability-hrid]'))
                                    .map(el => el.getAttribute('data-ability-hrid'))
                            );
                            const newAbilityHrids = new Set(newAbilities.map(a => a.abilityHrid));
                            const abilitiesChanged = currentAbilityHrids.size !== newAbilityHrids.size ||
                                [...currentAbilityHrids].some(h => !newAbilityHrids.has(h));
                            if (abilitiesChanged) {
                                if (cachedData?.combatUnit) {
                                    cachedData.combatUnit.combatAbilities = newAbilities;
                                }
                                this.breadExpTracking = {};
                                setTimeout(() => {
                                    this.updateBReadContent();
                                    this.updateBReadExperience();
                                }, 100);
                            }
                        }
                    }
                }
            }

            formatBReadCoins(value) {
                return mcsFormatCurrency(value, 'precise');
            }

            createBReadPane() {
                if (document.getElementById('bread-pane')) return;
                const pane = document.createElement('div');
                pane.id = 'bread-pane';
                registerPanel('bread-pane');
                pane.className = 'mcs-pane mcs-bread-pane';
                const header = document.createElement('div');
                header.className = 'mcs-pane-header mcs-bread-header';
                const titleSection = document.createElement('div');
                this.applyClass(titleSection, 'mcs-bread-title-section');

                const titleSpan = document.createElement('span');
                titleSpan.className = 'mcs-pane-title';
                titleSpan.textContent = 'BRead';

                const headerInfo = document.createElement('span');
                headerInfo.id = 'bread-header-info';
                this.applyClass(headerInfo, 'mcs-bread-header-info');

                titleSection.appendChild(titleSpan);
                titleSection.appendChild(headerInfo);

                const buttonSection = document.createElement('div');
                buttonSection.className = 'mcs-button-section';
                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'bread-minimize-btn';
                minimizeBtn.className = 'mcs-btn mcs-btn-minimize';
                minimizeBtn.textContent = '−';
                const resetBtn = document.createElement('button');
                resetBtn.id = 'bread-reset-btn';
                resetBtn.className = 'mcs-btn mcs-btn-small';
                resetBtn.textContent = 'Reset';
                buttonSection.appendChild(resetBtn);
                buttonSection.appendChild(minimizeBtn);
                header.appendChild(titleSection);
                header.appendChild(buttonSection);

                const rangeCalc = document.createElement('div');
                rangeCalc.id = 'bread-range-calc';
                rangeCalc.className = 'mcs-bread-range-calc';

                const minLevelInput = document.createElement('input');
                minLevelInput.id = 'bread-min-level';
                minLevelInput.type = 'number';
                minLevelInput.min = '1';
                minLevelInput.max = '199';
                minLevelInput.value = '1';
                minLevelInput.className = 'mcs-bread-range-input';
                minLevelInput.placeholder = 'Min';

                const maxLevelInput = document.createElement('input');
                maxLevelInput.id = 'bread-max-level';
                maxLevelInput.type = 'number';
                maxLevelInput.min = '2';
                maxLevelInput.max = '200';
                maxLevelInput.value = '100';
                maxLevelInput.className = 'mcs-bread-range-input';
                maxLevelInput.placeholder = 'Max';

                const calcBtn = document.createElement('button');
                calcBtn.id = 'bread-calc-btn';
                calcBtn.className = 'mcs-btn mcs-btn-small';
                calcBtn.textContent = 'How many Books?';

                const rangeResult = document.createElement('div');
                rangeResult.id = 'bread-range-result';
                rangeResult.className = 'mcs-bread-range-result';

                rangeCalc.appendChild(minLevelInput);
                rangeCalc.appendChild(maxLevelInput);
                rangeCalc.appendChild(calcBtn);
                rangeCalc.appendChild(rangeResult);

                const content = document.createElement('div');
                content.id = 'bread-content';
                content.className = 'mcs-pane-content mcs-bread-content';
                pane.appendChild(header);
                pane.appendChild(rangeCalc);
                pane.appendChild(content);
                document.body.appendChild(pane);
                this.makeBReadDraggable(pane, header);
                this.breadExpTracking = {};
                this.breadCurrentAbilityExp = {};
                this.breadCachedLevelExpTable = null;
                this.breadCachedItemDetailMap = null;
                const savedBreadMinimized = this.brStorage.get('minimized');
                this.breadIsMinimized = savedBreadMinimized === true || savedBreadMinimized === 'true';
                if (this.breadIsMinimized) {
                    content.classList.add('mcs-hidden');
                    pane.classList.add('mcs-width-fit', 'mcs-height-auto');
                    minimizeBtn.textContent = '+';
                    header.classList.add('minimized');
                    rangeCalc.classList.add('mcs-hidden');
                }
                this.updateBReadContent();
                minimizeBtn.onclick = () => {
                    this.breadIsMinimized = !this.breadIsMinimized;
                    if (this.breadIsMinimized) {
                        content.classList.add('mcs-hidden');
                        content.classList.remove('mcs-display-flex');
                        pane.classList.add('mcs-width-fit', 'mcs-height-auto');
                        minimizeBtn.textContent = '+';
                        header.classList.add('minimized');
                        rangeCalc.classList.add('mcs-hidden');
                        this.brStorage.set('minimized', true);
                    } else {
                        content.classList.remove('mcs-hidden');
                        content.classList.add('mcs-display-flex');
                        pane.classList.add('mcs-width-fit', 'mcs-height-auto');
                        minimizeBtn.textContent = '−';
                        header.classList.remove('minimized');
                        rangeCalc.classList.remove('mcs-hidden');
                        this.brStorage.set('minimized', false);
                        this.constrainPanelToBoundaries('bread-pane', 'mcs_BR', true);
                    }
                };
                calcBtn.onclick = () => {
                    const minLevel = parseInt(document.getElementById('bread-min-level')?.value || 1);
                    const maxLevel = parseInt(document.getElementById('bread-max-level')?.value || 100);
                    const rangeResult = document.getElementById('bread-range-result');

                    if (rangeResult && minLevel < maxLevel && minLevel >= 1 && maxLevel <= 200) {
                        const levelExperienceTable = InitClientDataCache.getLevelExperienceTable();
                        if (levelExperienceTable) {
                            const startExp = levelExperienceTable[minLevel];
                            const endExp = levelExperienceTable[maxLevel];
                            const totalExpNeeded = endExp - startExp;

                            const booksFor50xp = Math.ceil(totalExpNeeded / 50);
                            const booksFor500xp = Math.ceil(totalExpNeeded / 500);

                rangeResult.innerHTML = `
                    <div>Level ${minLevel} → ${maxLevel}</div>
                    <div>50xp/book: <strong>${booksFor50xp.toLocaleString()}</strong> books</div>
                    <div>500xp/book: <strong>${booksFor500xp.toLocaleString()}</strong> books</div>
                            `;
                        }
                    }
                };
                resetBtn.onclick = () => {
                    const inputs = document.querySelectorAll('.bread-target-input');
                    inputs.forEach(input => {
                        const min = parseInt(input.min);
                        input.value = min.toString();
                        input.dispatchEvent(new Event('change'));
                    });
                };
                if (!this._breadWsListener) {
                    this._breadWsListener = this.breadHandleWebSocketMessage.bind(this);
                    window.addEventListener('EquipSpyWebSocketMessage', this._breadWsListener);
                }
                VisibilityManager.register('bread-update', () => {
                    this.updateBReadExperience();
                }, 2000);
            }

            updateBReadContent() {
                const content = document.getElementById('bread-content');
                if (!content) return;
                this.breadInvalidateAbilityCache();
                let equippedAbilities = [];
                try {
                    const charData = CharacterDataStorage.get();

                    if (charData) {
                        if (charData.combatUnit?.combatAbilities) {
                            equippedAbilities = charData.combatUnit.combatAbilities;
                        }
                    }
                } catch (e) {
                    console.error('[BRead] Failed to load equipped abilities:', e);
                }
                if (equippedAbilities.length === 0) {
                    content.innerHTML = '<div class="mcs-bread-no-abilities">No abilities equipped</div>';
                    return;
                }
                content.innerHTML = '';
                equippedAbilities.forEach(ability => {
                    if (!ability || !ability.abilityHrid) return;
                    const itemDiv = document.createElement('div');
                    itemDiv.className = 'bread-ability-item mcs-bread-item';
                    itemDiv.setAttribute('data-ability-hrid', ability.abilityHrid);
                    const levelLabel = document.createElement('div');
                    levelLabel.className = 'bread-level-label mcs-bread-level mcs-font-16';
                    levelLabel.textContent = '...';
                    const iconId = ability.abilityHrid.split('/').pop();
                    const bookItemHrid = '/items/' + iconId;
                    const svgIcon = createItemIcon(iconId, { width: 30, height: 30, className: 'mcs-bread-icon', clickable: true, itemHrid: bookItemHrid });
                    svgIcon.addEventListener('click', (e) => {
                        e.stopPropagation();
                        mcsGoToMarketplace(bookItemHrid);
                    });
                    const expContainer = document.createElement('div');
                    expContainer.className = 'mcs-bread-exp-container';
                    const expLabel = document.createElement('div');
                    expLabel.className = 'bread-exp-label mcs-bread-exp mcs-text';
                    expLabel.textContent = '...';
                    const rateLabel = document.createElement('div');
                    rateLabel.className = 'bread-rate-label mcs-bread-rate mcs-font-9';
                    rateLabel.textContent = '0/hr';
                    expContainer.appendChild(expLabel);
                    expContainer.appendChild(rateLabel);
                    const timeLabel = document.createElement('div');
                    timeLabel.className = 'bread-time-label mcs-bread-time mcs-text';
                    timeLabel.textContent = '--';
                    const booksLabel = document.createElement('div');
                    booksLabel.className = 'bread-books-label mcs-bread-books mcs-font-22';
                    booksLabel.textContent = '...';
                    const marketValueLabel = document.createElement('div');
                    marketValueLabel.className = 'bread-market-value-label mcs-bread-market mcs-text';
                    marketValueLabel.textContent = '...';
                    const targetInput = document.createElement('input');
                    targetInput.className = 'bread-target-input mcs-bread-input mcs-text';
                    targetInput.type = 'number';
                    targetInput.min = '1';
                    targetInput.max = '200';
                    targetInput.value = '1';
                    itemDiv.appendChild(levelLabel);
                    itemDiv.appendChild(svgIcon);
                    itemDiv.appendChild(expContainer);
                    itemDiv.appendChild(timeLabel);
                    itemDiv.appendChild(booksLabel);
                    itemDiv.appendChild(marketValueLabel);
                    itemDiv.appendChild(targetInput);
                    content.appendChild(itemDiv);
                });
                this.updateBReadExperience();
            }

            breadShouldUpdateDOM() {
                const pane = document.getElementById('bread-pane');
                if (!pane) return false;

                return true;
            }

            breadIsHidden() {
                const pane = document.getElementById('bread-pane');
                return pane && pane.classList.contains('mcs-hidden');
            }

            updateBReadExperience() {
                if (!this.breadShouldUpdateDOM()) return;

                const isMinimized = this.breadIsMinimized;
                const isHidden = this.breadIsHidden();

                let characterAbilities = null;
                let levelExperienceTable = null;
                let itemDetailMap = null;
                if (Object.keys(this.breadCurrentAbilityExp).length > 0) {
                    characterAbilities = this.breadCurrentAbilityExp;
                }

                levelExperienceTable = InitClientDataCache.getLevelExperienceTable();
                itemDetailMap = InitClientDataCache.getItemDetailMap();
                if (!characterAbilities) {
                    try {
                        const charData = CharacterDataStorage.get();

                        if (charData) {
                            if (charData.characterAbilities) {
                                characterAbilities = {};
                                for (const ability of Object.values(charData.characterAbilities)) {
                                    characterAbilities[ability.abilityHrid] = {
                                        level: ability.level,
                                        experience: ability.experience
                                    };
                                }
                            }
                        }
                    } catch (e) {
                        console.error('[BRead] Failed to load character data:', e);
                    }
                }
                if (!characterAbilities || !levelExperienceTable || !itemDetailMap) {
                    return;
                }

                const marketData = mcsGetMarketData();

                let cheapestCost = Infinity;
                let cheapestBooks = 0;
                let cheapestIconId = '';

                const abilityItems = this.breadGetAbilityItems();
                const currentTime = Date.now();

                const calculateBooksToLevel = (currentLevel, currentExp, targetLevel, abilityPerBookExp) => {
                    const needExp = levelExperienceTable[targetLevel] - currentExp;
                    let needBooks = needExp / abilityPerBookExp;
                    if (currentLevel === 0) {
                        needBooks += 1;
                    }
                    return Math.ceil(needBooks);
                };

                abilityItems.forEach(item => {
                    const abilityHrid = item.getAttribute('data-ability-hrid');
                    const abilityData = characterAbilities[abilityHrid];

                    const currentLevel = abilityData?.level ?? 0;
                    const currentExp = abilityData?.experience ?? 0;
                    const itemHrid = abilityHrid.replace('/abilities/', '/items/');
                    const abilityPerBookExp = itemDetailMap[itemHrid]?.abilityBookDetail?.experienceGain;
                    const iconId = abilityHrid.split('/').pop();

                    const existingTracking = this.breadExpTracking[abilityHrid];
                    const hasGainedExp = existingTracking && (currentExp - existingTracking.startExp) > 0;

                    if (abilityPerBookExp && currentLevel < 200 && hasGainedExp) {
                        const booksToNextLevel = calculateBooksToLevel(currentLevel, currentExp, currentLevel + 1, abilityPerBookExp);

                        if (booksToNextLevel > 0) {
                            let askPrice = 0;
                            if (marketData?.marketData?.[itemHrid]?.['0']?.a > 0) {
                                askPrice = marketData.marketData[itemHrid]['0'].a;
                            }

                            const costToNextLevel = askPrice * booksToNextLevel;

                            if (askPrice > 0 && costToNextLevel < cheapestCost) {
                                cheapestCost = costToNextLevel;
                                cheapestBooks = booksToNextLevel;
                                cheapestIconId = iconId;
                            }
                        }
                    }

                    if (!this.breadExpTracking[abilityHrid]) {
                        this.breadExpTracking[abilityHrid] = {
                            startExp: currentExp,
                            startTime: currentTime,
                            lastExp: currentExp,
                            lastUpdateTime: currentTime,
                            savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                            savedTabHiddenMs: window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0
                        };
                    } else {
                        const tracking = this.breadExpTracking[abilityHrid];
                        tracking.lastExp = currentExp;
                        tracking.lastUpdateTime = currentTime;
                    }

                    if (isMinimized || isHidden) return;

                    const levelLabel = item.querySelector('.bread-level-label');
                    const expLabel = item.querySelector('.bread-exp-label');
                    const rateLabel = item.querySelector('.bread-rate-label');
                    const timeLabel = item.querySelector('.bread-time-label');
                    const booksLabel = item.querySelector('.bread-books-label');
                    const marketValueLabel = item.querySelector('.bread-market-value-label');
                    const targetInput = item.querySelector('.bread-target-input');
                    if (!levelLabel || !expLabel || !rateLabel || !timeLabel || !booksLabel || !targetInput) return;

                    if (!abilityData) {
                        levelLabel.textContent = '0';
                        expLabel.textContent = '0';
                        rateLabel.textContent = '0/hr';
                        timeLabel.textContent = '--';
                        booksLabel.textContent = '0';
                        marketValueLabel.textContent = '0 coin';
                        return;
                    }

                    levelLabel.textContent = currentLevel.toString();
                    const nextLevelExp = levelExperienceTable[currentLevel + 1];
                    const expNeeded = nextLevelExp - currentExp;
                    expLabel.textContent = Math.ceil(expNeeded).toString();

                    if (abilityPerBookExp) {
                        if (targetInput.value === '1' || parseInt(targetInput.value) <= currentLevel) {
                            targetInput.value = (currentLevel + 1).toString();
                            targetInput.min = (currentLevel + 1).toString();
                        }

                        const targetLevel = parseInt(targetInput.value);
                        if (targetLevel > currentLevel && targetLevel <= 200) {
                            const booksToTarget = calculateBooksToLevel(currentLevel, currentExp, targetLevel, abilityPerBookExp);
                            booksLabel.textContent = booksToTarget.toString();

                            if (marketData?.marketData?.[itemHrid]?.['0']?.a > 0) {
                                const askPrice = marketData.marketData[itemHrid]['0'].a;
                                const totalValue = askPrice * booksToTarget;
                                marketValueLabel.textContent = this.formatBReadCoins(totalValue);
                            } else {
                                marketValueLabel.textContent = '- coin';
                            }
                        } else {
                            booksLabel.textContent = '0';
                            marketValueLabel.textContent = '0 coin';
                        }
                        const updateTargetBooks = () => {
                            const targetLevel = parseInt(targetInput.value);
                            if (targetLevel > currentLevel && targetLevel <= 200) {
                                const booksToTarget = calculateBooksToLevel(currentLevel, currentExp, targetLevel, abilityPerBookExp);
                                booksLabel.textContent = booksToTarget.toString();

                                if (marketData?.marketData?.[itemHrid]?.['0']?.a > 0) {
                                    const askPrice = marketData.marketData[itemHrid]['0'].a;
                                    const totalValue = askPrice * booksToTarget;
                                    marketValueLabel.textContent = this.formatBReadCoins(totalValue);
                                } else {
                                    marketValueLabel.textContent = '-';
                                }

                                const tracking = this.breadExpTracking[abilityHrid];
                                if (tracking) {
                                    const expGained = currentExp - tracking.startExp;
                                    const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                                    if (timeElapsed > 0 && expGained > 0) {
                                        const expPerHour = (expGained / timeElapsed) * 3600;
                                        const expNeededForTarget = levelExperienceTable[targetLevel] - currentExp;
                                        const hoursNeeded = expNeededForTarget / expPerHour;
                                        if (hoursNeeded < 1) {
                                            const minutes = Math.ceil(hoursNeeded * 60);
                                            timeLabel.textContent = minutes + 'm';
                                        } else if (hoursNeeded < 24) {
                                            const hours = Math.floor(hoursNeeded);
                                            const minutes = Math.ceil((hoursNeeded - hours) * 60);
                                            timeLabel.textContent = hours + 'h ' + minutes + 'm';
                                        } else {
                                            const days = Math.floor(hoursNeeded / 24);
                                            const hours = Math.floor(hoursNeeded % 24);
                                            timeLabel.textContent = days + 'd ' + hours + 'h';
                                        }
                                    }
                                }
                            } else {
                                booksLabel.textContent = '0';
                                marketValueLabel.textContent = '0';
                                timeLabel.textContent = '--';
                            }
                        };
                        targetInput.onchange = updateTargetBooks;
                        targetInput.onkeyup = updateTargetBooks;
                    } else {
                        booksLabel.textContent = 'N/A';
                    }

                    const tracking = this.breadExpTracking[abilityHrid];
                    const expGained = currentExp - tracking.startExp;
                    const timeElapsed = mcsGetElapsedSeconds(tracking.startTime, currentTime, tracking.savedPausedMs, 0, true, tracking.savedTabHiddenMs);
                    if (timeElapsed > 0 && expGained > 0) {
                        const expPerHour = (expGained / timeElapsed) * 3600;
                        rateLabel.textContent = Math.round(expPerHour).toString() + '/hr';
                        const targetLevel = parseInt(targetInput.value);
                        if (targetLevel > currentLevel && targetLevel <= 200 && expPerHour > 0) {
                            const expNeededForTarget = levelExperienceTable[targetLevel] - currentExp;
                            const hoursNeeded = expNeededForTarget / expPerHour;
                            if (hoursNeeded < 1) {
                                const minutes = Math.ceil(hoursNeeded * 60);
                                timeLabel.textContent = minutes + 'm';
                            } else if (hoursNeeded < 24) {
                                const hours = Math.floor(hoursNeeded);
                                const minutes = Math.ceil((hoursNeeded - hours) * 60);
                                timeLabel.textContent = hours + 'h ' + minutes + 'm';
                            } else {
                                const days = Math.floor(hoursNeeded / 24);
                                const hours = Math.floor(hoursNeeded % 24);
                                timeLabel.textContent = days + 'd ' + hours + 'h';
                            }
                        } else {
                            timeLabel.textContent = '--';
                        }
                    } else if (timeElapsed > 0) {
                        rateLabel.textContent = '0/hr';
                        timeLabel.textContent = '--';
                    } else {
                        rateLabel.textContent = '0/hr';
                        timeLabel.textContent = '--';
                    }
                });

                this.updateBReadHeaderInfo(cheapestIconId, cheapestBooks, cheapestCost);
            }

            updateBReadHeaderInfo(iconId, books, cost) {
                const headerInfo = document.getElementById('bread-header-info');

                if (!iconId || !books || books <= 0 || cost === Infinity || cost === 0) {
                    window.mcs_breadCheapestSkill = null;
                } else {
                    window.mcs_breadCheapestSkill = { iconId, books, cost };
                }

                if (!headerInfo) return;

                if (!iconId || !books || books <= 0 || cost === Infinity || cost === 0) {
                    headerInfo.innerHTML = '';
                    return;
                }

    headerInfo.innerHTML = `
        ${createItemIconHtml(iconId, { width: 18, height: 18, style: 'flex-shrink: 0' })}
        <span class="mcs-bread-header-books">${books}</span>
        <span class="mcs-bread-header-label">books</span>
        <span class="mcs-bread-header-cost">${this.formatBReadCoins(cost)}</span>
                `;
            }

            makeBReadDraggable(pane, header) {
                DragHandler.makeDraggable(pane, header, 'mcs_BR');
            }

            destroyBRead() {
                VisibilityManager.clear('bread-update');
                if (this._breadWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._breadWsListener); this._breadWsListener = null; }
                const pane = document.getElementById('bread-pane');
                if (pane) pane.remove();
            }

// BRead end

// JHouse start

            get jhStorage() {
                if (!this._jhStorage) {
                    this._jhStorage = createModuleStorage('JH');
                }
                return this._jhStorage;
            }

            getHouseRecipes() {
                if (this._cachedHouseRecipes) {
                    return this._cachedHouseRecipes;
                }

                try {
                    const clientData = InitClientDataCache.get();

                    if (clientData?.houseRoomDetailMap) {
                        const recipes = {};

                        for (const [hrid, roomDetail] of Object.entries(clientData.houseRoomDetailMap)) {
                            const roomKey = hrid.split('/').pop() || '';
                            const roomName = roomKey.split('_').map(word =>
                                word.charAt(0).toUpperCase() + word.slice(1)
                            ).join(' ');

                            recipes[roomName] = {};

                            if (roomDetail.upgradeCostsMap) {
                                for (const [level, costs] of Object.entries(roomDetail.upgradeCostsMap)) {
                                    const recipe = {
                                        gold: 0,
                                        materials: {}
                                    };

                                    for (const cost of costs) {
                                        if (cost.itemHrid === '/items/coin') {
                                            recipe.gold = cost.count;
                                        } else {
                                            recipe.materials[cost.itemHrid] = cost.count;
                                        }
                                    }

                                    recipes[roomName][level] = recipe;
                                }
                            }
                        }

                        if (Object.keys(recipes).length > 0) {
                            this._cachedHouseRecipes = recipes;
                            return this._cachedHouseRecipes;
                        }
                    }
                } catch (e) {
                    console.error('[JHouse] Error building recipes from client data:', e);
                }

                if (window.HOUSE_RECIPES) {
                    this._cachedHouseRecipes = window.HOUSE_RECIPES;
                    return this._cachedHouseRecipes;
                }

                if (this.HOUSE_RECIPES) {
                    this._cachedHouseRecipes = this.HOUSE_RECIPES;
                    return this._cachedHouseRecipes;
                }

                return {};
            }

            numberToEnglish(num) {
                const words = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven',
                   'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen',
                   'fifteen', 'sixteen', 'seventeen'];
                return words[num] || num.toString();
            }

            formatGoldDetailed(amount) {
                return mcsFormatCurrency(amount, 'detailed');
            }

            formatGold(amount) {
                return mcsFormatCurrency(amount, 'gold');
            }

            formatItemName(itemHrid) {
                return mcsFormatHrid(itemHrid);
            }

            getItemCount(itemHrid, cachedInventory = null) {
                if (!window.lootDropsTrackerInstance?.spyCharacterItems && window._pendingInventoryData) {
                    const items = window._pendingInventoryData.filter(i =>
                        i.itemHrid === itemHrid &&
                        (i.itemLocationHrid === '/item_locations/inventory' || !i.itemLocationHrid) &&
                        (!i.enhancementLevel || i.enhancementLevel === 0)
                    );
                    return items.reduce((total, item) => total + (item.count ?? 0), 0);
                }try {
                    if (cachedInventory) {
            const items = cachedInventory.filter(i =>
                i.itemHrid === itemHrid &&
                (i.itemLocationHrid === '/item_locations/inventory' || !i.itemLocationHrid) &&
                (!i.enhancementLevel || i.enhancementLevel === 0)
            );
            return items.reduce((total, item) => total + (item.count ?? 0), 0);
                    }

                    if (window.lootDropsTrackerInstance?.spyCharacterItems) {
            const items = window.lootDropsTrackerInstance.spyCharacterItems.filter(i =>
                i.itemHrid === itemHrid &&
                (i.itemLocationHrid === '/item_locations/inventory' || !i.itemLocationHrid) &&
                (!i.enhancementLevel || i.enhancementLevel === 0)
            );
            return items.reduce((total, item) => total + (item.count ?? 0), 0);
                    }

                    const cachedData = CharacterDataStorage.get();
                    if (cachedData) {
            if (cachedData.characterItems && Array.isArray(cachedData.characterItems)) {
                const items = cachedData.characterItems.filter(i =>
                    i.itemHrid === itemHrid &&
                    (i.itemLocationHrid === '/item_locations/inventory' || !i.itemLocationHrid) &&
                    (!i.enhancementLevel || i.enhancementLevel === 0)
                );
                return items.reduce((total, item) => total + (item.count ?? 0), 0);
            }
                    }
                } catch (e) {
                }
                return 0;
            }

            getCurrentGold(cachedInventory = null) {
                if (!window.lootDropsTrackerInstance?.spyCharacterItems && window._pendingInventoryData) {
                    const coinItem = window._pendingInventoryData.find(i => i.itemHrid === '/items/coin');
                    if (coinItem) return coinItem.count ?? 0;
                }
                try {
                    if (cachedInventory) {
            const coinItem = cachedInventory.find(i => i.itemHrid === '/items/coin');
            return coinItem ? (coinItem.count ?? 0) : 0;
                    }

                    if (window.lootDropsTrackerInstance?.spyCharacterItems) {
            const coinItem = window.lootDropsTrackerInstance.spyCharacterItems.find(i => i.itemHrid === '/items/coin');
            if (coinItem) return coinItem.count ?? 0;
                    }

                    const cachedData = CharacterDataStorage.get();
                    if (cachedData) {
            if (cachedData.characterItems && Array.isArray(cachedData.characterItems)) {
                const coinItem = cachedData.characterItems.find(i => i.itemHrid === '/items/coin');
                return coinItem ? (coinItem.count ?? 0) : 0;
            }
                    }
                } catch (e) {
                }
                return 0;
            }

            getCachedInventory() {
                try {
                    if (!window.lootDropsTrackerInstance?.spyCharacterItems && window._pendingInventoryData) {
                        return window._pendingInventoryData;
                    }
                    if (window.lootDropsTrackerInstance?.spyCharacterItems) {
            return window.lootDropsTrackerInstance.spyCharacterItems;
                    }

                    const cachedData = CharacterDataStorage.get();
                    if (cachedData) {
            if (cachedData.characterItems && Array.isArray(cachedData.characterItems)) {
                return cachedData.characterItems;
            }
                    }
                } catch (e) {
                }
                return [];
            }

            getCurrentHouseData() {
                try {
                    const cachedData = CharacterDataStorage.get();
                    if (cachedData) {
            if (cachedData.characterHouseRoomMap) {
                return cachedData.characterHouseRoomMap;
            }
                    }

                    if (window.lootDropsTrackerInstance?.spyHouseData) {
            return window.lootDropsTrackerInstance.spyHouseData;
                    }
                } catch (e) {
                }
                return null;
            }

            getItemPrice(itemHrid, priceType) {
                try {
                    if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.spyMarketData) {
            const marketData = window.lootDropsTrackerInstance.spyMarketData[itemHrid];
            if (marketData && marketData[0]) {
                const price = priceType === 'ask' ? (marketData[0].a ?? 0) : (marketData[0].b ?? 0);
                if (price > 0) return price;
            }
                    }
                } catch (e) {
                }
                return null;
            }

            calculateUpgradeCost(recipe, priceType, cachedInventory = null) {
                const currentGold = this.getCurrentGold(cachedInventory);
                const goldNeeded = recipe.gold;

                let totalCost = goldNeeded;
                let hasMarketDataIssue = false;

                Object.entries(recipe.materials).forEach(([itemHrid, amountNeeded]) => {
                    const amountHave = this.getItemCount(itemHrid, cachedInventory);
                    const amountToBuy = Math.max(0, amountNeeded - amountHave);

                    if (amountToBuy > 0) {
            const itemPrice = this.getItemPrice(itemHrid, priceType);
            if (itemPrice === null) {
                hasMarketDataIssue = true;
            } else {
                totalCost += itemPrice * amountToBuy;
            }
                    }
                });

                return { cost: totalCost, hasMarketDataIssue: hasMarketDataIssue };
            }

            isUpgradeAffordable(recipe, cachedInventory = null) {
                const currentGold = this.getCurrentGold(cachedInventory);
                const costData = this.calculateUpgradeCost(recipe, 'ask', cachedInventory);

                if (costData.hasMarketDataIssue) {
                    return false;
                }

                return currentGold >= costData.cost;
            }

            calculateAllAffordability() {
                const HOUSE_RECIPES = this.getHouseRecipes();
                const cachedInventory = this.getCachedInventory();

                let houseData;
                if (this.jhouseLastHouseData) {
                    try {
            houseData = JSON.parse(this.jhouseLastHouseData);
                    } catch (e) {
            houseData = this.getCurrentHouseData();
                    }
                } else {
                    houseData = this.getCurrentHouseData();
                }

                if (!houseData || Object.keys(houseData).length === 0) {
                    return { affordable: [], allAffordable: [], count: 0, allMaxed: false, cheapestAsk: null, cheapestBid: null, cheapestRoom: null };
                }

                const affordableRooms = [];
                const allAffordableRooms = [];
                let totalRooms = 0;
                let maxedRooms = 0;
                let cheapestAsk = null;
                let cheapestBid = null;
                let cheapestRoom = null;

                const currentGold = this.getCurrentGold(cachedInventory);

                Object.entries(houseData).forEach(([houseRoomHrid, roomData]) => {
                    totalRooms++;
                    const level = typeof roomData === 'object' ? roomData.level : roomData;
                    const nextLevel = level + 1;

                    if (level >= 8) {
            maxedRooms++;
            return;
                    }

                    const roomKey = houseRoomHrid.split('/').pop() || '';
                    const isChecked = this.jhouseFilters && this.jhouseFilters[roomKey] === false ? false : true;

                    const roomName = roomKey.replace(/_/g, ' ').split(' ').map(word =>
            word.charAt(0).toUpperCase() + word.slice(1)
                    ).join(' ');

                    const recipe = HOUSE_RECIPES[roomName]?.[nextLevel.toString()];

                    if (recipe) {
            const costDataAsk = this.calculateUpgradeCost(recipe, 'ask', cachedInventory);
            const costDataBid = this.calculateUpgradeCost(recipe, 'bid', cachedInventory);

            const totalCostNeeded = costDataAsk.cost;
            const canAfford = !costDataAsk.hasMarketDataIssue && currentGold >= totalCostNeeded;

            if (canAfford) {
                allAffordableRooms.push(roomKey);
            }

            if (isChecked) {
                if (canAfford) {
                    affordableRooms.push(roomKey);
                }

                const totalAsk = costDataAsk.cost;
                if (!costDataAsk.hasMarketDataIssue && (cheapestAsk === null || totalAsk < cheapestAsk)) {
                    cheapestAsk = totalAsk;
                    cheapestBid = costDataBid.cost;
                    cheapestRoom = roomKey;
                }
            }
                    }
                });

                const allMaxed = maxedRooms === totalRooms;

                return {
                    affordable: affordableRooms,
                    allAffordable: allAffordableRooms,
                    count: affordableRooms.length,
                    allMaxed: allMaxed,
                    cheapestAsk: cheapestAsk,
                    cheapestBid: cheapestBid,
                    cheapestRoom: cheapestRoom
                };
            }

            getProgressColor(have, need) {
                if (have === 0) return '#ff4444';
                if (have >= need) return '#4CAF50';
                return '#FFA500';
            }

            createJHousePane() {
                if (document.getElementById('jhouse-pane')) return;

                const pane = document.createElement('div');
                pane.id = 'jhouse-pane';
                registerPanel('jhouse-pane');
                pane.className = 'mcs-pane mcs-jh-pane';

                const header = document.createElement('div');
                header.className = 'mcs-pane-header mcs-jh-header';

                const titleSection = document.createElement('div');
                titleSection.className = 'mcs-jh-title-section';

                const titleSpan = document.createElement('span');
                titleSpan.className = 'mcs-pane-title';
                titleSpan.textContent = 'JHouse';

                const affordableSpan = document.createElement('span');
                affordableSpan.id = 'jhouse-affordable-status';
                affordableSpan.className = 'mcs-jh-affordable-status';

                const cheapestSpan = document.createElement('span');
                cheapestSpan.id = 'jhouse-cheapest-status';
                cheapestSpan.className = 'mcs-jh-cheapest-status';

                titleSection.appendChild(titleSpan);
                titleSection.appendChild(affordableSpan);
                titleSection.appendChild(cheapestSpan);

                const buttonSection = document.createElement('div');
                buttonSection.className = 'mcs-button-section';

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'jhouse-minimize-btn';
                minimizeBtn.textContent = '−';
                minimizeBtn.className = 'mcs-btn';

                buttonSection.appendChild(minimizeBtn);
                header.appendChild(titleSection);
                header.appendChild(buttonSection);

                const statusPane = document.createElement('div');
                statusPane.id = 'jhouse-status-pane';
                statusPane.className = 'mcs-jh-status-pane';

                const statusLines = [
                    { id: 'status-house-levels', text: 'Waiting for current house levels...' },
                    { id: 'status-inventory', text: 'Waiting for current inventory...' },
                    { id: 'status-recipes', text: 'Waiting for house recipes...' },
                    { id: 'status-calculations', text: 'Waiting for initial calculations...' }
                ];

                statusLines.forEach(line => {
                    const lineDiv = document.createElement('div');
                    lineDiv.id = line.id;
                    lineDiv.className = 'mcs-jh-status-line';
                    lineDiv.textContent = line.text;
                    statusPane.appendChild(lineDiv);
                });

                const content = document.createElement('div');
                content.id = 'jhouse-content';
                content.className = 'mcs-jh-content';

                pane.appendChild(header);
                pane.appendChild(statusPane);
                pane.appendChild(content);
                document.body.appendChild(pane);

                this.makeJHouseDraggable(pane, header);

                this.jhouseSelectedRoom = 'dairy_barn';
                this.jhouseAffordableRooms = [];
                this.jhouseLastHouseData = null;
                this.jhouseInitialized = false;
                this._cachedHouseRecipes = null;

                const savedFilters = this.jhStorage.get('filters');
                if (savedFilters) {
                    try {
                        this.jhouseFilters = typeof savedFilters === 'string' ? JSON.parse(savedFilters) : savedFilters;
                    } catch (e) {
                        this.jhouseFilters = {};
                    }
                } else {
                    this.jhouseFilters = {};
                }

                const savedJhouseMinimized = this.jhStorage.get('minimized') === true || this.jhStorage.get('minimized') === 'true';
                this.jhouseIsMinimized = savedJhouseMinimized;
                if (savedJhouseMinimized) {
                    minimizeBtn.textContent = '+';
                    statusPane.style.display = 'none';
                    content.style.display = 'none';
                    header.style.borderRadius = '6px';
                }

                this.initializeJHouse();

                minimizeBtn.onclick = () => {
                    this.jhouseIsMinimized = !this.jhouseIsMinimized;
                    if (this.jhouseIsMinimized) {
            content.style.display = 'none';
            statusPane.style.display = 'none';
            minimizeBtn.textContent = '+';
            header.style.borderRadius = '6px';
            this.jhStorage.set('minimized', true);
                    } else {
            if (this.jhouseInitialized) {
                content.style.display = 'flex';
                this.jhouseLastFullRender = 0;
                this.updateJHouseContent(true);
            } else {
                statusPane.style.display = 'flex';
            }
            minimizeBtn.textContent = '−';
            header.style.borderRadius = '6px 6px 0 0';
            this.jhStorage.set('minimized', false);
            this.constrainPanelToBoundaries('jhouse-pane', 'mcs_JH', true);
                    }
                };

                const self = this;

                this.manualRefreshJHouse = function() {
                    self.updateJHouseContent();
                };

                window.refreshJHouse = this.manualRefreshJHouse;

                this.jhouseInventoryListener = (event) => {
                    if (self.jhouseInitialized && event.detail?.items) {
                        setTimeout(() => self.updateJHouseContent(true), 100);
                    }
                };

                this.jhouseInventoryDataListener = (event) => {
                    if (self.jhouseInitialized && event.detail?.items) {
                        setTimeout(() => self.updateJHouseContent(true), 150);
                    }
                };

                this.jhouseWebSocketListener = (event) => {
                    const data = event.detail;
            if (data?.type === 'item_update' || data?.type === 'inventory_update') {
                if (self.jhouseInitialized) {
                    setTimeout(() => self.updateJHouseContent(true), 100);
                }
            }

                    if (data?.characterHouseRoomMap) {
            const newHouseDataStr = JSON.stringify(data.characterHouseRoomMap);

            let hasValidUpgrade = false;
            let hasInvalidDowngrade = false;

            if (self.jhouseLastHouseData) {
                try {
                    const oldData = JSON.parse(self.jhouseLastHouseData);
                    Object.entries(data.characterHouseRoomMap).forEach(([roomHrid, roomData]) => {
                        const oldLevel = oldData[roomHrid]?.level ?? 0;
                        const newLevel = roomData.level ?? 0;

                        if (newLevel > oldLevel) {
                            hasValidUpgrade = true;
                            const roomName = roomHrid.split('/').pop();
                        } else if (newLevel < oldLevel) {
                            hasInvalidDowngrade = true;
                        }
                    });
                } catch (e) { /* house level data may be malformed */ }
            } else {
                hasValidUpgrade = true;
            }

            if (hasValidUpgrade && !hasInvalidDowngrade) {
                self.jhouseLastHouseData = newHouseDataStr;
                if (self.jhouseInitialized) {
                    setTimeout(() => self.updateJHouseContent(true), 50);
                }
            } else if (hasInvalidDowngrade) {
                const now = Date.now();
                if (!self.jhouseLastStaleWSLog || (now - self.jhouseLastStaleWSLog) > 1000) {
                    self.jhouseLastStaleWSLog = now;
                }
            }
                    }

                    if (data?.characterItems && self.jhouseInitialized) {
                if (window.lootDropsTrackerInstance?.spyCharacterItems) {
                    window.lootDropsTrackerInstance.spyCharacterItems = data.characterItems;
                }
                setTimeout(() => self.updateJHouseContent(true), 50);
            }

                    if (data?.marketListings && self.jhouseInitialized) {
                setTimeout(() => self.updateJHouseContent(true), 50);
            }
                };

                window.addEventListener('EquipSpyInventoryUpdated', this.jhouseInventoryListener);
                window.addEventListener('InventoryDataUpdated', this.jhouseInventoryDataListener);
                window.addEventListener('EquipSpyWebSocketMessage', this.jhouseWebSocketListener);

                VisibilityManager.register('jhouse-update', () => {
                    if (!self.jhouseInitialized) return;

                    const pane = document.getElementById('jhouse-pane');
                    const isPaneClosed = !pane || pane.style.display === 'none';

                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData && window.lootDropsTrackerInstance) {
                            if (cachedData.characterItems) {
                                const oldItems = window.lootDropsTrackerInstance.spyCharacterItems || [];
                                const newItems = cachedData.characterItems;

                                if (oldItems.length !== newItems.length) {
                                    window.lootDropsTrackerInstance.spyCharacterItems = newItems;
                                } else {
                                    let hasChanges = false;
                                    for (const newItem of newItems) {
                                        const oldItem = oldItems.find(i => i.itemHrid === newItem.itemHrid);
                                        if (!oldItem || oldItem.count !== newItem.count) {
                                            hasChanges = true;
                                            break;
                                        }
                                    }
                                    if (hasChanges) {
                                        window.lootDropsTrackerInstance.spyCharacterItems = newItems;
                                    }
                                }
                            }
                        }
                    } catch (e) {
                    }

                    if (!isPaneClosed && !self.jhouseIsMinimized) {
                        self.updateJHouseContent(false);
                    } else {
                        const affordabilityData = self.calculateAllAffordability();
                        self.jhouseAffordableRooms = affordabilityData.affordable;
                        self.jhouseAllAffordableRooms = affordabilityData.allAffordable;
                        self.jhouseCheapestRoom = affordabilityData.cheapestRoom;
                        self.jhouseAffordabilityResult = affordabilityData;

                        if (!isPaneClosed) {
                            const affordableStatus = document.getElementById('jhouse-affordable-status');
                            const cheapestStatus = document.getElementById('jhouse-cheapest-status');

                            if (affordableStatus) {
                                if (affordabilityData.allMaxed) {
                                    affordableStatus.style.color = '#FFD700';
                                    affordableStatus.textContent = 'You are a true land baron!';
                                    affordableStatus.style.display = 'block';
                                } else if (affordabilityData.count > 0) {
                                    affordableStatus.style.color = '#4CAF50';
                                    affordableStatus.textContent = `You can purchase ${affordabilityData.count}`;
                                    affordableStatus.style.display = 'block';
                                } else {
                                    affordableStatus.style.color = '#ff4444';
                                    affordableStatus.textContent = 'You can purchase 0';
                                    affordableStatus.style.display = 'block';
                                }
                            }

                            if (cheapestStatus) {
                                if (!affordabilityData.allMaxed && affordabilityData.cheapestAsk !== null && affordabilityData.cheapestBid !== null) {
                                    const roomDisplayName = affordabilityData.cheapestRoom
                                        ? affordabilityData.cheapestRoom.replace(/_/g, ' ').split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')
                                        : '';
                                    cheapestStatus.innerHTML = roomDisplayName
                                        ? `<div class="mcs-jh-cheapest-room-name">${roomDisplayName}</div><div>Cheapest ${self.formatGoldDetailed(affordabilityData.cheapestAsk)}a ${self.formatGoldDetailed(affordabilityData.cheapestBid)}b</div>`
                                        : `Cheapest ${self.formatGoldDetailed(affordabilityData.cheapestAsk)}a ${self.formatGoldDetailed(affordabilityData.cheapestBid)}b`;
                                    cheapestStatus.style.display = 'block';
                                } else {
                                    cheapestStatus.style.display = 'none';
                                }
                            }
                        }
                    }
                }, 5000);
            }

            initializeJHouse() {
                const updateStatus = (id, complete) => {
                    const elem = document.getElementById(id);
                    if (elem) {
            if (complete) {
                elem.style.color = '#4CAF50';
                elem.textContent = elem.textContent.replace('...', '...Complete');
            }
                    }
                };

                const checkAndComplete = async () => {
                    let allComplete = true;

                    const houseData = this.getCurrentHouseData();
                    if (houseData && Object.keys(houseData).length > 0) {
            updateStatus('status-house-levels', true);
            this.jhouseLastHouseData = JSON.stringify(houseData);
                    } else {
            allComplete = false;
                    }

                    const gold = this.getCurrentGold();
                    if (gold !== 0 || this.getItemCount('/items/coin') >= 0) {
            updateStatus('status-inventory', true);
                    } else {
            allComplete = false;
                    }

                    const recipes = this.getHouseRecipes();
                    if (recipes && Object.keys(recipes).length > 0) {
            updateStatus('status-recipes', true);
                    } else {
            allComplete = false;
                    }

                    if (allComplete) {
            updateStatus('status-calculations', true);

            setTimeout(() => {
                const statusPane = document.getElementById('jhouse-status-pane');
                const content = document.getElementById('jhouse-content');

                if (statusPane && content) {
                    statusPane.style.display = 'none';
                    if (!this.jhouseIsMinimized) {
                        content.style.display = 'flex';
                    }
                    this.jhouseInitialized = true;
                    this.updateJHouseContent();
                }
            }, 500);

            return true;
                    }

                    return false;
                };

                const startTime = Date.now();
                const MAX_INIT_TIME = 30000;

                const initInterval = setInterval(() => {
                    if (checkAndComplete()) {
                        clearInterval(initInterval);
                    } else if (Date.now() - startTime > MAX_INIT_TIME) {
                        clearInterval(initInterval);
                    }
                }, 200);

                checkAndComplete();
            }

            destroyJHouse() {
                VisibilityManager.clear('jhouse-update');

                if (this.jhouseInventoryListener) {
                    window.removeEventListener('EquipSpyInventoryUpdated', this.jhouseInventoryListener);
                    this.jhouseInventoryListener = null;
                }

                if (this.jhouseInventoryDataListener) {
                    window.removeEventListener('InventoryDataUpdated', this.jhouseInventoryDataListener);
                    this.jhouseInventoryDataListener = null;
                }

                if (this.jhouseWebSocketListener) {
                    window.removeEventListener('EquipSpyWebSocketMessage', this.jhouseWebSocketListener);
                    this.jhouseWebSocketListener = null;
                }

                const pane = document.getElementById('jhouse-pane');
                if (pane) {
                    pane.remove();
                }

                this.jhouseInitialized = false;

            }

            updateJHouseContent(forceFullRender = false) {
                let houseData;
                if (this.jhouseLastHouseData) {
                    try {
            houseData = JSON.parse(this.jhouseLastHouseData);
                    } catch (e) {
            houseData = this.getCurrentHouseData();
                    }
                } else {
                    houseData = this.getCurrentHouseData();
                }

                const affordabilityData = this.calculateAllAffordability();
                this.jhouseAffordableRooms = affordabilityData.affordable;
                this.jhouseAllAffordableRooms = affordabilityData.allAffordable;
                this.jhouseCheapestRoom = affordabilityData.cheapestRoom;
                this.jhouseAffordabilityResult = affordabilityData;

                const affordableStatus = document.getElementById('jhouse-affordable-status');
                const cheapestStatus = document.getElementById('jhouse-cheapest-status');

                if (affordableStatus) {
                    if (affordabilityData.allMaxed) {
            affordableStatus.style.color = '#FFD700';
            affordableStatus.textContent = 'You are a true land baron!';
            affordableStatus.style.display = 'block';
                    } else if (affordabilityData.count > 0) {
            affordableStatus.style.color = '#4CAF50';
            affordableStatus.textContent = `You can purchase ${affordabilityData.count}`;
            affordableStatus.style.display = 'block';
                    } else {
            affordableStatus.style.color = '#ff4444';
            affordableStatus.textContent = 'You can purchase 0';
            affordableStatus.style.display = 'block';
                    }
                }

                if (cheapestStatus) {
                    if (!affordabilityData.allMaxed && affordabilityData.cheapestAsk !== null && affordabilityData.cheapestBid !== null) {
            const roomDisplayName = affordabilityData.cheapestRoom
                ? affordabilityData.cheapestRoom.replace(/_/g, ' ').split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')
                : '';
            cheapestStatus.innerHTML = roomDisplayName
                ? `<div class="mcs-jh-cheapest-room-name">${roomDisplayName}</div><div>Cheapest ${this.formatGoldDetailed(affordabilityData.cheapestAsk)}a ${this.formatGoldDetailed(affordabilityData.cheapestBid)}b</div>`
                : `Cheapest ${this.formatGoldDetailed(affordabilityData.cheapestAsk)}a ${this.formatGoldDetailed(affordabilityData.cheapestBid)}b`;
            cheapestStatus.style.display = 'block';
                    } else {
            cheapestStatus.style.display = 'none';
                    }
                }

                const content = document.getElementById('jhouse-content');
                if (!content) return;

                if (this.jhouseIsMinimized) {
                    return;
                }

                const now = Date.now();
                const timeSinceLastRender = now - (this.jhouseLastFullRender ?? 0);
                const needsFullRender = forceFullRender || timeSinceLastRender > 10000;

                if (!needsFullRender) {
                    this.updateDetailPanelOnly(houseData);
                    return;
                }

                this.jhouseLastFullRender = now;

                content.innerHTML = '';

                if (!houseData || Object.keys(houseData).length === 0) {
                    const noDataDiv = document.createElement('div');
                    noDataDiv.className = 'mcs-jh-no-data';
                    noDataDiv.textContent = 'No house data available';
                    content.appendChild(noDataDiv);
                    return;
                }

                const mainContainer = document.createElement('div');
                mainContainer.className = 'mcs-jh-main-grid';

                const gridContainer = document.createElement('div');
                gridContainer.className = 'mcs-jh-room-grid';

                const houseRoomOrder = [
                    'dairy_barn',
                    'garden',
                    'log_shed',
                    'forge',
                    'workshop',
                    'sewing_parlor',
                    'kitchen',
                    'brewery',
                    'laboratory',
                    'observatory',
                    'dining_room',
                    'library',
                    'dojo',
                    'armory',
                    'gym',
                    'archery_range',
                    'mystical_study'
                ];

                const houseRooms = Object.entries(houseData).sort((a, b) => {
                    const keyA = a[0].split('/').pop() || '';
                    const keyB = b[0].split('/').pop() || '';
                    const indexA = houseRoomOrder.indexOf(keyA);
                    const indexB = houseRoomOrder.indexOf(keyB);
                    return indexA - indexB;
                });

                const houseRoomToIconMap = {
                    'dairy_barn': 'milking',
                    'archery_range': 'ranged',
                    'garden': 'foraging',
                    'log_shed': 'woodcutting',
                    'forge': 'cheesesmithing',
                    'workshop': 'crafting',
                    'sewing_parlor': 'tailoring',
                    'kitchen': 'cooking',
                    'brewery': 'brewing',
                    'laboratory': 'alchemy',
                    'observatory': 'enhancing',
                    'dining_room': 'stamina',
                    'library': 'intelligence',
                    'dojo': 'attack',
                    'armory': 'defense',
                    'gym': 'melee',
                    'mystical_study': 'magic'
                };

                houseRooms.forEach(([houseRoomHrid, roomData]) => {
                    const level = typeof roomData === 'object' ? roomData.level : roomData;

                    const roomName = (houseRoomHrid.split('/').pop() || '').replace(/_/g, ' ');
                    const displayName = roomName.split(' ').map(word =>
            word.charAt(0).toUpperCase() + word.slice(1)
                    ).join(' ');

                    const roomKey = houseRoomHrid.split('/').pop() || '';
                    const iconId = houseRoomToIconMap[roomKey] || roomKey;

                    const isAffordable = this.jhouseAllAffordableRooms && this.jhouseAllAffordableRooms.includes(roomKey);
                    const isCheapest = this.jhouseCheapestRoom === roomKey;
                    const isChecked = this.jhouseFilters[roomKey] !== false;

                    let backgroundColor = '#333';
                    if (isCheapest && isChecked) {
            backgroundColor = 'rgba(255, 215, 0, 0.2)';
                    } else if (isAffordable) {
            backgroundColor = isChecked ? 'rgba(76, 175, 80, 0.2)' : 'rgba(100, 150, 255, 0.05)';
                    }

                    let borderColor = 'transparent';
                    if (roomKey === this.jhouseSelectedRoom) {
            borderColor = '#FFA500';
                    } else if (isCheapest && isChecked) {
            borderColor = 'rgba(255, 215, 0, 0.5)';
                    } else if (isAffordable) {
            borderColor = isChecked ? 'rgba(76, 175, 80, 0.5)' : 'rgba(100, 150, 255, 0.2)';
                    }

                    const roomDiv = document.createElement('div');
                    roomDiv.className = 'mcs-jh-room';
                    roomDiv.style.background = backgroundColor;
                    roomDiv.style.borderColor = borderColor;

                    roomDiv.onclick = (e) => {
            if (e.target.type === 'checkbox') return;
            this.jhouseSelectedRoom = roomKey;
            this.jhouseLastFullRender = 0;
            this.updateJHouseContent();
                    };

                    roomDiv.onmouseover = () => {
            if (roomKey !== this.jhouseSelectedRoom) {
                if (isCheapest && isChecked) {
                    roomDiv.style.background = 'rgba(255, 215, 0, 0.3)';
                } else if (isAffordable) {
                    roomDiv.style.background = isChecked ? 'rgba(76, 175, 80, 0.3)' : 'rgba(100, 150, 255, 0.15)';
                } else {
                    roomDiv.style.background = '#444';
                }
            }
                    };

                    roomDiv.onmouseout = () => {
            if (roomKey !== this.jhouseSelectedRoom) {
                if (isCheapest && isChecked) {
                    roomDiv.style.background = 'rgba(255, 215, 0, 0.2)';
                } else if (isAffordable) {
                    roomDiv.style.background = isChecked ? 'rgba(76, 175, 80, 0.2)' : 'rgba(100, 150, 255, 0.05)';
                } else {
                    roomDiv.style.background = '#333';
                }
            }
                    };

                    const svgIcon = createItemIcon(iconId, { width: 16, height: 16, sprite: 'skills' });
                    svgIcon.style.flexShrink = '0';

                    roomDiv.appendChild(svgIcon);

                    const levelSpan = document.createElement('span');
                    levelSpan.className = 'mcs-jh-room-level';
                    levelSpan.textContent = `Lv ${level}`;
                    roomDiv.appendChild(levelSpan);

                    const checkbox = document.createElement('input');
                    checkbox.type = 'checkbox';
                    if (!this.jhouseFilters) {
                        this.jhouseFilters = {};
                    }
                    checkbox.checked = this.jhouseFilters[roomKey] !== false;
                    checkbox.className = 'mcs-jh-room-checkbox';
                    checkbox.onclick = (e) => {
            e.stopPropagation();
            if (!this.jhouseFilters) {
                this.jhouseFilters = {};
            }
            this.jhouseFilters[roomKey] = checkbox.checked;
            this.jhStorage.set('filters', this.jhouseFilters);
            this.jhouseLastFullRender = 0;
            this.updateJHouseContent();
                    };
                    roomDiv.appendChild(checkbox);

                    gridContainer.appendChild(roomDiv);
                });

                const detailPanel = document.createElement('div');
                detailPanel.className = 'mcs-jh-detail-panel';

                const selectedRoomName = this.jhouseSelectedRoom.replace(/_/g, ' ').split(' ').map(word =>
                    word.charAt(0).toUpperCase() + word.slice(1)
                ).join(' ');

                let currentLevel = 0;
                for (const [houseRoomHrid, roomData] of Object.entries(houseData)) {
                    const roomKey = houseRoomHrid.split('/').pop() || '';
                    if (roomKey === this.jhouseSelectedRoom) {
            currentLevel = typeof roomData === 'object' ? roomData.level : roomData;
            break;
                    }
                }

                const detailTitle = document.createElement('div');
                detailTitle.className = 'mcs-jh-detail-title';
                detailTitle.textContent = `${selectedRoomName} ${currentLevel}`;
                detailPanel.appendChild(detailTitle);

                const nextLevel = currentLevel + 1;

                const HOUSE_RECIPES = this.getHouseRecipes();
                const recipe = HOUSE_RECIPES[selectedRoomName]?.[nextLevel.toString()];
                const cachedInventory = this.getCachedInventory();

                if (recipe && nextLevel <= 8) {
                const costDataAsk = this.calculateUpgradeCost(recipe, 'ask', cachedInventory);
                const costDataBid = this.calculateUpgradeCost(recipe, 'bid', cachedInventory);

                const totalAsk = costDataAsk.cost;
                const totalBid = costDataBid.cost;

                const recipeTitle = document.createElement('div');
                recipeTitle.className = 'mcs-jh-recipe-title';

                let costText = `${nextLevel} `;

                if (costDataBid.hasMarketDataIssue && costDataAsk.hasMarketDataIssue) {
                    costText += 'has no market data';
                } else {
                    costText += 'costs ';
                    if (!costDataAsk.hasMarketDataIssue) {
            costText += `${this.formatGold(totalAsk)}a `;
                    }
                    if (!costDataBid.hasMarketDataIssue) {
            costText += `${this.formatGold(totalBid)}b`;
                    }
                }

                recipeTitle.textContent = costText.trim();
                detailPanel.appendChild(recipeTitle);

                const materialsCostLabel = document.createElement('div');
                materialsCostLabel.className = 'mcs-jh-section-label mcs-jh-label-materials-cost';
                materialsCostLabel.textContent = 'Materials Cost';
                detailPanel.appendChild(materialsCostLabel);

                const totalCostValues = document.createElement('div');
                totalCostValues.className = 'mcs-jh-cost-values';

                const askSpan = document.createElement('span');
                askSpan.className = 'mcs-jh-ask-value';
                askSpan.textContent = costDataAsk.hasMarketDataIssue ? '⚠️ No market data' : `${this.formatGold(costDataAsk.cost - recipe.gold)} ask`;

                const bidSpan = document.createElement('span');
                bidSpan.className = 'mcs-jh-bid-value';
                bidSpan.textContent = costDataBid.hasMarketDataIssue ? '⚠️ No market data' : `${this.formatGold(costDataBid.cost - recipe.gold)} bid`;

                totalCostValues.appendChild(askSpan);
                totalCostValues.appendChild(bidSpan);
                detailPanel.appendChild(totalCostValues);

                const currentGold = this.getCurrentGold(cachedInventory);
                const goldNeeded = recipe.gold;
                const goldColor = this.getProgressColor(currentGold, goldNeeded);

                const goldLabel = document.createElement('div');
                goldLabel.className = 'mcs-jh-section-label mcs-jh-label-gold';
                goldLabel.textContent = 'Gold';
                detailPanel.appendChild(goldLabel);

                const goldValue = document.createElement('div');
                goldValue.className = 'mcs-jh-gold-value';
                goldValue.style.color = goldColor;
                goldValue.textContent = `${this.formatGold(currentGold)} / ${this.formatGold(goldNeeded)}`;
                detailPanel.appendChild(goldValue);

                    const materialsTitle = document.createElement('div');
                    materialsTitle.className = 'mcs-jh-materials-title';
                    materialsTitle.textContent = 'Materials Required';
                    detailPanel.appendChild(materialsTitle);

                    const materialsList = document.createElement('div');
                    materialsList.className = 'mcs-jh-materials-list';

                    Object.entries(recipe.materials).forEach(([itemHrid, amountNeeded]) => {
            const amountHave = this.getItemCount(itemHrid, cachedInventory);
            const progressColor = this.getProgressColor(amountHave, amountNeeded);

            const amountToBuy = Math.max(0, amountNeeded - amountHave);
            const hasAskData = amountToBuy > 0 ? this.getItemPrice(itemHrid, 'ask') !== null : true;
            const hasBidData = amountToBuy > 0 ? this.getItemPrice(itemHrid, 'bid') !== null : true;
            const hasMarketData = hasAskData && hasBidData;

            const materialDiv = document.createElement('div');
            materialDiv.className = 'mcs-jh-material-row';
            materialDiv.addEventListener('click', () => {
                mcsGoToMarketplace(itemHrid);
            });

            const itemName = document.createElement('span');
            itemName.className = 'mcs-jh-material-name';
            itemName.textContent = this.formatItemName(itemHrid) + (!hasMarketData ? ' ⚠️' : '');

            const itemAmount = document.createElement('span');
            itemAmount.className = 'mcs-jh-material-amount';
            itemAmount.style.color = progressColor;
            itemAmount.textContent = `${amountHave.toLocaleString()} / ${amountNeeded.toLocaleString()}`;

            materialDiv.appendChild(itemName);
            materialDiv.appendChild(itemAmount);
            materialsList.appendChild(materialDiv);
                    });

                    detailPanel.appendChild(materialsList);

                } else if (currentLevel >= 8) {
                    const maxLevelDiv = document.createElement('div');
                    maxLevelDiv.className = 'mcs-jh-max-level';
                    maxLevelDiv.textContent = 'MAX LEVEL REACHED!';
                    detailPanel.appendChild(maxLevelDiv);

                } else {
                    const noRecipeDiv = document.createElement('div');
                    noRecipeDiv.className = 'mcs-jh-no-recipe';
                    noRecipeDiv.textContent = 'Recipe data not available';
                    detailPanel.appendChild(noRecipeDiv);
                }

                mainContainer.appendChild(gridContainer);
                mainContainer.appendChild(detailPanel);

                content.appendChild(mainContainer);
            }

            updateDetailPanelOnly(houseData) {
                if (!houseData) return;

                const detailPanel = document.querySelector('#jhouse-content > div > div:nth-child(2)');
                if (!detailPanel) return;

                const cachedInventory = this.getCachedInventory();

                const selectedRoomName = this.jhouseSelectedRoom.replace(/_/g, ' ').split(' ').map(word =>
                    word.charAt(0).toUpperCase() + word.slice(1)
                ).join(' ');

                let currentLevel = 0;
                for (const [houseRoomHrid, roomData] of Object.entries(houseData)) {
                    const roomKey = houseRoomHrid.split('/').pop() || '';
                    if (roomKey === this.jhouseSelectedRoom) {
            currentLevel = typeof roomData === 'object' ? roomData.level : roomData;
            break;
                    }
                }

                const nextLevel = currentLevel + 1;
                const HOUSE_RECIPES = this.getHouseRecipes();
                const recipe = HOUSE_RECIPES[selectedRoomName]?.[nextLevel.toString()];

                if (!recipe || nextLevel > 8) return;

                const costDataAsk = this.calculateUpgradeCost(recipe, 'ask', cachedInventory);
                const costDataBid = this.calculateUpgradeCost(recipe, 'bid', cachedInventory);

                const askSpan = detailPanel.querySelector('.mcs-jh-ask-value');
                const bidSpan = detailPanel.querySelector('.mcs-jh-bid-value');

                if (askSpan) {
                    askSpan.textContent = costDataAsk.hasMarketDataIssue ? '⚠️ No market data' : `${this.formatGold(costDataAsk.cost - recipe.gold)} ask`;
                }
                if (bidSpan) {
                    bidSpan.textContent = costDataBid.hasMarketDataIssue ? '⚠️ No market data' : `${this.formatGold(costDataBid.cost - recipe.gold)} bid`;
                }

                const currentGold = this.getCurrentGold(cachedInventory);
                const goldNeeded = recipe.gold;
                const goldColor = this.getProgressColor(currentGold, goldNeeded);

                const goldValueDiv = detailPanel.querySelector('.mcs-jh-gold-value');
                if (goldValueDiv) {
                    goldValueDiv.style.color = goldColor;
                    goldValueDiv.textContent = `${this.formatGold(currentGold)} / ${this.formatGold(goldNeeded)}`;
                }

                const materialDivs = detailPanel.querySelectorAll('.mcs-jh-material-row');
                let materialIndex = 0;

                Object.entries(recipe.materials).forEach(([itemHrid, amountNeeded]) => {
                    if (materialIndex >= materialDivs.length) return;

                    const amountHave = this.getItemCount(itemHrid, cachedInventory);
                    const progressColor = this.getProgressColor(amountHave, amountNeeded);

                    const materialDiv = materialDivs[materialIndex];
                    const amountSpan = materialDiv.querySelector('span:last-child');

                    if (amountSpan) {
            amountSpan.style.color = progressColor;
            amountSpan.textContent = `${amountHave.toLocaleString()} / ${amountNeeded.toLocaleString()}`;
                    }

                    materialIndex++;
                });
            }

            makeJHouseDraggable(pane, header) {
                DragHandler.makeDraggable(pane, header, 'mcs_JH');
            }

// JHouse end

// KOllection start

            get _koMatrix() {
                if (!this.__koMatrixCached) {
                    const km = {};
                    km.zeros = (rows, cols) => {
                        const data = [];
                        for (let i = 0; i < rows; i++) data[i] = new Float64Array(cols);
                        return { rows, cols, data, get(r, c) { return this.data[r][c]; }, set(r, c, v) { this.data[r][c] = v; } };
                    };
                    km.identity = (n) => {
                        const m = km.zeros(n, n);
                        for (let i = 0; i < n; i++) m.data[i][i] = 1;
                        return m;
                    };
                    km.subtract = (a, b) => {
                        const m = km.zeros(a.rows, a.cols);
                        for (let i = 0; i < a.rows; i++)
                            for (let j = 0; j < a.cols; j++)
                                m.data[i][j] = a.data[i][j] - b.data[i][j];
                        return m;
                    };
                    km.subset = (mat, r0, r1, c0, c1) => {
                        const m = km.zeros(r1 - r0, c1 - c0);
                        for (let i = r0; i < r1; i++)
                            for (let j = c0; j < c1; j++)
                                m.data[i - r0][j - c0] = mat.data[i][j];
                        return m;
                    };
                    km.inv = (mat) => {
                        const n = mat.rows;
                        const aug = km.zeros(n, 2 * n);
                        for (let i = 0; i < n; i++) {
                            for (let j = 0; j < n; j++) aug.data[i][j] = mat.data[i][j];
                            aug.data[i][n + i] = 1;
                        }
                        for (let col = 0; col < n; col++) {
                            let maxRow = col;
                            for (let row = col + 1; row < n; row++)
                                if (Math.abs(aug.data[row][col]) > Math.abs(aug.data[maxRow][col])) maxRow = row;
                            [aug.data[col], aug.data[maxRow]] = [aug.data[maxRow], aug.data[col]];
                            const pivot = aug.data[col][col];
                            if (Math.abs(pivot) < 1e-12) continue;
                            for (let j = 0; j < 2 * n; j++) aug.data[col][j] /= pivot;
                            for (let row = 0; row < n; row++) {
                                if (row === col) continue;
                                const factor = aug.data[row][col];
                                for (let j = 0; j < 2 * n; j++) aug.data[row][j] -= factor * aug.data[col][j];
                            }
                        }
                        return km.subset(aug, 0, n, n, 2 * n);
                    };
                    km.rowSum = (mat, row) => {
                        let sum = 0;
                        for (let j = 0; j < mat.cols; j++) sum += mat.data[row][j];
                        return sum;
                    };
                    km.rowValues = (mat, row, c0, c1) => {
                        const arr = [];
                        for (let j = c0; j < c1; j++) arr.push(mat.data[row][j]);
                        return arr;
                    };
                    this.__koMatrixCached = km;
                }
                return this.__koMatrixCached;
            }

            get koStorage() {
                if (!this._koStorage) {
                    this._koStorage = createModuleStorage('KO');
                }
                return this._koStorage;
            }

            mcs_ko_handleWebSocketMessage(event) {
                if (window.MCS_MODULES_DISABLED) return;
                const data = event.detail;
                if (data && data.type === "init_character_data") {
                    this.mcs_ko_characterItems = data.characterItems;
                    this.mcs_ko_characterHouseRoomMap = data.characterHouseRoomMap;
                    this.mcs_ko_combatAbilities = data.combatUnit?.combatAbilities;
                    this.mcs_ko_character = data.character;
                    this.mcs_ko_characterSkills = data.characterSkills;
                    if (data.myMarketListings && window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.myMarketListings = data.myMarketListings;
                    }
                    setTimeout(() => this.mcs_ko_updateScores(), 100);
                }
                if (data && data.type === "init_client_data") {
                    this.mcs_ko_levelExperienceTable = data.levelExperienceTable;
                    this.mcs_ko_houseRoomDetailMap = data.houseRoomDetailMap;
                    this.mcs_ko_itemDetailMap = data.itemDetailMap;
                    this.mcs_ko_actionDetailMap = data.actionDetailMap;
                    setTimeout(() => this.mcs_ko_updateScores(), 100);
                }
                if (data?.characterItems || data?.characterHouseRoomMap || data?.combatAbilities) {
                    if (data.characterItems) this.mcs_ko_characterItems = data.characterItems;
                    if (data.characterHouseRoomMap) this.mcs_ko_characterHouseRoomMap = data.characterHouseRoomMap;
                    if (data.combatAbilities) this.mcs_ko_combatAbilities = data.combatAbilities;
                    setTimeout(() => this.mcs_ko_updateScores(), 100);
                }
                if (data && data.type === "profile_shared") {
                    setTimeout(() => this.mcs_ko_handleProfileShared(data), 100);
                }
                if (data && data.type === "market_listings_updated") {
                    if (data.myMarketListings && window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.myMarketListings = data.myMarketListings;
                    }
                    setTimeout(() => this.mcs_ko_updateScores(), 100);
                }
            }

            mcs_ko_handleEquipmentChanged() {
                if (window.mcs__global_equipment_tracker?.allCharacterItems) {
                    this.mcs_ko_characterItems = window.mcs__global_equipment_tracker.allCharacterItems;
                }
                this.mcs_ko_lastDataHash = null;
                this.mcs_ko_updateScores();
            }

            mcs_ko_addSpecialItems(marketData) {
                marketData['/items/coin'] = [{ a: 1, b: 1 }];
                marketData['/items/task_token'] = [{ a: 0, b: 0 }];
                marketData['/items/cowbell'] = [{ a: 0, b: 0 }];
                marketData['/items/small_treasure_chest'] = [{ a: 0, b: 0 }];
                marketData['/items/medium_treasure_chest'] = [{ a: 0, b: 0 }];
                marketData['/items/large_treasure_chest'] = [{ a: 0, b: 0 }];
                marketData['/items/basic_task_badge'] = [{ a: 0, b: 0 }];
                marketData['/items/advanced_task_badge'] = [{ a: 0, b: 0 }];
                marketData['/items/expert_task_badge'] = [{ a: 0, b: 0 }];
                return marketData;
            }
            async mcs_ko_fetchMarketData() {
                if (window.lootDropsTrackerInstance?.spyMarketData) {
                    let marketData = {...window.lootDropsTrackerInstance.spyMarketData};
                    marketData = this.mcs_ko_addSpecialItems(marketData);

                    const itemCount = Object.keys(marketData).length;
                    if (itemCount > 0) {
                        return marketData;
                    }
                }

                return null;
            }
            mcs_ko_getWeightedPrice(marketPrices, ratio = 0.5) {
                if (!marketPrices || !marketPrices[0]) return 0;

                let ask = marketPrices[0].a;
                let bid = marketPrices[0].b;

                if (ask > 0 && bid < 0) {
                    bid = ask;
                }
                if (bid > 0 && ask < 0) {
                    ask = bid;
                }

                const weightedPrice = ask * ratio + bid * (1 - ratio);
                return weightedPrice;
            }
            async mcs_ko_calculateHouseScore() {
                const [score] = await this.mcs_ko_calculateHouseScoreWithDetails();
                return score;
            }
            async mcs_ko_calculateHouseScoreWithDetails() {
                const marketData = await this.mcs_ko_fetchMarketData();
                if (!marketData) {
                    return [0, []];
                }

                try {
                    if (!this.mcs_ko_characterHouseRoomMap || !this.mcs_ko_houseRoomDetailMap) {
                        return [0, []];
                    }

                    const battleHouses = ["dining_room", "library", "dojo", "gym", "armory", "archery_range", "mystical_study"];
                    let battleHouseScore = 0;
                    const details = [];

                    for (const key in this.mcs_ko_characterHouseRoomMap) {
                        const house = this.mcs_ko_characterHouseRoomMap[key];
                        if (battleHouses.some((battleHouse) => house.houseRoomHrid.includes(battleHouse))) {
                            const houseCost = await this.mcs_ko_getHouseFullBuildPrice(house, marketData);
                            const scoreValue = houseCost / 1000000;
                            battleHouseScore += scoreValue;

                            const houseDetail = this.mcs_ko_houseRoomDetailMap[house.houseRoomHrid];
                            const houseName = houseDetail ? houseDetail.name : house.houseRoomHrid.replace('/house_rooms/', '');

                            details.push({
                                name: `${houseName} ${house.level}`,
                                value: scoreValue.toFixed(1)
                            });
                        }
                    }

                    details.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));

                    return [battleHouseScore, details];
                } catch (e) {
                    console.error('[KOllection] Error calculating house score:', e);
                    return [0, []];
                }
            }
            async mcs_ko_getHouseFullBuildPrice(house, marketData) {
                try {
                    if (!this.mcs_ko_houseRoomDetailMap[house.houseRoomHrid]) {
                        return 0;
                    }

                    const upgradeCostsMap = this.mcs_ko_houseRoomDetailMap[house.houseRoomHrid].upgradeCostsMap;
                    if (!upgradeCostsMap) {
                        return 0;
                    }

                    const level = house.level;
                    let cost = 0;

                    for (let i = 1; i <= level; i++) {
                        const levelUpgrades = upgradeCostsMap[i];
                        if (!levelUpgrades) {
                            continue;
                        }

                        for (const item of levelUpgrades) {
                            const marketPrices = marketData[item.itemHrid];
                            if (marketPrices && marketPrices[0]) {
                                const itemCost = item.count * this.mcs_ko_getWeightedPrice(marketPrices);
                                cost += itemCost;
                            }
                        }
                    }

                    return cost;
                } catch (e) {
                    console.error(`[KOllection] Error in getHouseFullBuildPrice for ${house.houseRoomHrid}:`, e);
                    return 0;
                }
            }
            async mcs_ko_calculateAbilityScore() {
                const [score] = await this.mcs_ko_calculateAbilityScoreWithDetails();
                return score;
            }
            async mcs_ko_calculateAbilityScoreWithDetails() {
                const marketData = await this.mcs_ko_fetchMarketData();
                if (!marketData) return [0, []];

                const exp_50_skill = ["poke", "scratch", "smack", "quick_shot", "water_strike", "fireball", "entangle", "minor_heal"];

                try {
                    if (!this.mcs_ko_combatAbilities || !this.mcs_ko_levelExperienceTable) {
                        return [0, []];
                    }

                    let totalPrice = 0;
                    const details = [];

                    this.mcs_ko_combatAbilities.forEach((ability) => {
                        const needExp = this.mcs_ko_levelExperienceTable[ability.level] ?? 0;
                        const expPerBook = exp_50_skill.some(skill => ability.abilityHrid.includes(skill)) ? 50 : 500;
                        let needBooks = needExp / expPerBook;
                        needBooks += 1;

                        const itemHrid = ability.abilityHrid.replace("/abilities/", "/items/");
                        const marketPrices = marketData[itemHrid];

                        if (marketPrices && marketPrices[0]) {
                            const weightedPrice = this.mcs_ko_getWeightedPrice(marketPrices);
                            const cost = needBooks * weightedPrice;
                            totalPrice += cost;

                            const abilityName = ability.abilityHrid.replace('/abilities/', '').split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');

                            details.push({
                                name: `${abilityName} ${ability.level}`,
                                value: (cost / 1000000).toFixed(1)
                            });
                        }
                    });

                    details.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));

                    return [totalPrice / 1000000, details];
                } catch (e) {
                    console.error('[KOllection] Error calculating ability score:', e);
                    return [0, []];
                }
            }
            async mcs_ko_calculateEquippedAbilityScore() {
                const marketData = await this.mcs_ko_fetchMarketData();
                if (!marketData) return 0;

                const exp_50_skill = ["poke", "scratch", "smack", "quick_shot", "water_strike", "fireball", "entangle", "minor_heal"];

                try {
                    if (!this.mcs_ko_combatAbilities) {
                        return 0;
                    }

                    if (!this.mcs_ko_levelExperienceTable) {
                        return 0;
                    }

                    let totalPrice = 0;

                    const equippedAbilities = this.mcs_ko_combatAbilities.filter(ability => ability.isEquipped);

                    equippedAbilities.forEach((ability) => {
                        const needExp = this.mcs_ko_levelExperienceTable[ability.level] ?? 0;
                        const expPerBook = exp_50_skill.some(skill => ability.abilityHrid.includes(skill)) ? 50 : 500;
                        let needBooks = needExp / expPerBook;
                        needBooks += 1;
                        needBooks = parseFloat(needBooks.toFixed(1));

                        const itemHrid = ability.abilityHrid.replace("/abilities/", "/items/");
                        const marketPrices = marketData[itemHrid];

                        if (marketPrices && marketPrices[0]) {
                            const weightedPrice = this.mcs_ko_getWeightedPrice(marketPrices);
                            const cost = needBooks * weightedPrice;
                            totalPrice += cost;
                        }
                    });

                    return totalPrice / 1000000;
                } catch (e) {
                    console.error('[KOllection] Error calculating equipped ability score:', e);
                    return 0;
                }
            }
            mcs_ko_buildWearableItemMap() {
                if (window.mcs__global_equipment_tracker?.allCharacterItems) {
                    const wearableItemMap = {};

                    for (const item of window.mcs__global_equipment_tracker.allCharacterItems) {
                        if (item.itemLocationHrid &&
                            !item.itemLocationHrid.includes('/item_locations/inventory') &&
                            item.count > 0) {
                            wearableItemMap[item.itemLocationHrid] = {
                                itemLocationHrid: item.itemLocationHrid,
                                itemHrid: item.itemHrid,
                                enhancementLevel: item.enhancementLevel ?? 0,
                                count: item.count
                            };
                        }
                    }

                    return wearableItemMap;
                }

                if (!this.mcs_ko_characterItems) return null;

                const wearableItemMap = {};

                for (const item of this.mcs_ko_characterItems) {
                    if (item.itemLocationHrid &&
                        !item.itemLocationHrid.includes('/item_locations/inventory') &&
                        item.count > 0) {
                        wearableItemMap[item.itemLocationHrid] = {
                            itemLocationHrid: item.itemLocationHrid,
                            itemHrid: item.itemHrid,
                            enhancementLevel: item.enhancementLevel ?? 0,
                            count: item.count
                        };
                    }
                }

                return wearableItemMap;
            }
            async mcs_ko_calculateEquipmentScore() {
                const [score] = await this.mcs_ko_calculateEquipmentScoreWithDetails();
                return score;
            }
            async mcs_ko_calculateEquipmentScoreWithDetails() {
                const marketData = await this.mcs_ko_fetchMarketData();
                if (!marketData) return [0, []];

                try {
                    const wearableItemMap = this.mcs_ko_buildWearableItemMap();
                    if (!wearableItemMap) {
                        return [0, []];
                    }

                    let networthAsk = 0;
                    let networthBid = 0;
                    const details = [];

                    for (const key in wearableItemMap) {
                        const item = wearableItemMap[key];
                        const enhanceLevel = item.enhancementLevel ?? 0;
                        const itemHrid = item.itemHrid;
                        const marketPrices = marketData[itemHrid];

                        let itemCost = 0;
                        if (enhanceLevel && enhanceLevel > 1) {
                            let totalCost = await this.mcs_ko_estimateEnhancementCost(itemHrid, enhanceLevel, marketData);
                            totalCost = totalCost ? Math.round(totalCost) : 0;
                            itemCost = totalCost;
                            networthAsk += item.count * (totalCost > 0 ? totalCost : 0);
                            networthBid += item.count * (totalCost > 0 ? totalCost : 0);
                        } else if (marketPrices && marketPrices[0]) {
                            const askPrice = marketPrices[0].a > 0 ? marketPrices[0].a : 0;
                            const bidPrice = marketPrices[0].b > 0 ? marketPrices[0].b : 0;
                            itemCost = askPrice * 0.5 + bidPrice * 0.5;
                            networthAsk += item.count * askPrice;
                            networthBid += item.count * bidPrice;
                        }

                        const itemDetail = this.mcs_ko_itemDetailMap?.[itemHrid];
                        let itemName = itemDetail ? itemDetail.name : itemHrid.replace('/items/', '');

                        let displayName = itemName;
                        if (displayName.startsWith('Refined ')) {
                            displayName = displayName.replace('Refined ', '') + ' (R)';
                        }
                        if (enhanceLevel && enhanceLevel > 0) {
                            displayName += ` +${enhanceLevel}`;
                        }

                        details.push({
                            name: displayName,
                            value: (itemCost / 1000000).toFixed(1)
                        });
                    }

                    details.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));

                    const equippedNetworth = networthAsk * 0.5 + networthBid * 0.5;
                    return [equippedNetworth / 1000000, details];
                } catch (e) {
                    console.error('[KOllection] Error calculating equipment score:', e);
                    return [0, []];
                }
            }
            async mcs_ko_calculateNetWorth() {
                const marketData = await this.mcs_ko_fetchMarketData();
                if (!marketData) return { total: 0, equipment: 0, inventory: 0, market: 0, houses: 0, abilities: 0 };

                try {
                    let equipmentNetworthAsk = 0;
                    let equipmentNetworthBid = 0;
                    let inventoryNetworthAsk = 0;
                    let inventoryNetworthBid = 0;
                    let marketValue = 0;
                    let housesValue = 0;
                    let abilitiesValue = 0;

                    const characterItems = this.mcs_ko_characterItems ?? [];
                    for (const item of characterItems) {
                        if (!item.itemHrid) continue;

                        const enhanceLevel = item.enhancementLevel ?? 0;
                        const marketPrices = marketData[item.itemHrid];

                        if (enhanceLevel > 1) {
                            const totalCost = await this.mcs_ko_estimateEnhancementCost(item.itemHrid, enhanceLevel, marketData);
                            const cost = totalCost ? Math.round(totalCost) : 0;
                            if (item.itemLocationHrid === '/item_locations/inventory') {
                                inventoryNetworthAsk += item.count * (cost > 0 ? cost : 0);
                                inventoryNetworthBid += item.count * (cost > 0 ? cost : 0);
                            } else {
                                equipmentNetworthAsk += item.count * (cost > 0 ? cost : 0);
                                equipmentNetworthBid += item.count * (cost > 0 ? cost : 0);
                            }
                        } else if (marketPrices && marketPrices[0]) {
                            const askPrice = marketPrices[0].a > 0 ? marketPrices[0].a : 0;
                            const bidPrice = marketPrices[0].b > 0 ? marketPrices[0].b : 0;
                            if (item.itemLocationHrid === '/item_locations/inventory') {
                                inventoryNetworthAsk += item.count * askPrice;
                                inventoryNetworthBid += item.count * bidPrice;
                            } else {
                                equipmentNetworthAsk += item.count * askPrice;
                                equipmentNetworthBid += item.count * bidPrice;
                            }
                        }
                    }

                    const equipmentValue = equipmentNetworthAsk * 0.5 + equipmentNetworthBid * 0.5;
                    const inventoryValue = inventoryNetworthAsk * 0.5 + inventoryNetworthBid * 0.5;

                    let myMarketListings = window.lootDropsTrackerInstance?.myMarketListings;
                    if (!myMarketListings || myMarketListings.length === 0) {
                        try {
                            const cachedData = CharacterDataStorage.get();
                            if (cachedData) {
                                myMarketListings = cachedData.myMarketListings ?? [];
                                if (window.lootDropsTrackerInstance && myMarketListings.length > 0) {
                                    window.lootDropsTrackerInstance.myMarketListings = myMarketListings;
                                }
                            }
                        } catch (e) {
                            console.error('[KOllection] Error loading market listings from localStorage:', e);
                            myMarketListings = [];
                        }
                    }
                    let marketListingsNetworthAsk = 0;
                    let marketListingsNetworthBid = 0;
                    if (myMarketListings && myMarketListings.length > 0) {
                        for (const listing of myMarketListings) {
                            if (!listing.itemHrid) continue;

                            const quantity = listing.orderQuantity - (listing.filledQuantity ?? 0);
                            const enhancementLevel = listing.enhancementLevel ?? 0;
                            const marketPrices = marketData[listing.itemHrid];

                            if (!marketPrices || !marketPrices[0]) continue;

                            let askPrice = marketPrices[0].a ?? 0;
                            let bidPrice = marketPrices[0].b ?? 0;

                            if (listing.isSell) {
                                const taxRate = listing.itemHrid === '/items/bag_of_10_cowbells' ? 0.18 : 0.02;
                                askPrice *= (1 - taxRate);
                                bidPrice *= (1 - taxRate);

                                if (enhancementLevel > 1) {
                                    const totalCost = await this.mcs_ko_estimateEnhancementCost(listing.itemHrid, enhancementLevel, marketData);
                                    const cost = totalCost ? Math.round(totalCost) : 0;
                                    marketListingsNetworthAsk += quantity * (cost > 0 ? cost : 0);
                                    marketListingsNetworthBid += quantity * (cost > 0 ? cost : 0);
                                } else {
                                    marketListingsNetworthAsk += quantity * (askPrice > 0 ? askPrice : 0);
                                    marketListingsNetworthBid += quantity * (bidPrice > 0 ? bidPrice : 0);
                                }
                                marketListingsNetworthAsk += listing.unclaimedCoinCount ?? 0;
                                marketListingsNetworthBid += listing.unclaimedCoinCount ?? 0;
                            } else {
                                marketListingsNetworthAsk += quantity * listing.price;
                                marketListingsNetworthBid += quantity * listing.price;
                                marketListingsNetworthAsk += (listing.unclaimedItemCount ?? 0) * (askPrice > 0 ? askPrice : 0);
                                marketListingsNetworthBid += (listing.unclaimedItemCount ?? 0) * (bidPrice > 0 ? bidPrice : 0);
                            }
                        }
                    }
                    marketValue = marketListingsNetworthAsk * 0.5 + marketListingsNetworthBid * 0.5;

                    const marketData2 = await this.mcs_ko_fetchMarketData();
                    if (marketData2 && this.mcs_ko_characterHouseRoomMap) {
                        for (const key in this.mcs_ko_characterHouseRoomMap) {
                            const house = this.mcs_ko_characterHouseRoomMap[key];
                            const houseCost = await this.mcs_ko_getHouseFullBuildPrice(house, marketData2);
                            housesValue += houseCost;
                        }
                    }

                    const [abilityScore] = await this.mcs_ko_calculateAbilityScoreWithDetails();
                    abilitiesValue = abilityScore * 1000000;

                    const total = equipmentValue + inventoryValue + marketValue + housesValue + abilitiesValue;

                    return {
                        total,
                        equipment: equipmentValue,
                        inventory: inventoryValue,
                        market: marketValue,
                        houses: housesValue,
                        abilities: abilitiesValue
                    };
                } catch (e) {
                    console.error('[KOllection] Error calculating net worth:', e);
                    return { total: 0, equipment: 0, inventory: 0, market: 0, houses: 0, abilities: 0 };
                }
            }
            mcs_ko_formatNetWorth(value) {
                return mcsFormatCurrency(value, 'cost');
            }
            mcs_ko_getActionHridFromItemName(itemHrid) {
                if (!this.mcs_ko_itemDetailMap || !this.mcs_ko_actionDetailMap) return null;

                const itemDetail = this.mcs_ko_itemDetailMap[itemHrid];
                if (!itemDetail) return null;

                if (itemDetail.actionHrid) return itemDetail.actionHrid;

                let itemName = itemDetail.name;

                itemName = itemName.replace("Milk", "Cow");
                itemName = itemName.replace("Log", "Tree");
                itemName = itemName.replace("Cowing", "Milking");
                itemName = itemName.replace("Rainbow Cow", "Unicow");
                itemName = itemName.replace("Collector's Boots", "Collectors Boots");
                itemName = itemName.replace("Knight's Aegis", "Knights Aegis");

                for (const action of Object.values(this.mcs_ko_actionDetailMap)) {
                    if (action.name === itemName) {
                        return action.hrid;
                    }
                }

                return null;
            }
            mcs_ko_getBaseItemProductionCost(itemHrid, marketData) {
                const actionHrid = this.mcs_ko_getActionHridFromItemName(itemHrid);

                if (!actionHrid || !this.mcs_ko_actionDetailMap?.[actionHrid]) return -1;

                const actionDetail = this.mcs_ko_actionDetailMap[actionHrid];

                let totalPrice = 0;

                if (actionDetail.inputItems) {
                    for (const item of actionDetail.inputItems) {
                        const itemPrice = this.mcs_ko_getItemMarketPrice(item.itemHrid, marketData);
                        totalPrice += itemPrice * item.count;
                    }
                }

                totalPrice *= 0.9;

                if (actionDetail.upgradeItemHrid) {
                    const upgradePrice = this.mcs_ko_getItemMarketPrice(actionDetail.upgradeItemHrid, marketData);
                    totalPrice += upgradePrice * 1;
                }

                return totalPrice;
            }
            mcs_ko_getRealisticBaseItemPrice(itemHrid, marketData) {
                const capeItemTokenData = {
                    '/items/chimerical_quiver': {
                        tokenCost: 35000,
                        tokenShopItems: [
                            { hrid: '/items/griffin_leather', cost: 600 },
                            { hrid: '/items/manticore_sting', cost: 1000 },
                            { hrid: '/items/jackalope_antler', cost: 1200 },
                            { hrid: '/items/dodocamel_plume', cost: 3000 },
                            { hrid: '/items/griffin_talon', cost: 3000 }
                        ]
                    },
                    '/items/sinister_cape': {
                        tokenCost: 27000,
                        tokenShopItems: [
                            { hrid: '/items/acrobats_ribbon', cost: 2000 },
                            { hrid: '/items/magicians_cloth', cost: 2000 },
                            { hrid: '/items/chaotic_chain', cost: 3000 },
                            { hrid: '/items/cursed_ball', cost: 3000 }
                        ]
                    },
                    '/items/enchanted_cloak': {
                        tokenCost: 27000,
                        tokenShopItems: [
                            { hrid: '/items/royal_cloth', cost: 2000 },
                            { hrid: '/items/knights_ingot', cost: 2000 },
                            { hrid: '/items/bishops_scroll', cost: 2000 },
                            { hrid: '/items/regal_jewel', cost: 3000 },
                            { hrid: '/items/sundering_jewel', cost: 3000 }
                        ]
                    }
                };

                if (capeItemTokenData[itemHrid]) {
                    const capeData = capeItemTokenData[itemHrid];
                    let bestValuePerToken = 0;
                    for (const shopItem of capeData.tokenShopItems) {
                        const shopItemPrice = this.mcs_ko_getItemMarketPrice(shopItem.hrid, marketData);
                        if (shopItemPrice > 0) {
                            const valuePerToken = shopItemPrice / shopItem.cost;
                            if (valuePerToken > bestValuePerToken) {
                                bestValuePerToken = valuePerToken;
                            }
                        }
                    }
                    return bestValuePerToken * capeData.tokenCost;
                }

                const itemDetail = this.mcs_ko_itemDetailMap[itemHrid];
                const productionCost = itemDetail ? this.mcs_ko_getBaseItemProductionCost(itemHrid, marketData) : -1;

                const marketPrices = marketData[itemHrid];
                if (!marketPrices || !marketPrices[0]) {
                    return productionCost;
                }

                const ask = marketPrices[0].a;
                const bid = marketPrices[0].b;

                let result = 0;

                if (ask > 0) {
                    if (bid > 0) {
                        if (ask / bid > 1.3) {
                            result = Math.max(bid, productionCost);
                        } else {
                            result = ask;
                        }
                    } else {
                        if (productionCost > 0 && ask / productionCost > 1.3) {
                            result = productionCost;
                        } else {
                            result = Math.max(ask, productionCost);
                        }
                    }
                } else {
                    if (bid > 0) {
                        result = Math.max(bid, productionCost);
                    } else {
                        result = productionCost;
                    }
                }

                return result;
            }
            mcs_ko_getItemMarketPrice(itemHrid, marketData) {
                const marketPrices = marketData[itemHrid];
                if (!marketPrices || !marketPrices[0]) return 0;

                let ask = marketPrices[0].a;
                let bid = marketPrices[0].b;

                if (ask < 0 && bid < 0) return 0;

                if (ask > 0 && bid < 0) return ask;
                if (bid > 0 && ask < 0) return bid;

                return ask;
            }
            mcs_ko_getCosts(itemHrid, marketData) {
                const itemDetail = this.mcs_ko_itemDetailMap[itemHrid];
                if (!itemDetail) return { baseCost: 0, minProtectionCost: 0, perActionCost: 0 };

                const baseCost = this.mcs_ko_getRealisticBaseItemPrice(itemHrid, marketData);

                const protectionHrids = itemDetail.protectionItemHrids ?? [];
                const allProtectionHrids = [itemHrid, '/items/mirror_of_protection', ...protectionHrids];

                let minProtectionCost = baseCost;
                for (let i = 0; i < allProtectionHrids.length; i++) {
                    const protHrid = allProtectionHrids[i];
                    const cost = this.mcs_ko_getRealisticBaseItemPrice(protHrid, marketData);
                    if (i === 0) {
                        minProtectionCost = cost;
                    } else {
                        if (cost > 0 && (minProtectionCost < 0 || cost < minProtectionCost)) {
                            minProtectionCost = cost;
                        }
                    }
                }

                let perActionCost = 0;
                if (itemDetail.enhancementCosts) {
                    for (const need of itemDetail.enhancementCosts) {
                        const price = need.itemHrid.startsWith('/items/trainee_')
                            ? 250000
                            : this.mcs_ko_getItemMarketPrice(need.itemHrid, marketData);
                        perActionCost += price * need.count;
                    }
                }

                return { baseCost, minProtectionCost, perActionCost };
            }
            mcs_ko_enhancelate(itemHrid, stopAt, protectAt) {
                const successRate = [50, 45, 45, 40, 40, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30];
                const itemDetail = this.mcs_ko_itemDetailMap[itemHrid];
                if (!itemDetail) return { actions: 0, protect_count: 0 };

                const itemLevel = itemDetail.itemLevel || 1;

                const enhancingLevel = 125;
                const laboratoryLevel = 6;
                const enhancerBonus = 5.42;
                const teaEnhancing = false;
                const teaSuperEnhancing = false;
                const teaUltraEnhancing = true;
                const teaBlessed = true;

                const effectiveLevel = enhancingLevel + (teaEnhancing ? 3 : 0) + (teaSuperEnhancing ? 6 : 0) + (teaUltraEnhancing ? 8 : 0);
                let totalBonus;
                if (effectiveLevel >= itemLevel) {
                    totalBonus = 1 + (0.05 * (effectiveLevel + laboratoryLevel - itemLevel) + enhancerBonus) / 100;
                } else {
                    totalBonus = 1 - 0.5 * (1 - effectiveLevel / itemLevel) + (0.05 * laboratoryLevel + enhancerBonus) / 100;
                }

                const km = this._koMatrix;
                let markov = km.zeros(20, 20);
                for (let i = 0; i < stopAt; i++) {
                    const successChance = (successRate[i] / 100.0) * totalBonus;
                    const destination = i >= protectAt ? i - 1 : 0;
                    if (teaBlessed) {
                        markov.set(i, i + 2, successChance * 0.01);
                        markov.set(i, i + 1, successChance * 0.99);
                        markov.set(i, destination, 1 - successChance);
                    } else {
                        markov.set(i, i + 1, successChance);
                        markov.set(i, destination, 1.0 - successChance);
                    }
                }
                markov.set(stopAt, stopAt, 1.0);

                const Q = km.subset(markov, 0, stopAt, 0, stopAt);
                const M = km.inv(km.subtract(km.identity(stopAt), Q));
                const attempts = km.rowSum(M, 0);

                const protectValues = km.rowValues(M, 0, protectAt, stopAt);
                const protects = protectValues.map((a, i) => a * markov.get(i + protectAt, i + protectAt - 1)).reduce((a, b) => a + b, 0);

                return { actions: attempts, protect_count: protects };
            }
            async mcs_ko_findBestEnhanceStrat(itemHrid, stopAt, marketData) {
                const costs = this.mcs_ko_getCosts(itemHrid, marketData);

                const allResults = [];
                for (let protectAt = 2; protectAt <= stopAt; protectAt++) {
                    const simResult = this.mcs_ko_enhancelate(itemHrid, stopAt, protectAt);
                    const totalCost = costs.baseCost + costs.minProtectionCost * simResult.protect_count + costs.perActionCost * simResult.actions;
                    allResults.push({
                        protect_at: protectAt,
                        protect_count: simResult.protect_count,
                        simResult: simResult,
                        costs: costs,
                        totalCost: totalCost
                    });
                }

                let best = null;
                for (const r of allResults) {
                    if (best === null || r.totalCost < best.totalCost) {
                        best = r;
                    }
                }

                return best;
            }
            async mcs_ko_estimateEnhancementCost(itemHrid, targetLevel, marketData) {
                if (!this.mcs_ko_itemDetailMap) {
                    const marketPrices = marketData[itemHrid];
                    if (marketPrices && marketPrices[0]) {
                        const basePrice = this.mcs_ko_getWeightedPrice(marketPrices);
                        return basePrice * targetLevel * 2;
                    }
                    return 0;
                }

                const best = await this.mcs_ko_findBestEnhanceStrat(itemHrid, targetLevel, marketData);
                return best ? best.totalCost : 0;
            }
            mcs_ko_getPlayerName() {
                try {
                    return this.mcs_ko_character?.name || 'Unknown';
                } catch (e) {
                    console.error('[KOllection] Error getting player name:', e);
                    return 'Unknown';
                }
            }
            mcs_ko_loadFromLocalStorage() {
                try {
                    const cachedData = CharacterDataStorage.get();
                    if (cachedData) {
                        this.mcs_ko_characterItems = cachedData.characterItems;
                        this.mcs_ko_characterHouseRoomMap = cachedData.characterHouseRoomMap;
                        this.mcs_ko_combatAbilities = cachedData.combatUnit?.combatAbilities;
                        this.mcs_ko_character = cachedData.character;
                        this.mcs_ko_characterSkills = cachedData.characterSkills;
                    }

                    this.mcs_ko_levelExperienceTable = InitClientDataCache.getLevelExperienceTable();
                    this.mcs_ko_houseRoomDetailMap = InitClientDataCache.getHouseRoomDetailMap();
                    this.mcs_ko_itemDetailMap = InitClientDataCache.getItemDetailMap();
                    this.mcs_ko_actionDetailMap = InitClientDataCache.getActionDetailMap();
                } catch (e) {
                    console.error('[KOllection] Error loading from localStorage:', e);
                }
            }
            createKOllectionPane() {
                if (document.getElementById('kollection-pane')) return;

                this.mcs_ko_characterItems = null;
                this.mcs_ko_combatAbilities = null;
                this.mcs_ko_characterHouseRoomMap = null;
                this.mcs_ko_levelExperienceTable = null;
                this.mcs_ko_houseRoomDetailMap = null;
                this.mcs_ko_itemDetailMap = null;
                this.mcs_ko_actionDetailMap = null;
                this.mcs_ko_character = null;
                this.mcs_ko_characterSkills = null;

                this.mcs_ko_lastDataHash = null;
                this.mcs_ko_cachedScores = null;

                this.mcs_ko_loadFromLocalStorage();

                const pane = document.createElement('div');
                pane.id = 'kollection-pane';
                registerPanel('kollection-pane');
                pane.className = 'mcs-pane mcs-ko-pane';

                const header = document.createElement('div');
                header.className = 'mcs-pane-header';

                const titleSection = document.createElement('div');
                titleSection.className = 'mcs-ko-title-section';

                const titleSpan = document.createElement('span');
                titleSpan.id = 'kollection-title';
                titleSpan.className = 'mcs-pane-title';
                titleSpan.textContent = 'KOllection Score: 0.0';

                titleSection.appendChild(titleSpan);

                const buttonSection = document.createElement('div');
                buttonSection.className = 'mcs-button-section';

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'kollection-minimize-btn';
                minimizeBtn.textContent = '−';
                minimizeBtn.className = 'mcs-btn';

                buttonSection.appendChild(minimizeBtn);
                header.appendChild(titleSection);
                header.appendChild(buttonSection);

                const content = document.createElement('div');
                content.id = 'kollection-content';
                content.className = 'mcs-ko-content';

                const playerNameDiv = document.createElement('div');
                playerNameDiv.className = 'mcs-ko-player-name';
                playerNameDiv.id = 'kollection-player-name';
                playerNameDiv.textContent = 'Loading...';
                content.appendChild(playerNameDiv);

                const scoreItems = [
                    { id: 'house', label: 'Battle House score', detailsId: 'kollection-house-details' },
                    { id: 'ability', label: 'Ability score', detailsId: 'kollection-ability-details' },
                    { id: 'equipment', label: 'Equipment score', detailsId: 'kollection-equipment-details' }
                ];

                scoreItems.forEach(item => {
                    const containerDiv = document.createElement('div');
                    containerDiv.className = 'mcs-ko-score-container';

                    const scoreDiv = document.createElement('div');
                    scoreDiv.className = 'mcs-ko-score-row';

                    const toggleSpan = document.createElement('span');
                    toggleSpan.id = `kollection-${item.id}-toggle`;
                    toggleSpan.textContent = '+ ';
                    toggleSpan.className = 'mcs-ko-toggle-indicator';

                    const labelValueDiv = document.createElement('div');
                    labelValueDiv.className = 'mcs-ko-label-value';

                    const labelSpan = document.createElement('span');
                    labelSpan.textContent = item.label + ':';
                    labelSpan.className = 'mcs-ko-score-label';

                    const valueSpan = document.createElement('span');
                    valueSpan.id = `kollection-${item.id}-score`;
                    valueSpan.textContent = '0.0';
                    valueSpan.className = 'mcs-ko-score-value';

                    labelValueDiv.appendChild(labelSpan);
                    labelValueDiv.appendChild(valueSpan);

                    scoreDiv.appendChild(toggleSpan);
                    scoreDiv.appendChild(labelValueDiv);

                    const detailsDiv = document.createElement('div');
                    detailsDiv.id = item.detailsId;
                    detailsDiv.className = 'mcs-ko-details';

                    scoreDiv.onclick = () => {
                        const isCollapsed = detailsDiv.style.display === 'none';
                        detailsDiv.style.display = isCollapsed ? 'block' : 'none';
                        toggleSpan.textContent = isCollapsed ? '↓ ' : '+ ';
                    };

                    containerDiv.appendChild(scoreDiv);
                    containerDiv.appendChild(detailsDiv);
                    content.appendChild(containerDiv);
                });

                const totalDiv = document.createElement('div');
                totalDiv.className = 'mcs-ko-total-row';

                const totalLabel = document.createElement('span');
                totalLabel.textContent = 'Character Build Score:';
                totalLabel.className = 'mcs-ko-total-label';

                const totalValue = document.createElement('span');
                totalValue.id = 'kollection-total-score';
                totalValue.textContent = '0.0';
                totalValue.className = 'mcs-ko-total-value';

                totalDiv.appendChild(totalLabel);
                totalDiv.appendChild(totalValue);
                content.appendChild(totalDiv);

                const netWorthContainer = document.createElement('div');
                netWorthContainer.className = 'mcs-ko-networth-container';

                const netWorthHeader = document.createElement('div');
                netWorthHeader.className = 'mcs-ko-networth-header';

                const netWorthToggle = document.createElement('span');
                netWorthToggle.id = 'kollection-networth-toggle';
                netWorthToggle.textContent = '+ Net Worth:';

                const netWorthTotal = document.createElement('span');
                netWorthTotal.id = 'kollection-networth-total';
                netWorthTotal.textContent = '0';
                netWorthTotal.className = 'mcs-ko-score-value';

                netWorthHeader.appendChild(netWorthToggle);
                netWorthHeader.appendChild(netWorthTotal);

                const netWorthDetails = document.createElement('div');
                netWorthDetails.id = 'kollection-networth-details';
                netWorthDetails.className = 'mcs-ko-networth-details';

    netWorthDetails.innerHTML = `
        <div class="mcs-ko-networth-row"><span>Equipment:</span><span id="kollection-networth-equipment">0</span></div>
        <div class="mcs-ko-networth-row"><span>Inventory:</span><span id="kollection-networth-inventory">0</span></div>
        <div class="mcs-ko-networth-row"><span>Market Listings:</span><span id="kollection-networth-market">0</span></div>
        <div class="mcs-ko-networth-row"><span>Houses:</span><span id="kollection-networth-houses">0</span></div>
        <div class="mcs-ko-networth-row"><span>Abilities:</span><span id="kollection-networth-abilities">0</span></div>
                `;

                netWorthHeader.onclick = () => {
                    const isCollapsed = netWorthDetails.style.display === 'none';
                    netWorthDetails.style.display = isCollapsed ? 'block' : 'none';
                    netWorthToggle.textContent = (isCollapsed ? '- ' : '+ ') + 'Net Worth:';
                };

                netWorthContainer.appendChild(netWorthHeader);
                netWorthContainer.appendChild(netWorthDetails);
                content.appendChild(netWorthContainer);

                const inspectedPlayersDiv = document.createElement('div');
                inspectedPlayersDiv.className = 'mcs-ko-inspected-section';

                const inspectedHeader = document.createElement('div');
                inspectedHeader.className = 'mcs-ko-inspected-header';
                inspectedHeader.id = 'kollection-inspected-header';
                inspectedHeader.textContent = '+ Inspected Players (0)';

                const inspectedList = document.createElement('div');
                inspectedList.id = 'kollection-inspected-list';
                inspectedList.className = 'mcs-ko-inspected-list';

                inspectedPlayersDiv.appendChild(inspectedHeader);
                inspectedPlayersDiv.appendChild(inspectedList);
                content.appendChild(inspectedPlayersDiv);

                inspectedHeader.onclick = () => {
                    const isCollapsed = inspectedList.style.display === 'none';
                    inspectedList.style.display = isCollapsed ? 'block' : 'none';
                    const count = inspectedList.children.length;
                    inspectedHeader.textContent = (isCollapsed ? '↓ ' : '+ ') + `Inspected Players (${count})`;
                };

                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);

                this.mcs_ko_makeDraggable(pane, header);

                const savedMinimized = this.koStorage.get('minimized') === true || this.koStorage.get('minimized') === 'true';
                this.mcs_ko_isMinimized = savedMinimized;
                if (savedMinimized) {
                    minimizeBtn.textContent = '+';
                    content.style.display = 'none';
                    header.style.borderRadius = '6px';
                }

                minimizeBtn.onclick = () => {
                    this.mcs_ko_isMinimized = !this.mcs_ko_isMinimized;
                    if (this.mcs_ko_isMinimized) {
                        content.style.display = 'none';
                        minimizeBtn.textContent = '+';
                        header.style.borderRadius = '6px';
                        this.koStorage.set('minimized', true);
                    } else {
                        content.style.display = 'flex';
                        minimizeBtn.textContent = '−';
                        header.style.borderRadius = '6px 6px 0 0';
                        this.koStorage.set('minimized', false);
                        this.constrainPanelToBoundaries('kollection-pane', 'mcs_KO', true);
                    }
                };

                setTimeout(() => {
                    this.mcs_ko_updateScores();
                    this.mcs_ko_updateInspectedPlayersList();
                }, 2000);

                VisibilityManager.register('kollection-update', () => {
                    this.mcs_ko_loadFromLocalStorage();
                    this.mcs_ko_updateScores();
                    this.mcs_ko_updateInspectedPlayersList();
                }, 30000);

                this._koWsListener = this.mcs_ko_handleWebSocketMessage.bind(this);
                this._koEquipChangedListener = this.mcs_ko_handleEquipmentChanged.bind(this);
                window.addEventListener('EquipSpyWebSocketMessage', this._koWsListener);
                window.addEventListener('MCS_EquipmentChanged', this._koEquipChangedListener);
            }
            async mcs_ko_updateScores() {
                try {
                    const playerName = this.mcs_ko_getPlayerName();

                    const equippedItems = window.mcs__global_equipment_tracker?.getEquippedItems() ?? [];
                    const equippedHash = JSON.stringify(equippedItems.map(i => ({
                        location: i.itemLocationHrid,
                        item: i.itemHrid,
                        enhancement: i.enhancementLevel,
                        count: i.count
                    })));

                    const marketListings = window.lootDropsTrackerInstance?.myMarketListings ?? [];
                    const marketListingsHash = JSON.stringify(marketListings.map(l => ({
                        id: l.id,
                        filled: l.filledQuantity,
                        quantity: l.orderQuantity,
                        unclaimed: (l.unclaimedCoinCount ?? 0) + (l.unclaimedItemCount ?? 0)
                    })));

                    const dataHash = JSON.stringify({
                        items: this.mcs_ko_characterItems?.length ?? 0,
                        abilities: this.mcs_ko_combatAbilities?.length ?? 0,
                        houses: Object.keys(this.mcs_ko_characterHouseRoomMap ?? {}).length,
                        skills: JSON.stringify(this.mcs_ko_characterSkills),
                        equipped: equippedHash,
                        marketListings: marketListingsHash
                    });

                    const isDataLoading = !this.mcs_ko_characterItems &&
                                          !this.mcs_ko_combatAbilities &&
                                          !this.mcs_ko_characterHouseRoomMap;

                    if (!isDataLoading && this.mcs_ko_lastDataHash === dataHash && this.mcs_ko_cachedScores) {
                        const cached = this.mcs_ko_cachedScores;

                        const playerNameElem = document.getElementById('kollection-player-name');
                        const houseScoreElem = document.getElementById('kollection-house-score');
                        const abilityScoreElem = document.getElementById('kollection-ability-score');
                        const equipmentScoreElem = document.getElementById('kollection-equipment-score');
                        const totalScoreElem = document.getElementById('kollection-total-score');
                        const titleElem = document.getElementById('kollection-title');

                        if (playerNameElem) playerNameElem.textContent = playerName;
                        if (houseScoreElem) houseScoreElem.textContent = cached.houseScore.toFixed(1);
                        if (abilityScoreElem) abilityScoreElem.textContent = cached.abilityScore.toFixed(1);
                        if (equipmentScoreElem) equipmentScoreElem.textContent = cached.equipmentScore.toFixed(1);
                        if (totalScoreElem) totalScoreElem.textContent = cached.totalScore.toFixed(1);
                        if (titleElem) titleElem.textContent = `KOllection Score: ${cached.totalScore.toFixed(1)}`;

                        this.mcs_ko_updateDetailsSection('kollection-house-details', cached.houseDetails);
                        this.mcs_ko_updateDetailsSection('kollection-ability-details', cached.abilityDetails);
                        this.mcs_ko_updateDetailsSection('kollection-equipment-details', cached.equipmentDetails);

                        if (cached.netWorth) {
                            this.mcs_ko_updateNetWorthDisplay(cached.netWorth);
                        }

                        return;
                    }

                    const [houseScore, houseDetails] = await this.mcs_ko_calculateHouseScoreWithDetails();
                    const [abilityScore, abilityDetails] = await this.mcs_ko_calculateAbilityScoreWithDetails();

                    const netWorth = await this.mcs_ko_calculateNetWorth();

                    const equipmentScore = netWorth.equipment / 1000000;

                    const [, equipmentDetails] = await this.mcs_ko_calculateEquipmentScoreWithDetails();

                    const totalScore = houseScore + abilityScore + equipmentScore;

                    this.mcs_ko_lastDataHash = dataHash;
                    this.mcs_ko_cachedScores = {
                        houseScore,
                        abilityScore,
                        equipmentScore,
                        totalScore,
                        houseDetails,
                        abilityDetails,
                        equipmentDetails,
                        netWorth
                    };

                    const playerNameElem = document.getElementById('kollection-player-name');
                    const houseScoreElem = document.getElementById('kollection-house-score');
                    const abilityScoreElem = document.getElementById('kollection-ability-score');
                    const equipmentScoreElem = document.getElementById('kollection-equipment-score');
                    const totalScoreElem = document.getElementById('kollection-total-score');
                    const titleElem = document.getElementById('kollection-title');

                    if (playerNameElem) playerNameElem.textContent = playerName;
                    if (houseScoreElem) houseScoreElem.textContent = houseScore.toFixed(1);
                    if (abilityScoreElem) abilityScoreElem.textContent = abilityScore.toFixed(1);
                    if (equipmentScoreElem) equipmentScoreElem.textContent = equipmentScore.toFixed(1);
                    if (totalScoreElem) totalScoreElem.textContent = totalScore.toFixed(1);
                    if (titleElem) titleElem.textContent = `KOllection Score: ${totalScore.toFixed(1)}`;

                    this.mcs_ko_updateDetailsSection('kollection-house-details', houseDetails);
                    this.mcs_ko_updateDetailsSection('kollection-ability-details', abilityDetails);
                    this.mcs_ko_updateDetailsSection('kollection-equipment-details', equipmentDetails);

                    this.mcs_ko_updateNetWorthDisplay(netWorth);

                } catch (e) {
                    console.error('[KOllection] Error updating scores:', e);
                }
            }
            mcs_ko_updateNetWorthDisplay(netWorth) {
                const totalElem = document.getElementById('kollection-networth-total');
                const equipmentElem = document.getElementById('kollection-networth-equipment');
                const inventoryElem = document.getElementById('kollection-networth-inventory');
                const marketElem = document.getElementById('kollection-networth-market');
                const housesElem = document.getElementById('kollection-networth-houses');
                const abilitiesElem = document.getElementById('kollection-networth-abilities');

                if (totalElem) totalElem.textContent = this.mcs_ko_formatNetWorth(netWorth.total);
                if (equipmentElem) equipmentElem.textContent = this.mcs_ko_formatNetWorth(netWorth.equipment);
                if (inventoryElem) inventoryElem.textContent = this.mcs_ko_formatNetWorth(netWorth.inventory);
                if (marketElem) marketElem.textContent = this.mcs_ko_formatNetWorth(netWorth.market);
                if (housesElem) housesElem.textContent = this.mcs_ko_formatNetWorth(netWorth.houses);
                if (abilitiesElem) abilitiesElem.textContent = this.mcs_ko_formatNetWorth(netWorth.abilities);
            }
            mcs_ko_updateDetailsSection(elementId, details) {
                const elem = document.getElementById(elementId);
                if (!elem || !details || details.length === 0) return;

    elem.innerHTML = details.map(detail => `
        <div class="mcs-ko-detail-row">
            <span>${detail.name}</span>
            <span class="mcs-ko-score-value">${detail.value}</span>
        </div>
                `).join('');
            }
            mcs_ko_makeDraggable(pane, header) {
                DragHandler.makeDraggable(pane, header, 'mcs_KO');
            }
            mcs_ko_isProfileInKollection(characterID) {
                try {
                    const stored = localStorage.getItem('mcs__global_KO_inspected_players');
                    if (!stored) return false;
                    const inspectedPlayers = JSON.parse(stored);
                    return !!inspectedPlayers[characterID];
                } catch (e) {
                    console.error('[KOllection] Error checking if profile is in KOllection:', e);
                    return false;
                }
            }
            async mcs_ko_addProfileToKollection(profileData) {
                try {
                    const playerName = profileData.profile?.sharableCharacter?.name || 'Unknown';
                    const characterID = profileData.profile?.characterSkills?.[0]?.characterID;

                    let inspectedPlayers = {};
                    try {
                        const stored = localStorage.getItem('mcs__global_KO_inspected_players');
                        if (stored) {
                            inspectedPlayers = JSON.parse(stored);
                        }
                    } catch (e) {
                        console.error('[KOllection] Error loading inspected players:', e);
                    }

                    const [houseScore, abilityScore, equipmentScore, houseDetails, abilityDetails, equipmentDetails] = await this.mcs_ko_calculateProfileScoresWithDetails(profileData);
                    const totalScore = houseScore + abilityScore + equipmentScore;

                    if (!inspectedPlayers[characterID]) {
                        inspectedPlayers[characterID] = {
                            name: playerName,
                            count: Object.keys(inspectedPlayers).length + 1,
                            firstSeen: Date.now(),
                            lastSeen: Date.now(),
                            profileData: profileData
                        };
                    } else {
                        inspectedPlayers[characterID].lastSeen = Date.now();
                        inspectedPlayers[characterID].profileData = profileData;
                    }

                    inspectedPlayers[characterID].houseScore = houseScore;
                    inspectedPlayers[characterID].abilityScore = abilityScore;
                    inspectedPlayers[characterID].equipmentScore = equipmentScore;
                    inspectedPlayers[characterID].totalScore = totalScore;
                    inspectedPlayers[characterID].equipmentHidden = profileData.profile?.hideWearableItems;
                    inspectedPlayers[characterID].houseDetails = houseDetails;
                    inspectedPlayers[characterID].abilityDetails = abilityDetails;
                    inspectedPlayers[characterID].equipmentDetails = equipmentDetails;

                    localStorage.setItem('mcs__global_KO_inspected_players', JSON.stringify(inspectedPlayers));

                    this.mcs_ko_updateInspectedPlayersList();

                    return true;
                } catch (e) {
                    console.error('[KOllection] Error adding profile to KOllection:', e);
                    return false;
                }
            }
            mcs_ko_removeProfileFromKollection(characterID) {
                try {
                    const stored = localStorage.getItem('mcs__global_KO_inspected_players');
                    if (!stored) return false;

                    const inspectedPlayers = JSON.parse(stored);
                    delete inspectedPlayers[characterID];

                    localStorage.setItem('mcs__global_KO_inspected_players', JSON.stringify(inspectedPlayers));

                    this.mcs_ko_updateInspectedPlayersList();

                    return true;
                } catch (e) {
                    console.error('[KOllection] Error removing profile from KOllection:', e);
                    return false;
                }
            }
            async mcs_ko_handleProfileShared(profileData) {
                try {

                    window.mcs_last_profile_shared = profileData;

                    const playerName = profileData.profile?.sharableCharacter?.name || 'Unknown';
                    const characterID = profileData.profile?.characterSkills?.[0]?.characterID;

                    const [houseScore, abilityScore, equipmentScore, houseDetails, abilityDetails, equipmentDetails] = await this.mcs_ko_calculateProfileScoresWithDetails(profileData);
                    const totalScore = houseScore + abilityScore + equipmentScore;

                    const isInKollection = this.mcs_ko_isProfileInKollection(characterID);

                    await this.mcs_ko_showProfileScores(playerName, houseScore, abilityScore, equipmentScore, totalScore, profileData.profile?.hideWearableItems, characterID, isInKollection);

                } catch (e) {
                    console.error('[KOllection] Error handling profile shared:', e);
                }
            }
            async mcs_ko_calculateProfileScores(profileData) {
                const [houseScore, abilityScore, equipmentScore] = await this.mcs_ko_calculateProfileScoresWithDetails(profileData);
                return [houseScore, abilityScore, equipmentScore];
            }
            async mcs_ko_calculateProfileScoresWithDetails(profileData) {
                const marketData = await this.mcs_ko_fetchMarketData();
                if (!marketData) return [0, 0, 0, [], [], []];

                const profile = profileData.profile;
                const playerName = profile?.sharableCharacter?.name || 'Unknown';

                const battleHouses = ["dining_room", "library", "dojo", "gym", "armory", "archery_range", "mystical_study"];
                let houseScore = 0;
                const houseDetails = [];

                if (profile.characterHouseRoomMap) {
                    for (const key in profile.characterHouseRoomMap) {
                        const house = profile.characterHouseRoomMap[key];
                        if (battleHouses.some((battleHouse) => house.houseRoomHrid.includes(battleHouse))) {
                            const houseCost = await this.mcs_ko_getHouseFullBuildPrice(house, marketData);
                            const scoreValue = houseCost / 1000000;
                            houseScore += scoreValue;

                            const houseDetail = this.mcs_ko_houseRoomDetailMap?.[house.houseRoomHrid];
                            const houseName = houseDetail ? houseDetail.name : house.houseRoomHrid.replace('/house_rooms/', '');

                            houseDetails.push({
                                name: `${houseName} ${house.level}`,
                                value: scoreValue.toFixed(1)
                            });
                        }
                    }
                }

                houseDetails.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));

                if (profile.hideWearableItems) {

                    return [houseScore, 0, 0, houseDetails, [], []];
                }

                let abilityScore = 0;
                const abilityDetails = [];
                const exp_50_skill = ["poke", "scratch", "smack", "quick_shot", "water_strike", "fireball", "entangle", "minor_heal"];

                if (profile.equippedAbilities && profile.equippedAbilities.length > 0) {
                    const abilityDetailsForLog = [];

                    for (const ability of profile.equippedAbilities) {
                        const needExp = this.mcs_ko_levelExperienceTable?.[ability.level] ?? 0;
                        const expPerBook = exp_50_skill.some(skill => ability.abilityHrid.includes(skill)) ? 50 : 500;
                        let needBooks = needExp / expPerBook;
                        needBooks += 1;

                        const itemHrid = ability.abilityHrid.replace("/abilities/", "/items/");
                        const marketPrices = marketData[itemHrid];
                        let cost = 0;
                        let pricePerBook = 0;

                        if (marketPrices && marketPrices[0]) {
                            pricePerBook = this.mcs_ko_getWeightedPrice(marketPrices);
                            cost = needBooks * pricePerBook;
                            abilityScore += cost;
                        }

                        const abilityName = ability.abilityHrid.replace('/abilities/', '').split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');

                        abilityDetails.push({
                            name: `${abilityName} ${ability.level}`,
                            value: (cost / 1000000).toFixed(1)
                        });

                        abilityDetailsForLog.push({
                            hrid: ability.abilityHrid,
                            level: ability.level,
                            books: needBooks.toFixed(1),
                            pricePerBook: (pricePerBook / 1000000).toFixed(2),
                            totalCost: (cost / 1000000).toFixed(2)
                        });
                    }

                    abilityDetails.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));
                    abilityDetailsForLog.sort((a, b) => parseFloat(b.totalCost) - parseFloat(a.totalCost));

                    abilityDetailsForLog.forEach(detail => {
                        const hridShort = detail.hrid.replace('/abilities/', '');

                    });

                    abilityScore = abilityScore / 1000000;

                } else {

                }

                let equipmentScore = 0;
                let networthAsk = 0;
                let networthBid = 0;
                const equipmentDetails = [];

                if (profile.wearableItemMap) {
                    for (const key in profile.wearableItemMap) {
                        const item = profile.wearableItemMap[key];
                        const enhanceLevel = item.enhancementLevel ?? 0;
                        const itemHrid = item.itemHrid;
                        const marketPrices = marketData[itemHrid];

                        let itemCost = 0;
                        if (enhanceLevel && enhanceLevel > 1) {
                            let totalCost = await this.mcs_ko_estimateEnhancementCost(itemHrid, enhanceLevel, marketData);
                            totalCost = totalCost ? Math.round(totalCost) : 0;
                            itemCost = totalCost;
                            networthAsk += item.count * (totalCost > 0 ? totalCost : 0);
                            networthBid += item.count * (totalCost > 0 ? totalCost : 0);
                        } else if (marketPrices && marketPrices[0]) {
                            const askPrice = marketPrices[0].a > 0 ? marketPrices[0].a : 0;
                            const bidPrice = marketPrices[0].b > 0 ? marketPrices[0].b : 0;
                            itemCost = askPrice * 0.5 + bidPrice * 0.5;
                            networthAsk += item.count * askPrice;
                            networthBid += item.count * bidPrice;
                        }

                        const itemDetail = this.mcs_ko_itemDetailMap?.[itemHrid];
                        let itemName = itemDetail ? itemDetail.name : itemHrid.replace('/items/', '');

                        let displayName = itemName;
                        if (displayName.startsWith('Refined ')) {
                            displayName = displayName.replace('Refined ', '') + ' (R)';
                        }
                        if (enhanceLevel && enhanceLevel > 0) {
                            displayName += ` +${enhanceLevel}`;
                        }

                        equipmentDetails.push({
                            name: displayName,
                            value: (itemCost / 1000000).toFixed(1)
                        });
                    }

                    equipmentDetails.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));
                    equipmentScore = (networthAsk * 0.5 + networthBid * 0.5) / 1000000;
                }

                return [houseScore, abilityScore, equipmentScore, houseDetails, abilityDetails, equipmentDetails];
            }
            async mcs_ko_getProfilePanel() {
                for (let i = 0; i < 20; i++) {
                    const selectedElement = document.querySelector('div.SharableProfile_overviewTab__W4dCV');
                    if (selectedElement) {
                        return selectedElement;
                    }
                    await new Promise(resolve => setTimeout(resolve, 100));
                }
                return null;
            }
            async mcs_ko_showProfileScores(playerName, houseScore, abilityScore, equipmentScore, totalScore, equipmentHidden, characterID, isInKollection) {
                const profilePanel = await this.mcs_ko_getProfilePanel();
                if (!profilePanel) {
                    console.error('[KOllection] Could not find profile panel');
                    return;
                }

                const existing = document.getElementById('kollection-side-panel');
                if (existing) {
                    existing.remove();
                }

                const equipmentHiddenText = equipmentHidden ? " (Equipment hidden)" : "";

                const sidePanel = document.createElement('div');
                sidePanel.id = 'kollection-side-panel';
                sidePanel.className = 'mcs-ko-side-panel';

                const scoreSection = document.createElement('div');
                scoreSection.id = 'kollection-profile-scores';
                scoreSection.className = 'mcs-ko-score-section';

    scoreSection.innerHTML = `
        <div class="mcs-ko-side-name-row">
            <div class="mcs-ko-side-player-name">${playerName}</div>
            <span id="kollection-side-panel-close-btn" class="mcs-ko-close-btn" title="Close">×</span>
        </div>
        <div class="mcs-ko-build-score-toggle" id="kollection-toggle-scores">
            + Build Score: ${totalScore.toFixed(1)}${equipmentHiddenText}
        </div>
        <div id="kollection-score-details" class="mcs-ko-side-score-details">
            <div>House: ${houseScore.toFixed(1)}</div>
            <div>Ability: ${abilityScore.toFixed(1)}</div>
            <div>Equipment: ${equipmentScore.toFixed(1)}</div>
        </div>
                `;

                sidePanel.appendChild(scoreSection);

                const buttonsContainer = document.createElement('div');
                buttonsContainer.className = 'mcs-ko-buttons-container';
                sidePanel.appendChild(buttonsContainer);

                const modal = profilePanel.closest('.Modal_modalContent__Iw0Yv') || profilePanel.closest('[class*="Modal"]') || profilePanel.parentElement;

                document.body.appendChild(sidePanel);

                const positionPanel = () => {
                    if (modal) {
                        const modalRect = modal.getBoundingClientRect();
                        const panelWidth = 220;
                        const gap = 8;

                        if (modalRect.right + gap + panelWidth < window.innerWidth) {
                            sidePanel.style.left = (modalRect.right + gap) + 'px';
                        } else {
                            sidePanel.style.left = Math.max(10, modalRect.left - panelWidth - gap) + 'px';
                        }
                        sidePanel.style.top = modalRect.top + 'px';
                    }
                };

                positionPanel();

                const observer = new MutationObserver(() => {
                    if (!document.body.contains(modal) || !document.querySelector('.SharableProfile_overviewTab__W4dCV')) {
                        sidePanel.remove();
                        observer.disconnect();
                    }
                });
                observer.observe(document.body, { childList: true, subtree: true });

                const closeBtn = document.getElementById('kollection-side-panel-close-btn');
                if (closeBtn) {
                    closeBtn.addEventListener('click', () => {
                        sidePanel.remove();
                        observer.disconnect();
                    });
                }

                const toggleScores = document.getElementById('kollection-toggle-scores');
                const scoreDetails = document.getElementById('kollection-score-details');
                if (toggleScores && scoreDetails) {
                    toggleScores.addEventListener('click', () => {
                        const isCollapsed = scoreDetails.style.display === 'none';
                        scoreDetails.style.display = isCollapsed ? 'block' : 'none';
                        toggleScores.textContent =
                            (isCollapsed ? '- ' : '+ ') +
                            `Build Score: ${totalScore.toFixed(1)}${equipmentHiddenText}`;
                    });
                }

                this.mcs_ko_addKollectionButton(buttonsContainer, characterID, isInKollection);

                this.mcs_ko_addShykaiExportButton(buttonsContainer);
            }
            mcs_ko_addKollectionButton(panel, characterID, isInKollection) {
                const existingBtn = document.getElementById('kollection-add-remove-btn');
                if (existingBtn) {
                    existingBtn.remove();
                }

                const button = document.createElement('button');
                button.id = 'kollection-add-remove-btn';
                button.textContent = isInKollection ? 'Remove from KOllection' : 'Add to KOllection';
                button.className = 'mcs-ko-action-btn';
                button.style.backgroundColor = isInKollection ? '#ff5555' : '#4CAF50';
                button.style.color = isInKollection ? 'white' : 'black';

                button.onclick = async () => {
                    try {
                        const profileData = window.mcs_last_profile_shared;
                        if (!profileData) {
                            console.error('[KOllection] No profile data found');
                            button.textContent = 'Error: No Profile Data';
                            setTimeout(() => {
                                button.textContent = isInKollection ? 'Remove from KOllection' : 'Add to KOllection';
                            }, 2000);
                            return;
                        }

                        if (isInKollection) {
                            const success = this.mcs_ko_removeProfileFromKollection(characterID);
                            if (success) {
                                button.textContent = 'Removed!';
                                button.style.backgroundColor = '#4CAF50';
                                button.style.color = 'black';
                                isInKollection = false;
                                setTimeout(() => {
                                    button.textContent = 'Add to KOllection';
                                }, 1500);
                            } else {
                                button.textContent = 'Error!';
                                setTimeout(() => {
                                    button.textContent = 'Remove from KOllection';
                                }, 2000);
                            }
                        } else {
                            const success = await this.mcs_ko_addProfileToKollection(profileData);
                            if (success) {
                                button.textContent = 'Added!';
                                button.style.backgroundColor = '#ff5555';
                                button.style.color = 'white';
                                isInKollection = true;
                                setTimeout(() => {
                                    button.textContent = 'Remove from KOllection';
                                }, 1500);
                            } else {
                                button.textContent = 'Error!';
                                setTimeout(() => {
                                    button.textContent = 'Add to KOllection';
                                }, 2000);
                            }
                        }
                    } catch (e) {
                        console.error('[KOllection] Error toggling KOllection:', e);
                        button.textContent = 'Error!';
                        setTimeout(() => {
                            button.textContent = isInKollection ? 'Remove from KOllection' : 'Add to KOllection';
                        }, 2000);
                    }
                };

                panel.appendChild(button);
            }
            mcs_ko_constructShykaiExport(profileData) {
                const playerObj = {};
                playerObj.player = {};

                const profile = profileData.profile;

                playerObj.name = profile.sharableCharacter?.name || 'Unknown';

                if (profile.characterSkills) {
                    for (const skill of profile.characterSkills) {
                        if (skill.skillHrid.includes('stamina')) {
                            playerObj.player.staminaLevel = skill.level;
                        } else if (skill.skillHrid.includes('intelligence')) {
                            playerObj.player.intelligenceLevel = skill.level;
                        } else if (skill.skillHrid.includes('attack')) {
                            playerObj.player.attackLevel = skill.level;
                        } else if (skill.skillHrid.includes('melee')) {
                            playerObj.player.meleeLevel = skill.level;
                        } else if (skill.skillHrid.includes('defense')) {
                            playerObj.player.defenseLevel = skill.level;
                        } else if (skill.skillHrid.includes('ranged')) {
                            playerObj.player.rangedLevel = skill.level;
                        } else if (skill.skillHrid.includes('magic')) {
                            playerObj.player.magicLevel = skill.level;
                        }
                    }
                }

                playerObj.player.equipment = [];
                if (profile.wearableItemMap) {
                    for (const key in profile.wearableItemMap) {
                        const item = profile.wearableItemMap[key];
                        playerObj.player.equipment.push({
                            itemLocationHrid: item.itemLocationHrid,
                            itemHrid: item.itemHrid,
                            enhancementLevel: item.enhancementLevel ?? 0
                        });
                    }
                }

                playerObj.food = {};
                playerObj.food['/action_types/combat'] = [];
                playerObj.drinks = {};
                playerObj.drinks['/action_types/combat'] = [];

                for (let i = 0; i < 3; i++) {
                    playerObj.food['/action_types/combat'][i] = { itemHrid: "" };
                    playerObj.drinks['/action_types/combat'][i] = { itemHrid: "" };
                }

                if (profile.combatConsumables && Array.isArray(profile.combatConsumables)) {
                    let foodIndex = 0;
                    let drinkIndex = 0;
                    const itemDetailMap = this.mcs_ko_itemDetailMap || InitClientDataCache.getItemDetailMap();

                    profile.combatConsumables.forEach(consumable => {
                        const itemHrid = consumable.itemHrid;
                        const isDrink = itemHrid.includes('/drinks/') ||
                            itemHrid.includes('coffee') ||
                            itemDetailMap?.[itemHrid]?.type === 'drink';

                        if (isDrink && drinkIndex < 3) {
                            playerObj.drinks['/action_types/combat'][drinkIndex++] = { itemHrid: itemHrid };
                        } else if (!isDrink && foodIndex < 3) {
                            playerObj.food['/action_types/combat'][foodIndex++] = { itemHrid: itemHrid };
                        }
                    });
                }

                playerObj.abilities = [
                    { abilityHrid: '', level: 1 },
                    { abilityHrid: '', level: 1 },
                    { abilityHrid: '', level: 1 },
                    { abilityHrid: '', level: 1 },
                    { abilityHrid: '', level: 1 }
                ];

                if (profile.equippedAbilities) {
                    const abilityDetailMap = InitClientDataCache.getAbilityDetailMap();

                    let normalAbilityIndex = 1;
                    for (const ability of profile.equippedAbilities) {
                        if (ability && abilityDetailMap[ability.abilityHrid]?.isSpecialAbility) {
                            playerObj.abilities[0] = {
                                abilityHrid: ability.abilityHrid,
                                level: ability.level || 1
                            };
                        } else if (ability) {
                            playerObj.abilities[normalAbilityIndex++] = {
                                abilityHrid: ability.abilityHrid,
                                level: ability.level || 1
                            };
                        }
                    }
                }

                playerObj.triggerMap = {
                    ...(profile.abilityCombatTriggersMap ?? {}),
                    ...(profile.consumableCombatTriggersMap ?? {})
                };

                playerObj.houseRooms = {};
                if (profile.characterHouseRoomMap) {
                    for (const house of Object.values(profile.characterHouseRoomMap)) {
                        playerObj.houseRooms[house.houseRoomHrid] = house.level;
                    }
                }

                playerObj.achievements = {};
                if (profile.characterAchievements) {
                    for (const achievement of profile.characterAchievements) {
                        if (achievement.achievementHrid && achievement.isCompleted) {
                            playerObj.achievements[achievement.achievementHrid] = true;
                        }
                    }
                }

                return playerObj;
            }
            mcs_ko_addShykaiExportButton(panel) {
                const existingBtn = document.getElementById('kollection-shykai-export-btn');
                if (existingBtn) {
                    existingBtn.remove();
                }

                const button = document.createElement('button');
                button.id = 'kollection-shykai-export-btn';
                button.textContent = 'Export (Shykai)';
                button.className = 'mcs-ko-action-btn';
                button.style.backgroundColor = '#4CAF50';
                button.style.color = 'black';

                button.onclick = () => {
                    try {
                        const profileData = window.mcs_last_profile_shared;

                        if (!profileData || !profileData.profile) {
                            console.error('[KOllection] No profile data found');
                            button.textContent = 'Error: No Profile Data';
                            setTimeout(() => {
                                button.textContent = 'Export (Shykai)';
                            }, 2000);
                            return;
                        }

                        const exportObj = this.mcs_ko_constructShykaiExport(profileData);
                        const exportString = JSON.stringify(exportObj);

                        navigator.clipboard.writeText(exportString);

                        button.textContent = 'Copied!';
                        setTimeout(() => {
                            button.textContent = 'Export (Shykai)';
                        }, 2000);
                    } catch (e) {
                        console.error('[KOllection] Error exporting to clipboard:', e);
                        button.textContent = 'Error!';
                        setTimeout(() => {
                            button.textContent = 'Export (Shykai)';
                        }, 2000);
                    }
                };

                panel.appendChild(button);
            }
            mcs_ko_updateInspectedPlayersList() {
                const listContainer = document.getElementById('kollection-inspected-list');
                const headerElement = document.getElementById('kollection-inspected-header');
                if (!listContainer || !headerElement) return;

                try {
                    const stored = localStorage.getItem('mcs__global_KO_inspected_players');
                    if (!stored) {
                        listContainer.innerHTML = '<div class="mcs-ko-empty-message">No players inspected yet</div>';
                        headerElement.textContent = '+ Inspected Players (0)';
                        return;
                    }

                    const inspectedPlayers = JSON.parse(stored);
                    const playerArray = Object.entries(inspectedPlayers).map(([id, data]) => ({
                        id,
                        ...data
                    }));

                    playerArray.sort((a, b) => a.count - b.count);

                    if (playerArray.length === 0) {
                        listContainer.innerHTML = '<div class="mcs-ko-empty-message">No players inspected yet</div>';
                        headerElement.textContent = '+ Inspected Players (0)';
                        return;
                    }

                    listContainer.innerHTML = '';
                    playerArray.forEach(player => {
                        const playerContainer = document.createElement('div');
                        playerContainer.className = 'mcs-ko-player-container';

                        const playerDiv = document.createElement('div');
                        playerDiv.className = 'mcs-ko-player-row';

                        const totalScore = player.totalScore ?? 0;
                        const equipmentHiddenText = player.equipmentHidden ? ' (Hidden)' : '';

                        const deleteBtn = document.createElement('button');
                        deleteBtn.textContent = '×';
                        deleteBtn.className = 'mcs-ko-delete-btn';
                        deleteBtn.onclick = (e) => {
                            e.stopPropagation();
                            this.mcs_ko_deleteInspectedPlayer(player.id);
                        };

                        const toggleBtn = document.createElement('span');
                        toggleBtn.textContent = '+ ';
                        toggleBtn.className = 'mcs-ko-toggle-indicator';

                        const infoDiv = document.createElement('div');
                        infoDiv.className = 'mcs-ko-player-info';
            infoDiv.innerHTML = `
                <span class="mcs-ko-score-value">${player.name}</span>
                <span class="mcs-ko-total-value">${totalScore.toFixed(1)}${equipmentHiddenText}</span>
                        `;

                        const detailsDiv = document.createElement('div');
                        detailsDiv.className = 'mcs-ko-player-details';

                        const houseScore = player.houseScore ?? 0;
                        const abilityScore = player.abilityScore ?? 0;
                        const equipmentScore = player.equipmentScore ?? 0;
                        const houseDetails = player.houseDetails ?? [];
                        const abilityDetails = player.abilityDetails ?? [];
                        const equipmentDetails = player.equipmentDetails ?? [];

                        let detailsHTML = '';

            detailsHTML += `
                <div class="mcs-ko-detail-subsection">
                    <div class="mcs-ko-detail-sub-header"
                         onclick="this.nextElementSibling.style.display = this.nextElementSibling.style.display === 'none' ? 'block' : 'none'; this.querySelector('span').textContent = this.nextElementSibling.style.display === 'none' ? '+ ' : '↓ ';">
                        <span>+ </span><span>House score:</span>
                        <span class="mcs-ko-score-value">${houseScore.toFixed(1)}</span>
                    </div>
                    <div class="mcs-ko-detail-sub-content">
                                    ${houseDetails.map(d => `
                                        <div class="mcs-ko-detail-item">
                                            <span>${d.name}</span>
                                            <span class="mcs-ko-detail-item-value">${d.value}</span>
                                        </div>
                        `).join('')}
                        ${houseDetails.length === 0 ? '<div class="mcs-ko-empty-message">No data</div>' : ''}
                    </div>
                </div>
                        `;

            detailsHTML += `
                <div class="mcs-ko-detail-subsection">
                    <div class="mcs-ko-detail-sub-header"
                         onclick="this.nextElementSibling.style.display = this.nextElementSibling.style.display === 'none' ? 'block' : 'none'; this.querySelector('span').textContent = this.nextElementSibling.style.display === 'none' ? '+ ' : '↓ ';">
                        <span>+ </span><span>Ability score:</span>
                        <span class="mcs-ko-score-value">${abilityScore.toFixed(1)}</span>
                    </div>
                    <div class="mcs-ko-detail-sub-content-scroll">
                                    ${abilityDetails.map(d => `
                                        <div class="mcs-ko-detail-item">
                                            <span>${d.name}</span>
                                            <span class="mcs-ko-detail-item-value">${d.value}</span>
                                        </div>
                        `).join('')}
                        ${abilityDetails.length === 0 ? '<div class="mcs-ko-empty-message">No data</div>' : ''}
                    </div>
                </div>
                        `;

            detailsHTML += `
                <div class="mcs-ko-detail-subsection">
                    <div class="mcs-ko-detail-sub-header"
                         onclick="this.nextElementSibling.style.display = this.nextElementSibling.style.display === 'none' ? 'block' : 'none'; this.querySelector('span').textContent = this.nextElementSibling.style.display === 'none' ? '+ ' : '↓ ';">
                        <span>+ </span><span>Equipment score:</span>
                        <span class="mcs-ko-score-value">${equipmentScore.toFixed(1)}</span>
                    </div>
                    <div class="mcs-ko-detail-sub-content-scroll">
                                    ${equipmentDetails.map(d => `
                                        <div class="mcs-ko-detail-item">
                                            <span>${d.name}</span>
                                            <span class="mcs-ko-detail-item-value">${d.value}</span>
                                        </div>
                        `).join('')}
                        ${equipmentDetails.length === 0 ? '<div class="mcs-ko-empty-message">No data</div>' : ''}
                    </div>
                </div>
                        `;

                        detailsDiv.innerHTML = detailsHTML;

                        const toggleDetails = () => {
                            const isCollapsed = detailsDiv.style.display === 'none';
                            detailsDiv.style.display = isCollapsed ? 'block' : 'none';
                            toggleBtn.textContent = isCollapsed ? '↓ ' : '+ ';
                        };

                        toggleBtn.onclick = toggleDetails;
                        infoDiv.onclick = toggleDetails;

                        playerDiv.appendChild(deleteBtn);
                        playerDiv.appendChild(toggleBtn);
                        playerDiv.appendChild(infoDiv);

                        playerContainer.appendChild(playerDiv);
                        playerContainer.appendChild(detailsDiv);

                        listContainer.appendChild(playerContainer);
                    });

                    const isExpanded = listContainer.style.display !== 'none';
                    headerElement.textContent = (isExpanded ? '↓ ' : '+ ') + `Inspected Players (${playerArray.length})`;

                } catch (e) {
                    console.error('[KOllection] Error updating inspected players list:', e);
                    listContainer.innerHTML = '<div class="mcs-ko-error-message">Error loading list</div>';
                }
            }
            mcs_ko_deleteInspectedPlayer(characterID) {
                try {
                    const stored = localStorage.getItem('mcs__global_KO_inspected_players');
                    if (!stored) return;

                    const inspectedPlayers = JSON.parse(stored);

                    delete inspectedPlayers[characterID];

                    localStorage.setItem('mcs__global_KO_inspected_players', JSON.stringify(inspectedPlayers));

                    this.mcs_ko_updateInspectedPlayersList();

                } catch (e) {
                    console.error('[KOllection] Error deleting inspected player:', e);
                }
            }
            destroyKOllection() {
                VisibilityManager.clear('kollection-update');

                if (this._koWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._koWsListener); this._koWsListener = null; }
                if (this._koEquipChangedListener) { window.removeEventListener('MCS_EquipmentChanged', this._koEquipChangedListener); this._koEquipChangedListener = null; }

                const pane = document.getElementById('kollection-pane');
                if (pane) {
                    pane.remove();
                }
            }

// KOllection end

// NTally start

            get ntStorage() {
                if (!this._ntStorage) {
                    this._ntStorage = createModuleStorage('NT');
                }
                return this._ntStorage;
            }

            mcs_nt_createPane() {
                if (document.getElementById('mcs_nt_pane')) return;

                if (!this.mcs_nt_data) this.mcs_nt_data = [];
                if (!this.mcs_nt_observer) this.mcs_nt_observer = null;
                if (!this.mcs_nt_marketData) this.mcs_nt_marketData = {};
                if (!this.mcs_nt_sortBy) this.mcs_nt_sortBy = 'name';
                if (!this.mcs_nt_sortDirection) this.mcs_nt_sortDirection = 'asc';
                if (this.mcs_nt_marketTallyExpanded === undefined) this.mcs_nt_marketTallyExpanded = false;
                if (this.mcs_nt_planetSetsExpanded === undefined) this.mcs_nt_planetSetsExpanded = false;
                if (this.mcs_nt_treasureSetsExpanded === undefined) this.mcs_nt_treasureSetsExpanded = false;

                this.mcs_nt_planets = [
                    { id: 'smelly_planet', actionHrid: '/actions/combat/smelly_planet', name: 'Smelly Planet' },
                    { id: 'swamp_planet', actionHrid: '/actions/combat/swamp_planet', name: 'Swamp Planet' },
                    { id: 'aqua_planet', actionHrid: '/actions/combat/aqua_planet', name: 'Aqua Planet' },
                    { id: 'jungle_planet', actionHrid: '/actions/combat/jungle_planet', name: 'Jungle Planet' },
                    { id: 'gobo_planet', actionHrid: '/actions/combat/gobo_planet', name: 'Gobo Planet' },
                    { id: 'planet_of_the_eyes', actionHrid: '/actions/combat/planet_of_the_eyes', name: 'Planet of the Eyes' },
                    { id: 'sorcerers_tower', actionHrid: '/actions/combat/sorcerers_tower', name: "Sorcerer's Tower" },
                    { id: 'bear_with_it', actionHrid: '/actions/combat/bear_with_it', name: 'Bear With It' },
                    { id: 'golem_cave', actionHrid: '/actions/combat/golem_cave', name: 'Golem Cave' },
                    { id: 'twilight_zone', actionHrid: '/actions/combat/twilight_zone', name: 'Twilight Zone' },
                    { id: 'infernal_abyss', actionHrid: '/actions/combat/infernal_abyss', name: 'Infernal Abyss' },
                    { id: 'chimerical_den', actionHrid: '/actions/combat/chimerical_den', name: 'Chimerical Den' },
                    { id: 'sinister_circus', actionHrid: '/actions/combat/sinister_circus', name: 'Sinister Circus' },
                    { id: 'enchanted_fortress', actionHrid: '/actions/combat/enchanted_fortress', name: 'Enchanted Fortress' },
                    { id: 'pirate_cove', actionHrid: '/actions/combat/pirate_cove', name: 'Pirate Cove' }
                ];

                if (!this.mcs_nt_planetEnabled) this.mcs_nt_planetEnabled = {};
                this.mcs_nt_planets.forEach(planet => {
                    if (this.mcs_nt_planetEnabled[planet.id] === undefined) {
                        const enabled = this.ntStorage.get(`planet_${planet.id}`);
                        this.mcs_nt_planetEnabled[planet.id] = enabled === true || enabled === 'true';
                    }
                });

                if (!this.mcs_nt_treasureEnabled) this.mcs_nt_treasureEnabled = {};

                const self = this;
                window.isItemTrackedByNtally = (itemHrid) => {
                    if (!self.mcs_nt_data || !Array.isArray(self.mcs_nt_data)) {
                        return false;
                    }
                    return self.mcs_nt_data.some(item => item.hrid === itemHrid);
                };

                const pane = document.createElement('div');
                pane.id = 'mcs_nt_pane';
                registerPanel('mcs_nt_pane');

                const savedSize = this.ntStorage.get('size');
                let width = 420;
                let height = 550;
                if (savedSize) {
                    width = savedSize.width || 420;
                    height = savedSize.height || 550;
                }

                pane.className = 'mcs-pane mcs-nt-pane';
                pane.style.width = width + 'px';
                pane.style.height = height + 'px';

                pane.dataset.savedHeight = height;

                const header = document.createElement('div');
                header.className = 'mcs-pane-header';

                const titleSection = document.createElement('div');
                titleSection.className = 'mcs-nt-title-section';

                const titleSpan = document.createElement('span');
                titleSpan.id = 'mcs_nt_title';
                titleSpan.className = 'mcs-pane-title';
                titleSpan.textContent = 'NTally 0 / 0';

                titleSection.appendChild(titleSpan);

                const buttonSection = document.createElement('div');
                buttonSection.className = 'mcs-button-section';

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'mcs_nt_minimize_btn';
                minimizeBtn.textContent = '−';
                minimizeBtn.className = 'mcs-btn';

                buttonSection.appendChild(minimizeBtn);
                header.appendChild(titleSection);
                header.appendChild(buttonSection);

                const columnHeader = document.createElement('div');
                columnHeader.id = 'mcs_nt_column_header';
                columnHeader.className = 'mcs-nt-column-header';

                columnHeader.innerHTML = `<div class="mcs-nt-col-icon-spacer"></div>` +
                    `<div id="mcs_nt_sort_name" class="mcs-nt-col-sort-name" title="Click to sort by name">Name ▼</div>` +
                    `<div id="mcs_nt_sort_value" class="mcs-nt-col-sort-value" title="Click to sort by value">Value</div>` +
                    `<div class="mcs-nt-col-x-spacer"></div>`;

                const content = document.createElement('div');
                content.id = 'mcs_nt_content';
                content.className = 'mcs-nt-content';

                content.innerHTML = '<div class="mcs-nt-empty-state">Click items in your inventory to add them to the tally</div>';

                pane.appendChild(header);
                pane.appendChild(columnHeader);
                pane.appendChild(content);
                document.body.appendChild(pane);

                content.addEventListener('click', (e) => {
                    const deleteBtn = e.target.closest('.mcs_nt_delete_btn');
                    if (deleteBtn) {
                        const itemName = deleteBtn.getAttribute('data-item');
                        if (itemName) self.mcs_nt_removeItem(itemName);
                        return;
                    }
                    const itemIcon = e.target.closest('.mcs_nt_item_icon');
                    if (itemIcon) {
                        e.stopPropagation();
                        const itemHrid = itemIcon.getAttribute('data-hrid');
                        if (itemHrid) self.mcs_nt_openMarketplace(itemHrid);
                        return;
                    }
                });

                let dragStartX, dragStartY, initialLeft, initialTop;

                const onDragMove = (e) => {
                    const dx = e.clientX - dragStartX;
                    const dy = e.clientY - dragStartY;

                    let newLeft = initialLeft + dx;
                    let newTop = initialTop + dy;

                    const paneRect = pane.getBoundingClientRect();
                    const headerHeight = header.getBoundingClientRect().height;

                    const minLeft = 0;
                    const maxLeft = window.innerWidth - paneRect.width;
                    const minTop = 0;
                    const maxTop = window.innerHeight - headerHeight;

                    newLeft = Math.max(minLeft, Math.min(maxLeft, newLeft));
                    newTop = Math.max(minTop, Math.min(maxTop, newTop));

                    pane.style.left = newLeft + 'px';
                    pane.style.top = newTop + 'px';
                };

                const onDragUp = () => {
                    document.removeEventListener('mousemove', onDragMove);
                    document.removeEventListener('mouseup', onDragUp);
                    header.style.cursor = 'move';
                    const rect = pane.getBoundingClientRect();
                    this.ntStorage.set('position', { top: rect.top, left: rect.left });
                };

                header.addEventListener('mousedown', (e) => {
                    if (e.target.closest('button')) return;
                    dragStartX = e.clientX;
                    dragStartY = e.clientY;
                    const rect = pane.getBoundingClientRect();
                    initialLeft = rect.left;
                    initialTop = rect.top;
                    header.style.cursor = 'grabbing';
                    pane.style.left = initialLeft + 'px';
                    pane.style.right = 'auto';
                    this._ntDragMove = onDragMove;
                    this._ntDragUp = onDragUp;
                    document.addEventListener('mousemove', onDragMove);
                    document.addEventListener('mouseup', onDragUp);
                });

                minimizeBtn.addEventListener('click', () => {
                    const isMinimized = content.style.display === 'none';
                    if (isMinimized) {
                        content.style.display = 'block';
                        columnHeader.style.display = '';
                        minimizeBtn.textContent = '−';
                        header.style.borderRadius = '6px 6px 0 0';
                        const savedHeight = pane.dataset.savedHeight || height;
                        pane.style.height = savedHeight + 'px';
                        pane.style.minHeight = '300px';
                        pane.style.resize = 'both';
                        this.ntStorage.set('minimized', false);
                        this.mcs_nt_renderContent();
                    } else {
                        const currentRect = pane.getBoundingClientRect();
                        pane.dataset.savedHeight = currentRect.height;

                        content.style.display = 'none';
                        columnHeader.style.display = 'none';
                        minimizeBtn.textContent = '+';
                        header.style.borderRadius = '6px';

                        const headerHeight = header.getBoundingClientRect().height;
                        pane.style.height = headerHeight + 'px';
                        pane.style.minHeight = '0';
                        pane.style.resize = 'none';
                        this.ntStorage.set('minimized', true);
                    }
                });

                const savedPosition = this.ntStorage.get('position');
                if (savedPosition) {
                    pane.style.top = savedPosition.top + 'px';
                    if (savedPosition.left !== undefined) {
                        pane.style.left = savedPosition.left + 'px';
                        pane.style.right = 'auto';
                    } else if (savedPosition.right !== undefined) {
                        pane.style.right = savedPosition.right + 'px';
                    }
                }

                const savedMinimized = this.ntStorage.get('minimized');
                if (savedMinimized === true || savedMinimized === 'true') {
                    content.style.display = 'none';
                    columnHeader.style.display = 'none';
                    minimizeBtn.textContent = '+';
                    header.style.borderRadius = '6px';
                    const headerHeight = header.getBoundingClientRect().height;
                    pane.style.height = headerHeight + 'px';
                    pane.style.minHeight = '0';
                    pane.style.resize = 'none';
                }

                this._ntResizeObserver = new ResizeObserver(() => {
                    const rect = pane.getBoundingClientRect();
                    const isMinimized = content.style.display === 'none';

                    if (!isMinimized) {
                        pane.dataset.savedHeight = rect.height;
                    }

                    this.ntStorage.set('size', {
                        width: rect.width,
                        height: isMinimized ? pane.dataset.savedHeight : rect.height
                    });
                });
                this._ntResizeObserver.observe(pane);

                const sortNameHeader = document.getElementById('mcs_nt_sort_name');
                const sortValueHeader = document.getElementById('mcs_nt_sort_value');

                sortNameHeader.addEventListener('click', () => {
                    if (this.mcs_nt_sortBy === 'name') {
                        this.mcs_nt_sortDirection = this.mcs_nt_sortDirection === 'asc' ? 'desc' : 'asc';
                    } else {
                        this.mcs_nt_sortBy = 'name';
                        this.mcs_nt_sortDirection = 'asc';
                    }
                    this.mcs_nt_updateSortHeaders();
                    this.mcs_nt_renderContent();
                });

                sortValueHeader.addEventListener('click', () => {
                    if (this.mcs_nt_sortBy === 'value') {
                        this.mcs_nt_sortDirection = this.mcs_nt_sortDirection === 'asc' ? 'desc' : 'asc';
                    } else {
                        this.mcs_nt_sortBy = 'value';
                        this.mcs_nt_sortDirection = 'desc';
                    }
                    this.mcs_nt_updateSortHeaders();
                    this.mcs_nt_renderContent();
                });

                this.mcs_nt_loadData();

                this.mcs_nt_loadMarketData();

                this.mcs_nt_startObserver();

                this.mcs_nt_startMarketplacePanelMonitor();

                this.mcs_nt_setupEventListeners();

                this.mcs_nt_waitForMarketData();
            }

            mcs_nt_waitForMarketData() {
                const checkMarketData = () => {
                    if (window.lootDropsTrackerInstance?.spyMarketData &&
                        Object.keys(window.lootDropsTrackerInstance.spyMarketData).length > 0) {
                        this.mcs_nt_calculateChestValues().then(() => {
                            this.mcs_nt_renderContent();
                        });
                    } else {
                        setTimeout(checkMarketData, 500);
                    }
                };

                checkMarketData();
            }

            async mcs_nt_calculateChestValues() {
                if (!this.mcs_nt_chestCache) {
                    this.mcs_nt_chestCache = {};
                }

                try {
                    const initData = InitClientDataCache.get();
                    if (!initData || !initData.openableLootDropMap) {
                        console.error('[NTally] No openableLootDropMap in init data');
                        return;
                    }

                    const marketData = window.lootDropsTrackerInstance?.spyMarketData || {};

                    const itemHridToName = {};
                    if (initData.itemDetailMap) {
                        for (const key in initData.itemDetailMap) {
                            const item = initData.itemDetailMap[key];
                            if (item && item.name) {
                                itemHridToName[key] = item.name;
                            }
                        }
                    }

                    const formatItemName = (hrid) => mcsFormatHrid(hrid);

                    const useCowbell0 = typeof window.getTreasureUseCowbell0 === 'function' ? window.getTreasureUseCowbell0() : false;
                    const specialItemPrices = {
                        'Coin': {
                            ask: 1,
                            bid: 1
                        },
                        'Cowbell': {
                            ask: useCowbell0 ? 0 : ((marketData['/items/bag_of_10_cowbells']?.['0']?.a || 360000 * 0.82)) / 10,
                            bid: useCowbell0 ? 0 : ((marketData['/items/bag_of_10_cowbells']?.['0']?.b || 350000 * 0.82)) / 10
                        }
                    };

                    const formattedChestDropData = {};

                    for (let iteration = 0; iteration < 4; iteration++) {
                        for (let [chestHrid, items] of Object.entries(initData.openableLootDropMap)) {
                            const chestName = itemHridToName[chestHrid] || formatItemName(chestHrid);
                            if (!formattedChestDropData[chestName]) {
                                formattedChestDropData[chestName] = { items: {} };
                            }

                            let totalAsk = 0;
                            let totalBid = 0;

                            items.forEach(item => {
                                const { itemHrid, dropRate, minCount, maxCount } = item;
                                if (dropRate < 0.01) return;

                                const itemName = itemHridToName[itemHrid] || formatItemName(itemHrid);
                                const expectedYield = ((minCount + maxCount) / 2) * dropRate;

                                let askPrice = 0;
                                let bidPrice = 0;

                                if (specialItemPrices[itemName]) {
                                    askPrice = specialItemPrices[itemName].ask || 0;
                                    bidPrice = specialItemPrices[itemName].bid || 0;
                                }
                                else if (marketData[itemHrid] && marketData[itemHrid]['0']) {
                                    askPrice = marketData[itemHrid]['0'].a || 0;
                                    bidPrice = marketData[itemHrid]['0'].b || 0;
                                }

                                const taxFactor = (itemName in specialItemPrices) ? 1 : 0.98;
                                totalAsk += (askPrice * expectedYield) * taxFactor;
                                totalBid += (bidPrice * expectedYield) * taxFactor;
                            });

                            formattedChestDropData[chestName] = {
                                ...formattedChestDropData[chestName],
                                expectedAsk: totalAsk,
                                expectedBid: totalBid
                            };

                            specialItemPrices[chestName] = {
                                ask: totalAsk,
                                bid: totalBid
                            };
                        }
                    }

                    for (let chestHrid of Object.keys(initData.openableLootDropMap)) {
                        const chestName = itemHridToName[chestHrid] || formatItemName(chestHrid);
                        if (formattedChestDropData[chestName]) {
                            this.mcs_nt_chestCache[chestHrid] = formattedChestDropData[chestName];
                        }
                    }
                } catch (error) {
                    console.error('[NTally] Error calculating chest values:', error);
                }
            }

            mcs_nt_loadData() {
                try {
                    const saved = this.ntStorage.get('data');
                    if (saved) {
                        this.mcs_nt_data = typeof saved === 'string' ? JSON.parse(saved) : saved;
                    }
                } catch (e) {
                    console.error('[NTally] Error loading data:', e);
                    this.mcs_nt_data = [];
                }
            }

            mcs_nt_saveData() {
                try {
                    this.ntStorage.set('data', this.mcs_nt_data);
                } catch (e) {
                    console.error('[NTally] Error saving data:', e);
                }
            }

            mcs_nt_loadMarketData() {
            }

            mcs_nt_getVendorValue(itemHrid) {
                try {
                    const itemDetailMap = InitClientDataCache.getItemDetailMap();
                    if (itemDetailMap && itemDetailMap[itemHrid]) {
                        return itemDetailMap[itemHrid].sellPrice || 0;
                    }
                } catch (e) {
                    console.error('[NTally] Error getting vendor value:', e);
                }
                return 0;
            }

            mcs_nt_getItemPrice(itemHrid) {
                if (!itemHrid) {
                    return { ask: 0, bid: 0 };
                }

                let askPrice = 0;
                let bidPrice = 0;

                if (this.mcs_nt_chestCache && this.mcs_nt_chestCache[itemHrid]) {
                    const chestData = this.mcs_nt_chestCache[itemHrid];
                    askPrice = chestData.expectedAsk || 0;
                    bidPrice = chestData.expectedBid || 0;
                }
                else {
                    const marketData = window.lootDropsTrackerInstance?.spyMarketData || {};

                    if (marketData[itemHrid] && marketData[itemHrid]['0']) {
                        const priceData = marketData[itemHrid]['0'];
                        const rawAsk = priceData.a || 0;
                        const rawBid = priceData.b || 0;

                        if (rawAsk > 0) {
                            askPrice = rawAsk < 900 ? Math.floor(rawAsk * 0.98) : Math.ceil(rawAsk * 0.98);
                        }
                        if (rawBid > 0) {
                            bidPrice = rawBid < 900 ? Math.floor(rawBid * 0.98) : Math.ceil(rawBid * 0.98);
                        }
                    }
                }

                return {
                    ask: askPrice,
                    bid: bidPrice
                };
            }

            mcs_nt_renderMarketTally() {
                let marketListings = window.lootDropsTrackerInstance?.myMarketListings;
                if (!marketListings || marketListings.length === 0) {
                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData) {
                            marketListings = cachedData.myMarketListings || [];
                            if (window.lootDropsTrackerInstance && marketListings.length > 0) {
                                window.lootDropsTrackerInstance.myMarketListings = marketListings;
                            }
                        }
                    } catch (e) {
                        console.error('[NTally] Error loading market listings from localStorage:', e);
                        marketListings = [];
                    }
                }
                if (!marketListings || marketListings.length === 0) {
                    return '';
                }

                const itemDetailMap = InitClientDataCache.getItemDetailMap() || {};
                const isExpanded = this.mcs_nt_marketTallyExpanded;

                let totalSellListingValue = 0;
                let totalSellAskValue = 0;
                let totalSellBidValue = 0;
                let sellOrderCount = 0;

                let totalBuyCommitted = 0;
                let totalBuyUnclaimedValue = 0;
                let buyOrderCount = 0;

                const sellOrders = marketListings.filter(listing => {
                    if (!listing.isSell) return false;
                    const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                    return remaining > 0;
                });

                const buyOrders = marketListings.filter(listing => {
                    if (listing.isSell) return false;
                    const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                    const hasUnclaimed = (listing.unclaimedItemCount || 0) > 0;
                    return remaining > 0 || hasUnclaimed;
                });

                sellOrders.forEach(listing => {
                    const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                    const prices = this.mcs_nt_getItemPrice(listing.itemHrid);

                    totalSellListingValue += remaining * listing.price;
                    totalSellAskValue += remaining * prices.ask;
                    totalSellBidValue += remaining * prices.bid;
                    sellOrderCount++;
                });

                buyOrders.forEach(listing => {
                    const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                    const prices = this.mcs_nt_getItemPrice(listing.itemHrid);

                    totalBuyCommitted += remaining * listing.price;
                    totalBuyUnclaimedValue += (listing.unclaimedItemCount || 0) * prices.ask;
                    buyOrderCount++;
                });

                const totalOrderCount = sellOrderCount + buyOrderCount;

                const useAskPrice = window.getFlootUseAskPrice ? window.getFlootUseAskPrice() : false;
                const realSellValue = useAskPrice ? totalSellAskValue : totalSellBidValue;
                const realValueColor = useAskPrice ? '#6495ED' : '#4CAF50';
                const totalValue = realSellValue + totalBuyCommitted;

    let html = `
        <div class="mcs-nt-section">
            <div class="mcs_nt_market_tally_header mcs-nt-section-header">
                <span class="mcs-nt-section-title-gold">
                    ${isExpanded ? '▼' : '▶'} Market Tally (${totalOrderCount})
                </span>
                <span class="mcs-nt-section-summary">
                    <span class="mcs-nt-sell-value">Sell: ${this.mcs_nt_formatNumber(totalSellListingValue)}</span>
                    <span style="color: ${realValueColor};">(${this.mcs_nt_formatNumber(realSellValue)})</span>
                    <span class="mcs-nt-separator">|</span>
                    <span class="mcs-nt-buy-value">Buy: ${this.mcs_nt_formatNumber(totalBuyCommitted)}</span>
                    <span class="mcs-nt-separator">|</span>
                    <span class="mcs-nt-total-value">Total: ${this.mcs_nt_formatNumber(totalValue)}</span>
                </span>
            </div>
                `;

                if (isExpanded) {
                    html += `<div class="mcs-nt-expanded-content">`;

                    if (sellOrders.length > 0) {
                        html += `<div class="mcs-nt-sell-orders-header">SELL ORDERS (${sellOrderCount})</div>`;

                        const sortedSellOrders = [...sellOrders].sort((a, b) => {
                            const remainingA = a.orderQuantity - (a.filledQuantity || 0);
                            const remainingB = b.orderQuantity - (b.filledQuantity || 0);
                            return (b.price * remainingB) - (a.price * remainingA);
                        });

                        sortedSellOrders.forEach(listing => {
                            const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                            const prices = this.mcs_nt_getItemPrice(listing.itemHrid);
                            const itemDetail = itemDetailMap[listing.itemHrid];
                            const itemName = itemDetail ? itemDetail.name : listing.itemHrid.replace('/items/', '').replace(/_/g, ' ');
                            const spriteId = listing.itemHrid.replace('/items/', '');

                            const listingTotal = remaining * listing.price;
                            const askTotal = remaining * prices.ask;
                            const bidTotal = remaining * prices.bid;

                            let listingColor = '#FFA500';
                            if (listing.price > prices.ask) {
                                listingColor = '#ff5555';
                            } else if (listing.price < prices.bid) {
                                listingColor = '#4CAF50';
                            }

                html += `
                    <div class="mcs-nt-order-row">
                        <div class="mcs-nt-order-icon">
                            ${createItemIconHtml(spriteId, { width: '100%', height: '100%', sprite: 'items_sprite', className: 'Icon_icon__2LtL_', style: 'pointer-events: none', title: itemName })}
                        </div>
                        <div class="mcs-nt-order-details">
                            <div class="mcs-nt-order-name">
                                ${itemName} x${remaining.toLocaleString()}
                            </div>
                            <div class="mcs-nt-order-unit-price">
                                @ ${listing.price.toLocaleString()} each
                            </div>
                        </div>
                        <div class="mcs-nt-order-totals">
                            <div class="mcs-nt-order-listing-total">
                                <span style="color: ${listingColor};">List: ${this.mcs_nt_formatNumber(listingTotal)}</span>
                            </div>
                            <div class="mcs-nt-order-market-totals">
                                <span class="mcs-nt-color-green">${this.mcs_nt_formatNumber(askTotal)}</span>
                                <span class="mcs-nt-color-muted"> / </span>
                                <span class="mcs-nt-color-blue">${this.mcs_nt_formatNumber(bidTotal)}</span>
                            </div>
                        </div>
                    </div>
                            `;
                        });
                    }

                    if (buyOrders.length > 0) {
                        html += `<div class="mcs-nt-buy-orders-header">BUY ORDERS (${buyOrderCount})</div>`;

                        const sortedBuyOrders = [...buyOrders].sort((a, b) => {
                            const remainingA = a.orderQuantity - (a.filledQuantity || 0);
                            const remainingB = b.orderQuantity - (b.filledQuantity || 0);
                            return (b.price * remainingB) - (a.price * remainingA);
                        });

                        sortedBuyOrders.forEach(listing => {
                            const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                            const unclaimedItems = listing.unclaimedItemCount || 0;
                            const prices = this.mcs_nt_getItemPrice(listing.itemHrid);
                            const itemDetail = itemDetailMap[listing.itemHrid];
                            const itemName = itemDetail ? itemDetail.name : listing.itemHrid.replace('/items/', '').replace(/_/g, ' ');
                            const spriteId = listing.itemHrid.replace('/items/', '');

                            const committedCoins = remaining * listing.price;
                            const unclaimedValue = unclaimedItems * prices.ask;

                            let bidColor = '#FF6B6B';
                            if (listing.price < prices.bid) {
                                bidColor = '#4CAF50';
                            } else if (listing.price > prices.ask) {
                                bidColor = '#ff5555';
                            }

                html += `
                    <div class="mcs-nt-order-row">
                        <div class="mcs-nt-order-icon">
                            ${createItemIconHtml(spriteId, { width: '100%', height: '100%', sprite: 'items_sprite', className: 'Icon_icon__2LtL_', style: 'pointer-events: none', title: itemName })}
                        </div>
                        <div class="mcs-nt-order-details">
                            <div class="mcs-nt-order-name">
                                ${itemName} x${remaining.toLocaleString()}${unclaimedItems > 0 ? ` <span class="mcs-nt-color-gold">(+${unclaimedItems} unclaimed)</span>` : ''}
                            </div>
                            <div class="mcs-nt-order-unit-price">
                                @ ${listing.price.toLocaleString()} each
                            </div>
                        </div>
                        <div class="mcs-nt-order-totals">
                            <div class="mcs-nt-order-listing-total">
                                <span style="color: ${bidColor};">Committed: ${this.mcs_nt_formatNumber(committedCoins)}</span>
                            </div>
                                        ${unclaimedItems > 0 ? `
                                        <div class="mcs-nt-order-market-totals">
                                            <span class="mcs-nt-color-gold">Unclaimed: ${this.mcs_nt_formatNumber(unclaimedValue)}</span>
                                        </div>
                                        ` : `
                                        <div class="mcs-nt-order-market-totals">
                                            <span class="mcs-nt-color-green">${this.mcs_nt_formatNumber(prices.ask)} ask</span>
                                            <span class="mcs-nt-color-muted"> / </span>
                                            <span class="mcs-nt-color-blue">${this.mcs_nt_formatNumber(prices.bid)} bid</span>
                                        </div>
                            `}
                        </div>
                    </div>
                            `;
                        });
                    }

                    html += `</div>`;
                }

                html += `</div>`;
                return html;
            }

            mcs_nt_attachMarketTallyListener(content) {
                const header = content.querySelector('.mcs_nt_market_tally_header');
                if (header) {
                    header.addEventListener('click', () => {
                        this.mcs_nt_marketTallyExpanded = !this.mcs_nt_marketTallyExpanded;
                        this.mcs_nt_renderContent();
                    });
                }
            }

            mcs_nt_getPlanetDrops(actionHrid) {
                const drops = new Map();

                try {
                    const actionDetailMap = InitClientDataCache.getActionDetailMap();
                    const combatMonsterDetailMap = InitClientDataCache.getCombatMonsterDetailMap();
                    const itemDetailMap = InitClientDataCache.getItemDetailMap();

                    if (!actionDetailMap) {
                        return [];
                    }

                    const action = actionDetailMap[actionHrid];
                    if (!action || !action.combatZoneInfo) {
                        return [];
                    }

                    const addDrop = (drop) => {
                        if (drop.itemHrid === '/items/coin') return;
                        if (drop.itemHrid && !drops.has(drop.itemHrid)) {
                            const itemDetail = itemDetailMap?.[drop.itemHrid];
                            const itemName = itemDetail?.name || drop.itemHrid.replace('/items/', '').replace(/_/g, ' ');
                            drops.set(drop.itemHrid, { name: itemName, hrid: drop.itemHrid });
                        }
                    };

                    if (action.combatZoneInfo.isDungeon && action.combatZoneInfo.dungeonInfo) {
                        const dungeonInfo = action.combatZoneInfo.dungeonInfo;
                        if (dungeonInfo.rewardDropTable) {
                            dungeonInfo.rewardDropTable.forEach(drop => addDrop(drop));
                        }
                        return Array.from(drops.values());
                    }

                    const fightInfo = action.combatZoneInfo.fightInfo;
                    if (!fightInfo || !combatMonsterDetailMap) {
                        return [];
                    }

                    const addDropsFromMonster = (monsterHrid) => {
                        const monster = combatMonsterDetailMap[monsterHrid];
                        if (!monster) return;

                        if (monster.dropTable) {
                            monster.dropTable.forEach(drop => addDrop(drop));
                        }

                        if (monster.rareDropTable) {
                            monster.rareDropTable.forEach(drop => addDrop(drop));
                        }
                    };

                    if (fightInfo.randomSpawnInfo?.spawns) {
                        fightInfo.randomSpawnInfo.spawns.forEach(spawn => {
                            addDropsFromMonster(spawn.combatMonsterHrid);
                        });
                    }

                    if (fightInfo.bossSpawns) {
                        fightInfo.bossSpawns.forEach(bossSpawn => {
                            addDropsFromMonster(bossSpawn.combatMonsterHrid);
                        });
                    }

                    return Array.from(drops.values());
                } catch (e) {
                    console.error('[NTally] Error getting planet drops:', e);
                    return [];
                }
            }

            mcs_nt_togglePlanet(planetId, enabled) {
                const planet = this.mcs_nt_planets.find(p => p.id === planetId);
                if (!planet) return;

                this.mcs_nt_planetEnabled[planetId] = enabled;
                this.ntStorage.set(`planet_${planetId}`, enabled);

                const drops = this.mcs_nt_getPlanetDrops(planet.actionHrid);

                if (enabled) {
                    drops.forEach(drop => {
                        const existingIndex = this.mcs_nt_data.findIndex(item =>
                            item.hrid === drop.hrid || item.name === drop.name
                        );
                        if (existingIndex < 0) {
                            this.mcs_nt_data.push({
                                name: drop.name,
                                quantity: 0,
                                hrid: drop.hrid,
                                source: planetId
                            });
                        }
                    });
                } else {
                    const itemsToKeep = new Set();
                    this.mcs_nt_planets.forEach(p => {
                        if (p.id !== planetId && this.mcs_nt_planetEnabled[p.id]) {
                            const otherDrops = this.mcs_nt_getPlanetDrops(p.actionHrid);
                            otherDrops.forEach(drop => itemsToKeep.add(drop.hrid));
                        }
                    });

                    const openableItems = this.mcs_nt_getAllOpenableItems();
                    for (const chestHrid of Object.keys(openableItems)) {
                        if (this.mcs_nt_treasureEnabled[chestHrid]) {
                            itemsToKeep.add(chestHrid);
                            const treasureDrops = this.mcs_nt_getTreasureDrops(chestHrid);
                            treasureDrops.forEach(drop => itemsToKeep.add(drop.hrid));
                        }
                    }

                    this.mcs_nt_data = this.mcs_nt_data.filter(item => {
                        if (!item.source) return true;
                        if (item.source !== planetId) return true;
                        if (itemsToKeep.has(item.hrid)) {
                            for (const chestHrid of Object.keys(openableItems)) {
                                if (this.mcs_nt_treasureEnabled[chestHrid]) {
                                    if (item.hrid === chestHrid) {
                                        item.source = `treasure_${chestHrid}`;
                                        return true;
                                    }
                                    const treasureDrops = this.mcs_nt_getTreasureDrops(chestHrid);
                                    if (treasureDrops.some(d => d.hrid === item.hrid)) {
                                        item.source = `treasure_${chestHrid}`;
                                        return true;
                                    }
                                }
                            }
                            for (const p of this.mcs_nt_planets) {
                                if (p.id !== planetId && this.mcs_nt_planetEnabled[p.id]) {
                                    const otherDrops = this.mcs_nt_getPlanetDrops(p.actionHrid);
                                    if (otherDrops.some(d => d.hrid === item.hrid)) {
                                        item.source = p.id;
                                        return true;
                                    }
                                }
                            }
                        }
                        return false;
                    });
                }

                this.mcs_nt_saveData();
                this.mcs_nt_updateQuantities();
                this.mcs_nt_renderContent();

                if (window.updateAllInventoryPrices) {
                    setTimeout(() => window.updateAllInventoryPrices(true), 100);
                }
            }

            mcs_nt_renderPlanetSets() {
                const isExpanded = this.mcs_nt_planetSetsExpanded;

                const enabledCount = this.mcs_nt_planets.filter(p => this.mcs_nt_planetEnabled[p.id]).length;

    let html = `
        <div class="mcs-nt-section">
            <div class="mcs_nt_planet_sets_header mcs-nt-section-header">
                <span class="mcs-nt-section-title-purple">
                    ${isExpanded ? '▼' : '▶'} Planet Sets ${enabledCount > 0 ? `(${enabledCount})` : ''}
                </span>
            </div>
                `;

                if (isExpanded) {
                    html += `<div class="mcs-nt-section-content">`;
                    html += `<div class="mcs-nt-toggle-grid">`;

                    this.mcs_nt_planets.forEach(planet => {
                        const isEnabled = this.mcs_nt_planetEnabled[planet.id];
            html += `
                <div class="mcs-nt-toggle-item">
                    <label class="mcs-nt-toggle-switch">
                        <input type="checkbox" class="mcs-nt-toggle-checkbox" id="mcs_nt_planet_${planet.id}" data-planet-id="${planet.id}"
                            ${isEnabled ? 'checked' : ''}>
                        <span class="mcs-nt-toggle-slider" style="background-color: ${isEnabled ? '#4CAF50' : '#555'};"></span>
                        <span class="mcs-nt-toggle-knob" style="left: ${isEnabled ? '16px' : '2px'};"></span>
                    </label>
                    <label for="mcs_nt_planet_${planet.id}" class="mcs-nt-toggle-label" style="color: ${isEnabled ? '#4CAF50' : '#e0e0e0'};">
                        ${planet.name}
                    </label>
                </div>
                        `;
                    });

                    html += `</div>`;
                    html += `</div>`;
                }

                html += `</div>`;
                return html;
            }

            mcs_nt_attachPlanetSetsListener(content) {
                const header = content.querySelector('.mcs_nt_planet_sets_header');
                if (header) {
                    header.addEventListener('click', (e) => {
                        if (e.target.type === 'checkbox' || e.target.closest('.mcs_nt_toggle_switch')) {
                            return;
                        }
                        this.mcs_nt_planetSetsExpanded = !this.mcs_nt_planetSetsExpanded;
                        this.mcs_nt_renderContent();
                    });
                }

                this.mcs_nt_planets.forEach(planet => {
                    const toggle = content.querySelector(`#mcs_nt_planet_${planet.id}`);
                    if (toggle) {
                        toggle.addEventListener('change', (e) => {
                            e.stopPropagation();
                            this.mcs_nt_togglePlanet(planet.id, e.target.checked);
                        });
                    }
                });
            }

            mcs_nt_getAllOpenableItems() {
                try {
                    const initData = InitClientDataCache.get();
                    return initData?.openableLootDropMap || {};
                } catch (e) {
                    console.error('[NTally] Error getting openable items:', e);
                    return {};
                }
            }

            mcs_nt_formatTreasureName(hrid) {
                let name = hrid.replace('/items/', '').replace(/_/g, ' ');
                name = name.replace(/\b\w/g, c => c.toUpperCase());
                name = name.replace(/\bSmall\b/g, 'Sm.');
                name = name.replace(/\bMedium\b/g, 'Md.');
                name = name.replace(/\bLarge\b/g, 'Lg.');
                name = name.replace(/\bChest\b/g, 'Ch.');
                name = name.replace(/\bCache\b/g, 'Ca.');
                name = name.replace(/\bCrate\b/g, 'Cr.');
                name = name.replace(/\bRefinement\b/g, 'Ref.');
                name = name.replace(/\bBag Of 10 Cowbells\b/g, '10 Cowbells');
                return name;
            }

            mcs_nt_getTreasureDrops(chestHrid) {
                const drops = [];
                try {
                    const openableItems = this.mcs_nt_getAllOpenableItems();
                    const lootTable = openableItems[chestHrid];
                    if (!lootTable) return drops;

                    const itemDetailMap = InitClientDataCache.getItemDetailMap();
                    const seen = new Set();

                    for (const drop of lootTable) {
                        if (drop.itemHrid === '/items/coin') continue;
                        if (drop.itemHrid === '/items/cowbell') continue;
                        if (seen.has(drop.itemHrid)) continue;
                        seen.add(drop.itemHrid);

                        const itemDetail = itemDetailMap?.[drop.itemHrid];
                        const itemName = itemDetail?.name || drop.itemHrid.replace('/items/', '').replace(/_/g, ' ');
                        drops.push({ name: itemName, hrid: drop.itemHrid });
                    }
                } catch (e) {
                    console.error('[NTally] Error getting treasure drops:', e);
                }
                return drops;
            }

            mcs_nt_toggleTreasure(chestHrid, enabled) {
                this.mcs_nt_treasureEnabled[chestHrid] = enabled;
                this.ntStorage.set(`treasure_${chestHrid.replace('/items/', '')}`, enabled);

                const drops = this.mcs_nt_getTreasureDrops(chestHrid);
                const itemDetailMap = InitClientDataCache.getItemDetailMap();

                const sourceId = `treasure_${chestHrid}`;

                if (enabled) {
                    const chestDetail = itemDetailMap?.[chestHrid];
                    const chestName = chestDetail?.name || chestHrid.replace('/items/', '').replace(/_/g, ' ');
                    const existingChest = this.mcs_nt_data.findIndex(item => item.hrid === chestHrid);
                    if (existingChest < 0) {
                        this.mcs_nt_data.push({
                            name: chestName,
                            quantity: 0,
                            hrid: chestHrid,
                            source: sourceId
                        });
                    }

                    drops.forEach(drop => {
                        const existingIndex = this.mcs_nt_data.findIndex(item =>
                            item.hrid === drop.hrid || item.name === drop.name
                        );
                        if (existingIndex < 0) {
                            this.mcs_nt_data.push({
                                name: drop.name,
                                quantity: 0,
                                hrid: drop.hrid,
                                source: sourceId
                            });
                        }
                    });
                } else {
                    const itemsToKeep = new Set();
                    const openableItems = this.mcs_nt_getAllOpenableItems();
                    for (const otherChestHrid of Object.keys(openableItems)) {
                        if (otherChestHrid !== chestHrid && this.mcs_nt_treasureEnabled[otherChestHrid]) {
                            const otherDrops = this.mcs_nt_getTreasureDrops(otherChestHrid);
                            otherDrops.forEach(drop => itemsToKeep.add(drop.hrid));
                            itemsToKeep.add(otherChestHrid);
                        }
                    }

                    this.mcs_nt_planets.forEach(p => {
                        if (this.mcs_nt_planetEnabled[p.id]) {
                            const planetDrops = this.mcs_nt_getPlanetDrops(p.actionHrid);
                            planetDrops.forEach(drop => itemsToKeep.add(drop.hrid));
                        }
                    });

                    this.mcs_nt_data = this.mcs_nt_data.filter(item => {
                        if (!item.source) return true;
                        if (item.source !== sourceId) return true;
                        if (itemsToKeep.has(item.hrid)) {
                            for (const p of this.mcs_nt_planets) {
                                if (this.mcs_nt_planetEnabled[p.id]) {
                                    const planetDrops = this.mcs_nt_getPlanetDrops(p.actionHrid);
                                    if (planetDrops.some(d => d.hrid === item.hrid)) {
                                        item.source = p.id;
                                        return true;
                                    }
                                }
                            }
                            for (const otherChestHrid of Object.keys(openableItems)) {
                                if (otherChestHrid !== chestHrid && this.mcs_nt_treasureEnabled[otherChestHrid]) {
                                    if (item.hrid === otherChestHrid) {
                                        item.source = `treasure_${otherChestHrid}`;
                                        return true;
                                    }
                                    const otherDrops = this.mcs_nt_getTreasureDrops(otherChestHrid);
                                    if (otherDrops.some(d => d.hrid === item.hrid)) {
                                        item.source = `treasure_${otherChestHrid}`;
                                        return true;
                                    }
                                }
                            }
                        }
                        return false;
                    });
                }

                this.mcs_nt_saveData();
                this.mcs_nt_updateQuantities();
                this.mcs_nt_renderContent();

                if (window.updateAllInventoryPrices) {
                    setTimeout(() => window.updateAllInventoryPrices(true), 100);
                }
            }

            mcs_nt_renderTreasureSets() {
                const isExpanded = this.mcs_nt_treasureSetsExpanded;
                const openableItems = this.mcs_nt_getAllOpenableItems();
                const chestHrids = Object.keys(openableItems).sort((a, b) => {
                    const nameA = this.mcs_nt_formatTreasureName(a);
                    const nameB = this.mcs_nt_formatTreasureName(b);
                    return nameA.localeCompare(nameB);
                });

                chestHrids.forEach(chestHrid => {
                    if (this.mcs_nt_treasureEnabled[chestHrid] === undefined) {
                        const enabled = this.ntStorage.get(`treasure_${chestHrid.replace('/items/', '')}`);
                        this.mcs_nt_treasureEnabled[chestHrid] = enabled === true || enabled === 'true';
                    }
                });

                const enabledCount = chestHrids.filter(hrid => this.mcs_nt_treasureEnabled[hrid]).length;

    let html = `
        <div class="mcs-nt-section">
            <div class="mcs_nt_treasure_sets_header mcs-nt-section-header">
                <span class="mcs-nt-section-title-gold">
                    ${isExpanded ? '▼' : '▶'} Treasure Sets ${enabledCount > 0 ? `(${enabledCount})` : ''}
                </span>
            </div>
                `;

                if (isExpanded) {
                    html += `<div class="mcs-nt-section-content">`;
                    html += `<div class="mcs-nt-toggle-grid">`;

                    chestHrids.forEach(chestHrid => {
                        const isEnabled = this.mcs_nt_treasureEnabled[chestHrid];
                        const displayName = this.mcs_nt_formatTreasureName(chestHrid);
                        const safeId = chestHrid.replace('/items/', '').replace(/[^a-z0-9]/gi, '_');
            html += `
                <div class="mcs-nt-toggle-item">
                    <label class="mcs-nt-toggle-switch">
                        <input type="checkbox" class="mcs-nt-toggle-checkbox" id="mcs_nt_treasure_${safeId}" data-treasure-hrid="${chestHrid}"
                            ${isEnabled ? 'checked' : ''}>
                        <span class="mcs-nt-toggle-slider" style="background-color: ${isEnabled ? '#FFD700' : '#555'};"></span>
                        <span class="mcs-nt-toggle-knob" style="left: ${isEnabled ? '16px' : '2px'};"></span>
                    </label>
                    <label for="mcs_nt_treasure_${safeId}" class="mcs-nt-toggle-label" style="color: ${isEnabled ? '#FFD700' : '#e0e0e0'};" title="${chestHrid.replace('/items/', '').replace(/_/g, ' ')}">
                        ${displayName}
                    </label>
                </div>
                        `;
                    });

                    html += `</div>`;
                    html += `</div>`;
                }

                html += `</div>`;
                return html;
            }

            mcs_nt_attachTreasureSetsListener(content) {
                const header = content.querySelector('.mcs_nt_treasure_sets_header');
                if (header) {
                    header.addEventListener('click', (e) => {
                        if (e.target.type === 'checkbox' || e.target.closest('.mcs_nt_toggle_switch')) {
                            return;
                        }
                        this.mcs_nt_treasureSetsExpanded = !this.mcs_nt_treasureSetsExpanded;
                        this.mcs_nt_renderContent();
                    });
                }

                const openableItems = this.mcs_nt_getAllOpenableItems();
                for (const chestHrid of Object.keys(openableItems)) {
                    const safeId = chestHrid.replace('/items/', '').replace(/[^a-z0-9]/gi, '_');
                    const toggle = content.querySelector(`#mcs_nt_treasure_${safeId}`);
                    if (toggle) {
                        toggle.addEventListener('change', (e) => {
                            e.stopPropagation();
                            this.mcs_nt_toggleTreasure(chestHrid, e.target.checked);
                        });
                    }
                }
            }

            mcs_nt_addItem(itemName, quantity, itemHrid) {
                const existingIndex = this.mcs_nt_data.findIndex(item =>
                    itemHrid ? item.hrid === itemHrid : item.name === itemName
                );

                if (existingIndex >= 0) {
                    this.mcs_nt_data[existingIndex].quantity = quantity;
                    if (itemHrid && !this.mcs_nt_data[existingIndex].hrid) {
                        this.mcs_nt_data[existingIndex].hrid = itemHrid;
                    }
                } else {
                    this.mcs_nt_data.push({
                        name: itemName,
                        quantity: quantity,
                        hrid: itemHrid || null
                    });
                }

                this.mcs_nt_saveData();
                this.mcs_nt_renderContent();

                if (window.updateAllInventoryPrices) {
                    setTimeout(() => window.updateAllInventoryPrices(true), 100);
                }
            }

            mcs_nt_removeItem(itemName) {
                this.mcs_nt_data = this.mcs_nt_data.filter(item => item.name !== itemName);
                this.mcs_nt_saveData();
                this.mcs_nt_renderContent();

                if (window.updateAllInventoryPrices) {
                    setTimeout(() => window.updateAllInventoryPrices(true), 100);
                }
            }

            mcs_nt_calculateTotals() {
                let totalAsk = 0;
                let totalBid = 0;

                this.mcs_nt_data.forEach(item => {
                    const itemHrid = item.hrid || ('/items/' + item.name.toLowerCase().replace(/'/g, '').replace(/ /g, '_'));
                    const prices = this.mcs_nt_getItemPrice(itemHrid);
                    const vendorValue = this.mcs_nt_getVendorValue(itemHrid);

                    const isScamBid = vendorValue > 0 && prices.bid > 0 && prices.bid < vendorValue;
                    const isEqualToVendor = vendorValue > 0 && prices.bid > 0 && prices.bid === vendorValue;

                    const displayBid = (isScamBid || isEqualToVendor) ? vendorValue : prices.bid;

                    totalAsk += prices.ask * item.quantity;
                    totalBid += displayBid * item.quantity;
                });

                return { totalAsk, totalBid };
            }

            mcs_nt_calculateMarketTotal() {
                let marketListings = window.lootDropsTrackerInstance?.myMarketListings;
                if (!marketListings || marketListings.length === 0) {
                    this.mcs_nt_lastMarketTotal = 0;
                    return 0;
                }

                let totalSellAskValue = 0;
                let totalSellBidValue = 0;
                let totalBuyCommitted = 0;

                marketListings.forEach(listing => {
                    const remaining = listing.orderQuantity - (listing.filledQuantity || 0);
                    if (remaining <= 0) return;

                    if (listing.isSell) {
                        const prices = this.mcs_nt_getItemPrice(listing.itemHrid);
                        totalSellAskValue += remaining * prices.ask;
                        totalSellBidValue += remaining * prices.bid;
                    } else {
                        totalBuyCommitted += remaining * listing.price;
                    }
                });

                const useAskPrice = window.getFlootUseAskPrice ? window.getFlootUseAskPrice() : false;
                const realSellValue = useAskPrice ? totalSellAskValue : totalSellBidValue;
                const total = realSellValue + totalBuyCommitted;
                this.mcs_nt_lastMarketTotal = total;
                return total;
            }

            mcs_nt_formatNumber(num) {
                return mcsFormatCurrency(num, 'ntally');
            }

            mcs_nt_updateSortHeaders() {
                const sortNameHeader = document.getElementById('mcs_nt_sort_name');
                const sortValueHeader = document.getElementById('mcs_nt_sort_value');

                if (!sortNameHeader || !sortValueHeader) return;

                if (this.mcs_nt_sortBy === 'name') {
                    sortNameHeader.style.color = '#e0e0e0';
                    sortNameHeader.textContent = `Name ${this.mcs_nt_sortDirection === 'asc' ? '▼' : '▲'}`;
                } else {
                    sortNameHeader.style.color = '#999';
                    sortNameHeader.textContent = 'Name';
                }

                if (this.mcs_nt_sortBy === 'value') {
                    sortValueHeader.style.color = '#e0e0e0';
                    sortValueHeader.textContent = `Value ${this.mcs_nt_sortDirection === 'asc' ? '▼' : '▲'}`;
                } else {
                    sortValueHeader.style.color = '#999';
                    sortValueHeader.textContent = 'Value';
                }
            }

            mcs_nt_shouldUpdateDOM() {
                const pane = document.getElementById('mcs_nt_pane');
                if (!pane || pane.style.display === 'none') return false;

                const content = document.getElementById('mcs_nt_content');
                if (!content || content.style.display === 'none') return false;

                return true;
            }

            mcs_nt_renderContent() {
                const content = document.getElementById('mcs_nt_content');
                const titleSpan = document.getElementById('mcs_nt_title');
                if (!titleSpan) return;

                const { totalAsk, totalBid } = this.mcs_nt_calculateTotals();
                this.mcs_nt_lastTotalAsk = totalAsk;
                this.mcs_nt_lastTotalBid = totalBid;

                titleSpan.textContent = `NTally ${this.mcs_nt_formatNumber(totalAsk)} ask ${this.mcs_nt_formatNumber(totalBid)} bid`;

                if (!this.mcs_nt_shouldUpdateDOM()) return;

                if (!content) return;

                this.mcs_nt_updateSortHeaders();

                const marketTallyHtml = this.mcs_nt_renderMarketTally();

                const planetSetsHtml = this.mcs_nt_renderPlanetSets();

                const treasureSetsHtml = this.mcs_nt_renderTreasureSets();

                if (this.mcs_nt_data.length === 0) {
                    content.innerHTML = marketTallyHtml + planetSetsHtml + treasureSetsHtml + '<div class="mcs-nt-empty-state">Click items in your inventory to add them to the tally</div>';
                    this.mcs_nt_attachMarketTallyListener(content);
                    this.mcs_nt_attachPlanetSetsListener(content);
                    this.mcs_nt_attachTreasureSetsListener(content);
                    return;
                }

                const sortedData = [...this.mcs_nt_data].sort((a, b) => {
                    if (this.mcs_nt_sortBy === 'name') {
                        const nameA = a.name.toLowerCase();
                        const nameB = b.name.toLowerCase();
                        const comparison = nameA.localeCompare(nameB);
                        return this.mcs_nt_sortDirection === 'asc' ? comparison : -comparison;
                    } else {
                        const hridA = a.hrid || ('/items/' + a.name.toLowerCase().replace(/'/g, '').replace(/ /g, '_'));
                        const hridB = b.hrid || ('/items/' + b.name.toLowerCase().replace(/'/g, '').replace(/ /g, '_'));
                        const pricesA = this.mcs_nt_getItemPrice(hridA);
                        const pricesB = this.mcs_nt_getItemPrice(hridB);
                        const totalA = (pricesA.ask + pricesA.bid) / 2 * a.quantity;
                        const totalB = (pricesB.ask + pricesB.bid) / 2 * b.quantity;
                        const comparison = totalA - totalB;
                        return this.mcs_nt_sortDirection === 'asc' ? comparison : -comparison;
                    }
                });

                let html = '';

                sortedData.forEach(item => {
                    const itemHrid = item.hrid || ('/items/' + item.name.toLowerCase().replace(/'/g, '').replace(/ /g, '_'));
                    const prices = this.mcs_nt_getItemPrice(itemHrid);
                    const vendorValue = this.mcs_nt_getVendorValue(itemHrid);

                    const isScamBid = vendorValue > 0 && prices.bid > 0 && prices.bid < vendorValue;
                    const isEqualToVendor = vendorValue > 0 && prices.bid > 0 && prices.bid === vendorValue;

                    const displayBid = (isScamBid || isEqualToVendor) ? vendorValue : prices.bid;
                    const itemTotalAsk = prices.ask * item.quantity;
                    const itemTotalBid = displayBid * item.quantity;

                    const spriteId = itemHrid.replace('/items/', '');

                    const isZeroQty = item.quantity === 0;
                    const iconCursor = isZeroQty ? 'not-allowed' : 'pointer';
                    const iconOpacity = isZeroQty ? '0.3' : '1';
                    const iconFilter = isZeroQty ? 'grayscale(100%)' : 'none';
                    const iconTitle = isZeroQty ? 'Item not in inventory' : 'Click to open in marketplace';

                    html += `<div data-item-name="${item.name}" class="mcs-nt-item-row">`;

                    html += `<div class="mcs_nt_item_icon mcs-nt-item-icon" data-hrid="${itemHrid}" data-quantity="${item.quantity}" style="cursor: ${iconCursor}; opacity: ${iconOpacity}; filter: ${iconFilter};" title="${iconTitle}">`;
                    html += createItemIconHtml(spriteId, { width: '100%', height: '100%', sprite: 'items_sprite', className: 'Icon_icon__2LtL_', style: 'pointer-events: none', title: item.name });
                    html += `</div>`;

                    html += `<div class="mcs-nt-item-info">`;
                    html += `<div class="mcs-nt-item-name">${item.name}</div>`;
                    html += `<div class="mcs_nt_qty mcs-nt-item-qty">Qty: ${item.quantity.toLocaleString()}</div>`;
                    html += `</div>`;

                    html += `<div class="mcs-nt-item-prices">`;
                    html += `<div class="mcs_nt_unit_price mcs-nt-item-unit-price">`;
                    if (isScamBid) {
                        html += `${prices.ask.toLocaleString()} ask <span class="mcs-nt-scam-bid">${displayBid.toLocaleString()} vendor</span>`;
                    } else if (isEqualToVendor) {
                        html += `${prices.ask.toLocaleString()} ask <span class="mcs-nt-equal-vendor">${displayBid.toLocaleString()} vend</span>`;
                    } else {
                        html += `${prices.ask.toLocaleString()} ask ${displayBid.toLocaleString()} bid`;
                    }
                    html += `</div>`;
                    html += `<div class="mcs_nt_total_price mcs-nt-item-total-price">`;
                    if (isScamBid) {
                        html += `${this.mcs_nt_formatNumber(itemTotalAsk)} ask <span class="mcs-nt-scam-total">⚠️ ${this.mcs_nt_formatNumber(itemTotalBid)} vend</span>`;
                    } else if (isEqualToVendor) {
                        html += `${this.mcs_nt_formatNumber(itemTotalAsk)} ask <span class="mcs-nt-equal-vendor-total">${this.mcs_nt_formatNumber(itemTotalBid)} vend</span>`;
                    } else {
                        html += `${this.mcs_nt_formatNumber(itemTotalAsk)} ask ${this.mcs_nt_formatNumber(itemTotalBid)} bid`;
                    }
                    html += `</div>`;
                    html += `</div>`;

                    html += `<button class="mcs_nt_delete_btn mcs-nt-delete-btn" data-item="${item.name}">X</button>`;

                    html += `</div>`;
                });

                content.innerHTML = marketTallyHtml + planetSetsHtml + treasureSetsHtml + html;

                this.mcs_nt_attachMarketTallyListener(content);
                this.mcs_nt_attachPlanetSetsListener(content);
                this.mcs_nt_attachTreasureSetsListener(content);

            }

            mcs_nt_openMarketplace(itemHrid) {
                mcsGoToMarketplace(itemHrid);
            }

            mcs_nt_startObserver() {
                if (this.mcs_nt_observer) return;

                let tooltipDebounceTimer = null;
                let pendingMutations = [];
                this.mcs_nt_observer = new MutationObserver((mutations) => {
                    pendingMutations.push(...mutations);
                    if (tooltipDebounceTimer) return;
                    tooltipDebounceTimer = setTimeout(() => {
                        tooltipDebounceTimer = null;
                        const batch = pendingMutations;
                        pendingMutations = [];
                        for (const mutation of batch) {
                            for (const node of mutation.addedNodes) {
                                if (node.nodeType === 1) {
                                    if (node.classList && node.classList.contains('MuiTooltip-tooltip')) {
                                        this.mcs_nt_injectButton(node);
                                    }
                                    const tooltips = node.querySelectorAll && node.querySelectorAll('.MuiTooltip-tooltip');
                                    if (tooltips) {
                                        tooltips.forEach(tooltip => this.mcs_nt_injectButton(tooltip));
                                    }
                                }
                            }
                        }
                    }, 50);
                });

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

                const ntTooltipObserver = this.mcs_nt_observer;
                document.addEventListener('visibilitychange', () => {
                    if (document.hidden) {
                        ntTooltipObserver.disconnect();
                    } else {
                        ntTooltipObserver.observe(document.body, { childList: true, subtree: true });
                    }
                });
            }

            mcs_nt_injectButton(tooltipElement) {
                if (tooltipElement.querySelector('.mcs_nt_add_btn') || tooltipElement.querySelector('.mcs_nt_scam_warning')) return;

                const actionMenu = tooltipElement.querySelector('[class*="Item_actionMenu"]');
                if (!actionMenu) return;

                const itemInfo = tooltipElement.querySelector('[class*="Item_itemInfo"]');
                if (!itemInfo) return;

                const nameElement = itemInfo.querySelector('[class*="Item_name"]');
                const countElement = itemInfo.querySelector('[class*="Item_count"]');

                if (!nameElement) return;

                const itemName = nameElement.textContent.trim();
                const itemCount = countElement ? parseInt(countElement.textContent.replace(/[^0-9]/g, '')) || 1 : 1;

                const itemHrid = '/items/' + itemName.toLowerCase().replace(/'/g, '').replace(/ /g, '_');

                const checkIsInTally = () => {
                    return this.mcs_nt_data.some(item =>
                        itemHrid ? item.hrid === itemHrid : item.name === itemName
                    );
                };

                let vendorSellPrice = 0;
                const sellButton = tooltipElement.querySelector('[class*="Button_sell"]');
                if (sellButton) {
                    const sellText = sellButton.textContent;
                    const match = sellText.match(/Sell For ([\d,]+) Coins?/i);
                    if (match) {
                        vendorSellPrice = parseInt(match[1].replace(/,/g, ''));
                    }
                }

                const marketData = window.lootDropsTrackerInstance?.spyMarketData || {};
                let bidPrice = 0;
                let rawBid = 0;
                let rawAsk = 0;

                if (marketData[itemHrid] && marketData[itemHrid]['0']) {
                    rawBid = marketData[itemHrid]['0'].b || 0;
                    rawAsk = marketData[itemHrid]['0'].a || 0;
                    if (rawBid > 0) {
                        bidPrice = rawBid < 900 ? Math.floor(rawBid * 0.98) : Math.ceil(rawBid * 0.98);
                    }
                }

                const isScamBid = vendorSellPrice > 0 && bidPrice > 0 && bidPrice < vendorSellPrice;

                if (rawBid > 0 || rawAsk > 0) {
                    const marketInfo = document.createElement('div');
                    marketInfo.className = 'mcs_nt_market_info mcs-nt-market-info';
                    marketInfo.innerHTML = `Market: ${rawAsk.toLocaleString()} ask / ${rawBid.toLocaleString()} bid`;
                    actionMenu.appendChild(marketInfo);
                }

                if (isScamBid) {
                    const scamWarning = document.createElement('div');
                    scamWarning.className = 'mcs_nt_scam_warning mcs-nt-scam-warning';
                    scamWarning.innerHTML = '⚠️ SCAM BID!';
                    actionMenu.appendChild(scamWarning);
                }

                const updateButtonAppearance = (isInTally) => {
                    if (isInTally) {
                        addButton.textContent = 'Remove from Tally';
                        addButton.style.background = '#d32f2f';
                    } else {
                        addButton.textContent = 'Add to Tally';
                        addButton.style.background = '#4CAF50';
                    }
                };

                const addButton = document.createElement('button');
                const gameButtonClasses = sellButton ? sellButton.className.replace(/Button_sell[^\s]*/g, '').trim() : '';
                addButton.className = (gameButtonClasses ? gameButtonClasses + ' ' : '') + 'mcs_nt_add_btn mcs-nt-tally-btn';

                updateButtonAppearance(checkIsInTally());

                addButton.addEventListener('click', (e) => {
                    e.stopPropagation();

                    const isCurrentlyInTally = checkIsInTally();

                    if (isCurrentlyInTally) {
                        this.mcs_nt_removeItem(itemName);
                        addButton.textContent = 'Removed!';
                        addButton.style.background = '#2196F3';
                        setTimeout(() => {
                            updateButtonAppearance(checkIsInTally());
                        }, 1000);
                    } else {
                        this.mcs_nt_addItem(itemName, itemCount, itemHrid);
                        addButton.textContent = 'Added!';
                        addButton.style.background = '#2196F3';
                        setTimeout(() => {
                            updateButtonAppearance(checkIsInTally());
                        }, 1000);
                    }
                });

                actionMenu.appendChild(addButton);
            }

            mcs_nt_updateItemRow(itemName) {
                if (!this.mcs_nt_shouldUpdateDOM()) return;

                const content = document.getElementById('mcs_nt_content');
                if (!content) return;

                const item = this.mcs_nt_data.find(i => i.name === itemName);
                if (!item) return;

                const itemHrid = item.hrid || ('/items/' + item.name.toLowerCase().replace(/'/g, '').replace(/ /g, '_'));
                const prices = this.mcs_nt_getItemPrice(itemHrid);
                const vendorValue = this.mcs_nt_getVendorValue(itemHrid);

                const isScamBid = vendorValue > 0 && prices.bid > 0 && prices.bid < vendorValue;
                const isEqualToVendor = vendorValue > 0 && prices.bid > 0 && prices.bid === vendorValue;

                const displayBid = (isScamBid || isEqualToVendor) ? vendorValue : prices.bid;

                const itemTotalAsk = prices.ask * item.quantity;
                const itemTotalBid = displayBid * item.quantity;

                const rows = content.querySelectorAll('[data-item-name]');
                for (const row of rows) {
                    if (row.getAttribute('data-item-name') === itemName) {
                        const iconElement = row.querySelector('.mcs_nt_item_icon');
                        if (iconElement) {
                            const isZeroQty = item.quantity === 0;
                            iconElement.style.cursor = isZeroQty ? 'not-allowed' : 'pointer';
                            iconElement.style.opacity = isZeroQty ? '0.3' : '1';
                            iconElement.style.filter = isZeroQty ? 'grayscale(100%)' : 'none';
                            iconElement.title = isZeroQty ? 'Item not in inventory' : 'Click to open in marketplace';
                            iconElement.setAttribute('data-quantity', item.quantity);
                        }

                        const qtyElement = row.querySelector('.mcs_nt_qty');
                        if (qtyElement) {
                            qtyElement.textContent = `Qty: ${item.quantity.toLocaleString()}`;
                        }

                        const unitPriceElement = row.querySelector('.mcs_nt_unit_price');
                        if (unitPriceElement) {
                            if (isScamBid) {
                                unitPriceElement.innerHTML = `${prices.ask.toLocaleString()} ask <span class="mcs-nt-scam-bid">${displayBid.toLocaleString()} vendor</span>`;
                            } else if (isEqualToVendor) {
                                unitPriceElement.innerHTML = `${prices.ask.toLocaleString()} ask <span class="mcs-nt-equal-vendor">${displayBid.toLocaleString()} vend</span>`;
                            } else {
                                unitPriceElement.textContent = `${prices.ask.toLocaleString()} ask ${displayBid.toLocaleString()} bid`;
                            }
                        }

                        const totalPriceElement = row.querySelector('.mcs_nt_total_price');
                        if (totalPriceElement) {
                            if (isScamBid) {
                                totalPriceElement.innerHTML = `${this.mcs_nt_formatNumber(itemTotalAsk)} ask <span class="mcs-nt-scam-total">⚠️ ${this.mcs_nt_formatNumber(itemTotalBid)} vend</span>`;
                            } else if (isEqualToVendor) {
                                totalPriceElement.innerHTML = `${this.mcs_nt_formatNumber(itemTotalAsk)} ask <span class="mcs-nt-equal-vendor-total">${this.mcs_nt_formatNumber(itemTotalBid)} vend</span>`;
                            } else {
                                totalPriceElement.textContent = `${this.mcs_nt_formatNumber(itemTotalAsk)} ask ${this.mcs_nt_formatNumber(itemTotalBid)} bid`;
                            }
                        }
                        break;
                    }
                }
            }

            mcs_nt_updateTotals() {
                const titleSpan = document.getElementById('mcs_nt_title');
                if (!titleSpan) return;

                const { totalAsk, totalBid } = this.mcs_nt_calculateTotals();
                this.mcs_nt_lastTotalAsk = totalAsk;
                this.mcs_nt_lastTotalBid = totalBid;
                titleSpan.textContent = `NTally ${this.mcs_nt_formatNumber(totalAsk)} ask ${this.mcs_nt_formatNumber(totalBid)} bid`;
            }

            mcs_nt_refreshPrices() {
                this.mcs_nt_calculateChestValues().then(() => {
                    this.mcs_nt_data.forEach(item => {
                        this.mcs_nt_updateItemRow(item.name);
                    });
                    this.mcs_nt_updateTotals();
                });
            }

            mcs_nt_updateQuantities() {
                const changedItems = [];
                const removedItems = [];

                const characterItems = window.lootDropsTrackerInstance?.spyCharacterItems || [];

                this.mcs_nt_data.forEach(item => {
                    const itemHrid = item.hrid || ('/items/' + item.name.toLowerCase().replace(/'/g, '').replace(/ /g, '_'));

                    const inventoryItem = characterItems.find(charItem =>
                        charItem.itemHrid === itemHrid &&
                        (charItem.itemLocationHrid === '/item_locations/inventory' || !charItem.itemLocationHrid)
                    );

                    const currentQuantity = inventoryItem ? (inventoryItem.count || 0) : 0;

                    if (currentQuantity > 0) {
                        if (currentQuantity !== item.quantity) {
                            item.quantity = currentQuantity;
                            changedItems.push(item.name);
                        }
                    } else {
                        if (item.quantity !== 0) {
                            item.quantity = 0;
                            removedItems.push(item.name);
                        }
                    }
                });

                const allChangedItems = [...changedItems, ...removedItems];

                if (allChangedItems.length > 0) {
                    this.mcs_nt_saveData();
                    allChangedItems.forEach(itemName => {
                        this.mcs_nt_updateItemRow(itemName);
                    });
                    this.mcs_nt_updateTotals();
                }
            }

            mcs_nt_handleMarketDataUpdated() {
                this.mcs_nt_refreshPrices();
            }

            mcs_nt_handleBattleEnded() {
                this.mcs_nt_updateQuantities();
            }

            mcs_nt_handleFlootPricesUpdated() {
                this.mcs_nt_calculateChestValues().then(() => {
                    this.mcs_nt_renderContent();
                });
            }

            mcs_nt_handleWebSocketMessage(event) {
                const data = event.detail;
                if (data?.type === 'init_character_data' && data.myMarketListings) {
                    if (window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.myMarketListings = data.myMarketListings;
                    }
                    setTimeout(() => this.mcs_nt_renderContent(), 100);
                }
                if (data?.type === 'market_item_order_updated' || data?.type === 'market_item_orders' || data?.type === 'market_listings_updated') {
                    if (data.myMarketListings && window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.myMarketListings = data.myMarketListings;
                    }
                    setTimeout(() => {
                        this.mcs_nt_updateQuantities();
                        this.mcs_nt_renderContent();
                    }, 100);
                }
            }

            mcs_nt_setupEventListeners() {
                if (this._ntWsListener) return;
                this._ntMarketDataListener = this.mcs_nt_handleMarketDataUpdated.bind(this);
                this._ntBattleEndedListener = this.mcs_nt_handleBattleEnded.bind(this);
                this._ntFlootPricesListener = this.mcs_nt_handleFlootPricesUpdated.bind(this);
                this._ntWsListener = this.mcs_nt_handleWebSocketMessage.bind(this);
                window.addEventListener('mcs-market-data-updated', this._ntMarketDataListener);
                window.addEventListener('mcs-battle-ended', this._ntBattleEndedListener);
                window.addEventListener('FlootPricesUpdated', this._ntFlootPricesListener);
                window.addEventListener('EquipSpyWebSocketMessage', this._ntWsListener);

                VisibilityManager.register('ntally-quantity-update', () => {
                    this.mcs_nt_updateQuantities();
                }, 2000);

                VisibilityManager.register('ntally-price-update', () => {
                    this.mcs_nt_refreshPrices();
                }, 10000);
            }

            mcs_nt_destroy() {
                if (this._ntDragMove) {
                    document.removeEventListener('mousemove', this._ntDragMove);
                    document.removeEventListener('mouseup', this._ntDragUp);
                    this._ntDragMove = null;
                    this._ntDragUp = null;
                }
                if (this.mcs_nt_observer) {
                    this.mcs_nt_observer.disconnect();
                    this.mcs_nt_observer = null;
                }
                if (this._ntResizeObserver) {
                    this._ntResizeObserver.disconnect();
                    this._ntResizeObserver = null;
                }

                VisibilityManager.clear('ntally-quantity-update');
                VisibilityManager.clear('ntally-price-update');

                if (this._ntMarketDataListener) { window.removeEventListener('mcs-market-data-updated', this._ntMarketDataListener); this._ntMarketDataListener = null; }
                if (this._ntBattleEndedListener) { window.removeEventListener('mcs-battle-ended', this._ntBattleEndedListener); this._ntBattleEndedListener = null; }
                if (this._ntFlootPricesListener) { window.removeEventListener('FlootPricesUpdated', this._ntFlootPricesListener); this._ntFlootPricesListener = null; }
                if (this._ntWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._ntWsListener); this._ntWsListener = null; }

                const pane = document.getElementById('mcs_nt_pane');
                if (pane) {
                    pane.remove();
                }

                this.mcs_nt_stopMarketplacePanelMonitor();
            }

            mcs_nt_startMarketplacePanelMonitor() {
                this.mcs_nt_stopMarketplacePanelMonitor();

                let marketplaceDebounceTimer = null;
                this.mcs_nt_marketplaceObserver = new MutationObserver(() => {
                    if (marketplaceDebounceTimer) return;
                    marketplaceDebounceTimer = setTimeout(() => {
                        marketplaceDebounceTimer = null;
                        this.mcs_nt_checkMarketplacePanel();
                    }, 200);
                });

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

                const ntMarketObserver = this.mcs_nt_marketplaceObserver;
                const ntSelf = this;
                document.addEventListener('visibilitychange', () => {
                    if (document.hidden) {
                        ntMarketObserver.disconnect();
                    } else {
                        ntMarketObserver.observe(document.body, { childList: true, subtree: true });
                        ntSelf.mcs_nt_checkMarketplacePanel();
                    }
                });

                this.mcs_nt_checkMarketplacePanel();
            }

            mcs_nt_stopMarketplacePanelMonitor() {
                if (this.mcs_nt_marketplaceObserver) {
                    this.mcs_nt_marketplaceObserver.disconnect();
                    this.mcs_nt_marketplaceObserver = null;
                }
            }

            mcs_nt_checkMarketplacePanel() {
                const savedStates = ToolVisibilityStorage.get();
                if (savedStates['floot-market-warnings'] === false) {
                    const existing = document.querySelector('.mcs-nt-marketplace-scam-warning');
                    if (existing) existing.remove();
                    this.mcs_nt_lastMarketBidState = null;
                    return;
                }

                let infoContainer = document.querySelector('[class*="MarketplacePanel"][class*="infoContainer"]');
                if (!infoContainer) {
                    infoContainer = document.querySelector('[class*="MarketplacePanel_infoContainer"]');
                }
                if (!infoContainer) {
                    this.mcs_nt_lastMarketBidState = null;
                    return;
                }

                let itemName = null;

                const iconSvg = infoContainer.querySelector('svg[aria-label]');
                if (iconSvg) {
                    itemName = iconSvg.getAttribute('aria-label');
                }

                if (!itemName) {
                    const svgIcon = infoContainer.querySelector('svg[role="img"]');
                    if (svgIcon) {
                        itemName = svgIcon.getAttribute('aria-label');
                    }
                }

                if (!itemName) {
                    const nameElements = infoContainer.querySelectorAll('div, span, h1, h2, h3, h4, h5, h6');
                    for (const el of nameElements) {
                        const text = el.textContent.trim();
                        if (text.length > 2 && text.length < 50 && !text.match(/^[\d,]+/)) {
                            if (!text.includes('Bid') && !text.includes('Ask') && !text.includes('Price') && !text.includes('Quantity')) {
                                itemName = text;
                                break;
                            }
                        }
                    }
                }

                if (!itemName) {
                    return;
                }

                const itemHrid = '/items/' + itemName.toLowerCase().replace(/'/g, '').replace(/ /g, '_');

                const vendorValue = this.mcs_nt_getVendorValue(itemHrid);
                if (vendorValue === 0) {
                    return;
                }

                const orderBooksContainer = document.querySelector('[class*="orderBooksContainer"]');
                if (!orderBooksContainer) {
                    return;
                }

                const orderBookContainers = orderBooksContainer.querySelectorAll('[class*="orderBookTableContainer"]');
                if (orderBookContainers.length < 2) {
                    return;
                }

                const bidTableContainer = orderBookContainers[1];

                const bidPriceElement = bidTableContainer.querySelector('[class*="price"] span');
                if (!bidPriceElement) return;

                const rawBidText = bidPriceElement.textContent.trim();

                let rawBid = 0;
                const cleanText = rawBidText.replace(/,/g, '').trim().toUpperCase();

                if (cleanText.endsWith('M')) {
                    rawBid = parseFloat(cleanText) * 1000000;
                } else if (cleanText.endsWith('K')) {
                    rawBid = parseFloat(cleanText) * 1000;
                } else {
                    rawBid = parseInt(cleanText);
                }

                if (isNaN(rawBid) || rawBid === 0) return;

                const bidAfterTax = rawBid < 900 ? Math.floor(rawBid * 0.98) : Math.ceil(rawBid * 0.98);

                const isScamBid = bidAfterTax < vendorValue;
                const isEqualToVendor = bidAfterTax === vendorValue;

                const currentState = `${itemName}:${rawBid}:${isScamBid}`;

                if (this.mcs_nt_lastMarketBidState === currentState) {
                    return;
                }

                this.mcs_nt_lastMarketBidState = currentState;

                const bidPriceHeader = bidTableContainer.querySelector('th:nth-child(2)');
                if (!bidPriceHeader) return;

                const existingWarning = bidPriceHeader.querySelector('.mcs-nt-marketplace-scam-warning');
                if (existingWarning) {
                    existingWarning.remove();
                }

                if (isScamBid) {
                    const warningDiv = document.createElement('div');
                    warningDiv.className = 'mcs-nt-marketplace-scam-warning mcs-nt-marketplace-warning';
                    warningDiv.style.color = '#ff1744';
                    warningDiv.innerHTML = '⚠️ SCAM! VENDOR';
                    bidPriceHeader.appendChild(warningDiv);
                } else if (isEqualToVendor) {
                    const warningDiv = document.createElement('div');
                    warningDiv.className = 'mcs-nt-marketplace-scam-warning mcs-nt-marketplace-warning';
                    warningDiv.style.color = '#FFD700';
                    warningDiv.innerHTML = 'SAME AS VENDOR';
                    bidPriceHeader.appendChild(warningDiv);
                }
            }

// NTally end

// PF start

            get pfStorage() {
                if (!this._pfStorage) {
                    this._pfStorage = createModuleStorage('PF');
                }
                return this._pfStorage;
            }

            createPFormancePane() {
                if (document.getElementById('pformance-pane')) return;

                const pane = document.createElement('div');
                pane.id = 'pformance-pane';
                registerPanel('pformance-pane');
                this.applyClass(pane, 'mcs-pf-pane');

                const savedSize = this.pfStorage.get('size');
                let width = 420;
                let height = 550;
                if (savedSize) {
                    try {
                        const size = typeof savedSize === 'string' ? JSON.parse(savedSize) : savedSize;
                        width = size.width || 420;
                        height = size.height || 550;
                    } catch (e) {
                        console.error('[PFormance] Error restoring size:', e);
                    }
                }

                pane.style.width = `${width}px`;
                pane.style.height = `${height}px`;

                pane.dataset.savedHeight = height;

                const header = document.createElement('div');
                this.applyClass(header, 'mcs-pf-header');

                const titleSection = document.createElement('div');
                this.applyClass(titleSection, 'mcs-pf-title-section');

                const titleSpan = document.createElement('span');
                titleSpan.id = 'pformance-title';
                this.applyClass(titleSpan, 'mcs-pf-title');
                titleSpan.textContent = 'PFormance: 0 KB';

                titleSection.appendChild(titleSpan);

                const buttonSection = document.createElement('div');
                this.applyClass(buttonSection, 'mcs-pf-button-section');

                const refreshBtn = document.createElement('button');
                refreshBtn.id = 'pformance-refresh-btn';
                refreshBtn.textContent = '↻';
                refreshBtn.title = 'Refresh storage data';
                this.applyClass(refreshBtn, 'mcs-pf-btn');
                refreshBtn.onclick = () => this.pf_updateStorageData();

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'pformance-minimize-btn';
                minimizeBtn.textContent = '−';
                this.applyClasses(minimizeBtn, 'mcs-pf-btn', 'mcs-pf-minimize-btn');

                buttonSection.appendChild(refreshBtn);
                buttonSection.appendChild(minimizeBtn);
                header.appendChild(titleSection);
                header.appendChild(buttonSection);

                const content = document.createElement('div');
                content.id = 'pformance-content';
                this.applyClass(content, 'mcs-pf-content');

                content.innerHTML = '<div class="mcs-pf-loading">Loading storage data...</div>';

                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);

                let dragStartX, dragStartY, initialLeft, initialTop;

                const onDragMove = (e) => {
                    const dx = e.clientX - dragStartX;
                    const dy = e.clientY - dragStartY;

                    let newLeft = initialLeft + dx;
                    let newTop = initialTop + dy;

                    const paneRect = pane.getBoundingClientRect();
                    const headerHeight = header.getBoundingClientRect().height;

                    const minLeft = -paneRect.width + 100;
                    const maxLeft = window.innerWidth - 100;
                    const minTop = 0;
                    const maxTop = window.innerHeight - headerHeight;

                    newLeft = Math.max(minLeft, Math.min(maxLeft, newLeft));
                    newTop = Math.max(minTop, Math.min(maxTop, newTop));

                    pane.style.left = newLeft + 'px';
                    pane.style.top = newTop + 'px';
                };

                const onDragUp = () => {
                    document.removeEventListener('mousemove', onDragMove);
                    document.removeEventListener('mouseup', onDragUp);
                    header.style.cursor = 'move';
                    const rect = pane.getBoundingClientRect();
                    this.pfStorage.set('position', { top: rect.top, left: rect.left });
                    this.constrainPanelToBoundaries('pformance-pane', 'mcs_PF', true);
                };

                header.addEventListener('mousedown', (e) => {
                    if (e.target.closest('button')) return;
                    dragStartX = e.clientX;
                    dragStartY = e.clientY;
                    const rect = pane.getBoundingClientRect();
                    initialLeft = rect.left;
                    initialTop = rect.top;
                    header.style.cursor = 'grabbing';
                    pane.style.left = initialLeft + 'px';
                    pane.style.right = 'auto';
                    this._pfDragMove = onDragMove;
                    this._pfDragUp = onDragUp;
                    document.addEventListener('mousemove', onDragMove);
                    document.addEventListener('mouseup', onDragUp);
                });

                minimizeBtn.addEventListener('click', () => {
                    const isMinimized = content.style.display === 'none';
                    if (isMinimized) {
                        content.style.display = 'block';
                        minimizeBtn.textContent = '−';
                        header.classList.remove('mcs-pf-header-minimized');
                        const savedHeight = pane.dataset.savedHeight || height;
                        pane.style.height = savedHeight + 'px';
                        pane.style.minHeight = '300px';
                        pane.style.resize = 'both';
                        this.pfStorage.set('minimized', false);
                    } else {
                        const currentRect = pane.getBoundingClientRect();
                        pane.dataset.savedHeight = currentRect.height;

                        content.style.display = 'none';
                        minimizeBtn.textContent = '+';
                        header.classList.add('mcs-pf-header-minimized');

                        const headerHeight = header.getBoundingClientRect().height;
                        pane.style.height = headerHeight + 'px';
                        pane.style.minHeight = '0';
                        pane.style.resize = 'none';
                        this.pfStorage.set('minimized', true);
                    }
                });

                const savedPosition = this.pfStorage.get('position');
                if (savedPosition) {
                    try {
                        const position = typeof savedPosition === 'string' ? JSON.parse(savedPosition) : savedPosition;
                        pane.style.top = position.top + 'px';
                        if (position.left !== undefined) {
                            pane.style.left = position.left + 'px';
                            pane.style.right = 'auto';
                        } else if (position.right !== undefined) {
                            pane.style.right = position.right + 'px';
                        }
                        this.constrainPanelToBoundaries('pformance-pane', 'mcs_PF', true);
                    } catch (e) {
                        console.error('[PFormance] Error restoring position:', e);
                    }
                }

                const savedMinimized = this.pfStorage.get('minimized') === true || this.pfStorage.get('minimized') === 'true';
                if (savedMinimized) {
                    content.style.display = 'none';
                    minimizeBtn.textContent = '+';
                    header.classList.add('mcs-pf-header-minimized');
                    const headerHeight = header.getBoundingClientRect().height;
                    pane.style.height = headerHeight + 'px';
                    pane.style.minHeight = '0';
                    pane.style.resize = 'none';
                }

                let pfResizeTimer = null;
                this._pfResizeObserver = new ResizeObserver(() => {
                    const rect = pane.getBoundingClientRect();
                    const isMinimized = content.style.display === 'none';

                    if (!isMinimized) {
                        pane.dataset.savedHeight = rect.height;
                    }

                    clearTimeout(pfResizeTimer);
                    pfResizeTimer = setTimeout(() => {
                        this.pfStorage.set('size', {
                            width: rect.width,
                            height: isMinimized ? pane.dataset.savedHeight : rect.height
                        });
                    }, 300);
                });
                this._pfResizeObserver.observe(pane);

                this.pf_updateStorageData();

                const savedStates = ToolVisibilityStorage.get();
                const shouldRun = savedStates['pformance'] !== false;

                if (shouldRun) {
                    PerformanceMonitor.enabled = true;
                    StorageMonitor.enabled = true;

                    VisibilityManager.register('pformance-cpu-update', () => {
                        this.pf_updateCpuDisplay();
                        this.pf_updateStorageIODisplay();
                    }, 1000);

                    this.pformanceRunning = true;
                } else {
                    PerformanceMonitor.enabled = false;
                    StorageMonitor.enabled = false;
                    this.pformanceRunning = false;
                }
            }

            pf_getStorageSize(key) {
                try {
                    const value = localStorage.getItem(key);
                    if (!value) return 0;
                    return new Blob([value]).size;
                } catch (e) {
                    return 0;
                }
            }

            pf_formatBytes(bytes) {
                if (bytes === 0) return '0 B';
                if (bytes < 1024) return bytes.toFixed(0) + ' B';
                if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
                return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
            }

            pf_isKeyActive(key) {
                const activeKeyPatterns = [
                    'mcs__global_marketAPI_json',
                    'initClientData', 'init_character_data', 'mcs__global_init_character_data',
                    'mcs__global_FC_enabled', 'mcs__global_FC_settings_map',
                    'mcs__global_KO_inspected_players',
                    'mcs__global_market_timestamp',
                    'mwi-suite-tool-visibility', 'mwi-combat-suite-position',

                    'mcs_AM_', 'mcs_BR_', 'mcs_CR_', 'mcs_DP_', 'mcs_EW_', 'mcs_FL_', 'mcs_GW_',
                    'mcs_HW_', 'mcs_IH_', 'mcs_JH_', 'mcs_KO_', 'mcs_LY_', 'mcs_MA_', 'mcs_NT_',
                    'mcs_OP_', 'mcs_PF_', 'mcs_QC_', 'mcs_TR_',

                    'amazingMinimized', 'amazingPanePosition', 'meatersMinimized',
                    'breadMinimized', 'breadPanePosition',
                    'crack_consumable_inventory',
                    'dpsMinimized', 'dpsFilterAbilities',
                    'equipSpyMinimized', 'equipSpy_position', 'equipSpy_locked', 'equipSpy_simpleMode',
                    'equipSpy_noSellMode', 'equipSpy_comparisonOrder', 'equipSpy_selectedHeaderSlot',
                    'fcb_enabled', 'fcb_settingsMap',
                    'floot_contentMinimized',
                    'lootDropsPosition', 'lootDropsHidden', 'lootDropsSortPref', 'lootDropsStartHidden', 'lootDropsSessionHistory',
                    'gwhizMinimized', 'gwhizBulwarkEnabled', 'gwhizTTLCollapsed', 'gwhizCharmsCollapsed', 'gwhizPanePosition',
                    'hwhatPanePosition', 'hwhatIsMinimized', 'hwhatMode', 'hwhatCostsEnabled', 'hwhatCowbellTaxEnabled',
                    'ihurtMinimized', 'ihurtPanePosition',
                    'jhouseMinimized', 'jhousePanePosition', 'jhouseFilters',
                    'kollection_market_timestamp', 'kollection_market_data', 'kollection_inspected_players', 'mcs_ko_minimized',
                    'lucky_settings', 'lucky_position', 'lucky_panel_state', 'lucky_panel_settings', 'lucky_panel_',
                    'manaPaneSize', 'manaPanePosition', 'manaMinimized',
                    'mcs_nt_data', 'mcs_nt_panePosition', 'mcs_nt_paneSize', 'mcs_nt_minimized', 'mcs_nt_planet_', 'mcs_nt_treasure_',
                    'oPanelPosition', 'oPanelSize', 'oPanelIsLocked', 'oPanelZoomLevels', 'oPanelConfig',
                    'pformancePanePosition', 'pformancePaneSize', 'pformanceMinimized',
                    'mcs_qc_panePosition', 'mcs_qc_paneSize', 'mcs_qc_minimized', 'mcs_qc_guide_collapsed', 'mcs_qc_sections_collapsed', 'mcs_qc_charms_',
                    'treasurePaneSize', 'treasureMinimized', 'treasurePanePosition', 'mcs_TR_'
                ];

                const lowerKey = key.toLowerCase();

                for (const pattern of activeKeyPatterns) {
                    if (lowerKey === pattern.toLowerCase() || lowerKey.includes(pattern.toLowerCase())) {
                        return true;
                    }
                }

                if (lowerKey.match(/^character_\d+_/)) return true;
                if (lowerKey.match(/^mcs_ko_\d+_/)) return true;

                return false;
            }

            pf_categorizeKeys() {
                const categories = {
                    'Game Data': [],
                    'MCS Global': [],
                    'MCS Modules': [],
                    'Other': []
                };

                const gameDataKeys = new Set([
                    'initClientData',
                    'i18nextLng',
                    'lastExternalReferrer',
                    'lastExternalReferrerTime',
                    'topicsLastReferenceTime',
                    '_gcl_ls',
                    'localHash'
                ]);

                for (let i = 0; i < localStorage.length; i++) {
                    const key = localStorage.key(i);
                    if (!key) continue;

                    const size = this.pf_getStorageSize(key);
                    const lowerKey = key.toLowerCase();

                    const knownModulePrefixes = ['AM', 'BR', 'CR', 'DP', 'EW', 'FC', 'FL', 'GW', 'HW', 'IH', 'JH', 'KO', 'LY', 'MA', 'NT', 'OP', 'PF', 'QC', 'SC', 'TR'];

                    if (key.startsWith('mcs__global_')) {
                        categories['MCS Global'].push({ key, size, isActive: true });
                    }
                    else if (key.match(/^mcs_[A-Z]{2}_/) && knownModulePrefixes.some(prefix => key.startsWith(`mcs_${prefix}_`))) {
                        categories['MCS Modules'].push({ key, size, isActive: true });
                    }
                    else if (gameDataKeys.has(key)) {
                        categories['Game Data'].push({ key, size, isActive: true });
                    }
                    else if (this.pf_isLegacyMcsKey(lowerKey)) {
                        categories['Other'].push({ key, size, isActive: true });
                    }
                    else {
                        categories['Other'].push({ key, size, isActive: false });
                    }
                }

                return categories;
            }

            pf_isLegacyMcsKey(lowerKey) {
                const legacyPatterns = [
                    'mwi-suite-tool-visibility', 'mwi-combat-suite-position',
                    'lootdrops', 'equipspy', 'floot_', 'kollection', 'lucky',
                    'ntally', 'opanel', 'ewatch', 'jhouse', 'dps-pane', 'bread',
                    'hwhat', 'gwhiz', 'amazing', 'meaters', 'fcb', 'ihurt',
                    'crack', 'qcharm', 'treasure', 'mana', 'pformance'
                ];
                return legacyPatterns.some(pattern => lowerKey.includes(pattern));
            }

            pf_updateStorageData(isAutoRefresh = false) {
                const content = document.getElementById('pformance-content');
                const titleSpan = document.getElementById('pformance-title');
                if (!content || !titleSpan) return;

                const categories = this.pf_categorizeKeys();

                const categoryTotals = {};
                let grandTotal = 0;

                for (const [category, items] of Object.entries(categories)) {
                    const total = items.reduce((sum, item) => sum + item.size, 0);
                    categoryTotals[category] = total;
                    grandTotal += total;
                }

                titleSpan.textContent = `PFormance: ${this.pf_formatBytes(grandTotal)}`;

                const collapsedStates = this.pfStorage.get('collapsedSections') ?? {};

                if (isAutoRefresh && content.children.length > 0) {
                    const summaryDiv = content.querySelector('.mcs-pf-summary');
                    if (summaryDiv) {
                        const totalDiv = summaryDiv.querySelector('.mcs-pf-total');
                        const itemsDiv = summaryDiv.querySelector('.mcs-pf-items-count');
                        if (totalDiv) totalDiv.textContent = `Total Storage: ${this.pf_formatBytes(grandTotal)}`;
                        if (itemsDiv) itemsDiv.textContent = `Items: ${localStorage.length}`;
                    }

                    const categoryOrder = ['Game Data', 'MCS Global', 'MCS Modules', 'Other'];
                    categoryOrder.forEach(category => {
                        const containerId = `pf-cat-${category.replace(/\s+/g, '-').toLowerCase()}`;
                        const detailsId = `${containerId}-details`;
                        const details = document.getElementById(detailsId);

                        if (details && details.style.display !== 'none') {
                            this.pf_updateCategoryContent(containerId, category);
                        } else if (details) {
                            const items = categories[category] ?? [];
                            const total = categoryTotals[category] || 0;
                            const percentage = grandTotal > 0 ? ((total / grandTotal) * 100).toFixed(1) : '0.0';

                            const header = details.previousElementSibling;
                            if (header) {
                                const totalDiv = header.querySelector('.mcs-pf-category-total');
                                const percentDiv = header.querySelector('.mcs-pf-category-percent');
                                if (totalDiv) totalDiv.textContent = this.pf_formatBytes(total);
                                if (percentDiv) percentDiv.textContent = `${percentage}%`;

                                const countSpan = header.querySelector('.mcs-pf-item-count');
                                if (countSpan) {
                                    countSpan.textContent = `(${items.length})`;
                                }
                            }
                        }
                    });

                    return;
                }

                const categoryOrder = ['Game Data', 'MCS Global', 'MCS Modules', 'Other'];

                let html = '';

                html += '<div class="mcs-pf-summary">';
                html += `<div class="mcs-pf-total">Total Storage: ${this.pf_formatBytes(grandTotal)}</div>`;
                html += `<div class="mcs-pf-items-count">Items: ${localStorage.length}</div>`;
                html += '</div>';

                const cpuCollapsed = collapsedStates['pf-cpu'] === true;
                html += '<div class="mcs-pf-section">';
                html += '<div class="pf-toggle-header mcs-pf-toggle-header" data-details-id="pf-cpu-details" data-container-id="pf-cpu">';
                html += `<div><span id="pf-cpu-toggle" class="mcs-pf-toggle-indicator">${cpuCollapsed ? '+' : '↓'}</span><span class="mcs-pf-cpu-label">CPU Usage</span><span class="mcs-pf-section-subtitle">(real-time, 5s window)</span></div>`;
                html += '</div>';
                html += `<div id="pf-cpu-details" class="mcs-pf-section-details" style="${cpuCollapsed ? 'display: none;' : ''}"><div id="pf-cpu-section"></div></div>`;
                html += '</div>';

                const ioCollapsed = collapsedStates['pf-storage-io'] === true;
                html += '<div class="mcs-pf-section mcs-pf-section-bordered">';
                html += '<div class="pf-toggle-header mcs-pf-toggle-header" data-details-id="pf-storage-io-details" data-container-id="pf-storage-io">';
                html += `<div><span id="pf-storage-io-toggle" class="mcs-pf-toggle-indicator">${ioCollapsed ? '+' : '↓'}</span><span class="mcs-pf-io-label">LocalStorage I/O</span><span class="mcs-pf-section-subtitle">(real-time, 5s window)</span></div>`;
                html += '</div>';
                html += `<div id="pf-storage-io-details" class="mcs-pf-section-details" style="${ioCollapsed ? 'display: none;' : ''}"><div id="pf-storage-io-section"></div></div>`;
                html += '</div>';

                categoryOrder.forEach(category => {
                    const items = categories[category];
                    const total = categoryTotals[category];
                    if (!items || items.length === 0) return;

                    const percentage = grandTotal > 0 ? ((total / grandTotal) * 100).toFixed(1) : '0.0';
                    const itemCount = items.length;

                    const containerId = `pf-cat-${category.replace(/\s+/g, '-').toLowerCase()}`;
                    const detailsId = `${containerId}-details`;
                    const isCollapsed = collapsedStates[containerId] !== false;

                    html += '<div class="mcs-pf-section">';

                    html += `<div class="pf-toggle-header mcs-pf-toggle-header" data-details-id="${detailsId}" data-container-id="${containerId}">`;
                    html += `<div style="flex: 1;">`;
                    html += `<span id="${containerId}-toggle" class="mcs-pf-toggle-indicator">${isCollapsed ? '+' : '↓'}</span>`;
                    html += `<span class="mcs-pf-category-label">${category}</span>`;
                    html += `<span class="mcs-pf-item-count">(${itemCount})</span>`;
                    html += `</div>`;
                    html += `<div style="text-align: right;">`;
                    html += `<div class="mcs-pf-category-total">${this.pf_formatBytes(total)}</div>`;
                    html += `<div class="mcs-pf-category-percent">${percentage}%</div>`;
                    html += `</div>`;
                    html += `</div>`;

                    html += `<div id="${detailsId}" class="mcs-pf-category-items" style="display: ${isCollapsed ? 'none' : 'block'};">`;

                    const sortedItems = category === 'MCS Modules'
                        ? items.sort((a, b) => a.key.localeCompare(b.key))
                        : items.sort((a, b) => b.size - a.size);

                    sortedItems.forEach(item => {
                        const itemPercentage = total > 0 ? ((item.size / total) * 100).toFixed(1) : '0.0';
                        const keyClass = item.isActive ? 'mcs-pf-item-key-active' : 'mcs-pf-item-key-inactive';
                        const keyTitle = item.isActive ? `${item.key} (used by MCS)` : item.key;

                        html += '<div class="mcs-pf-item-row">';
                        html += `<span class="${keyClass}" title="${keyTitle}">${item.key}</span>`;
                        html += `<span class="mcs-pf-item-size">${this.pf_formatBytes(item.size)} (${itemPercentage}%)</span>`;
                        html += `<button class="pf-delete-item mcs-pf-delete-btn" data-key="${item.key}" title="Delete ${item.key}">×</button>`;
                        html += '</div>';
                    });

                    html += '</div>';
                    html += '</div>';
                });

                if (navigator.storage && navigator.storage.estimate) {
                    navigator.storage.estimate().then(estimate => {
                        const used = estimate.usage || 0;
                        const quota = estimate.quota || 0;

                        if (quota > 0) {
                            const percentUsed = ((used / quota) * 100).toFixed(2);
                            const quotaInfo = document.getElementById('pf-quota-info');

                            if (quotaInfo) {
                                const percentColor = percentUsed > 80 ? '#FF5252' : '#4CAF50';
                    quotaInfo.innerHTML = `
                        <div class="mcs-pf-quota-container">
                            <div class="mcs-pf-quota-title">Browser Storage Quota</div>
                            <div class="mcs-pf-quota-details">
                                <div>Used: ${this.pf_formatBytes(used)}</div>
                                <div>Quota: ${this.pf_formatBytes(quota)}</div>
                                <div style="color: ${percentColor};">${percentUsed}% used</div>
                            </div>
                        </div>
                                `;
                            }
                        }
                    });
                }

                html += '<div id="pf-quota-info"></div>';

                content.innerHTML = html;

                const toggleHeaders = content.querySelectorAll('.pf-toggle-header');
                toggleHeaders.forEach(header => {
                    header.addEventListener('click', () => {
                        const detailsId = header.getAttribute('data-details-id');
                        const containerId = header.getAttribute('data-container-id');
                        this.pf_toggleDetails(detailsId, containerId);
                    });
                });

                const deleteButtons = content.querySelectorAll('.pf-delete-item');
                deleteButtons.forEach(button => {
                    button.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const key = button.getAttribute('data-key');
                        this.pf_deleteLocalStorageItem(key);
                    });
                });

                this.pf_updateCpuDisplay();
                this.pf_updateStorageIODisplay();
            }

            pf_deleteLocalStorageItem(key) {
                const isActive = this.pf_isKeyActive(key);
                const warningMsg = isActive
                    ? `⚠️ WARNING: "${key}" is ACTIVELY USED by MCS.\n\nDeleting this will likely break functionality!\n\nAre you SURE you want to delete it?`
                    : `Delete localStorage item "${key}"?`;

                if (confirm(warningMsg)) {
                    try {
                        localStorage.removeItem(key);
                        this.pf_updateStorageData();
                    } catch (e) {
                        console.error(`[PFormance] Error deleting localStorage item:`, e);
                        alert(`Error deleting item: ${e.message}`);
                    }
                }
            }

            pf_toggleDetails(detailsId, containerId) {
                const details = document.getElementById(detailsId);
                const toggle = document.getElementById(`${containerId}-toggle`);

                if (details && toggle) {
                    const isCollapsed = details.style.display === 'none';
                    details.style.display = isCollapsed ? 'block' : 'none';
                    toggle.textContent = isCollapsed ? '↓' : '+';

                    const collapsedStates = this.pfStorage.get('collapsedSections') ?? {};
                    collapsedStates[containerId] = !isCollapsed;
                    this.pfStorage.set('collapsedSections', collapsedStates);

                    if (isCollapsed) {
                        this.pf_refreshSectionContent(containerId);
                    }
                }
            }

            pf_refreshSectionContent(containerId) {
                if (containerId === 'pf-cpu') {
                    this.pf_updateCpuDisplay();
                } else if (containerId === 'pf-storage-io') {
                    this.pf_updateStorageIODisplay();
                } else if (containerId.startsWith('pf-cat-')) {
                    const categoryName = containerId.replace('pf-cat-', '').replace(/-/g, ' ');
                    const categoryMap = {
                        'game data': 'Game Data',
                        'mcs global': 'MCS Global',
                        'mcs modules': 'MCS Modules',
                        'other': 'Other'
                    };
                    const category = categoryMap[categoryName];
                    if (category) {
                        this.pf_updateCategoryContent(containerId, category);
                    }
                }
            }

            pf_updateCategoryContent(containerId, categoryName) {
                const detailsId = `${containerId}-details`;
                const details = document.getElementById(detailsId);
                if (!details) return;

                const categories = this.pf_categorizeKeys();
                const items = categories[categoryName] ?? [];
                const total = items.reduce((sum, item) => sum + item.size, 0);

                const sortedItems = categoryName === 'MCS Modules'
                    ? items.sort((a, b) => a.key.localeCompare(b.key))
                    : items.sort((a, b) => b.size - a.size);

                let html = '';
                sortedItems.forEach(item => {
                    const itemPercentage = total > 0 ? ((item.size / total) * 100).toFixed(1) : '0.0';
                    const keyClass = item.isActive ? 'mcs-pf-item-key-active' : 'mcs-pf-item-key-inactive';
                    const keyTitle = item.isActive ? `${item.key} (used by MCS)` : item.key;

                    html += '<div class="mcs-pf-item-row">';
                    html += `<span class="${keyClass}" title="${keyTitle}">${item.key}</span>`;
                    html += `<span class="mcs-pf-item-size">${this.pf_formatBytes(item.size)} (${itemPercentage}%)</span>`;
                    html += `<button class="pf-delete-item mcs-pf-delete-btn" data-key="${item.key}" title="Delete ${item.key}">×</button>`;
                    html += '</div>';
                });

                details.innerHTML = html;

                const deleteButtons = details.querySelectorAll('.pf-delete-item');
                deleteButtons.forEach(button => {
                    button.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const key = button.getAttribute('data-key');
                        this.pf_deleteLocalStorageItem(key);
                    });
                });

                const header = details.previousElementSibling;
                if (header) {
                    const categories2 = this.pf_categorizeKeys();
                    let grandTotal = 0;
                    for (const [_, catItems] of Object.entries(categories2)) {
                        grandTotal += catItems.reduce((sum, item) => sum + item.size, 0);
                    }
                    const percentage = grandTotal > 0 ? ((total / grandTotal) * 100).toFixed(1) : '0.0';

                    const totalDiv = header.querySelector('.mcs-pf-category-total');
                    const percentDiv = header.querySelector('.mcs-pf-category-percent');
                    if (totalDiv) totalDiv.textContent = this.pf_formatBytes(total);
                    if (percentDiv) percentDiv.textContent = `${percentage}%`;

                    const countSpan = header.querySelector('.mcs-pf-item-count');
                    if (countSpan) {
                        countSpan.textContent = `(${items.length})`;
                    }
                }
            }

            pf_updateCpuDisplay() {
                const cpuSection = document.getElementById('pf-cpu-section');
                if (!cpuSection) return;

                let html = '';

                if (typeof PerformanceMonitor !== 'undefined') {
                    const perfStats = PerformanceMonitor.getAllStats();
                    const sortedPerf = Object.entries(perfStats)
                        .filter(([_, stats]) => stats.cpuPercent > 0 || stats.callCount > 0)
                        .sort((a, b) => b[1].cpuPercent - a[1].cpuPercent);

                    if (sortedPerf.length > 0) {
                        sortedPerf.forEach(([moduleName, stats]) => {
                            const cpuColor = stats.cpuPercent > 10 ? '#FF5252' :
                                           stats.cpuPercent > 5 ? '#FFA500' :
                                           stats.cpuPercent > 1 ? '#FFEB3B' : '#4CAF50';

                            html += '<div class="mcs-pf-stat-row">';
                            html += `<span class="mcs-pf-stat-label">${moduleName}</span>`;
                            html += `<div style="text-align: right;">`;
                            html += `<span class="mcs-pf-cpu-percent" style="color: ${cpuColor};">${stats.cpuPercent.toFixed(2)}%</span>`;
                            html += `<span class="mcs-pf-stat-meta">${stats.callCount} calls</span>`;
                            html += `<span class="mcs-pf-stat-meta">${stats.avgTime.toFixed(2)}ms avg</span>`;
                            html += `</div>`;
                            html += '</div>';
                        });
                    } else {
                        html += '<div class="mcs-pf-no-activity">No CPU activity</div>';
                    }
                }

                cpuSection.innerHTML = html;
            }

            pf_updateStorageIODisplay() {
                const storageIOSection = document.getElementById('pf-storage-io-section');
                if (!storageIOSection) return;

                let html = '';

                if (typeof StorageMonitor !== 'undefined') {
                    const ioStats = StorageMonitor.getAllStats();
                    const sortedIO = Object.entries(ioStats)
                        .filter(([_, stats]) => stats.reads > 0 || stats.writes > 0)
                        .sort((a, b) => (b[1].reads + b[1].writes) - (a[1].reads + a[1].writes));

                    if (sortedIO.length > 0) {
                        sortedIO.forEach(([key, stats]) => {
                            const totalOps = stats.reads + stats.writes;
                            const opsColor = totalOps > 50 ? '#FF5252' :
                                           totalOps > 20 ? '#FFA500' :
                                           totalOps > 5 ? '#FFEB3B' : '#4CAF50';

                            const displayKey = key.length > 35 ? key.substring(0, 32) + '...' : key;

                            html += '<div class="mcs-pf-stat-row">';
                            html += `<span class="mcs-pf-stat-label" title="${key}">${displayKey}</span>`;
                            html += `<div style="text-align: right;">`;
                            html += `<span class="mcs-pf-ops-count" style="color: ${opsColor};">${totalOps} ops</span>`;
                            html += `<span class="mcs-pf-stat-meta">${stats.reads}R</span>`;
                            html += `<span class="mcs-pf-stat-meta" style="margin-left: 4px;">${stats.writes}W</span>`;
                            html += `</div>`;
                            html += '</div>';
                        });
                    } else {
                        html += '<div class="mcs-pf-no-activity">No storage activity</div>';
                    }
                }

                storageIOSection.innerHTML = html;
            }

            destroyPFormance() {
                if (this._pfDragMove) {
                    document.removeEventListener('mousemove', this._pfDragMove);
                    document.removeEventListener('mouseup', this._pfDragUp);
                    this._pfDragMove = null;
                    this._pfDragUp = null;
                }
                PerformanceMonitor.enabled = false;
                StorageMonitor.enabled = false;

                VisibilityManager.clear('pformance-cpu-update');
                if (this._pfResizeObserver) {
                    this._pfResizeObserver.disconnect();
                    this._pfResizeObserver = null;
                }
                const pane = document.getElementById('pformance-pane');
                if (pane) {
                    pane.remove();
                }
            }

// PF end

// QCharm start

            get qcStorage() {
                if (!this._qcStorage) {
                    this._qcStorage = createModuleStorage('QC');
                }
                return this._qcStorage;
            }

            qc_handleWebSocketMessage(event) {
                if (window.MCS_MODULES_DISABLED) return;
                const pane = document.getElementById('qcharm-pane');
                if (pane && pane.classList.contains('mcs-hidden')) return;
                const data = event.detail;
                if (data?.type === 'init_character_data' ||
                    data?.type === 'item_update' ||
                    data?.type === 'inventory_update' ||
                    data?.type === 'character_update') {
                    this.qc_onEquipmentChanged();
                }
            }

            qc_handleMarketDataUpdated() {
                const pane = document.getElementById('qcharm-pane');
                if (pane && pane.classList.contains('mcs-hidden')) return;
                this.qc_updateCharmData();
            }

            qc_getBaseExp(tier) {
                const baseExpValues = {
                    'trainee': 1,
                    'basic': 2,
                    'advanced': 3.5,
                    'expert': 5,
                    'master': 6.5,
                    'grandmaster': 8
                };
                return baseExpValues[tier] || 0;
            }

            qc_getEnhancementMultiplier(level) {
                const multipliers = {
                    '0': 1, '1': 1.1, '2': 1.21, '3': 1.33, '4': 1.46,
                    '5': 1.6, '6': 1.75, '7': 1.91, '8': 2.08, '9': 2.26,
                    '10': 2.45, '11': 2.67, '12': 2.92, '13': 3.2, '14': 3.51,
                    '15': 3.85, '16': 4.22, '17': 4.62, '18': 5.05, '19': 5.51,
                    '20': 6
                };
                return multipliers[level.toString()] || 1;
            }

            createQCharmPane() {
                if (document.getElementById('qcharm-pane')) return;

                if (!this.qc_sortColumn) {
                    this.qc_sortColumn = 'expPerAsk';
                    this.qc_sortDirection = 'desc';
                }

                const pane = document.createElement('div');
                pane.id = 'qcharm-pane';
                registerPanel('qcharm-pane');
                pane.className = 'mcs-pane mcs-qcharm-pane';

                const savedSize = this.qcStorage.get('size');
                let width = 500;
                let height = 400;
                if (savedSize) {
                    width = savedSize.width || 500;
                    height = savedSize.height || 400;
                }

                pane.style.width = `${width}px`;
                pane.style.height = `${height}px`;

                pane.dataset.savedHeight = height;

                const header = document.createElement('div');
                header.className = 'mcs-pane-header';

                const titleSection = document.createElement('div');
                titleSection.className = 'mcs-qcharm-title-section';

                const titleSpan = document.createElement('span');
                titleSpan.id = 'qcharm-title';
                titleSpan.className = 'mcs-qcharm-title';
                titleSpan.textContent = 'QCharm';

                titleSection.appendChild(titleSpan);

                const buttonSection = document.createElement('div');
                buttonSection.className = 'mcs-qcharm-button-section';

                const refreshBtn = document.createElement('button');
                refreshBtn.id = 'qcharm-refresh-btn';
                refreshBtn.className = 'mcs-qcharm-btn';
                refreshBtn.textContent = '↻';
                refreshBtn.title = 'Refresh charm data';

                const minimizeBtn = document.createElement('button');
                minimizeBtn.id = 'qcharm-minimize-btn';
                minimizeBtn.className = 'mcs-qcharm-btn';
                minimizeBtn.textContent = '−';

                buttonSection.appendChild(refreshBtn);
                buttonSection.appendChild(minimizeBtn);
                header.appendChild(titleSection);
                header.appendChild(buttonSection);

                const content = document.createElement('div');
                content.id = 'qcharm-content';
                content.className = 'mcs-qcharm-content';

                const guideSection = document.createElement('div');
                guideSection.className = 'mcs-qcharm-guide-section';

                const guideHeader = document.createElement('div');
                guideHeader.className = 'mcs-qcharm-guide-header';
                guideHeader.innerHTML = '<span>Charm EXP Guide</span><span class="mcs-qcharm-guide-toggle">▼</span>';

                const guideContent = document.createElement('div');
                guideContent.className = 'mcs-qcharm-guide-content';

                const baseExpRow = document.createElement('div');
                baseExpRow.className = 'mcs-qcharm-guide-row';
    baseExpRow.innerHTML = `
        <div class="mcs-qcharm-guide-item">Trainee 1%</div>
        <div class="mcs-qcharm-guide-item">Basic 2%</div>
        <div class="mcs-qcharm-guide-item">Advanced 3.5%</div>
        <div class="mcs-qcharm-guide-item">Expert 5%</div>
        <div class="mcs-qcharm-guide-item">Master 6.5%</div>
        <div class="mcs-qcharm-guide-item">Grandmaster 8%</div>
                `;

                const enhTable = document.createElement('div');
                enhTable.className = 'mcs-qcharm-guide-enh-table';
                const enhMultipliers = [
                    ['+0: 1x', '+1: 1.1x', '+2: 1.21x', '+3: 1.33x'],
                    ['+4: 1.46x', '+5: 1.6x', '+6: 1.75x', '+7: 1.91x'],
                    ['+8: 2.08x', '+9: 2.26x', '+10: 2.45x', '+11: 2.67x'],
                    ['+12: 2.92x', '+13: 3.2x', '+14: 3.51x', '+15: 3.85x'],
                    ['+16: 4.22x', '+17: 4.62x', '+18: 5.05x', '+19: 5.51x'],
                    ['+20: 6x', '', '', '']
                ];

                enhMultipliers.forEach(row => {
                    const rowDiv = document.createElement('div');
                    rowDiv.className = 'mcs-qcharm-guide-enh-row';
                    row.forEach(item => {
                        const cell = document.createElement('div');
                        cell.className = 'mcs-qcharm-guide-enh-cell';
                        cell.textContent = item;
                        rowDiv.appendChild(cell);
                    });
                    enhTable.appendChild(rowDiv);
                });

                guideContent.appendChild(baseExpRow);
                guideContent.appendChild(enhTable);
                guideSection.appendChild(guideHeader);
                guideSection.appendChild(guideContent);

                const savedGuideState = this.qcStorage.get('guide_collapsed');
                if (savedGuideState === true || savedGuideState === 'true') {
                    guideContent.classList.add('mcs-qcharm-guide-collapsed');
                    guideHeader.querySelector('.mcs-qcharm-guide-toggle').textContent = '▶';
                }

                guideHeader.addEventListener('click', () => {
                    const isCollapsed = guideContent.classList.toggle('mcs-qcharm-guide-collapsed');
                    guideHeader.querySelector('.mcs-qcharm-guide-toggle').textContent = isCollapsed ? '▶' : '▼';
                    window.lootDropsTrackerInstance.qcStorage.set('guide_collapsed', isCollapsed);
                });

                content.appendChild(guideSection);

                pane.appendChild(header);
                pane.appendChild(content);
                document.body.appendChild(pane);

                let dragStartX, dragStartY, initialLeft, initialTop;

                const onDragMove = (e) => {
                    const dx = e.clientX - dragStartX;
                    const dy = e.clientY - dragStartY;

                    let newLeft = initialLeft + dx;
                    let newTop = initialTop + dy;

                    const paneRect = pane.getBoundingClientRect();
                    const headerHeight = header.getBoundingClientRect().height;

                    const minLeft = -paneRect.width + 100;
                    const maxLeft = window.innerWidth - 100;
                    const minTop = 0;
                    const maxTop = window.innerHeight - headerHeight;

                    newLeft = Math.max(minLeft, Math.min(maxLeft, newLeft));
                    newTop = Math.max(minTop, Math.min(maxTop, newTop));

                    pane.style.left = newLeft + 'px';
                    pane.style.top = newTop + 'px';
                };

                const onDragUp = () => {
                    document.removeEventListener('mousemove', onDragMove);
                    document.removeEventListener('mouseup', onDragUp);
                    header.style.cursor = 'move';
                    const rect = pane.getBoundingClientRect();
                    window.lootDropsTrackerInstance.qcStorage.set('position', { top: rect.top, left: rect.left });
                    this.constrainPanelToBoundaries('qcharm-pane', 'mcs_QC', true);
                };

                header.addEventListener('mousedown', (e) => {
                    if (e.target.closest('button')) return;
                    dragStartX = e.clientX;
                    dragStartY = e.clientY;
                    const rect = pane.getBoundingClientRect();
                    initialLeft = rect.left;
                    initialTop = rect.top;
                    header.style.cursor = 'grabbing';
                    pane.style.left = initialLeft + 'px';
                    pane.style.right = 'auto';
                    window.lootDropsTrackerInstance._qcDragMove = onDragMove;
                    window.lootDropsTrackerInstance._qcDragUp = onDragUp;
                    document.addEventListener('mousemove', onDragMove);
                    document.addEventListener('mouseup', onDragUp);
                });

                minimizeBtn.addEventListener('click', () => {
                    const isMinimized = content.classList.contains('mcs-hidden');
                    if (isMinimized) {
                        content.classList.remove('mcs-hidden');
                        minimizeBtn.textContent = '−';
                        header.classList.remove('mcs-pane-header-minimized');
                        pane.classList.remove('mcs-qcharm-pane-minimized');
                        const savedHeight = pane.dataset.savedHeight || height;
                        pane.style.height = savedHeight + 'px';
                        window.lootDropsTrackerInstance.qcStorage.set('minimized', false);
                    } else {
                        const currentRect = pane.getBoundingClientRect();
                        pane.dataset.savedHeight = currentRect.height;

                        content.classList.add('mcs-hidden');
                        minimizeBtn.textContent = '+';
                        header.classList.add('mcs-pane-header-minimized');
                        pane.classList.add('mcs-qcharm-pane-minimized');

                        const headerHeight = header.getBoundingClientRect().height;
                        pane.style.height = headerHeight + 'px';
                        window.lootDropsTrackerInstance.qcStorage.set('minimized', true);
                    }
                });

                refreshBtn.addEventListener('click', () => {
                    this.qc_updateCharmData();
                });

                pane._qcPositionInitialized = false;

                const restoreSavedPosition = () => {
                    const savedPosition = window.lootDropsTrackerInstance.qcStorage.get('position');
                    if (savedPosition && (savedPosition.top !== undefined || savedPosition.left !== undefined || savedPosition.right !== undefined)) {
                        const hasValidTop = savedPosition.top !== undefined && savedPosition.top > 0;
                        const hasValidLeft = savedPosition.left !== undefined && savedPosition.left > 0;
                        const hasValidRight = savedPosition.right !== undefined && savedPosition.right > 0;

                        if (hasValidTop || hasValidLeft || hasValidRight) {
                            if (hasValidTop) {
                                pane.style.top = savedPosition.top + 'px';
                            }
                            if (hasValidLeft) {
                                pane.style.left = savedPosition.left + 'px';
                                pane.style.right = 'auto';
                            } else if (hasValidRight) {
                                pane.style.right = savedPosition.right + 'px';
                            }
                            window.lootDropsTrackerInstance.constrainPanelToBoundaries('qcharm-pane', 'mcs_QC', true);
                        }
                    }
                    pane._qcPositionInitialized = true;
                };

                const savedMinimized = this.qcStorage.get('minimized');
                if (savedMinimized === true || savedMinimized === 'true') {
                    content.classList.add('mcs-hidden');
                    minimizeBtn.textContent = '+';
                    header.classList.add('mcs-pane-header-minimized');
                    pane.classList.add('mcs-qcharm-pane-minimized');
                    const headerHeight = header.getBoundingClientRect().height;
                    pane.style.height = headerHeight + 'px';
                }

                let qcResizeTimer = null;
                this._qcResizeObserver = new ResizeObserver(() => {
                    const rect = pane.getBoundingClientRect();
                    const isMinimized = content.classList.contains('mcs-hidden');

                    if (!isMinimized) {
                        pane.dataset.savedHeight = rect.height;
                    }

                    clearTimeout(qcResizeTimer);
                    qcResizeTimer = setTimeout(() => {
                        window.lootDropsTrackerInstance.qcStorage.set('size', {
                            width: rect.width,
                            height: isMinimized ? parseFloat(pane.dataset.savedHeight) : rect.height
                        });
                    }, 300);
                });
                this._qcResizeObserver.observe(pane);

                this._qcVisibilityObserver = new MutationObserver((mutations) => {
                    for (const mutation of mutations) {
                        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                            const isHidden = pane.classList.contains('mcs-hidden');

                            if (!isHidden) {
                                if (!pane._qcPositionInitialized) {
                                    restoreSavedPosition();
                                    window.lootDropsTrackerInstance.qc_updateCharmData();
                                }
                            } else {
                                if (pane._qcPositionInitialized) {
                                    const rect = pane.getBoundingClientRect();
                                    if (rect.top > 0 || rect.left > 0) {
                                        const position = {
                                            top: rect.top,
                                            left: rect.left
                                        };
                                        window.lootDropsTrackerInstance.qcStorage.set('position', position);
                                    }
                                }
                            }
                        }
                    }
                });
                this._qcVisibilityObserver.observe(pane, { attributes: true, attributeFilter: ['class'] });

                this._qcWsListener = this.qc_handleWebSocketMessage.bind(this);
                this._qcMarketDataListener = this.qc_handleMarketDataUpdated.bind(this);
                window.addEventListener('EquipSpyWebSocketMessage', this._qcWsListener);
                window.addEventListener('MarketDataUpdated', this._qcMarketDataListener);

                const savedStates = ToolVisibilityStorage.get();
                const shouldRun = savedStates['qcharm'] !== false;

                if (shouldRun) {
                    restoreSavedPosition();

                    this.qc_updateCharmData();
                } else {
                    pane.classList.add('mcs-hidden');
                }
            }

            qc_getEquippedCharm() {
                try {
                    const charData = CharacterDataStorage.get() || {};

                    if (!charData.characterItems) {

                        return null;
                    }

                    const charmItem = charData.characterItems.find(item =>
                        item.itemLocationHrid === '/item_locations/charm'
                    );

                    if (charmItem) {

                        return charmItem;
                    }

                    return null;
                } catch (e) {
                    console.error('[QCharm] Error getting equipped charm:', e);
                    return null;
                }
            }

            qc_getCharmFamily(charmHrid) {
                if (!charmHrid) return [];

                const match = charmHrid.match(/\/items\/(trainee|basic|advanced|expert|master|grandmaster)_(.+?)_charm/i);
                if (!match) {

                    return [];
                }

                const baseType = match[2];

                const tiers = ['trainee', 'basic', 'advanced', 'expert', 'master', 'grandmaster'];

                const family = tiers.map(tier => `/items/${tier}_${baseType}_charm`);
                return family;
            }

            qc_getStoredCharmData() {
                return this.qcStorage.get('charms', {});
            }

            qc_saveCharmData(charmData) {
                this.qcStorage.set('charms', charmData);
            }

                qc_updateCharmData() {
                    const equippedCharm = this.qc_getEquippedCharm();
                    if (!equippedCharm) {
                        this.qc_renderCharmTable([]);
                        return;
                    }
                    const charmFamily = this.qc_getCharmFamily(equippedCharm.itemHrid);
                    const storedData = this.qc_getStoredCharmData();
                    const marketData = window.lootDropsTrackerInstance?.spyMarketData ?? {};
                    const now = Date.now();

                    charmFamily.forEach(charmHrid => {
                        if (!storedData[charmHrid]) {
                            storedData[charmHrid] = {};
                        }
                        const isTrainee = charmHrid.includes('trainee');

                        if (isTrainee) {

                            storedData[charmHrid].askPrice = 250000;
                            storedData[charmHrid].lastSeen = now;

                        } else {

                            if (marketData[charmHrid]) {

                                if (!storedData[charmHrid].enhancements) {
                                    storedData[charmHrid].enhancements = {};
                                }

                                let foundCount = 0;

                                for (let enhLevel = 0; enhLevel <= 20; enhLevel++) {
                                    const enhKey = enhLevel.toString();
                                if (marketData[charmHrid][enhKey]) {
                                    const askPrice = marketData[charmHrid][enhKey].a ?? 0;
                                    if (askPrice > 0) {
                                        storedData[charmHrid].enhancements[enhKey] = {
                                            askPrice: askPrice,
                                            lastSeen: now
                                        };
                                        foundCount++;
                                    }
                                }
                            }

                        } else {

                        }
                    }
                });

                this.qc_saveCharmData(storedData);
                this.qc_renderCharmTable(charmFamily, equippedCharm.itemHrid, storedData);
            }

            qc_onEquipmentChanged() {
                this.qc_updateCharmData();
            }

            qc_getCharmDisplayName(charmHrid) {

                const match = charmHrid.match(/\/items\/(trainee|basic|advanced|expert|master|grandmaster)_(.+?)_charm/i);
                if (!match) return charmHrid;

                const tier = match[1].charAt(0).toUpperCase() + match[1].slice(1).toLowerCase();
                const baseName = match[2].split('_').map(word =>
                    word.charAt(0).toUpperCase() + word.slice(1)
                ).join(' ');

                return `${baseName} (${tier})`;
            }

            qc_calculateCharmExp(charmHrid, enhancementLevel = 0) {

                const match = charmHrid.match(/\/items\/(trainee|basic|advanced|expert|master|grandmaster)_/i);
                if (!match) return null;

                const tier = match[1].toLowerCase();
                const baseExp = this.qc_getBaseExp(tier);
                if (!baseExp) return null;

                const multiplier = this.qc_getEnhancementMultiplier(enhancementLevel);
                return baseExp * multiplier;
            }

            qc_getCharmExpPercent(charmHrid, enhancementLevel = 0) {
                const exp = this.qc_calculateCharmExp(charmHrid, enhancementLevel);
                return exp !== null ? exp.toFixed(2) + '%' : 'N/A';
            }

            qc_getQualityTier(charmHrid) {
                const tiers = ['trainee', 'basic', 'advanced', 'expert', 'master', 'grandmaster'];
                const match = charmHrid.match(/\/items\/(trainee|basic|advanced|expert|master|grandmaster)_/i);
                if (!match) return 0;
                return tiers.indexOf(match[1].toLowerCase());
            }

            qc_sortCharmRows(rows) {
                const column = this.qc_sortColumn;
                const direction = this.qc_sortDirection === 'asc' ? 1 : -1;

                return rows.sort((a, b) => {
                    let valA, valB;

                    switch (column) {
                        case 'name':

                            valA = a.tier * 100 + (a.enhLevel !== null ? a.enhLevel : -1);
                            valB = b.tier * 100 + (b.enhLevel !== null ? b.enhLevel : -1);
                            break;
                        case 'expPercent':
                            valA = a.expPercent;
                            valB = b.expPercent;
                            break;
                        case 'askPrice':
                            valA = a.askPrice;
                            valB = b.askPrice;
                            break;
                        case 'expPerAsk':
                            valA = a.expPerAsk;
                            valB = b.expPerAsk;
                            break;
                    }

                    if (valA === valB) {

                        const tierDiff = a.tier - b.tier;
                        if (tierDiff !== 0) return tierDiff;
                        return (a.enhLevel ?? 0) - (b.enhLevel ?? 0);
                    }
                    return direction * (valA < valB ? -1 : 1);
                });
            }

            qc_setSortColumn(column) {
                if (this.qc_sortColumn === column) {

                    this.qc_sortDirection = this.qc_sortDirection === 'asc' ? 'desc' : 'asc';
                } else {
                    this.qc_sortColumn = column;
                    this.qc_sortDirection = column === 'expPerAsk' ? 'desc' : 'asc';
                }
                this.qc_updateCharmData();
            }

            qc_renderCharmTable(charmFamily, equippedCharmHrid, storedData) {
                const content = document.getElementById('qcharm-content');
                if (!content) return;

                let tableContainer = content.querySelector('.mcs-qcharm-table-container');
                if (!tableContainer) {
                    tableContainer = document.createElement('div');
                    tableContainer.className = 'mcs-qcharm-table-container';
                    content.appendChild(tableContainer);
                }

                if (charmFamily.length === 0) {
                    tableContainer.innerHTML = '<div class="mcs-qcharm-empty">No charm equipped</div>';
                    return;
                }

                const equippedCharm = this.qc_getEquippedCharm();
                const equippedEnhLevel = equippedCharm?.enhancementLevel ?? 0;
                const equippedExp = this.qc_calculateCharmExp(equippedCharmHrid, equippedEnhLevel);

                const allRows = [];

                charmFamily.forEach(charmHrid => {
                    const name = this.qc_getCharmDisplayName(charmHrid);
                    const isTrainee = charmHrid.includes('trainee');
                    const tier = this.qc_getQualityTier(charmHrid);

                    if (isTrainee) {
                        const askPrice = storedData[charmHrid]?.askPrice || 250000;
                        const lastSeen = storedData[charmHrid]?.lastSeen ?? 0;
                        const exp = this.qc_calculateCharmExp(charmHrid, 0);
                        const expPercent = exp !== null ? exp : 0;
                        const expPerAsk = askPrice > 0 && exp !== null ? (exp / askPrice * 1000000) : 0;
                        const isEquipped = charmHrid === equippedCharmHrid && equippedEnhLevel === 0;

                        allRows.push({
                            charmHrid,
                            name,
                            enhLevel: null,
                            isEquipped,
                            tier,
                            expPercent,
                            expPercentStr: this.qc_getCharmExpPercent(charmHrid, 0),
                            askPrice,
                            askPriceStr: askPrice.toLocaleString(),
                            expPerAsk,
                            expPerAskStr: expPerAsk > 0 ? expPerAsk.toFixed(2) : 'N/A',
                            lastSeen
                        });
                    } else {
                        const enhancements = storedData[charmHrid]?.enhancements || {};
                        const enhLevels = Object.keys(enhancements).map(k => parseInt(k)).sort((a, b) => a - b);

                        if (enhLevels.length === 0) {
                            const exp = this.qc_calculateCharmExp(charmHrid, 0);
                            const expPercent = exp !== null ? exp : 0;
                            const isEquipped = charmHrid === equippedCharmHrid && equippedEnhLevel === 0;

                            allRows.push({
                                charmHrid,
                                name,
                                enhLevel: null,
                                isEquipped,
                                tier,
                                expPercent,
                                expPercentStr: this.qc_getCharmExpPercent(charmHrid, 0),
                                askPrice: 0,
                                askPriceStr: 'No data',
                                expPerAsk: 0,
                                expPerAskStr: 'N/A',
                                lastSeen: 0
                            });
                        } else {
                            enhLevels.forEach(enhLevel => {
                                const enhData = enhancements[enhLevel.toString()];
                                const askPrice = enhData?.askPrice ?? 0;
                                const lastSeen = enhData?.lastSeen ?? 0;
                                const exp = this.qc_calculateCharmExp(charmHrid, enhLevel);
                                const expPercent = exp !== null ? exp : 0;
                                const expPerAsk = askPrice > 0 && exp !== null ? (exp / askPrice * 1000000) : 0;
                                const isEquipped = charmHrid === equippedCharmHrid && enhLevel === equippedEnhLevel;

                                allRows.push({
                                    charmHrid,
                                    name,
                                    enhLevel,
                                    isEquipped,
                                    tier,
                                    expPercent,
                                    expPercentStr: this.qc_getCharmExpPercent(charmHrid, enhLevel),
                                    askPrice,
                                    askPriceStr: askPrice > 0 ? askPrice.toLocaleString() : 'No data',
                                    expPerAsk,
                                    expPerAskStr: expPerAsk > 0 ? expPerAsk.toFixed(2) : 'N/A',
                                    lastSeen
                                });
                            });
                        }
                    }
                });

                const sortedRows = this.qc_sortCharmRows(allRows);

                const higherOrEqualExpRows = sortedRows.filter(row => row.expPercent >= equippedExp);
                const lowerExpRows = sortedRows.filter(row => row.expPercent < equippedExp);

                const renderTableSection = (rows, sectionTitle, sectionId) => {
                    if (rows.length === 0) return '';

                    let html = '';

                    html += `<div class="mcs-qcharm-section">`;
                    html += `<div class="mcs-qcharm-section-header" data-section="${sectionId}">`;
                    html += `<span>${sectionTitle}</span>`;
                    html += `<span class="mcs-qcharm-section-toggle">▼</span>`;
                    html += `</div>`;
                    html += `<div class="mcs-qcharm-section-content" data-section="${sectionId}">`;

                    html += '<table class="mcs-qcharm-table">';

                    html += '<thead><tr>';
                    html += `<th class="mcs-qcharm-th mcs-qcharm-sortable ${this.qc_sortColumn === 'name' ? 'mcs-qcharm-sorted-' + this.qc_sortDirection : ''}" data-column="name">Name</th>`;
                    html += `<th class="mcs-qcharm-th" title="Enhancement Level">Enh</th>`;
                    html += `<th class="mcs-qcharm-th mcs-qcharm-sortable ${this.qc_sortColumn === 'expPercent' ? 'mcs-qcharm-sorted-' + this.qc_sortDirection : ''}" data-column="expPercent">Exp%</th>`;
                    html += `<th class="mcs-qcharm-th mcs-qcharm-sortable ${this.qc_sortColumn === 'askPrice' ? 'mcs-qcharm-sorted-' + this.qc_sortDirection : ''}" data-column="askPrice">Ask Price</th>`;
                    html += `<th class="mcs-qcharm-th mcs-qcharm-sortable ${this.qc_sortColumn === 'expPerAsk' ? 'mcs-qcharm-sorted-' + this.qc_sortDirection : ''}" data-column="expPerAsk">Exp/Ask</th>`;
                    html += `<th class="mcs-qcharm-th" title="Last seen in market data">Last Seen</th>`;
                    html += '</tr></thead>';

                    html += '<tbody>';
                    rows.forEach(row => {
                        const rowClass = row.isEquipped ? 'mcs-qcharm-row mcs-qcharm-equipped' : 'mcs-qcharm-row';
                        const enhDisplay = row.enhLevel !== null ? row.enhLevel : '-';

                        let lastSeenDisplay = 'Never';
                        if (row.lastSeen > 0) {
                            const date = new Date(row.lastSeen);
                            const month = (date.getMonth() + 1).toString().padStart(2, '0');
                            const day = date.getDate().toString().padStart(2, '0');
                            const hours = date.getHours().toString().padStart(2, '0');
                            const minutes = date.getMinutes().toString().padStart(2, '0');
                            const seconds = date.getSeconds().toString().padStart(2, '0');
                            lastSeenDisplay = `${month}/${day} ${hours}:${minutes}:${seconds}`;
                        }

                        html += `<tr class="${rowClass}">`;
                        html += `<td class="mcs-qcharm-td">${row.name}</td>`;
                        html += `<td class="mcs-qcharm-td">${enhDisplay}</td>`;
                        html += `<td class="mcs-qcharm-td">${row.expPercentStr}</td>`;
                        html += `<td class="mcs-qcharm-td">${row.askPriceStr}</td>`;
                        html += `<td class="mcs-qcharm-td">${row.expPerAskStr}</td>`;
                        html += `<td class="mcs-qcharm-td mcs-qcharm-last-seen">${lastSeenDisplay}</td>`;
                        html += '</tr>';
                    });
                    html += '</tbody>';

                    html += '</table>';
                    html += '</div>';
                    html += '</div>';
                    return html;
                };

                let html = '';
                html += renderTableSection(higherOrEqualExpRows, `Charm Upgrades (${equippedExp?.toFixed(2)}%)`, 'upgrades');
                html += renderTableSection(lowerExpRows, `Charm Downgrades (${equippedExp?.toFixed(2)}%)`, 'downgrades');

                tableContainer.innerHTML = html;

                tableContainer.querySelectorAll('.mcs-qcharm-sortable').forEach(th => {
                    th.addEventListener('click', (e) => {
                        const column = e.target.dataset.column;
                        this.qc_setSortColumn(column);
                    });
                });

                const savedSectionStates = this.qcStorage.get('sections_collapsed', {});

                tableContainer.querySelectorAll('.mcs-qcharm-section-header').forEach(header => {
                    const sectionId = header.dataset.section;
                    const content = tableContainer.querySelector(`.mcs-qcharm-section-content[data-section="${sectionId}"]`);
                    const toggle = header.querySelector('.mcs-qcharm-section-toggle');

                    if (savedSectionStates[sectionId] === true && content && toggle) {
                        content.classList.add('mcs-qcharm-section-collapsed');
                        toggle.textContent = '▶';
                    }

                    header.addEventListener('click', () => {
                        if (content && toggle) {
                            const isCollapsed = content.classList.toggle('mcs-qcharm-section-collapsed');
                            toggle.textContent = isCollapsed ? '▶' : '▼';

                            const states = window.lootDropsTrackerInstance.qcStorage.get('sections_collapsed', {});
                            states[sectionId] = isCollapsed;
                            window.lootDropsTrackerInstance.qcStorage.set('sections_collapsed', states);
                        }
                    });
                });
            }

            destroyQCharmPane() {
                if (this._qcDragMove) {
                    document.removeEventListener('mousemove', this._qcDragMove);
                    document.removeEventListener('mouseup', this._qcDragUp);
                    this._qcDragMove = null;
                    this._qcDragUp = null;
                }
                if (this._qcResizeObserver) { this._qcResizeObserver.disconnect(); this._qcResizeObserver = null; }
                if (this._qcVisibilityObserver) { this._qcVisibilityObserver.disconnect(); this._qcVisibilityObserver = null; }
                if (this._qcWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._qcWsListener); this._qcWsListener = null; }
                if (this._qcMarketDataListener) { window.removeEventListener('MarketDataUpdated', this._qcMarketDataListener); this._qcMarketDataListener = null; }
                const pane = document.getElementById('qcharm-pane');
                if (pane) pane.remove();
            }

// QCharm end

// OPanel start

            get opStorage() {
                    if (!this._opStorage) {
                        this._opStorage = createModuleStorage('OP');
                    }
                    return this._opStorage;
                }

                createOPanel() {
                    if (document.getElementById('opanel-pane')) return;
                    this._opanelActiveDocListeners = [];

                    if (!this.oPanelConfig) {
                        const saved = this.opStorage.get('config');
                        if (saved) {
                            try {
                                this.oPanelConfig = saved;

                                if (this.oPanelConfig.experiencePerHour === undefined) {
                                    this.oPanelConfig.experiencePerHour = false;
                                }
                                if (this.oPanelConfig.totalProfit === undefined) {
                                    this.oPanelConfig.totalProfit = false;
                                }
                                if (this.oPanelConfig.dps === undefined) {
                                    this.oPanelConfig.dps = false;
                                }
                                if (this.oPanelConfig.overExpected === undefined) {
                                    this.oPanelConfig.overExpected = false;
                                }
                                if (this.oPanelConfig.overExpectedOnlyPlayer === undefined) {
                                    this.oPanelConfig.overExpectedOnlyPlayer = false;
                                }
                                if (this.oPanelConfig.overExpectedOnlyNumbers === undefined) {
                                    this.oPanelConfig.overExpectedOnlyNumbers = false;
                                }
                                if (this.oPanelConfig.luck === undefined) {
                                    this.oPanelConfig.luck = false;
                                }
                                if (this.oPanelConfig.luckOnlyPlayer === undefined) {
                                    this.oPanelConfig.luckOnlyPlayer = false;
                                }
                                if (this.oPanelConfig.luckOnlyNumbers === undefined) {
                                    this.oPanelConfig.luckOnlyNumbers = false;
                                }
                                if (this.oPanelConfig.deathsPerHour === undefined) {
                                    this.oPanelConfig.deathsPerHour = false;
                                }
                                if (this.oPanelConfig.houses === undefined) {
                                    this.oPanelConfig.houses = false;
                                }
                                if (this.oPanelConfig.equipmentWatch === undefined) {
                                    this.oPanelConfig.equipmentWatch = false;
                                }
                                if (this.oPanelConfig.combatStatus === undefined) {
                                    this.oPanelConfig.combatStatus = true;
                                }
                                if (this.oPanelConfig.usePlayerNameRecolor === undefined) {
                                    this.oPanelConfig.usePlayerNameRecolor = false;
                                }
                                if (this.oPanelConfig.ntallyInventory === undefined) {
                                    this.oPanelConfig.ntallyInventory = false;
                                }
                                if (this.oPanelConfig.kollectionBuildScore === undefined) {
                                    this.oPanelConfig.kollectionBuildScore = false;
                                }
                                if (this.oPanelConfig.kollectionNetWorth === undefined) {
                                    this.oPanelConfig.kollectionNetWorth = false;
                                }
                                if (this.oPanelConfig.ewatchCoins === undefined) {
                                    this.oPanelConfig.ewatchCoins = false;
                                }
                                if (this.oPanelConfig.ewatchMarket === undefined) {
                                    this.oPanelConfig.ewatchMarket = false;
                                }
                                if (this.oPanelConfig.skillBooks === undefined) {
                                    this.oPanelConfig.skillBooks = false;
                                }
                                if (this.oPanelConfig.treasure === undefined) {
                                    this.oPanelConfig.treasure = false;
                                }

                                if (!this.oPanelConfig.order) {
                                    this.oPanelConfig.order = ['battleTimer', 'combatRevenue', 'consumables', 'experiencePerHour', 'totalProfit', 'dps', 'overExpected', 'luck', 'deathsPerHour', 'houses', 'equipmentWatch', 'combatStatus', 'ntallyInventory', 'kollectionBuildScore', 'kollectionNetWorth', 'ewatchCoins', 'ewatchMarket', 'skillBooks'];
                                } else {
                                    if (!this.oPanelConfig.order.includes('experiencePerHour')) {
                                        this.oPanelConfig.order.push('experiencePerHour');
                                    }
                                    if (!this.oPanelConfig.order.includes('totalProfit')) {
                                        this.oPanelConfig.order.push('totalProfit');
                                    }
                                    if (!this.oPanelConfig.order.includes('dps')) {
                                        this.oPanelConfig.order.push('dps');
                                    }
                                    if (!this.oPanelConfig.order.includes('overExpected')) {
                                        this.oPanelConfig.order.push('overExpected');
                                    }
                                    if (!this.oPanelConfig.order.includes('luck')) {
                                        this.oPanelConfig.order.push('luck');
                                    }
                                    if (!this.oPanelConfig.order.includes('deathsPerHour')) {
                                        this.oPanelConfig.order.push('deathsPerHour');
                                    }
                                    if (!this.oPanelConfig.order.includes('houses')) {
                                        this.oPanelConfig.order.push('houses');
                                    }
                                    if (!this.oPanelConfig.order.includes('equipmentWatch')) {
                                        this.oPanelConfig.order.push('equipmentWatch');
                                    }
                                    if (!this.oPanelConfig.order.includes('combatStatus')) {
                                        this.oPanelConfig.order.push('combatStatus');
                                    }
                                    if (!this.oPanelConfig.order.includes('ntallyInventory')) {
                                        this.oPanelConfig.order.push('ntallyInventory');
                                    }
                                    if (!this.oPanelConfig.order.includes('kollectionBuildScore')) {
                                        this.oPanelConfig.order.push('kollectionBuildScore');
                                    }
                                    if (!this.oPanelConfig.order.includes('kollectionNetWorth')) {
                                        this.oPanelConfig.order.push('kollectionNetWorth');
                                    }
                                    if (!this.oPanelConfig.order.includes('ewatchCoins')) {
                                        this.oPanelConfig.order.push('ewatchCoins');
                                    }
                                    if (!this.oPanelConfig.order.includes('ewatchMarket')) {
                                        this.oPanelConfig.order.push('ewatchMarket');
                                    }
                                    if (!this.oPanelConfig.order.includes('skillBooks')) {
                                        this.oPanelConfig.order.push('skillBooks');
                                    }
                                    if (!this.oPanelConfig.order.includes('treasure')) {
                                        this.oPanelConfig.order.push('treasure');
                                    }
                                }

                                if (!this.oPanelConfig.sizes) {
                                    this.oPanelConfig.sizes = {
                                        battleTimer: { width: null, height: 40 },
                                        combatRevenue: { width: null, height: 150 },
                                        consumables: { width: null, height: 80 },
                                        experiencePerHour: { width: null, height: 40 },
                                        totalProfit: { width: null, height: 40 },
                                        dps: { width: null, height: 150 },
                                        overExpected: { width: null, height: 70 },
                                        luck: { width: null, height: 70 },
                                        deathsPerHour: { width: null, height: 40 },
                                        houses: { width: null, height: 40 },
                                        equipmentWatch: { width: null, height: 80 },
                                        combatStatus: { width: null, height: 40 },
                                        ntallyInventory: { width: null, height: 40 },
                                        kollectionBuildScore: { width: null, height: 40 },
                                        kollectionNetWorth: { width: null, height: 40 },
                                        ewatchCoins: { width: null, height: 40 },
                                        ewatchMarket: { width: null, height: 40 },
                                        skillBooks: { width: null, height: 40 },
                                        treasure: { width: null, height: 40 }
                                    };
                                } else {
                                    if (!this.oPanelConfig.sizes.experiencePerHour) {
                                        this.oPanelConfig.sizes.experiencePerHour = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.totalProfit) {
                                        this.oPanelConfig.sizes.totalProfit = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.dps) {
                                        this.oPanelConfig.sizes.dps = { width: null, height: 150 };
                                    }
                                    if (!this.oPanelConfig.sizes.overExpected) {
                                        this.oPanelConfig.sizes.overExpected = { width: null, height: 70 };
                                    }
                                    if (!this.oPanelConfig.sizes.luck) {
                                        this.oPanelConfig.sizes.luck = { width: null, height: 70 };
                                    }
                                    if (!this.oPanelConfig.sizes.deathsPerHour) {
                                        this.oPanelConfig.sizes.deathsPerHour = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.houses) {
                                        this.oPanelConfig.sizes.houses = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.equipmentWatch) {
                                        this.oPanelConfig.sizes.equipmentWatch = { width: null, height: 80 };
                                    }
                                    if (!this.oPanelConfig.sizes.combatStatus) {
                                        this.oPanelConfig.sizes.combatStatus = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.ntallyInventory) {
                                        this.oPanelConfig.sizes.ntallyInventory = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.kollectionBuildScore) {
                                        this.oPanelConfig.sizes.kollectionBuildScore = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.kollectionNetWorth) {
                                        this.oPanelConfig.sizes.kollectionNetWorth = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.ewatchCoins) {
                                        this.oPanelConfig.sizes.ewatchCoins = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.ewatchMarket) {
                                        this.oPanelConfig.sizes.ewatchMarket = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.skillBooks) {
                                        this.oPanelConfig.sizes.skillBooks = { width: null, height: 40 };
                                    }
                                    if (!this.oPanelConfig.sizes.treasure) {
                                        this.oPanelConfig.sizes.treasure = { width: null, height: 40 };
                                    }
                                }

                                if (!this.oPanelConfig.positions) {
                                    this.oPanelConfig.positions = {
                                        battleTimer: { x: 0, y: 0 },
                                        combatRevenue: { x: 0, y: 0 },
                                        consumables: { x: 0, y: 0 },
                                        experiencePerHour: { x: 0, y: 0 },
                                        totalProfit: { x: 0, y: 0},
                                        dps: { x: 0, y: 0 },
                                        overExpected: { x: 0, y: 0 },
                                        luck: { x: 0, y: 0 },
                                        deathsPerHour: { x: 0, y: 0 },
                                        houses: { x: 0, y: 0 },
                                        equipmentWatch: { x: 0, y: 0 },
                                        combatStatus: { x: 0, y: 0 },
                                        ntallyInventory: { x: 0, y: 0 },
                                        kollectionBuildScore: { x: 0, y: 0 },
                                        kollectionNetWorth: { x: 0, y: 0 },
                                        ewatchCoins: { x: 0, y: 0 },
                                        ewatchMarket: { x: 0, y: 0 },
                                        skillBooks: { x: 0, y: 0 },
                                        treasure: { x: 0, y: 0 }
                                    };
                                } else {
                                    if (!this.oPanelConfig.positions.experiencePerHour) {
                                        this.oPanelConfig.positions.experiencePerHour = { x: 0, y:0 };
                                    }
                                    if (!this.oPanelConfig.positions.totalProfit) {
                                        this.oPanelConfig.positions.totalProfit = { x: 0, y:0 };
                                    }
                                    if (!this.oPanelConfig.positions.dps) {
                                        this.oPanelConfig.positions.dps = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.overExpected) {
                                        this.oPanelConfig.positions.overExpected = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.luck) {
                                        this.oPanelConfig.positions.luck = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.deathsPerHour) {
                                        this.oPanelConfig.positions.deathsPerHour = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.houses) {
                                        this.oPanelConfig.positions.houses = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.equipmentWatch) {
                                        this.oPanelConfig.positions.equipmentWatch = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.combatStatus) {
                                        this.oPanelConfig.positions.combatStatus = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.ntallyInventory) {
                                        this.oPanelConfig.positions.ntallyInventory = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.kollectionBuildScore) {
                                        this.oPanelConfig.positions.kollectionBuildScore = { x: 0, y:0 };
                                    }
                                    if (!this.oPanelConfig.positions.kollectionNetWorth) {
                                        this.oPanelConfig.positions.kollectionNetWorth = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.ewatchCoins) {
                                        this.oPanelConfig.positions.ewatchCoins = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.ewatchMarket) {
                                        this.oPanelConfig.positions.ewatchMarket = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.skillBooks) {
                                        this.oPanelConfig.positions.skillBooks = { x: 0, y: 0 };
                                    }
                                    if (!this.oPanelConfig.positions.treasure) {
                                        this.oPanelConfig.positions.treasure = { x: 0, y: 0 };
                                    }
                                }
                            } catch (e) {
                                this.oPanelConfig = {
                                    battleTimer: true,
                                    combatRevenue: true,
                                    consumables: true,
                                    experiencePerHour: true,
                                    totalProfit: true,
                                    dps: true,
                                    overExpected: true,
                                    luck: true,
                                    deathsPerHour: true,
                                    houses: true,
                                    equipmentWatch: true,
                                    combatStatus: true,
                                    ntallyInventory: true,
                                    kollectionBuildScore: true,
                                    kollectionNetWorth: true,
                                    ewatchCoins: true,
                                    ewatchMarket: true,
                                    skillBooks: true,
                                    treasure: true,
                                    order: ['battleTimer', 'combatRevenue', 'consumables', 'experiencePerHour', 'totalProfit', 'dps', 'overExpected', 'luck', 'deathsPerHour', 'houses', 'equipmentWatch', 'combatStatus', 'ntallyInventory', 'kollectionBuildScore', 'kollectionNetWorth', 'ewatchCoins', 'ewatchMarket', 'skillBooks', 'treasure'],
                                    sizes: {
                                        battleTimer: { width: 400, height: 30 },
                                        combatRevenue: { width: 400, height: 70 },
                                        consumables: { width: 400, height: 70 },
                                        experiencePerHour: { width: 400, height: 30 },
                                        totalProfit: { width: 400, height: 30 },
                                        dps: { width: 400, height: 70 },
                                        overExpected: { width: null, height: 70 },
                                        luck: { width: null, height: 70 },
                                        deathsPerHour: { width: 400, height: 30 },
                                        houses: { width: 400, height: 30 },
                                        equipmentWatch: { width: 400, height: 40 },
                                        combatStatus: { width: 400, height: 30 },
                                        ntallyInventory: { width: 400, height: 30 },
                                        kollectionBuildScore: { width: 400, height: 30 },
                                        kollectionNetWorth: { width: 400, height: 30 },
                                        ewatchCoins: { width: 400, height: 30 },
                                        ewatchMarket: { width: 400, height: 30 },
                                        skillBooks: { width: 400, height: 30 },
                                        treasure: { width: 400, height: 30 }
                                    },
                                    positions: {}
                                };
                                let currentY = 20;
                                this.oPanelConfig.order.forEach(optionKey => {
                                    this.oPanelConfig.positions[optionKey] = {
                                        x: 40,
                                        y: currentY
                                    };
                                    currentY += this.oPanelConfig.sizes[optionKey].height + 10;
                                });
                            }
                        } else {
                            this.oPanelConfig = {
                                battleTimer: true,
                                combatRevenue: true,
                                consumables: true,
                                experiencePerHour: true,
                                totalProfit: true,
                                dps: true,
                                overExpected: true,
                                luck: true,
                                deathsPerHour: true,
                                houses: true,
                                equipmentWatch: true,
                                combatStatus: true,
                                ntallyInventory: true,
                                kollectionBuildScore: true,
                                kollectionNetWorth: true,
                                ewatchCoins: true,
                                ewatchMarket: true,
                                skillBooks: true,
                                treasure: true,
                                overExpectedOnlyNumbers: true,
                                overExpectedOnlyPlayer: false,
                                luckOnlyNumbers: true,
                                luckOnlyPlayer: false,
                                usePlayerNameRecolor: true,
                                snapToGrid: true,
                                ewatchShowBar: true,
                                order: ['battleTimer', 'combatRevenue', 'consumables', 'experiencePerHour', 'totalProfit', 'dps', 'overExpected', 'luck', 'deathsPerHour', 'houses', 'equipmentWatch', 'combatStatus', 'ntallyInventory', 'kollectionBuildScore', 'kollectionNetWorth', 'ewatchCoins', 'ewatchMarket', 'skillBooks', 'treasure'],
                                firstLoad: false,
                                sizes: {
                                    battleTimer: { width: 400, height: 30 },
                                    combatRevenue: { width: 280, height: 70 },
                                    consumables: { width: 160, height: 80 },
                                    experiencePerHour: { width: 90, height: 30 },
                                    totalProfit: { width: 280, height: 40 },
                                    dps: { width: 140, height: 80 },
                                    overExpected: { width: 50, height: 60 },
                                    luck: { width: 80, height: 70 },
                                    deathsPerHour: { width: 90, height: 30 },
                                    houses: { width: 160, height: 50 },
                                    equipmentWatch: { width: 280, height: 50 },
                                    combatStatus: { width: 160, height: 30 },
                                    ntallyInventory: { width: 160, height: 30 },
                                    kollectionBuildScore: { width: 160, height: 30 },
                                    kollectionNetWorth: { width: 160, height: 30 },
                                    ewatchCoins: { width: 160, height: 30 },
                                    ewatchMarket: { width: 160, height: 30 },
                                    skillBooks: { width: 160, height: 30 },
                                    treasure: { width: 160, height: 30 }
                                },
                                positions: {
                                    battleTimer: { x: 10, y: 10 },
                                    combatRevenue: { x: 10, y: 50 },
                                    consumables: { x: 310, y: 90 },
                                    experiencePerHour: { x: 150, y: 10 },
                                    totalProfit: { x: 10, y: 100 },
                                    dps: { x: 10, y: 180 },
                                    overExpected: { x: 160, y: 180 },
                                    luck: { x: 210, y: 180 },
                                    deathsPerHour: { x: 240, y: 10 },
                                    houses: { x: 310, y: 40 },
                                    equipmentWatch: { x: 10, y: 130 },
                                    combatStatus: { x: 310, y: 10 },
                                    ntallyInventory: { x: 310, y: 170 },
                                    kollectionBuildScore: { x: 10, y: 260 },
                                    kollectionNetWorth: { x: 130, y: 260 },
                                    ewatchCoins: { x: 310, y: 190 },
                                    ewatchMarket: { x: 310, y: 210 },
                                    skillBooks: { x: 310, y: 230 },
                                    treasure: { x: 310, y: 260 }
                                }
                            };
                            this.opStorage.set('is_locked', true);
                            this.opStorage.set('position', { top: 0, left: 0 });
                            this.opStorage.set('size', { width: 527, height: 296 });
                            this.opStorage.set('zoom_levels', {
                                dps: 110, overExpected: 110, luck: 110,
                                combatStatus: 100, equipmentWatch: 130, ewatchCoins: 110,
                                houses: 100, consumables: 100, deathsPerHour: 90,
                                skillBooks: 100
                            });
                        }
                    } else if (!this.oPanelConfig.order) {
                        this.oPanelConfig.order = ['battleTimer', 'combatRevenue', 'consumables', 'experiencePerHour', 'totalProfit', 'dps', 'deathsPerHour', 'houses', 'equipmentWatch', 'ntallyInventory', 'kollectionBuildScore', 'kollectionNetWorth', 'ewatchCoins', 'ewatchMarket'];
                    }

                    if (this.oPanelConfig.experiencePerHour === undefined) {
                        this.oPanelConfig.experiencePerHour = false;
                    }
                    if (this.oPanelConfig.totalProfit === undefined) {
                        this.oPanelConfig.totalProfit = false;
                    }
                    if (this.oPanelConfig.dps === undefined) {
                        this.oPanelConfig.dps = false;
                    }
                    if (this.oPanelConfig.deathsPerHour === undefined) {
                        this.oPanelConfig.deathsPerHour = false;
                    }
                    if (this.oPanelConfig.houses === undefined) {
                        this.oPanelConfig.houses = false;
                    }
                    if (this.oPanelConfig.equipmentWatch === undefined) {
                        this.oPanelConfig.equipmentWatch = false;
                    }
                    if (this.oPanelConfig.ntallyInventory === undefined) {
                        this.oPanelConfig.ntallyInventory = false;
                    }
                    if (this.oPanelConfig.kollectionBuildScore === undefined) {
                        this.oPanelConfig.kollectionBuildScore = false;
                    }
                    if (this.oPanelConfig.kollectionNetWorth === undefined) {
                        this.oPanelConfig.kollectionNetWorth = false;
                    }
                    if (this.oPanelConfig.ewatchCoins === undefined) {
                        this.oPanelConfig.ewatchCoins = false;
                    }
                    if (this.oPanelConfig.ewatchMarket === undefined) {
                        this.oPanelConfig.ewatchMarket = false;
                    }
                    if (this.oPanelConfig.skillBooks === undefined) {
                        this.oPanelConfig.skillBooks = false;
                    }
                    if (this.oPanelConfig.treasure === undefined) {
                        this.oPanelConfig.treasure = false;
                    }

                    if (this.oPanelConfig.snapToGrid === undefined) {
                        this.oPanelConfig.snapToGrid = true;
                    }

                    if (this.oPanelConfig.ewatchShowBar === undefined) {
                        this.oPanelConfig.ewatchShowBar = true;
                    }

                    if (!this.oPanelConfig.sizes) {
                        this.oPanelConfig.sizes = {
                            battleTimer: { width: null, height: 40 },
                            combatRevenue: { width: null, height: 150 },
                            consumables: { width: null, height: 80 },
                            experiencePerHour: { width: null, height: 40 },
                            totalProfit: { width: null, height: 40 },
                            dps: { width: null, height: 150 },
                            deathsPerHour: { width: null, height: 40 },
                            houses: { width: null, height: 40 },
                            equipmentWatch: { width: null, height: 80 },
                            ntallyInventory: { width: null, height: 40 },
                            kollectionBuildScore: { width: null, height: 40 },
                            kollectionNetWorth: { width: null, height: 40 },
                            ewatchCoins: { width: null, height: 40 },
                            ewatchMarket: { width: null, height: 40 },
                            skillBooks: { width: null, height: 40 },
                            treasure: { width: null, height: 40 }
                        };
                    } else {
                        if (!this.oPanelConfig.sizes.experiencePerHour) {
                            this.oPanelConfig.sizes.experiencePerHour = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.totalProfit) {
                            this.oPanelConfig.sizes.totalProfit = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.dps) {
                            this.oPanelConfig.sizes.dps = { width: null, height: 150 };
                        }
                        if (!this.oPanelConfig.sizes.deathsPerHour) {
                            this.oPanelConfig.sizes.deathsPerHour = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.houses) {
                            this.oPanelConfig.sizes.houses = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.equipmentWatch) {
                            this.oPanelConfig.sizes.equipmentWatch = { width: null, height: 80 };
                        }
                        if (!this.oPanelConfig.sizes.ntallyInventory) {
                            this.oPanelConfig.sizes.ntallyInventory = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.kollectionBuildScore) {
                            this.oPanelConfig.sizes.kollectionBuildScore = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.kollectionNetWorth) {
                            this.oPanelConfig.sizes.kollectionNetWorth = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.ewatchCoins) {
                            this.oPanelConfig.sizes.ewatchCoins = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.ewatchMarket) {
                            this.oPanelConfig.sizes.ewatchMarket = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.skillBooks) {
                            this.oPanelConfig.sizes.skillBooks = { width: null, height: 40 };
                        }
                        if (!this.oPanelConfig.sizes.treasure) {
                            this.oPanelConfig.sizes.treasure = { width: null, height: 40 };
                        }
                    }

                    if (!this.oPanelConfig.positions) {
                        this.oPanelConfig.positions = {
                            battleTimer: { x: 0, y: 0 },
                            combatRevenue: { x: 0, y: 50 },
                            consumables: { x: 0, y: 210 },
                            experiencePerHour: { x: 0, y: 300 },
                            totalProfit: { x: 0, y: 350 },
                            dps: { x: 0, y: 400 },
                            deathsPerHour: { x: 0, y: 560 },
                            houses: { x: 0, y: 610 },
                            equipmentWatch: { x: 0, y: 660 },
                            ntallyInventory: { x: 0, y: 710 },
                            kollectionBuildScore: { x: 0, y: 760 },
                            kollectionNetWorth: { x: 0, y: 810 },
                            ewatchCoins: { x: 0, y: 860 },
                            ewatchMarket: { x: 0, y: 910 },
                            skillBooks: { x: 0, y: 960 },
                            treasure: { x: 0, y: 0 }
                        };
                    } else {
                        if (!this.oPanelConfig.positions.experiencePerHour) {
                            this.oPanelConfig.positions.experiencePerHour = { x: 0, y: 300 };
                        }
                        if (!this.oPanelConfig.positions.totalProfit) {
                            this.oPanelConfig.positions.totalProfit = { x: 0, y: 350 };
                        }
                        if (!this.oPanelConfig.positions.dps) {
                            this.oPanelConfig.positions.dps = { x: 0, y: 400 };
                        }
                        if (!this.oPanelConfig.positions.deathsPerHour) {
                            this.oPanelConfig.positions.deathsPerHour = { x: 0, y: 560 };
                        }
                        if (!this.oPanelConfig.positions.houses) {
                            this.oPanelConfig.positions.houses = { x: 0, y: 610 };
                        }
                        if (!this.oPanelConfig.positions.equipmentWatch) {
                            this.oPanelConfig.positions.equipmentWatch = { x: 0, y: 660 };
                        }
                        if (!this.oPanelConfig.positions.ntallyInventory) {
                            this.oPanelConfig.positions.ntallyInventory = { x: 0, y: 710 };
                        }
                        if (!this.oPanelConfig.positions.kollectionBuildScore) {
                            this.oPanelConfig.positions.kollectionBuildScore = { x: 0, y: 760 };
                        }
                        if (!this.oPanelConfig.positions.kollectionNetWorth) {
                            this.oPanelConfig.positions.kollectionNetWorth = { x: 0, y: 810 };
                        }
                        if (!this.oPanelConfig.positions.skillBooks) {
                            this.oPanelConfig.positions.skillBooks = { x: 0, y: 960 };
                        }
                        if (!this.oPanelConfig.positions.treasure) {
                            this.oPanelConfig.positions.treasure = { x: 0, y: 0 };
                        }
                    }

                    if (this.oPanelConfig.hasOwnProperty('option2')) {
                        this.oPanelConfig.combatRevenue = this.oPanelConfig.option2;
                        delete this.oPanelConfig.option2;
                        const idx = this.oPanelConfig.order.indexOf('option2');
                        if (idx !== -1) {
                            this.oPanelConfig.order[idx] = 'combatRevenue';
                        }
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                    }

                    if (this.oPanelConfig.hasOwnProperty('option3')) {
                        this.oPanelConfig.consumables = this.oPanelConfig.option3;
                        delete this.oPanelConfig.option3;
                        const idx = this.oPanelConfig.order.indexOf('option3');
                        if (idx !== -1) {
                            this.oPanelConfig.order[idx] = 'consumables';
                        }
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                    }

                    const pane = document.createElement('div');
                    pane.id = 'opanel-pane';
                    registerPanel('opanel-pane');
                    this.applyClass(pane, 'mcs-opanel-pane');

                    const iconsBackground = document.createElement('div');
                    iconsBackground.id = 'opanel-icons-background';
                    this.applyClass(iconsBackground, 'mcs-opanel-icons-bg');

                    const computerIcon = document.createElement('button');
                    computerIcon.id = 'opanel-computer-icon';
                    computerIcon.innerHTML = '💻';
                    this.applyClasses(computerIcon, 'mcs-opanel-icon', 'mcs-opanel-computer-icon');
                    computerIcon.onclick = (e) => {
                        e.stopPropagation();
                        this.toggleOPanelImportExport();
                    };

                    const lockIcon = document.createElement('button');
                    lockIcon.id = 'opanel-lock-icon';
                    lockIcon.innerHTML = '🔓';
                    this.applyClasses(lockIcon, 'mcs-opanel-icon', 'mcs-opanel-lock-icon');
                    lockIcon.onclick = (e) => {
                        e.stopPropagation();
                        this.toggleOPanelLock();
                    };

                    const gearIcon = document.createElement('button');
                    gearIcon.id = 'opanel-gear-icon';
                    gearIcon.innerHTML = '⚙';
                    this.applyClasses(gearIcon, 'mcs-opanel-icon', 'mcs-opanel-gear-icon');
                    gearIcon.onclick = (e) => {
                        e.stopPropagation();
                        this.toggleOPanelConfigMenu();
                    };

                    const dragHandle = document.createElement('div');
                    dragHandle.id = 'opanel-drag-handle';
                    dragHandle.innerHTML = '✥';
                    this.applyClasses(dragHandle, 'mcs-opanel-icon', 'mcs-opanel-drag-handle');

                    const configMenu = document.createElement('div');
                    configMenu.id = 'opanel-config-menu';
                    this.applyClass(configMenu, 'mcs-opanel-config-menu');

                    const closeButton = document.createElement('div');
                    closeButton.textContent = '×';
                    this.applyClass(closeButton, 'mcs-opanel-close-btn');
                    closeButton.onclick = () => {
                        configMenu.style.display = 'none';
                    };
                    configMenu.appendChild(closeButton);

                    const optionsContainer = document.createElement('div');
                    optionsContainer.id = 'opanel-options-container';
                    this.applyClass(optionsContainer, 'mcs-opanel-options-container');
                    configMenu.appendChild(optionsContainer);

                    this.oPanelConfig.order.forEach((optionKey) => {
                        const checkboxContainer = document.createElement('div');
                        this.applyClass(checkboxContainer, 'mcs-opanel-checkbox-container');

                        const checkbox = document.createElement('input');
                        checkbox.type = 'checkbox';
                        checkbox.id = `opanel-checkbox-${optionKey}`;
                        checkbox.checked = this.oPanelConfig[optionKey];
                        this.applyClass(checkbox, 'mcs-opanel-checkbox');
                        checkbox.onchange = () => {
                            this.oPanelConfig[optionKey] = checkbox.checked;
                            window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                            this.toggleOPanelOption(optionKey, checkbox.checked);
                        };

                        const label = document.createElement('label');
                        label.htmlFor = `opanel-checkbox-${optionKey}`;
                        const optionNames = {
                            battleTimer: 'Session Timer / EPH',
                            combatRevenue: 'Combat Revenue',
                            consumables: 'Consumables',
                            experiencePerHour: 'Experience/hr',
                            totalProfit: 'Total Profit',
                            dps: 'DPS',
                            overExpected: 'Over Expected %',
                            luck: 'Luck',
                            deathsPerHour: 'Deaths/hr',
                            houses: 'Houses',
                            equipmentWatch: 'Equipment Watch',
                            combatStatus: 'Combat Status',
                            usePlayerNameRecolor: 'Use Player Name Recolor',
                            ntallyInventory: 'NTally Inventory',
                            kollectionBuildScore: 'Build Score',
                            kollectionNetWorth: 'Net Worth',
                            ewatchCoins: 'EWatch Coins',
                            ewatchMarket: 'EWatch Market',
                            skillBooks: 'Skill Books',
                            treasure: 'Treasure'
                        };
                        label.textContent = optionNames[optionKey];
                        this.applyClass(label, 'mcs-opanel-label');

                        checkboxContainer.appendChild(checkbox);
                        checkboxContainer.appendChild(label);
                        optionsContainer.appendChild(checkboxContainer);
                    });

                    const snapToggleContainer = document.createElement('div');
                    this.applyClass(snapToggleContainer, 'mcs-opanel-checkbox-container');

                    const snapCheckbox = document.createElement('input');
                    snapCheckbox.type = 'checkbox';
                    snapCheckbox.id = 'opanel-snap-to-grid-checkbox';
                    snapCheckbox.checked = this.oPanelConfig.snapToGrid !== false;
                    this.applyClass(snapCheckbox, 'mcs-opanel-checkbox');
                    snapCheckbox.onchange = () => {
                        this.oPanelConfig.snapToGrid = snapCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                    };

                    const snapLabel = document.createElement('label');
                    snapLabel.htmlFor = 'opanel-snap-to-grid-checkbox';
                    snapLabel.textContent = 'Snap to Grid';
                    this.applyClass(snapLabel, 'mcs-opanel-label');

                    snapToggleContainer.appendChild(snapCheckbox);
                    snapToggleContainer.appendChild(snapLabel);
                    optionsContainer.appendChild(snapToggleContainer);

                    const recolorToggleContainer = document.createElement('div');
                    this.applyClass(recolorToggleContainer, 'mcs-opanel-checkbox-container');

                    const recolorCheckbox = document.createElement('input');
                    recolorCheckbox.type = 'checkbox';
                    recolorCheckbox.id = 'opanel-player-name-recolor-checkbox';
                    recolorCheckbox.checked = this.oPanelConfig.usePlayerNameRecolor || false;
                    this.applyClass(recolorCheckbox, 'mcs-opanel-checkbox');
                    recolorCheckbox.onchange = () => {
                        this.oPanelConfig.usePlayerNameRecolor = recolorCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        this.updateOPanelDPS();
                        this.updateOPanelCombatRevenue();
                        this.updateOPanelOverExpected();
                        this.updateOPanelLuck();
                    };

                    const recolorLabel = document.createElement('label');
                    recolorLabel.htmlFor = 'opanel-player-name-recolor-checkbox';
                    recolorLabel.textContent = 'Use Player Name Recolor';
                    this.applyClass(recolorLabel, 'mcs-opanel-label');

                    recolorToggleContainer.appendChild(recolorCheckbox);
                    recolorToggleContainer.appendChild(recolorLabel);
                    optionsContainer.appendChild(recolorToggleContainer);

                    const onlyPlayerContainer = document.createElement('div');
                    this.applyClass(onlyPlayerContainer, 'mcs-opanel-checkbox-container');

                    const onlyPlayerCheckbox = document.createElement('input');
                    onlyPlayerCheckbox.type = 'checkbox';
                    onlyPlayerCheckbox.id = 'opanel-expected-only-player-checkbox';
                    onlyPlayerCheckbox.checked = this.oPanelConfig.overExpectedOnlyPlayer || false;
                    this.applyClass(onlyPlayerCheckbox, 'mcs-opanel-checkbox');
                    onlyPlayerCheckbox.onchange = () => {
                        this.oPanelConfig.overExpectedOnlyPlayer = onlyPlayerCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        this.updateOPanelOverExpected();
                    };

                    const onlyPlayerLabel = document.createElement('label');
                    onlyPlayerLabel.htmlFor = 'opanel-expected-only-player-checkbox';
                    onlyPlayerLabel.textContent = 'Expected: Only Player';
                    this.applyClass(onlyPlayerLabel, 'mcs-opanel-label');

                    onlyPlayerContainer.appendChild(onlyPlayerCheckbox);
                    onlyPlayerContainer.appendChild(onlyPlayerLabel);
                    optionsContainer.appendChild(onlyPlayerContainer);

                    const onlyNumbersContainer = document.createElement('div');
                    this.applyClass(onlyNumbersContainer, 'mcs-opanel-checkbox-container');

                    const onlyNumbersCheckbox = document.createElement('input');
                    onlyNumbersCheckbox.type = 'checkbox';
                    onlyNumbersCheckbox.id = 'opanel-expected-only-numbers-checkbox';
                    onlyNumbersCheckbox.checked = this.oPanelConfig.overExpectedOnlyNumbers || false;
                    this.applyClass(onlyNumbersCheckbox, 'mcs-opanel-checkbox');
                    onlyNumbersCheckbox.onchange = () => {
                        this.oPanelConfig.overExpectedOnlyNumbers = onlyNumbersCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        this.updateOPanelOverExpected();
                    };

                    const onlyNumbersLabel = document.createElement('label');
                    onlyNumbersLabel.htmlFor = 'opanel-expected-only-numbers-checkbox';
                    onlyNumbersLabel.textContent = 'Expected: Only Numbers';
                    this.applyClass(onlyNumbersLabel, 'mcs-opanel-label');

                    onlyNumbersContainer.appendChild(onlyNumbersCheckbox);
                    onlyNumbersContainer.appendChild(onlyNumbersLabel);
                    optionsContainer.appendChild(onlyNumbersContainer);

                    const ewatchBarContainer = document.createElement('div');
                    this.applyClass(ewatchBarContainer, 'mcs-opanel-checkbox-container');

                    const ewatchBarCheckbox = document.createElement('input');
                    ewatchBarCheckbox.type = 'checkbox';
                    ewatchBarCheckbox.id = 'opanel-ewatch-bar-checkbox';
                    ewatchBarCheckbox.checked = this.oPanelConfig.ewatchShowBar !== false;
                    this.applyClass(ewatchBarCheckbox, 'mcs-opanel-checkbox');
                    ewatchBarCheckbox.onchange = () => {
                        this.oPanelConfig.ewatchShowBar = ewatchBarCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        this.updateOPanelEWatchLayout();
                    };

                    const ewatchBarLabel = document.createElement('label');
                    ewatchBarLabel.htmlFor = 'opanel-ewatch-bar-checkbox';
                    ewatchBarLabel.textContent = 'Equipment Watch: Bar';
                    this.applyClass(ewatchBarLabel, 'mcs-opanel-label');

                    ewatchBarContainer.appendChild(ewatchBarCheckbox);
                    ewatchBarContainer.appendChild(ewatchBarLabel);
                    optionsContainer.appendChild(ewatchBarContainer);

                    const luckOnlyPlayerContainer = document.createElement('div');
                    this.applyClass(luckOnlyPlayerContainer, 'mcs-opanel-checkbox-container');

                    const luckOnlyPlayerCheckbox = document.createElement('input');
                    luckOnlyPlayerCheckbox.type = 'checkbox';
                    luckOnlyPlayerCheckbox.id = 'opanel-luck-only-player-checkbox';
                    luckOnlyPlayerCheckbox.checked = this.oPanelConfig.luckOnlyPlayer || false;
                    this.applyClass(luckOnlyPlayerCheckbox, 'mcs-opanel-checkbox');
                    luckOnlyPlayerCheckbox.onchange = () => {
                        this.oPanelConfig.luckOnlyPlayer = luckOnlyPlayerCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        this.updateOPanelLuck();
                    };

                    const luckOnlyPlayerLabel = document.createElement('label');
                    luckOnlyPlayerLabel.htmlFor = 'opanel-luck-only-player-checkbox';
                    luckOnlyPlayerLabel.textContent = 'Luck: Only Player';
                    this.applyClass(luckOnlyPlayerLabel, 'mcs-opanel-label');

                    luckOnlyPlayerContainer.appendChild(luckOnlyPlayerCheckbox);
                    luckOnlyPlayerContainer.appendChild(luckOnlyPlayerLabel);
                    optionsContainer.appendChild(luckOnlyPlayerContainer);

                    const luckOnlyNumbersContainer = document.createElement('div');
                    this.applyClass(luckOnlyNumbersContainer, 'mcs-opanel-checkbox-container');

                    const luckOnlyNumbersCheckbox = document.createElement('input');
                    luckOnlyNumbersCheckbox.type = 'checkbox';
                    luckOnlyNumbersCheckbox.id = 'opanel-luck-only-numbers-checkbox';
                    luckOnlyNumbersCheckbox.checked = this.oPanelConfig.luckOnlyNumbers || false;
                    this.applyClass(luckOnlyNumbersCheckbox, 'mcs-opanel-checkbox');
                    luckOnlyNumbersCheckbox.onchange = () => {
                        this.oPanelConfig.luckOnlyNumbers = luckOnlyNumbersCheckbox.checked;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        this.updateOPanelLuck();
                    };

                    const luckOnlyNumbersLabel = document.createElement('label');
                    luckOnlyNumbersLabel.htmlFor = 'opanel-luck-only-numbers-checkbox';
                    luckOnlyNumbersLabel.textContent = 'Luck: Only Numbers';
                    this.applyClass(luckOnlyNumbersLabel, 'mcs-opanel-label');

                    luckOnlyNumbersContainer.appendChild(luckOnlyNumbersCheckbox);
                    luckOnlyNumbersContainer.appendChild(luckOnlyNumbersLabel);
                    optionsContainer.appendChild(luckOnlyNumbersContainer);

                    const autogridContainer = document.createElement('div');
                    this.applyClass(autogridContainer, 'mcs-opanel-action-btn-container');

                    const autogridButton = document.createElement('button');
                    autogridButton.textContent = 'Autogrid';
                    this.applyClass(autogridButton, 'mcs-opanel-action-btn');
                    autogridButton.onclick = () => {
                        this.autogridOPanelPanels();
                    };
                    autogridContainer.appendChild(autogridButton);
                    optionsContainer.appendChild(autogridContainer);

                    const resetContainer = document.createElement('div');
                    this.applyClass(resetContainer, 'mcs-opanel-reset-btn-container');

                    const resetButton = document.createElement('button');
                    resetButton.textContent = 'Reset';
                    this.applyClass(resetButton, 'mcs-opanel-reset-btn');
                    resetButton.onclick = () => {
                        this.resetOPanelToDefaults();
                    };
                    resetContainer.appendChild(resetButton);
                    optionsContainer.appendChild(resetContainer);

                    pane.appendChild(configMenu);

                    const content = document.createElement('div');
                    content.id = 'opanel-content';
                    this.applyClass(content, 'mcs-opanel-content');

                    const contentGrid = document.createElement('div');
                    contentGrid.id = 'opanel-content-grid';
                    this.applyClass(contentGrid, 'mcs-opanel-content-grid');
                    content.appendChild(contentGrid);

                    const gridSizeShim = document.createElement('div');
                    gridSizeShim.id = 'opanel-grid-size-shim';
                    this.applyClass(gridSizeShim, 'mcs-opanel-grid-shim');
                    contentGrid.appendChild(gridSizeShim);

                    const gridOverlay = document.createElement('div');
                    gridOverlay.id = 'opanel-grid-overlay';
                    this.applyClass(gridOverlay, 'mcs-opanel-grid-overlay');
                    contentGrid.appendChild(gridOverlay);

                    const spacerWrapper = document.createElement('div');
                    spacerWrapper.id = 'opanel-spacer-wrapper';
                    this.applyClass(spacerWrapper, 'mcs-opanel-spacer-wrapper');
                    contentGrid.appendChild(spacerWrapper);

                    for (let i = 0; i < 10; i++) {
                        const spacerBox = document.createElement('div');
                        spacerBox.className = 'opanel-spacer-box';
                        this.applyClass(spacerBox, 'mcs-opanel-spacer-box');
                        spacerBox.style.top = `${i * 100}px`;

                        const spacerContent = document.createElement('div');
                        this.applyClass(spacerContent, 'mcs-opanel-spacer-content');
                        spacerContent.textContent = '1\n2\n3\n4\n5\n6\n7\n8\n9\n10';
                        spacerBox.appendChild(spacerContent);

                        spacerWrapper.appendChild(spacerBox);
                    }

                    const heightForcer = document.createElement('div');
                    heightForcer.id = 'opanel-height-forcer';
                    this.applyClass(heightForcer, 'mcs-opanel-height-forcer');
                    contentGrid.appendChild(heightForcer);

                    pane.appendChild(content);
                    pane.appendChild(iconsBackground);
                    pane.appendChild(computerIcon);
                    pane.appendChild(lockIcon);
                    pane.appendChild(gearIcon);
                    pane.appendChild(dragHandle);
                    document.body.appendChild(pane);

                    const corners = [
                        { name: 'nw', cursor: 'nw-resize', position: 'top: 0; left: 0;' },
                        { name: 'ne', cursor: 'ne-resize', position: 'top: 0; right: 0;' },
                        { name: 'sw', cursor: 'sw-resize', position: 'bottom: 0; left: 0;' },
                        { name: 'se', cursor: 'se-resize', position: 'bottom: 0; right: 0;' }
                    ];

                    corners.forEach(corner => {
                        const handle = document.createElement('div');
                        handle.className = `opanel-resize-handle opanel-resize-${corner.name}`;
                        handle.setAttribute('data-corner', corner.name);
                        this.applyClass(handle, 'mcs-opanel-corner-handle');
                        handle.style.cursor = corner.cursor;
                        const positions = corner.position.split(';').map(s => s.trim()).filter(s => s);
                        positions.forEach(pos => {
                            const [prop, val] = pos.split(':').map(s => s.trim());
                            handle.style[prop] = val;
                        });
                        pane.appendChild(handle);

                        this.makeOPanelCornerResizable(pane, handle, corner.name);
                    });

                    this.makeOPanelDraggable(pane, dragHandle, 'mcs_OP');

                    const savedPos = this.opStorage.get('position');
                    if (savedPos) {
                        const pos = typeof savedPos === 'string' ? JSON.parse(savedPos) : savedPos;
                        pane.style.top = pos.top + 'px';
                        pane.style.left = pos.left + 'px';
                    }

                    const savedSize = this.opStorage.get('size');
                    if (savedSize) {
                        const size = typeof savedSize === 'string' ? JSON.parse(savedSize) : savedSize;
                        pane.style.width = size.width + 'px';
                        pane.style.height = size.height + 'px';
                    }

                    const lockedVal = this.opStorage.get('is_locked');
                    this.oPanelIsLocked = lockedVal === true || lockedVal === 'true';
                    if (this.oPanelIsLocked) {
                        lockIcon.innerHTML = '🔒';
                    }

                    if (this.oPanelMainResizeObserver) {
                        this.oPanelMainResizeObserver.disconnect();
                    }
                    this.oPanelMainResizeObserver = new ResizeObserver(() => {
                        const rect = pane.getBoundingClientRect();
                        const sizeData = {
                            width: rect.width,
                            height: rect.height
                        };
                        window.lootDropsTrackerInstance.opStorage.set('size', sizeData);
                        this.updateOPanelLayout();
                        this.updateOPanelConfigMenuPosition();
                    });
                    this.oPanelMainResizeObserver.observe(pane);

                    this.updateOPanelContent();

                    this.updateOPanelConfigMenuPosition();

                    pane.addEventListener('mouseenter', () => {
                        iconsBackground.style.opacity = '1';
                        dragHandle.style.opacity = '1';
                        gearIcon.style.opacity = '1';
                        lockIcon.style.opacity = '1';
                        computerIcon.style.opacity = '1';
                    });
                    pane.addEventListener('mouseleave', () => {
                        iconsBackground.style.opacity = '0';
                        dragHandle.style.opacity = '0';
                        gearIcon.style.opacity = '0';
                        lockIcon.style.opacity = '0';
                        computerIcon.style.opacity = '0';
                    });
                }

                toggleOPanelConfigMenu() {
                    const menu = document.getElementById('opanel-config-menu');
                    const pane = document.getElementById('opanel-pane');
                    if (menu && pane) {
                        if (menu.style.display !== 'block') {
                            menu.style.display = 'block';
                            requestAnimationFrame(() => {
                                this.updateOPanelConfigMenuPosition();
                            });
                        } else {
                            menu.style.display = 'none';
                        }
                    }
                }

                toggleOPanelImportExport() {
                    let panel = document.getElementById('opanel-import-export-panel');
                    if (!panel) {
                        panel = document.createElement('div');
                        panel.id = 'opanel-import-export-panel';
                        this.applyClass(panel, 'mcs-opanel-import-export-panel');

                        const title = document.createElement('span');
                        title.textContent = 'Config:';
                        this.applyClass(title, 'mcs-opanel-ie-title');
                        panel.appendChild(title);

                        const exportBtn = document.createElement('button');
                        exportBtn.textContent = 'Export';
                        this.applyClass(exportBtn, 'mcs-opanel-ie-btn');
                        exportBtn.onclick = () => this.exportOPanelConfig();
                        panel.appendChild(exportBtn);

                        const importBtn = document.createElement('button');
                        importBtn.textContent = 'Import';
                        this.applyClass(importBtn, 'mcs-opanel-ie-btn');
                        importBtn.onclick = () => this.importOPanelConfig();
                        panel.appendChild(importBtn);

                        document.body.appendChild(panel);
                    }

                    if (panel.style.display !== 'flex') {
                        panel.style.display = 'flex';
                        const pane = document.getElementById('opanel-pane');
                        if (pane) {
                            const paneRect = pane.getBoundingClientRect();
                            panel.style.left = paneRect.left + 'px';
                            panel.style.width = paneRect.width + 'px';
                            requestAnimationFrame(() => {
                                panel.style.top = (paneRect.top - panel.offsetHeight - 4) + 'px';
                            });
                        }
                    } else {
                        panel.style.display = 'none';
                    }
                }

                exportOPanelConfig() {
                    const exportData = {
                        config: this.oPanelConfig,
                        is_locked: this.oPanelIsLocked || false,
                        position: this.opStorage.get('position') || { top: 0, left: 0 },
                        size: this.opStorage.get('size') || { width: 527, height: 296 },
                        zoom_levels: this.oPanelZoomLevels || this.opStorage.get('zoom_levels') || {}
                    };

                    const json = JSON.stringify(exportData, null, 2);
                    const blob = new Blob([json], { type: 'application/json' });
                    const url = URL.createObjectURL(blob);

                    const playerName = (CharacterDataStorage.getCurrentCharacterName() || 'unknown').replace(/\s+/g, '-');
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = `${playerName}-opanel-config.json`;
                    a.click();
                    URL.revokeObjectURL(url);
                }

                importOPanelConfig() {
                    const input = document.createElement('input');
                    input.type = 'file';
                    input.accept = '.json';
                    input.onchange = (e) => {
                        const file = e.target.files[0];
                        if (!file) return;

                        const reader = new FileReader();
                        reader.onload = (evt) => {
                            try {
                                const importData = JSON.parse(evt.target.result);

                                if (!importData.config || !importData.config.order) {
                                    alert('Invalid OPanel configuration file.');
                                    return;
                                }

                                if (!confirm('This will overwrite your current OPanel configuration. Continue?')) {
                                    return;
                                }

                                this.oPanelConfig = importData.config;
                                this.opStorage.set('config', this.oPanelConfig);

                                if (importData.is_locked !== undefined) {
                                    this.oPanelIsLocked = importData.is_locked;
                                    this.opStorage.set('is_locked', this.oPanelIsLocked);
                                    const lockIcon = document.getElementById('opanel-lock-icon');
                                    if (lockIcon) {
                                        lockIcon.innerHTML = this.oPanelIsLocked ? '🔒' : '🔓';
                                    }
                                }

                                if (importData.position) {
                                    this.opStorage.set('position', importData.position);
                                    const pane = document.getElementById('opanel-pane');
                                    if (pane) {
                                        pane.style.top = importData.position.top + 'px';
                                        pane.style.left = importData.position.left + 'px';
                                    }
                                }

                                if (importData.size) {
                                    this.opStorage.set('size', importData.size);
                                    const pane = document.getElementById('opanel-pane');
                                    if (pane) {
                                        pane.style.width = importData.size.width + 'px';
                                        pane.style.height = importData.size.height + 'px';
                                    }
                                }

                                if (importData.zoom_levels) {
                                    this.oPanelZoomLevels = importData.zoom_levels;
                                    this.opStorage.set('zoom_levels', this.oPanelZoomLevels);
                                }

                                this.updateOPanelContent(true);

                                const panel = document.getElementById('opanel-import-export-panel');
                                if (panel) panel.style.display = 'none';

                            } catch (err) {
                                alert('Failed to parse configuration file: ' + err.message);
                            }
                        };
                        reader.readAsText(file);
                    };
                    input.click();
                }

                updateOPanelConfigMenuPosition() {
                    const menu = document.getElementById('opanel-config-menu');
                    const pane = document.getElementById('opanel-pane');
                    if (menu && pane) {
                        void pane.offsetHeight;

                        const paneRect = pane.getBoundingClientRect();

                        const originalDisplay = menu.style.display;
                        menu.style.display = 'block';
                        menu.style.visibility = 'hidden';
                        const menuHeight = menu.offsetHeight;
                        menu.style.visibility = 'visible';
                        menu.style.display = originalDisplay;

                        menu.style.left = paneRect.left + 'px';
                        menu.style.top = (paneRect.top - menuHeight - 4) + 'px';
                        menu.style.width = paneRect.width + 'px';
                        menu.style.boxSizing = 'border-box';
                    }
                }

                toggleOPanelLock() {
                    if (this.oPanelIsLocked === undefined) {
                        const lockedVal = this.opStorage.get('is_locked');
                        this.oPanelIsLocked = lockedVal === true || lockedVal === 'true';
                    }

                    this.oPanelIsLocked = !this.oPanelIsLocked;
                    this.opStorage.set('is_locked', this.oPanelIsLocked);

                    const lockIcon = document.getElementById('opanel-lock-icon');
                    if (lockIcon) {
                        lockIcon.innerHTML = this.oPanelIsLocked ? '🔒' : '🔓';
                    }

                    const contentGrid = document.getElementById('opanel-content-grid');
                    if (contentGrid) {
                        const boxes = contentGrid.querySelectorAll('.opanel-option-box');
                        boxes.forEach(box => {
                            box.style.cursor = this.oPanelIsLocked ? 'default' : 'move';

                            const resizeHandle = box.querySelector('.opanel-box-resize-handle');
                            if (resizeHandle) {
                                resizeHandle.style.display = this.oPanelIsLocked ? 'none' : 'block';
                            }

                            const zoomControls = box.querySelector('.opanel-zoom-controls');
                            if (zoomControls) {
                                zoomControls.style.pointerEvents = this.oPanelIsLocked ? 'none' : 'auto';
                            }
                        });
                    }
                }

                adjustOPanelZoom(optionKey, delta) {
                    if (!this.oPanelZoomLevels) {
                        const saved = this.opStorage.get('zoom_levels');
                        this.oPanelZoomLevels = saved ?? {};
                    }

                    const currentZoom = this.oPanelZoomLevels[optionKey] || 100;

                    const newZoom = Math.max(50, Math.min(200, currentZoom + (delta * 10)));

                    this.oPanelZoomLevels[optionKey] = newZoom;
                    this.opStorage.set('zoom_levels', this.oPanelZoomLevels);

                    const displayIdMap = {
                        'battleTimer': 'opanel-battle-timer',
                        'combatRevenue': 'opanel-combat-revenue',
                        'consumables': 'opanel-consumables',
                        'experiencePerHour': 'opanel-experience-hr',
                        'totalProfit': 'opanel-total-profit',
                        'dps': 'opanel-dps',
                        'overExpected': 'opanel-over-expected',
                        'luck': 'opanel-luck',
                        'deathsPerHour': 'opanel-deaths-hr',
                        'houses': 'opanel-houses',
                        'equipmentWatch': 'opanel-ewatch',
                        'combatStatus': 'opanel-combat-status',
                        'ntallyInventory': 'opanel-ntally-inventory',
                        'kollectionBuildScore': 'opanel-kollection-build-score',
                        'kollectionNetWorth': 'opanel-kollection-net-worth',
                        'ewatchCoins': 'opanel-ewatch-coins',
                        'ewatchMarket': 'opanel-ewatch-market',
                        'skillBooks': 'opanel-skill-books',
                        'treasure': 'opanel-treasure'
                    };

                    const displayId = displayIdMap[optionKey];
                    if (displayId) {
                        const displayElement = document.getElementById(displayId);
                        if (displayElement) {
                            const zoomPercent = newZoom / 100;
                            displayElement.style.zoom = zoomPercent;
                        }
                    }
                }

                applyOPanelZoom(optionKey, displayElement) {
                    if (!this.oPanelZoomLevels) {
                        const saved = this.opStorage.get('zoom_levels');
                        this.oPanelZoomLevels = saved ?? {};
                    }

                    const zoomLevel = this.oPanelZoomLevels[optionKey];
                    if (zoomLevel && displayElement) {
                        const zoomPercent = zoomLevel / 100;
                        displayElement.style.zoom = zoomPercent;
                    }
                }

                toggleOPanelOption(optionKey, isEnabled) {
                    const contentGrid = document.getElementById('opanel-content-grid');
                    if (!contentGrid) {
                        return;
                    }

                    if (isEnabled) {
                        this.updateOPanelContent();
                    } else {
                        const existingBox = contentGrid.querySelector(`[data-option-key="${optionKey}"]`);
                        if (existingBox) {
                            const computedStyle = window.getComputedStyle(existingBox);
                            const width = parseFloat(computedStyle.width);
                            const height = parseFloat(computedStyle.height);
                            const leftValue = parseInt(existingBox.style.left);
                            const topValue = parseInt(existingBox.style.top);
                            const x = isNaN(leftValue) ? 0 : leftValue;
                            const y = isNaN(topValue) ? 0 : topValue;

                            if (!this.oPanelConfig.sizes) {
                                this.oPanelConfig.sizes = {};
                            }
                            if (!this.oPanelConfig.sizes[optionKey]) {
                                this.oPanelConfig.sizes[optionKey] = {};
                            }
                            this.oPanelConfig.sizes[optionKey].width = width;
                            this.oPanelConfig.sizes[optionKey].height = height;

                            if (!this.oPanelConfig.positions) {
                                this.oPanelConfig.positions = {};
                            }
                            if (!this.oPanelConfig.positions[optionKey]) {
                                this.oPanelConfig.positions[optionKey] = {};
                            }
                            this.oPanelConfig.positions[optionKey].x = x;
                            this.oPanelConfig.positions[optionKey].y = y;

                            window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);

                            existingBox.remove();
                        }
                    }
                }

                updateOPanelContent(skipSaveCurrentState = false) {
                    const contentGrid = document.getElementById('opanel-content-grid');
                    if (!contentGrid) {
                        return;
                    }

                    if (this._opanelActiveDocListeners) {
                        this._opanelActiveDocListeners.forEach(l => {
                            document.removeEventListener('mousemove', l.move);
                            document.removeEventListener('mouseup', l.up);
                        });
                        this._opanelActiveDocListeners = [];
                    }

                    const existingBoxes = contentGrid.querySelectorAll('.opanel-option-box');
                    existingBoxes.forEach(box => {
                        const optionKey = box.dataset.optionKey;
                        if (optionKey && !skipSaveCurrentState) {
                            const computedStyle = window.getComputedStyle(box);
                            const width = parseFloat(computedStyle.width);
                            const height = parseFloat(computedStyle.height);

                            if (!this.oPanelConfig.sizes) {
                                this.oPanelConfig.sizes = {};
                            }
                            if (!this.oPanelConfig.sizes[optionKey]) {
                                this.oPanelConfig.sizes[optionKey] = {};
                            }
                            this.oPanelConfig.sizes[optionKey].width = width;
                            this.oPanelConfig.sizes[optionKey].height = height;

                            const leftValue = parseInt(box.style.left);
                            const topValue = parseInt(box.style.top);
                            const x = isNaN(leftValue) ? 0 : leftValue;
                            const y = isNaN(topValue) ? 0 : topValue;

                            if (!this.oPanelConfig.positions) {
                                this.oPanelConfig.positions = {};
                            }
                            if (!this.oPanelConfig.positions[optionKey]) {
                                this.oPanelConfig.positions[optionKey] = {};
                            }
                            this.oPanelConfig.positions[optionKey].x = x;
                            this.oPanelConfig.positions[optionKey].y = y;

                        }
                        box.remove();
                    });

                    window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);

                    this.oPanelConfig.order.forEach((optionKey) => {
                        if (this.oPanelConfig[optionKey] === true) {
                            const optionBox = document.createElement('div');
                            optionBox.className = 'opanel-option-box';
                            optionBox.dataset.optionKey = optionKey;

                            const savedSize = this.oPanelConfig.sizes?.[optionKey] ?? {};
                            const savedPos = this.oPanelConfig.positions?.[optionKey] ?? {};
                            const defaultSizes = {
                                battleTimer: { width: 400, height: 30 },
                                combatRevenue: { width: 400, height: 70 },
                                consumables: { width: 400, height: 70 },
                                experiencePerHour: { width: 400, height: 30 },
                                totalProfit: { width: 400, height: 30 },
                                dps: { width: 400, height: 70 },
                                overExpected: { width: 400, height: 70 },
                                deathsPerHour: { width: 400, height: 30 },
                                houses: { width: 400, height: 30 },
                                equipmentWatch: { width: 400, height: 40 }
                            };
                            const defaultPositions = {
                                battleTimer: { x: 40, y: 20 },
                                combatRevenue: { x: 40, y: 60 },
                                consumables: { x: 40, y: 140 },
                                experiencePerHour: { x: 40, y: 220 },
                                totalProfit: { x: 40, y: 260 },
                                dps: { x: 40, y: 300 },
                                overExpected: { x: 40, y: 380 },
                                deathsPerHour: { x: 40, y: 460 },
                                houses: { x: 40, y: 500 },
                                equipmentWatch: { x: 40, y: 540 }
                            };
                            const defaultSize = defaultSizes[optionKey] || { width: 400, height: 30 };
                            const width = (savedSize.width !== null && savedSize.width !== undefined) ? savedSize.width : defaultSize.width;
                            const height = (savedSize.height !== null && savedSize.height !== undefined) ? savedSize.height : defaultSize.height;

                            const defaultPos = defaultPositions[optionKey] || { x: 0, y: 0 };
                            const x = savedPos.x !== undefined ? savedPos.x : defaultPos.x;
                            const y = savedPos.y !== undefined ? savedPos.y : defaultPos.y;

                const baseStyles = `
                    position: absolute;
                    left: ${x}px;
                    top: ${y}px;
                    width: ${width}px;
                    height: ${height}px;
                    min-width: 50px;
                    min-height: 30px;
                    background: transparent;
                    box-sizing: border-box;
                    resize: none;
                    overflow: hidden;
                    cursor: move;
                    border: 1px solid transparent;
                    border-top: 1px solid #4a4a4a;
                    z-index: 1;
                    display: block;
                    visibility: visible;
                    transition: background 0.2s, border-color 0.2s;
                            `;

                            if (optionKey === 'battleTimer') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const timerWrapper = document.createElement('div');
                                this.applyClass(timerWrapper, 'mcs-opanel-widget-wrapper');

                                const timerDisplay = document.createElement('div');
                                timerDisplay.id = 'opanel-battle-timer';
                                this.applyClass(timerDisplay, 'mcs-opanel-timer-display');
                                timerDisplay.textContent = '--:--:--';
                                timerWrapper.appendChild(timerDisplay);
                                optionBox.appendChild(timerWrapper);
                                this.applyOPanelZoom('battleTimer', timerDisplay);
                            } else if (optionKey === 'combatRevenue') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const revenueWrapper = document.createElement('div');
                                this.applyClass(revenueWrapper, 'mcs-opanel-widget-wrapper');

                                const revenueDisplay = document.createElement('div');
                                revenueDisplay.id = 'opanel-combat-revenue';
                                this.applyClass(revenueDisplay, 'mcs-opanel-revenue-display');
                                revenueDisplay.innerHTML = '<div style="text-align: center; color: #888;">--</div>';
                                revenueWrapper.appendChild(revenueDisplay);
                                optionBox.appendChild(revenueWrapper);
                                this.applyOPanelZoom('combatRevenue', revenueDisplay);
                            } else if (optionKey === 'consumables') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const consumablesWrapper = document.createElement('div');
                                this.applyClass(consumablesWrapper, 'mcs-opanel-widget-wrapper');

                                const consumablesDisplay = document.createElement('div');
                                consumablesDisplay.id = 'opanel-consumables';
                                this.applyClass(consumablesDisplay, 'mcs-opanel-consumables-display');
                                consumablesDisplay.innerHTML = '<div style="text-align: center; color: #888;">Loading...</div>';
                                consumablesWrapper.appendChild(consumablesDisplay);
                                optionBox.appendChild(consumablesWrapper);
                                this.applyOPanelZoom('consumables', consumablesDisplay);
                            } else if (optionKey === 'experiencePerHour') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const expWrapper = document.createElement('div');
                                this.applyClass(expWrapper, 'mcs-opanel-widget-wrapper');

                                const expDisplay = document.createElement('div');
                                expDisplay.id = 'opanel-experience-hr';
                                this.applyClass(expDisplay, 'mcs-opanel-exp-display');
                                expDisplay.textContent = '0 exp/hr';
                                expWrapper.appendChild(expDisplay);
                                optionBox.appendChild(expWrapper);
                                this.applyOPanelZoom('experiencePerHour', expDisplay);
                            } else if (optionKey === 'totalProfit') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const profitWrapper = document.createElement('div');
                                this.applyClass(profitWrapper, 'mcs-opanel-widget-wrapper');

                                const profitDisplay = document.createElement('div');
                                profitDisplay.id = 'opanel-total-profit';
                                this.applyClass(profitDisplay, 'mcs-opanel-profit-display');
                                profitDisplay.innerHTML = '<span style="color: #4CAF50;">0</span><span style="color: white;">-</span><span style="color: #f44336;">0</span><span style="color: white;">=</span><span style="color: #FFD700;">0/day</span>';
                                profitWrapper.appendChild(profitDisplay);
                                optionBox.appendChild(profitWrapper);
                                this.applyOPanelZoom('totalProfit', profitDisplay);
                            } else if (optionKey === 'dps') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const dpsWrapper = document.createElement('div');
                                this.applyClass(dpsWrapper, 'mcs-opanel-widget-wrapper');

                                const dpsDisplay = document.createElement('div');
                                dpsDisplay.id = 'opanel-dps';
                                this.applyClass(dpsDisplay, 'mcs-opanel-dps-display');
                                dpsDisplay.innerHTML = '<div style="color: #888;">No DPS data</div>';
                                dpsWrapper.appendChild(dpsDisplay);
                                optionBox.appendChild(dpsWrapper);
                                this.applyOPanelZoom('dps', dpsDisplay);
                            } else if (optionKey === 'overExpected') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const overExpectedWrapper = document.createElement('div');
                                this.applyClass(overExpectedWrapper, 'mcs-opanel-widget-wrapper');

                                const overExpectedDisplay = document.createElement('div');
                                overExpectedDisplay.id = 'opanel-over-expected';
                                this.applyClass(overExpectedDisplay, 'mcs-opanel-over-expected-display');
                                overExpectedDisplay.innerHTML = '<div style="color: #888;">No Lucky data</div>';
                                overExpectedWrapper.appendChild(overExpectedDisplay);
                                optionBox.appendChild(overExpectedWrapper);
                                this.applyOPanelZoom('overExpected', overExpectedDisplay);
                            } else if (optionKey === 'luck') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const luckWrapper = document.createElement('div');
                                this.applyClass(luckWrapper, 'mcs-opanel-widget-wrapper');

                                const luckDisplay = document.createElement('div');
                                luckDisplay.id = 'opanel-luck';
                                this.applyClass(luckDisplay, 'mcs-opanel-luck-display');
                                luckDisplay.innerHTML = '<div style="color: #888;">No Lucky data</div>';
                                luckWrapper.appendChild(luckDisplay);
                                optionBox.appendChild(luckWrapper);
                                this.applyOPanelZoom('luck', luckDisplay);
                            } else if (optionKey === 'deathsPerHour') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const deathsWrapper = document.createElement('div');
                                this.applyClass(deathsWrapper, 'mcs-opanel-widget-wrapper');

                                const deathsDisplay = document.createElement('div');
                                deathsDisplay.id = 'opanel-deaths-hr';
                                this.applyClass(deathsDisplay, 'mcs-opanel-deaths-display');
                                deathsDisplay.textContent = '0.0 deaths/hr';
                                deathsWrapper.appendChild(deathsDisplay);
                                optionBox.appendChild(deathsWrapper);
                                this.applyOPanelZoom('deathsPerHour', deathsDisplay);
                            } else if (optionKey === 'houses') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const housesWrapper = document.createElement('div');
                                this.applyClass(housesWrapper, 'mcs-opanel-widget-wrapper');

                                const housesDisplay = document.createElement('div');
                                housesDisplay.id = 'opanel-houses';
                                this.applyClass(housesDisplay, 'mcs-opanel-houses-display');
                                housesDisplay.innerHTML = '<span style="white-space: nowrap; color: #4CAF50;">0 houses affordable</span><span style="padding-top:3px;white-space: nowrap; color: #888;">Cheapest: --</span>';
                                housesWrapper.appendChild(housesDisplay);
                                optionBox.appendChild(housesWrapper);
                                this.applyOPanelZoom('houses', housesDisplay);
                            } else if (optionKey === 'equipmentWatch') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const ewatchWrapper = document.createElement('div');
                                this.applyClass(ewatchWrapper, 'mcs-opanel-widget-wrapper');

                                const ewatchDisplay = document.createElement('div');
                                ewatchDisplay.id = 'opanel-ewatch';
                                this.applyClass(ewatchDisplay, 'mcs-opanel-ewatch-display');
                    ewatchDisplay.innerHTML = `
                        <div style="display: flex; flex-wrap: wrap; align-items: line-height:3px; center; gap: 4px; margin-bottom: 3px;">
                            <span id="opanel-ewatch-item" style="margin-top:2px; white-space: nowrap; color: #FFD700; font-weight: bold;">--</span>
                            <span id="opanel-ewatch-remaining" style="margin-top:2px;white-space: nowrap; color: #888;">--</span>
                            <span id="opanel-ewatch-time" style="margin-top:2px;white-space: nowrap; color: #f5a623;">--</span>
                            <span id="opanel-ewatch-percent-inline" style="margin-top:2px; font-size: 10px; color: #888; display: none;">0.0%</span>
                        </div>
                        <div id="opanel-ewatch-bar-row" style="display: flex; align-items: center; gap: 6px;">
                            <div id="opanel-ewatch-progress" style="width: 100px; background: rgba(0,0,0,0.3); border-radius: 2px; height: 4px; overflow: hidden;">
                                <div id="opanel-ewatch-progress-bar" style="width: 0%; height: 100%; background: #6495ED; transition: width 0.3s ease;"></div>
                            </div>
                            <span id="opanel-ewatch-percent" style="font-size: 10px; color: #888; min-width: 35px;">0.0%</span>
                        </div>
                                `;
                                ewatchWrapper.appendChild(ewatchDisplay);
                                optionBox.appendChild(ewatchWrapper);
                                this.applyOPanelZoom('equipmentWatch', ewatchDisplay);
                            } else if (optionKey === 'combatStatus') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const combatStatusWrapper = document.createElement('div');
                                this.applyClass(combatStatusWrapper, 'mcs-opanel-widget-wrapper');

                                const combatStatusDisplay = document.createElement('div');
                                combatStatusDisplay.id = 'opanel-combat-status';
                                this.applyClass(combatStatusDisplay, 'mcs-opanel-combat-status-display');

                                let inCombat = window.MCS_IN_COMBAT === true;
                                if (window.lootDropsTrackerInstance?.isLiveSessionActive) {
                                    inCombat = true;
                                }

                                combatStatusDisplay.innerHTML = inCombat
                                    ? '<span style="color: #4CAF50;">In Combat</span>'
                                    : '<span style="color: #f44336;">No Combat</span>';

                                combatStatusWrapper.appendChild(combatStatusDisplay);
                                optionBox.appendChild(combatStatusWrapper);
                                this.applyOPanelZoom('combatStatus', combatStatusDisplay);
                            } else if (optionKey === 'ntallyInventory') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const ntallyWrapper = document.createElement('div');
                                this.applyClass(ntallyWrapper, 'mcs-opanel-widget-wrapper');

                                const ntallyDisplay = document.createElement('div');
                                ntallyDisplay.id = 'opanel-ntally-inventory';
                                this.applyClass(ntallyDisplay, 'mcs-opanel-ntally-display');
                                ntallyDisplay.innerHTML = '<span>📦</span><span style="color: #999;">0 bid</span>';
                                ntallyWrapper.appendChild(ntallyDisplay);
                                optionBox.appendChild(ntallyWrapper);
                                this.applyOPanelZoom('ntallyInventory', ntallyDisplay);
                            } else if (optionKey === 'kollectionBuildScore') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const buildScoreWrapper = document.createElement('div');
                                this.applyClass(buildScoreWrapper, 'mcs-opanel-widget-wrapper');

                                const buildScoreDisplay = document.createElement('div');
                                buildScoreDisplay.id = 'opanel-kollection-build-score';
                                this.applyClass(buildScoreDisplay, 'mcs-opanel-build-score-display');
                                buildScoreDisplay.textContent = 'Build Score: 0.0';
                                buildScoreWrapper.appendChild(buildScoreDisplay);
                                optionBox.appendChild(buildScoreWrapper);
                                this.applyOPanelZoom('kollectionBuildScore', buildScoreDisplay);
                            } else if (optionKey === 'kollectionNetWorth') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const netWorthWrapper = document.createElement('div');
                                this.applyClass(netWorthWrapper, 'mcs-opanel-widget-wrapper');

                                const netWorthDisplay = document.createElement('div');
                                netWorthDisplay.id = 'opanel-kollection-net-worth';
                                this.applyClass(netWorthDisplay, 'mcs-opanel-net-worth-display');
                                netWorthDisplay.textContent = 'Net Worth: 0';
                                netWorthWrapper.appendChild(netWorthDisplay);
                                optionBox.appendChild(netWorthWrapper);
                                this.applyOPanelZoom('kollectionNetWorth', netWorthDisplay);
                            } else if (optionKey === 'ewatchCoins') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const coinsWrapper = document.createElement('div');
                                this.applyClass(coinsWrapper, 'mcs-opanel-widget-wrapper');

                                const coinsDisplay = document.createElement('div');
                                coinsDisplay.id = 'opanel-ewatch-coins';
                                this.applyClass(coinsDisplay, 'mcs-opanel-coins-display');
                                coinsDisplay.innerHTML = '<span style="width: 11px; height: 11px; display: inline-flex;">' + createItemIconHtml('coin', { width: '100%', height: '100%', sprite: 'items_sprite' }) + '</span><span style="color: #FFD700;">0</span>';
                                coinsWrapper.appendChild(coinsDisplay);
                                optionBox.appendChild(coinsWrapper);
                                this.applyOPanelZoom('ewatchCoins', coinsDisplay);
                            } else if (optionKey === 'ewatchMarket') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const marketWrapper = document.createElement('div');
                                this.applyClass(marketWrapper, 'mcs-opanel-widget-wrapper');

                                const marketDisplay = document.createElement('div');
                                marketDisplay.id = 'opanel-ewatch-market';
                                this.applyClass(marketDisplay, 'mcs-opanel-market-display');
                                marketDisplay.innerHTML = '<span>📈</span><span style="color: #4CAF50;">0</span>';
                                marketWrapper.appendChild(marketDisplay);
                                optionBox.appendChild(marketWrapper);
                                this.applyOPanelZoom('ewatchMarket', marketDisplay);
                            } else if (optionKey === 'skillBooks') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const skillBooksWrapper = document.createElement('div');
                                this.applyClass(skillBooksWrapper, 'mcs-opanel-widget-wrapper');

                                const skillBooksDisplay = document.createElement('div');
                                skillBooksDisplay.id = 'opanel-skill-books';
                                this.applyClass(skillBooksDisplay, 'mcs-opanel-skill-books-display');
                                skillBooksDisplay.innerHTML = '<span style="color: #999;">No skill data</span>';
                                skillBooksWrapper.appendChild(skillBooksDisplay);
                                optionBox.appendChild(skillBooksWrapper);
                                this.applyOPanelZoom('skillBooks', skillBooksDisplay);
                            } else if (optionKey === 'treasure') {
                    optionBox.style.cssText = baseStyles + `
                        padding: 4px 0 0 0;
                                `;

                                const spacer = document.createElement('div');
                                spacer.className = 'opanel-spacer';
                                this.applyClass(spacer, 'mcs-opanel-spacer');
                                optionBox.appendChild(spacer);

                                const treasureWrapper = document.createElement('div');
                                this.applyClass(treasureWrapper, 'mcs-opanel-widget-wrapper');

                                const treasureDisplay = document.createElement('div');
                                treasureDisplay.id = 'opanel-treasure';
                                this.applyClass(treasureDisplay, 'mcs-opanel-treasure-display');
                                treasureDisplay.innerHTML = `${createItemIconHtml('large_treasure_chest', { width: 18, height: 18, sprite: 'items_sprite', style: 'vertical-align: middle' })}<span>Treasure</span>`;
                                treasureWrapper.appendChild(treasureDisplay);
                                optionBox.appendChild(treasureWrapper);
                                this.applyOPanelZoom('treasure', treasureDisplay);
                            }

                            const resizeHandle = document.createElement('div');
                            resizeHandle.className = 'opanel-box-resize-handle';
                            this.applyClass(resizeHandle, 'mcs-opanel-box-resize-handle');
                            optionBox.appendChild(resizeHandle);

                            const zoomControls = document.createElement('div');
                            zoomControls.className = 'opanel-zoom-controls';
                            this.applyClass(zoomControls, 'mcs-opanel-zoom-controls');

                            const zoomOutBtn = document.createElement('button');
                            zoomOutBtn.textContent = '−';
                            this.applyClass(zoomOutBtn, 'mcs-opanel-zoom-btn');
                            zoomOutBtn.onclick = (e) => {
                                e.stopPropagation();
                                this.adjustOPanelZoom(optionKey, -1);
                            };

                            const zoomInBtn = document.createElement('button');
                            zoomInBtn.textContent = '+';
                            this.applyClass(zoomInBtn, 'mcs-opanel-zoom-btn');
                            zoomInBtn.onclick = (e) => {
                                e.stopPropagation();
                                this.adjustOPanelZoom(optionKey, 1);
                            };

                            zoomControls.appendChild(zoomOutBtn);
                            zoomControls.appendChild(zoomInBtn);
                            optionBox.appendChild(zoomControls);

                            optionBox.addEventListener('mouseenter', () => {
                                optionBox.style.background = '#2a2a2a';
                                optionBox.style.borderLeft = '1px solid #4a4a4a';
                                optionBox.style.borderRight = '1px solid #4a4a4a';
                                optionBox.style.borderBottom = '1px solid #4a4a4a';
                                resizeHandle.style.opacity = '1';
                                if (!this.oPanelIsLocked) {
                                    zoomControls.style.opacity = '1';
                                }
                            });
                            optionBox.addEventListener('mouseleave', () => {
                                optionBox.style.background = 'transparent';
                                optionBox.style.borderLeft = '1px solid transparent';
                                optionBox.style.borderRight = '1px solid transparent';
                                optionBox.style.borderBottom = '1px solid transparent';
                                resizeHandle.style.opacity = '0';
                                zoomControls.style.opacity = '0';
                            });

                            if (this.oPanelIsLocked) {
                                optionBox.style.cursor = 'default';
                                resizeHandle.style.display = 'none';
                                zoomControls.style.pointerEvents = 'none';
                            } else {
                                optionBox.style.cursor = 'move';
                                zoomControls.style.pointerEvents = 'auto';
                            }

                            this.makeOPanelBoxResizable(optionBox, resizeHandle, optionKey);

                            this.makeOPanelBoxDraggable(optionBox, optionKey);

                            optionBox.addEventListener('dblclick', (e) => {
                                e.stopPropagation();

                                const panelMapping = {
                                    'battleTimer': 'milt-loot-drops-display',
                                    'combatRevenue': 'milt-loot-drops-display',
                                    'consumables': 'consumables-pane',
                                    'experiencePerHour': 'gwhiz-pane',
                                    'totalProfit': 'hwhat-pane',
                                    'dps': 'dps-pane',
                                    'overExpected': 'lucky-panel',
                                    'luck': 'lucky-panel',
                                    'deathsPerHour': 'ihurt-pane',
                                    'houses': 'jhouse-pane',
                                    'equipmentWatch': 'equipment-spy-pane',
                                    'ntallyInventory': 'mcs_nt_pane',
                                    'kollectionBuildScore': 'kollection-pane',
                                    'kollectionNetWorth': 'kollection-pane',
                                    'ewatchCoins': 'equipment-spy-pane',
                                    'ewatchMarket': 'mcs_nt_pane',
                                    'skillBooks': 'bread-pane',
                                    'treasure': 'treasure-pane'
                                };

                                const targetPanelId = panelMapping[optionKey];
                                if (targetPanelId) {
                                    const checkbox = document.querySelector(`input[type="checkbox"][data-tool-panel="${targetPanelId}"]`);
                                    if (checkbox) {
                                        checkbox.checked = !checkbox.checked;
                                        checkbox.dispatchEvent(new Event('change', { bubbles: true }));
                                    }
                                }
                            });

                            let resizeTimeout;
                            let ignoreInitialResize = true;
                            setTimeout(() => {
                                ignoreInitialResize = false;
                            }, 2000);

                            if (!this.oPanelOptionResizeObservers) {
                                this.oPanelOptionResizeObservers = new Map();
                            }

                            if (this.oPanelOptionResizeObservers.has(optionKey)) {
                                this.oPanelOptionResizeObservers.get(optionKey).disconnect();
                            }

                            const resizeObserver = new ResizeObserver(() => {
                                if (ignoreInitialResize) {
                                    return;
                                }

                                clearTimeout(resizeTimeout);
                                resizeTimeout = setTimeout(() => {
                                    const computedStyle = window.getComputedStyle(optionBox);
                                    const width = parseFloat(computedStyle.width);
                                    const height = parseFloat(computedStyle.height);

                                    if (!this.oPanelConfig.sizes) {
                                        this.oPanelConfig.sizes = {};
                                    }
                                    if (!this.oPanelConfig.sizes[optionKey]) {
                                        this.oPanelConfig.sizes[optionKey] = {};
                                    }
                                    this.oPanelConfig.sizes[optionKey].width = width;
                                    this.oPanelConfig.sizes[optionKey].height = height;
                                    window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                                }, 100);
                            });

                            this.oPanelOptionResizeObservers.set(optionKey, resizeObserver);
                            resizeObserver.observe(optionBox);

                            contentGrid.appendChild(optionBox);
                        }
                    });

                    this.updateOPanelLayout();

                    this.startOPanelMasterUpdate();

                    if (this.oPanelConfig.firstLoad) {
                        this.oPanelConfig.firstLoad = false;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                        setTimeout(() => {
                            this.autogridOPanelPanels();
                        }, 100);
                    }
                }

                updateOPanelLayout() {
                }

                makeOPanelBoxDraggable(box, optionKey) {
                    const GRID_SIZE = 10;
                    let startX, startY, startLeft, startTop;
                    const gridOverlay = document.getElementById('opanel-grid-overlay');

                    const snapToGrid = (value) => Math.round(value / GRID_SIZE) * GRID_SIZE;

                    const onMouseMove = (e) => {
                        const deltaX = e.clientX - startX;
                        const deltaY = e.clientY - startY;

                        let newLeft = startLeft + deltaX;
                        let newTop = startTop + deltaY;

                        if (this.oPanelConfig.snapToGrid !== false) {
                            newLeft = snapToGrid(newLeft);
                            newTop = snapToGrid(newTop);
                        }

                        box.style.left = newLeft + 'px';
                        box.style.top = newTop + 'px';
                    };

                    const onMouseUp = () => {
                        document.removeEventListener('mousemove', onMouseMove);
                        document.removeEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners = this._opanelActiveDocListeners.filter(l => l.move !== onMouseMove);
                        box.style.zIndex = '1';
                        box.style.cursor = 'move';
                        if (gridOverlay) gridOverlay.style.display = 'none';

                        const newLeft = parseInt(box.style.left);
                        const newTop = parseInt(box.style.top);

                        if (!this.oPanelConfig.positions) this.oPanelConfig.positions = {};
                        if (!this.oPanelConfig.positions[optionKey]) this.oPanelConfig.positions[optionKey] = {};
                        this.oPanelConfig.positions[optionKey].x = newLeft;
                        this.oPanelConfig.positions[optionKey].y = newTop;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                    };

                    box.addEventListener('mousedown', (e) => {
                        if (this.oPanelIsLocked) return;
                        if (e.target.classList.contains('opanel-box-resize-handle')) return;
                        const rect = box.getBoundingClientRect();
                        if (e.clientX > rect.right - 20 && e.clientY > rect.bottom - 20) return;

                        startX = e.clientX;
                        startY = e.clientY;
                        startLeft = parseInt(box.style.left) || 0;
                        startTop = parseInt(box.style.top) || 0;
                        box.style.zIndex = '100';
                        box.style.cursor = 'grabbing';
                        if (gridOverlay) gridOverlay.style.display = 'block';
                        e.preventDefault();
                        document.addEventListener('mousemove', onMouseMove);
                        document.addEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners.push({ move: onMouseMove, up: onMouseUp });
                    });
                }

                makeOPanelBoxResizable(box, handle, optionKey) {
                    let startX, startY, startWidth, startHeight;

                    const onMouseMove = (e) => {
                        const deltaX = e.clientX - startX;
                        const deltaY = e.clientY - startY;

                        const minWidth = parseInt(box.style.minWidth) || 10;
                        const minHeight = parseInt(box.style.minHeight) || 10;
                        let newWidth = Math.max(minWidth, startWidth + deltaX);
                        let newHeight = Math.max(minHeight, startHeight + deltaY);

                        if (this.oPanelConfig.snapToGrid !== false) {
                            const GRID_SIZE = 10;
                            newWidth = Math.round(newWidth / GRID_SIZE) * GRID_SIZE;
                            newHeight = Math.round(newHeight / GRID_SIZE) * GRID_SIZE;
                        }

                        box.style.width = newWidth + 'px';
                        box.style.height = newHeight + 'px';
                    };

                    const onMouseUp = () => {
                        document.removeEventListener('mousemove', onMouseMove);
                        document.removeEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners = this._opanelActiveDocListeners.filter(l => l.move !== onMouseMove);

                        const rect = box.getBoundingClientRect();
                        if (!this.oPanelConfig.sizes) this.oPanelConfig.sizes = {};
                        if (!this.oPanelConfig.sizes[optionKey]) this.oPanelConfig.sizes[optionKey] = {};
                        this.oPanelConfig.sizes[optionKey].width = rect.width;
                        this.oPanelConfig.sizes[optionKey].height = rect.height;
                        window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                    };

                    handle.addEventListener('mousedown', (e) => {
                        if (this.oPanelIsLocked) { e.preventDefault(); e.stopPropagation(); return; }
                        startX = e.clientX;
                        startY = e.clientY;
                        const rect = box.getBoundingClientRect();
                        startWidth = rect.width;
                        startHeight = rect.height;
                        e.preventDefault();
                        e.stopPropagation();
                        document.addEventListener('mousemove', onMouseMove);
                        document.addEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners.push({ move: onMouseMove, up: onMouseUp });
                    });
                }

                makeOPanelDraggable(pane, dragHandle, storageKey) {
                    let dragOffset = { x: 0, y: 0 };

                    const onMouseMove = (e) => {
                        let newLeft = e.clientX - dragOffset.x;
                        let newTop = e.clientY - dragOffset.y;

                        const rect = pane.getBoundingClientRect();
                        const winWidth = window.innerWidth;
                        const winHeight = window.innerHeight;
                        const minVisiblePx = 30;

                        const handleRect = dragHandle.getBoundingClientRect();
                        const handleOffsetX = handleRect.left - rect.left;
                        const handleOffsetY = handleRect.top - rect.top;

                        const handleLeft = newLeft + handleOffsetX;
                        const handleRight = handleLeft + handleRect.width;
                        const handleTop = newTop + handleOffsetY;
                        const handleBottom = handleTop + handleRect.height;

                        if (handleRight < minVisiblePx) newLeft = minVisiblePx - handleOffsetX - handleRect.width;
                        if (handleLeft > winWidth - minVisiblePx) newLeft = winWidth - minVisiblePx - handleOffsetX;
                        if (handleBottom < minVisiblePx) newTop = minVisiblePx - handleOffsetY - handleRect.height;
                        if (handleTop > winHeight - minVisiblePx) newTop = winHeight - minVisiblePx - handleOffsetY;

                        pane.style.left = newLeft + 'px';
                        pane.style.top = newTop + 'px';
                        pane.style.right = 'auto';
                        pane.style.bottom = 'auto';
                    };

                    const onMouseUp = () => {
                        document.removeEventListener('mousemove', onMouseMove);
                        document.removeEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners = this._opanelActiveDocListeners.filter(l => l.move !== onMouseMove);
                        const rect = pane.getBoundingClientRect();
                        this.opStorage.set('position', { top: rect.top, left: rect.left });
                    };

                    dragHandle.addEventListener('mousedown', (e) => {
                        const rect = pane.getBoundingClientRect();
                        dragOffset.x = e.clientX - rect.left;
                        dragOffset.y = e.clientY - rect.top;
                        e.preventDefault();
                        e.stopPropagation();
                        document.addEventListener('mousemove', onMouseMove);
                        document.addEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners.push({ move: onMouseMove, up: onMouseUp });
                    });
                }

                makeOPanelCornerResizable(pane, handle, cornerName) {
                    let startX, startY, startWidth, startHeight, startLeft, startTop;

                    const onMouseMove = (e) => {
                        const deltaX = e.clientX - startX;
                        const deltaY = e.clientY - startY;

                        let newWidth = startWidth;
                        let newHeight = startHeight;
                        let newLeft = startLeft;
                        let newTop = startTop;

                        if (cornerName.includes('e')) newWidth = startWidth + deltaX;
                        if (cornerName.includes('w')) { newWidth = startWidth - deltaX; newLeft = startLeft + deltaX; }
                        if (cornerName.includes('s')) newHeight = startHeight + deltaY;
                        if (cornerName.includes('n')) { newHeight = startHeight - deltaY; newTop = startTop + deltaY; }

                        const minWidth = parseInt(pane.style.minWidth) || 10;
                        const minHeight = parseInt(pane.style.minHeight) || 10;

                        if (newWidth < minWidth) { newWidth = minWidth; if (cornerName.includes('w')) newLeft = startLeft + startWidth - minWidth; }
                        if (newHeight < minHeight) { newHeight = minHeight; if (cornerName.includes('n')) newTop = startTop + startHeight - minHeight; }

                        pane.style.width = newWidth + 'px';
                        pane.style.height = newHeight + 'px';
                        pane.style.left = newLeft + 'px';
                        pane.style.top = newTop + 'px';
                    };

                    const onMouseUp = () => {
                        document.removeEventListener('mousemove', onMouseMove);
                        document.removeEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners = this._opanelActiveDocListeners.filter(l => l.move !== onMouseMove);
                        const rect = pane.getBoundingClientRect();
                        window.lootDropsTrackerInstance.opStorage.set('size', { width: rect.width, height: rect.height });
                        window.lootDropsTrackerInstance.opStorage.set('position', { top: rect.top, left: rect.left });
                    };

                    handle.addEventListener('mousedown', (e) => {
                        if (this.oPanelIsLocked) { e.preventDefault(); e.stopPropagation(); return; }
                        startX = e.clientX;
                        startY = e.clientY;
                        const rect = pane.getBoundingClientRect();
                        startWidth = rect.width;
                        startHeight = rect.height;
                        startLeft = rect.left;
                        startTop = rect.top;
                        e.preventDefault();
                        e.stopPropagation();
                        document.addEventListener('mousemove', onMouseMove);
                        document.addEventListener('mouseup', onMouseUp);
                        this._opanelActiveDocListeners.push({ move: onMouseMove, up: onMouseUp });
                    });
                }

                resetOPanelPositions() {
                    this.oPanelConfig.positions = {
                        battleTimer: { x: 0, y: 0 },
                        combatRevenue: { x: 0, y: 50 },
                        consumables: { x: 0, y: 210 },
                        experiencePerHour: { x: 0, y: 300 },
                        totalProfit: { x: 0, y: 350 },
                        dps: { x: 0, y: 400 },
                        deathsPerHour: { x: 0, y: 560 },
                        houses: { x: 0, y: 610 },
                        equipmentWatch: { x: 0, y: 660 }
                    };
                    window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);

                    this.updateOPanelContent();
                }

                autogridOPanelPanels() {
                    const contentGrid = document.getElementById('opanel-content-grid');
                    const content = document.getElementById('opanel-content');
                    if (!contentGrid || !content) return;

                    const GRID_SIZE = 10;

                    const viewableHeight = content.clientHeight;

                    const visiblePanels = [];
                    this.oPanelConfig.order.forEach((optionKey) => {
                        if (this.oPanelConfig[optionKey] === true) {
                            const box = contentGrid.querySelector(`[data-option-key="${optionKey}"]`);
                            if (box) {
                                const currentX = parseInt(box.style.left) || 0;
                                const currentY = parseInt(box.style.top) || 0;
                                visiblePanels.push({
                                    key: optionKey,
                                    box: box,
                                    width: box.offsetWidth,
                                    height: box.offsetHeight,
                                    beforeX: currentX,
                                    beforeY: currentY
                                });
                            }
                        }
                    });

                    if (visiblePanels.length === 0) return;

                    const COLUMN_SPACER = 10;
                    const ROW_SPACER = 10;
                    const START_X = 10;
                    const START_Y = 10;
                    const columnWidths = [];
                    let currentColumn = 0;
                    let currentY = START_Y;

                    visiblePanels.forEach((panel) => {
                        const snappedY = Math.round(currentY / GRID_SIZE) * GRID_SIZE;

                        if (snappedY + panel.height > viewableHeight && currentY > START_Y) {
                            currentColumn++;
                            currentY = START_Y;
                            const newSnappedY = START_Y;

                            let x = START_X;
                            for (let i = 0; i < currentColumn; i++) {
                                x += (columnWidths[i] ?? 0) + COLUMN_SPACER;
                            }

                            panel.box.style.left = x + 'px';
                            panel.box.style.top = newSnappedY + 'px';

                            if (!columnWidths[currentColumn] || panel.width > columnWidths[currentColumn]) {
                                columnWidths[currentColumn] = panel.width;
                            }

                            if (!this.oPanelConfig.positions) {
                                this.oPanelConfig.positions = {};
                            }
                            if (!this.oPanelConfig.positions[panel.key]) {
                                this.oPanelConfig.positions[panel.key] = {};
                            }
                            this.oPanelConfig.positions[panel.key].x = x;
                            this.oPanelConfig.positions[panel.key].y = newSnappedY;

                            currentY = newSnappedY + panel.height + ROW_SPACER;
                        } else {
                            let x = START_X;
                            for (let i = 0; i < currentColumn; i++) {
                                x += (columnWidths[i] ?? 0) + COLUMN_SPACER;
                            }

                            panel.box.style.left = x + 'px';
                            panel.box.style.top = snappedY + 'px';

                            if (!columnWidths[currentColumn] || panel.width > columnWidths[currentColumn]) {
                                columnWidths[currentColumn] = panel.width;
                            }

                            if (!this.oPanelConfig.positions) {
                                this.oPanelConfig.positions = {};
                            }
                            if (!this.oPanelConfig.positions[panel.key]) {
                                this.oPanelConfig.positions[panel.key] = {};
                            }
                            this.oPanelConfig.positions[panel.key].x = x;
                            this.oPanelConfig.positions[panel.key].y = snappedY;

                            currentY = snappedY + panel.height + ROW_SPACER;
                        }
                    });

                    window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);
                }

                resetOPanelToDefaults() {
                    const defaultConfig = {
                        battleTimer: true,
                        combatRevenue: true,
                        consumables: true,
                        experiencePerHour: true,
                        totalProfit: true,
                        dps: true,
                        overExpected: true,
                        luck: true,
                        deathsPerHour: true,
                        houses: true,
                        equipmentWatch: true,
                        combatStatus: true,
                        order: ['battleTimer', 'combatRevenue', 'consumables', 'experiencePerHour', 'totalProfit', 'dps', 'overExpected', 'luck', 'deathsPerHour', 'houses', 'equipmentWatch', 'combatStatus'],
                        sizes: {
                            battleTimer: { width: 400, height: 30 },
                            combatRevenue: { width: 400, height: 70 },
                            consumables: { width: 400, height: 70 },
                            experiencePerHour: { width: 400, height: 30 },
                            totalProfit: { width: 400, height: 30 },
                            dps: { width: 400, height: 70 },
                            overExpected: { width: null, height: 70 },
                            luck: { width: null, height: 70 },
                            deathsPerHour: { width: 400, height: 30 },
                            houses: { width: 400, height: 30 },
                            equipmentWatch: { width: 400, height: 40 },
                            combatStatus: { width: 400, height: 30 }
                        },
                        positions: {}
                    };

                    let currentY = 20;
                    defaultConfig.order.forEach(optionKey => {
                        defaultConfig.positions[optionKey] = {
                            x: 40,
                            y: currentY
                        };
                        currentY += defaultConfig.sizes[optionKey].height + 10;
                    });

                    this.oPanelConfig = defaultConfig;
                    window.lootDropsTrackerInstance.opStorage.set('config', this.oPanelConfig);

                    const pane = document.getElementById('opanel-pane');
                    if (pane) {
                        pane.style.width = '500px';
                        pane.style.height = '550px';
                        window.lootDropsTrackerInstance.opStorage.set('size', { width: 500, height: 550 });
                    }

                    defaultConfig.order.forEach(optionKey => {
                        const checkbox = document.getElementById(`opanel-checkbox-${optionKey}`);
                        if (checkbox) {
                            checkbox.checked = defaultConfig[optionKey];
                        }
                    });

                    this.updateOPanelContent(true);
                }

                toggleOPanel() {
                    const pane = document.getElementById('opanel-pane');
                    if (pane) {
                        this.stopAllOPanelIntervals();
                        pane.remove();
                    } else {
                        this.createOPanel();
                    }
                }

                startOPanelMasterUpdate() {
                    this.stopAllOPanelIntervals();

                    this.updateOPanelTimer();
                    this.updateOPanelCombatRevenue();
                    this.updateOPanelConsumables();
                    this.updateOPanelExperience();
                    this.updateOPanelTotalProfit();
                    this.updateOPanelDPS();
                    this.updateOPanelOverExpected();
                    this.updateOPanelLuck();
                    this.updateOPanelDeaths();
                    this.updateOPanelHouses();
                    this.updateOPanelEWatch();
                    this.updateOPanelEWatchLayout();
                    this.updateOPanelCombatStatus();
                    this.updateOPanelNtallyInventory();
                    this.updateOPanelKollectionBuildScore();
                    this.updateOPanelKollectionNetWorth();
                    this.updateOPanelEwatchCoins();
                    this.updateOPanelEwatchMarket();
                    this.updateOPanelSkillBooks();

                    let frameCount = 0;
                    VisibilityManager.register('opanel-master', () => {
                        frameCount++;

                        this.updateOPanelTimer();
                        this.updateOPanelCombatStatus();

                        if (frameCount % 2 === 0) {
                            this.updateOPanelCombatRevenue();
                            this.updateOPanelConsumables();
                            this.updateOPanelExperience();
                            this.updateOPanelTotalProfit();
                            this.updateOPanelDPS();
                            this.updateOPanelOverExpected();
                            this.updateOPanelLuck();
                            this.updateOPanelDeaths();
                            this.updateOPanelNtallyInventory();
                            this.updateOPanelEwatchCoins();
                            this.updateOPanelEwatchMarket();
                            this.updateOPanelSkillBooks();
                        }

                        if (frameCount % 5 === 0) {
                            this.updateOPanelHouses();
                            this.updateOPanelEWatch();
                            this.updateOPanelKollectionBuildScore();
                            this.updateOPanelKollectionNetWorth();
                        }

                        if (frameCount >= 100) frameCount = 0;
                    }, 1000);
                }

                stopAllOPanelIntervals() {
                    VisibilityManager.clear('opanel-master');

                    if (this.oPanelMainResizeObserver) {
                        this.oPanelMainResizeObserver.disconnect();
                        this.oPanelMainResizeObserver = null;
                    }

                    if (this.oPanelOptionResizeObservers) {
                        this.oPanelOptionResizeObservers.forEach(observer => observer.disconnect());
                        this.oPanelOptionResizeObservers.clear();
                    }
                }

                updateOPanelTimer() {
                    const timerDisplay = document.getElementById('opanel-battle-timer');
                    if (!timerDisplay) return;

                    let timerText = '--:--:--';

                    if (this.startTime && this.isLiveSessionActive) {
                        const now = new Date();
                        const elapsed = now - this.startTime;
                        timerText = this.formatElapsedTime(elapsed);
                    } else if (this.startTime && this.sessionEndTime) {
                        const elapsed = this.sessionEndTime - this.startTime;
                        timerText = this.formatElapsedTime(elapsed);
                    }

                    if (this.isLiveSessionActive && this.sessionStartTime) {
                        const eph = this.calculateEPH();
                        timerDisplay.textContent = `${timerText} | ${eph} EPH`;
                    } else {
                        timerDisplay.textContent = timerText;
                    }
                }

                updateOPanelCombatRevenue() {
                    const revenueDisplay = document.getElementById('opanel-combat-revenue');
                    if (!revenueDisplay) return;

                    const tracker = window.lootDropsTrackerInstance;
                    if (!tracker) {
                        revenueDisplay.innerHTML = '<div style="text-align: center; color: #888;">--</div>';
                        return;
                    }

                    const userName = tracker.userName;
                    const playerRevenue = tracker.flootPlayerRevenue;

                    if (!playerRevenue || Object.keys(playerRevenue).length === 0) {
                        revenueDisplay.innerHTML = '<div style="text-align: center; color: #888;">No loot tracked</div>';
                        return;
                    }

                    const playerNames = Object.keys(playerRevenue).sort((a, b) => {
                        if (a === userName) return -1;
                        if (b === userName) return 1;
                        return 0;
                    });

                    let html = '';
                    for (const playerName of playerNames) {
                        const { total, perDay } = playerRevenue[playerName];

                        const totalText = total > 0 ? this.formatOPanelCoins(total) : '--';
                        const goldPerDayText = perDay > 0 ? this.formatOPanelCoins(Math.round(perDay)) : '';

                        const isCurrentUser = playerName === userName;
                        const nameColor = this.getPlayerNameColorByName(playerName);
                        const perDayColor = isCurrentUser ? '#90EE90' : '#aaa';

            html += `
                <div style="display: flex; flex-wrap: wrap; align-items: center; gap: 3px 6px; margin: 0 0 3px 0; font-size: 10px;">
                    <span style="color: ${nameColor}; font-weight: bold;">${playerName}</span>
                    <span style="display: flex; align-items: center; gap: 4px; color: #ffffff;">
                        <span style="font-size: 10px;">💰</span>
                        <span>${totalText}</span>
                    </span>
                    ${goldPerDayText ? `<span style="color: ${perDayColor};">${goldPerDayText}/day</span>` : ''}
                </div>
                        `;
                    }

                    revenueDisplay.innerHTML = html || '<div style="text-align: center; color: #888;">--</div>';
                }

                formatOPanelCoins(value) {
                    if (window.formatFlootCoins) {
                        return window.formatFlootCoins(value);
                    }
                    return `${Math.round(value).toLocaleString()} coin`;
                }

                updateOPanelConsumables() {
                    const consumablesDisplay = document.getElementById('opanel-consumables');
                    if (!consumablesDisplay) {
                        return;
                    }

                    const tracker = window.lootDropsTrackerInstance;
                    if (!tracker) {
                        consumablesDisplay.innerHTML = '<div style="text-align: center; color: #888;">--</div>';
                        return;
                    }

                    let yourTime = '--';
                    let yourColor = '#e0e0e0';
                    if (tracker.yourMinTime && tracker.yourMinTime !== Infinity) {
                        yourTime = mcsFormatDuration(tracker.yourMinTime, 'eta');
                        const days = tracker.yourMinTime / 86400;
                        if (days < 1) {
                            yourColor = '#c42323';
                        } else if (days < 2) {
                            yourColor = '#e8a738';
                        } else {
                            yourColor = '#65b83e';
                        }
                    }

                    let partyTime = '--';
                    let partyColor = '#e0e0e0';
                    if (tracker.partyMinTime !== undefined && tracker.partyMinTime !== Infinity) {
                        partyTime = mcsFormatDuration(tracker.partyMinTime, 'eta');
                        const days = tracker.partyMinTime / 86400;
                        if (days < 1) {
                            partyColor = '#FF6B6B';
                        } else if (days < 2) {
                            partyColor = '#FFA500';
                        } else {
                            partyColor = '#90EE90';
                        }
                    }

                    let row2Html = '';
                    if (tracker.minConsumables && tracker.minConsumables.length > 0 && tracker.minConsumablesCount) {
                        let iconsHtml = '';
                        tracker.minConsumables.forEach(item => {
                            const iconId = item.itemHrid.split('/').pop();
                            iconsHtml += createItemIconHtml(iconId, { className: 'opanel-consumable-icon-clickable', clickable: true, itemHrid: item.itemHrid, style: 'flex-shrink: 0' });
                        });

                        const askText = tracker.formatPriceShort ? tracker.formatPriceShort(tracker.totalConsumableAsk || 0) : '--';
                        const bidText = tracker.formatPriceShort ? tracker.formatPriceShort(tracker.totalConsumableBid || 0) : '--';

            row2Html = `
                <div style="display: flex; flex-wrap: wrap; align-items: center; gap: 3px 6px; font-size: 10px;">
                    <span style="color: #ff6666; padding-top:3px;font-weight: bold; gap: 4px;">${tracker.minConsumablesCount} remaining</span>
                    <span style="display: flex; padding-top:3px;align-items: center; gap: 4px;">${iconsHtml}</span>
                    <span style="color: #90EE90; padding-top:3px;font-weight: bold; gap: 4px;">Total Cost/Day:</span>
                    <span style="color: #ffffff; padding-top:3px;gap: 4px;">Ask: ${askText} / Bid: ${bidText}</span>
                </div>
                        `;
                    }

        const html = `
            <div style="display: flex; flex-wrap: wrap; align-items: center; gap: 3px 6px; margin-bottom: 0px; font-size: 10px;">
                <span style="color: #e0e0e0; font-weight: bold; gap: 4px;">You:</span>
                <span style="color: ${yourColor}; font-weight: bold; gap: 4px;">${yourTime}</span>
                <span style="color: #e0e0e0; font-weight: bold; gap: 4px;">Party:</span>
                <span style="color: ${partyColor}; font-weight: bold; gap: 4px;">${partyTime}</span>
            </div>
            ${row2Html}
                    `;

                    consumablesDisplay.innerHTML = html;

                    if (!consumablesDisplay.dataset.clickListenerAttached) {
                        consumablesDisplay.addEventListener('click', (e) => {
                            let icon = e.target;
                            const tagNameUpper = icon.tagName ? icon.tagName.toUpperCase() : '';
                            if (tagNameUpper === 'USE') {
                                icon = icon.parentElement;
                            }
                            if (!icon.classList || !icon.classList.contains('opanel-consumable-icon-clickable')) {
                                icon = e.target.closest('.opanel-consumable-icon-clickable');
                            }
                            if (icon && icon.classList && icon.classList.contains('opanel-consumable-icon-clickable')) {
                                const itemHrid = icon.getAttribute('data-item-hrid');
                                if (itemHrid) {
                                    mcsGoToMarketplace(itemHrid);
                                }
                            }
                        });
                        consumablesDisplay.dataset.clickListenerAttached = 'true';
                    }
                }

                updateOPanelExperience() {
                    const expDisplay = document.getElementById('opanel-experience-hr');
                    if (!expDisplay) return;

                    const tracker = window.lootDropsTrackerInstance;
                    if (tracker && tracker.gwhizTotalExpPerHour !== undefined) {
                        const totalExpPerHour = tracker.gwhizTotalExpPerHour || 0;
                        if (totalExpPerHour > 0) {
                            expDisplay.textContent = Math.floor(totalExpPerHour).toLocaleString() + ' exp/hr';
                        } else {
                            expDisplay.textContent = '0 exp/hr';
                        }
                    } else {
                        expDisplay.textContent = '0 exp/hr';
                    }
                }

                updateOPanelTotalProfit() {
                    const profitDisplay = document.getElementById('opanel-total-profit');
                    if (!profitDisplay) {
                        return;
                    }

                    const tracker = window.lootDropsTrackerInstance;
                    if (tracker && tracker.hwhatCurrentRevenue !== undefined) {
                        const revenue = tracker.hwhatCurrentRevenue || 0;
                        const cost = tracker.hwhatCurrentCost || 0;
                        const profit = tracker.hwhatCurrentProfit || 0;
                        const tax = tracker.hwhatCowbellTaxPerDay || 0;
                        const showTax = tracker.hwhatTaxEnabled || false;

                        const revenueText = tracker.formatGoldNumber ? tracker.formatGoldNumber(revenue) : revenue.toString();
                        const costText = tracker.formatGoldNumber ? tracker.formatGoldNumber(cost) : cost.toString();
                        const profitText = tracker.formatGoldNumber ? tracker.formatGoldNumber(profit) : profit.toString();
                        const taxText = tracker.formatGoldNumber ? tracker.formatGoldNumber(tax) : tax.toString();

                        let html = '';

                        html += `<span style="white-space: nowrap;"><span style="color: #4CAF50;">${revenueText}</span><span style="color: white;"> - </span></span>`;

                        if (showTax) {
                            const iconHtml = createItemIconHtml('bag_of_10_cowbells', { width: 16, height: 16, style: 'vertical-align: middle' });
                            html += `<span style="white-space: nowrap;">${iconHtml}<span style="color: #dc3545;">${taxText}</span><span style="color: white;"> - </span></span>`;
                        }

                        html += `<span style="white-space: nowrap;"><span style="color: #f44336;">${costText}</span><span style="color: white;"> = </span></span>`;

                        html += `<span style="white-space: nowrap; color: #FFD700;">${profitText}/day</span>`;

                        profitDisplay.innerHTML = html;
                    } else {
                        profitDisplay.innerHTML = '<span style="white-space: nowrap;"><span style="color: #4CAF50;">0</span><span style="color: white;"> - </span></span><span style="white-space: nowrap;"><span style="color: #f44336;">0</span><span style="color: white;"> = </span></span><span style="white-space: nowrap; color: #FFD700;">0/day</span>';
                    }
                }

                getPlayerIndexByName(playerName) {
                    if (!this.dpsTracking || !this.dpsTracking.players) {
                        return -1;
                    }

                    for (let i = 0; i < this.dpsTracking.players.length; i++) {
                        if (this.dpsTracking.players[i].name === playerName) {
                            return i;
                        }
                    }

                    return -1;
                }

                getPlayerNameColor(playerIndex) {
                    if (!this.oPanelConfig.usePlayerNameRecolor) {
                        return '#FFD700';
                    }

                    const tracker = window.lootDropsTrackerInstance;
                    if (!tracker || !tracker.fcbPlayerNameRecolorEnabled || !tracker.fcbSettingsMap) {
                        return '#FFD700';
                    }

                    const trackerKey = `tracker${playerIndex}`;
                    if (tracker.fcbSettingsMap[trackerKey]) {
                        const settings = tracker.fcbSettingsMap[trackerKey];
                        return `rgb(${settings.r},${settings.g},${settings.b})`;
                    }

                    return '#FFD700';
                }

                getPlayerNameColorByName(playerName) {
                    const playerIndex = this.getPlayerIndexByName(playerName);
                    if (playerIndex === -1) {
                        return '#FFD700';
                    }
                    return this.getPlayerNameColor(playerIndex);
                }

                updateOPanelDPS() {
                    const dpsDisplay = document.getElementById('opanel-dps');
                    if (!dpsDisplay) {
                        return;
                    }

                    const titleSpan = document.getElementById('dps-title-span');
                    const dpsContent = document.getElementById('dps-content');
                    if (!dpsContent) {
                        dpsDisplay.innerHTML = '<div style="color: #888;">No DPS data</div>';
                        return;
                    }

                    const playerItems = dpsContent.querySelectorAll('.mcs-dps-player-item');
                    if (playerItems.length === 0) {
                        dpsDisplay.innerHTML = '<div style="color: #888;">No DPS data</div>';
                        return;
                    }

                    let totalDPSText = '0.0';
                    if (titleSpan) {
                        const highlight = titleSpan.querySelector('.mcs-dps-title-highlight');
                        if (highlight) {
                            totalDPSText = highlight.textContent.trim();
                        }
                    }

                    let html = '';
                    playerItems.forEach(item => {
                        const nameLabel = item.querySelector('.mcs-dps-name-label');
                        const dpsLabel = item.querySelector('.mcs-dps-dps-label');
                        if (!nameLabel || !dpsLabel) return;

                        const playerName = nameLabel.textContent.trim();
                        const nameColor = this.getPlayerNameColorByName(playerName);

                        const dpsText = dpsLabel.childNodes[0]?.textContent?.trim() || '0.0';
                        const accuracySpan = dpsLabel.querySelector('.mcs-dps-accuracy-span');
                        const accuracyText = accuracySpan ? accuracySpan.textContent.trim() : '--';

                        html += `<div style="margin-bottom:3px;display: flex; justify-content: space-between; gap: 4px;">`;
                        html += `<span style="color: ${nameColor};gap: 4px;">${playerName}</span>`;
                        html += `<span style="color: #4CAF50;gap: 4px;">${dpsText} <span style="color: #FF9800;">${accuracyText}</span></span>`;
                        html += `</div>`;
                    });

                    html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                    html += `<span style="color: #fff; font-weight: bold;gap: 4px;">Total DPS</span>`;
                    html += `<span style="color: #90EE90; font-weight: bold;gap: 4px;">${totalDPSText}</span>`;
                    html += `</div>`;

                    dpsDisplay.innerHTML = html;
                }

                updateOPanelOverExpected() {
                    const overExpectedDisplay = document.getElementById('opanel-over-expected');
                    if (!overExpectedDisplay) {
                        return;
                    }

                    const bigExpectedContent = document.getElementById('lucky-big-expected-content');
                    if (!bigExpectedContent) {
                        overExpectedDisplay.innerHTML = '<div style="color: #888;">Lucky not available</div>';
                        return;
                    }

                    const playerItems = bigExpectedContent.querySelectorAll('.lucky-big-expected-item:not(.lucky-big-expected-total)');
                    const totalItem = bigExpectedContent.querySelector('.lucky-big-expected-total');

                    if (playerItems.length === 0 && !totalItem) {
                        overExpectedDisplay.innerHTML = '<div style="color: #888;">No Lucky data</div>';
                        return;
                    }

                    const onlyPlayer = this.oPanelConfig.overExpectedOnlyPlayer || false;
                    const onlyNumbers = this.oPanelConfig.overExpectedOnlyNumbers || false;

                    const tracker = window.lootDropsTrackerInstance;
                    const currentUserName = tracker ? tracker.userName : '';

                    const playersData = [];
                    playerItems.forEach(item => {
                        const nameSpan = item.querySelector('.lucky-big-expected-name');
                        const percentSpan = item.querySelector('.lucky-big-expected-percent');

                        if (nameSpan && percentSpan) {
                            const playerName = nameSpan.textContent;
                            const percent = percentSpan.textContent;
                            const color = percentSpan.style.color || '#a8aed4';
                            const isCurrentUser = playerName === currentUserName;

                            playersData.push({
                                name: playerName,
                                percent: percent,
                                color: color,
                                isCurrentUser: isCurrentUser
                            });
                        }
                    });

                    playersData.sort((a, b) => {
                        if (a.isCurrentUser && !b.isCurrentUser) return -1;
                        if (!a.isCurrentUser && b.isCurrentUser) return 1;
                        return 0;
                    });

                    let html = '';

                    const filteredPlayers = onlyPlayer ? playersData.filter(p => p.isCurrentUser) : playersData;

                    filteredPlayers.forEach(player => {
                        const nameColor = this.getPlayerNameColorByName(player.name);

                        if (onlyPlayer && onlyNumbers) {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        } else if (onlyNumbers) {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        } else if (onlyPlayer) {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${nameColor};">${player.name}</span>`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        } else {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px; gap: 4px;color: ${nameColor};">${player.name}</span>`;
                            html += `<span style="padding-bottom:3px; gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        }
                    });

                    if (totalItem && !onlyPlayer) {
                        const nameSpan = totalItem.querySelector('.lucky-big-expected-name');
                        const percentSpan = totalItem.querySelector('.lucky-big-expected-percent');

                        if (nameSpan && percentSpan) {
                            const totalName = nameSpan.textContent;
                            const totalPercent = percentSpan.textContent;
                            const totalColor = percentSpan.style.color || '#a8aed4';

                            if (onlyNumbers) {
                                html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                                html += `<span style="padding bottom:3px;color: ${totalColor}; font-weight: bold;">${totalPercent}</span>`;
                                html += `</div>`;
                            } else {
                                html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                                html += `<span style="padding bottom:3px;gap: 4px;color: #fff; font-weight: bold;">${totalName}</span>`;
                                html += `<span style="padding bottom:3px;gap: 4px;color: ${totalColor}; font-weight: bold;">${totalPercent}</span>`;
                                html += `</div>`;
                            }
                        }
                    }

                    overExpectedDisplay.innerHTML = html || '<div style="color: #888;">No data</div>';
                }

                updateOPanelLuck() {
                    const luckDisplay = document.getElementById('opanel-luck');
                    if (!luckDisplay) {
                        return;
                    }

                    const bigLuckContent = document.getElementById('lucky-big-luck-content');
                    if (!bigLuckContent) {
                        luckDisplay.innerHTML = '<div style="color: #888;">Lucky not available</div>';
                        return;
                    }

                    const playerItems = bigLuckContent.querySelectorAll('.lucky-big-luck-item');

                    if (playerItems.length === 0) {
                        luckDisplay.innerHTML = '<div style="color: #888;">No Lucky data</div>';
                        return;
                    }

                    const onlyPlayer = this.oPanelConfig.luckOnlyPlayer || false;
                    const onlyNumbers = this.oPanelConfig.luckOnlyNumbers || false;

                    const tracker = window.lootDropsTrackerInstance;
                    const currentUserName = tracker ? tracker.userName : '';

                    const playersData = [];
                    playerItems.forEach(item => {
                        const nameSpan = item.querySelector('.lucky-big-luck-name');
                        const percentSpan = item.querySelector('.lucky-big-luck-percent');

                        if (nameSpan && percentSpan) {
                            const playerName = nameSpan.textContent;
                            const percent = percentSpan.textContent;
                            const color = percentSpan.style.color || '#a8aed4';
                            const isCurrentUser = playerName === currentUserName;

                            playersData.push({
                                name: playerName,
                                percent: percent,
                                color: color,
                                isCurrentUser: isCurrentUser
                            });
                        }
                    });

                    playersData.sort((a, b) => {
                        if (a.isCurrentUser && !b.isCurrentUser) return -1;
                        if (!a.isCurrentUser && b.isCurrentUser) return 1;
                        return 0;
                    });

                    let html = '';

                    const filteredPlayers = onlyPlayer ? playersData.filter(p => p.isCurrentUser) : playersData;

                    filteredPlayers.forEach(player => {
                        const nameColor = this.getPlayerNameColorByName(player.name);

                        if (onlyPlayer && onlyNumbers) {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        } else if (onlyNumbers) {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        } else if (onlyPlayer) {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${nameColor};">${player.name}</span>`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        } else {
                            html += `<div style="display: flex; justify-content: space-between; gap: 4px;">`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${nameColor};">${player.name}</span>`;
                            html += `<span style="padding-bottom:3px;gap: 4px;color: ${player.color};">${player.percent}</span>`;
                            html += `</div>`;
                        }
                    });

                    luckDisplay.innerHTML = html || '<div style="color: #888;">No data</div>';
                }

                updateOPanelDeaths() {
                    const deathsDisplay = document.getElementById('opanel-deaths-hr');
                    if (!deathsDisplay) {
                        return;
                    }

                    const ihurtDeathsSpan = document.getElementById('ihurt-deaths-per-hour');
                    if (ihurtDeathsSpan) {
                        deathsDisplay.textContent = ihurtDeathsSpan.textContent;
                    } else {
                        deathsDisplay.textContent = '0.0 deaths/hr';
                    }
                }

                updateOPanelHouses() {
                    const housesDisplay = document.getElementById('opanel-houses');
                    if (!housesDisplay) return;

                    const affordability = this.jhouseAffordabilityResult;
                    if (!affordability) {
                        housesDisplay.innerHTML = '<span style="white-space: nowrap; color: #888;">No house data</span>';
                        return;
                    }

                    let html = '';

                    const count = affordability.count ?? 0;
                    const countColor = count > 0 ? '#4CAF50' : '#ff4444';
                    html += `<span style="white-space: nowrap; color: ${countColor};">${count} houses affordable</span>`;

                    if (!affordability.allMaxed && affordability.cheapestAsk !== null) {
                        const roomDisplayName = affordability.cheapestRoom
                            ? affordability.cheapestRoom.replace(/_/g, ' ').split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')
                            : '';
                        if (roomDisplayName) {
                            html += `<span style="white-space: nowrap; color: #FFD700;">${roomDisplayName}</span>`;
                        }
                        const cheapestText = this.formatGold ? this.formatGold(affordability.cheapestAsk) : affordability.cheapestAsk.toLocaleString();
                        html += `<span style="white-space: nowrap; color: #888;">Cheapest: ${cheapestText}</span>`;
                    } else if (affordability.allMaxed) {
                        html += `<span style="white-space: nowrap; color: #FFD700;">All maxed!</span>`;
                    }

                    housesDisplay.innerHTML = html;
                }

                updateOPanelEWatch() {
                    const ewatchDisplay = document.getElementById('opanel-ewatch');
                    if (!ewatchDisplay) return;

                    const itemSpan = document.getElementById('opanel-ewatch-item');
                    const remainingSpan = document.getElementById('opanel-ewatch-remaining');
                    const timeSpan = document.getElementById('opanel-ewatch-time');
                    const progressBar = document.getElementById('opanel-ewatch-progress-bar');
                    const percentSpan = document.getElementById('opanel-ewatch-percent');
                    const percentInline = document.getElementById('opanel-ewatch-percent-inline');

                    const displayItem = this.spyHeaderDisplayItem;
                    if (!displayItem) {
                        if (itemSpan) itemSpan.textContent = '--';
                        if (remainingSpan) remainingSpan.textContent = '--';
                        if (timeSpan) timeSpan.textContent = '--';
                        if (progressBar) { progressBar.style.width = '0%'; progressBar.style.background = '#6495ED'; }
                        if (percentSpan) percentSpan.textContent = '0.0%';
                        if (percentInline) percentInline.textContent = '0.0%';
                        return;
                    }

                    const itemDisplay = displayItem.enhLevel !== ''
                        ? `${displayItem.name} +${displayItem.enhLevel}`
                        : displayItem.name;

                    if (itemSpan) {
                        itemSpan.textContent = itemDisplay;
                        itemSpan.style.color = displayItem.name === 'Everything' ? '#FFA500' : '#FFD700';
                    }

                    if (remainingSpan) {
                        if (displayItem.stillNeeded > 0) {
                            const formattedGold = this.formatGoldCompact ? this.formatGoldCompact(displayItem.stillNeeded) : displayItem.stillNeeded.toLocaleString();
                            remainingSpan.textContent = formattedGold;
                            remainingSpan.style.display = '';
                            remainingSpan.style.color = 'white';
                        } else {
                            remainingSpan.style.display = 'none';
                        }
                    }

                    if (timeSpan) {
                        timeSpan.textContent = displayItem.timeStr;
                        timeSpan.style.color = !displayItem.inCombat ? '#f44336' : (displayItem.percent >= 100 ? '#4CAF50' : '#f5a623');
                    }

                    if (progressBar) {
                        progressBar.style.width = `${displayItem.percent}%`;
                        progressBar.style.background = displayItem.percent >= 100 ? '#4CAF50' : (displayItem.inCombat ? '#6495ED' : '#f44336');
                    }

                    if (percentSpan) {
                        percentSpan.textContent = `${displayItem.percent.toFixed(1)}%`;
                        percentSpan.style.color = displayItem.percent >= 100 ? '#4CAF50' : '#888';
                    }

                    if (percentInline) {
                        percentInline.textContent = `${displayItem.percent.toFixed(1)}%`;
                        percentInline.style.color = displayItem.percent >= 100 ? '#4CAF50' : '#888';
                    }
                }

                updateOPanelEWatchLayout() {
                    const barRow = document.getElementById('opanel-ewatch-bar-row');
                    const percentSpan = document.getElementById('opanel-ewatch-percent');
                    const percentInline = document.getElementById('opanel-ewatch-percent-inline');

                    if (!barRow || !percentSpan || !percentInline) return;

                    const showBar = this.oPanelConfig.ewatchShowBar !== false;

                    if (showBar) {
                        barRow.style.display = 'flex';
                        percentInline.style.display = 'none';
                    } else {
                        barRow.style.display = 'none';
                        percentInline.style.display = '';
                    }
                }

                updateOPanelCombatStatus() {
                    const combatStatusDisplay = document.getElementById('opanel-combat-status');
                    if (!combatStatusDisplay) return;

                    let inCombat = window.MCS_IN_COMBAT === true;
                    if (window.lootDropsTrackerInstance?.isLiveSessionActive) {
                        inCombat = true;
                    }

                    combatStatusDisplay.innerHTML = inCombat
                        ? '<span style="color: #4CAF50;">In Combat</span>'
                        : '<span style="color: #f44336;">No Combat</span>';
                }

                updateOPanelNtallyInventory() {
                    const ntallyDisplay = document.getElementById('opanel-ntally-inventory');
                    if (!ntallyDisplay) return;

                    const totalAsk = this.mcs_nt_lastTotalAsk ?? 0;
                    const totalBid = this.mcs_nt_lastTotalBid ?? 0;
                    const useAskPrice = window.getFlootUseAskPrice ? window.getFlootUseAskPrice() : false;
                    const ntallyPrice = useAskPrice ? totalAsk : totalBid;
                    const ntallyLabel = useAskPrice ? 'ask' : 'bid';
                    const ntallyColor = useAskPrice ? '#6495ED' : '#4CAF50';

                    const formattedValue = this.mcs_nt_formatNumber ? this.mcs_nt_formatNumber(ntallyPrice) : ntallyPrice.toLocaleString();
                    ntallyDisplay.innerHTML = `<span>📦</span><span style="color: ${ntallyPrice > 0 ? ntallyColor : '#999'}; font-weight: ${ntallyPrice > 0 ? 'bold' : 'normal'};">${formattedValue} ${ntallyLabel}</span>`;
                }

                updateOPanelKollectionBuildScore() {
                    const buildScoreDisplay = document.getElementById('opanel-kollection-build-score');
                    if (!buildScoreDisplay) return;

                    const totalScoreElem = document.getElementById('kollection-total-score');
                    if (totalScoreElem) {
                        buildScoreDisplay.textContent = `Build Score: ${totalScoreElem.textContent}`;
                    } else {
                        buildScoreDisplay.textContent = 'Build Score: --';
                    }
                }

                updateOPanelKollectionNetWorth() {
                    const netWorthDisplay = document.getElementById('opanel-kollection-net-worth');
                    if (!netWorthDisplay) return;

                    const netWorthElem = document.getElementById('kollection-networth-total');
                    if (netWorthElem) {
                        netWorthDisplay.textContent = `Net Worth: ${netWorthElem.textContent}`;
                    } else {
                        netWorthDisplay.textContent = 'Net Worth: --';
                    }
                }

                updateOPanelEwatchCoins() {
                    const coinsDisplay = document.getElementById('opanel-ewatch-coins');
                    if (!coinsDisplay) return;

                    let coinValue = 0;
                    if (this.spyCharacterItems) {
                        const coinItem = this.spyCharacterItems.find(item => item.itemHrid === '/items/coin');
                        if (coinItem && coinItem.count) {
                            coinValue = coinItem.count;
                        }
                    }

                    const formattedValue = this.mcs_nt_formatNumber ? this.mcs_nt_formatNumber(coinValue) : coinValue.toLocaleString();
                    coinsDisplay.innerHTML = `<span style="width: 11px; height: 11px; display: inline-flex;">${createItemIconHtml('coin', { width: '100%', height: '100%', sprite: 'items_sprite' })}</span><span style="color: ${coinValue > 0 ? '#FFD700' : '#999'}; font-weight: ${coinValue > 0 ? 'bold' : 'normal'};">${formattedValue}</span>`;
                }

                updateOPanelEwatchMarket() {
                    const marketDisplay = document.getElementById('opanel-ewatch-market');
                    if (!marketDisplay) return;

                    const marketTotal = this.mcs_nt_lastMarketTotal ?? 0;

                    const formattedValue = this.mcs_nt_formatNumber ? this.mcs_nt_formatNumber(marketTotal) : marketTotal.toLocaleString();
                    marketDisplay.innerHTML = `<span>📈</span><span style="color: ${marketTotal > 0 ? '#FFD700' : '#999'}; font-weight: ${marketTotal > 0 ? 'bold' : 'normal'};">${formattedValue}</span>`;
                }

                updateOPanelSkillBooks() {
                    const skillBooksDisplay = document.getElementById('opanel-skill-books');
                    if (!skillBooksDisplay) return;

                    const skillBooksInfo = window.mcs_breadCheapestSkill;

                    if (!skillBooksInfo || !skillBooksInfo.iconId || !skillBooksInfo.books || skillBooksInfo.books <= 0) {
                        if (this._lastSkillBooksKey !== null) {
                            skillBooksDisplay.innerHTML = '<span style="color: #999;">No skill data</span>';
                            this._lastSkillBooksKey = null;
                        }
                        return;
                    }

                    const key = skillBooksInfo.iconId + '|' + skillBooksInfo.books + '|' + skillBooksInfo.cost;
                    if (key === this._lastSkillBooksKey) return;
                    this._lastSkillBooksKey = key;

                    const itemHrid = '/items/' + skillBooksInfo.iconId;
        const newContent = `
            ${createItemIconHtml(skillBooksInfo.iconId, { width: 18, height: 18, className: 'opanel-bread-icon-clickable', clickable: true, itemHrid, style: 'flex-shrink: 0; pointer-events: auto' })}
            <span style="color: #4CAF50; font-weight: bold;">${skillBooksInfo.books}</span>
            <span style="color: #aaa;">books</span>
            <span style="color: #FFD700;">${mcsFormatCurrency(skillBooksInfo.cost, 'cost')}</span>
                    `;

                    skillBooksDisplay.innerHTML = newContent;

                    if (!skillBooksDisplay.dataset.clickListenerAttached) {
                        skillBooksDisplay.addEventListener('click', (e) => {
                            let icon = e.target;
                            if (icon.tagName && icon.tagName.toUpperCase() === 'USE') {
                                icon = icon.parentElement;
                            }
                            if (!icon.classList || !icon.classList.contains('opanel-bread-icon-clickable')) {
                                icon = e.target.closest('.opanel-bread-icon-clickable');
                            }
                            if (icon && icon.classList && icon.classList.contains('opanel-bread-icon-clickable')) {
                                const itemHrid = icon.getAttribute('data-item-hrid');
                                if (itemHrid) {
                                    e.stopPropagation();
                                    mcsGoToMarketplace(itemHrid);
                                }
                            }
                        });
                        skillBooksDisplay.dataset.clickListenerAttached = 'true';
                    }
                }

// OPanel end

// CRackData start

                get crStorage() {
                    if (!this._crStorage) {
                        this._crStorage = createModuleStorage('CR');
                    }
                    return this._crStorage;
                }

                loadAbilityDetailMap() {
                    return InitClientDataCache.getAbilityDetailMap();
                }

                getDefaultConsumed(itemHrid) {
                    const name = itemHrid.toLowerCase();
                    if (name.includes('coffee')) return 2;
                    if (name.includes('donut') || name.includes('cupcake') || name.includes('cake') || name.includes('gummy') || name.includes('yogurt')) return 10;
                    return 0;
                }

                calcElapsedSeconds(tracker) {
                    const now = Date.now();
                    const start = tracker.actualStartTime || tracker.startTime || now;
                    const saved = tracker.savedPausedMs ?? 0;
                    const paused = (window.MCS_TOTAL_PAUSED_MS ?? 0) - saved;
                    const current = window.MCS_MODULES_DISABLED && window.MCS_PAUSE_START_TIME
                        ? (Date.now() - window.MCS_PAUSE_START_TIME) : 0;
                    return Math.max(0, ((now - start) - paused - current) / 1000);
                }

                calcElapsedMs(tracker) {
                    return this.calcElapsedSeconds(tracker) * 1000;
                }

                createPartyTracker() {
                    return {
                        actualConsumed: {},
                        defaultConsumed: {},
                        inventoryAmount: {},
                        startTime: Date.now(),
                        actualStartTime: Date.now(),
                        lastUpdate: null,
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                    };
                }

                resetConsumableTracking() {
                    const cachedData = CharacterDataStorage.get();

                    this.consumableTracker = {
                        actualConsumed: {},
                        defaultConsumed: {},
                        inventoryAmount: {},
                        startTime: Date.now(),
                        actualStartTime: Date.now(),
                        lastUpdate: null,
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                    };
                    this.partyConsumableTracker = {};
                    this.partyConsumableSnapshots = {};

                    this.crStorage.set('consumable_tracker', null);
                    this.crStorage.set('party_tracker', null);
                    this.crStorage.set('party_snapshots', null);
                    this.crStorage.set('last_battle', null);

                    if (cachedData) {
                        const foodSlots = cachedData.actionTypeFoodSlotsMap?.['/action_types/combat'] ?? [];
                        const drinkSlots = cachedData.actionTypeDrinkSlotsMap?.['/action_types/combat'] ?? [];

                        [...foodSlots, ...drinkSlots].forEach(slot => {
                            if (slot && slot.itemHrid) {
                                const inventoryItem = cachedData.characterItems.find(item =>
                                    item.itemHrid === slot.itemHrid &&
                                    item.itemLocationHrid === '/item_locations/inventory'
                                );
                                if (inventoryItem) {
                                    this.consumableTracker.inventoryAmount[slot.itemHrid] = inventoryItem.count;

                                    this.consumableTracker.actualConsumed[slot.itemHrid] = 0;
                                    this.consumableTracker.defaultConsumed[slot.itemHrid] = this.getDefaultConsumed(slot.itemHrid);
                                }
                            }
                        });

                        if (this.lastBattleData && this.lastBattleData.players) {
                            const currentPlayerName = cachedData.character?.name || this.spyCharacterName || '';
                            this.lastBattleData.players.forEach(player => {
                                if (player.name === currentPlayerName) return;

                                if (player.combatConsumables && player.combatConsumables.length > 0) {
                                    this.partyConsumableTracker[player.name] = this.createPartyTracker();
                                    player.combatConsumables.forEach(consumable => {
                                        if (consumable && consumable.itemHrid && consumable.count) {
                                            this.partyConsumableTracker[player.name].inventoryAmount[consumable.itemHrid] = consumable.count;
                                            this.partyConsumableTracker[player.name].actualConsumed[consumable.itemHrid] = 0;
                                            this.partyConsumableTracker[player.name].defaultConsumed[consumable.itemHrid] = this.getDefaultConsumed(consumable.itemHrid);
                                        }
                                    });
                                }
                            });
                        }

                        this.saveConsumableTracking();
                    }

                    this.consumableResetPending = false;
                    this.consumableResetBattleCount = 0;
                    this.consumableResetItems = [];
                    this.consumableResetPartyItems = {};

                    this.updateConsumablesDisplay();
                }
                estimateTimeToZeroForPartyMemberTracked(playerName, itemHrid, currentCount) {
                    if (!this.partyConsumableTracker[playerName]) {
                        return null;
                    }
                    const tracker = this.partyConsumableTracker[playerName];

                    const actualConsumed = tracker.actualConsumed[itemHrid] ?? 0;
                    let defaultConsumed = tracker.defaultConsumed[itemHrid] ?? 0;

                    if (defaultConsumed === 0) {
                        defaultConsumed = this.getDefaultConsumed(itemHrid);
                        if (defaultConsumed === 0) return null;
                        tracker.defaultConsumed[itemHrid] = defaultConsumed;
                    }

                    const actualElapsedSeconds = this.calcElapsedSeconds(tracker);

                    const DEFAULT_TIME = 10 * 60;
                    const actualRate = actualElapsedSeconds > 0 ? (actualConsumed / actualElapsedSeconds) : 0;
                    const combinedRate = (defaultConsumed + actualConsumed) / (DEFAULT_TIME + actualElapsedSeconds);
                    const consumptionRate = (actualRate * 0.9) + (combinedRate * 0.1);

                    if (consumptionRate === 0) {
                        return null;
                    }

                    const actualCurrentAmount = tracker.inventoryAmount[itemHrid] !== undefined
                        ? tracker.inventoryAmount[itemHrid]
                        : currentCount;

                    const remainingSeconds = actualCurrentAmount / consumptionRate;
                    const consumedPerDay = Math.ceil((consumptionRate * 86400));

                    return { remainingSeconds, consumedPerDay };
                }
                initConsumableTracking() {
                    const saved = this.crStorage.get('consumable_tracker');
                    if (saved) {
                        try {
                            if (saved.consumedCount && !saved.actualConsumed) {
                                const migratedDefault = {};
                                const migratedActual = {};

                                Object.keys(saved.consumedCount ?? {}).forEach(itemHrid => {
                                    migratedDefault[itemHrid] = this.getDefaultConsumed(itemHrid);
                                    migratedActual[itemHrid] = 0;
                                });

                                this.consumableTracker = {
                                    actualConsumed: migratedActual,
                                    defaultConsumed: migratedDefault,
                                    inventoryAmount: saved.inventoryAmount ?? {},
                                    startTime: Date.now(),
                                    actualStartTime: Date.now(),
                                    lastUpdate: null,
                                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                                };
                                this.saveSoloConsumableTracking();
                            } else if (saved.usageCounts || saved.currentCounts) {
                                const migratedDefault = {};
                                const migratedActual = {};

                                Object.keys(saved.usageCounts ?? {}).forEach(itemHrid => {
                                    migratedDefault[itemHrid] = this.getDefaultConsumed(itemHrid);
                                    migratedActual[itemHrid] = 0;
                                });

                                this.consumableTracker = {
                                    actualConsumed: migratedActual,
                                    defaultConsumed: migratedDefault,
                                    inventoryAmount: saved.currentCounts ?? {},
                                    startTime: Date.now(),
                                    actualStartTime: Date.now(),
                                    lastUpdate: null,
                                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                                };
                                this.saveSoloConsumableTracking();
                            } else if (saved.startCounts && !saved.actualConsumed) {
                                this.consumableTracker = {
                                    actualConsumed: {},
                                    defaultConsumed: {},
                                    inventoryAmount: {},
                                    startTime: Date.now(),
                                    actualStartTime: Date.now(),
                                    lastUpdate: null,
                                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                                };
                                this.saveSoloConsumableTracking();
                            } else {
                                const now = Date.now();
                                const elapsedMs = saved.elapsedTrackingMs ?? 0;

                                this.consumableTracker = {
                                    actualConsumed: saved.actualConsumed ?? {},
                                    defaultConsumed: saved.defaultConsumed ?? {},
                                    inventoryAmount: saved.inventoryAmount ?? {},
                                    startTime: now - elapsedMs,
                                    actualStartTime: now - elapsedMs,
                                    lastUpdate: saved.lastUpdate || null,
                                    savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                                };
                            }
                        } catch (e) {
                            console.error('[Consumables] Failed to load tracker:', e);
                        }
                    }
                    if (!this.consumableTracker) {
                        this.consumableTracker = {
                            actualConsumed: {},
                            defaultConsumed: {},
                            inventoryAmount: {},
                            startTime: null,
                            actualStartTime: null,
                            lastUpdate: null,
                            savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                        };
                    }

                    const savedPartyTracker = this.crStorage.get('party_tracker');
                    if (savedPartyTracker) {
                        try {
                            const now = Date.now();
                            this.partyConsumableTracker = {};
                            Object.keys(savedPartyTracker).forEach(playerName => {
                                const playerTracker = savedPartyTracker[playerName];

                                if (playerTracker.actualConsumed && playerTracker.defaultConsumed &&
                                    playerTracker.inventoryAmount && typeof playerTracker.actualConsumed === 'object') {

                                    const elapsedMs = playerTracker.elapsedTrackingMs ?? 0;

                                    this.partyConsumableTracker[playerName] = {
                                        actualConsumed: playerTracker.actualConsumed ?? {},
                                        defaultConsumed: playerTracker.defaultConsumed ?? {},
                                        inventoryAmount: playerTracker.inventoryAmount ?? {},
                                        startTime: now - elapsedMs,
                                        actualStartTime: now - elapsedMs,
                                        lastUpdate: playerTracker.lastUpdate || null,
                                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                                    };
                                } else {
                                }
                            });
                        } catch (e) {
                            console.error('[Consumables] Failed to load party tracker:', e);
                            this.partyConsumableTracker = {};
                        }
                    } else {
                        this.partyConsumableTracker = {};
                    }

                    const savedPartySnapshots = this.crStorage.get('party_snapshots');
                    if (savedPartySnapshots) {
                        try {
                            this.partyConsumableSnapshots = savedPartySnapshots;
                        } catch (e) {
                            console.error('[Consumables] Failed to load party snapshots:', e);
                            this.partyConsumableSnapshots = {};
                        }
                    } else {
                        this.partyConsumableSnapshots = {};
                    }

                    const savedBattleData = this.crStorage.get('last_battle');
                    if (savedBattleData) {
                        try {
                            this.lastBattleData = savedBattleData;
                        } catch (e) {
                            console.error('[Consumables] Failed to load last battle data:', e);
                        }
                    }

                    const savedLastKnown = this.crStorage.get('party_last_known');
                    if (savedLastKnown) {
                        try {
                            this.partyLastKnownConsumables = savedLastKnown;
                        } catch (e) {
                            console.error('[Consumables] Failed to load last known consumables:', e);
                            this.partyLastKnownConsumables = {};
                        }
                    } else {
                        this.partyLastKnownConsumables = {};
                    }
                }
                saveSoloConsumableTracking() {
                    if (this.consumableTracker) {
                        try {
                            const elapsedTrackingMs = this.calcElapsedMs(this.consumableTracker);

                            const trackerToSave = {
                                actualConsumed: this.consumableTracker.actualConsumed ?? {},
                                defaultConsumed: this.consumableTracker.defaultConsumed ?? {},
                                inventoryAmount: this.consumableTracker.inventoryAmount ?? {},
                                elapsedTrackingMs: Math.max(0, elapsedTrackingMs),
                                lastUpdate: this.consumableTracker.lastUpdate || null,
                                savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                                saveTimestamp: Date.now()
                            };
                            this.crStorage.set('consumable_tracker', trackerToSave);
                        } catch (e) {
                            console.error('[Consumables] Failed to save solo tracker:', e);
                            console.error('[Consumables] Tracker data:', this.consumableTracker);
                        }
                    }
                }

                savePartyConsumableTracking() {
                    if (this.partyConsumableTracker) {
                        try {
                            const partyTrackerToSave = {};
                            Object.keys(this.partyConsumableTracker).forEach(playerName => {
                                const tracker = this.partyConsumableTracker[playerName];
                                if (tracker && tracker.actualConsumed && tracker.defaultConsumed && tracker.inventoryAmount) {
                                    partyTrackerToSave[playerName] = {
                                        actualConsumed: tracker.actualConsumed ?? {},
                                        defaultConsumed: tracker.defaultConsumed ?? {},
                                        inventoryAmount: tracker.inventoryAmount ?? {},
                                        elapsedTrackingMs: Math.max(0, this.calcElapsedMs(tracker)),
                                        lastUpdate: tracker.lastUpdate || null,
                                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                                        saveTimestamp: Date.now()
                                    };
                                }
                            });
                            this.crStorage.set('party_tracker', partyTrackerToSave);
                        } catch (e) {
                            console.error('[Consumables] Failed to save party tracker:', e);
                            console.error('[Consumables] Party tracker data:', this.partyConsumableTracker);
                        }
                    }

                    if (this.partyConsumableSnapshots) {
                        try {
                            this.crStorage.set('party_snapshots', this.partyConsumableSnapshots);
                        } catch (e) {
                            console.error('[Consumables] Failed to save party snapshots:', e);
                        }
                    }

                    if (this.lastBattleData) {
                        try {
                            this.crStorage.set('last_battle', this.lastBattleData);
                        } catch (e) {
                            console.error('[Consumables] Failed to save last battle data:', e);
                        }
                    }

                    if (this.partyLastKnownConsumables) {
                        try {
                            this.crStorage.set('party_last_known', this.partyLastKnownConsumables);
                        } catch (e) {
                            console.error('[Consumables] Failed to save last known consumables:', e);
                        }
                    }
                }

                saveConsumableTracking() {
                    this.saveSoloConsumableTracking();
                    this.savePartyConsumableTracking();
                }
                saveCrackInventory() {
                    if (this.consumableTracker && this.consumableTracker.inventoryAmount) {
                        this.crStorage.set('consumable_inventory', this.consumableTracker.inventoryAmount);
                    }
                }
                estimateTimeToZero(itemHrid, currentCount) {
                    if (!this.consumableTracker || !this.consumableTracker.startTime) {
                        return null;
                    }

                    const actualConsumed = this.consumableTracker.actualConsumed[itemHrid] ?? 0;
                    const defaultConsumed = this.consumableTracker.defaultConsumed[itemHrid] ?? 0;

                    const actualElapsedSeconds = this.calcElapsedSeconds(this.consumableTracker);

                    const DEFAULT_TIME = 10 * 60;
                    const actualRate = actualElapsedSeconds > 0 ? (actualConsumed / actualElapsedSeconds) : 0;
                    const combinedRate = (defaultConsumed + actualConsumed) / (DEFAULT_TIME + actualElapsedSeconds);
                    const consumptionRate = (actualRate * 0.9) + (combinedRate * 0.1);

                    if (consumptionRate === 0) {
                        return null;
                    }

                    const actualCurrentAmount = this.consumableTracker.inventoryAmount[itemHrid] !== undefined
                        ? this.consumableTracker.inventoryAmount[itemHrid]
                        : currentCount;

                    const remainingSeconds = actualCurrentAmount / consumptionRate;
                    const consumedPerDay = Math.ceil((consumptionRate * 86400));

                    return { remainingSeconds, consumedPerDay };
                }
                formatTimeRemaining(seconds) {
                    return mcsFormatDuration(seconds, 'eta');
                }
                formatTimeShort(seconds) {
                    return mcsFormatDuration(seconds, 'short');
                }
                async fetchMarketJSON() {
                    return mcsGetMarketData();
                }
                getItemPrices(itemHrid, price_data) {
                    if (!price_data || !price_data.marketData) return null;
                    const item_price_data = price_data.marketData[itemHrid];
                    if (!item_price_data || !item_price_data[0]) return null;
                    const ask = item_price_data[0].a;
                    const bid = item_price_data[0].b;
                    if ((ask <= 0 || ask === -1) && (bid <= 0 || bid === -1)) return null;
                    return {
                        ask: ask > 0 ? ask : 0,
                        bid: bid > 0 ? bid : 0
                    };
                }
                formatPriceShort(price) {
                    return mcsFormatCurrency(price, 'short');
                }

// CRackData end

// CRackUI start

            renderConsumableRow({ itemHrid, count, tracker, iconId, itemName, countColorClass, nameColorClass, timeColorClass, extraClasses, extraAttrs, priceData }) {
                    let html = '';
                    html += '<div class="mcs-crack-consumable-container">';
                    html += '<div class="consumable-row ' + (extraClasses || '') + ' mcs-crack-consumable-row" ' + (extraAttrs || '') + ' data-icon-id="' + iconId + '">';
                    html += '<span class="mcs-crack-stat-count ' + (countColorClass || '') + '">' + count + '</span>';
                    html += createItemIconHtml(iconId, { className: 'consumable-icon-clickable mcs-crack-consumable-icon', clickable: true, itemHrid: itemHrid });
                    html += '<span class="mcs-crack-consumable-name ' + (nameColorClass || '') + '">' + itemName + '</span>';

                    const etaData = tracker._etaData;
                    if (etaData) {
                        const actualElapsedSeconds = this.calcElapsedSeconds(tracker);
                        const actualConsumed = tracker.actualConsumed[itemHrid] ?? 0;
                        const defaultConsumed = tracker.defaultConsumed[itemHrid] ?? 0;
                        const combinedConsumed = defaultConsumed + actualConsumed;
                        const DEFAULT_TIME = 10 * 60;
                        const combinedTime = Math.floor(DEFAULT_TIME + actualElapsedSeconds);

                        html += '<div class="mcs-crack-stack-container">';
                        html += '<div class="mcs-crack-stack-row">';
                        html += '<span class="mcs-crack-stat-actual" title="90% weight">\u2B06 ' + Math.floor(actualElapsedSeconds) + 's</span>';
                        html += '<span class="mcs-crack-stat-actual" title="90% weight">\u2B06 ' + actualConsumed + '</span>';
                        html += '</div>';
                        html += '<div class="mcs-crack-stack-row">';
                        html += '<span class="mcs-crack-stat-combined" title="10% weight">\u2B07 ' + combinedTime + 's</span>';
                        html += '<span class="mcs-crack-stat-combined" title="10% weight">\u2B07 ' + combinedConsumed + '</span>';
                        html += '</div>';
                        html += '</div>';

                        html += '<span class="mcs-crack-per-day">' + etaData.consumedPerDay + '/day</span>';
                        html += this.generatePriceHTML(itemHrid, priceData, etaData.consumedPerDay);
                        html += '<span class="mcs-crack-time-remaining ' + (timeColorClass || '') + '">' + this.formatTimeRemaining(etaData.remainingSeconds) + '</span>';
                    } else {
                        html += '<span class="mcs-crack-waiting">Waiting...</span>';
                    }
                    html += '</div>';
                    html += '</div>';
                    return html;
                }

                createConsumablesPane() {
                    if (document.getElementById('consumables-pane')) return;
                    const pane = document.createElement('div');
                    pane.id = 'consumables-pane';
                    registerPanel('consumables-pane');
                    pane.className = 'mcs-crack-pane';

                    const header = document.createElement('div');
                    header.className = 'mcs-crack-header';

                    const leftSection = document.createElement('div');
                    leftSection.className = 'mcs-crack-header-left';

                    const titleSpan = document.createElement('span');
                    titleSpan.className = 'mcs-crack-title';
                    titleSpan.textContent = 'CRack';

                    const yourEtaContainer = document.createElement('span');
                    yourEtaContainer.className = 'mcs-crack-eta-container';
                    yourEtaContainer.innerHTML = '<span id="consumables-days-left">--</span>';

                    const partyEtaContainer = document.createElement('span');
                    partyEtaContainer.id = 'party-eta-container';
                    partyEtaContainer.className = 'mcs-crack-party-eta-container';
                    partyEtaContainer.innerHTML = 'Party: <span id="party-min-eta"></span>';

                    leftSection.appendChild(titleSpan);
                    leftSection.appendChild(yourEtaContainer);
                    leftSection.appendChild(partyEtaContainer);

                    const buttonContainer = document.createElement('div');
                    buttonContainer.className = 'mcs-crack-button-container';

                    const resetBtn = document.createElement('button');
                    resetBtn.className = 'mcs-crack-reset-btn';
                    resetBtn.textContent = '↻';
                    resetBtn.title = 'Reset tracking to defaults immediately';
                    resetBtn.onclick = (e) => {
                        e.stopPropagation();
                        this.resetConsumableTracking();
                    };

                    const minimizeBtn = document.createElement('button');
                    minimizeBtn.id = 'consumables-minimize-btn';
                    minimizeBtn.className = 'mcs-crack-minimize-btn';
                    minimizeBtn.textContent = '−';

                    buttonContainer.appendChild(resetBtn);
                    buttonContainer.appendChild(minimizeBtn);
                    header.appendChild(leftSection);
                    header.appendChild(buttonContainer);

                    const content = document.createElement('div');
                    content.id = 'consumables-content';
                    content.className = 'mcs-crack-content';

                    pane.appendChild(header);
                    pane.appendChild(content);
                    document.body.appendChild(pane);
                    const self = this;

                    content.addEventListener('click', (e) => {
                        let target = e.target;
                        if (target.tagName && target.tagName.toUpperCase() === 'USE') {
                            target = target.parentElement;
                        }
                        if (!target.classList || !target.classList.contains('consumable-icon-clickable')) {
                            target = e.target.closest('.consumable-icon-clickable');
                        }
                        if (target && target.classList && target.classList.contains('consumable-icon-clickable')) {
                            const itemHrid = target.getAttribute('data-item-hrid');
                            if (itemHrid) {
                                self.openConsumableMarketplace(itemHrid);
                            }
                        }
                    });

                    if (!this.partyConsumableSnapshots) {
                        this.partyConsumableSnapshots = {};
                    }

                    const handleWebSocketMessage = PerformanceMonitor.wrap('CRack', (event) => {
                        if (window.MCS_MODULES_DISABLED) return;

                        const data = event.detail;

                        if (data?.type === 'init_character_data' || data?.type === 'action_type_consumable_slots_updated') {
                            if (data?.type === 'action_type_consumable_slots_updated') {
                                const cachedData = CharacterDataStorage.get();
                                if (cachedData) {
                                    if (data.actionTypeFoodSlotsMap) {
                                        cachedData.actionTypeFoodSlotsMap = data.actionTypeFoodSlotsMap;
                                    }
                                    if (data.actionTypeDrinkSlotsMap) {
                                        cachedData.actionTypeDrinkSlotsMap = data.actionTypeDrinkSlotsMap;
                                    }
                                }
                            }

                            const foodSlots = data.actionTypeFoodSlotsMap?.['/action_types/combat'] ?? [];
                            const drinkSlots = data.actionTypeDrinkSlotsMap?.['/action_types/combat'] ?? [];

                            const currentEquippedHrids = new Set();
                            [...foodSlots, ...drinkSlots].forEach(slot => {
                                if (slot?.itemHrid) {
                                    currentEquippedHrids.add(slot.itemHrid);
                                }
                            });

                            const previousHrids = self.lastSeenConsumableHrids
                                || new Set(Object.keys(self.consumableTracker?.actualConsumed ?? {}));
                            self.lastSeenConsumableHrids = currentEquippedHrids;

                            const hasChanges = currentEquippedHrids.size !== previousHrids.size ||
                                [...currentEquippedHrids].some(hrid => !previousHrids.has(hrid));

                            if (hasChanges && self.consumableTracker) {
                                Object.keys(self.consumableTracker.actualConsumed ?? {}).forEach(itemHrid => {
                                    if (!currentEquippedHrids.has(itemHrid)) {
                                        delete self.consumableTracker.actualConsumed[itemHrid];
                                        delete self.consumableTracker.defaultConsumed[itemHrid];
                                        delete self.consumableTracker.inventoryAmount[itemHrid];
                                    }
                                });
                                self.updateConsumablesDisplay();
                            }
                        }

                        if (data?.type === 'new_battle') {

                            if (data.players) {
                                const cachedData = CharacterDataStorage.get();
                                if (cachedData) {
                                    const currentPlayerName = cachedData?.character?.name || self.spyCharacterName || '';

                                    const currentPartyMembers = new Set();
                                    data.players.forEach(player => {
                                        if (player?.character?.name && player.character.name !== currentPlayerName) {
                                            currentPartyMembers.add(player.character.name);
                                        }
                                    });

                                    if (self.partyConsumableTracker) {
                                        Object.keys(self.partyConsumableTracker).forEach(playerName => {
                                            if (!currentPartyMembers.has(playerName)) {
                                                delete self.partyConsumableTracker[playerName];
                                            }
                                        });
                                    }
                                    if (self.partyConsumableSnapshots) {
                                        Object.keys(self.partyConsumableSnapshots).forEach(playerName => {
                                            if (!currentPartyMembers.has(playerName)) {
                                                delete self.partyConsumableSnapshots[playerName];
                                            }
                                        });
                                    }
                                    if (self.lastMinTimes) {
                                        Object.keys(self.lastMinTimes).forEach(playerName => {
                                            if (!currentPartyMembers.has(playerName)) {
                                                delete self.lastMinTimes[playerName];
                                            }
                                        });
                                    }

                                    self.savePartyConsumableTracking();

                                    data.players.forEach(player => {
                                        if (!player || !player.character) return;

                                        const playerName = player.character.name;

                                        if (playerName === currentPlayerName) {
                                            return;
                                        }

                                        if (!self.partyConsumableSnapshots[playerName]) {
                                            self.partyConsumableSnapshots[playerName] = {};
                                        }

                                        if (!self.partyLastKnownConsumables) {
                                            self.partyLastKnownConsumables = {};
                                        }
                                        if (!self.partyLastKnownConsumables[playerName]) {
                                            self.partyLastKnownConsumables[playerName] = {};
                                        }

                                        if (!self.partyConsumableTracker) {
                                            self.partyConsumableTracker = {};
                                        }
                                        if (!self.partyConsumableTracker[playerName]) {
                                            self.partyConsumableTracker[playerName] = self.createPartyTracker();

                                            player.combatConsumables.forEach(consumable => {
                                                if (consumable && consumable.itemHrid) {
                                                    self.partyConsumableTracker[playerName].actualConsumed[consumable.itemHrid] = 0;
                                                    self.partyConsumableTracker[playerName].defaultConsumed[consumable.itemHrid] =
                                                        self.getDefaultConsumed(consumable.itemHrid);
                                                }
                                            });

                                        }

                                        const tracker = self.partyConsumableTracker[playerName];

                                        if (player.combatConsumables && player.combatConsumables.length > 0 && tracker) {
                                            const currentConsumableHrids = new Set(
                                                player.combatConsumables
                                                    .filter(c => c && c.itemHrid)
                                                    .map(c => c.itemHrid)
                                            );

                                            Object.keys(tracker.actualConsumed).forEach(itemHrid => {
                                                if (!currentConsumableHrids.has(itemHrid)) {
                                                    delete tracker.actualConsumed[itemHrid];
                                                    delete tracker.defaultConsumed[itemHrid];
                                                    delete tracker.inventoryAmount[itemHrid];
                                                }
                                            });
                                        }

                                        const currentlySeenHrids = new Set();

                                        if (player.combatConsumables && player.combatConsumables.length > 0) {
                                            player.combatConsumables.forEach(consumable => {
                                                if (!consumable || !consumable.itemHrid) return;

                                                const itemHrid = consumable.itemHrid;
                                                const currentCount = consumable.count;
                                                const previousCount = self.partyConsumableSnapshots[playerName][itemHrid];

                                                currentlySeenHrids.add(itemHrid);

                                                self.partyLastKnownConsumables[playerName][itemHrid] = {
                                                    itemHrid: itemHrid,
                                                    lastSeenCount: currentCount
                                                };

                                                if (previousCount !== undefined) {
                                                    const diff = previousCount - currentCount;

                                                    if (diff === 1) {
                                                        tracker.actualConsumed[itemHrid] = (tracker.actualConsumed[itemHrid] ?? 0) + 1;
                                                        tracker.lastUpdate = Date.now();
                                                    }
                                                }

                                                self.partyConsumableSnapshots[playerName][itemHrid] = currentCount;
                                                tracker.inventoryAmount[itemHrid] = currentCount;
                                            });
                                        }

                                        Object.keys(self.partyLastKnownConsumables[playerName] ?? {}).forEach(itemHrid => {
                                            if (!currentlySeenHrids.has(itemHrid)) {
                                                const previousCount = self.partyConsumableSnapshots[playerName][itemHrid];

                                                if (previousCount !== undefined && previousCount > 0) {
                                                    tracker.inventoryAmount[itemHrid] = 0;
                                                    self.partyConsumableSnapshots[playerName][itemHrid] = 0;
                                                }
                                            }
                                        });
                                    });

                                    self.lastBattleData = data;

                                    self.savePartyConsumableTracking();

                                    self.updateConsumablesDisplay();
                                }
                            }

                            if (self.consumableWaitingForFreshData) {
                                self.consumableWaitingForFreshData = false;
                            }
                        }

                        if (data?.type === 'battle_consumable_ability_updated') {
                            if (data.consumable) {
                                const itemHrid = data.consumable.itemHrid;

                                if (!self.consumableTracker) {
                                    self.consumableTracker = {
                                        consumedCount: {},
                                        inventoryAmount: {},
                                        startTime: Date.now(),
                                        lastUpdate: null,
                                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0
                                    };
                                }

                                if (!self.consumableTracker.startTime) {
                                    self.consumableTracker.startTime = Date.now();
                                }
                                if (!self.consumableTracker.actualStartTime) {
                                    self.consumableTracker.actualStartTime = Date.now();
                                }
                                if (self.consumableTracker.savedPausedMs === undefined) {
                                    self.consumableTracker.savedPausedMs = window.MCS_TOTAL_PAUSED_MS ?? 0;
                                }

                                const isFirstTimeSeen = self.consumableTracker.actualConsumed[itemHrid] === undefined;

                                if (isFirstTimeSeen) {
                                    self.consumableTracker.actualConsumed[itemHrid] = 0;
                                    self.consumableTracker.defaultConsumed[itemHrid] = self.getDefaultConsumed(itemHrid);
                                }

                                self.consumableTracker.actualConsumed[itemHrid]++;
                                self.consumableTracker.lastUpdate = Date.now();

                                self.saveSoloConsumableTracking();
                                self.updateConsumablesDisplay();
                            }
                        }
                    });

                    this._crWsListener = handleWebSocketMessage;
                    window.addEventListener('EquipSpyWebSocketMessage', handleWebSocketMessage);

                    const savedConsumablesMinimized = this.crStorage.get('minimized');
                    this.consumablesIsMinimized = savedConsumablesMinimized === true || savedConsumablesMinimized === 'true';
                    if (this.consumablesIsMinimized) {
                        content.classList.add('mcs-hidden');
                        minimizeBtn.textContent = '+';
                    }
                    let wasDraggedAfterMaximize = false;
                    minimizeBtn.onclick = () => {
                        this.consumablesIsMinimized = !this.consumablesIsMinimized;
                        if (this.consumablesIsMinimized) {
                            content.classList.add('mcs-hidden');
                            minimizeBtn.textContent = '+';
                            this.crStorage.set('minimized', true);
                            this.updateMinimizedSummary();
                            if (this.consumablesPreMaximizePosition && !wasDraggedAfterMaximize) {
                                pane.style.top = this.consumablesPreMaximizePosition.top + 'px';
                                pane.style.left = this.consumablesPreMaximizePosition.left + 'px';
                                pane.style.right = 'auto';
                                this.crStorage.set('position', this.consumablesPreMaximizePosition);
                                this.consumablesPreMaximizePosition = null;
                            }
                        } else {
                            const rect = pane.getBoundingClientRect();
                            this.consumablesPreMaximizePosition = {
                                top: rect.top,
                                left: rect.left
                            };
                            wasDraggedAfterMaximize = false;
                            content.classList.remove('mcs-hidden');
                            minimizeBtn.textContent = '−';
                            this.crStorage.set('minimized', false);
                            const summary = document.getElementById('consumables-minimized-summary');
                            if (summary) summary.remove();
                            this.constrainPanelToBoundaries('consumables-pane', 'mcs_CR', true);
                        }
                    };
                    const savedPos = this.crStorage.get('position');
                    if (savedPos) {
                        pane.style.top = savedPos.top + 'px';
                        pane.style.left = savedPos.left + 'px';
                        pane.style.right = 'auto';
                    }
                    DragHandler.makeDraggable(pane, header, 'mcs_CR');
                    header.addEventListener('dblclick', (e) => {
                        if (e.target.tagName === 'BUTTON') return;
                        minimizeBtn.click();
                    });
                    this.updateConsumablesDisplay();
                }
                async updateMinimizedSummary() {
                    if (this.isUpdatingMinimizedSummary) return;
                    this.isUpdatingMinimizedSummary = true;
                    try {
                        const content = document.getElementById('consumables-content');
                        if (!content || !content.classList.contains('mcs-hidden')) {
                            this.isUpdatingMinimizedSummary = false;
                            return;
                        }
                        const pane = document.getElementById('consumables-pane');
                        if (!pane) {
                            this.isUpdatingMinimizedSummary = false;
                            return;
                        }
                        const cachedData = CharacterDataStorage.get();
                        if (!cachedData) {
                            this.isUpdatingMinimizedSummary = false;
                            return;
                        }
                        const foodSlots = cachedData.actionTypeFoodSlotsMap?.['/action_types/combat'] ?? [];
                        const drinkSlots = cachedData.actionTypeDrinkSlotsMap?.['/action_types/combat'] ?? [];
                        const inventoryByHrid = new Map();
                        if (cachedData.characterItems) {
                            for (const item of cachedData.characterItems) {
                                if (item.itemLocationHrid === '/item_locations/inventory') {
                                    inventoryByHrid.set(item.itemHrid, item);
                                }
                            }
                        }
                        const allConsumables = [];
                        [...foodSlots, ...drinkSlots].forEach(slot => {
                            if (slot && slot.itemHrid) {
                                const inventoryItem = inventoryByHrid.get(slot.itemHrid);
                                if (inventoryItem) {
                                    allConsumables.push({
                                        itemHrid: slot.itemHrid,
                                        count: inventoryItem.count
                                    });
                                }
                            }
                        });
                        if (allConsumables.length === 0) {
                            this.isUpdatingMinimizedSummary = false;
                            return;
                        }
                        let minTime = Infinity;
                        const itemsWithTime = [];
                        allConsumables.forEach(item => {
                            const etaData = this.estimateTimeToZero(item.itemHrid, item.count);
                            if (etaData) {
                                const roundedSeconds = Math.round(etaData.remainingSeconds / 10) * 10;
                                if (roundedSeconds < minTime) {
                                    minTime = roundedSeconds;
                                }
                            }
                            itemsWithTime.push({ item, etaData });
                        });
                        this.updateConsumablesDaysLeft(minTime);
                        const minItems = [];
                        if (minTime === Infinity) {
                            itemsWithTime.forEach(({ item }) => {
                                minItems.push({ itemHrid: item.itemHrid, count: item.count });
                            });
                        } else {
                            itemsWithTime.forEach(({ item, etaData }) => {
                                if (etaData && Math.abs(etaData.remainingSeconds - minTime) <= 60) {
                                    minItems.push({ itemHrid: item.itemHrid, count: item.count });
                                }
                            });
                        }
                        if (minItems.length === 0) {
                            this.isUpdatingMinimizedSummary = false;
                            return;
                        }
                        const minCount = minItems[0].count;

                        this.yourMinTime = minTime;
                        this.minConsumables = minItems;
                        this.minConsumablesCount = minCount;

                        let totalAsk = 0;
                        let totalBid = 0;
                        const price_data = await this.fetchMarketJSON();
                        if (price_data) {
                            allConsumables.forEach(item => {
                                const etaData = this.estimateTimeToZero(item.itemHrid, item.count);
                                if (etaData) {
                                    const prices = this.getItemPrices(item.itemHrid, price_data);
                                    if (prices && etaData.consumedPerDay) {
                                        totalAsk += prices.ask * etaData.consumedPerDay;
                                        totalBid += prices.bid * etaData.consumedPerDay;
                                    }
                                }
                            });
                        }

                        this.totalConsumableAsk = totalAsk;
                        this.totalConsumableBid = totalBid;

                        const summaryKey = minItems.map(i => i.itemHrid).sort().join('|');
                        const existing = document.getElementById('consumables-minimized-summary');

                        if (existing && this._lastMinSummaryKey === summaryKey) {
                            const countEl = existing.querySelector('.mcs-crack-summary-count');
                            if (countEl) countEl.textContent = minCount;
                            const nameEl = existing.querySelector('.mcs-crack-summary-name');
                            if (nameEl && minItems.length === 1) {
                                nameEl.textContent = this.getSpyItemName(minItems[0].itemHrid);
                            }
                            const costEl = existing.querySelector('.mcs-crack-summary-cost-value');
                            if (costEl) {
                                costEl.textContent = 'Ask: ' + this.formatPriceShort(totalAsk) + ' / Bid: ' + this.formatPriceShort(totalBid);
                            }
                        } else {
                            if (existing) existing.remove();
                            this._lastMinSummaryKey = summaryKey;

                            const summary = document.createElement('div');
                            summary.id = 'consumables-minimized-summary';
                            summary.className = 'mcs-crack-minimized-summary';

                            const leftSide = document.createElement('div');
                            leftSide.className = 'mcs-crack-summary-left';

                            const countSpan = document.createElement('span');
                            countSpan.className = 'mcs-crack-summary-count';
                            countSpan.textContent = minCount;
                            leftSide.appendChild(countSpan);

                            minItems.forEach(item => {
                                const iconId = item.itemHrid.split('/').pop();
                                const svgIcon = createItemIcon(iconId, { className: 'mcs-crack-consumable-icon consumable-icon-clickable', clickable: true, itemHrid: item.itemHrid });
                                svgIcon.addEventListener('click', (e) => {
                                    e.stopPropagation();
                                    mcsGoToMarketplace(item.itemHrid);
                                });
                                leftSide.appendChild(svgIcon);
                            });

                            if (minItems.length === 1) {
                                const nameSpan = document.createElement('span');
                                nameSpan.className = 'mcs-crack-summary-name';
                                nameSpan.textContent = this.getSpyItemName(minItems[0].itemHrid);
                                leftSide.appendChild(nameSpan);
                            }
                            summary.appendChild(leftSide);

                            const rightSide = document.createElement('div');
                            rightSide.className = 'mcs-crack-summary-right';
                rightSide.innerHTML = `
            <div class="mcs-crack-summary-cost-label">Total Cost/Day:</div>
            <div class="mcs-crack-summary-cost-value">Ask: ${this.formatPriceShort(totalAsk)} / Bid: ${this.formatPriceShort(totalBid)}</div>
                        `;
                            summary.appendChild(rightSide);
                            const header = pane.querySelector('div:first-child');
                            if (header && header.nextSibling) {
                                pane.insertBefore(summary, header.nextSibling);
                            } else {
                                pane.appendChild(summary);
                            }
                        }
                        this.isUpdatingMinimizedSummary = false;
                    } catch (error) {
                        console.error('[Consumables] Error in updateMinimizedSummary:', error);
                        this.isUpdatingMinimizedSummary = false;
                    }
                }
                updateConsumablesDaysLeft(minTimeSeconds) {
                    const daysLeftSpan = document.getElementById('consumables-days-left');
                    if (!daysLeftSpan) return;
                    if (minTimeSeconds === Infinity || minTimeSeconds === null || minTimeSeconds === undefined) return;
                    daysLeftSpan.textContent = mcsFormatDuration(minTimeSeconds, 'eta');
                    const days = minTimeSeconds / 86400;
                    daysLeftSpan.classList.remove('mcs-crack-eta-critical', 'mcs-crack-eta-warning', 'mcs-crack-eta-good');
                    if (days < 1) {
                        daysLeftSpan.classList.add('mcs-crack-eta-critical');
                    } else if (days < 2) {
                        daysLeftSpan.classList.add('mcs-crack-eta-warning');
                    } else {
                        daysLeftSpan.classList.add('mcs-crack-eta-good');
                    }
                }
                generatePriceHTML(itemHrid, price_data, consumedPerDay) {
                    const prices = this.getItemPrices(itemHrid, price_data);
                    if (!prices) return '';
                    const dailyAskCost = prices.ask * consumedPerDay;
                    const dailyBidCost = prices.bid * consumedPerDay;
                    const askStr = this.formatPriceShort(dailyAskCost);
                    const bidStr = this.formatPriceShort(dailyBidCost);
        return `<span class="mcs-crack-price-text">
        <span>Ask: ${askStr}</span>
        <span>Bid: ${bidStr}</span>
                </span>`;
                }
                async updateConsumablesDisplay() {
                    const price_data = await this.fetchMarketJSON();
                    if (this.consumableWaitingForFreshData) {
                        const content = document.getElementById('consumables-content');
                        if (!content) return;
                        let html = '';
                        html += '<div class="mcs-crack-reset-complete">';
                        html += '<div class="mcs-crack-reset-title">✅ Reset Complete!</div>';
                        html += '<div class="mcs-crack-reset-waiting">⏳ Waiting for fresh data...</div>';
                        html += '<div class="mcs-crack-reset-subtitle">Next battle will initialize tracking</div>';
                        html += '</div>';
                        if (this.consumableResetItems && this.consumableResetItems.length > 0) {
                            html += '<div class="mcs-crack-party-name">Your Consumables:</div>';
                            this.consumableResetItems.forEach(item => {
                                const itemName = this.getSpyItemName(item.itemHrid);
                                const iconId = item.itemHrid.split('/').pop();
                                html += '<div class="consumable-row mcs-crack-consumable-row mcs-crack-consumable-container" data-icon-id="' + iconId + '">';
                                html += '<span class="mcs-crack-consumable-count mcs-crack-count-placeholder">--</span>';
                                html += '<span class="icon-placeholder consumable-icon-clickable mcs-crack-consumable-icon" data-item-hrid="' + item.itemHrid + '" title="Click to open in marketplace"></span>';
                                html += '<span class="mcs-crack-consumable-name mcs-crack-name-placeholder">' + itemName + '</span>';
                                html += '</div>';
                            });
                        }
                        content.innerHTML = html;
                        const self = this;
                        setTimeout(() => {
                            if (self.loadConsumableIcons) {
                                self.loadConsumableIcons();
                            }
                        }, 100);
                        return;
                    }
                    const content = document.getElementById('consumables-content');
                    if (!content) return;

                    let html = '';
                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (!cachedData) {
                            content.innerHTML = '<div class="mcs-crack-no-data">No data</div>';
                            return;
                        }
                        if (!cachedData.actionTypeFoodSlotsMap || !cachedData.actionTypeDrinkSlotsMap) {
                            content.innerHTML = '<div class="mcs-crack-no-data">No consumables</div>';
                            return;
                        }
                        const foodSlots = cachedData.actionTypeFoodSlotsMap['/action_types/combat'] ?? [];
                        const drinkSlots = cachedData.actionTypeDrinkSlotsMap['/action_types/combat'] ?? [];
                        const allConsumables = [];
                        foodSlots.forEach(food => {
                            if (food && food.itemHrid) {
                                const inventoryItem = cachedData.characterItems.find(item => item.itemHrid === food.itemHrid &&
                                    item.itemLocationHrid === '/item_locations/inventory'
                                );
                                if (inventoryItem) {
                                    allConsumables.push({
                                        itemHrid: food.itemHrid,
                                        count: inventoryItem.count,
                                        type: 'food'
                                    });
                                }
                            }
                        });
                        drinkSlots.forEach(drink => {
                            if (drink && drink.itemHrid) {
                                const inventoryItem = cachedData.characterItems.find(item => item.itemHrid === drink.itemHrid &&
                                    item.itemLocationHrid === '/item_locations/inventory'
                                );
                                if (inventoryItem) {
                                    allConsumables.push({
                                        itemHrid: drink.itemHrid,
                                        count: inventoryItem.count,
                                        type: 'drink'
                                    });
                                }
                            }
                        });

                        if (allConsumables.length === 0) {
                            content.innerHTML = '<div class="mcs-crack-no-data">No consumables equipped</div>';
                            return;
                        }
                        if (!this.consumableTracker || !this.consumableTracker.startTime) {
                            this.initConsumableTracking();
                            if (!this.consumableTracker.startTime) {
                                this.consumableTracker.startTime = Date.now();

                                allConsumables.forEach(item => {
                                    this.consumableTracker.inventoryAmount[item.itemHrid] = item.count;
                                    if (!this.consumableTracker.actualConsumed[item.itemHrid]) {
                                        this.consumableTracker.actualConsumed[item.itemHrid] = 0;
                                    }
                                    if (!this.consumableTracker.defaultConsumed[item.itemHrid]) {
                                        this.consumableTracker.defaultConsumed[item.itemHrid] = this.getDefaultConsumed(item.itemHrid);
                                    }
                                });

                                this.saveConsumableTracking();
                            }
                        } else {
                            const crackData = this.crStorage.get('consumable_inventory');

                            allConsumables.forEach(item => {
                                const newAmount = (crackData && crackData[item.itemHrid] !== undefined)
                                    ? crackData[item.itemHrid]
                                    : item.count;

                                this.consumableTracker.inventoryAmount[item.itemHrid] = newAmount;
                                if (this.consumableTracker.actualConsumed[item.itemHrid] === undefined) {
                                    this.consumableTracker.actualConsumed[item.itemHrid] = 0;
                                    this.consumableTracker.defaultConsumed[item.itemHrid] = this.getDefaultConsumed(item.itemHrid);
                                }
                            });
                        }
                        let minTime = Infinity;
                        const itemsWithTime = [];
                        allConsumables.forEach(item => {
                            const itemName = this.getSpyItemName(item.itemHrid);
                            const iconId = item.itemHrid.split('/').pop();
                            const etaData = this.estimateTimeToZero(item.itemHrid, item.count);
                            if (etaData) {
                                const roundedSeconds = Math.round(etaData.remainingSeconds / 30) * 30;
                                if (roundedSeconds < minTime) {
                                    minTime = roundedSeconds;
                                }
                            }
                            itemsWithTime.push({ item, itemName, iconId, etaData });
                        });
                        this.updateConsumablesDaysLeft(minTime);

                        this.yourMinTime = minTime;

                        let entirePartyMinTime = minTime;
                        const battleObj = this.lastBattleData;
                        if (battleObj) {
                            try {
                                if (battleObj.players && battleObj.players.length > 1) {
                                    const currentPlayerName = cachedData?.character?.name || this.spyCharacterName || '';
                                    battleObj.players.forEach(player => {
                                        if (player.name === currentPlayerName) return;
                                        if (player.combatConsumables && player.combatConsumables.length > 0) {
                                            player.combatConsumables.forEach(consumable => {
                                                if (consumable && consumable.itemHrid && consumable.count) {
                                                    const etaData = this.estimateTimeToZeroForPartyMemberTracked(player.name, consumable.itemHrid, consumable.count);
                                                    if (etaData) {
                                                        const roundedSeconds = Math.round(etaData.remainingSeconds / 10) * 10;
                                                        if (roundedSeconds < entirePartyMinTime) {
                                                            entirePartyMinTime = roundedSeconds;
                                                        }
                                                    }
                                                }
                                            });
                                        }
                                    });
                                }
                            } catch (e) {
                                console.error('[Consumables] Error calculating overall min:', e);
                            }
                        }

                        const minItems = [];
                        itemsWithTime.forEach(({ item, etaData }) => {
                            if (etaData && Math.abs(etaData.remainingSeconds - minTime) <= 60) {
                                minItems.push({
                                    itemHrid: item.itemHrid,
                                    count: item.count
                                });
                            }
                        });
                        this.minConsumables = minItems;
                        this.minConsumablesCount = minItems.length > 0 ? minItems[0].count : 0;

                        let playerTotalAsk = 0;
                        let playerTotalBid = 0;
                        itemsWithTime.forEach(({ item, itemName, iconId, etaData }) => {
                            let countColorClass = '';
                            let nameColorClass = '';
                            let timeColorClass = '';
                            if (etaData) {
                                const isOverallMin = Math.abs(etaData.remainingSeconds - entirePartyMinTime) <= 60;
                                const isPlayerMin = Math.abs(etaData.remainingSeconds - minTime) <= 60;
                                if (isOverallMin) {
                                    countColorClass = 'mcs-crack-count-critical';
                                    nameColorClass = 'mcs-crack-consumable-name-warning';
                                    timeColorClass = 'mcs-crack-time-critical';
                                } else if (isPlayerMin) {
                                    countColorClass = 'mcs-crack-count-warning';
                                    nameColorClass = 'mcs-crack-count-warning';
                                    timeColorClass = 'mcs-crack-time-warning';
                                }
                            }
                            const tracker = Object.assign({}, this.consumableTracker, { _etaData: etaData });
                            html += this.renderConsumableRow({
                                itemHrid: item.itemHrid, count: item.count, tracker, iconId, itemName,
                                countColorClass, nameColorClass, timeColorClass,
                                extraAttrs: 'data-item-hrid="' + item.itemHrid + '"',
                                priceData: price_data
                            });
                            if (etaData) {
                                const prices = this.getItemPrices(item.itemHrid, price_data);
                                if (prices && etaData.consumedPerDay) {
                                    playerTotalAsk += prices.ask * etaData.consumedPerDay;
                                    playerTotalBid += prices.bid * etaData.consumedPerDay;
                                }
                            }
                        });
                        html += '<div class="mcs-crack-total-cost">';
                        html += '<span class="mcs-crack-party-name">Total Cost/Day:</span> ';
                        html += '<span>Ask: ' + this.formatPriceShort(playerTotalAsk) + ' / Bid: ' + this.formatPriceShort(playerTotalBid) + '</span>';
                        html += '</div>';
                        window.lootDropsTrackerInstance.consumablesCostPerDayAsk = playerTotalAsk;
                        window.lootDropsTrackerInstance.consumablesCostPerDayBid = playerTotalBid;

                        this.totalConsumableAsk = playerTotalAsk;
                        this.totalConsumableBid = playerTotalBid;
                        if (battleObj) {
                            try {
                                if (battleObj.players && battleObj.players.length > 1) {
                                    const currentPlayerName = cachedData?.character?.name || this.spyCharacterName || '';

                                    if (!this.partyConsumableTracker) {
                                        this.partyConsumableTracker = {};
                                    }
                                    if (!this.lastMinTimes) {
                                        this.lastMinTimes = {};
                                    }

                                    battleObj.players.forEach(player => {
                                        if (player.name === currentPlayerName) return;

                                        if (!this.partyConsumableTracker[player.name] && player.combatConsumables && player.combatConsumables.length > 0) {
                                            this.partyConsumableTracker[player.name] = this.createPartyTracker();

                                            player.combatConsumables.forEach(consumable => {
                                                if (consumable && consumable.itemHrid && consumable.count) {
                                                    this.partyConsumableTracker[player.name].inventoryAmount[consumable.itemHrid] = consumable.count;
                                                    this.partyConsumableTracker[player.name].actualConsumed[consumable.itemHrid] = 0;
                                                    this.partyConsumableTracker[player.name].defaultConsumed[consumable.itemHrid] = this.getDefaultConsumed(consumable.itemHrid);
                                                }
                                            });

                                            this.savePartyConsumableTracking();
                                        }

                                        html += '<div class="mcs-crack-party-section">';
                                        html += `<div class="mcs-crack-party-name">${player.name}</div>`;

                                        const allPlayerConsumables = new Map();

                                        if (player.combatConsumables && player.combatConsumables.length > 0) {
                                            player.combatConsumables.forEach(consumable => {
                                                if (consumable && consumable.itemHrid) {
                                                    allPlayerConsumables.set(consumable.itemHrid, consumable.count);
                                                }
                                            });
                                        }

                                        if (this.partyConsumableTracker[player.name]) {
                                            Object.keys(this.partyConsumableTracker[player.name].inventoryAmount ?? {}).forEach(itemHrid => {
                                                if (!allPlayerConsumables.has(itemHrid)) {
                                                    allPlayerConsumables.set(itemHrid, this.partyConsumableTracker[player.name].inventoryAmount[itemHrid] ?? 0);
                                                }
                                            });
                                        }

                                        if (allPlayerConsumables.size > 0) {
                                            let playerMinTime = Infinity;
                                            let partyMemberTotalAsk = 0;
                                            let partyMemberTotalBid = 0;

                                            allPlayerConsumables.forEach((count, itemHrid) => {
                                                const etaData = this.estimateTimeToZeroForPartyMemberTracked(player.name, itemHrid, count);
                                                if (etaData) {
                                                    const roundedSeconds = Math.round(etaData.remainingSeconds / 30) * 30;
                                                    if (roundedSeconds < playerMinTime) {
                                                        playerMinTime = roundedSeconds;
                                                    }
                                                }
                                            });

                                            const cachedMinTime = this.lastMinTimes[player.name];
                                            if (cachedMinTime !== undefined && Math.abs(playerMinTime - cachedMinTime) < 30) {
                                                playerMinTime = cachedMinTime;
                                            } else {
                                                this.lastMinTimes[player.name] = playerMinTime;
                                            }

                                            allPlayerConsumables.forEach((count, itemHrid) => {
                                                const itemName = this.getSpyItemName(itemHrid);
                                                const iconId = itemHrid.split('/').pop();
                                                const partyTracker = this.partyConsumableTracker[player.name];
                                                const etaData = this.estimateTimeToZeroForPartyMemberTracked(player.name, itemHrid, count);
                                                const isMinItem = (etaData && Math.abs(etaData.remainingSeconds - playerMinTime) <= 60);

                                                if (partyTracker && partyTracker.actualConsumed && partyTracker.defaultConsumed) {
                                                    const tracker = Object.assign({}, partyTracker, { _etaData: etaData });
                                                    const rowAttrs = `data-player-name="${player.name}" data-item-hrid="${itemHrid}" data-is-min="${isMinItem}"`;
                                                    html += this.renderConsumableRow({
                                                        itemHrid, count, tracker, iconId, itemName,
                                                        countColorClass: isMinItem ? 'mcs-crack-count-critical' : '',
                                                        nameColorClass: isMinItem ? 'mcs-crack-consumable-name-warning' : '',
                                                        timeColorClass: isMinItem ? 'mcs-crack-time-critical' : 'mcs-crack-time-normal',
                                                        extraClasses: 'party-consumable-row',
                                                        extraAttrs: rowAttrs,
                                                        priceData: price_data
                                                    });
                                                } else {
                                                    html += '<div class="mcs-crack-consumable-container"><span class="mcs-crack-tracker-error">Tracker Error</span></div>';
                                                }
                                                if (etaData) {
                                                    const prices = this.getItemPrices(itemHrid, price_data);
                                                    if (prices && etaData.consumedPerDay) {
                                                        partyMemberTotalAsk += prices.ask * etaData.consumedPerDay;
                                                        partyMemberTotalBid += prices.bid * etaData.consumedPerDay;
                                                    }
                                                }
                                            });
                                            html += '<div class="mcs-crack-total-cost">';
                                            html += '<span class="mcs-crack-party-name">Total Cost/Day:</span> ';
                                            html += '<span>Ask: ' + this.formatPriceShort(partyMemberTotalAsk) + ' / Bid: ' + this.formatPriceShort(partyMemberTotalBid) + '</span>';
                                            html += '</div>';
                                            if (player.name === currentPlayerName) {
                                                window.lootDropsTrackerInstance.consumablesCostPerDayAsk = partyMemberTotalAsk;
                                                window.lootDropsTrackerInstance.consumablesCostPerDayBid = partyMemberTotalBid;
                                            }
                                        } else {
                                            html += '<div class="mcs-crack-no-data">No consumables</div>';
                                        }
                                        html += '</div>';
                                    });
                                }
                            } catch (e) {
                                console.error('[Consumables] Error parsing party data:', e);
                            }
                        }
                        content.innerHTML = html;
                        if (battleObj) {
                            try {
                                const partyEtaContainer = document.getElementById('party-eta-container');
                                if (battleObj.players && battleObj.players.length > 1) {
                                    if (partyEtaContainer) {
                                        partyEtaContainer.classList.remove('mcs-hidden');
                                    }
                                    let partyMinEta = Infinity;
                                    const currentPlayerName = cachedData?.character?.name || this.spyCharacterName || '';
                                    battleObj.players.forEach(player => {
                                        if (player.name === currentPlayerName) return;
                                        if (player.combatConsumables && player.combatConsumables.length > 0) {
                                            player.combatConsumables.forEach(consumable => {
                                                if (consumable && consumable.itemHrid && consumable.count !== undefined) {
                                                    if (consumable.count === 0) {
                                                        partyMinEta = 0;
                                                    } else {
                                                        const etaData = this.estimateTimeToZeroForPartyMemberTracked(player.name, consumable.itemHrid, consumable.count);
                                                        if (etaData && etaData.remainingSeconds < partyMinEta) {
                                                            partyMinEta = etaData.remainingSeconds;
                                                        }
                                                    }
                                                }
                                            });
                                        }
                                    });

                                    this.partyMinTime = partyMinEta;

                                    const partyEtaSpan = document.getElementById('party-min-eta');
                                    if (partyEtaSpan) {
                                        partyEtaSpan.classList.remove('mcs-crack-party-eta-disabled', 'mcs-crack-party-eta-critical', 'mcs-crack-party-eta-warning', 'mcs-crack-party-eta-good');
                                        if (partyMinEta === Infinity) {
                                            partyEtaSpan.textContent = 'Waiting...';
                                            partyEtaSpan.classList.add('mcs-crack-party-eta-disabled');
                                        } else {
                                            partyEtaSpan.textContent = mcsFormatDuration(partyMinEta, 'eta');
                                            const days = partyMinEta / 86400;
                                            if (days < 1) {
                                                partyEtaSpan.classList.add('mcs-crack-party-eta-critical');
                                            } else if (days < 2) {
                                                partyEtaSpan.classList.add('mcs-crack-party-eta-warning');
                                            } else {
                                                partyEtaSpan.classList.add('mcs-crack-party-eta-good');
                                            }
                                        }
                                    }
                                } else {
                                    if (partyEtaContainer) {
                                        partyEtaContainer.classList.add('mcs-hidden');
                                    }
                                }
                            } catch (e) {
                                console.error('[Consumables] Error updating party ETA:', e);
                            }
                        }
                    } catch (error) {
                        console.error('[Consumables] Error in updateConsumablesDisplay:', error);
                        console.error('[Consumables] Error stack:', error.stack);
                        content.innerHTML = '<div class="mcs-crack-tracker-error">Error loading consumables</div>';
                    }
                    if (this.consumablesIsMinimized) {
                        this.updateMinimizedSummary();
                    }
                }
                openConsumableMarketplace(itemHrid) {
                    mcsGoToMarketplace(itemHrid);
                }
                loadConsumableIcons() {
                    const content = document.getElementById('consumables-content');
                    if (!content) {
                        return;
                    }

                    const rows = content.querySelectorAll('.consumable-row');

                    rows.forEach(row => {
                        const iconId = row.getAttribute('data-icon-id');
                        if (!iconId) return;

                        const placeholder = row.querySelector('.icon-placeholder');
                        if (!placeholder) return;

                        if (placeholder.querySelector('svg')) return;

                        placeholder.appendChild(createItemIcon(iconId, { className: 'mcs-crack-consumable-icon' }));
                    });
                }
                destroyCRack() {
                    if (this._crWsListener) {
                        window.removeEventListener('EquipSpyWebSocketMessage', this._crWsListener);
                        this._crWsListener = null;
                    }
                    const pane = document.getElementById('consumables-pane');
                    if (pane) pane.remove();
                }

// CRackUI end

// HWhat start

            get hwStorage() {
                if (!this._hwStorage) {
                    this._hwStorage = createModuleStorage('HW');
                }
                return this._hwStorage;
            }

            _updateCowbellCache(characterItems) {
                if (!this._cowbellCache) {
                    this._cowbellCache = {
                        cowbellCount: 0,
                        bagCount: 0,
                        lastUpdate: 0,
                        cacheDuration: 5000
                    };
                }
                if (!characterItems || !Array.isArray(characterItems)) return;

                const cowbellItem = characterItems.find(item => item.itemHrid === '/items/cowbell');
                const bagItem = characterItems.find(item => item.itemHrid === '/items/bag_of_10_cowbells');

                this._cowbellCache.cowbellCount = cowbellItem ? (cowbellItem.count || 0) : 0;
                this._cowbellCache.bagCount = bagItem ? (bagItem.count || 0) : 0;
                this._cowbellCache.lastUpdate = Date.now();
            }

            _getCowbellCounts() {
                if (!this._cowbellCache) {
                    this._cowbellCache = {
                        cowbellCount: 0,
                        bagCount: 0,
                        lastUpdate: 0,
                        cacheDuration: 5000
                    };
                }

                const now = Date.now();
                if (now - this._cowbellCache.lastUpdate > this._cowbellCache.cacheDuration) {
                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData) {
                            this._updateCowbellCache(cachedData.characterItems);
                        }
                    } catch (e) {
                        console.error('[HWhat] Error refreshing cowbell cache:', e);
                    }
                }
                return {
                    cowbellCount: this._cowbellCache.cowbellCount,
                    bagCount: this._cowbellCache.bagCount
                };
            }

            _updateCharacterItemsInStorage(endCharacterItems) {
                if (!endCharacterItems) return false;

                try {
                    const characterData = CharacterDataStorage.get();
                    if (!characterData) return false;

                    let hasChanges = false;

                    endCharacterItems.forEach(updatedItem => {
                        const existingItem = characterData.characterItems.find(
                            item => item.itemHrid === updatedItem.itemHrid
                        );
                        if (existingItem) {
                            if (existingItem.count !== updatedItem.count) {
                                existingItem.count = updatedItem.count;
                                hasChanges = true;
                            }
                        } else {
                            characterData.characterItems.push(updatedItem);
                            hasChanges = true;
                        }
                    });

                    if (hasChanges) {
                        CharacterDataStorage.set(characterData);
                        this._updateCowbellCache(characterData.characterItems);
                    }

                    return hasChanges;
                } catch (e) {
                    console.error('[HWhat] Error updating character items:', e);
                    return false;
                }
            }

            hwhatHandleBattle() {
                setTimeout(() => this.updateHWhatDisplay(), 100);
            }

            hwhatHandleWebSocketMessage(event) {
                if (window.MCS_MODULES_DISABLED) return;
                const data = event.detail;
                if (data?.type === 'init_character_data' && data.characterItems) {
                    this._updateCowbellCache(data.characterItems);
                    setTimeout(() => this.updateHWhatDisplay(), 100);
                }
                if ((data?.type === 'action_completed' || data?.type === 'items_updated') && data.endCharacterItems) {
                    if (this._updateCharacterItemsInStorage(data.endCharacterItems)) {
                        setTimeout(() => this.updateHWhatDisplay(), 100);
                    }
                }
            }

            hwhatHandleStorage(event) {
                if (event.key && event.key.startsWith('mcs__global_init_character_data')) {
                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData) {
                            if (cachedData.characterItems) {
                                this._updateCowbellCache(cachedData.characterItems);
                                if (window.lootDropsTrackerInstance) {
                                    window.lootDropsTrackerInstance.spyCharacterItems = cachedData.characterItems;
                                }
                            }
                        }
                    } catch (e) {
                        console.error('[HWhat] Error syncing inventory from storage event:', e);
                    }
                    setTimeout(() => this.updateHWhatDisplay(), 100);
                }
            }

            createHWhatPanel() {
                if (document.getElementById('hwhat-pane')) {
                    return;
                }
                const hwhatPane = document.createElement('div');
                hwhatPane.id = 'hwhat-pane';
                registerPanel('hwhat-pane');
                hwhatPane.className = 'mcs-pane mcs-hw-pane';
    hwhatPane.innerHTML = `
<div id="hwhat-header" class="mcs-pane-header">
    <div class="mcs-hw-header-left">
        <span class="mcs-pane-title mcs-hw-title">HWhat</span>
        <span id="hwhat-combat-status" class="mcs-hw-combat-status">Not in Combat</span>
        <div id="hwhat-header-calc" class="mcs-hw-header-calc">
            <span class="mcs-hw-color-green"><span id="hwhat-header-revenue">0</span></span>
            <span class="mcs-hw-color-white"> - </span>
            <span id="hwhat-header-tax-section" class="mcs-hw-header-tax-section">
                <div id="hwhat-header-tax-icon-placeholder" class="mcs-hw-header-tax-icon"></div>
                <span class="mcs-hw-color-tax"><span id="hwhat-header-tax">0</span></span>
                <span class="mcs-hw-color-white"> - </span>
            </span>
            <span class="mcs-hw-color-red"><span id="hwhat-header-cost">0</span></span>
            <span class="mcs-hw-color-white"> = </span>
            <span class="mcs-hw-color-gold"><span id="hwhat-header-profit">0</span>/day</span>
        </div>
    </div>
    <div class="mcs-button-section">
        <button id="hwhat-costs-toggle" class="mcs-hw-toggle-btn">Costs On</button>
        <button id="hwhat-mode-toggle" class="mcs-hw-toggle-btn">Lazy</button>
        <button id="hwhat-minimize-btn" class="mcs-hw-toggle-btn">-</button>
    </div>
</div>
<div id="hwhat-content" class="mcs-hw-content">
        <div id="hwhat-maximized">
<div id="hwhat-tax-section" class="mcs-hw-tax-section">
    <div id="hwhat-tax-icon-placeholder" class="mcs-hw-tax-icon"></div>
    <div class="mcs-hw-tax-details">
        <div id="hwhat-tax-header" class="mcs-hw-tax-header-text">Pay the Tax!</div>
        <div class="mcs-hw-profit-value mcs-hw-color-tax"><span id="hwhat-tax-cost">0</span> coin/day</div>
        <div class="mcs-hw-info-text">
    25 Bag of 10 Cowbells per week <span id="hwhat-bags-needed" class="mcs-hw-bags-needed">(You need 0 bags)</span>
</div>
    </div>
    <button id="hwhat-tax-toggle" class="mcs-hw-toggle-btn mcs-hw-tax-toggle">No thanks ima swipe</button>
</div>
<div class="mcs-hw-profit-box mcs-hw-lazy-box">
    <div class="mcs-hw-profit-title mcs-hw-color-green">Lazy Profit</div>
    <div class="mcs-hw-profit-value mcs-hw-color-green"><span id="hwhat-lazy-profit">0</span> coin/day</div>
    <div class="mcs-hw-info-text">Revenue (Bid) - Cost (Ask)</div>
    <div class="mcs-hw-equation mcs-hw-lazy-equation">
        <span id="hwhat-lazy-equation">0 - 0 = 0</span>
    </div>
</div>
<div class="mcs-hw-profit-box mcs-hw-mid-box">
    <div class="mcs-hw-profit-title mcs-hw-color-blue">Mid Profit</div>
    <div class="mcs-hw-profit-value mcs-hw-color-blue"><span id="hwhat-mid-profit">0</span> coin/day</div>
    <div class="mcs-hw-info-text">Revenue (Ask) - Cost (Bid)</div>
    <div class="mcs-hw-equation mcs-hw-mid-equation">
        <span id="hwhat-mid-equation">0 - 0 = 0</span>
    </div>
</div>
<div class="mcs-hw-diff-box">
    <div class="mcs-hw-profit-title mcs-hw-color-gold">Difference</div>
    <div class="mcs-hw-profit-value mcs-hw-color-gold"><span id="hwhat-difference">0</span> coin/day</div>
    <div class="mcs-hw-diff-message">Don't be lazy!</div>
</div>
        </div>
    </div>
            `;
                document.body.appendChild(hwhatPane);
                setTimeout(() => {
                    const placeholder = document.getElementById('hwhat-tax-icon-placeholder');
                    if (placeholder) {
                        const svgIcon = createItemIcon('bag_of_10_cowbells', { width: 80, height: 80 });
                        svgIcon.style.flexShrink = '0';
                        placeholder.replaceWith(svgIcon);
                    }
                    const headerTaxPlaceholder = document.getElementById('hwhat-header-tax-icon-placeholder');
                    if (headerTaxPlaceholder) {
                        const svgIcon = createItemIcon('bag_of_10_cowbells', { width: 16, height: 16 });
                        svgIcon.style.verticalAlign = 'middle';
                        svgIcon.style.marginRight = '2px';
                        headerTaxPlaceholder.replaceWith(svgIcon);
                    }
                }, 100);
                const savedPos = this.hwStorage.get('position');
                if (savedPos) {
                    hwhatPane.style.top = savedPos.top + 'px';
                    hwhatPane.style.left = savedPos.left + 'px';
                }
                const savedMinimized = this.hwStorage.get('minimized');
                this.hwhatIsMinimized = savedMinimized === true || savedMinimized === 'true';
                this.updateHWhatMinimizeState();
                const header = document.getElementById('hwhat-header');
                DragHandler.makeDraggable(hwhatPane, header, 'mcs_HW');
                if (this.hwStorage.get('mode') === null) {
                    this.hwStorage.set('mode', 'lazy');
                }
                this.hwhatMode = this.hwStorage.get('mode') || 'lazy';
                const modeToggle = document.getElementById('hwhat-mode-toggle');
                if (modeToggle) {
                    modeToggle.textContent = this.hwhatMode === 'lazy' ? 'Lazy' : 'Mid';
                    modeToggle.style.background = this.hwhatMode === 'lazy' ? 'rgba(76, 175, 80, 0.3)' : 'rgba(33, 150, 243, 0.3)';
                    modeToggle.style.borderColor = this.hwhatMode === 'lazy' ? 'rgba(76, 175, 80, 0.5)' : 'rgba(33, 150, 243, 0.5)';
                    modeToggle.style.color = this.hwhatMode === 'lazy' ? '#4CAF50' : '#2196F3';
                }
                document.getElementById('hwhat-minimize-btn').onclick = () => this.toggleHWhatMinimize();
                document.getElementById('hwhat-mode-toggle').onclick = () => this.toggleHWhatMode();
                if (this.hwStorage.get('costs_enabled') === null) {
                    this.hwStorage.set('costs_enabled', true);
                }
                const savedCostsEnabled = this.hwStorage.get('costs_enabled');
                this.hwhatCostsEnabled = savedCostsEnabled === true || savedCostsEnabled === 'true';
                const costsToggle = document.getElementById('hwhat-costs-toggle');
                if (costsToggle) {
                    costsToggle.textContent = this.hwhatCostsEnabled ? 'Costs On' : 'Costs Off';
                }
                document.getElementById('hwhat-costs-toggle').onclick = () => this.toggleHWhatCosts();
                if (this.hwStorage.get('cowbell_tax_enabled') === null) {
                    this.hwStorage.set('cowbell_tax_enabled', false);
                }
                const savedTaxEnabled = this.hwStorage.get('cowbell_tax_enabled');
                this.hwhatCowbellTaxEnabled = savedTaxEnabled === true || savedTaxEnabled === 'true';
                const taxToggle = document.getElementById('hwhat-tax-toggle');
                const taxHeader = document.getElementById('hwhat-tax-header');
                if (taxToggle) {
                    taxToggle.textContent = this.hwhatCowbellTaxEnabled ? 'No thanks ima swipe' : 'Moooooooooooo';
                    taxToggle.style.background = this.hwhatCowbellTaxEnabled ? 'rgba(220, 53, 69, 0.3)' : 'rgba(255, 255, 255, 0.1)';
                    taxToggle.style.borderColor = this.hwhatCowbellTaxEnabled ? 'rgba(220, 53, 69, 0.5)' : 'rgba(255, 255, 255, 0.3)';
                    taxToggle.style.color = this.hwhatCowbellTaxEnabled ? '#dc3545' : 'white';
                }
                if (taxHeader) {
                    taxHeader.textContent = this.hwhatCowbellTaxEnabled ? 'Paying the Tax!' : 'Pay the Tax!';
                }
                document.getElementById('hwhat-tax-toggle').onclick = () => this.toggleHWhatCowbellTax();

                const savedStates = ToolVisibilityStorage.get();
                this.hwhatShowFullNumbers = savedStates['hwhat-full-numbers'] !== false;

                const waitForData = setInterval(() => {
                    if (this.spyMarketData && Object.keys(this.spyMarketData).length > 0) {
                        clearInterval(waitForData);
                        this.updateHWhatDisplay();
                    }
                }, 500);
                setTimeout(() => {
                    clearInterval(waitForData);
                    this.updateHWhatDisplay();
                }, 5000);
                this._hwhatBattleListener = this.hwhatHandleBattle.bind(this);
                this._hwhatCombatEndedListener = this.hwhatHandleBattle.bind(this);
                this._hwhatWsListener = this.hwhatHandleWebSocketMessage.bind(this);
                this._hwhatStorageListener = this.hwhatHandleStorage.bind(this);
                window.addEventListener('LootTrackerBattle', this._hwhatBattleListener);
                window.addEventListener('LootTrackerCombatEnded', this._hwhatCombatEndedListener);
                window.addEventListener('EquipSpyWebSocketMessage', this._hwhatWsListener);
                window.addEventListener('storage', this._hwhatStorageListener);

                VisibilityManager.register('hwhat-update', () => {
                    const hwhatPane = document.getElementById('hwhat-pane');
                    if (!hwhatPane) {
                        VisibilityManager.clear('hwhat-update');
                        return;
                    }

                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData && window.lootDropsTrackerInstance) {
                            if (cachedData.characterItems) {
                                const oldItems = window.lootDropsTrackerInstance.spyCharacterItems ?? [];
                                const newItems = cachedData.characterItems;

                                if (oldItems.length !== newItems.length) {
                                    window.lootDropsTrackerInstance.spyCharacterItems = newItems;
                                } else {
                                    let hasChanges = false;
                                    for (const newItem of newItems) {
                                        const oldItem = oldItems.find(i => i.itemHrid === newItem.itemHrid);
                                        if (!oldItem || oldItem.count !== newItem.count) {
                                            hasChanges = true;
                                            break;
                                        }
                                    }
                                    if (hasChanges) {
                                        window.lootDropsTrackerInstance.spyCharacterItems = newItems;
                                    }
                                }
                            }
                        }
                    } catch (e) {
                        console.error('[HWhat] Error syncing inventory in fallback:', e);
                    }

                    this.updateHWhatDisplay();
                }, 5000);
            }

            toggleHWhatMinimize() {
                this.hwhatIsMinimized = !this.hwhatIsMinimized;
                this.hwStorage.set('minimized', this.hwhatIsMinimized);
                this.updateHWhatMinimizeState();
            }

            toggleHWhatMode() {
                this.hwhatMode = this.hwhatMode === 'lazy' ? 'mid' : 'lazy';
                this.hwStorage.set('mode', this.hwhatMode);
                const modeToggle = document.getElementById('hwhat-mode-toggle');
                if (modeToggle) {
                    modeToggle.textContent = this.hwhatMode === 'lazy' ? 'Lazy' : 'Mid';
                    modeToggle.style.background = this.hwhatMode === 'lazy' ? 'rgba(76, 175, 80, 0.3)' : 'rgba(33, 150, 243, 0.3)';
                    modeToggle.style.borderColor = this.hwhatMode === 'lazy' ? 'rgba(76, 175, 80, 0.5)' : 'rgba(33, 150, 243, 0.5)';
                    modeToggle.style.color = this.hwhatMode === 'lazy' ? '#4CAF50' : '#2196F3';
                }
                this.updateHWhatDisplay();
                if (this.updateProfitCostDisplay) {
                    this.updateProfitCostDisplay();
                }
                if (this.purchaseTimerIntervals) {
                    Object.values(this.purchaseTimerIntervals).forEach(interval => clearInterval(interval));
                    this.purchaseTimerIntervals = {};
                }
                if (this.purchaseTimerInterval) {
                    clearInterval(this.purchaseTimerInterval);
                    this.purchaseTimerInterval = null;
                }
                if (this.updateLockedTimers) {
                    this.updateLockedTimers();
                }
                if (this.updateSpyDisplay) {
                    this.updateSpyDisplay();
                }
                if (this.updateHeaderStatus) {
                    this.updateHeaderStatus();
                }
            }

            toggleHWhatCosts() {
                this.hwhatCostsEnabled = !this.hwhatCostsEnabled;
                this.hwStorage.set('costs_enabled', this.hwhatCostsEnabled);
                const costsToggle = document.getElementById('hwhat-costs-toggle');
                if (costsToggle) {
                    costsToggle.textContent = this.hwhatCostsEnabled ? 'Costs On' : 'Costs Off';
                }
                this.updateHWhatDisplay();
                if (this.updateProfitCostDisplay) {
                    this.updateProfitCostDisplay();
                }
                if (this.purchaseTimerIntervals) {
                    Object.values(this.purchaseTimerIntervals).forEach(interval => clearInterval(interval));
                    this.purchaseTimerIntervals = {};
                }
                if (this.purchaseTimerInterval) {
                    clearInterval(this.purchaseTimerInterval);
                    this.purchaseTimerInterval = null;
                }
                if (this.updateLockedTimers) {
                    this.updateLockedTimers();
                }
                if (this.updateSpyDisplay) {
                    this.updateSpyDisplay();
                }
                if (this.updateHeaderStatus) {
                    this.updateHeaderStatus();
                }
            }

            toggleHWhatCowbellTax() {
                this.hwhatCowbellTaxEnabled = !this.hwhatCowbellTaxEnabled;
                this.hwStorage.set('cowbell_tax_enabled', this.hwhatCowbellTaxEnabled);
                const taxToggle = document.getElementById('hwhat-tax-toggle');
                const taxHeader = document.getElementById('hwhat-tax-header');
                if (taxToggle) {
                    taxToggle.textContent = this.hwhatCowbellTaxEnabled ? 'No thanks ima swipe' : 'Moooooooooooo';
                    taxToggle.style.background = this.hwhatCowbellTaxEnabled ? 'rgba(220, 53, 69, 0.3)' : 'rgba(255, 255, 255, 0.1)';
                    taxToggle.style.borderColor = this.hwhatCowbellTaxEnabled ? 'rgba(220, 53, 69, 0.5)' : 'rgba(255, 255, 255, 0.3)';
                    taxToggle.style.color = this.hwhatCowbellTaxEnabled ? '#dc3545' : 'white';
                }
                if (taxHeader) {
                    taxHeader.textContent = this.hwhatCowbellTaxEnabled ? 'Paying the Tax!' : 'Pay the Tax!';
                }
                this.updateHWhatDisplay();
                if (this.updateProfitCostDisplay) {
                    this.updateProfitCostDisplay();
                }
                if (this.purchaseTimerIntervals) {
                    Object.values(this.purchaseTimerIntervals).forEach(interval => clearInterval(interval));
                    this.purchaseTimerIntervals = {};
                }
                if (this.purchaseTimerInterval) {
                    clearInterval(this.purchaseTimerInterval);
                    this.purchaseTimerInterval = null;
                }
                if (this.updateLockedTimers) {
                    this.updateLockedTimers();
                }
                if (this.updateSpyDisplay) {
                    this.updateSpyDisplay();
                }
                if (this.updateHeaderStatus) {
                    this.updateHeaderStatus();
                }
            }

            updateHWhatMinimizeState() {
                const maximizedDiv = document.getElementById('hwhat-maximized');
                const contentDiv = document.getElementById('hwhat-content');
                const headerDiv = document.getElementById('hwhat-header');
                const btn = document.getElementById('hwhat-minimize-btn');
                if (!maximizedDiv || !btn) return;
                if (this.hwhatIsMinimized) {
                    maximizedDiv.style.display = 'none';
                    if (contentDiv) contentDiv.style.display = 'none';
                    if (headerDiv) headerDiv.style.borderRadius = '6px';
                    btn.textContent = '+';
                } else {
                    maximizedDiv.style.display = 'block';
                    if (contentDiv) contentDiv.style.display = 'block';
                    if (headerDiv) headerDiv.style.borderRadius = '6px 6px 0 0';
                    btn.textContent = '-';
                    this.constrainPanelToBoundaries('hwhat-pane', 'mcs_HW', true);
                }
            }

            updateHWhatDisplay() {
                let inCombat = window.MCS_IN_COMBAT === true;
                if (window.lootDropsTrackerInstance?.isLiveSessionActive) {
                    inCombat = true;
                }
                const combatStatusEl = document.getElementById('hwhat-combat-status');
                if (combatStatusEl) {
                    combatStatusEl.style.display = inCombat ? 'none' : 'inline';
                }

                if (!inCombat && this.hwhatFrozenValues) {
                    const frozen = this.hwhatFrozenValues;
                    this.updateHWhatDisplayElements(frozen);
                    return;
                }

                const tracker = window.lootDropsTrackerInstance;
                const userName = tracker?.userName;
                const revenue = (tracker?.flootPlayerRevenue?.[userName]?.perDay) ?? 0;

                const costBid = this.hwhatCostsEnabled ? this.consumableCost('bid') : 0;
                const costAsk = this.hwhatCostsEnabled ? this.consumableCost('ask') : 0;
                let cowbellTaxPerDay = 0;
                let bagsNeeded = 0;
                if (this.hwhatCowbellTaxEnabled) {
                    bagsNeeded = this.calculateNeededCowbellBags();
                    const cowbellItem = this.spyMarketData['/items/bag_of_10_cowbells'];
                    if (cowbellItem && cowbellItem['0'] && cowbellItem['0'].a) {
                        const bagsPerWeek = Math.max(0, 25 - (this.calculateOwnedCowbellBags ? this.calculateOwnedCowbellBags() : 0));
                        cowbellTaxPerDay = (cowbellItem['0'].a * bagsPerWeek) / 7;
                    }
                }
                const lazyProfit = revenue - costAsk - (this.hwhatCowbellTaxEnabled ? cowbellTaxPerDay : 0);
                const midProfit = revenue - costBid - (this.hwhatCowbellTaxEnabled ? cowbellTaxPerDay : 0);
                const difference = midProfit - lazyProfit;
                const currentMode = this.hwhatMode || 'lazy';
                const currentCost = currentMode === 'lazy' ? costAsk : costBid;
                const currentProfit = currentMode === 'lazy' ? lazyProfit : midProfit;

                this.hwhatCurrentRevenue = revenue;
                this.hwhatCurrentCost = currentCost;
                this.hwhatCurrentProfit = currentProfit;
                this.hwhatCostBid = costBid;
                this.hwhatCostAsk = costAsk;
                this.hwhatCowbellTaxPerDay = cowbellTaxPerDay;
                this.hwhatTaxEnabled = this.hwhatCowbellTaxEnabled && cowbellTaxPerDay > 0;

                if (inCombat) {
                    this.hwhatFrozenValues = {
                        revenue, costBid, costAsk,
                        cowbellTaxPerDay, bagsNeeded,
                        lazyProfit, midProfit, difference,
                        currentCost, currentProfit
                    };
                }

                this.updateHWhatDisplayElements({
                    revenue, costBid, costAsk,
                    cowbellTaxPerDay, bagsNeeded,
                    lazyProfit, midProfit, difference,
                    currentCost, currentProfit
                });
            }

            updateHWhatDisplayElements(values) {
                const {
                    revenue, costBid, costAsk,
                    cowbellTaxPerDay, bagsNeeded,
                    lazyProfit, midProfit, difference,
                    currentCost, currentProfit
                } = values;

                const headerRevenueEl = document.getElementById('hwhat-header-revenue');
                const headerCostEl = document.getElementById('hwhat-header-cost');
                const headerProfitEl = document.getElementById('hwhat-header-profit');
                const headerTaxSection = document.getElementById('hwhat-header-tax-section');
                const headerTaxEl = document.getElementById('hwhat-header-tax');
                if (headerRevenueEl) headerRevenueEl.textContent = this.formatGoldNumber(revenue);
                if (headerCostEl) headerCostEl.textContent = this.formatGoldNumber(currentCost);
                if (headerProfitEl) headerProfitEl.textContent = this.formatGoldNumber(currentProfit);
                if (headerTaxSection && headerTaxEl) {
                    if (this.hwhatCowbellTaxEnabled && cowbellTaxPerDay > 0) {
                        headerTaxSection.style.display = 'inline';
                        headerTaxEl.textContent = this.formatGoldNumber(cowbellTaxPerDay);
                    } else {
                        headerTaxSection.style.display = 'none';
                    }
                }
                const lazyProfitEl = document.getElementById('hwhat-lazy-profit');
                const midProfitEl = document.getElementById('hwhat-mid-profit');
                const differenceEl = document.getElementById('hwhat-difference');
                const lazyEquationEl = document.getElementById('hwhat-lazy-equation');
                const midEquationEl = document.getElementById('hwhat-mid-equation');
                if (lazyProfitEl) lazyProfitEl.textContent = this.formatGoldNumber(lazyProfit);
                if (midProfitEl) midProfitEl.textContent = this.formatGoldNumber(midProfit);
                if (differenceEl) differenceEl.textContent = this.formatGoldNumber(difference);
                const taxCostEl = document.getElementById('hwhat-tax-cost');
                if (taxCostEl) {
                    taxCostEl.textContent = this.formatGoldNumber(cowbellTaxPerDay);
                }
                if (lazyEquationEl) {
                    if (this.hwhatCowbellTaxEnabled && cowbellTaxPerDay > 0) {
                        lazyEquationEl.textContent = `${this.formatGoldNumber(revenue)} - ${this.formatGoldNumber(costAsk)} - ${this.formatGoldNumber(cowbellTaxPerDay)} = ${this.formatGoldNumber(lazyProfit)}`;
                    } else {
                        lazyEquationEl.textContent = `${this.formatGoldNumber(revenue)} - ${this.formatGoldNumber(costAsk)} = ${this.formatGoldNumber(lazyProfit)}`;
                    }
                }
                if (midEquationEl) {
                    if (this.hwhatCowbellTaxEnabled && cowbellTaxPerDay > 0) {
                        midEquationEl.textContent = `${this.formatGoldNumber(revenue)} - ${this.formatGoldNumber(costBid)} - ${this.formatGoldNumber(cowbellTaxPerDay)} = ${this.formatGoldNumber(midProfit)}`;
                    } else {
                        midEquationEl.textContent = `${this.formatGoldNumber(revenue)} - ${this.formatGoldNumber(costBid)} = ${this.formatGoldNumber(midProfit)}`;
                    }
                }
                const bagsNeededEl = document.getElementById('hwhat-bags-needed');
                if (bagsNeededEl) {
                    bagsNeededEl.textContent = `(You need ${bagsNeeded} bag${bagsNeeded !== 1 ? 's' : ''})`;
                    if (bagsNeeded === 0) {
                        bagsNeededEl.style.color = '#4CAF50';
                    } else if (bagsNeeded <= 10) {
                        bagsNeededEl.style.color = '#ffa500';
                    } else {
                        bagsNeededEl.style.color = '#dc3545';
                    }
                }
            }

            calculateNeededCowbellBags() {
                try {
                    const { cowbellCount, bagCount } = this._getCowbellCounts();
                    const totalCowbellsOwned = cowbellCount + (10 * bagCount);
                    const cowbellsNeeded = Math.max(0, 250 - totalCowbellsOwned);
                    const bagsNeeded = Math.ceil(cowbellsNeeded / 10);
                    return bagsNeeded;
                } catch (e) {
                    console.error('[HWhat] Error calculating needed cowbell bags:', e);
                    return 0;
                }
            }

            calculateOwnedCowbellBags() {
                try {
                    const { cowbellCount, bagCount } = this._getCowbellCounts();
                    const totalCowbellsOwned = cowbellCount + (10 * bagCount);
                    const equivalentBags = Math.floor(totalCowbellsOwned / 10);
                    return equivalentBags;
                } catch (e) {
                    console.error('[HWhat] Error calculating owned cowbell bags:', e);
                    return 0;
                }
            }

            startHWhatCowbellPolling() {
            }

            consumableCost(priceType) {
                if (!window.lootDropsTrackerInstance) {
                    return 0;
                }
                const cost = priceType === 'ask'
                    ? (window.lootDropsTrackerInstance.consumablesCostPerDayAsk || 0)
                    : (window.lootDropsTrackerInstance.consumablesCostPerDayBid || 0);
                return cost;
            }

            getItemPriceForCostCustom(itemHrid, priceType) {
                if (!this.spyMarketData || !this.spyMarketData[itemHrid]) {
                    return 0;
                }
                const itemData = this.spyMarketData[itemHrid];
                const level0Data = itemData[0];
                if (!level0Data) {
                    return 0;
                }
                const price = priceType === 'ask' ?
                    (level0Data.a || 0) :
                    (level0Data.b || 0);
                return price;
            }

            destroyHWhat() {
                VisibilityManager.clear('hwhat-update');
                if (this._hwhatBattleListener) { window.removeEventListener('LootTrackerBattle', this._hwhatBattleListener); this._hwhatBattleListener = null; }
                if (this._hwhatCombatEndedListener) { window.removeEventListener('LootTrackerCombatEnded', this._hwhatCombatEndedListener); this._hwhatCombatEndedListener = null; }
                if (this._hwhatWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._hwhatWsListener); this._hwhatWsListener = null; }
                if (this._hwhatStorageListener) { window.removeEventListener('storage', this._hwhatStorageListener); this._hwhatStorageListener = null; }
                const pane = document.getElementById('hwhat-pane');
                if (pane) pane.remove();
            }

// HWhat end

// EWatch start

                get ewStorage() {
                    if (!this._ewStorage) {
                        this._ewStorage = createModuleStorage('EW');
                    }
                    return this._ewStorage;
                }

                ewatchHandleWebSocketMessage(event) {
                    if (window.MCS_MODULES_DISABLED) return;
                    const data = event.detail;
                    if ((data?.type === 'init_character_data' ||
                         data?.type === 'item_update' ||
                         data?.type === 'inventory_update' ||
                         data?.type === 'character_update') && data.characterItems) {
                        const equippedItems = [];
                        for (const item of data.characterItems) {
                            if (!item.itemLocationHrid.includes("/item_locations/inventory")) {
                                equippedItems.push(item);
                            }
                        }
                        this.spyCharacterItems = equippedItems;
                        setTimeout(() => this.updateSpyDisplay(), 100);
                    }
                    if (data?.type === 'init_client_data' && data.itemDetailMap) {
                        this.spyItemDetailMap = data.itemDetailMap;
                    }
                }

                ewatchHandleForceLoad(event) {
                    this.spyCharacterItems = event.detail.items;
                    this.updateSpyDisplay();
                }

                ewatchHandleCharacterData(event) {
                    const data = event.detail;
                    if (data.characterItems) {
                        if (window.lootDropsTrackerInstance) {
                            window.lootDropsTrackerInstance.spyCharacterItems = data.characterItems;
                            setTimeout(() => window.lootDropsTrackerInstance.updateSpyDisplay(), 100);
                        }
                    }
                }

                ewatchHandleCoinUpdate(event) {
                    if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.spyCharacterItems) {
                        const coinItem = window.lootDropsTrackerInstance.spyCharacterItems.find(
                            item => item.itemHrid === '/items/coin'
                        );
                        if (coinItem) {
                            coinItem.count = event.detail.count;
                        } else {
                            window.lootDropsTrackerInstance.spyCharacterItems.push({
                                itemHrid: '/items/coin',
                                itemLocationHrid: '/item_locations/inventory',
                                count: event.detail.count
                            });
                        }
                        window.lootDropsTrackerInstance.updateCoinHeader();
                    }
                }

                ewatchHandleBattleEvent() {
                    setTimeout(() => {
                        this.updateSpyDisplay();
                        this.updateHeaderStatus();
                        this.updateLockedTimers();
                    }, 100);
                }

                ewatchHandleEquipmentChanged() {
                    if (this.spyIsInteracting) return;
                    try {
                        const newData = window.mcs__global_equipment_tracker?.allCharacterItems;
                        if (!newData) return;
                        this.spyCharacterItems = newData;
                        this.updateSpyDisplay();
                    } catch (e) {
                        console.error('[EWatch] Error handling equipment change:', e);
                    }
                }

                isInCombat() {
                    if (window.MCS_IN_COMBAT === true) return true;
                    if (window.lootDropsTrackerInstance?.isLiveSessionActive) return true;
                    return false;
                }

                _buildItemLocationMap() {
                    const map = new Map();
                    if (this.spyCharacterItems) {
                        for (const item of this.spyCharacterItems) {
                            if (item.itemLocationHrid) {
                                map.set(item.itemLocationHrid, item);
                            }
                        }
                    }
                    return map;
                }

                updateHeaderStatus() {
                    const statusEl = document.getElementById('spy-header-status');
                    if (!statusEl) return;
                    const inCombat = this.isInCombat();

                    const lockedSlots = Object.keys(this.spyLockedComparisons);
                    if (lockedSlots.length === 0) {
                        statusEl.innerHTML = 'Not Watching Anything';
                        statusEl.style.color = '#aaa';
                        return;
                    }
                    const itemByLocation = this._buildItemLocationMap();

                    if (!inCombat && this.spyFrozenHeaderValues) {
                        const frozen = this.spyFrozenHeaderValues;
                        const itemDisplay = frozen.enhLevel !== ''
                            ? `${frozen.name} +${frozen.enhLevel}`
                            : frozen.name;

                        let tickMarksHtml = '';
                        if (frozen.segments && frozen.segments.length > 1) {
                            let cumulativePercent = 0;
                            frozen.segments.forEach((seg, idx) => {
                                cumulativePercent += seg.percent;
                                if (idx < frozen.segments.length - 1) {
                                    tickMarksHtml += `<div class="mcs-ew-tick-mark" style="left: ${cumulativePercent}%;"></div>`;
                                }
                            });
                        }

                        const goldNeededText = frozen.stillNeeded > 0 ? ` <span class="mcs-ew-gold-needed">${this.formatGoldCompact(frozen.stillNeeded)}</span>` : '';
                        const barColor = '#f44336';

            statusEl.innerHTML = `
        <div class="mcs-ew-status-col">
            <div class="mcs-ew-status-row">
                <span style="color: ${frozen.name === 'Everything' ? '#FFA500' : '#FFD700'};">${itemDisplay}</span>
                ${goldNeededText}
                <span class="mcs-ew-nc-label">NC</span>
                <span class="mcs-ew-nc-time">(${frozen.timeStr})</span>
            </div>
            <div class="mcs-ew-header-bar-track">
                <div style="width: ${frozen.percent}%; height: 100%; background: ${barColor}; transition: width 0.3s ease; position: absolute; top: 0; left: 0;"></div>
                ${tickMarksHtml}
            </div>
        </div>
                `;
                        return;
                    }

                    let shortestTime = Infinity;
                    let shortestItem = null;
                    let selectedItem = null;
                    let everythingItem = null;
                    const currentGold = this.getSpyCurrentGold();

                    let totalCost = 0;
                    let segmentData = [];
                    let orderedLockedSlots = lockedSlots;
                    if (this.comparisonOrder && Array.isArray(this.comparisonOrder)) {
                        const orderedSlots = this.comparisonOrder.filter(slot => lockedSlots.includes(slot));
                        const newSlots = lockedSlots.filter(slot => !this.comparisonOrder.includes(slot));
                        orderedLockedSlots = [...orderedSlots, ...newSlots];
                    }

                    orderedLockedSlots.forEach(slot => {
                        const locked = this.spyLockedComparisons[slot];
                        const item = itemByLocation.get(`/item_locations/${slot}`);
                        const currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);
                        let priceToUse = currentAskPrice;
                        if (currentAskPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                            priceToUse = locked.lastKnownAskPrice;
                        }
                        const currentEquippedBid = item ? this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0) : 0;
                        const currentDifference = this.spyNoSellMode ? priceToUse : (priceToUse - currentEquippedBid);
                        if (currentDifference > 0) {
                            totalCost += currentDifference;
                            segmentData.push({
                                slot: slot,
                                cost: currentDifference
                            });
                        }
                    });

                    if (totalCost > 0) {
                        const progressPercent = Math.min((currentGold / totalCost) * 100, 100);
                        const stillNeeded = totalCost - currentGold;
                        let totalSeconds = stillNeeded <= 0 ? 0 : -1;
                        if (stillNeeded > 0 && this.totalPerDay > 0) {
                            const daysToAfford = stillNeeded / this.totalPerDay;
                            totalSeconds = Math.floor(daysToAfford * 24 * 60 * 60);
                        }

                        segmentData.forEach(seg => {
                            seg.percent = (seg.cost / totalCost) * 100;
                        });
                        everythingItem = {
                            name: 'Everything',
                            enhLevel: '',
                            seconds: totalSeconds,
                            percent: progressPercent,
                            segments: segmentData,
                            stillNeeded: stillNeeded
                        };
                    }

                    lockedSlots.forEach(slot => {
                        const locked = this.spyLockedComparisons[slot];
                        const item = itemByLocation.get(`/item_locations/${slot}`);

                        const currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);

                        let priceToUse = currentAskPrice;

                        if (currentAskPrice === 0 && (!locked.lastKnownAskPrice || locked.lastKnownAskPrice === 0)) {
                            return;
                        }

                        if (currentAskPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                            priceToUse = locked.lastKnownAskPrice;
                        }

                        const currentEquippedBid = item
                            ? this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0)
                            : 0;

                        const currentDifference = this.spyNoSellMode ? priceToUse : (priceToUse - currentEquippedBid);
                        const stillNeeded = currentDifference - currentGold;

                        const itemData = {
                            name: this.getSpyItemName(locked.itemHrid),
                            enhLevel: locked.enhLevel,
                            seconds: stillNeeded <= 0 ? 0 : -1,
                            percent: stillNeeded <= 0 ? 100 : Math.min((currentGold / currentDifference) * 100, 100),
                            stillNeeded: stillNeeded
                        };

                        if (stillNeeded > 0 && this.totalPerDay > 0) {
                            const daysToAfford = stillNeeded / this.totalPerDay
                            const totalSeconds = daysToAfford * 24 * 60 * 60;
                            itemData.seconds = totalSeconds;

                            if (totalSeconds < shortestTime) {
                                shortestTime = totalSeconds;
                                shortestItem = itemData;
                            }
                        } else if (stillNeeded <= 0) {
                            if (0 < shortestTime) {
                                shortestTime = 0;
                                shortestItem = itemData;
                            }
                        }

                        if (this.spySelectedHeaderSlot && slot === this.spySelectedHeaderSlot) {
                            selectedItem = itemData;
                        }
                    });

                    if (this.spySelectedHeaderSlot === 'everything' && everythingItem) {
                        selectedItem = everythingItem;
                    }

                    const displayItem = selectedItem || shortestItem;

                    if (!displayItem) {
                        statusEl.innerHTML = 'Calculating...';
                        statusEl.style.color = '#aaa';
                        return;
                    }

                    const formatTime = (totalSeconds) => mcsFormatDuration(totalSeconds, 'compact');

                    const timeStr = !inCombat ? '<span class="mcs-ew-no-combat">No Combat</span>'
                        : displayItem.seconds < 0 ? '--' : formatTime(displayItem.seconds);
                    const itemDisplay = displayItem.enhLevel !== ''
                        ? `${displayItem.name} +${displayItem.enhLevel}`
                        : displayItem.name;

                    let tickMarksHtml = '';
                    if (displayItem.segments && displayItem.segments.length > 1) {
                        let cumulativePercent = 0;
                        displayItem.segments.forEach((seg, idx) => {
                            cumulativePercent += seg.percent;
                            if (idx < displayItem.segments.length - 1) {
                                tickMarksHtml += `<div class="mcs-ew-tick-mark" style="left: ${cumulativePercent}%;"></div>`;
                            }
                        });
                    }

                    const goldNeededText = displayItem.stillNeeded > 0 ? ` <span class="mcs-ew-gold-needed">${this.formatGoldCompact(displayItem.stillNeeded)}</span>` : '';
                    this.spyHeaderDisplayItem = {
                        name: displayItem.name,
                        enhLevel: displayItem.enhLevel,
                        seconds: displayItem.seconds,
                        percent: displayItem.percent,
                        stillNeeded: displayItem.stillNeeded,
                        inCombat: inCombat,
                        timeStr: !inCombat ? 'No Combat' : displayItem.seconds < 0 ? '--' : formatTime(displayItem.seconds)
                    };
                    if (inCombat) {
                        this.spyFrozenHeaderValues = {
                            name: displayItem.name,
                            enhLevel: displayItem.enhLevel,
                            seconds: displayItem.seconds,
                            percent: displayItem.percent,
                            segments: displayItem.segments,
                            stillNeeded: displayItem.stillNeeded,
                            timeStr: timeStr
                        };
                    }

                    const barColor = inCombat ?
                        (displayItem.percent >= 100 ? '#4CAF50' : '#6495ED') :
                        (displayItem.percent >= 100 ? '#4CAF50' : '#f44336');

        statusEl.innerHTML = `
        <div class="mcs-ew-status-col">
            <div class="mcs-ew-status-row">
                <span style="color: ${displayItem.name === 'Everything' ? '#FFA500' : '#FFD700'};">${itemDisplay}</span>
                ${goldNeededText}
                <span style="color: ${inCombat ? (displayItem.percent >= 100 ? '#4CAF50' : '#f5a623') : '#f44336'}; font-weight: bold;">${timeStr}</span>
            </div>
            <div class="mcs-ew-header-bar-track">
                <div style="width: ${displayItem.percent}%; height: 100%; background: ${barColor}; transition: width 0.3s ease; position: absolute; top: 0; left: 0;"></div>
                ${tickMarksHtml}
            </div>
        </div>
                `;
                }
                setupPageContextBridge() {
                    const self = this;
                    if (this.bridgePollInterval) {
                        return;
                    }
                    const bridge = document.getElementById('equipspy-data-bridge');
                    if (!bridge) {
                        return;
                    }
                    let hasCharacterData = false;
                    let hasClientData = false;
                    let attemptCount = 0;
                    const maxAttempts = 60;
                    const pollInterval = setInterval(() => {
                        attemptCount++;
                        if (attemptCount % 10 === 0) {
                        }
                        if (!hasCharacterData) {
                            const charData = bridge.getAttribute('data-character-items');
                            if (charData) {
                                try {
                                    const data = JSON.parse(charData);
                                    if (self.spyCharacterItems.length === 0 || data.length > self.spyCharacterItems.length) {
                                        self.spyCharacterItems = data;
                                        self.updateSpyDisplay();
                                        hasCharacterData = true;
                                    }
                                } catch (e) {

                                }
                            }
                        }
                        if (!hasClientData) {
                            const clientData = bridge.getAttribute('data-item-detail-map');
                            if (clientData) {
                                try {
                                    const data = JSON.parse(clientData);
                                    self.spyItemDetailMap = data;
                                    hasClientData = true;
                                } catch (e) {

                                }
                            }
                        }
                        if (hasCharacterData && hasClientData) {
                            clearInterval(pollInterval);
                            self.bridgePollInterval = null;
                        }
                    }, 500);
                    setTimeout(() => {
                        clearInterval(pollInterval);
                        if (!hasCharacterData) {
                            self.tryLoadFromPageContext();
                            setTimeout(() => {
                                if (self.spyCharacterItems.length === 0) {
                                    const content = document.getElementById('spy-content');
                                    if (content) {
                                        content.innerHTML = '<div class="mcs-ew-error-msg">Equipment data failed to load.<br><br>Try:<br>1. Refresh the page (F5)<br>2. Change combat zones<br>3. Open your inventory</div>';
                                    }
                                } else {
                                    self.updateSpyDisplay();
                                }
                            }, 2000);
                        }
                    }, maxAttempts * 500);
                    self._ewatchBridgeForceLoadListener = (event) => {
                        self.spyCharacterItems = event.detail.items;
                        self.updateSpyDisplay();
                    };
                    window.addEventListener('EquipSpyForceLoadSuccess', self._ewatchBridgeForceLoadListener);
                }
                startDataPolling() {
                    const self = this;
                    let attempts = 0;
                    const maxAttempts = 30;
                    const pollInterval = setInterval(() => {
                        attempts++;
                        const equipped = self.extractEquipmentFromUI();
                        if (equipped.length > 0) {
                            self.spyCharacterItems = equipped;
                            self.updateSpyDisplay();
                            clearInterval(pollInterval);
                        } else if (attempts >= maxAttempts) {
                            clearInterval(pollInterval);
                        }
                    }, 1000);
                }
                extractEquipmentFromUI() {
                    const equipped = [];
                    try {
                        const rootElement = document.querySelector('#root') || document.body;
                        if (rootElement) {
                            const keys = Object.keys(rootElement);
                            for (const key of keys) {
                                if (key.startsWith('__reactContainer') ||
                                    key.startsWith('__reactFiber') ||
                                    key.startsWith('__reactInternalInstance')) {
                                    try {
                                        const reactData = rootElement[key];
                                        const items = this.searchReactTree(reactData, 'characterItems');
                                        if (items && Array.isArray(items) && items.length > 0) {
                                            const equippedItems = items.filter(item => {
                                                if (!item.itemLocationHrid) return false;
                                                if (item.itemLocationHrid === '/item_locations/inventory') return false;
                                                const slot = item.itemLocationHrid.replace('/item_locations/', '');
                                                return this.spyConfig.ALLOWED_SLOTS.includes(slot);
                                            });
                                            if (equippedItems.length > 0) {
                                                equipped.push(...equippedItems);
                                                break;
                                            }
                                        }
                                    } catch (e) {

                                    }
                                }
                            }
                        }
                    } catch (e) {

                    }
                    return equipped;
                }
                searchReactTree(node, targetKey, depth = 0, maxDepth = 10, visited = new WeakSet()) {
                    if (depth > maxDepth || !node || typeof node !== 'object') {
                        return null;
                    }
                    if (visited.has(node)) {
                        return null;
                    }
                    visited.add(node);
                    if (node[targetKey]) {
                        return node[targetKey];
                    }
                    const propsToSearch = [
                        'child', 'sibling',
                        'memoizedState', 'memoizedProps', 'pendingProps',
                        'stateNode'
                    ];
                    for (const prop of propsToSearch) {
                        if (node[prop]) {
                            try {
                                const result = this.searchReactTree(node[prop], targetKey, depth + 1, maxDepth, visited);
                                if (result) return result;
                            } catch (e) {
                            }
                        }
                    }
                    return null;
                }
                interceptNetworkRequests() {
                    if (this._networkIntercepted) return;
                    this._networkIntercepted = true;
                    this._ewatchWsListener = this.ewatchHandleWebSocketMessage.bind(this);
                    this._ewatchForceLoadListener = this.ewatchHandleForceLoad.bind(this);
                    this._ewatchCharDataListener = this.ewatchHandleCharacterData.bind(this);
                    this._ewatchCoinListener = this.ewatchHandleCoinUpdate.bind(this);
                    window.addEventListener('EquipSpyWebSocketMessage', this._ewatchWsListener);
                    window.addEventListener('EquipSpyForceLoadSuccess', this._ewatchForceLoadListener);
                    window.addEventListener('LootTrackerCharacterData', this._ewatchCharDataListener);
                    window.addEventListener('EquipSpyCoinUpdate', this._ewatchCoinListener);
                }
                tryLoadFromPageContext() {
                    try {
                        if (window.characterItems && Array.isArray(window.characterItems)) {
                            this.spyCharacterItems = window.characterItems;
                        }
                        const keys = Object.keys(localStorage);
                        for (const key of keys) {
                            if (key.toLowerCase().includes('character') || key.toLowerCase().includes('init')) {
                                try {
                                    const data = localStorage.getItem(key);
                                    if (data) {
                                        const parsed = JSON.parse(data);
                                        if (parsed.characterItems && Array.isArray(parsed.characterItems)) {
                                            this.spyCharacterItems = parsed.characterItems;
                                            break;
                                        }
                                    }
                                } catch (e) {
                                }
                            }
                        }
                    } catch (e) {

                    }
                }
                async loadSpyMarketData() {
                    const callTime = Date.now();

                    if (this.isLoadingMarketData) {

                        return;
                    }

                    if (this.spyMarketDataTimestamp && (callTime - this.spyMarketDataTimestamp) < 60000) {
                        const secAgo = ((callTime - this.spyMarketDataTimestamp) / 1000).toFixed(1);

                        return;
                    }

                    const fetchStart = performance.now();

                    try {
                        this.isLoadingMarketData = true;
                        const res = await fetch('https://www.milkywayidle.com/game_data/marketplace.json?t=' + callTime);
                        const json = await res.json();
                        this.spyMarketData = json.marketData ?? {};
                        this.spyMarketDataTimestamp = Date.now();
                        localStorage.setItem('mcs__global_market_timestamp', this.spyMarketDataTimestamp);

                        const fetchElapsed = performance.now() - fetchStart;

                        window.dispatchEvent(new CustomEvent('MarketDataUpdated', {
                            detail: { timestamp: this.spyMarketDataTimestamp }
                        }));
                    } catch (e) {
                        console.error('[EWatch] loadSpyMarketData FAILED:', e);
                    } finally {
                        this.isLoadingMarketData = false;
                    }
                }
                loadSpySettings() {
                    try {
                        const savedLocked = this.ewStorage.get('locked');
                        if (savedLocked) {
                            this.spyLockedComparisons = typeof savedLocked === 'string' ? JSON.parse(savedLocked) : savedLocked;
                        }

                        const savedHeaderSlot = this.ewStorage.get('selected_header_slot');
                        if (savedHeaderSlot) {
                            this.spySelectedHeaderSlot = savedHeaderSlot;
                        }

                        this.loadComparisonOrder();

                        const savedMarketValue = this.ewStorage.get('market_value_mode');
                        this.spyMarketValueMode = savedMarketValue !== false && savedMarketValue !== 'false';
                    } catch (e) {

                    }
                }
                createSpyPane() {

                    const savedEquipSpyMinimizedRaw = this.ewStorage.get('minimized');
                    this.spyIsMinimized = savedEquipSpyMinimizedRaw === true || savedEquipSpyMinimizedRaw === 'true';

                    const pane = document.createElement('div');
                    pane.id = this.spyConfig.PANE_ID;

                    pane.className = 'mcs-ew-pane';
                    try {
                        const pos = this.ewStorage.get('position');
                        if (pos) {
                            pane.style.top = (typeof pos.top === 'number' ? pos.top + 'px' : pos.top);
                            pane.style.right = (typeof pos.right === 'number' ? pos.right + 'px' : pos.right);
                            pane.style.left = 'auto';
                        }
                    } catch (e) {

                    }
                    pane.style.background = this.spyConfig.BG_COLOR;
                        const header = document.createElement('div');
                        header.className = 'mcs-ew-header';
        header.innerHTML = `
            <div class="mcs-ew-header-left">
                <span class="mcs-ew-header-title">EWatch</span>
                <div id="spy-header-status" class="mcs-ew-header-status">
        Not Watching Anything
                </div>
            </div>
            <div class="mcs-ew-header-buttons">
            <button id="spy-nosell-toggle" class="mcs-ew-btn" style="
    background: ${this.spyNoSellMode ? 'rgba(255, 100, 100, 0.3)' : 'rgba(100, 149, 237, 0.3)'};
    border-color: ${this.spyNoSellMode ? '#ff6666' : '#6495ED'};
    color: ${this.spyNoSellMode ? '#ff6666' : '#6495ED'};
">${this.spyNoSellMode ? 'No Sell' : 'Sell'}</button>
                <button id="spy-simple-mode-btn" class="mcs-ew-btn" style="
        background: rgba(100,149,237,0.3);
        border-color: #6495ED;
        color: #6495ED;
                ">Simple</button>
                <button id="spy-minimize-btn" class="mcs-ew-btn-minimize">${this.spyIsMinimized ? '+' : '-'}</button>
            </div>
                    `;
                    const content = document.createElement('div');
                    content.id = 'spy-content';
                    content.className = 'mcs-ew-content';
                    content.style.display = this.spyIsMinimized ? 'none' : 'block';
                    content.innerHTML = '<div class="mcs-ew-status-msg">Ready</div>';
                    const profitCostSection = document.createElement('div');
                    profitCostSection.id = 'spy-profit-cost-section';
                    profitCostSection.className = 'mcs-ew-profit-section';
                    profitCostSection.style.borderBottom = `1px solid ${this.spyConfig.BORDER_COLOR}`;
        profitCostSection.innerHTML = `
            <div class="mcs-ew-profit-label" style="color: #4CAF50;">Profit:</div>
            <div id="spy-profit-type" class="mcs-ew-profit-type">Bid</div>
            <div id="spy-profit-value" class="mcs-ew-profit-value" style="color: #4CAF50;">0 g/day</div>
            <div class="mcs-ew-profit-label" style="color: #FF6B6B;">Cost:</div>
            <div id="spy-cost-type" class="mcs-ew-profit-type">Bid</div>
            <div id="spy-cost-value" class="mcs-ew-profit-value" style="color: #FF6B6B;">0 g/day</div>
            <div class="mcs-ew-profit-label" style="color: #FFD700;">Total:</div>
            <div class="mcs-ew-profit-empty"></div>
            <div id="spy-total-value" class="mcs-ew-profit-value" style="color: #FFD700;">0 g/day</div>
                    `;
                    pane.appendChild(header);
                    pane.appendChild(profitCostSection);
                    pane.appendChild(content);
                    document.body.appendChild(pane);
                    registerPanel('equipment-spy-pane');
                    const scrollbarStyle = document.createElement('style');
        scrollbarStyle.textContent = `
            #spy-content::-webkit-scrollbar {
                width: 24px;
            }
            #spy-content::-webkit-scrollbar-track {
                background: rgba(0, 0, 0, 0.3);
                border-radius: 4px;
            }
            #spy-content::-webkit-scrollbar-thumb {
                background: rgba(76, 175, 80, 0.6);
                border-radius: 4px;
                border: 0px solid rgba(0, 0, 0, 0.3);
            }
            #spy-content::-webkit-scrollbar-thumb:hover {
                background: rgba(76, 175, 80, 0.8);
            }
            /* Firefox scrollbar styling for content */
            #spy-content {
                scrollbar-width: auto;
                scrollbar-color: rgba(76, 175, 80, 0.6) rgba(0, 0, 0, 0.3);
            }
            /* 4x LARGER scrollbars for dropdown selects (48px = 4x default 12px) */
            select[id^="spy-item-select"]::-webkit-scrollbar {
                width: 10px !important;
            }
            select[id^="spy-item-select"]::-webkit-scrollbar-track {
                background: rgba(0, 0, 0, 0.5);
                border-radius: 6px;
            }
            select[id^="spy-item-select"]::-webkit-scrollbar-thumb {
                background: rgba(76, 175, 80, 0.7);
                border-radius: 6px;
                border: 0px solid rgba(0, 0, 0, 0.5);
            }
            select[id^="spy-item-select"]::-webkit-scrollbar-thumb:hover {
                background: rgba(76, 175, 80, 0.9);
            }
            /* Firefox scrollbar styling for dropdowns */
            select[id^="spy-item-select"] {
                scrollbar-width: thick !important;
                scrollbar-color: rgba(76, 175, 80, 0.7) rgba(0, 0, 0, 0.5);
            }
            /* Make dropdown list taller to show scrollbar better */
            select[id^="spy-item-select"] {
                height: auto !important;
                max-height: 300px !important;
            }
            /* Drag cursors */
            .spy-slot-draggable {
                cursor: grab !important;
            }
            .spy-slot-draggable:active {
                cursor: grabbing !important;
            }
            /* Force grabbing cursor during drag everywhere - prevent copy/not-allowed */
            body.spy-dragging,
            body.spy-dragging *,
            body.spy-dragging .spy-slot-draggable,
            body.spy-dragging #spy-content,
            body.spy-dragging .spy-everything-section,
            body.spy-dragging .spy-drop-zone {
                cursor: grabbing !important;
            }
                    `;
                    document.head.appendChild(scrollbarStyle);
                    let dragOffset = { x: 0, y: 0 };

                    this._spyOnDragMove = (e) => {
                        let newLeft = e.clientX - dragOffset.x;
                        let newTop = e.clientY - dragOffset.y;
                        const winWidth = window.innerWidth;
                        const winHeight = window.innerHeight;
                        const headerHeight = header.offsetHeight;
                        const paneWidth = pane.getBoundingClientRect().width;
                        newLeft = Math.max(-paneWidth + 100, Math.min(newLeft, winWidth - 100));
                        newTop = Math.max(0, Math.min(newTop, winHeight - headerHeight));
                        pane.style.left = newLeft + 'px';
                        pane.style.top = newTop + 'px';
                        pane.style.right = 'auto';
                    };

                    this._spyOnDragUp = () => {
                        document.removeEventListener('mousemove', this._spyOnDragMove);
                        document.removeEventListener('mouseup', this._spyOnDragUp);
                        const rect = pane.getBoundingClientRect();
                        const right = window.innerWidth - rect.right;
                        this.ewStorage.set('position', { top: rect.top, right: right });
                    };

                    this._spyOnDragStart = (e) => {
                        if (e.target.tagName === 'BUTTON') return;
                        const rect = pane.getBoundingClientRect();
                        dragOffset.x = e.clientX - rect.left;
                        dragOffset.y = e.clientY - rect.top;
                        document.addEventListener('mousemove', this._spyOnDragMove);
                        document.addEventListener('mouseup', this._spyOnDragUp);
                    };
                    header.addEventListener('mousedown', this._spyOnDragStart);
                    document.getElementById('spy-minimize-btn').addEventListener('click', () => this.toggleSpyMinimize());
                    document.getElementById('spy-nosell-toggle').addEventListener('click', () => this.toggleNoSellMode());

                    document.getElementById('spy-simple-mode-btn').addEventListener('click', () => {
                        if (this.spyIsInteracting || this.spyOpenComparisons.size > 0) {
                            return;
                        }
                        this.spySimpleMode = !this.spySimpleMode;
                        this.ewStorage.set('simple_mode', this.spySimpleMode);
                        const btn = document.getElementById('spy-simple-mode-btn');
                        if (this.spySimpleMode) {
                            btn.textContent = 'Edit';
                            btn.style.background = 'rgba(76, 175, 80, 0.3)';
                            btn.style.borderColor = '#4CAF50';
                            btn.style.color = '#4CAF50';
                        } else {
                            btn.textContent = 'Lock';
                            btn.style.background = 'rgba(100,149,237,0.3)';
                            btn.style.borderColor = '#6495ED';
                            btn.style.color = '#6495ED';
                        }
                        this.updateSpyDisplay();
                    });

                    this._ewatchBattleListener = this.ewatchHandleBattleEvent.bind(this);
                    this._ewatchCombatEndedListener = this.ewatchHandleBattleEvent.bind(this);
                    window.addEventListener('LootTrackerBattle', this._ewatchBattleListener);
                    window.addEventListener('LootTrackerCombatEnded', this._ewatchCombatEndedListener);

                    this.updateSpyDisplay();
                    const simpleModeBtn = document.getElementById('spy-simple-mode-btn');
                    if (this.spySimpleMode && simpleModeBtn) {
                        simpleModeBtn.textContent = 'Edit';
                        simpleModeBtn.style.background = 'rgba(76, 175, 80, 0.3)';
                        simpleModeBtn.style.borderColor = '#4CAF50';
                        simpleModeBtn.style.color = '#4CAF50';
                    } else if (simpleModeBtn) {
                        simpleModeBtn.textContent = 'Lock';
                        simpleModeBtn.style.background = 'rgba(100,149,237,0.3)';
                        simpleModeBtn.style.borderColor = '#6495ED';
                        simpleModeBtn.style.color = '#6495ED';
                    }
                    if (this.spyIsMinimized && simpleModeBtn) {
                        simpleModeBtn.style.display = 'none';
                    }
                    if (this.spyIsMinimized) {
                        const header = pane.querySelector('div:first-child');
                        if (header) {
                            header.style.borderRadius = '8px';
                        }
                    }

                    VisibilityManager.register('ewatch-market-refresh', async () => {
                        if (this.spyIsInteracting) return;
                        await this.loadSpyMarketData();
                        this.updateLastKnownPrices();
                    }, 10 * 60 * 1000);
                    VisibilityManager.register('ewatch-profit-cost', () => {
                        if (this.spyIsInteracting) {
                            return;
                        }
                        this.updateProfitCostDisplay();
                        this.updateHeaderStatus();
                    }, 1000);
                    this._ewatchEquipChangedListener = this.ewatchHandleEquipmentChanged.bind(this);
                    window.addEventListener('MCS_EquipmentChanged', this._ewatchEquipChangedListener);
                    setTimeout(() => {
                        const testSlot = document.querySelector('.spy-slot-draggable');
                        if (testSlot) {
                            const cursor = window.getComputedStyle(testSlot).cursor;
                        }
                    }, 1000);
                    if (!document._spyDragoverAdded) {
                        document._spyDragoverAdded = true;
                        this._spyDragoverListener = (e) => {
                            if (document.body.classList.contains('spy-dragging')) {
                                e.preventDefault();
                                e.dataTransfer.dropEffect = 'move';
                            }
                        };
                        document.addEventListener('dragover', this._spyDragoverListener);
                    }
                }
                calculateRevenuePerDay(priceType) {
                    if (!window.lootDropsTrackerInstance) {
                        return 0;
                    }
                    const playerStats = window.lootDropsTrackerInstance.playerDropStats ?? {};
                    const userName = window.lootDropsTrackerInstance.userName;
                    if (!playerStats[userName]) return 0;

                    const items = playerStats[userName].items ?? {};
                    let total = 0;
                    for (const hrid in items) {
                        const count = items[hrid];
                        const unitValue = window.getUnitValue(hrid, 'live', 0, priceType);
                        if (unitValue !== null) {
                            total += unitValue * count;
                        }
                    }

                    let hoursElapsed = 0;
                    if (window.lootDropsTrackerInstance.startTime && window.lootDropsTrackerInstance.isLiveSessionActive) {
                        const elapsedMs = Date.now() - window.lootDropsTrackerInstance.startTime.getTime();
                        hoursElapsed = elapsedMs / (1000 * 60 * 60);
                    }

                    if (hoursElapsed < 0.01) return 0;
                    return (total / hoursElapsed) * 24;
                }
                getItemPriceForCost(itemHrid, priceType) {
                    if (!this.spyMarketData || !this.spyMarketData[itemHrid]) return 0;
                    const itemData = this.spyMarketData[itemHrid];
                    const level0Data = itemData[0];
                    if (!level0Data) return 0;
                    return priceType === 'ask' ? (level0Data.a ?? 0) : (level0Data.b ?? 0);
                }
                updateProfitCostDisplay() {
                    const profitTypeEl = document.getElementById('spy-profit-type');
                    const profitValueEl = document.getElementById('spy-profit-value');
                    const costTypeEl = document.getElementById('spy-cost-type');
                    const costValueEl = document.getElementById('spy-cost-value');
                    const totalValueEl = document.getElementById('spy-total-value');
                    if (!profitValueEl || !costValueEl || !totalValueEl) {
                        return;
                    }
                    if (!window.lootDropsTrackerInstance) {
                        return;
                    }
                    const hwhatMode = window.lootDropsTrackerInstance.hwhatMode || 'lazy';
                    let profitPerDay = 0;
                    let costPerDay = 0;
                    let taxPerDay = 0;
                    profitPerDay = window.lootDropsTrackerInstance.hwhatCurrentRevenue ?? 0;
                    if (hwhatMode === 'lazy') {
                        costPerDay = window.lootDropsTrackerInstance.hwhatCostAsk ?? 0;
                    } else {
                        costPerDay = window.lootDropsTrackerInstance.hwhatCostBid ?? 0;
                    }
                    if (window.lootDropsTrackerInstance.hwhatTaxEnabled) {
                        taxPerDay = window.lootDropsTrackerInstance.hwhatCowbellTaxPerDay ?? 0;
                    }
                    const totalPerDay = profitPerDay - costPerDay - taxPerDay;
                    this.totalPerDay = totalPerDay;
                    this.totalPerDayFormatted = this.formatGoldNumber(totalPerDay);
                    const priceTypeDisplay = hwhatMode === 'lazy' ? 'Lazy' : 'Mid';
                    if (profitTypeEl) profitTypeEl.textContent = priceTypeDisplay;
                    if (costTypeEl) costTypeEl.textContent = priceTypeDisplay;
                    profitValueEl.textContent = this.formatGoldNumber(profitPerDay) + ' coin/day';
                    costValueEl.textContent = this.formatGoldNumber(costPerDay) + ' coin/day';
                    totalValueEl.textContent = this.formatGoldNumber(totalPerDay) + ' coin/day';
                    totalValueEl.style.color = 'gold';
                }
                formatGoldNumber(num) {
                    const showFullNumbers = this.hwhatShowFullNumbers !== false;

                    if (showFullNumbers) {
                        return Math.floor(num).toLocaleString('en-US');
                    }
                    const sign = num < 0 ? '-' : '';
                    return sign + mcsFormatCurrency(Math.abs(num), 'abbreviated');
                }
                manualRefresh() {
                    this.tryLoadFromPageContext();
                    this.updateSpyDisplay();
                }
                toggleSpyMinimize() {
                    this.spyIsMinimized = !this.spyIsMinimized;
                    this.ewStorage.set('minimized', this.spyIsMinimized);
                    const pane = document.getElementById('equipment-spy-pane');
                    const content = document.getElementById('spy-content');
                    const btn = document.getElementById('spy-minimize-btn');
                    const simpleModeBtn = document.getElementById('spy-simple-mode-btn');
                    const headerStatus = document.getElementById('spy-header-status');
                    const header = pane?.querySelector('div:first-child');
                    if (!pane || !content || !btn) {
                        return;
                    }
                    if (this.spyIsMinimized) {
                        content.style.display = 'none';
                        btn.textContent = '+';
                        if (simpleModeBtn) simpleModeBtn.style.display = 'none';
                        if (headerStatus) headerStatus.style.display = 'flex';
                        if (header) header.style.borderRadius = '8px';
                    } else {
                        content.style.display = 'block';
                        btn.textContent = '-';
                        if (simpleModeBtn) simpleModeBtn.style.display = 'block';
                        if (headerStatus) headerStatus.style.display = 'flex';
                        if (header) header.style.borderRadius = '6px 6px 0 0';
                        this.constrainPanelToBoundaries('equipment-spy-pane', this.spyConfig.STORAGE_KEY, false);
                    }
                    this.updateSpyDisplay();
                }
                formatSpyCoins(value) {
                    if (value === null || typeof value === 'undefined') return '0';
                    return Math.round(value).toLocaleString();
                }
                formatGoldCompact(value) {
                    return mcsFormatCurrency(value, 'abbreviated');
                }
                getSpyCurrentGold() {
                    try {
                        let totalGold = 0;

                        const coinItem = this.spyCharacterItems.find(item => item.itemHrid === '/items/coin');
                        if (coinItem && coinItem.count) {
                            totalGold = coinItem.count;
                        }

                        const { totalAsk, totalBid } = this.mcs_nt_calculateTotals ? this.mcs_nt_calculateTotals() : { totalAsk: 0, totalBid: 0 };
                        const useAskPrice = window.getFlootUseAskPrice ? window.getFlootUseAskPrice() : false;
                        const ntallyPrice = useAskPrice ? totalAsk : totalBid;
                        totalGold += ntallyPrice;

                        if (this.spyMarketValueMode !== false) {
                            const marketTotal = this.mcs_nt_calculateMarketTotal ? this.mcs_nt_calculateMarketTotal() : 0;
                            totalGold += marketTotal;
                        }

                        return totalGold;
                    } catch (e) {
                        return 0;
                    }
                }
                getSpyItemName(hrid) {
                    if (!hrid) return 'Unknown';
                    if (hrid === '/items/empty') return 'Empty';
                    if (this.spyItemDetailMap[hrid] && this.spyItemDetailMap[hrid].name) {
                        return this.spyItemDetailMap[hrid].name;
                    }
                    return mcsFormatHrid(hrid);
                }
                getSpyBidPrice(itemHrid, enhancementLevel = 0) {
                    if (itemHrid === '/items/empty') return 0;
                    if (!this.spyMarketData[itemHrid]) return 0;
                    const priceData = this.spyMarketData[itemHrid][enhancementLevel] || this.spyMarketData[itemHrid][0];
                    return priceData?.b > 0 ? priceData.b : 0;
                }
                getSpyEquippedValue(itemHrid, enhancementLevel = 0) {
                    if (itemHrid === '/items/empty') return 0;
                    const useAskPrice = window.getFlootUseAskPrice ? window.getFlootUseAskPrice() : false;
                    const basePrice = useAskPrice
                        ? this.getSpyAskPrice(itemHrid, enhancementLevel)
                        : this.getSpyBidPrice(itemHrid, enhancementLevel);
                    if (basePrice < 900) {
                        return Math.floor(basePrice * 0.98);
                    } else {
                        return Math.ceil(basePrice * 0.98);
                    }
                }
                getSpyAskPrice(itemHrid, enhancementLevel = 0) {
                    if (itemHrid === '/items/empty') return 0;
                    if (!this.spyMarketData[itemHrid]) return 0;
                    const priceData = this.spyMarketData[itemHrid][enhancementLevel];
                    return priceData?.a > 0 ? priceData.a : 0;
                }
                getSpyAvailableEnhancements(itemHrid) {
                    return Array.from({ length: 21 }, (_, i) => i);
                }
                getSpyItemsInCategory(slot) {
                    const items = [];
                    for (const [hrid, details] of Object.entries(this.spyItemDetailMap)) {
                        if (details.equipmentDetail &&
                            details.equipmentDetail.type === `/equipment_types/${slot}`) {
                            items.push({ hrid, name: details.name });
                        }
                    }
                    return items.sort((a, b) => a.name.localeCompare(b.name));
                }
                lockSpyComparison(slot, itemHrid, enhLevel, askPrice, difference) {
                    const savedItems = [...this.spyCharacterItems];
                    const currentGold = this.getSpyCurrentGold();
                    const goldNeeded = difference - currentGold;
                    const hasMarketData = this.spyMarketData[itemHrid] &&
                        this.spyMarketData[itemHrid][enhLevel] &&
                        this.spyMarketData[itemHrid][enhLevel].a > 0;
                    this.spyLockedComparisons[slot] = {
                        itemHrid: itemHrid,
                        enhLevel: enhLevel,
                        askPrice: hasMarketData ? askPrice : 0,
                        difference: hasMarketData ? difference : 0,
                        goldNeeded: hasMarketData && goldNeeded > 0 ? goldNeeded : 0,
                        timestamp: Date.now(),
                        lastKnownAskPrice: hasMarketData ? askPrice : 0,
                        lastKnownPriceTimestamp: hasMarketData ? Date.now() : null,
                        hasMarketData: hasMarketData
                    };
                    this.ignoreNextStorageEvent = true;
                    this.ewStorage.set('locked', this.spyLockedComparisons);
                    setTimeout(() => {
                        this.ignoreNextStorageEvent = false;
                    }, 100);
                    const comparisonElement = document.getElementById(`spy-comparison-${slot}`);
                    if (comparisonElement) {
                        comparisonElement.remove();
                    }
                    this.spyCharacterItems = savedItems;
                    this.updateSpyDisplay();
                    this.updateHeaderStatus();
                }
                saveLockedComparisons() {
                    if (this.ignoreNextStorageEvent) return;
                    this.ewStorage.set('locked', this.spyLockedComparisons);
                }
                unlockSpyComparison(slot) {
                    const savedItems = [...this.spyCharacterItems];
                    delete this.spyLockedComparisons[slot];

                    if (this.spySelectedHeaderSlot === slot) {
                        this.spySelectedHeaderSlot = null;
                        this.ewStorage.set('selected_header_slot', null);
                    }

                    this.ignoreNextStorageEvent = true;
                    this.ewStorage.set('locked', this.spyLockedComparisons);
                    setTimeout(() => {
                        this.ignoreNextStorageEvent = false;
                    }, 100);
                    if (this.purchaseTimerIntervals && this.purchaseTimerIntervals[slot]) {
                        clearInterval(this.purchaseTimerIntervals[slot]);
                        delete this.purchaseTimerIntervals[slot];
                    }
                    this.spyCharacterItems = savedItems;
                    this.updateSpyDisplay();
                    this.updateHeaderStatus();
                }
                toggleHeaderSelection(slot) {
                    if (this.spySelectedHeaderSlot === slot) {
                        this.spySelectedHeaderSlot = null;
                    } else {
                        this.spySelectedHeaderSlot = slot;
                    }

                    this.ewStorage.set('selected_header_slot', this.spySelectedHeaderSlot);

                    this.updateSpyDisplay();
                    this.updateHeaderStatus();
                }
                updateLockedTimers() {
                    if (!this.purchaseTimerIntervals) {
                        this.purchaseTimerIntervals = {};
                    }
                    const itemByLocation = this._buildItemLocationMap();
                    Object.keys(this.spyLockedComparisons).forEach(slot => {
                        const locked = this.spyLockedComparisons[slot];
                        if (this.purchaseTimerIntervals[slot]) {
                            return;
                        }
                        const updateDisplay = () => {
                            if (document.hidden) return;
                            const etaDisplay = document.getElementById(`spy-locked-eta-${slot}`);
                            if (!etaDisplay) return;

                            const inCombat = this.isInCombat();
                            if (!inCombat) {
                                if (!this.spyFrozenLockedTimers) {
                                    this.spyFrozenLockedTimers = {};
                                }
                                const frozenTimer = this.spyFrozenLockedTimers[slot];
                                if (frozenTimer) {
                        etaDisplay.innerHTML = `<div class="mcs-ew-eta-text">
                    <span class="mcs-ew-nc-label">NC</span>
                    <span class="mcs-ew-nc-time"> (${frozenTimer})</span>
                            </div>`;
                                } else {
                        etaDisplay.innerHTML = `<div class="mcs-ew-eta-nc">
                    NC
                            </div>`;
                                }
                                return;
                            }

                            const item = itemByLocation.get(`/item_locations/${slot}`);

                            const currentPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);

                            if (currentPrice === 0 && (!locked.lastKnownAskPrice || locked.lastKnownAskPrice === 0)) {
                    etaDisplay.innerHTML = `<div class="mcs-ew-eta-waiting">
                Never Seen
                        </div>`;
                                return;
                            }

                            if (!this.totalPerDay || this.totalPerDay <= 0) {
                    etaDisplay.innerHTML = `<div class="mcs-ew-eta-waiting">
                Waiting for data...
                        </div>`;
                                return;
                            }

                            let priceToUse = currentPrice;
                            if (currentPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                                priceToUse = locked.lastKnownAskPrice;
                            }

                            const currentEquippedBid = item
                                ? this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0)
                                : 0;

                            const currentDifference = this.spyNoSellMode
                                ? priceToUse
                                : (priceToUse - currentEquippedBid);

                            const currentGold = this.getSpyCurrentGold();
                            const stillNeeded = currentDifference - currentGold;

                            if (stillNeeded <= 0) {
                                if (!this.spyFrozenLockedTimers) {
                                    this.spyFrozenLockedTimers = {};
                                }
                                this.spyFrozenLockedTimers[slot] = `Affordable!`;

                    etaDisplay.innerHTML = `<div class="mcs-ew-eta-affordable">
                Affordable!
                        </div>`;
                                return;
                            }

                            const daysNeeded = stillNeeded / this.totalPerDay;
                            const hoursNeeded = daysNeeded * 24;
                            const minutesNeeded = hoursNeeded * 60;
                            const secondsNeeded = minutesNeeded * 60;

                            let timeStr;
                            if (daysNeeded >= 1) {
                                const days = Math.floor(daysNeeded);
                                const hours = Math.floor((daysNeeded - days) * 24);
                                const minutes = Math.floor(((daysNeeded - days) * 24 - hours) * 60);
                                const seconds = Math.floor((((daysNeeded - days) * 24 - hours) * 60 - minutes) * 60);
                                timeStr = `${days}d ${hours}h ${minutes}m ${seconds}s`;
                            } else if (hoursNeeded >= 1) {
                                const hours = Math.floor(hoursNeeded);
                                const minutes = Math.floor((hoursNeeded - hours) * 60);
                                const seconds = Math.floor(((hoursNeeded - hours) * 60 - minutes) * 60);
                                timeStr = `${hours}h ${minutes}m ${seconds}s`;
                            } else if (minutesNeeded >= 1) {
                                const minutes = Math.floor(minutesNeeded);
                                const seconds = Math.floor((minutesNeeded - minutes) * 60);
                                timeStr = `${minutes}m ${seconds}s`;
                            } else {
                                const seconds = Math.ceil(secondsNeeded);
                                timeStr = `${seconds}s`;
                            }

                            if (!this.spyFrozenLockedTimers) {
                                this.spyFrozenLockedTimers = {};
                            }
                            this.spyFrozenLockedTimers[slot] = `ETA: ${timeStr}`;

                etaDisplay.innerHTML = `<div class="mcs-ew-eta-timer">
            ETA: ${timeStr}
                    </div>`;
                        };
                        updateDisplay();
                        this.purchaseTimerIntervals[slot] = setInterval(updateDisplay, 1000);
                    });
                }
                updateCoinHeader() {
                    if (this.spyIsInteracting) {
                        return;
                    }
                    const coinAmountElement = document.getElementById('spy-coin-amount');
                const coinPerDayElement = document.getElementById('spy-coin-per-day');
                if (!coinAmountElement || !coinPerDayElement) {
                    return;
                }
                const itemByLocation = this._buildItemLocationMap();
                let coinOnlyGold = 0;
                let hasGoldData = false;
                if (this.spyCharacterItems && Array.isArray(this.spyCharacterItems)) {
                    const coinItem = this.spyCharacterItems.find(item => item.itemHrid === '/items/coin');
                    if (coinItem && typeof coinItem.count === 'number') {
                        coinOnlyGold = coinItem.count;
                        hasGoldData = true;
                    }
                }
                const currentGold = this.getSpyCurrentGold();
                coinAmountElement.textContent = this.formatSpyCoins(coinOnlyGold);
                const hwhatMode = window.lootDropsTrackerInstance?.hwhatMode || 'lazy';
                const inCombat = this.isInCombat();

                if (!inCombat && this.spyFrozenProfit) {
                    const frozen = this.spyFrozenProfit;
                    coinPerDayElement.style.color = 'gold';
                    coinPerDayElement.style.fontWeight = 'bold';
                    coinPerDayElement.innerHTML = `<span class="mcs-ew-nc-label">NC</span> <span class="mcs-ew-nc-time">(${frozen.strategyLabel}: ${frozen.profitFormatted}/day)</span>`;
                } else {
                    const currentRevenue = this.hwhatCurrentRevenue ?? 0;
                    const currentCostForMode = hwhatMode === 'lazy' ? (this.hwhatCostAsk ?? 0) : (this.hwhatCostBid ?? 0);
                    let currentProfit = currentRevenue - currentCostForMode;
                    if (currentProfit > 0) {
                        const profitFormatted = this.formatGoldNumber(currentProfit);
                        const strategyLabel = hwhatMode === 'lazy' ? 'Lazy' : 'Mid';
                        coinPerDayElement.style.color = 'gold';
                        coinPerDayElement.style.fontWeight = 'bold';
                        coinPerDayElement.textContent = `${strategyLabel}: ${profitFormatted}/day`;

                        if (inCombat) {
                            this.spyFrozenProfit = { profitFormatted, strategyLabel };
                        }
                    } else {
                        coinPerDayElement.style.color = '#999';
                        coinPerDayElement.style.fontWeight = 'normal';
                        coinPerDayElement.textContent = 'No income data';
                    }
                }
                Object.keys(this.spyLockedComparisons).forEach(slot => {
                    const locked = this.spyLockedComparisons[slot];
                    const item = itemByLocation.get(`/item_locations/${slot}`);
                    const currentPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);

                    let priceToUse = currentPrice;

                    if (currentPrice === 0 && (!locked.lastKnownAskPrice || locked.lastKnownAskPrice === 0)) {
                        return;
                    }

                    if (currentPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                        priceToUse = locked.lastKnownAskPrice;
                    }
                    const currentEquippedBid = item ?
                        this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0) : 0;
                    const currentDifference = this.spyNoSellMode ? priceToUse : (priceToUse - currentEquippedBid);
                    const needGold = currentDifference;
                    let progressPercent = 0;
                    let isAffordable = false;
                    if (!hasGoldData) {
                        progressPercent = 0;
                        isAffordable = false;
                    } else if (needGold > 0) {
                        progressPercent = Math.min((currentGold / needGold) * 100, 100);
                        isAffordable = progressPercent >= 100;
                    } else {
                        progressPercent = 100;
                        isAffordable = true;
                    }
                    const progressBarContainer = document.querySelector(`#spy-slot-${slot} .mcs-ew-progress-track`);
                    if (progressBarContainer) {
                        const progressBar = progressBarContainer.querySelector('div');
                        const progressText = progressBarContainer.closest('.mcs-ew-progress-row').querySelector('.mcs-ew-progress-text');
                        if (progressBar) {
                            progressBar.style.width = `${progressPercent}%`;
                            const inCombat = this.isInCombat();
                            progressBar.style.background = inCombat ? (isAffordable ? '#4CAF50' : '#6495ED') : '#f44336';
                        }
                        if (progressText) {
                            const inCombat = this.isInCombat();
                            progressText.style.color = inCombat ? (isAffordable ? '#fff' : '#6495ED') : '#f44336';
                            progressText.style.fontWeight = isAffordable ? 'bold' : 'normal';
                            progressText.textContent = !hasGoldData ? 'Waiting for data...' :
                                (isAffordable ? 'Affordable' : `${progressPercent.toFixed(5)}%`);
                        }
                    }
                    const remainingGoldEl = document.getElementById(`spy-remaining-${slot}`);
                    if (remainingGoldEl) {
                        const stillNeeded = currentDifference - currentGold;
                        if (stillNeeded > 0) {
                            remainingGoldEl.textContent = `${this.formatGoldCompact(stillNeeded)} needed`;
                            remainingGoldEl.style.display = '';
                        } else {
                            remainingGoldEl.style.display = 'none';
                        }
                    }
                });
                const lockedSlots = Object.keys(this.spyLockedComparisons);
                if (lockedSlots.length > 0) {
                    let totalCost = 0;
                    lockedSlots.forEach(slot => {
                        const locked = this.spyLockedComparisons[slot];
                        const item = itemByLocation.get(`/item_locations/${slot}`);
                        const currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);
                        let priceToUse = currentAskPrice;
                        if (currentAskPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                            priceToUse = locked.lastKnownAskPrice;
                        }
                        const currentEquippedBid = item ?
                            this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0) : 0;
                        const currentDifference = this.spyNoSellMode ? priceToUse : (priceToUse - currentEquippedBid);

                        if (currentDifference > 0) {
                            totalCost += currentDifference;
                        }
                    });
                    if (totalCost > 0) {
                        const progressPercent = Math.min((currentGold / totalCost) * 100, 100);
                        const isAffordable = progressPercent >= 100;
                        const everythingTimer = document.getElementById('spy-everything-timer');
                        if (everythingTimer && this.goldPerDay > 0 && !isAffordable) {
                            const stillNeeded = totalCost - currentGold;
                            const daysToAfford = stillNeeded / this.totalPerDay;
                            const totalSeconds = Math.floor(daysToAfford * 24 * 60 * 60);
                            const months = Math.floor(totalSeconds / (30 * 24 * 60 * 60));
                            const days = Math.floor((totalSeconds % (30 * 24 * 60 * 60)) / (24 * 60 * 60));
                            const hours = Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60));
                            const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
                            const seconds = totalSeconds % 60;
                            const parts = [];
                            if (months > 0) parts.push(`${months}mo`);
                            if (days > 0) parts.push(`${days}d`);
                            if (hours > 0) parts.push(`${hours}h`);
                            if (minutes > 0) parts.push(`${minutes}m`);
                            if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
                            everythingTimer.textContent = parts.join(' ');
                            everythingTimer.style.color = '#f5a623';
                        } else if (everythingTimer && isAffordable) {
                            everythingTimer.textContent = 'Affordable!';
                            everythingTimer.style.color = '#66ff66';
                            everythingTimer.style.fontWeight = 'bold';
                        }
                        const everythingProgressBar = document.querySelector('.mcs-ew-everything-track > div:first-child');
                        const everythingProgressText = document.querySelector('.mcs-ew-everything .mcs-ew-progress-text');
                        if (everythingProgressBar) {
                            everythingProgressBar.style.width = `${progressPercent}%`;
                            const inCombat = this.isInCombat();
                            everythingProgressBar.style.background = inCombat ? (isAffordable ? '#4CAF50' : '#6495ED') : '#f44336';
                        }
                        if (everythingProgressText) {
                            const inCombat = this.isInCombat();
                            everythingProgressText.style.color = inCombat ? (isAffordable ? '#fff' : '#6495ED') : '#f44336';
                            everythingProgressText.style.fontWeight = isAffordable ? 'bold' : 'normal';
                            everythingProgressText.textContent = !hasGoldData ? 'Waiting for data...' :
                                (isAffordable ? 'Affordable' : `${progressPercent.toFixed(5)}%`);
                        }
                    }
                }
            }
            toggleNoSellMode() {
                this.spyNoSellMode = !this.spyNoSellMode;
                this.ewStorage.set('no_sell_mode', this.spyNoSellMode);

                const toggle = document.getElementById('spy-nosell-toggle');
                if (toggle) {
                    if (this.spyNoSellMode) {
                        toggle.textContent = 'No Sell';
                        toggle.style.background = 'rgba(255, 100, 100, 0.3)';
                        toggle.style.borderColor = '#ff6666';
                        toggle.style.color = '#ff6666';
                    } else {
                        toggle.textContent = 'Sell';
                        toggle.style.background = 'rgba(100, 149, 237, 0.3)';
                        toggle.style.borderColor = '#6495ED';
                        toggle.style.color = '#6495ED';
                    }
                }

                this.updateSpyDisplay();
            }
            toggleMarketValueMode() {
                this.spyMarketValueMode = !this.spyMarketValueMode;
                this.ewStorage.set('market_value_mode', this.spyMarketValueMode);

                const toggle = document.getElementById('spy-market-value-toggle');
                if (toggle) {
                    if (this.spyMarketValueMode) {
                        toggle.textContent = 'Market Value On';
                        toggle.style.background = 'rgba(76, 175, 80, 0.3)';
                        toggle.style.borderColor = '#4CAF50';
                        toggle.style.color = '#4CAF50';
                    } else {
                        toggle.textContent = 'Market Value Off';
                        toggle.style.background = 'rgba(255, 100, 100, 0.3)';
                        toggle.style.borderColor = '#ff6666';
                        toggle.style.color = '#ff6666';
                    }
                }

                this.updateSpyDisplay();
            }
            showSpyComparison(slot, currentItemHrid) {
                const slotContainer = document.getElementById(`spy-slot-${slot}`);
                if (!slotContainer) {
                    return;
                }
                if (this.spyLockedComparisons[slot]) {
                    return;
                }
                const existingDropdown = document.getElementById(`spy-comparison-${slot}`);
                if (existingDropdown) {
                    this.spyIsInteracting = false;
                    this.spyOpenComparisons.delete(slot);
                    existingDropdown.remove();
                    this.updateSpyDisplay();
                    return;
                }
                this.spyIsInteracting = true;
                this.spyOpenComparisons.add(slot);
                const items = this.getSpyItemsInCategory(slot);
                if (items.length === 0) return;
                const container = document.getElementById(`spy-slot-${slot}`);
                if (!container) return;
                const dropdown = document.createElement('div');
                dropdown.id = `spy-comparison-${slot}`;
                dropdown.className = 'mcs-ew-comparison';
                dropdown.style.borderLeft = `2px solid ${this.spyConfig.MAIN_COLOR}`;
    let html = `
        <div class="mcs-ew-compare-header">
        <div class="mcs-ew-compare-label">Compare with:</div>
        <button id="spy-watch-comparison-${slot}" class="mcs-ew-watch-btn">👁️ Watch</button>
        </div>
        <select id="spy-item-select-${slot}" class="mcs-ew-item-select" size=10>
            <option value="">-- Select Item --</option>
                `;
                items.forEach(item => {
                    const selected = item.hrid === currentItemHrid ? 'selected' : '';
                    let lastSeenText = '';
                    if (this.spyMarketData[item.hrid]) {
                        let mostRecentTimestamp = 0;
                        Object.keys(this.spyMarketData[item.hrid]).forEach(level => {
                            const data = this.spyMarketData[item.hrid][level];
                            if (data && data.t && data.t > mostRecentTimestamp) {
                                mostRecentTimestamp = data.t;
                            }
                        });
                        if (mostRecentTimestamp > 0) {
                            const timeSince = Date.now() - mostRecentTimestamp;
                            const minutesAgo = Math.floor(timeSince / (1000 * 60));
                            const hoursAgo = Math.floor(minutesAgo / 60);
                            const daysAgo = Math.floor(hoursAgo / 24);
                            if (daysAgo > 0) {
                                lastSeenText = ` (${daysAgo}d ago)`;
                            } else if (hoursAgo > 0) {
                                lastSeenText = ` (${hoursAgo}h ago)`;
                            } else if (minutesAgo > 0) {
                                lastSeenText = ` (${minutesAgo}m ago)`;
                            } else {
                                lastSeenText = ` (just now)`;
                            }
                        }
                    }
                    html += `<option value="${item.hrid}"${selected}>${item.name}${lastSeenText}</option>`;
                });
                html += `</select>`;
                html += `<div id="spy-enh-buttons-${slot}" class="mcs-ew-enh-container"></div>`;
                html += `<div id="spy-price-display-${slot}" class="mcs-ew-price-display"></div>`;
                html += `<div id="spy-eta-display-${slot}" class="mcs-ew-eta-display"></div>`;
                dropdown.innerHTML = html;
                container.appendChild(dropdown);
                const select = document.getElementById(`spy-item-select-${slot}`);

                if (!this.ewatchDropdownListeners) {
                    this.ewatchDropdownListeners = new Map();
                }

                const dropdownKey = `dropdown-${slot}`;

                if (this.ewatchDropdownListeners.has(dropdownKey)) {
                    const oldListeners = this.ewatchDropdownListeners.get(dropdownKey);
                    if (oldListeners.change) {
                        select.removeEventListener('change', oldListeners.change);
                    }
                    if (oldListeners.focus) {
                        select.removeEventListener('focus', oldListeners.focus);
                    }
                    if (oldListeners.blur) {
                        select.removeEventListener('blur', oldListeners.blur);
                    }
                }

                const changeHandler = (e) => {
                    const selectedHrid = e.target.value;
                    if (!selectedHrid) {
                        document.getElementById(`spy-enh-buttons-${slot}`).innerHTML = '';
                        document.getElementById(`spy-price-display-${slot}`).innerHTML = '';
                        return;
                    }
                    this.showSpyEnhancementButtons(slot, selectedHrid);
                };

                const focusHandler = () => {
                    this.spyIsInteracting = true;
                };

                const blurHandler = () => {
                    this.spyIsInteracting = false;
                };

                this.ewatchDropdownListeners.set(dropdownKey, {
                    change: changeHandler,
                    focus: focusHandler,
                    blur: blurHandler
                });

                select.addEventListener('change', changeHandler);
                select.addEventListener('focus', focusHandler);
                select.addEventListener('blur', blurHandler);

                const watchBtn = document.getElementById(`spy-watch-comparison-${slot}`);

                const watchBtnKey = `watchbtn-${slot}`;
                if (this.ewatchDropdownListeners.has(watchBtnKey)) {
                    const oldWatchClick = this.ewatchDropdownListeners.get(watchBtnKey).click;
                    if (oldWatchClick) {
                        watchBtn.removeEventListener('click', oldWatchClick);
                    }
                }

                const watchBtnClickHandler = () => {
                    const selectedHrid = select.value;
                    if (!selectedHrid) {
                        return;
                    }
                    const selectedBtn = dropdown.querySelector('.spy-enh-btn.spy-selected');
                    if (!selectedBtn) {
                        return;
                    }
                    const enhLevel = parseInt(selectedBtn.dataset.level);
                    const askPrice = this.getSpyAskPrice(selectedHrid, enhLevel);
                    const currentItem = this.spyCharacterItems.find(item => item.itemLocationHrid === `/item_locations/${slot}`);
                    const currentBid = currentItem ? this.getSpyEquippedValue(currentItem.itemHrid, currentItem.enhancementLevel ?? 0) : 0;
                    const difference = this.spyNoSellMode ? askPrice : (askPrice - currentBid);

                    this.spyIsInteracting = false;
                    this.spyOpenComparisons.delete(slot);
                    this.lockSpyComparison(slot, selectedHrid, enhLevel, askPrice, difference);
                };

                this.ewatchDropdownListeners.set(watchBtnKey, { click: watchBtnClickHandler });
                watchBtn.addEventListener('click', watchBtnClickHandler);

                if (currentItemHrid) {
                    this.showSpyEnhancementButtons(slot, currentItemHrid);
                }
            }
            showSpyEnhancementButtons(slot, itemHrid) {
                const buttonContainer = document.getElementById(`spy-enh-buttons-${slot}`);
                const priceDisplay = document.getElementById(`spy-price-display-${slot}`);
                if (!buttonContainer || !priceDisplay) return;
                const levelsWithData = new Set();
                if (this.spyMarketData[itemHrid]) {
                    Object.keys(this.spyMarketData[itemHrid]).forEach(level => {
                        const data = this.spyMarketData[itemHrid][level];
                        if (data && data.a > 0) {
                            levelsWithData.add(parseInt(level));
                        }
                    });
                }
                let html = '<div class="mcs-ew-enh-col">';
                html += '<div class="mcs-ew-enh-row">';
                for (let level = 0; level <= 10; level++) {
                    const hasData = levelsWithData.has(level);
                    const bgColor = hasData ? 'rgba(76, 175, 80, 0.5)' : 'rgba(100, 100, 100, 0.3)';
                    const borderColor = hasData ? '#4CAF50' : '#666';
        html += `<button class="spy-enh-btn mcs-ew-enh-btn" data-slot="${slot}" data-hrid="${itemHrid}" data-level="${level}" style="
            background: ${bgColor};
            border: 1px solid ${borderColor};
                    ">+${level}</button>`;
                }
                html += '</div>';
                html += '<div class="mcs-ew-enh-row">';
                for (let level = 11; level <= 20; level++) {
                    const hasData = levelsWithData.has(level);
                    const bgColor = hasData ? 'rgba(76, 175, 80, 0.5)' : 'rgba(100, 100, 100, 0.3)';
                    const borderColor = hasData ? '#4CAF50' : '#666';
        html += `<button class="spy-enh-btn mcs-ew-enh-btn" data-slot="${slot}" data-hrid="${itemHrid}" data-level="${level}" style="
            background: ${bgColor};
            border: 1px solid ${borderColor};
                    ">+${level}</button>`;
                }
                html += '</div>';
                html += '</div>';
                buttonContainer.innerHTML = html;

                if (!this.ewatchButtonListeners) {
                    this.ewatchButtonListeners = new Map();
                }

                const containerKey = `container-${slot}`;

                if (this.ewatchButtonListeners.has(containerKey)) {
                    const oldListeners = this.ewatchButtonListeners.get(containerKey);
                    if (oldListeners.mouseenter) {
                        buttonContainer.removeEventListener('mouseenter', oldListeners.mouseenter);
                    }
                    if (oldListeners.mouseleave) {
                        buttonContainer.removeEventListener('mouseleave', oldListeners.mouseleave);
                    }
                }

                const mouseenterHandler = () => {
                    this.spyIsInteracting = true;
                };
                const mouseleaveHandler = () => {
                    setTimeout(() => {
                        this.spyIsInteracting = false;
                    }, 100);
                };

                this.ewatchButtonListeners.set(containerKey, {
                    mouseenter: mouseenterHandler,
                    mouseleave: mouseleaveHandler
                });

                buttonContainer.addEventListener('mouseenter', mouseenterHandler);
                buttonContainer.addEventListener('mouseleave', mouseleaveHandler);

                const equippedItem = this.spyCharacterItems.find(item => item.itemLocationHrid === `/item_locations/${slot}`
                );
                const equippedBidPrice = equippedItem ? this.getSpyEquippedValue(equippedItem.itemHrid, equippedItem.enhancementLevel ?? 0) : 0;

                const buttonKey = `buttons-${slot}`;
                if (this.ewatchButtonListeners.has(buttonKey)) {
                    const oldClickListener = this.ewatchButtonListeners.get(buttonKey).click;
                    if (oldClickListener) {
                        buttonContainer.removeEventListener('click', oldClickListener);
                    }
                }

                const buttonClickHandler = (e) => {
                    const btn = e.target.closest('.spy-enh-btn');
                    if (!btn) return;

                    e.stopPropagation();
                        this.spyIsInteracting = true;
                        buttonContainer.querySelectorAll('.spy-enh-btn').forEach(b => {
                            const btnLevel = parseInt(b.dataset.level);
                            const btnHasData = levelsWithData.has(btnLevel);
                            b.style.background = btnHasData ? 'rgba(76, 175, 80, 0.5)' : 'rgba(100, 100, 100, 0.3)';
                            b.style.borderColor = btnHasData ? '#4CAF50' : '#666';
                            b.classList.remove('spy-selected');
                        });
                        btn.style.background = this.spyConfig.MAIN_COLOR;
                        btn.style.borderColor = this.spyConfig.MAIN_COLOR;
                        btn.classList.add('spy-selected');
                        const hrid = btn.dataset.hrid;
                        const level = parseInt(btn.dataset.level);
                        const hasMarketData = this.spyMarketData[hrid] &&
                            this.spyMarketData[hrid][level] &&
                            this.spyMarketData[hrid][level].a > 0;
                        const askPrice = hasMarketData ? this.getSpyAskPrice(hrid, level) : 0;
                        const itemName = this.getSpyItemName(hrid);
                        const etaDisplay = document.getElementById(`spy-eta-display-${slot}`);
                        const difference = hasMarketData ?
                (this.spyNoSellMode ? Number(askPrice) : (Number(askPrice) - Number(equippedBidPrice)))
                : 0;
                        if (this.purchaseTimerInterval) {
                            clearInterval(this.purchaseTimerInterval);
                            this.purchaseTimerInterval = null;
                        }
                        if (etaDisplay) {
                            etaDisplay.innerHTML = '';
                        }
                        if (hasMarketData) {
                            if (difference > 0) {
                                if (this.totalPerDay > 0) {
                                    const currentGold = this.getSpyCurrentGold();
                                    const goldNeeded = difference - currentGold;
                                    if (goldNeeded > 0) {
                                        const targetGold = difference;
                                        const updateTimerDisplay = () => {
                                            if (document.hidden) return;
                                            const inCombat = this.isInCombat();
                                            if (!inCombat) {
                                                if (etaDisplay) {
                                                    if (this.spyFrozenEditModeTimer) {
                                            etaDisplay.innerHTML = `<div class="mcs-ew-eta-text">
                                                            <span class="mcs-ew-nc-label">NC</span>
                                                            <span class="mcs-ew-nc-time"> (${this.spyFrozenEditModeTimer})</span>
                                                                    </div>`;
                                                    } else {
                                            etaDisplay.innerHTML = `<div class="mcs-ew-eta-nc">
                                                            NC
                                                                    </div>`;
                                                    }
                                                }
                                                return;
                                            }

                                            const currentGold = this.getSpyCurrentGold();
                                            const stillNeeded = targetGold - currentGold;
                                            if (stillNeeded <= 0) {
                                                this.spyFrozenEditModeTimer = 'Affordable!';
                                                if (etaDisplay) {
                                        etaDisplay.innerHTML = `<div class="mcs-ew-eta-affordable-inline">
                                                        Affordable!
                                                                </div>`;
                                                }
                                                if (this.purchaseTimerInterval) {
                                                    clearInterval(this.purchaseTimerInterval);
                                                    this.purchaseTimerInterval = null;
                                                }
                                                return;
                                            }
                                            const daysToAfford = stillNeeded / this.totalPerDay;
                                            const totalSeconds = Math.floor(daysToAfford * 24 * 60 * 60);
                                            const months = Math.floor(totalSeconds / (30 * 24 * 60 * 60));
                                            const days = Math.floor((totalSeconds % (30 * 24 * 60 * 60)) / (24 * 60 * 60));
                                            const hours = Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60));
                                            const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
                                            const seconds = totalSeconds % 60;
                                            const parts = [];
                                            if (months > 0) parts.push(`${months}mo`);
                                            if (days > 0) parts.push(`${days}d`);
                                            parts.push(`${hours}h`);
                                            parts.push(`${minutes}m`);
                                            parts.push(`${seconds}s`);
                                            const timerDisplay = parts.join(' ');
                                            this.spyFrozenEditModeTimer = `Time: ${timerDisplay}`;
                                            if (etaDisplay) {
                                    etaDisplay.innerHTML = `<div class="mcs-ew-eta-countdown">
                                                    Time: ${timerDisplay}
                                                            </div>`;
                                            }
                                        };
                                        updateTimerDisplay();
                                        this.purchaseTimerInterval = setInterval(updateTimerDisplay, 1000);
                                    } else {
                                        if (etaDisplay) {
                                etaDisplay.innerHTML = `<div class="mcs-ew-eta-affordable-inline">
                                                Affordable!
                                                        </div>`;
                                        }
                                    }
                                } else {
                                    if (etaDisplay) {
                            etaDisplay.innerHTML = `<div class="mcs-ew-eta-nodata">
                                            No income data from loot tracker.
                                                    </div>`;
                                    }
                                }
                            }
                        } else {
                            if (etaDisplay) {
                    etaDisplay.innerHTML = `<div class="mcs-ew-eta-nodata">
                                    Never Seen
                                            </div>`;
                            }
                        }
                        const diffColor = difference > 0 ? '#ff6666' : difference < 0 ? '#66ff66' : '#FFD700';
                        const diffSign = difference > 0 ? '+' : '';
                        let timestampText = '';
                        if (this.spyMarketDataTimestamp) {
                            const timeSince = Date.now() - this.spyMarketDataTimestamp;
                            const minutesAgo = Math.floor(timeSince / (1000 * 60));
                            const hoursAgo = Math.floor(minutesAgo / 60);
                            const daysAgo = Math.floor(hoursAgo / 24);
                            if (daysAgo > 0) {
                                timestampText = `${daysAgo}d ago`;
                            } else if (hoursAgo > 0) {
                                timestampText = `${hoursAgo}h ago`;
                            } else if (minutesAgo > 0) {
                                timestampText = `${minutesAgo}m ago`;
                            } else {
                                timestampText = 'just now';
                            }
                        }
                        const currentGold = this.getSpyCurrentGold();
                        const stillNeeded = difference - currentGold;
                        const needsGoldText = stillNeeded > 0 ? ` <span class="mcs-ew-gold-needed">${this.formatGoldCompact(stillNeeded)} needed</span>` : '';

            priceDisplay.innerHTML = `
                ${itemName} +${level}${needsGoldText}<br>
                ${hasMarketData && timestampText ?
                    `<span class="mcs-ew-price-lastseen">Last Seen: ${timestampText}</span><br>` :
                    `<span class="mcs-ew-price-nodata">⚠ No Market Data</span><br>`}
                Lowest Ask: ${hasMarketData ? this.formatSpyCoins(askPrice) : 'N/A'}<br>
                <span style="color: ${diffColor};">Difference: ${hasMarketData ? diffSign + this.formatSpyCoins(difference) : 'N/A'}</span>
                        `;
                        const lockBtn = document.getElementById(`spy-lock-comparison-${slot}`);
                        if (lockBtn) {
                            lockBtn.onclick = () => this.lockSpyComparison(slot, hrid, level, askPrice, difference);
                        }
                        setTimeout(() => {
                            this.spyIsInteracting = false;
                        }, 2000);
                };

                this.ewatchButtonListeners.set(buttonKey, { click: buttonClickHandler });
                buttonContainer.addEventListener('click', buttonClickHandler);
            }
            spyEyeButtonHtml(slot, isSelected) {
                const icon = isSelected
                    ? `👁️`
                    : `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/><path d="M14.12 14.12a3 3 0 1 1-4.24-4.24"/></svg>`;
    return `<button class="spy-header-select-btn mcs-ew-eye-btn" data-slot="${slot}" style="
        background: ${isSelected ? 'rgba(100, 149, 237, 0.3)' : 'rgba(100, 100, 100, 0.2)'};
        border: 1px solid ${isSelected ? '#6495ED' : '#666'};
        color: ${isSelected ? '#6495ED' : '#999'};
                " title="Show this item in header">${icon}</button>`;
            }
            spyProgressBarHtml(progressPercent, isAffordable, hasGoldData) {
                const barColor = this.isInCombat() ? (isAffordable ? '#4CAF50' : '#6495ED') : '#f44336';
                const textColor = this.isInCombat() ? (isAffordable ? '#fff' : '#6495ED') : '#f44336';
                const statusText = !hasGoldData ? 'Waiting for data...' : (isAffordable ? 'Affordable' : `${progressPercent.toFixed(5)}%`);
                return `<div class="mcs-ew-progress-row">` +
                    `<div class="mcs-ew-progress-track">` +
                    `<div style="width: ${progressPercent}%; height: 100%; background: ${barColor}; transition: width 0.3s ease;"></div>` +
                    `</div>` +
                    `<span class="mcs-ew-progress-text" style="color: ${textColor}; font-weight: ${isAffordable ? 'bold' : 'normal'};">` +
                    statusText +
                    `</span>` +
                    `</div>`;
            }
            spySlotWrapperOpen(isSelected) {
    return `<div style="
    margin-top: 4px; padding: 6px 6px 2px 6px; border-radius: 3px;
    background: ${isSelected ? 'rgba(100, 149, 237, 0.1)' : 'rgba(255,215,0,0.1)'};
    border-left: 2px solid ${isSelected ? '#6495ED' : '#FFD700'};
            ">`;
            }
            updateSpyDisplay() {
                if (this.spyIsInteracting || this.spyOpenComparisons.size > 0) {
                    return;
                }
                if (this.purchaseTimerIntervals) {
                    Object.keys(this.purchaseTimerIntervals).forEach(slot => {
                        clearInterval(this.purchaseTimerIntervals[slot]);
                    });
                    this.purchaseTimerIntervals = {};
                }
                const content = document.getElementById('spy-content');
                if (!content) return;
                const itemByLocation = this._buildItemLocationMap();
                let equipped = this.spyCharacterItems.filter(item => {
                    if (!item.itemLocationHrid || item.itemLocationHrid === '/item_locations/inventory') {
                        return false;
                    }
                    const slot = item.itemLocationHrid.replace('/item_locations/', '');
                    return this.spyConfig.ALLOWED_SLOTS.includes(slot);
                });
                if (equipped.length === 0) {
        content.innerHTML = `
<div class="mcs-ew-no-equip">
    <div class="mcs-ew-no-equip-mb">No equipment equipped</div>
    ${createForceLoadEquipmentButton()}
</div>
                    `;
                    setTimeout(() => {
                        const btn = document.getElementById('spy-force-load-btn');
                        if (btn) {
                            btn.addEventListener('click', forceExtractEquipmentData);
                        }
                    }, 100);
                    return;
                }
                const openComparisons = {};
                this.spyConfig.ALLOWED_SLOTS.forEach(slot => {
                    const comparisonElement = document.getElementById(`spy-comparison-${slot}`);
                    if (comparisonElement && !comparisonElement.classList.contains('spy-default-watch-panel')) {
                        openComparisons[slot] = {
                            isOpen: true,
                            selectedItem: document.getElementById(`spy-item-select-${slot}`)?.value || '',
                            selectedEnhancement: null
                        };
                        const selectedBtn = comparisonElement.querySelector('.spy-enh-btn[style*="' + this.spyConfig.MAIN_COLOR + '"]');
                        if (selectedBtn) {
                            openComparisons[slot].selectedEnhancement = parseInt(selectedBtn.dataset.level);
                        }
                    }
                });
                let totalBidValue = 0;
                let currentGold = 0;
                let hasGoldData = false;
                const coinItem = this.spyCharacterItems.find(item => item.itemHrid === '/items/coin');
                if (coinItem && coinItem.count) {
                    currentGold = coinItem.count;
                    hasGoldData = true;
                }
                const goldPerDayFormatted = this.goldPerDayFormatted || '';
                let html = '<div class="mcs-ew-content-wrap">';
                html += `<div class="mcs-ew-gold-bar">`;
                html += `<div class="mcs-ew-gold-coin">`;
                html += `<span class="mcs-ew-coin-icon">${createItemIconHtml('coin', { width: '100%', height: '100%', sprite: 'items_sprite' })}</span>`;
                html += `<span id="spy-coin-amount">${this.formatSpyCoins(currentGold)}</span>`;
                html += `</div>`;

                const { totalAsk, totalBid } = this.mcs_nt_calculateTotals ? this.mcs_nt_calculateTotals() : { totalAsk: 0, totalBid: 0 };
                const useAskPrice = window.getFlootUseAskPrice ? window.getFlootUseAskPrice() : false;
                const ntallyPrice = useAskPrice ? totalAsk : totalBid;
                const ntallyLabel = useAskPrice ? 'ask' : 'bid';
                const ntallyColor = useAskPrice ? '#6495ED' : '#4CAF50';

                const marketTotal = this.mcs_nt_calculateMarketTotal ? this.mcs_nt_calculateMarketTotal() : 0;

                html += `<div class="mcs-ew-gold-stat" style="color: ${ntallyPrice > 0 ? ntallyColor : '#999'}; font-weight: ${ntallyPrice > 0 ? 'bold' : 'normal'};">`;
                html += `<span>📦</span>`;
                html += `<span>${this.mcs_nt_formatNumber ? this.mcs_nt_formatNumber(ntallyPrice) : ntallyPrice.toLocaleString()} ${ntallyLabel}</span>`;
                html += `</div>`;

                html += `<div class="mcs-ew-gold-stat" style="color: ${marketTotal > 0 ? '#FFD700' : '#999'}; font-weight: ${marketTotal > 0 ? 'bold' : 'normal'};">`;
                html += `<span>📈</span>`;
                html += `<span>${this.mcs_nt_formatNumber ? this.mcs_nt_formatNumber(marketTotal) : marketTotal.toLocaleString()}</span>`;
                html += `</div>`;

                html += `<div id="spy-coin-per-day" class="mcs-ew-gold-stat" style="color: ${goldPerDayFormatted ? '#90EE90' : '#999'}; font-weight: ${goldPerDayFormatted ? 'bold' : 'normal'};">`;
            if (goldPerDayFormatted) {
                const inCombat = this.isInCombat();
                if (!inCombat) {
                    html += `<span class="mcs-ew-nc-label">NC</span> <span class="mcs-ew-nc-time">(${goldPerDayFormatted}/day)</span>`;
                } else {
                    html += `${goldPerDayFormatted}/day`;
                }
            } else {
                html += `No income data`;
            }
            html += `</div>`;

            html += `</div>`;
                const lastRefreshed = this.spyMarketDataTimestamp
                    ? new Date(this.spyMarketDataTimestamp).toLocaleString([], {
                        month: 'short',
                        day: 'numeric',
                        hour: 'numeric',
                        minute: '2-digit'
                    })
                    : 'Never';
                html += `<div class="mcs-ew-market-bar">`;
                html += `<span class="mcs-ew-market-label">Market Data: ${lastRefreshed}</span>`;
                html += `<button id="spy-refresh-market" class="mcs-ew-refresh-btn">🔄 Refresh</button>`;
                html += `</div>`;

                const mvOn = this.spyMarketValueMode !== false;
                html += `<div class="mcs-ew-market-value-bar">`;
                html += `<span class="mcs-ew-market-label">Include market orders in calculations</span>`;
    html += `<button id="spy-market-value-toggle" class="mcs-ew-toggle-btn" style="
    background: ${mvOn ? 'rgba(76, 175, 80, 0.3)' : 'rgba(255, 100, 100, 0.3)'};
    border-color: ${mvOn ? '#4CAF50' : '#ff6666'};
    color: ${mvOn ? '#4CAF50' : '#ff6666'};
            ">${mvOn ? 'Market Value On' : 'Market Value Off'}</button>`;
                html += `</div>`;

                const slots = {};

                this.spyConfig.ALLOWED_SLOTS.forEach(slot => {
                    slots[slot] = [];
                });

                equipped.forEach(item => {
                    const slot = item.itemLocationHrid.replace('/item_locations/', '');
                    if (this.spyConfig.ALLOWED_SLOTS.includes(slot) && item.count > 0) {
                        slots[slot].push(item);
                    }
                });

                this.spyConfig.ALLOWED_SLOTS.forEach(slot => {
                    if (slots[slot].length === 0) {
                        slots[slot].push({
                            itemLocationHrid: `/item_locations/${slot}`,
                            itemHrid: '/items/empty',
                            enhancementLevel: 0,
                            count: 0
                        });
                    }
                });

                const sortedSlots = this.getOrderedSlots(slots);
                sortedSlots.forEach(slot => {
                    if (!this.spyConfig.ALLOWED_SLOTS.includes(slot)) {
                        return;
                    }
                    const slotName = slot.split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
                    slots[slot].forEach(item => {
                        if (this.spySimpleMode && !this.spyLockedComparisons[slot]) {
                            return;
                        }
                        const itemName = this.getSpyItemName(item.itemHrid);
                        const enhLevel = item.enhancementLevel ?? 0;
                        const equippedValue = this.getSpyEquippedValue(item.itemHrid, enhLevel);
                        totalBidValue += equippedValue * item.count;
                        const enhText = enhLevel > 0 ? ` +${enhLevel}` : '';
                        const countText = item.count > 1 ? ` x${item.count}` : '';
                        const bidText = equippedValue > 0 ? this.formatSpyCoins(equippedValue) : 'No bid';
            html += `<div id="spy-slot-${slot}"
              draggable="true"
              data-slot="${slot}"
                          class="spy-slot-draggable mcs-ew-slot">`;
                        if (!this.spySimpleMode) {
                            html += `<div class="mcs-ew-equip-row spy-equip-slot-row" data-slot="${slot}" data-item-hrid="${item.itemHrid}">`;
                            html += `<span class="mcs-ew-slot-name">${slotName}:</span>`;
                            html += `<span class="mcs-ew-slot-item">${itemName}${enhText}${countText}</span>`;
                            html += `<span class="mcs-ew-slot-bid">${bidText}</span>`;
                            html += `</div>`;
                        }
                        if (this.spyLockedComparisons[slot]) {
                            const locked = this.spyLockedComparisons[slot];
                            const lockedItemName = this.getSpyItemName(locked.itemHrid);
                            let currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);
                            const hasCurrentMarketData = currentAskPrice > 0;
                            if (!hasCurrentMarketData && (!locked.lastKnownAskPrice || locked.lastKnownAskPrice === 0)) {
                                if (this.spySimpleMode) {
                                    html += `<div class="mcs-ew-locked-nodata">`;
                                    html += `<div class="mcs-ew-flex-between">`;
                                    html += `<div class="mcs-ew-flex-col">`;
                                    html += `<div class="mcs-ew-locked-name-nodata">${lockedItemName} +${locked.enhLevel}</div>`;
                                    html += `<div class="mcs-ew-waiting-market">Waiting for market data...</div>`;
                                    html += `</div>`;
                                    html += `<div class="mcs-ew-never-seen">Never Seen</div>`;
                                    html += `</div>`;
                                    html += `</div>`;
                                } else {
                                    html += `<div class="mcs-ew-locked-nodata">`;
                                    html += `<div class="mcs-ew-flex-between">`;
                                    html += `<div class="mcs-ew-watching-label">👁️ Watching:</div>`;
                                    html += `<button class="spy-unlock-btn mcs-ew-unwatch-btn" data-slot="${slot}">✖ Unwatch</button>`;
                                    html += `</div>`;
                                    html += `<div class="mcs-ew-locked-name">${lockedItemName} +${locked.enhLevel}</div>`;
                                    html += `<div class="mcs-ew-waiting-centered">Waiting for market data...</div>`;
                                    html += `<div id="spy-locked-eta-${slot}" class="mcs-ew-eta-display"></div>`;
                                    html += `</div>`;
                                }
                            } else {
                                let usingLastKnownPrice = false;
                                if (currentAskPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                                    currentAskPrice = locked.lastKnownAskPrice;
                                    usingLastKnownPrice = true;
                                }
                                const currentEquippedBid = this.getSpyEquippedValue(item.itemHrid, enhLevel);
                                const currentDifference = this.spyNoSellMode ? currentAskPrice : (currentAskPrice - currentEquippedBid);
                                const diffColor = currentDifference > 0 ? '#ff6666' : currentDifference < 0 ? '#66ff66' : '#FFD700';
                                const diffSign = currentDifference > 0 ? '+' : '';
                                const totalGold = currentGold;
                                const needGold = currentDifference;
                                let progressPercent = 0;
                                let isAffordable = false;
                                if (needGold > 0) {
                                    progressPercent = Math.min((totalGold / needGold) * 100, 100);
                                    isAffordable = progressPercent >= 100;
                                } else {
                                    progressPercent = 100;
                                    isAffordable = true;
                                }
                                const isSelected = this.spySelectedHeaderSlot === slot;
                                const stillNeeded = currentDifference - currentGold;
                                const needsGoldText = stillNeeded > 0 ? ` <span id="spy-remaining-${slot}" class="mcs-ew-gold-needed">${this.formatGoldCompact(stillNeeded)} needed</span>` : '';
                                html += this.spySlotWrapperOpen(isSelected);
                                if (this.spySimpleMode) {
                                    html += `<div class="mcs-ew-flex-between">`;
                                    html += `<div class="mcs-ew-flex-row">`;
                                    html += this.spyEyeButtonHtml(slot, isSelected);
                                    html += `<div class="mcs-ew-flex-col">`;
                                    html += `<div class="mcs-ew-locked-gold-name">${lockedItemName} +${locked.enhLevel}${needsGoldText}</div>`;
                                    if (usingLastKnownPrice) {
                                        html += `<div class="mcs-ew-last-price-note">Using last seen price</div>`;
                                    }
                                    html += `</div>`;
                                    html += `</div>`;
                                    html += `<div id="spy-locked-eta-${slot}" class="mcs-ew-locked-eta"></div>`;
                                    html += `</div>`;
                                } else {
                                    html += `<div class="mcs-ew-flex-between">`;
                                    html += `<div class="mcs-ew-flex-row">`;
                                    html += this.spyEyeButtonHtml(slot, isSelected);
                                    html += `<div class="mcs-ew-watching-title">Watching</div>`;
                                    html += `</div>`;
                                    html += `<button class="spy-unlock-btn mcs-ew-unwatch-btn" data-slot="${slot}">✖ Unwatch</button>`;
                                    html += `</div>`;
                                    html += `<div class="mcs-ew-locked-gold-name-mb">${lockedItemName} +${locked.enhLevel}${needsGoldText}</div>`;
                                    if (locked.lastKnownPriceTimestamp) {
                                        const timeSinceLastSeen = Date.now() - locked.lastKnownPriceTimestamp;
                                        const minutesAgo = Math.floor(timeSinceLastSeen / (1000 * 60));
                                        const hoursAgo = Math.floor(minutesAgo / 60);
                                        const daysAgo = Math.floor(hoursAgo / 24);
                                        let timeAgoText = '';
                                        if (daysAgo > 0) {
                                            timeAgoText = `${daysAgo}d ago`;
                                        } else if (hoursAgo > 0) {
                                            timeAgoText = `${hoursAgo}h ago`;
                                        } else if (minutesAgo > 0) {
                                            timeAgoText = `${minutesAgo}m ago`;
                                        } else {
                                            timeAgoText = 'just now';
                                        }
                                        html += `<div class="mcs-ew-price-change">Last Price Change: ${timeAgoText}</div>`;
                                    }
                                    html += `<div class="mcs-ew-price-row">`;
                                    html += `<span class="mcs-ew-price-label">Ask Price:</span>`;
                                    if (usingLastKnownPrice) {
                                        html += `<div class="mcs-ew-ask-price-group">`;
                                        html += `<span class="mcs-ew-price-gold">${this.formatSpyCoins(currentAskPrice)}</span>`;
                                        html += `<span class="mcs-ew-last-known-note">(last known)</span>`;
                                        html += `</div>`;
                                    } else {
                                        html += `<span class="mcs-ew-price-gold">${this.formatSpyCoins(currentAskPrice)}</span>`;
                                    }
                                    html += `</div>`;
                                    html += `<div class="mcs-ew-price-row-mb6">`;
                                    html += `<span class="mcs-ew-price-label">Difference:</span>`;
                                    html += `<span style="color: ${diffColor}; font-weight: bold;">${diffSign}${this.formatSpyCoins(currentDifference)}</span>`;
                                    html += `</div>`;
                                }
                                html += this.spyProgressBarHtml(progressPercent, isAffordable, hasGoldData);
                                if (!this.spySimpleMode) {
                                    html += `<div id="spy-locked-eta-${slot}" class="mcs-ew-eta-display"></div>`;
                                }
                                html += `</div>`;
                            }
                        } else {
                            html += `<div id="spy-default-${slot}" class="mcs-ew-default-panel spy-default-watch-panel" style="border-left: 2px solid ${this.spyConfig.MAIN_COLOR};" data-slot="${slot}" data-item-hrid="${item.itemHrid}">`;
                html += `<div class="mcs-ew-default-inner">
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/>
                        <path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/>
                        <line x1="1" y1="1" x2="23" y2="23"/>
                        <path d="M14.12 14.12a3 3 0 1 1-4.24-4.24"/>
                    </svg>
                    <span>Click to watch</span>
                            </div>`;
                            html += `</div>`;
                        }
                        html += `</div>`;
                    });
                });
                if (!this.spySimpleMode) {
                    html += `<div class="mcs-ew-total-row" style="border-top: 1px solid ${this.spyConfig.BORDER_COLOR};">`;
                    html += `<span style="color: ${this.spyConfig.MAIN_COLOR};">Total:</span>`;
                    html += `<span style="color: #FFD700;">${this.formatSpyCoins(totalBidValue)}</span>`;
                    html += `</div>`;
                }
                let lockedSlots = Object.keys(this.spyLockedComparisons);
                if (this.comparisonOrder && Array.isArray(this.comparisonOrder)) {
                    const orderedSlots = this.comparisonOrder.filter(slot => lockedSlots.includes(slot));
                    const newSlots = lockedSlots.filter(slot => !this.comparisonOrder.includes(slot));
                    lockedSlots = [...orderedSlots, ...newSlots];
                }
                if (lockedSlots.length > 0) {
                    let totalCost = 0;
                    let segmentData = [];
                    lockedSlots.forEach(slot => {
                        const locked = this.spyLockedComparisons[slot];
                        const item = itemByLocation.get(`/item_locations/${slot}`);
                        const currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);
                        let priceToUse = currentAskPrice;
                        if (currentAskPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                            priceToUse = locked.lastKnownAskPrice;
                        }
                        const currentEquippedBid = item ?
                            this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0) : 0;
                        const currentDifference = this.spyNoSellMode ? priceToUse : (priceToUse - currentEquippedBid);
                        if (currentDifference > 0) {
                            totalCost += currentDifference;
                            segmentData.push({
                                slot: slot,
                                cost: currentDifference
                            });
                        }
                    });
                    if (totalCost > 0) {
                        const progressPercent = Math.min((currentGold / totalCost) * 100, 100);
                        const isAffordable = progressPercent >= 100;
                        segmentData.forEach(seg => {
                            seg.percent = (seg.cost / totalCost) * 100;
                        });
                        const stillNeeded = totalCost - currentGold;
                        const everythingGoldText = stillNeeded > 0 ? ` <span class="mcs-ew-gold-needed">${this.formatGoldCompact(stillNeeded)} needed</span>` : '';
                        let everythingTimerHtml = '';
                        if (this.goldPerDay > 0 && !isAffordable) {
                            const daysToAfford = stillNeeded / this.totalPerDay;
                            const totalSeconds = Math.floor(daysToAfford * 24 * 60 * 60);
                            const months = Math.floor(totalSeconds / (30 * 24 * 60 * 60));
                            const days = Math.floor((totalSeconds % (30 * 24 * 60 * 60)) / (24 * 60 * 60));
                            const hours = Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60));
                            const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
                            const seconds = totalSeconds % 60;
                            const parts = [];
                            if (months > 0) parts.push(`${months}mo`);
                            if (days > 0) parts.push(`${days}d`);
                            if (hours > 0) parts.push(`${hours}h`);
                            if (minutes > 0) parts.push(`${minutes}m`);
                            if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
                            everythingTimerHtml = `<div id="spy-everything-timer" class="mcs-ew-everything-timer">${parts.join(' ')}</div>`;
                        } else if (isAffordable) {
                            everythingTimerHtml = `<div class="mcs-ew-everything-affordable">Affordable!</div>`;
                        }
                        const isEverythingSelected = this.spySelectedHeaderSlot === 'everything';
            html += `<div class="spy-everything-section mcs-ew-everything" style="
    background: ${isEverythingSelected ? 'rgba(100, 149, 237, 0.1)' : 'rgba(255,165,0,0.1)'};
    border-left: 2px solid ${isEverythingSelected ? '#6495ED' : '#FFA500'};
    border-top: 1px solid ${this.spyConfig.BORDER_COLOR};
            ">`;
                        html += `<div class="mcs-ew-flex-between">`;
                        html += `<div class="mcs-ew-flex-row">`;
                        const eyeIconEverything = isEverythingSelected
                            ? `👁️`
                            : `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/><path d="M14.12 14.12a3 3 0 1 1-4.24-4.24"/></svg>`;
            html += `<button class="spy-header-select-btn mcs-ew-eye-btn" data-slot="everything" style="
        background: ${isEverythingSelected ? 'rgba(100, 149, 237, 0.3)' : 'rgba(100, 100, 100, 0.2)'};
        border: 1px solid ${isEverythingSelected ? '#6495ED' : '#666'};
        color: ${isEverythingSelected ? '#6495ED' : '#999'};
                " title="Show everything in header">${eyeIconEverything}</button>`;
                        html += `<div class="mcs-ew-everything-title">Everything${everythingGoldText}</div>`;
                        html += `</div>`;
                        html += everythingTimerHtml;
                        html += `</div>`;
                        html += `<div class="mcs-ew-everything-progress">`;
                        html += `<div class="mcs-ew-everything-track">`;
                        const everythingBarColor = this.isInCombat() ? (isAffordable ? '#4CAF50' : '#6495ED') : '#f44336';
                        html += `<div style="width: ${progressPercent}%; height: 100%; background: ${everythingBarColor}; transition: width 0.3s ease; position: absolute; top: 0; left: 0;"></div>`;
                        let cumulativePercent = 0;
                        segmentData.forEach((seg, idx) => {
                            cumulativePercent += seg.percent;
                            if (idx < segmentData.length - 1) {
                                html += `<div class="mcs-ew-tick-mark" style="left: ${cumulativePercent}%;"></div>`;
                            }
                        });
                        html += `</div>`;
                        const everythingTextColor = this.isInCombat() ? (isAffordable ? '#fff' : '#6495ED') : '#f44336';
                        html += `<span class="mcs-ew-progress-text" style="color: ${everythingTextColor}; font-weight: ${isAffordable ? 'bold' : 'normal'};">`;
                        html += !hasGoldData ? 'Waiting for data...' : (isAffordable ? 'Affordable' : `${progressPercent.toFixed(5)}%`);
                        html += `</span>`;
                        html += `</div>`;
                        html += `</div>`;
                    }
                }
                if (this.spySimpleMode && Object.keys(this.spyLockedComparisons).length === 0) {
        html += `<div class="mcs-ew-simple-empty">
Simple mode: Lock comparisons to track items
                    </div>`;
                }
                html += '</div>';
                const preservedTimers = {};
                Object.keys(this.spyLockedComparisons).forEach(slot => {
                    const existingEta = document.getElementById(`spy-locked-eta-${slot}`);
                    if (existingEta && existingEta.innerHTML.trim()) {
                        preservedTimers[slot] = existingEta.innerHTML;
                    }
                });
                content.innerHTML = html;
                Object.keys(preservedTimers).forEach(slot => {
                    const etaElement = document.getElementById(`spy-locked-eta-${slot}`);
                    if (etaElement) {
                        etaElement.innerHTML = preservedTimers[slot];
                    }
                });
                const slotDivs = document.querySelectorAll('[id^="spy-slot-"]');
                slotDivs.forEach(slotDiv => {
                    slotDiv.addEventListener('dragstart', (e) => {
                        this.spyIsInteracting = true;
                        this.draggedSlot = slotDiv.dataset.slot;
                        slotDiv.classList.add('dragging');
                        slotDiv.style.backgroundColor = 'rgba(200, 200, 200, 0.5)';
                        slotDiv.style.border = '2px solid #999';
                        document.body.classList.add('spy-dragging');
                        e.dataTransfer.effectAllowed = 'move';
                        e.dataTransfer.setData('text/plain', slotDiv.dataset.slot);
                        const canvas = document.createElement('canvas');
                        canvas.width = 1;
                        canvas.height = 1;
                        const ctx = canvas.getContext('2d');
                        ctx.clearRect(0, 0, 1, 1);
                        e.dataTransfer.setDragImage(canvas, 0, 0);
                        setTimeout(() => {
                            const spyContentEl = document.getElementById('spy-content');
                            const allSlots = [...spyContentEl.querySelectorAll('.spy-slot-draggable')];
                            const draggingIndex = allSlots.indexOf(slotDiv);
                            const isFirstItem = draggingIndex === 0;
                            const isLastItem = draggingIndex === allSlots.length - 1;
                            allSlots.forEach((slot, index) => {
                                if (index === draggingIndex) return;
                                if (isLastItem && index === draggingIndex + 1) return;
                                if (isFirstItem && index === 0) return;
                                if (isFirstItem && index === 1) return;
                                const dropZone = document.createElement('div');
                                dropZone.className = 'spy-drop-zone mcs-ew-drop-zone';
                                slot.parentNode.insertBefore(dropZone, slot);
                            });
                            if (!isLastItem) {
                                const everythingSection = spyContentEl.querySelector('.spy-everything-section');
                                const lastDropZone = document.createElement('div');
                                lastDropZone.className = 'spy-drop-zone mcs-ew-drop-zone';
                                if (everythingSection && everythingSection.parentNode) {
                                    everythingSection.parentNode.insertBefore(lastDropZone, everythingSection);
                                } else {
                                    spyContentEl.appendChild(lastDropZone);
                                }
                            }
                        }, 10);
                    });
                    slotDiv.addEventListener('dragend', (e) => {
                        this.spyIsInteracting = false;
                        slotDiv.classList.remove('dragging');
                        slotDiv.style.backgroundColor = '';
                        slotDiv.style.border = '';
                        document.body.classList.remove('spy-dragging');
                        this.draggedSlot = null;
                        this.lastHighlightedZone = null;
                        document.querySelectorAll('.spy-drop-zone').forEach(dz => dz.remove());
                    });
                });
                const spyContent = document.getElementById('spy-content');
                if (spyContent && !spyContent.dataset.dragListenersAdded) {
                    spyContent.dataset.dragListenersAdded = 'true';
                    spyContent.addEventListener('dragover', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        e.dataTransfer.dropEffect = 'move';
                        e.dataTransfer.effectAllowed = 'move';
                        const dropZone = document.elementFromPoint(e.clientX, e.clientY);
                        if (dropZone !== this.lastHighlightedZone) {
                            if (this.lastHighlightedZone && this.lastHighlightedZone.classList.contains('spy-drop-zone')) {
                                this.lastHighlightedZone.style.background = 'rgba(200, 200, 200, 0.3)';
                                this.lastHighlightedZone.style.borderColor = '#999';
                            }
                            if (dropZone && dropZone.classList.contains('spy-drop-zone')) {
                                dropZone.style.background = 'rgba(76, 175, 80, 0.6)';
                                dropZone.style.borderColor = '#4CAF50';
                                this.targetDropZone = dropZone;
                            } else {
                                this.targetDropZone = null;
                            }
                            this.lastHighlightedZone = dropZone;
                        }
                    });
                    spyContent.addEventListener('dragenter', (e) => {
                        e.preventDefault();
                        e.dataTransfer.dropEffect = 'move';
                    });
                    spyContent.addEventListener('drop', (e) => {
                        e.preventDefault();
                        if (!this.draggedSlot) return;
                        const spyContentEl = document.getElementById('spy-content');
                        const draggingElement = document.querySelector('.spy-slot-draggable.dragging');
                        if (this.targetDropZone && draggingElement) {
                            this.targetDropZone.parentNode.insertBefore(draggingElement, this.targetDropZone);
                        }
                        const allSlots = [...spyContentEl.querySelectorAll('[id^="spy-slot-"]')];
                        this.comparisonOrder = allSlots.map(el => el.dataset.slot);
                        this.saveComparisonOrder();
                        this.updateEverythingSegments();
                        this.targetDropZone = null;
                    });
                }
                document.querySelectorAll('.spy-default-watch-panel').forEach(panel => {
                    panel.addEventListener('click', () => {
                        const slot = panel.dataset.slot;
                        const itemHrid = panel.dataset.itemHrid;
                        this.showSpyComparison(slot, itemHrid);
                    });
                });
                document.querySelectorAll('.spy-unlock-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const slot = btn.dataset.slot;
                        this.unlockSpyComparison(slot);
                    });
                });
                document.querySelectorAll('.spy-header-select-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const slot = btn.dataset.slot;
                        this.toggleHeaderSelection(slot);
                    });
                });
                const refreshMarketBtn = document.getElementById('spy-refresh-market');
                if (refreshMarketBtn) {
                    refreshMarketBtn.addEventListener('click', async () => {
                        refreshMarketBtn.disabled = true;
                        refreshMarketBtn.textContent = '⏳ Refreshing...';
                        refreshMarketBtn.style.opacity = '0.6';
                        await this.loadSpyMarketData();
                        this.updateLastKnownPrices();
                        this.updateSpyDisplay();
                        refreshMarketBtn.textContent = '✓ Updated!';
                        refreshMarketBtn.style.background = 'rgba(76, 175, 80, 0.3)';
                        refreshMarketBtn.style.borderColor = '#4CAF50';
                        refreshMarketBtn.style.color = '#4CAF50';
                        setTimeout(() => {
                            refreshMarketBtn.disabled = false;
                            refreshMarketBtn.textContent = '🔄 Refresh';
                            refreshMarketBtn.style.background = 'rgba(100, 149, 237, 0.3)';
                            refreshMarketBtn.style.borderColor = '#6495ED';
                            refreshMarketBtn.style.color = '#6495ED';
                            refreshMarketBtn.style.opacity = '1';
                        }, 2000);
                    });
                }
                const marketValueToggle = document.getElementById('spy-market-value-toggle');
                if (marketValueToggle) {
                    marketValueToggle.addEventListener('click', () => this.toggleMarketValueMode());
                }

                this.updateCoinHeader();
                setTimeout(() => this.updateLockedTimers(), 100);
                VisibilityManager.clear('ewatch-coin-header');
                VisibilityManager.register('ewatch-coin-header', () => this.updateCoinHeader(), 5000);
                this.updateProfitCostDisplay();
                this.updateHeaderStatus();
            }
            updateLastKnownPrices() {
                let needsSave = false;
                Object.keys(this.spyLockedComparisons).forEach(slot => {
                    const locked = this.spyLockedComparisons[slot];
                    const currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);
                    if (currentAskPrice > 0 && currentAskPrice !== locked.lastKnownAskPrice) {
                        locked.lastKnownAskPrice = currentAskPrice;
                        locked.lastKnownPriceTimestamp = Date.now();
                        needsSave = true;
                    }
                });
                if (needsSave) {
                    this.saveLockedComparisons();
                }
            }
            updateEverythingSegments() {
                const everythingSection = document.querySelector('.spy-everything-section');
                if (!everythingSection) return;
                const lockedSlots = Object.keys(this.spyLockedComparisons);
                if (lockedSlots.length === 0) return;
                const itemByLocation = this._buildItemLocationMap();
                let orderedLockedSlots = lockedSlots;
                if (this.comparisonOrder && Array.isArray(this.comparisonOrder)) {
                    const orderedSlots = this.comparisonOrder.filter(slot => lockedSlots.includes(slot));
                    const newSlots = lockedSlots.filter(slot => !this.comparisonOrder.includes(slot));
                    orderedLockedSlots = [...orderedSlots, ...newSlots];
                }
                let totalCost = 0;
                const segmentData = [];
                orderedLockedSlots.forEach(slot => {
                    const locked = this.spyLockedComparisons[slot];
                    const item = itemByLocation.get(`/item_locations/${slot}`);
                    const currentAskPrice = this.getSpyAskPrice(locked.itemHrid, locked.enhLevel);
                    let priceToUse = currentAskPrice;
                    if (currentAskPrice === 0 && locked.lastKnownAskPrice && locked.lastKnownAskPrice > 0) {
                        priceToUse = locked.lastKnownAskPrice;
                    }
                    const currentEquippedBid = item ?
                        this.getSpyEquippedValue(item.itemHrid, item.enhancementLevel ?? 0) : 0;
            const currentDifference = this.spyNoSellMode ? priceToUse : (priceToUse - currentEquippedBid);
                    if (currentDifference > 0) {
                        totalCost += currentDifference;
                        segmentData.push({
                            slot: slot,
                            cost: currentDifference
                        });
                    }
                });
                if (totalCost === 0) return;
                segmentData.forEach(seg => {
                    seg.percent = (seg.cost / totalCost) * 100;
                });
                const progressBarContainer = everythingSection.querySelector('.mcs-ew-everything-track');
                if (!progressBarContainer) return;
                progressBarContainer.querySelectorAll('.mcs-ew-tick-mark').forEach(marker => marker.remove());
                let cumulativePercent = 0;
                segmentData.forEach((seg, idx) => {
                    cumulativePercent += seg.percent;
                    if (idx < segmentData.length - 1) {
                        const marker = document.createElement('div');
                        marker.className = 'mcs-ew-tick-mark';
                        marker.style.left = `${cumulativePercent}%`;
                        progressBarContainer.appendChild(marker);
                    }
                });
            }
            getDragAfterElement(container, y) {
                const draggableElements = [...container.querySelectorAll('.spy-slot-draggable:not([style*="opacity: 0.5"])')]
                    .filter(el => el.dataset.slot !== this.draggedSlot);
                return draggableElements.reduce((closest, child) => {
                    const box = child.getBoundingClientRect();
                    const offset = y - box.top - box.height / 2;
                    if (offset < 0 && offset > closest.offset) {
                        return { offset: offset, element: child };
                    } else {
                        return closest;
                    }
                }, { offset: Number.NEGATIVE_INFINITY }).element;
            }
            handleStartHiddenChange() {
                this.startHiddenEnabled = this.domRefs.startHiddenCheckbox.checked;
                localStorage.setItem(CONFIG.STORAGE.startHidden, String(this.startHiddenEnabled));
            }
            handleHistorySelectionChange() {
                const selectedValue = this.domRefs.historySelect.value;
                this.viewingLive = (selectedValue === 'live');
                if (selectedValue === 'combined') {
                    this.aggregateSessionHistory();
                }
                this.renderCurrentView();
                this.updateTimerDisplay();
            }
            bindUiEvents() {
                this.domRefs.headerTopRow.addEventListener('mousedown', (e) => {
                    if (!this.isHidden && e.button === 0 && !e.target.closest('button, .ldt-settings-menu, .ldt-history-select, input')) {
                        this.startMove(e);
                    }
                });
                this.domRefs.panel.addEventListener('mousedown', (e) => {
                    if (this.isHidden && e.button === 0 && !e.target.closest('button')) {
                        this.startMove(e);
                    }
                });
                this.domRefs.settingsButton.onclick = (e) => { e.stopPropagation(); this.toggleSettingsMenu(); };
                this.domRefs.clearButton.onclick = () => this.clearHistory();
                this.domRefs.exportButton.onclick = () => this.exportLootCsv();
                if (this.domRefs.spyButton) this.domRefs.spyButton.onclick = () => this.spy();
                this.domRefs.showButton.onclick = () => this.toggleVisibility();
                if (this.domRefs.minimizeContentButton) {
                    this.domRefs.minimizeContentButton.onclick = () => this.toggleVisibility();
                }

                this.domRefs.startHiddenCheckbox.onchange = () => this.handleStartHiddenChange();
                this.domRefs.historySelect.onchange = () => this.handleHistorySelectionChange();
                const tooltipElements = this.domRefs.panel.querySelectorAll('[data-tooltip]');
                tooltipElements.forEach(el => {
                    el.addEventListener('mouseenter', (e) => this.showTooltip(e));
                    el.addEventListener('mouseleave', () => this.hideTooltip());
                });
                if (!this._boundHandleClickOutsideMenu) {
                    this._boundHandleClickOutsideMenu = this.handleClickOutsideMenu.bind(this);
                }
                document.addEventListener('click', this._boundHandleClickOutsideMenu);
                window.addEventListener("LootTrackerCombatEnded", (e) => this.handleSessionEnd(e.detail));
                window.addEventListener("LootTrackerBattle", (e) => this.processBattleUpdate(e.detail));
                window.addEventListener('storage', (e) => this.handleStorageChange(e));

                const waitForData = () => {
                    const hasCharacterData = CharacterDataStorage.getCurrentCharacterName();
                    const hasClientData = InitClientDataCache.get();

                    if (hasCharacterData && hasClientData) {
                        console.log('[MCS] Panels generated');
                        this.createEquipmentSpy();
                    } else {
                        setTimeout(waitForData, 500);
                    }
                };

                setTimeout(waitForData, 1000);

                if (this.domRefs.minimizeContentButton) {
                    this.domRefs.minimizeContentButton.textContent = this.isHidden ? '+' : '−';
                }
            }

            destroyEWatch() {
                if (this.purchaseTimerIntervals) {
                    Object.keys(this.purchaseTimerIntervals).forEach(slot => {
                        clearInterval(this.purchaseTimerIntervals[slot]);
                    });
                    this.purchaseTimerIntervals = {};
                }
                VisibilityManager.clear('ewatch-market-refresh');
                VisibilityManager.clear('ewatch-profit-cost');
                VisibilityManager.clear('ewatch-coin-header');
                if (this._ewatchWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._ewatchWsListener); this._ewatchWsListener = null; }
                if (this._ewatchForceLoadListener) { window.removeEventListener('EquipSpyForceLoadSuccess', this._ewatchForceLoadListener); this._ewatchForceLoadListener = null; }
                if (this._ewatchBridgeForceLoadListener) { window.removeEventListener('EquipSpyForceLoadSuccess', this._ewatchBridgeForceLoadListener); this._ewatchBridgeForceLoadListener = null; }
                if (this._ewatchCharDataListener) { window.removeEventListener('LootTrackerCharacterData', this._ewatchCharDataListener); this._ewatchCharDataListener = null; }
                if (this._ewatchCoinListener) { window.removeEventListener('EquipSpyCoinUpdate', this._ewatchCoinListener); this._ewatchCoinListener = null; }
                if (this._ewatchBattleListener) { window.removeEventListener('LootTrackerBattle', this._ewatchBattleListener); this._ewatchBattleListener = null; }
                if (this._ewatchCombatEndedListener) { window.removeEventListener('LootTrackerCombatEnded', this._ewatchCombatEndedListener); this._ewatchCombatEndedListener = null; }
                if (this._ewatchEquipChangedListener) { window.removeEventListener('MCS_EquipmentChanged', this._ewatchEquipChangedListener); this._ewatchEquipChangedListener = null; }
                if (this._equipChangedListener) { window.removeEventListener('MCS_EquipmentChanged', this._equipChangedListener); this._equipChangedListener = null; }
                if (this._spyDragoverListener) {
                    document.removeEventListener('dragover', this._spyDragoverListener);
                    this._spyDragoverListener = null;
                    document._spyDragoverAdded = false;
                }
                if (this._spyOnDragMove) {
                    document.removeEventListener('mousemove', this._spyOnDragMove);
                    document.removeEventListener('mouseup', this._spyOnDragUp);
                    this._spyOnDragMove = null;
                    this._spyOnDragUp = null;
                }
                if (this._spyOnDragStart) {
                    const header = document.querySelector('#equipment-spy-pane .mcs-ew-spy-header');
                    if (header) header.removeEventListener('mousedown', this._spyOnDragStart);
                    this._spyOnDragStart = null;
                }
                if (this._boundMovePanel) {
                    document.removeEventListener('mousemove', this._boundMovePanel);
                    this._boundMovePanel = null;
                }
                if (this._boundEndMove) {
                    document.removeEventListener('mouseup', this._boundEndMove);
                    this._boundEndMove = null;
                }
                if (this._boundHandleClickOutsideMenu) {
                    document.removeEventListener('click', this._boundHandleClickOutsideMenu);
                    this._boundHandleClickOutsideMenu = null;
                }
                const pane = document.getElementById('equipment-spy-pane');
                if (pane) pane.remove();
            }

// EWatch end

// FCB start

            get fcStorage() {
                if (!this._fcStorage) {
                    this._fcStorage = createModuleStorage('FC');
                }
                return this._fcStorage;
            }

            initFCB() {
                this.fcbEnabled = this.fcStorage.get('enabled', false) === true;

                const self = this;
                const recheckSettings = () => {
                    const charName = CharacterDataStorage.getCurrentCharacterName();
                    if (charName && charName !== 'default') {
                        self.fcStorage.clearCache();
                        self.fcbEnabled = self.fcStorage.get('enabled', false) === true;
                        self.fcbEnemyDPSEnabled = self.fcStorage.get('enemyd', false) === true;
                        self.fcbPlayerDPSEnabled = self.fcStorage.get('playerd', false) === true;
                        self.fcbPlayerNameRecolorEnabled = self.fcStorage.get('playerc', false) === true;
                    } else {
                        setTimeout(recheckSettings, 1000);
                    }
                };
                setTimeout(recheckSettings, 1000);

                this.fcbEnemyDPSEnabled = this.fcStorage.get('enemyd', false) === true;
                this.fcbPlayerDPSEnabled = this.fcStorage.get('playerd', false) === true;
                this.fcbPlayerNameRecolorEnabled = this.fcStorage.get('playerc', false) === true;
                this.fcbSettingsMap = {
                    tracker0 : {
                        id: "tracker0",
                        desc: "Enable player #1 damage text",
                        isTrue: true,
                        descH: "Enable player #1 healing text",
                        isTrueH: true,
                        r: 255,
                        g: 99,
                        b: 132,
                    },
                    tracker1 : {
                        id: "tracker1",
                        desc: "Enable player #2 damage text",
                        isTrue: true,
                        descH: "Enable player #2 healing text",
                        isTrueH: true,
                        r: 54,
                        g: 162,
                        b: 235,
                    },
                    tracker2 : {
                        id: "tracker2",
                        desc: "Enable player #3 damage text",
                        isTrue: true,
                        descH: "Enable player #3 healing text",
                        isTrueH: true,
                        r: 255,
                        g: 206,
                        b: 86,
                    },
                    tracker3 : {
                        id: "tracker3",
                        desc: "Enable player #4 damage text",
                        isTrue: true,
                        descH: "Enable player #4 healing text",
                        isTrueH: true,
                        r: 75,
                        g: 192,
                        b: 192,
                    },
                    tracker4 : {
                        id: "tracker4",
                        desc: "Enable player #5 damage text",
                        isTrue: true,
                        descH: "Enable player #5 healing text",
                        isTrueH: true,
                        r: 153,
                        g: 102,
                        b: 255,
                    },
                    tracker6 : {
                        id: "tracker6",
                        desc: "Enable enemies damage text",
                        isTrue: true,
                        descH: "Enable enemies healing text",
                        isTrueH: true,
                        r: 255,
                        g: 0,
                        b: 0,
                    },
                    missedText : {
                        id: "missedText",
                        desc: "Enable missed attack text",
                        isTrue: true,
                    }
                };
                this.fcbReadSettings();

                this.fcbMonstersHP = [];
                this.fcbMonstersMP = [];
                this.fcbMonstersDmgCounter = [];
                this.fcbPlayersHP = [];
                this.fcbPlayersMP = [];
                this.fcbPlayersDmgCounter = [];

                this.fcbBattleStartTime = null;
                this.fcbPlayerDamageByMonster = {};
                this.fcbCumulativePlayerDamage = {};
                this.fcbCurrentBattlePlayerDamage = {};
                this.fcbCumulativeTimeElapsed = 0;
                this.fcbCurrentBattleStartTime = null;
                this.fcbIsPaused = true;
                this.fcbLastCombatUpdate = null;
                this.fcbEndTime = null;

                this.fcbPlayerFloatingQueues = {};
                this.fcbEnemyFloatingQueues = {};
                this.fcbActiveFloatingTexts = new Set();

                this.fcbPlayerDPSInterval = null;
                this.fcbEnemyDPSInterval = null;

                this.fcbCachedPlayersArea = null;
                this.fcbCachedMonstersArea = null;
                this.fcbCacheInvalidationTime = 0;

                this.fcbHookWebSocket();

                this.fcbWatchPlayerDamageSplats();

                this.fcbWatchMonsterElements();

                this.fcbStartIntervals();
            }

            fcbWatchMonsterElements() {
                if (this.fcbMonsterObserver) {
                    this.fcbMonsterObserver.disconnect();
                }

                if (this.fcbMonsterWatchTimeout) {
                    clearTimeout(this.fcbMonsterWatchTimeout);
                    this.fcbMonsterWatchTimeout = null;
                }

                const checkAndWatch = () => {
                    const monstersArea = document.querySelector('[class*="monstersArea"]');
                    if (!monstersArea) {
                        this.fcbMonsterWatchTimeout = setTimeout(checkAndWatch, 1000);
                        return;
                    }

                    this.fcbMonsterObserver = new MutationObserver((mutations) => {
                        if (document.hidden) return;
                        if (!this.fcbEnemyDPSEnabled) return;

                        mutations.forEach((mutation) => {
                            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                                mutation.addedNodes.forEach(node => {
                                    if (node.nodeType === Node.ELEMENT_NODE) {
                                        if (typeof node.className === 'string' && node.className.includes('CombatUnit_combatUnit__')) {
                                            this.fcbPreCreateDPSContainer(node);
                                        }
                                        const monsters = node.querySelectorAll('[class*="CombatUnit_combatUnit__"]');
                                        monsters.forEach(monster => {
                                            this.fcbPreCreateDPSContainer(monster);
                                        });
                                    }
                                });
                            }
                        });
                    });

                    this.fcbMonsterObserver.observe(monstersArea, {
                        childList: true,
                        subtree: true
                    });
                };

                checkAndWatch();
            }

            fcbPreCreateDPSContainer(monsterElement) {
                if (!monsterElement || monsterElement.querySelector('.floating-text-dps-container')) return;

                const dpsContainer = document.createElement('div');
                dpsContainer.className = 'floating-text-dps-container';

                let totalPlayers = this.fcbCurrentPlayerCount || 1;
                if (!totalPlayers || totalPlayers < 1) {
                    const playersArea = this.fcbGetCachedPlayersArea();
                    totalPlayers = playersArea && playersArea.children[0] ? playersArea.children[0].children.length : 1;
                }

                let columnsHtml = '';
                for (let i = 0; i < totalPlayers; i++) {
                    let color = '#808080';
                    if (this.fcbSettingsMap[`tracker${i}`]) {
                        color = `rgb(${this.fcbSettingsMap[`tracker${i}`].r},${this.fcbSettingsMap[`tracker${i}`].g},${this.fcbSettingsMap[`tracker${i}`].b})`;
                    }
                    columnsHtml += `<div class="mcs-fcb-dps-column mcs-fcb-text-shadow" style="color: ${color};">0/s</div>`;
                }
                dpsContainer.innerHTML = columnsHtml;
                monsterElement.appendChild(dpsContainer);
            }

            fcbStartIntervals() {
                this.fcbStopIntervals();

                if (this.fcbPlayerDPSEnabled) {
                    VisibilityManager.register('fcb-player-dps', () => {
                        if (!this.fcbIsPaused) {
                            this.fcbUpdateAllPlayerDPS();
                        }
                    }, 2000);
                }

                if (this.fcbEnemyDPSEnabled) {
                    VisibilityManager.register('fcb-enemy-dps', () => {
                        if (!this.fcbIsPaused && this.fcbBattleStartTime) {
                            Object.keys(this.fcbPlayerDamageByMonster).forEach(monsterIndex => {
                                const monsterHP = this.fcbMonstersHP[parseInt(monsterIndex)];
                                if (monsterHP > 0) {
                                    this.fcbUpdateDPSDisplay(parseInt(monsterIndex));
                                }
                            });
                        }
                    }, 250);
                }

                VisibilityManager.register('fcb-floating-cleanup', () => {
                    this.fcbCleanupOrphanedFloatingTexts();
                }, 30000);
            }

            fcbStopIntervals() {
                VisibilityManager.clear('fcb-player-dps');

                VisibilityManager.clear('fcb-enemy-dps');

                VisibilityManager.clear('fcb-floating-cleanup');
            }

            fcbCleanup() {

                this.fcbStopIntervals();

                if (this.fcbPlayerSplatRecheckTimeout) {
                    clearTimeout(this.fcbPlayerSplatRecheckTimeout);
                    this.fcbPlayerSplatRecheckTimeout = null;
                }
                if (this.fcbMonsterWatchTimeout) {
                    clearTimeout(this.fcbMonsterWatchTimeout);
                    this.fcbMonsterWatchTimeout = null;
                }

                if (this.fcbPlayerSplatObserver) {
                    this.fcbPlayerSplatObserver.disconnect();
                    this.fcbPlayerSplatObserver = null;
                }

                if (this.fcbMonsterObserver) {
                    this.fcbMonsterObserver.disconnect();
                    this.fcbMonsterObserver = null;
                }

                this.fcbActiveFloatingTexts.forEach(div => {
                    if (div.parentNode) {
                        div.parentNode.removeChild(div);
                    }
                });
                this.fcbActiveFloatingTexts.clear();

                this.fcbPlayerFloatingQueues = {};
                this.fcbEnemyFloatingQueues = {};

                this.fcbInvalidateCache();
            }

            fcbCleanupOrphanedFloatingTexts() {
                const toRemove = [];
                this.fcbActiveFloatingTexts.forEach(div => {
                    if (!div || !div.parentNode || !document.body.contains(div)) {
                        toRemove.push(div);
                    }
                });

                toRemove.forEach(div => {
                    this.fcbActiveFloatingTexts.delete(div);
                    if (div && div.parentNode) {
                        div.parentNode.removeChild(div);
                    }
                });

                if (this.fcbActiveFloatingTexts.size > 100) {
                    console.warn('FCB: Floating text Set exceeded 100 entries, clearing old entries');
                    const arr = Array.from(this.fcbActiveFloatingTexts);
                    const toKeep = arr.slice(-50);
                    arr.slice(0, -50).forEach(div => {
                        if (div && div.parentNode) {
                            div.parentNode.removeChild(div);
                        }
                    });
                    this.fcbActiveFloatingTexts = new Set(toKeep);
                }
            }

            fcbWatchPlayerDamageSplats() {
                const self = this;

                if (this.fcbPlayerSplatObserver) {
                    this.fcbPlayerSplatObserver.disconnect();
                }

                if (this.fcbPlayerSplatRecheckTimeout) {
                    clearTimeout(this.fcbPlayerSplatRecheckTimeout);
                    this.fcbPlayerSplatRecheckTimeout = null;
                }

                const checkAndWatch = () => {
                    const playersArea = document.querySelector('[class*="playersArea"]');
                    if (!playersArea || !playersArea.children[0]) {
                        this.fcbPlayerSplatRecheckTimeout = setTimeout(checkAndWatch, 1000);
                        return;
                    }

                    const playersContainer = playersArea.children[0];

                    self.fcbPlayerSplatObserver = new MutationObserver((mutations) => {
                        if (document.hidden) return;
                        mutations.forEach((mutation) => {
                            try {
                                const nodesToProcess = [];

                                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                                    nodesToProcess.push(mutation.target);
                                }
                                else if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                                    mutation.addedNodes.forEach(addedNode => {
                                        if (addedNode.nodeType === Node.ELEMENT_NODE) {
                                            const isDamage = typeof addedNode.className === 'string' && addedNode.className.includes('CombatUnit_damage__');
                                            const isMiss = typeof addedNode.className === 'string' && addedNode.className.includes('CombatUnit_miss__');
                                            const isMana = typeof addedNode.className === 'string' && addedNode.className.includes('CombatUnit_mana__');
                                            const isHeal = typeof addedNode.className === 'string' && addedNode.className.includes('CombatUnit_heal__');

                                            if (isDamage || isMiss || isMana || isHeal) {
                                                nodesToProcess.push(addedNode);
                                            }
                                        }
                                    });
                                }

                                nodesToProcess.forEach(node => {
                                    if (!node) return;

                                const isDamage = typeof node.className === 'string' && node.className.includes('CombatUnit_damage__');
                                const isMiss = typeof node.className === 'string' && node.className.includes('CombatUnit_miss__');
                                const isMana = typeof node.className === 'string' && node.className.includes('CombatUnit_mana__');
                                const isHeal = typeof node.className === 'string' && node.className.includes('CombatUnit_heal__');

                                if (!isDamage && !isMiss && !isMana && !isHeal) return;

                                const value = node.textContent.trim();

                                if (!value) return;

                                if (node.dataset.fcbLastValue === value) return;

                                node.dataset.fcbLastValue = value;

                                let playerElement = node;
                                while (playerElement && !(typeof playerElement.className === 'string' && playerElement.className.includes('CombatUnit_combatUnit__'))) {
                                    playerElement = playerElement.parentElement;
                                }

                                if (!playerElement) return;

                                const playerIndex = Array.from(playersContainer.children).indexOf(playerElement);
                                if (playerIndex === -1) return;

                                let color, columnOffset;

                                if (isMana) {
                                    color = '#2196F3';
                                    columnOffset = -1;
                                } else if (isDamage) {
                                    color = self.fcbSettingsMap.tracker6 ?
                                        `rgb(${self.fcbSettingsMap.tracker6.r},${self.fcbSettingsMap.tracker6.g},${self.fcbSettingsMap.tracker6.b})` :
                                        '#ff0000';
                                    columnOffset = 0;
                                } else if (isMiss) {
                                    color = '#808080';
                                    columnOffset = 0;
                                } else if (isHeal) {
                                    color = '#4CAF50';
                                    columnOffset = 1;
                                }

                                self.fcbCreateFloatingTextForPlayerSplat(playerIndex, value, color, columnOffset);
                                });
                            } catch (error) {
                                console.error('FCB: Error processing player splat mutation:', error);
                            }
                        });
                    });

                    Array.from(playersContainer.children).forEach((player) => {
                        const splatsContainer = player.querySelector('[class*="CombatUnit_splatsContainer__"]');
                        if (splatsContainer) {
                            self.fcbPlayerSplatObserver.observe(splatsContainer, {
                                attributes: true,
                                attributeFilter: ['class'],
                                childList: true,
                                subtree: true
                            });
                        }
                    });

                    this.fcbPlayerSplatRecheckTimeout = setTimeout(checkAndWatch, 30000);
                };

                checkAndWatch();
            }

            fcbCreateFloatingTextForPlayerSplat(playerIndex, value, color, columnOffset) {
                if (!this.fcbEnabled) return;

                if (document.hidden) return;

                if (!this.fcbPlayerFloatingQueues[playerIndex]) {
                    this.fcbPlayerFloatingQueues[playerIndex] = {
                        '-1': { queue: [], processing: false },
                        '0': { queue: [], processing: false },
                        '1': { queue: [], processing: false }
                    };
                }

                const queueKey = columnOffset.toString();
                const queue = this.fcbPlayerFloatingQueues[playerIndex][queueKey];

                queue.queue.push({ value, color, columnOffset });

                if (queue.queue.length > 5) {
                    queue.queue.shift();
                }

                if (!queue.processing) {
                    this.fcbProcessPlayerFloatingQueue(playerIndex, columnOffset);
                }
            }

            fcbProcessPlayerFloatingQueue(playerIndex, columnOffset) {
                const queueKey = columnOffset.toString();
                const queue = this.fcbPlayerFloatingQueues[playerIndex]?.[queueKey];

                if (!queue) {
                    console.warn('FCB: Queue not found for player', playerIndex, 'column', columnOffset);
                    return;
                }

                if (queue.queue.length === 0) {
                    queue.processing = false;
                    return;
                }

                queue.processing = true;
                const item = queue.queue.shift();

                try {
                    this.fcbDisplayPlayerFloatingText(playerIndex, item.value, item.color, item.columnOffset);
                } catch (error) {
                    console.error('FCB: Error displaying player floating text:', error);
                }

                if (queue.queue.length > 0) {
                    setTimeout(() => {
                        this.fcbProcessPlayerFloatingQueue(playerIndex, columnOffset);
                    }, 500);
                } else {
                    queue.processing = false;
                }
            }

            fcbDisplayPlayerFloatingText(playerIndex, value, color, columnOffset) {
                const playerElement = this.fcbGetPlayerElement(playerIndex);
                if (!playerElement) return;

                const rect = playerElement.getBoundingClientRect();
                const centerX = rect.left + rect.width / 2;
                const columnWidth = rect.width / 3;
                const columnSpacing = 12;

                const startX = centerX + (columnOffset * (columnWidth * 0.5 + columnSpacing));

                const startY = rect.top + rect.height / 2 - 50;
                const endY = startY - 100;

                const floatingDiv = document.createElement('div');
                floatingDiv.className = 'fcb-floating-text';
                floatingDiv.style.left = `${startX}px`;
                floatingDiv.style.top = `${startY}px`;
                floatingDiv.style.color = color;

                floatingDiv.textContent = value;
                floatingDiv.dataset.columnOffset = columnOffset;
                floatingDiv.dataset.playerIndex = playerIndex;
                floatingDiv.dataset.targetY = endY;

                this.fcbActiveFloatingTexts.add(floatingDiv);
                document.body.appendChild(floatingDiv);

                this.fcbPushUpCollidingTexts(floatingDiv, endY, columnOffset, playerIndex);

                setTimeout(() => {
                    floatingDiv.style.transition = 'top 0.5s ease-out';
                    floatingDiv.style.top = `${endY}px`;
                }, 10);

                setTimeout(() => {
                    floatingDiv.style.transition = 'opacity 0.5s ease-out';
                    floatingDiv.style.opacity = '0';
                }, 1000);

                setTimeout(() => {
                    this.fcbActiveFloatingTexts.delete(floatingDiv);
                    if (floatingDiv.parentNode) {
                        floatingDiv.parentNode.removeChild(floatingDiv);
                    }
                }, 2000);
            }

            fcbPushUpCollidingTexts(newDiv, targetY, columnOffset, playerIndex) {
                const pushDistance = 30;

                const columnDivs = [];
                this.fcbActiveFloatingTexts.forEach(existingDiv => {
                    if (existingDiv === newDiv) return;
                    if (existingDiv.dataset.columnOffset !== columnOffset.toString()) return;
                    if (existingDiv.dataset.playerIndex !== playerIndex.toString()) return;

                    const existingRect = existingDiv.getBoundingClientRect();
                    columnDivs.push({
                        div: existingDiv,
                        y: existingRect.top,
                        targetY: parseFloat(existingDiv.dataset.targetY)
                    });
                });

                columnDivs.sort((a, b) => b.y - a.y);

                for (let i = 0; i < columnDivs.length; i++) {
                    const current = columnDivs[i];
                    const checkAgainstY = (i === 0) ? targetY : columnDivs[i - 1].targetY;

                    if (Math.abs(current.y - checkAgainstY) < pushDistance || current.targetY >= checkAgainstY) {
                        const newTargetY = checkAgainstY - pushDistance;
                        current.div.dataset.targetY = newTargetY;
                        current.targetY = newTargetY;

                        current.div.style.transition = 'top 0.3s ease-out';
                        current.div.style.top = `${newTargetY}px`;
                    }
                }
            }

            fcbToggleEnabled(enabled) {
                this.fcbEnabled = enabled;
                this.fcStorage.set('enabled', enabled);

                if (!enabled) {
                    document.querySelectorAll('.fcb-floating-text').forEach(el => {
                        if (el.parentNode) el.parentNode.removeChild(el);
                    });
                    this.fcbActiveFloatingTexts.clear();
                }
            }

            fcbToggleEnemyDPS(enabled) {
                this.fcbEnemyDPSEnabled = enabled;
                this.fcStorage.set('enemyd', enabled);

                this.fcbStartIntervals();

                if (!enabled) {
                    document.querySelectorAll('.floating-text-dps-container').forEach(el => {
                        if (el.parentNode) el.parentNode.removeChild(el);
                    });
                } else {
                    const monstersArea = this.fcbGetCachedMonstersArea();
                    if (monstersArea && monstersArea.children[0]) {
                        const monstersContainer = monstersArea.children[0];
                        const monsters = monstersContainer.children;
                        for (let i = 0; i < monsters.length; i++) {
                            this.fcbUpdateDPSDisplay(i);
                        }
                    }
                }
            }

            fcbTogglePlayerDPS(enabled) {
                this.fcbPlayerDPSEnabled = enabled;
                this.fcStorage.set('playerd', enabled);

                this.fcbStartIntervals();

                if (!enabled) {
                    document.querySelectorAll('.floating-text-player-dps-current').forEach(el => {
                        if (el.parentNode) el.parentNode.removeChild(el);
                    });
                    document.querySelectorAll('.floating-text-player-dps-total').forEach(el => {
                        if (el.parentNode) el.parentNode.removeChild(el);
                    });
                } else {
                    this.fcbUpdateAllPlayerDPS();
                }
            }

            fcbTogglePlayerNameRecolor(enabled) {
                this.fcbPlayerNameRecolorEnabled = enabled;
                this.fcStorage.set('playerc', enabled);

                if (!enabled) {
                    const playersArea = this.fcbGetCachedPlayersArea();
                    if (!playersArea || !playersArea.children[0]) return;

                    const playersContainer = playersArea.children[0];
                    const players = playersContainer.children;

                    for (let i = 0; i < players.length; i++) {
                        const playerElement = players[i];
                        const nameElement = playerElement.querySelector('[class^="CombatUnit_name"]');

                        if (nameElement) {
                            nameElement.style.backgroundColor = '';
                            nameElement.style.color = '';
                            nameElement.style.padding = '';
                            nameElement.style.borderRadius = '';
                        }
                    }
                } else {
                    this.fcbUpdatePlayerNameColors();
                }
            }

            fcbReadSettings() {
                const savedSettings = localStorage.getItem("mcs__global_FC_settings_map");
                if (savedSettings) {
                    const parsedSettings = JSON.parse(savedSettings);
                    for (const key in parsedSettings) {
                        if (this.fcbSettingsMap[key]) {
                            Object.assign(this.fcbSettingsMap[key], parsedSettings[key]);
                        }
                    }
                }
            }

            fcbResetDPSTracking(isNewSession = false) {
                if (isNewSession) {
                    this.fcbBattleStartTime = Date.now();
                    this.fcbCurrentBattleStartTime = Date.now();
                    this.fcbCumulativeTimeElapsed = 0;
                    this.fcbCumulativePlayerDamage = {};
                    this.fcbEndTime = null;
                } else {
                    if (this.fcbBattleStartTime && this.fcbEndTime) {
                        this.fcbCumulativeTimeElapsed += (this.fcbEndTime - this.fcbBattleStartTime) / 1000;
                    } else if (this.fcbBattleStartTime && !this.fcbEndTime) {
                        this.fcbCumulativeTimeElapsed += (Date.now() - this.fcbBattleStartTime) / 1000;
                    }
                    this.fcbBattleStartTime = Date.now();
                    this.fcbCurrentBattleStartTime = Date.now();
                    this.fcbEndTime = null;
                }

                this.fcbIsPaused = false;
                this.fcbPlayerDamageByMonster = {};
                this.fcbCurrentBattlePlayerDamage = {};
                this.fcbLastCombatUpdate = Date.now();

                this.fcbInvalidateCache();

                const monstersArea = this.fcbGetCachedMonstersArea();
                if (monstersArea && monstersArea.children[0]) {
                    const monstersContainer = monstersArea.children[0];
                    const monsters = monstersContainer.children;

                    for (let i = 0; i < monsters.length; i++) {
                        const dpsContainer = monsters[i].querySelector('.floating-text-dps-container');
                        if (dpsContainer) {
                            const totalPlayers = this.fcbCurrentPlayerCount || 1;
                            let columnsHtml = '';
                            for (let j = 0; j < totalPlayers; j++) {
                                let color = '#808080';
                                if (this.fcbSettingsMap[`tracker${j}`]) {
                                    color = `rgb(${this.fcbSettingsMap[`tracker${j}`].r},${this.fcbSettingsMap[`tracker${j}`].g},${this.fcbSettingsMap[`tracker${j}`].b})`;
                                }
                                columnsHtml += `<div class="mcs-fcb-dps-column mcs-fcb-text-shadow" style="color: ${color};">0/s</div>`;
                            }
                            dpsContainer.innerHTML = columnsHtml;
                        }
                    }
                }
            }

            fcbPauseDPSTracking() {
                if (!this.fcbIsPaused) {
                    this.fcbEndTime = Date.now();
                    this.fcbIsPaused = true;
                }

                this.fcbPlayerFloatingQueues = {};
                this.fcbEnemyFloatingQueues = {};
            }

            fcbRecordDamage(playerIndex, monsterIndex, damage) {
                if (!this.fcbPlayerDamageByMonster[monsterIndex]) {
                    this.fcbPlayerDamageByMonster[monsterIndex] = {};
                }
                if (!this.fcbPlayerDamageByMonster[monsterIndex][playerIndex]) {
                    this.fcbPlayerDamageByMonster[monsterIndex][playerIndex] = 0;
                }
                this.fcbPlayerDamageByMonster[monsterIndex][playerIndex] += damage;

                if (!this.fcbCumulativePlayerDamage[playerIndex]) {
                    this.fcbCumulativePlayerDamage[playerIndex] = 0;
                }
                this.fcbCumulativePlayerDamage[playerIndex] += damage;

                if (!this.fcbCurrentBattlePlayerDamage[playerIndex]) {
                    this.fcbCurrentBattlePlayerDamage[playerIndex] = 0;
                }
                this.fcbCurrentBattlePlayerDamage[playerIndex] += damage;

                this.fcbUpdateDPSDisplay(monsterIndex);
                this.fcbUpdatePlayerDPSDisplay(playerIndex);
            }

            fcbCalculateDPS(totalDamage) {
                if (!this.fcbBattleStartTime) return 0;
                const elapsedSeconds = (Date.now() - this.fcbBattleStartTime) / 1000;
                if (elapsedSeconds < 0.1) return 0;
                return Math.round(totalDamage / elapsedSeconds);
            }

            fcbCalculateCumulativeDPS(playerIndex) {
                const totalDamage = this.fcbCumulativePlayerDamage[playerIndex] || 0;
                let totalTime = this.fcbCumulativeTimeElapsed;

                if (this.fcbBattleStartTime) {
                    const now = this.fcbEndTime || Date.now();
                    totalTime += (now - this.fcbBattleStartTime) / 1000;
                }

                if (totalTime < 0.1) return 0;
                return Math.round(totalDamage / totalTime);
            }

            fcbCalculateCurrentBattleDPS(playerIndex) {
                const currentDamage = this.fcbCurrentBattlePlayerDamage[playerIndex] || 0;

                if (!this.fcbBattleStartTime || this.fcbIsPaused) return 0;

                const elapsedSeconds = (Date.now() - this.fcbBattleStartTime) / 1000;
                if (elapsedSeconds < 0.1) return 0;

                return Math.round(currentDamage / elapsedSeconds);
            }

            fcbFormatNumber(num) {
                return mcsFormatCurrency(num, 'compact');
            }

            fcbUpdatePlayerDPSDisplay(playerIndex) {
                const playerElement = this.fcbGetPlayerElement(playerIndex);
                if (!playerElement) return;

                let currentContainer = playerElement.querySelector('.floating-text-player-dps-current');
                let totalContainer = playerElement.querySelector('.floating-text-player-dps-total');

                if (!this.fcbPlayerDPSEnabled) {
                    if (currentContainer && currentContainer.parentNode) {
                        currentContainer.parentNode.removeChild(currentContainer);
                    }
                    if (totalContainer && totalContainer.parentNode) {
                        totalContainer.parentNode.removeChild(totalContainer);
                    }
                    return;
                }

                if (!currentContainer) {
                    currentContainer = document.createElement('div');
                    currentContainer.className = 'floating-text-player-dps-current';
                    playerElement.insertBefore(currentContainer, playerElement.firstChild);
                }

                if (!totalContainer) {
                    totalContainer = document.createElement('div');
                    totalContainer.className = 'floating-text-player-dps-total';
                    if (currentContainer.nextSibling) {
                        playerElement.insertBefore(totalContainer, currentContainer.nextSibling);
                    } else {
                        playerElement.insertBefore(totalContainer, playerElement.firstChild);
                        playerElement.insertBefore(currentContainer, totalContainer);
                    }
                }

                const currentDamage = this.fcbCurrentBattlePlayerDamage[playerIndex] || 0;
                const currentDPS = this.fcbCalculateCurrentBattleDPS(playerIndex);

                const totalDamage = this.fcbCumulativePlayerDamage[playerIndex] || 0;
                const totalDPS = this.fcbCalculateCumulativeDPS(playerIndex);

                if (this.fcbSettingsMap[`tracker${playerIndex}`]) {
                    const color = `rgb(${this.fcbSettingsMap[`tracker${playerIndex}`].r},${this.fcbSettingsMap[`tracker${playerIndex}`].g},${this.fcbSettingsMap[`tracker${playerIndex}`].b})`;
                    currentContainer.style.color = color;
                    currentContainer.classList.add('mcs-fcb-text-shadow');
                    totalContainer.style.color = color;
                    totalContainer.classList.add('mcs-fcb-text-shadow');
                }

                currentContainer.textContent = `${currentDPS} DPS ${this.fcbFormatNumber(currentDamage)} cur`;
                totalContainer.textContent = `${totalDPS} DPS ${this.fcbFormatNumber(totalDamage)} total`;
            }

            fcbUpdateAllPlayerDPS() {
                const playersArea = this.fcbGetCachedPlayersArea();
                if (!playersArea || !playersArea.children[0]) return;

                const totalPlayers = playersArea.children[0].children.length;
                for (let i = 0; i < totalPlayers; i++) {
                    this.fcbUpdatePlayerDPSDisplay(i);
                }
            }

            fcbUpdateDPSDisplay(monsterIndex) {
                const monsterElement = this.fcbGetMonsterElement(monsterIndex);
                if (!monsterElement) return;

                let dpsContainer = monsterElement.querySelector('.floating-text-dps-container');

                if (!this.fcbEnemyDPSEnabled) {
                    if (dpsContainer) {
                        dpsContainer.style.visibility = 'hidden';
                    }
                    return;
                }

                if (!dpsContainer) {
                    dpsContainer = document.createElement('div');
                    dpsContainer.className = 'floating-text-dps-container';
                    monsterElement.appendChild(dpsContainer);
                } else {
                    dpsContainer.style.visibility = 'visible';
                }

                dpsContainer.innerHTML = '';

                const playersArea = this.fcbGetCachedPlayersArea();
                const totalPlayers = playersArea && playersArea.children[0] ? playersArea.children[0].children.length : 0;

                for (let i = 0; i < totalPlayers; i++) {
                    const totalDamage = this.fcbPlayerDamageByMonster[monsterIndex]?.[i] || 0;
                    const dps = this.fcbCalculateDPS(totalDamage);

                    const column = document.createElement('div');
                    column.className = 'mcs-fcb-dps-column';

                    if (this.fcbSettingsMap[`tracker${i}`]) {
                        const color = `rgb(${this.fcbSettingsMap[`tracker${i}`].r},${this.fcbSettingsMap[`tracker${i}`].g},${this.fcbSettingsMap[`tracker${i}`].b})`;
                        column.style.color = color;
                        column.classList.add('mcs-fcb-text-shadow');
                    }

                    column.textContent = `${dps}/s`;
                    dpsContainer.appendChild(column);
                }
            }

            fcbCreateFloatingText(targetElement, text, color, isCrit, isMiss, attackerName, targetName, playerIndex = null) {
                if (!this.fcbEnabled) return;

                const monsterIndex = this.fcbGetMonsterIndexFromElement(targetElement);
                if (monsterIndex === -1) return;

                this.fcbEnqueueEnemyFloatingText(monsterIndex, playerIndex, text, color, isMiss);
            }

            fcbGetMonsterIndexFromElement(targetElement) {
                const monstersArea = this.fcbGetCachedMonstersArea();
                if (!monstersArea || !monstersArea.children[0]) return -1;

                const monstersContainer = monstersArea.children[0];
                const monsters = Array.from(monstersContainer.children);
                return monsters.indexOf(targetElement);
            }

            fcbEnqueueEnemyFloatingText(monsterIndex, playerIndex, text, color, isMiss) {
                if (document.hidden) return;

                if (!this.fcbEnemyFloatingQueues[monsterIndex]) {
                    this.fcbEnemyFloatingQueues[monsterIndex] = {};
                }

                if (!this.fcbEnemyFloatingQueues[monsterIndex][playerIndex]) {
                    this.fcbEnemyFloatingQueues[monsterIndex][playerIndex] = {
                        queue: [],
                        processing: false
                    };
                }

                const queue = this.fcbEnemyFloatingQueues[monsterIndex][playerIndex];

                queue.queue.push({ text, color, isMiss });

                if (queue.queue.length > 5) {
                    queue.queue.shift();
                }

                if (!queue.processing) {
                    this.fcbProcessEnemyFloatingQueue(monsterIndex, playerIndex);
                }
            }

            fcbProcessEnemyFloatingQueue(monsterIndex, playerIndex) {
                const queue = this.fcbEnemyFloatingQueues[monsterIndex]?.[playerIndex];
                if (!queue) return;

                if (queue.queue.length === 0) {
                    queue.processing = false;
                    return;
                }

                queue.processing = true;
                const item = queue.queue.shift();

                try {
                    this.fcbDisplayEnemyFloatingText(monsterIndex, playerIndex, item.text, item.color, item.isMiss);
                } catch (error) {
                    console.error('FCB: Error displaying enemy floating text:', error);
                }

                if (queue.queue.length > 0) {
                    setTimeout(() => {
                        this.fcbProcessEnemyFloatingQueue(monsterIndex, playerIndex);
                    }, 500);
                } else {
                    queue.processing = false;
                }
            }

            fcbDisplayEnemyFloatingText(monsterIndex, playerIndex, text, color, isMiss) {
                const targetElement = this.fcbGetMonsterElement(monsterIndex);
                if (!targetElement) return;

                const rect = targetElement.getBoundingClientRect();
                const startY = rect.top + rect.height / 2 - 50;
                const endY = startY - 100;

                const playersArea = this.fcbGetCachedPlayersArea();
                const totalPlayers = playersArea && playersArea.children[0] ? playersArea.children[0].children.length : 1;

                const monsterLeft = rect.left;
                const monsterWidth = rect.width;
                const columnWidth = monsterWidth / totalPlayers;
                const columnCenterX = monsterLeft + (playerIndex * columnWidth) + (columnWidth / 2);

                const startX = columnCenterX;

                const floatingDiv = document.createElement('div');
                floatingDiv.className = 'fcb-floating-text';
                floatingDiv.style.left = `${startX}px`;
                floatingDiv.style.top = `${startY}px`;
                floatingDiv.style.color = color;

                let combatText = '';
                if (isMiss) {
                    combatText = '0';
                } else {
                    combatText = text;
                }

                floatingDiv.textContent = combatText;
                floatingDiv.dataset.monsterIndex = monsterIndex;
                floatingDiv.dataset.playerIndex = playerIndex;
                floatingDiv.dataset.targetY = endY;

                this.fcbActiveFloatingTexts.add(floatingDiv);
                document.body.appendChild(floatingDiv);

                this.fcbPushUpCollidingEnemyTexts(floatingDiv, endY, monsterIndex, playerIndex);

                setTimeout(() => {
                    floatingDiv.style.transition = 'top 0.5s ease-out';
                    floatingDiv.style.top = `${endY}px`;
                }, 10);

                setTimeout(() => {
                    floatingDiv.style.transition = 'opacity 0.5s ease-out';
                    floatingDiv.style.opacity = '0';
                }, 1000);

                setTimeout(() => {
                    this.fcbActiveFloatingTexts.delete(floatingDiv);
                    if (floatingDiv.parentNode) {
                        floatingDiv.parentNode.removeChild(floatingDiv);
                    }
                }, 2000);
            }

            fcbPushUpCollidingEnemyTexts(newDiv, targetY, monsterIndex, playerIndex) {
                const pushDistance = 30;

                const columnDivs = [];
                this.fcbActiveFloatingTexts.forEach(existingDiv => {
                    if (existingDiv === newDiv) return;
                    if (existingDiv.dataset.monsterIndex !== monsterIndex.toString()) return;
                    if (existingDiv.dataset.playerIndex !== playerIndex.toString()) return;

                    const existingRect = existingDiv.getBoundingClientRect();
                    columnDivs.push({
                        div: existingDiv,
                        y: existingRect.top,
                        targetY: parseFloat(existingDiv.dataset.targetY)
                    });
                });

                columnDivs.sort((a, b) => b.y - a.y);

                for (let i = 0; i < columnDivs.length; i++) {
                    const current = columnDivs[i];
                    const checkAgainstY = (i === 0) ? targetY : columnDivs[i - 1].targetY;

                    if (Math.abs(current.y - checkAgainstY) < pushDistance || current.targetY >= checkAgainstY) {
                        const newTargetY = checkAgainstY - pushDistance;
                        current.div.dataset.targetY = newTargetY;
                        current.targetY = newTargetY;

                        current.div.style.transition = 'top 0.3s ease-out';
                        current.div.style.top = `${newTargetY}px`;
                    }
                }
            }

            fcbGetCachedPlayersArea() {
                const now = Date.now();
                if (!this.fcbCachedPlayersArea || now - this.fcbCacheInvalidationTime > 5000) {
                    this.fcbCachedPlayersArea = document.querySelector('[class*="playersArea"]');
                    this.fcbCachedMonstersArea = document.querySelector('[class*="monstersArea"]');
                    this.fcbCacheInvalidationTime = now;
                }
                return this.fcbCachedPlayersArea;
            }

            fcbGetCachedMonstersArea() {
                this.fcbGetCachedPlayersArea();
                return this.fcbCachedMonstersArea;
            }

            fcbInvalidateCache() {
                this.fcbCachedPlayersArea = null;
                this.fcbCachedMonstersArea = null;
                this.fcbCacheInvalidationTime = 0;
            }

            fcbGetPlayerElement(playerIndex) {
                const playersArea = this.fcbGetCachedPlayersArea();
                if (!playersArea || !playersArea.children[0]) {
                    return null;
                }

                const playersContainer = playersArea.children[0];
                const players = playersContainer.children;
                return players[playerIndex] || null;
            }

            fcbGetMonsterElement(monsterIndex) {
                const monstersArea = this.fcbGetCachedMonstersArea();
                if (!monstersArea || !monstersArea.children[0]) {
                    return null;
                }

                const monstersContainer = monstersArea.children[0];
                const monsters = monstersContainer.children;
                return monsters[monsterIndex] || null;
            }

            fcbGetPlayerName(playerElement) {
                if (!playerElement) return 'Player';
                const nameElement = playerElement.querySelector('[class*="name"]');
                return nameElement ? nameElement.textContent.trim() : 'Player';
            }

            fcbGetMonsterName(monsterElement) {
                if (!monsterElement) return 'Monster';
                const nameElement = monsterElement.querySelector('[class*="name"]');
                return nameElement ? nameElement.textContent.trim() : 'Monster';
            }

            fcbUpdatePlayerNameColors() {
                const playersArea = this.fcbGetCachedPlayersArea();
                if (!playersArea || !playersArea.children[0]) return;

                const playersContainer = playersArea.children[0];
                const players = playersContainer.children;

                for (let i = 0; i < players.length; i++) {
                    const playerElement = players[i];
                    const nameElement = playerElement.querySelector('[class^="CombatUnit_name"]');

                    if (nameElement && this.fcbSettingsMap[`tracker${i}`]) {
                        if (this.fcbPlayerNameRecolorEnabled) {
                            const color = `rgb(${this.fcbSettingsMap[`tracker${i}`].r},${this.fcbSettingsMap[`tracker${i}`].g},${this.fcbSettingsMap[`tracker${i}`].b})`;
                            nameElement.style.backgroundColor = color;
                            nameElement.style.color = '#000000';
                            nameElement.style.padding = '2px 6px';
                            nameElement.style.borderRadius = '3px';
                        } else {
                            nameElement.style.backgroundColor = '';
                            nameElement.style.color = '';
                            nameElement.style.padding = '';
                            nameElement.style.borderRadius = '';
                        }
                    }
                }
            }

            fcbCreateFloatingCombatText(fromIndex, toIndex, hpDiff, reversed = false) {
                if (!reversed && hpDiff > 0) {
                    this.fcbRecordDamage(fromIndex, toIndex, hpDiff);
                }

                if (!this.fcbEnabled) return;

                if (reversed) {
                    return;
                }

                const attackerElement = this.fcbGetPlayerElement(fromIndex);
                const targetElement = this.fcbGetMonsterElement(toIndex);
                const attackerName = this.fcbGetPlayerName(attackerElement);
                const targetName = this.fcbGetMonsterName(targetElement);
                const settingId = `tracker${fromIndex}`;

                let text, color, isCrit = false, isMiss = false;

                if (hpDiff === 0) {
                    text = '';
                    color = '#808080';
                    isMiss = true;
                    if (!this.fcbSettingsMap.missedText?.isTrue) {
                        return;
                    }
                } else if (hpDiff > 0) {
                    text = hpDiff.toString();
                    if (!this.fcbSettingsMap[settingId]?.isTrue) {
                        return;
                    }
                    color = `rgb(${this.fcbSettingsMap[settingId].r},${this.fcbSettingsMap[settingId].g},${this.fcbSettingsMap[settingId].b})`;
                } else {
                    text = '+' + Math.abs(hpDiff);
                    if (!this.fcbSettingsMap[settingId]?.isTrueH) {
                        return;
                    }
                    color = '#4CAF50';
                }

                if (hpDiff > 0 && Math.random() < 0.2) {
                    isCrit = true;
                }

                const playersArea = this.fcbGetCachedPlayersArea();
                const totalPlayers = playersArea && playersArea.children[0] ? playersArea.children[0].children.length : 1;

                this.fcbCreateFloatingText(targetElement, text, color, isCrit, isMiss, attackerName, targetName, fromIndex, totalPlayers, true);
            }

            fcbHandleMessage(message) {
                let obj = JSON.parse(message);
                if (obj && obj.type === "new_battle") {
                    let isNewSession = false;
                    if (this.fcbLastCombatUpdate) {
                        const timeSinceLastUpdate = (Date.now() - this.fcbLastCombatUpdate) / 1000;
                        if (timeSinceLastUpdate > 5) {
                            isNewSession = true;
                        }
                    } else {
                        isNewSession = true;
                    }

                    this.fcbMonstersHP = obj.monsters.map((monster) => monster.currentHitpoints);
                    this.fcbMonstersMP = obj.monsters.map((monster) => monster.currentManapoints);
                    this.fcbMonstersDmgCounter = obj.monsters.map((monster) => monster.damageSplatCounter);
                    this.fcbPlayersHP = obj.players.map((player) => player.currentHitpoints);
                    this.fcbPlayersMP = obj.players.map((player) => player.currentManapoints);
                    this.fcbPlayersDmgCounter = obj.players.map((player) => player.damageSplatCounter);

                    this.fcbCurrentPlayerCount = obj.players.length;

                    this.fcbResetDPSTracking(isNewSession);

                    setTimeout(() => {
                        this.fcbUpdatePlayerNameColors();
                        const playersArea = this.fcbGetCachedPlayersArea();
                        if (playersArea && playersArea.children[0]) {
                            const totalPlayers = playersArea.children[0].children.length;
                            for (let i = 0; i < totalPlayers; i++) {
                                this.fcbUpdatePlayerDPSDisplay(i);
                            }
                        }
                        if (this.fcbEnemyDPSEnabled) {
                            const monstersArea = this.fcbGetCachedMonstersArea();
                            if (monstersArea && monstersArea.children[0]) {
                                const monstersContainer = monstersArea.children[0];
                                for (let i = 0; i < monstersContainer.children.length; i++) {
                                    this.fcbUpdateDPSDisplay(i);
                                }
                            }
                        }
                    }, 100);
                } else if (obj && obj.type === "battle_updated" && this.fcbMonstersHP.length) {
                    this.fcbLastCombatUpdate = Date.now();
                    this.fcbEndTime = Date.now();

                    const mMap = obj.mMap;
                    const pMap = obj.pMap;
                    const monsterIndices = Object.keys(obj.mMap);
                    const playerIndices = Object.keys(obj.pMap);

                    let castMonster = -1;
                    monsterIndices.forEach((monsterIndex) => {
                        if(mMap[monsterIndex].cMP < this.fcbMonstersMP[monsterIndex]){castMonster = monsterIndex;}
                        this.fcbMonstersMP[monsterIndex] = mMap[monsterIndex].cMP;
                    });
                    let castPlayer = -1;
                    playerIndices.forEach((userIndex) => {
                        if(pMap[userIndex].cMP < this.fcbPlayersMP[userIndex]){castPlayer = userIndex;}
                        this.fcbPlayersMP[userIndex] = pMap[userIndex].cMP;
                    });

                    let hurtMonster = false;
                    let hurtPlayer = false;
                    let monsterLifeSteal = {from:null, to:null, hpDiff:null};
                    let playerLifeSteal = {from:null, to:null, hpDiff:null};

                    this.fcbMonstersHP.forEach((mHP, mIndex) => {
                        const monster = mMap[mIndex];
                        if (monster) {
                            const hpDiff = mHP - monster.cHP;
                            if (hpDiff > 0) {hurtMonster = true;}
                            let dmgSplat = false;
                            if (this.fcbMonstersDmgCounter[mIndex] < monster.dmgCounter) {dmgSplat = true;}
                            this.fcbMonstersHP[mIndex] = monster.cHP;
                            this.fcbMonstersDmgCounter[mIndex] = monster.dmgCounter;
                            if (dmgSplat && hpDiff >= 0 && playerIndices.length > 0) {
                                if (playerIndices.length > 1) {
                                    playerIndices.forEach((userIndex) => {
                                        if(userIndex === castPlayer) {
                                            this.fcbCreateFloatingCombatText(parseInt(userIndex), parseInt(mIndex), hpDiff);
                                        }
                                    });
                                } else {
                                    this.fcbCreateFloatingCombatText(parseInt(playerIndices[0]), parseInt(mIndex), hpDiff);
                                }
                            }
                            if (hpDiff < 0 ) {
                                if (castMonster > -1){
                                    this.fcbCreateFloatingCombatText(parseInt(mIndex), parseInt(castMonster), hpDiff, true);
                                }else{
                                    monsterLifeSteal.from=parseInt(mIndex);
                                    monsterLifeSteal.to=parseInt(mIndex);
                                    monsterLifeSteal.hpDiff=hpDiff;
                                }
                            }
                        }
                    });

                    this.fcbPlayersHP.forEach((pHP, pIndex) => {
                        const player = pMap[pIndex];
                        if (player) {
                            const hpDiff = pHP - player.cHP;
                            if (hpDiff > 0) {hurtPlayer = true;}
                            let dmgSplat = false;
                            if (this.fcbPlayersDmgCounter[pIndex] < player.dmgCounter) {dmgSplat = true;}
                            this.fcbPlayersHP[pIndex] = player.cHP;
                            this.fcbPlayersDmgCounter[pIndex] = player.dmgCounter;
                            if (dmgSplat && hpDiff >= 0 && monsterIndices.length > 0) {
                                if (monsterIndices.length > 1) {
                                    monsterIndices.forEach((monsterIndex) => {
                                        if(monsterIndex === castMonster) {
                                            this.fcbCreateFloatingCombatText(parseInt(pIndex), parseInt(monsterIndex), hpDiff, true);
                                        }
                                    });
                                } else {
                                    this.fcbCreateFloatingCombatText(parseInt(pIndex), parseInt(monsterIndices[0]), hpDiff, true);
                                }
                            }
                            if (hpDiff < 0 ) {
                                if (castPlayer > -1){
                                    this.fcbCreateFloatingCombatText(parseInt(castPlayer), parseInt(pIndex), hpDiff);
                                }else{
                                    playerLifeSteal.from=parseInt(pIndex);
                                    playerLifeSteal.to=parseInt(pIndex);
                                    playerLifeSteal.hpDiff=hpDiff;
                                }
                            }
                        }
                    });

                    if (hurtMonster && playerLifeSteal.from !== null) {
                        this.fcbCreateFloatingCombatText(playerLifeSteal.from, playerLifeSteal.to, playerLifeSteal.hpDiff);
                    }
                    if (hurtPlayer && monsterLifeSteal.from !== null) {
                        this.fcbCreateFloatingCombatText(monsterLifeSteal.from, monsterLifeSteal.to, monsterLifeSteal.hpDiff, true);
                    }

                    const allMonstersDead = this.fcbMonstersHP.every(hp => hp <= 0);
                    if (allMonstersDead) {
                        this.fcbPauseDPSTracking();
                    }
                }
                return message;
            }

            fcbHookWebSocket() {
                if (this.fcbWebSocketHooked) return;
                this.fcbWebSocketHooked = true;

                const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
                const oriGet = dataProperty.get;
                const self = this;

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

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

                    return self.fcbHandleMessage(message);
                };

                Object.defineProperty(MessageEvent.prototype, "data", dataProperty);
            }

// FCB end

// MAna start

                get maStorage() {
                    if (!this._maStorage) {
                        this._maStorage = createModuleStorage('MA');
                    }
                    return this._maStorage;
                }

                loadAbilityDetailMap() {
                    return InitClientDataCache.getAbilityDetailMap();
                }

                createMAnaPane() {
                    if (document.getElementById('mana-pane')) return;

                    const pane = document.createElement('div');
                    pane.id = 'mana-pane';
                    registerPanel('mana-pane');

                    const savedSize = this.maStorage.get('size');
                    let width = 600;
                    let height = 550;
                    if (savedSize) {
                        try {
                            const size = typeof savedSize === 'string' ? JSON.parse(savedSize) : savedSize;
                            width = size.width || 600;
                            height = size.height || 550;
                        } catch (e) {
                            console.error('[MAna] Error restoring size:', e);
                        }
                    }

                    pane.className = 'mcs-pane mcs-ma-pane';
                    pane.style.width = width + 'px';
                    pane.style.height = height + 'px';

                    pane.dataset.savedHeight = height;

                    const header = document.createElement('div');
                    header.className = 'mcs-pane-header';

                    const titleSection = document.createElement('div');
                    titleSection.className = 'mcs-ma-title-section';

                    const title = document.createElement('span');
                    title.className = 'mcs-pane-title';
                    title.textContent = 'MAna';

                    const timeDisplay = document.createElement('div');
                    timeDisplay.id = 'mana-time-display';
                    timeDisplay.className = 'mcs-ma-time-display';
                    timeDisplay.textContent = '00:00:00';

                    const manaDisplay = document.createElement('div');
                    manaDisplay.id = 'mana-header-display';
                    manaDisplay.className = 'mcs-ma-mana-display';
                    manaDisplay.textContent = '0/0';

                    titleSection.appendChild(title);
                    titleSection.appendChild(timeDisplay);
                    titleSection.appendChild(manaDisplay);

                    const buttonSection = document.createElement('div');
                    buttonSection.className = 'mcs-button-section';

                    const resetBtn = document.createElement('button');
                    resetBtn.textContent = '↻';
                    resetBtn.title = 'Reset tracking';
                    resetBtn.className = 'mcs-btn';
                    resetBtn.onclick = () => this.resetMAnaTracking();

                    const minimizeBtn = document.createElement('button');
                    minimizeBtn.id = 'mana-minimize-btn';
                    minimizeBtn.textContent = '−';
                    minimizeBtn.className = 'mcs-btn';

                    buttonSection.appendChild(resetBtn);
                    buttonSection.appendChild(minimizeBtn);
                    header.appendChild(titleSection);
                    header.appendChild(buttonSection);

                    const content = document.createElement('div');
                    content.id = 'mana-content';
                    content.className = 'mcs-ma-content';

        content.innerHTML = `
            <div class="mcs-ma-waiting">
                <div class="mcs-ma-waiting-icon">⏳</div>
                <div>Waiting for new fight to begin</div>
                <div class="mcs-ma-waiting-sub">MAna will begin tracking mana usage shortly</div>
            </div>
                    `;

                    pane.appendChild(header);
                    pane.appendChild(content);
                    document.body.appendChild(pane);

                    let dragStartX, dragStartY, initialLeft, initialTop;

                    const onDragMove = (e) => {
                        const dx = e.clientX - dragStartX;
                        const dy = e.clientY - dragStartY;

                        let newLeft = initialLeft + dx;
                        let newTop = initialTop + dy;

                        const paneRect = pane.getBoundingClientRect();
                        const headerHeight = header.getBoundingClientRect().height;

                        const minLeft = -paneRect.width + 100;
                        const maxLeft = window.innerWidth - 100;
                        const minTop = 0;
                        const maxTop = window.innerHeight - headerHeight;

                        newLeft = Math.max(minLeft, Math.min(maxLeft, newLeft));
                        newTop = Math.max(minTop, Math.min(maxTop, newTop));

                        pane.style.left = newLeft + 'px';
                        pane.style.top = newTop + 'px';
                    };

                    const onDragUp = () => {
                        document.removeEventListener('mousemove', onDragMove);
                        document.removeEventListener('mouseup', onDragUp);
                        header.style.cursor = 'move';
                        const rect = pane.getBoundingClientRect();
                        this.maStorage.set('position', { top: rect.top, left: rect.left });
                    };

                    header.addEventListener('mousedown', (e) => {
                        if (e.target.closest('button')) return;
                        dragStartX = e.clientX;
                        dragStartY = e.clientY;
                        const rect = pane.getBoundingClientRect();
                        initialLeft = rect.left;
                        initialTop = rect.top;
                        header.style.cursor = 'grabbing';
                        pane.style.left = initialLeft + 'px';
                        pane.style.right = 'auto';
                        this._maDragMove = onDragMove;
                        this._maDragUp = onDragUp;
                        document.addEventListener('mousemove', onDragMove);
                        document.addEventListener('mouseup', onDragUp);
                    });

                    minimizeBtn.addEventListener('click', () => {
                        const isMinimized = content.style.display === 'none';
                        if (isMinimized) {
                            content.style.display = 'block';
                            minimizeBtn.textContent = '−';
                            header.style.borderRadius = '6px 6px 0 0';
                            const savedHeight = pane.dataset.savedHeight || height;
                            pane.style.height = savedHeight + 'px';
                            pane.style.minHeight = '300px';
                            pane.style.resize = 'both';
                            this.maStorage.set('minimized', false);
                        } else {
                            const currentRect = pane.getBoundingClientRect();
                            pane.dataset.savedHeight = currentRect.height;

                            content.style.display = 'none';
                            minimizeBtn.textContent = '+';
                            header.style.borderRadius = '6px';

                            const headerHeight = header.getBoundingClientRect().height;
                            pane.style.height = headerHeight + 'px';
                            pane.style.minHeight = '0';
                            pane.style.resize = 'none';
                            this.maStorage.set('minimized', true);
                        }
                    });

                    const savedPosition = this.maStorage.get('position');
                    if (savedPosition) {
                        try {
                            const position = typeof savedPosition === 'string' ? JSON.parse(savedPosition) : savedPosition;
                            pane.style.top = position.top + 'px';
                            if (position.left !== undefined) {
                                pane.style.left = position.left + 'px';
                                pane.style.right = 'auto';
                            } else if (position.right !== undefined) {
                                pane.style.right = position.right + 'px';
                            }
                        } catch (e) {
                            console.error('[MAna] Error restoring position:', e);
                        }
                    }

                    const savedMinimized = this.maStorage.get('minimized') === true || this.maStorage.get('minimized') === 'true';
                    if (savedMinimized) {
                        content.style.display = 'none';
                        minimizeBtn.textContent = '+';
                        header.style.borderRadius = '6px';
                        const headerHeight = header.getBoundingClientRect().height;
                        pane.style.height = headerHeight + 'px';
                        pane.style.minHeight = '0';
                        pane.style.resize = 'none';
                    }

                    this._maResizeObserver = new ResizeObserver(() => {
                        const rect = pane.getBoundingClientRect();
                        const isMinimized = content.style.display === 'none';

                        if (!isMinimized) {
                            pane.dataset.savedHeight = rect.height;
                        }

                        this.maStorage.set('size', {
                            width: rect.width,
                            height: isMinimized ? pane.dataset.savedHeight : rect.height
                        });
                    });
                    this._maResizeObserver.observe(pane);

                    this.manaTracking = {
                        players: {},
                        startTime: null,
                        lastUpdateTime: null,
                        totalDuration: 0,
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                        savedTabHiddenMs: window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0
                    };

                    const self = this;

                    const handleWebSocketMessage = PerformanceMonitor.wrap('MAna', (event) => {
                        if (window.MCS_MODULES_DISABLED) return;

                        const data = event.detail;
                        const messageType = data?.type;

                        if (!messageType ||
                            (messageType !== 'battle_updated' &&
                             messageType !== 'new_battle' &&
                             messageType !== 'battle_consumable_ability_updated')) {
                            return;
                        }

                        if (messageType === 'battle_updated') {
                            self.handleMAnaBattleUpdate(data);
                            return;
                        }

                        if (messageType === 'new_battle') {
                            self.initializeMAnaTracking(data.players);
                            return;
                        }

                        if (messageType === 'battle_consumable_ability_updated') {
                            if (data.ability) {
                                const abilityHrid = data.ability.abilityHrid || data.ability;
                                const abilityDetailMap = self.loadAbilityDetailMap();
                                const abilityDetail = abilityDetailMap[abilityHrid];

                                if (abilityDetail && abilityDetail.manaCost) {
                                    const mainPlayerName = CharacterStorageUtils.getPlayerKey();
                                    const playerData = Object.values(self.manaTracking.players || {}).find(p => p.name === mainPlayerName);

                                    if (playerData) {
                                        if (!playerData.knownAbilityCosts) {
                                            playerData.knownAbilityCosts = {};
                                        }
                                        playerData.knownAbilityCosts[abilityHrid] = abilityDetail.manaCost;

                                        if (!playerData.equippedAbilities) {
                                            playerData.equippedAbilities = {};
                                        }

                                        const abilityName = abilityHrid.split('/').pop().replace(/_/g, ' ');

                                        if (!playerData.equippedAbilities[abilityHrid]) {
                                            playerData.equippedAbilities[abilityHrid] = {
                                                name: abilityName,
                                                manaCost: abilityDetail.manaCost,
                                                casts: 1,
                                                totalMana: abilityDetail.manaCost
                                            };
                                        } else {
                                            playerData.equippedAbilities[abilityHrid].casts++;
                                            playerData.equippedAbilities[abilityHrid].totalMana += abilityDetail.manaCost;
                                        }

                                        self.updateMAnaContent();
                                    }
                                }
                            }
                        }
                    });

                    window.addEventListener('EquipSpyWebSocketMessage', handleWebSocketMessage);

                    if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.lastBattleData) {
                        const battleData = window.lootDropsTrackerInstance.lastBattleData;
                        if (battleData.players) {
                            self.initializeMAnaTracking(battleData.players);
                        }
                    }
                }

                initializeMAnaTracking(players) {
                    const currentTime = Date.now();

                    if (this.manaTracking.startTime) {
                        this.manaTracking.totalDuration = mcsGetElapsedSeconds(
                            this.manaTracking.startTime,
                            this.manaTracking.lastUpdateTime,
                            this.manaTracking.savedPausedMs,
                            this.manaTracking.totalDuration,
                            true,
                            this.manaTracking.savedTabHiddenMs
                        );
                    }
                    this.manaTracking.savedPausedMs = window.MCS_TOTAL_PAUSED_MS ?? 0;
                    this.manaTracking.savedTabHiddenMs = window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0;

                    if (!this.manaTracking.players) {
                        this.manaTracking.players = {};
                    }

                    players.forEach((player, index) => {
                        if (!this.manaTracking.players[index]) {
                            this.manaTracking.players[index] = {
                                name: player.name,
                                abilities: {},
                                specificAbilities: {},
                                equippedAbilities: {},
                                knownAbilityCosts: {},
                                lastMP: null,
                                lastAbilityHrid: null,
                                lastIsAutoAttack: false,
                                lastInt: null,
                                seenInts: new Set(),
                                totalManaGained: 0,
                                manaGainsBySize: {},
                                manaChanges: {},
                                fullManaCount: 0,
                                maxMP: player.mMP ?? 0,
                                abilityQueue: [],
                                derivedCurrentMP: player.cMP ?? 0,
                                derivedMaxMP: player.mMP ?? 0,
                                actualCurrentMP: player.cMP ?? 0,
                                actualMaxMP: player.mMP ?? 0
                            };
                        } else {
                            if (this.manaTracking.players[index].lastMP === undefined) {
                                this.manaTracking.players[index].lastMP = null;
                            }
                            if (this.manaTracking.players[index].totalManaGained === undefined) {
                                this.manaTracking.players[index].totalManaGained = 0;
                            }
                            if (!this.manaTracking.players[index].manaGainsBySize) {
                                this.manaTracking.players[index].manaGainsBySize = {};
                            }
                            if (this.manaTracking.players[index].fullManaCount === undefined) {
                                this.manaTracking.players[index].fullManaCount = 0;
                            }
                            if (!this.manaTracking.players[index].manaChanges) {
                                this.manaTracking.players[index].manaChanges = {};
                            }
                            this.manaTracking.players[index].maxMP = (player.mMP ?? this.manaTracking.players[index].maxMP) ?? 0;
                            if (this.manaTracking.players[index].derivedCurrentMP === undefined) {
                                this.manaTracking.players[index].derivedCurrentMP = player.cMP ?? 0;
                            }
                            if (this.manaTracking.players[index].derivedMaxMP === undefined) {
                                this.manaTracking.players[index].derivedMaxMP = player.mMP ?? 0;
                            }
                            if (player.cMP !== undefined && player.cMP !== null) {
                                this.manaTracking.players[index].actualCurrentMP = player.cMP;
                            }
                            if (player.mMP !== undefined && player.mMP !== null && player.mMP > 0) {
                                this.manaTracking.players[index].actualMaxMP = player.mMP;
                            }
                            if (!this.manaTracking.players[index].abilityQueue) {
                                this.manaTracking.players[index].abilityQueue = [];
                            }
                            if (!this.manaTracking.players[index].specificAbilities) {
                                this.manaTracking.players[index].specificAbilities = {};
                            }
                            if (!this.manaTracking.players[index].knownAbilityCosts) {
                                this.manaTracking.players[index].knownAbilityCosts = {};
                            }
                            if (this.manaTracking.players[index].lastInt === undefined) {
                                this.manaTracking.players[index].lastInt = null;
                            }
                            if (!this.manaTracking.players[index].seenInts) {
                                this.manaTracking.players[index].seenInts = new Set();
                            }
                            if (!this.manaTracking.players[index].equippedAbilities) {
                                this.manaTracking.players[index].equippedAbilities = {};
                            }
                        }
                    });

                    this.manaTracking.startTime = currentTime;
                    this.manaTracking.lastUpdateTime = currentTime;
                    this.updateMAnaContent();
                }

                handleMAnaBattleUpdate(data) {
                    if (!this.manaTracking || !this.manaTracking.players) return;

                    const pMap = data.pMap;
                    if (!pMap) return;

                    const currentTime = Date.now();

                    Object.keys(pMap).forEach(pIndex => {
                        const player = pMap[pIndex];
                        if (!player || !this.manaTracking.players[pIndex]) return;

                        const playerTracking = this.manaTracking.players[pIndex];
                        const currentInt = player.int;
                        const currentMP = player.cMP ?? 0;
                        const lastMP = playerTracking.lastMP;

                        const isNewEntity = currentInt !== undefined && currentInt !== null &&
                                          currentInt !== playerTracking.lastInt;

                        playerTracking.actualCurrentMP = currentMP;
                        playerTracking.actualMaxMP = (player.mMP ?? playerTracking.actualMaxMP) ?? 0;

                        const currentAbilityHrid = player.abilityHrid;
                        const currentIsAutoAttack = player.isAutoAtk;

                        if (!playerTracking.abilityQueue) {
                            playerTracking.abilityQueue = [];
                        }

                        const lastInQueue = playerTracking.abilityQueue[playerTracking.abilityQueue.length - 1];

                        const shouldQueue = (() => {
                            if (!currentAbilityHrid) {
                                return false;
                            }

                            if (isNewEntity) {
                                return false;
                            }

                            if (!lastInQueue || lastInQueue.hrid !== currentAbilityHrid) {
                                return true;
                            }

                            if (lastInQueue && lastInQueue.hrid === currentAbilityHrid) {
                                if (lastInQueue.isAutoAttack !== currentIsAutoAttack && !currentIsAutoAttack) {
                                    return true;
                                }
                            }

                            return false;
                        })();

                        if (shouldQueue) {
                            playerTracking.abilityQueue.push({
                                hrid: currentAbilityHrid,
                                isAutoAttack: currentIsAutoAttack,
                                int: currentInt,
                                timestamp: currentTime
                            });
                            if (playerTracking.abilityQueue.length > 10) {
                                playerTracking.abilityQueue.shift();
                            }
                        }

                        if (lastMP === null) {
                            playerTracking.lastMP = currentMP;
                            playerTracking.derivedCurrentMP = currentMP;
                            playerTracking.derivedMaxMP = player.mMP ?? 0;
                            return;
                        }

                        if (currentMP !== lastMP) {
                            const manaChange = currentMP - lastMP;
                            const changeKey = `Mana change (${manaChange > 0 ? '+' : ''}${manaChange})`;

                            if (!playerTracking.manaChanges[changeKey]) {
                                playerTracking.manaChanges[changeKey] = {
                                    amount: manaChange,
                                    count: 0
                                };
                            }
                            playerTracking.manaChanges[changeKey].count += 1;

                            playerTracking.derivedCurrentMP += manaChange;
                            playerTracking.derivedCurrentMP = Math.max(0, Math.min(playerTracking.derivedMaxMP, playerTracking.derivedCurrentMP));
                        }

                        if (lastMP > currentMP) {
                            let remainingManaCost = lastMP - currentMP;

                            const manaUseKey = `Mana use (${remainingManaCost})`;
                            if (!playerTracking.abilities[manaUseKey]) {
                                playerTracking.abilities[manaUseKey] = {
                                    name: manaUseKey,
                                    manaCost: remainingManaCost,
                                    casts: 0,
                                    totalMana: 0
                                };
                            }
                            const abilityData = playerTracking.abilities[manaUseKey];
                            abilityData.casts += 1;
                            abilityData.totalMana += remainingManaCost;
                            abilityData.manaCost = remainingManaCost;

                            if (playerTracking.abilityQueue.length > 0) {
                                if (playerTracking.abilityQueue.length === 1) {
                                    const ability = playerTracking.abilityQueue.shift();

                                    if (ability.hrid) {
                                        const abilityHrid = ability.hrid;
                                        const abilityName = abilityHrid.split('/').pop().replace(/_/g, ' ');

                                        playerTracking.knownAbilityCosts[abilityHrid] = remainingManaCost;

                                        if (!playerTracking.specificAbilities[abilityHrid]) {
                                            playerTracking.specificAbilities[abilityHrid] = {
                                                name: abilityName,
                                                manaCost: remainingManaCost,
                                                casts: 0,
                                                totalMana: 0
                                            };
                                        }

                                        const specificAbilityData = playerTracking.specificAbilities[abilityHrid];
                                        specificAbilityData.casts++;
                                        specificAbilityData.totalMana += remainingManaCost;
                                        specificAbilityData.manaCost = remainingManaCost;

                                    }
                                } else {
                                    let attributedMana = 0;
                                    const abilitiesToProcess = [...playerTracking.abilityQueue];
                                    playerTracking.abilityQueue = [];

                                    for (const ability of abilitiesToProcess) {
                                        if (ability.hrid) {
                                            const abilityHrid = ability.hrid;
                                            const abilityName = abilityHrid.split('/').pop().replace(/_/g, ' ');

                                            let manaCost = playerTracking.knownAbilityCosts[abilityHrid] ||
                                                          (remainingManaCost - attributedMana) / (abilitiesToProcess.length - abilitiesToProcess.indexOf(ability));

                                            if (!playerTracking.specificAbilities[abilityHrid]) {
                                                playerTracking.specificAbilities[abilityHrid] = {
                                                    name: abilityName,
                                                    manaCost: manaCost,
                                                    casts: 0,
                                                    totalMana: 0
                                                };
                                            }

                                            const specificAbilityData = playerTracking.specificAbilities[abilityHrid];
                                            specificAbilityData.casts++;
                                            specificAbilityData.totalMana += manaCost;

                                            if (playerTracking.knownAbilityCosts[abilityHrid]) {
                                                specificAbilityData.manaCost = playerTracking.knownAbilityCosts[abilityHrid];
                                            } else {
                                                specificAbilityData.manaCost = specificAbilityData.totalMana / specificAbilityData.casts;
                                            }

                                            attributedMana += manaCost;
                                        }
                                    }
                                }
                            } else if (playerTracking.lastAbilityHrid) {
                                const abilityHrid = playerTracking.lastAbilityHrid;
                                const abilityName = abilityHrid.split('/').pop().replace(/_/g, ' ');

                                if (!playerTracking.specificAbilities[abilityHrid]) {
                                    playerTracking.specificAbilities[abilityHrid] = {
                                        name: abilityName,
                                        manaCost: remainingManaCost,
                                        casts: 0,
                                        totalMana: 0
                                    };
                                }

                                const specificAbilityData = playerTracking.specificAbilities[abilityHrid];
                                specificAbilityData.casts++;
                                specificAbilityData.totalMana += remainingManaCost;
                                specificAbilityData.manaCost = specificAbilityData.totalMana / specificAbilityData.casts;

                            }
                        } else if (currentMP > lastMP) {
                            const manaGain = currentMP - lastMP;

                            if (!playerTracking.totalManaGained) {
                                playerTracking.totalManaGained = 0;
                            }
                            if (!playerTracking.manaGainsBySize) {
                                playerTracking.manaGainsBySize = {};
                            }

                            playerTracking.totalManaGained += manaGain;

                            const gainKey = `${manaGain}`;
                            if (!playerTracking.manaGainsBySize[gainKey]) {
                                playerTracking.manaGainsBySize[gainKey] = {
                                    amount: manaGain,
                                    count: 0,
                                    totalMana: 0
                                };
                            }
                            playerTracking.manaGainsBySize[gainKey].count++;
                            playerTracking.manaGainsBySize[gainKey].totalMana += manaGain;

                            if (currentMP >= playerTracking.maxMP && lastMP < playerTracking.maxMP) {
                                if (!playerTracking.fullManaCount) {
                                    playerTracking.fullManaCount = 0;
                                }
                                playerTracking.fullManaCount++;
                            }
                        }

                        playerTracking.lastMP = currentMP;
                        playerTracking.lastAbilityHrid = currentAbilityHrid;
                        playerTracking.lastIsAutoAttack = currentIsAutoAttack;

                        if (isNewEntity) {
                            playerTracking.lastInt = currentInt;
                            playerTracking.seenInts.add(currentInt);
                        }
                    });

                    this.manaTracking.lastUpdateTime = currentTime;

                    const now = Date.now();
                    const content = document.getElementById('mana-content');
                    const isMinimized = content && content.style.display === 'none';
                    const throttleInterval = isMinimized ? 2000 : 500;

                    if (!this.manaTracking.lastUIUpdate || now - this.manaTracking.lastUIUpdate >= throttleInterval) {
                        this.manaTracking.lastUIUpdate = now;
                        this.updateMAnaContent();
                    }
                }

                resetMAnaTracking() {
                    this.manaTracking = {
                        players: {},
                        startTime: null,
                        lastUpdateTime: null,
                        totalDuration: 0,
                        lastUIUpdate: 0,
                        savedPausedMs: window.MCS_TOTAL_PAUSED_MS ?? 0,
                        savedTabHiddenMs: window.MCS_TOTAL_TAB_HIDDEN_MS ?? 0
                    };
                    this.updateMAnaContent();
                }

                updateMAnaContent() {
                    const content = document.getElementById('mana-content');
                    if (!content) return;

                    let elapsedSeconds = this.manaTracking?.startTime
                        ? mcsGetElapsedSeconds(this.manaTracking.startTime, this.manaTracking.lastUpdateTime, this.manaTracking.savedPausedMs, this.manaTracking?.totalDuration ?? 0, true, this.manaTracking?.savedTabHiddenMs)
                        : (this.manaTracking?.totalDuration ?? 0);
                    if (elapsedSeconds === 0) elapsedSeconds = 1;

                    const mainPlayerName = CharacterStorageUtils.getPlayerKey();
                    let playerData = null;
                    let mainPlayerIndex = null;

                    if (this.manaTracking?.players) {
                        for (const [index, player] of Object.entries(this.manaTracking.players)) {
                            if (player.name === mainPlayerName) {
                                playerData = player;
                                mainPlayerIndex = index;
                                break;
                            }
                        }
                    }

                    const timeDisplay = document.getElementById('mana-time-display');
                    if (timeDisplay) {
                        const timeStr = mcsFormatDuration(elapsedSeconds, 'clock');

                        if (timeDisplay.textContent !== timeStr) {
                            timeDisplay.textContent = timeStr;
                        }
                    }

                    const manaDisplay = document.getElementById('mana-header-display');
                    if (manaDisplay && playerData) {
                        const currentMana = Math.round(playerData.actualCurrentMP ?? 0);
                        const maxMana = playerData.actualMaxMP ?? 0;
                        const manaStr = `${currentMana}/${maxMana}`;

                        if (manaDisplay.textContent !== manaStr) {
                            manaDisplay.textContent = manaStr;
                        }
                    }

                    if (content.style.display === 'none') return;

                    if (!this.manaTracking?.players || Object.keys(this.manaTracking.players).length === 0) {
                        if (!content.querySelector('.mana-waiting')) {
                content.innerHTML = `
                    <div class="mana-waiting mcs-ma-waiting">
                        <div class="mcs-ma-waiting-icon">⏳</div>
                        <div>Waiting for new fight to begin</div>
                        <div class="mcs-ma-waiting-sub">MAna will begin tracking mana usage shortly</div>
                    </div>
                            `;
                        }
                        return;
                    }

                    if (!playerData) {
                        if (!content.querySelector('.mana-no-usage')) {
                content.innerHTML = `
                    <div class="mana-no-usage mcs-ma-waiting">
                        <div class="mcs-ma-waiting-icon">⏳</div>
                        <div>No mana usage detected yet</div>
                        <div class="mcs-ma-waiting-sub">Cast abilities to see tracking data</div>
                    </div>
                            `;
                        }
                        return;
                    }

                    const hasAbilities = playerData.equippedAbilities && Object.keys(playerData.equippedAbilities).length > 0;
                    const hasManaChanges = playerData.manaChanges && Object.keys(playerData.manaChanges).length > 0;

                    if (!hasAbilities && !hasManaChanges) {
                        if (!content.querySelector('.mana-no-usage')) {
                content.innerHTML = `
                    <div class="mana-no-usage mcs-ma-waiting">
                        <div class="mcs-ma-waiting-icon">⏳</div>
                        <div>No mana usage detected yet</div>
                        <div class="mcs-ma-waiting-sub">Cast abilities to see tracking data</div>
                    </div>
                            `;
                        }
                        return;
                    }

                    this.initializeManaDOMStructure(content, playerData);

                    this.updateAbilityRows(playerData, elapsedSeconds);

                    this.updateManaChangesSection(playerData, elapsedSeconds);
                }

                initializeManaDOMStructure(content, playerData) {
                    if (content.querySelector('#mana-abilities-table')) return;

        content.innerHTML = `
            <div class="mcs-ma-table-wrapper">
                <table id="mana-abilities-table" class="mcs-ma-table">
                    <thead>
                        <tr class="mcs-ma-thead-row">
                            <th class="mcs-ma-th mcs-ma-th-left">Ability Name</th>
                            <th class="mcs-ma-th mcs-ma-th-right">Casts</th>
                            <th class="mcs-ma-th mcs-ma-th-right">Mana Cost</th>
                            <th class="mcs-ma-th mcs-ma-th-right">Total Mana</th>
                            <th class="mcs-ma-th mcs-ma-th-right">m/s</th>
                        </tr>
                    </thead>
                    <tbody id="mana-abilities-tbody"></tbody>
                </table>

                <div class="mcs-ma-changes-section">
                    <table id="mana-changes-table" class="mcs-ma-table">
                        <thead>
                            <tr class="mcs-ma-thead-row">
                                <th class="mcs-ma-th mcs-ma-th-left">Change</th>
                                <th class="mcs-ma-th mcs-ma-th-right">Total</th>
                                <th class="mcs-ma-th mcs-ma-th-right">Count</th>
                                <th class="mcs-ma-th mcs-ma-th-right">Mana/s</th>
                            </tr>
                        </thead>
                        <tbody id="mana-changes-tbody"></tbody>
                        <tfoot id="mana-changes-tfoot"></tfoot>
                    </table>
                </div>
            </div>
                    `;
                }

                updateAbilityRows(playerData, elapsedSeconds) {
                    const tbody = document.getElementById('mana-abilities-tbody');
                    if (!tbody) return;

                    if (!playerData.equippedAbilities || Object.keys(playerData.equippedAbilities).length === 0) {
                        if (tbody.children.length > 0) {
                            tbody.innerHTML = '';
                        }
                        return;
                    }

                    const abilities = Object.entries(playerData.equippedAbilities)
                        .map(([hrid, ability]) => ({ ...ability, hrid }))
                        .sort((a, b) => b.totalMana - a.totalMana);
                    const currentIds = new Set();

                    abilities.forEach((ability, index) => {
                        const sanitizedId = ability.hrid.replace(/[^a-zA-Z0-9_-]/g, '_');
                        const rowId = `ability-row-${sanitizedId}`;
                        currentIds.add(rowId);
                        let row = document.getElementById(rowId);

                        if (!row) {
                            row = document.createElement('tr');
                            row.id = rowId;
                            row.className = 'mcs-ma-ability-row';
                row.innerHTML = `
                    <td class="ability-name mcs-ma-ability-name"></td>
                    <td class="ability-casts mcs-ma-td-right mcs-ma-color-green"></td>
                    <td class="ability-cost mcs-ma-td-right mcs-ma-color-orange"></td>
                    <td class="ability-total mcs-ma-td-right mcs-ma-color-red"></td>
                    <td class="ability-rate mcs-ma-td-right mcs-ma-color-red"></td>
                            `;
                            if (index < tbody.children.length) {
                                tbody.insertBefore(row, tbody.children[index]);
                            } else {
                                tbody.appendChild(row);
                            }
                        } else {
                            const currentIndex = Array.from(tbody.children).indexOf(row);
                            if (currentIndex !== index) {
                                if (index < tbody.children.length) {
                                    tbody.insertBefore(row, tbody.children[index]);
                                } else {
                                    tbody.appendChild(row);
                                }
                            }
                        }

                        const manaPerSecond = (ability.totalMana / elapsedSeconds).toFixed(2);

                        const nameCell = row.querySelector('.ability-name');
                        if (nameCell.textContent !== ability.name) nameCell.textContent = ability.name;

                        const castsCell = row.querySelector('.ability-casts');
                        const castsText = `${ability.casts}×`;
                        if (castsCell.textContent !== castsText) castsCell.textContent = castsText;

                        const costCell = row.querySelector('.ability-cost');
                        const costText = ability.manaCost.toString();
                        if (costCell.textContent !== costText) costCell.textContent = costText;

                        const totalCell = row.querySelector('.ability-total');
                        const totalText = `-${ability.totalMana.toFixed(1)}`;
                        if (totalCell.textContent !== totalText) totalCell.textContent = totalText;

                        const rateCell = row.querySelector('.ability-rate');
                        const rateText = `-${manaPerSecond}`;
                        if (rateCell.textContent !== rateText) rateCell.textContent = rateText;
                    });

                    const existingRows = Array.from(tbody.querySelectorAll('[id^="ability-row-"]'));
                    existingRows.forEach(row => {
                        if (!currentIds.has(row.id)) {
                            row.remove();
                        }
                    });
                }

                updateManaChangesSection(playerData, elapsedSeconds) {
                    const tbody = document.getElementById('mana-changes-tbody');
                    const tfoot = document.getElementById('mana-changes-tfoot');
                    if (!tbody || !tfoot) return;

                    const manaChanges = Object.values(playerData.manaChanges || {});
                    if (manaChanges.length === 0) {
                        if (tbody.children.length > 0) {
                            tbody.innerHTML = '';
                        }

                        let fullManaRow = document.getElementById('mana-full-mana-row-empty');
                        if (!fullManaRow) {
                tfoot.innerHTML = `
                    <tr id="mana-full-mana-row-empty" class="mcs-ma-full-mana-row">
                        <td class="mcs-ma-td mcs-ma-color-purple">Full Mana</td>
                        <td class="mcs-ma-td-right mcs-ma-color-purple">—</td>
                        <td class="full-mana-count mcs-ma-td-right mcs-ma-color-green"></td>
                        <td class="mcs-ma-td-right mcs-ma-color-purple">—</td>
                    </tr>
                            `;
                            fullManaRow = document.getElementById('mana-full-mana-row-empty');
                        }

                        const fullManaCell = fullManaRow.querySelector('.full-mana-count');
                        const fullManaText = `${playerData.fullManaCount ?? 0}×`;
                        if (fullManaCell.textContent !== fullManaText) {
                            fullManaCell.textContent = fullManaText;
                        }
                        return;
                    }

                    manaChanges.sort((a, b) => Math.abs(b.amount) - Math.abs(a.amount));

                    let netChange = 0;

                    manaChanges.forEach(change => {
                        const totalChange = change.amount * change.count;
                        const changePerSecond = (totalChange / elapsedSeconds).toFixed(2);
                        netChange += totalChange;

                        const color = change.amount < 0 ? '#ef5350' : '#64b5f6';
                        const sign = change.amount > 0 ? '+' : '';

                        const rowId = `change-row-${change.amount}`;
                        let row = document.getElementById(rowId);

                        if (!row) {
                            row = document.createElement('tr');
                            row.id = rowId;
                            row.className = 'mcs-ma-change-row';
                row.innerHTML = `
                    <td class="change-amount mcs-ma-td"></td>
                    <td class="change-total mcs-ma-td-right"></td>
                    <td class="change-count mcs-ma-td-right mcs-ma-color-green"></td>
                    <td class="change-rate mcs-ma-td-right"></td>
                            `;
                            tbody.appendChild(row);
                        }

                        const amountCell = row.querySelector('.change-amount');
                        const amountText = `${sign}${change.amount}`;
                        if (amountCell.textContent !== amountText || amountCell.style.color !== color) {
                            amountCell.textContent = amountText;
                            amountCell.style.color = color;
                        }

                        const totalCell = row.querySelector('.change-total');
                        const totalText = `${sign}${totalChange.toFixed(1)}`;
                        if (totalCell.textContent !== totalText || totalCell.style.color !== color) {
                            totalCell.textContent = totalText;
                            totalCell.style.color = color;
                        }

                        const countCell = row.querySelector('.change-count');
                        const countText = `${change.count}×`;
                        if (countCell.textContent !== countText) countCell.textContent = countText;

                        const rateCell = row.querySelector('.change-rate');
                        const rateText = `${sign}${changePerSecond}`;
                        if (rateCell.textContent !== rateText || rateCell.style.color !== color) {
                            rateCell.textContent = rateText;
                            rateCell.style.color = color;
                        }
                    });

                    const netChangePerSecond = (netChange / elapsedSeconds).toFixed(2);
                    const netColor = netChange < 0 ? '#ef5350' : '#64b5f6';
                    const netSign = netChange > 0 ? '+' : '';

                    let netChangeRow = document.getElementById('mana-net-change-row');
                    let fullManaRow = document.getElementById('mana-full-mana-row');

                    if (!netChangeRow || !fullManaRow) {
            tfoot.innerHTML = `
                <tr id="mana-net-change-row" class="mcs-ma-net-row">
                    <td class="net-label mcs-ma-td">Net Change</td>
                    <td class="net-total mcs-ma-td-right"></td>
                    <td class="mcs-ma-td-right mcs-ma-color-green">—</td>
                    <td class="net-rate mcs-ma-td-right"></td>
                </tr>
                <tr id="mana-full-mana-row" class="mcs-ma-full-mana-row">
                    <td class="mcs-ma-td mcs-ma-color-purple">Full Mana</td>
                    <td class="mcs-ma-td-right mcs-ma-color-purple">—</td>
                    <td class="full-mana-count mcs-ma-td-right mcs-ma-color-green"></td>
                    <td class="mcs-ma-td-right mcs-ma-color-purple">—</td>
                </tr>
                        `;
                        netChangeRow = document.getElementById('mana-net-change-row');
                        fullManaRow = document.getElementById('mana-full-mana-row');
                    }

                    const netLabelCell = netChangeRow.querySelector('.net-label');
                    if (netLabelCell.style.color !== netColor) netLabelCell.style.color = netColor;

                    const netTotalCell = netChangeRow.querySelector('.net-total');
                    const netTotalText = `${netSign}${netChange.toFixed(1)}`;
                    if (netTotalCell.textContent !== netTotalText || netTotalCell.style.color !== netColor) {
                        netTotalCell.textContent = netTotalText;
                        netTotalCell.style.color = netColor;
                    }

                    const netRateCell = netChangeRow.querySelector('.net-rate');
                    const netRateText = `${netSign}${netChangePerSecond}`;
                    if (netRateCell.textContent !== netRateText || netRateCell.style.color !== netColor) {
                        netRateCell.textContent = netRateText;
                        netRateCell.style.color = netColor;
                    }

                    const fullManaCell = fullManaRow.querySelector('.full-mana-count');
                    const fullManaText = `${playerData.fullManaCount ?? 0}×`;
                    if (fullManaCell.textContent !== fullManaText) {
                        fullManaCell.textContent = fullManaText;
                    }
                }

                destroyMAna() {
                    if (this._maDragMove) {
                        document.removeEventListener('mousemove', this._maDragMove);
                        document.removeEventListener('mouseup', this._maDragUp);
                        this._maDragMove = null;
                        this._maDragUp = null;
                    }
                    if (this._maResizeObserver) {
                        this._maResizeObserver.disconnect();
                        this._maResizeObserver = null;
                    }
                    const pane = document.getElementById('mana-pane');
                    if (pane) pane.remove();
                }

// MAna end

// TReasure start

            mcs_tr_handleWebSocketMessage(event) {
                if (window.MCS_MODULES_DISABLED) return;
                const data = event.detail;
                if (data?.type === 'loot_opened') {
                    this.mcs_tr_handleLootOpened(data);
                }
            }

            mcs_tr_handleStorage(event) {
                if (event.key && event.key.includes('mcs_FL_ask_bid_price_mode')) {
                    this.mcs_tr_renderContent();
                }
            }

            mcs_tr_handlePriceToggleClick(event) {
                const target = event.target;
                if (target.classList.contains('ldt-price-toggle-btn') ||
                    target.classList.contains('ldt-price-toggle-btn-hidden')) {
                    setTimeout(() => this.mcs_tr_renderContent(), 200);
                }
            }

            mcs_tr_handleFlootPricesUpdated() {
                this.mcs_tr_renderContent();
            }

            mcs_tr_getStorageKey() {
                const playerName = this.mcs_tr_getPlayerName();
                return `mcs_TR_${playerName}`;
            }

            mcs_tr_getPlayerName() {
                try {
                    const cachedData = CharacterDataStorage.get();
                    if (cachedData) {
                        if (cachedData.character?.name) {
                            return cachedData.character.name;
                        }
                    }
                } catch (e) {
                    console.error('[TReasure] Error getting player name:', e);
                }
                return 'Unknown';
            }

            mcs_tr_initData() {
                return {
                    chests: {},
                    hidden: [],
                    minimized: false,
                    position: null,
                    size: null,
                    useMirrorValue: false,
                    useCowbell0: false,
                    expandedTokenShops: []
                };
            }

            mcs_tr_getTokenShopData() {
                return {
                    '/items/chimerical_token': {
                        name: 'Chimerical Token',
                        items: [
                            { hrid: '/items/griffin_leather', name: 'Griffin Leather', cost: 600 },
                            { hrid: '/items/manticore_sting', name: 'Manticore Sting', cost: 1000 },
                            { hrid: '/items/jackalope_antler', name: 'Jackalope Antler', cost: 1200 },
                            { hrid: '/items/dodocamel_plume', name: 'Dodocamel Plume', cost: 3000 },
                            { hrid: '/items/griffin_talon', name: 'Griffin Talon', cost: 3000 },
                            { hrid: '/items/chimerical_quiver', name: 'Chimerical Quiver', cost: 35000, isCapeItem: true }
                        ]
                    },
                    '/items/sinister_token': {
                        name: 'Sinister Token',
                        items: [
                            { hrid: '/items/acrobats_ribbon', name: "Acrobat's Ribbon", cost: 2000 },
                            { hrid: '/items/magicians_cloth', name: "Magician's Cloth", cost: 2000 },
                            { hrid: '/items/chaotic_chain', name: 'Chaotic Chain', cost: 3000 },
                            { hrid: '/items/cursed_ball', name: 'Cursed Ball', cost: 3000 },
                            { hrid: '/items/sinister_cape', name: 'Sinister Cape', cost: 27000, isCapeItem: true }
                        ]
                    },
                    '/items/enchanted_token': {
                        name: 'Enchanted Token',
                        items: [
                            { hrid: '/items/royal_cloth', name: 'Royal Cloth', cost: 2000 },
                            { hrid: '/items/knights_ingot', name: "Knight's Ingot", cost: 2000 },
                            { hrid: '/items/bishops_scroll', name: "Bishop's Scroll", cost: 2000 },
                            { hrid: '/items/regal_jewel', name: 'Regal Jewel', cost: 3000 },
                            { hrid: '/items/sundering_jewel', name: 'Sundering Jewel', cost: 3000 },
                            { hrid: '/items/enchanted_cloak', name: 'Enchanted Cloak', cost: 27000, isCapeItem: true }
                        ]
                    },
                    '/items/pirate_token': {
                        name: 'Pirate Token',
                        items: [
                            { hrid: '/items/marksman_brooch', name: 'Marksman Brooch', cost: 2000 },
                            { hrid: '/items/corsair_crest', name: 'Corsair Crest', cost: 2000 },
                            { hrid: '/items/damaged_anchor', name: 'Damaged Anchor', cost: 2000 },
                            { hrid: '/items/maelstrom_plating', name: 'Maelstrom Plating', cost: 2000 },
                            { hrid: '/items/kraken_leather', name: 'Kraken Leather', cost: 2000 },
                            { hrid: '/items/kraken_fang', name: 'Kraken Fang', cost: 3000 }
                        ]
                    }
                };
            }

            mcs_tr_getMirrorPrice() {
                const price = typeof window.getUnitValue === 'function' ? window.getUnitValue('/items/mirror_of_protection', 'live') : 0;
                return price ?? 0;
            }

            mcs_tr_calculateTokenValue(tokenHrid) {
                const data = this.mcs_tr_loadData();
                const useMirrorValue = data.useMirrorValue;
                const shopData = this.mcs_tr_getTokenShopData()[tokenHrid];
                if (!shopData) return 0;

                let bestValuePerToken = 0;

                for (const item of shopData.items) {
                    let itemPrice;
                    if (item.isCapeItem && useMirrorValue) {
                        itemPrice = this.mcs_tr_getMirrorPrice();
                    } else if (item.isCapeItem) {
                        continue;
                    } else {
                        itemPrice = this.mcs_tr_getItemPrice(item.hrid);
                    }

                    if (itemPrice > 0) {
                        const valuePerToken = itemPrice / item.cost;
                        if (valuePerToken > bestValuePerToken) {
                            bestValuePerToken = valuePerToken;
                        }
                    }
                }

                return bestValuePerToken;
            }

            mcs_tr_getCapeItemPrice(tokenHrid, capeItem) {
                const data = this.mcs_tr_loadData();
                if (data.useMirrorValue) {
                    return this.mcs_tr_getMirrorPrice();
                }

                const shopData = this.mcs_tr_getTokenShopData()[tokenHrid];
                if (!shopData) return 0;

                let bestValuePerToken = 0;
                for (const item of shopData.items) {
                    if (item.isCapeItem) continue;
                    const itemPrice = this.mcs_tr_getItemPrice(item.hrid);
                    if (itemPrice > 0) {
                        const valuePerToken = itemPrice / item.cost;
                        if (valuePerToken > bestValuePerToken) {
                            bestValuePerToken = valuePerToken;
                        }
                    }
                }

                return bestValuePerToken * capeItem.cost;
            }

            mcs_tr_loadData() {
                try {
                    const key = this.mcs_tr_getStorageKey();
                    const saved = localStorage.getItem(key);
                    if (saved) {
                        const data = JSON.parse(saved);
                        if (!data.chests) data.chests = {};
                        if (!data.hidden) data.hidden = [];
                        if (data.useMirrorValue === undefined) data.useMirrorValue = false;
                        if (data.useCowbell0 === undefined) data.useCowbell0 = false;
                        if (!data.expandedTokenShops) data.expandedTokenShops = [];
                        return data;
                    }
                } catch (e) {
                    console.error('[TReasure] Error loading data:', e);
                }
                return this.mcs_tr_initData();
            }

            mcs_tr_saveData(data) {
                try {
                    const key = this.mcs_tr_getStorageKey();
                    localStorage.setItem(key, JSON.stringify(data));
                } catch (e) {
                    console.error('[TReasure] Error saving data:', e);
                }
            }

            mcs_tr_resetChest(chestHrid = null) {
                const data = this.mcs_tr_loadData();
                if (chestHrid) {
                    delete data.chests[chestHrid];
                } else {
                    data.chests = {};
                }
                this.mcs_tr_saveData(data);
                this.mcs_tr_renderContent();
            }

            mcs_tr_loadHiddenChests() {
                const data = this.mcs_tr_loadData();
                return new Set(data.hidden || []);
            }

            mcs_tr_saveHiddenChests(hiddenSet) {
                const data = this.mcs_tr_loadData();
                data.hidden = [...hiddenSet];
                this.mcs_tr_saveData(data);
            }

            mcs_tr_toggleChestVisibility(chestHrid) {
                const data = this.mcs_tr_loadData();
                const hidden = new Set(data.hidden || []);
                if (hidden.has(chestHrid)) {
                    hidden.delete(chestHrid);
                } else {
                    hidden.add(chestHrid);
                }
                data.hidden = [...hidden];
                this.mcs_tr_saveData(data);
                this.mcs_tr_renderContent();
            }

            mcs_tr_getChestLootTable(chestHrid) {
                try {
                    const initData = InitClientDataCache.get();
                    if (!initData?.openableLootDropMap) return null;

                    return initData.openableLootDropMap[chestHrid] || null;
                } catch (e) {
                    console.error('[TReasure] Error getting chest loot table:', e);
                    return null;
                }
            }

            mcs_tr_getAllOpenableItems() {
                try {
                    const initData = InitClientDataCache.get();
                    return initData?.openableLootDropMap || {};
                } catch (e) {
                    console.error('[TReasure] Error getting openable items:', e);
                    return {};
                }
            }

            mcs_tr_calculateExpectedForOne(chestHrid) {
                const lootTable = this.mcs_tr_getChestLootTable(chestHrid);
                if (!lootTable) return {};

                const expected = {};
                for (const drop of lootTable) {
                    const itemHrid = drop.itemHrid;
                    const dropRate = drop.dropRate ?? 0;
                    const minCount = drop.minCount ?? 0;
                    const maxCount = drop.maxCount ?? 0;
                    const avgCount = (minCount + maxCount) / 2;
                    const expectedCount = dropRate * avgCount;

                    if (expectedCount > 0) {
                        expected[itemHrid] = (expected[itemHrid] ?? 0) + expectedCount;
                    }
                }
                return expected;
            }

            mcs_tr_calculateExpectedForN(chestHrid, count) {
                const expectedForOne = this.mcs_tr_calculateExpectedForOne(chestHrid);
                const expected = {};
                for (const [itemHrid, value] of Object.entries(expectedForOne)) {
                    expected[itemHrid] = value * count;
                }
                return expected;
            }

            mcs_tr_calculateChestExpectedValue(chestHrid) {
                const expectedForOne = this.mcs_tr_calculateExpectedForOne(chestHrid);
                let totalValue = 0;

                for (const [itemHrid, expectedCount] of Object.entries(expectedForOne)) {
                    const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                    totalValue += expectedCount * itemPrice;
                }

                return totalValue;
            }

            mcs_tr_getItemPrice(itemHrid) {
                if (itemHrid === '/items/coin') {
                    return 1;
                }

                if (itemHrid === '/items/cowbell') {
                    const data = this.mcs_tr_loadData();
                    if (data.useCowbell0) {
                        return 0;
                    }
                    const useAskPrice = typeof window.getFlootUseAskPrice === 'function' ? window.getFlootUseAskPrice() : false;
                    const bagPrice = typeof window.getUnitValue === 'function' ? window.getUnitValue('/items/bag_of_10_cowbells', 'live') : 0;
                    if (bagPrice) {
                        return bagPrice / 10;
                    }
                    return useAskPrice ? 36000 : 35000;
                }

                if (itemHrid === '/items/task_token') {
                    const cachePrice = typeof window.getUnitValue === 'function' ? window.getUnitValue('/items/large_meteorite_cache', 'live') : 0;
                    if (cachePrice) {
                        return cachePrice / 30;
                    }
                    return 0;
                }

                const capeItemMap = {
                    '/items/chimerical_quiver': { tokenHrid: '/items/chimerical_token', cost: 35000 },
                    '/items/sinister_cape': { tokenHrid: '/items/sinister_token', cost: 27000 },
                    '/items/enchanted_cloak': { tokenHrid: '/items/enchanted_token', cost: 27000 }
                };

                if (capeItemMap[itemHrid]) {
                    const data = this.mcs_tr_loadData();
                    if (data.useMirrorValue) {
                        return this.mcs_tr_getMirrorPrice();
                    } else {
                        const capeInfo = capeItemMap[itemHrid];
                        return this.mcs_tr_getCapeItemPrice(capeInfo.tokenHrid, { cost: capeInfo.cost });
                    }
                }

                const tokenHrids = [
                    '/items/chimerical_token',
                    '/items/sinister_token',
                    '/items/enchanted_token',
                    '/items/pirate_token'
                ];
                if (tokenHrids.includes(itemHrid)) {
                    return this.mcs_tr_calculateTokenValue(itemHrid);
                }

                const price = typeof window.getUnitValue === 'function' ? window.getUnitValue(itemHrid, 'live') : 0;
                return price ?? 0;
            }

            mcs_tr_formatItemName(hrid) {
                return mcsFormatHrid(hrid);
            }

            mcs_tr_formatNumber(value) {
                return mcsFormatCurrency(value, 'cost');
            }

            mcs_tr_formatExpectedCount(value) {
                if (value >= 1000000000) {
                    return (value / 1000000000).toFixed(2) + 'B';
                } else if (value >= 1000000) {
                    return (value / 1000000).toFixed(2) + 'M';
                } else if (value >= 1000) {
                    return (value / 1000).toFixed(1) + 'K';
                } else if (value >= 100) {
                    return value.toFixed(1);
                } else if (value >= 1) {
                    return value.toFixed(2);
                } else if (value >= 0.01) {
                    return value.toFixed(3);
                } else if (value >= 0.001) {
                    return value.toFixed(4);
                } else if (value > 0) {
                    return value.toExponential(2);
                }
                return '0';
            }

            mcs_tr_formatPercentDiff(actual, expected) {
                if (expected === 0) {
                    return actual > 0 ? '+∞%' : '0%';
                }
                const diff = ((actual - expected) / expected) * 100;
                const sign = diff >= 0 ? '+' : '';
                return `${sign}${diff.toFixed(1)}%`;
            }

            mcs_tr_exportData() {
                try {
                    const data = this.mcs_tr_loadData();
                    const playerName = this.mcs_tr_getPlayerName();
                    const exportObj = {
                        player: playerName,
                        exportedAt: new Date().toISOString(),
                        settings: {
                            useMirrorValue: data.useMirrorValue,
                            useCowbell0: data.useCowbell0
                        },
                        chests: {}
                    };

                    for (const [chestHrid, chest] of Object.entries(data.chests)) {
                        const chestName = this.mcs_tr_formatItemName(chestHrid);
                        const expectedPerOpen = this.mcs_tr_calculateExpectedForOne(chestHrid);
                        const chestEV = this.mcs_tr_calculateChestExpectedValue(chestHrid);

                        const totalLoot = {};
                        for (const [itemHrid, count] of Object.entries(chest.total.loot || {})) {
                            totalLoot[itemHrid] = {
                                name: this.mcs_tr_formatItemName(itemHrid),
                                count,
                                unitPrice: this.mcs_tr_getItemPrice(itemHrid),
                                totalValue: count * this.mcs_tr_getItemPrice(itemHrid)
                            };
                        }

                        const lastLoot = {};
                        for (const [itemHrid, count] of Object.entries(chest.last.loot || {})) {
                            lastLoot[itemHrid] = {
                                name: this.mcs_tr_formatItemName(itemHrid),
                                count,
                                unitPrice: this.mcs_tr_getItemPrice(itemHrid),
                                totalValue: count * this.mcs_tr_getItemPrice(itemHrid)
                            };
                        }

                        let totalActualValue = 0;
                        for (const item of Object.values(totalLoot)) {
                            totalActualValue += item.totalValue;
                        }
                        const totalExpectedValue = chestEV * chest.total.opened;

                        exportObj.chests[chestHrid] = {
                            name: chestName,
                            expectedValuePerOpen: chestEV,
                            total: {
                                opened: chest.total.opened,
                                actualValue: totalActualValue,
                                expectedValue: totalExpectedValue,
                                luck: totalExpectedValue > 0 ? ((totalActualValue / totalExpectedValue - 1) * 100).toFixed(1) + '%' : 'N/A',
                                loot: totalLoot
                            },
                            last: {
                                opened: chest.last.opened,
                                loot: lastLoot
                            },
                            expectedPerOpen
                        };
                    }

                    const blob = new Blob([JSON.stringify(exportObj, null, 2)], { type: 'application/json' });
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = `treasure_${playerName}_${new Date().toISOString().slice(0, 10)}.json`;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                } catch (e) {
                    console.error('[TReasure] Error exporting data:', e);
                }
            }

            mcs_tr_importData() {
                const input = document.createElement('input');
                input.type = 'file';
                input.accept = '.json';
                input.onchange = (e) => {
                    const file = e.target.files[0];
                    if (!file) return;
                    const reader = new FileReader();
                    reader.onload = (ev) => {
                        try {
                            const imported = JSON.parse(ev.target.result);
                            if (!imported.chests || typeof imported.chests !== 'object') {
                                alert('Invalid treasure export file: no chests data found.');
                                return;
                            }

                            const rawChests = {};
                            for (const [chestHrid, chest] of Object.entries(imported.chests)) {
                                const totalLoot = {};
                                for (const [itemHrid, item] of Object.entries(chest.total?.loot || {})) {
                                    totalLoot[itemHrid] = typeof item === 'object' ? item.count : item;
                                }
                                const lastLoot = {};
                                for (const [itemHrid, item] of Object.entries(chest.last?.loot || {})) {
                                    lastLoot[itemHrid] = typeof item === 'object' ? item.count : item;
                                }
                                rawChests[chestHrid] = {
                                    total: { opened: chest.total?.opened || 0, loot: totalLoot },
                                    last: { opened: chest.last?.opened || 0, loot: lastLoot }
                                };
                            }

                            const data = this.mcs_tr_loadData();
                            data.chests = rawChests;
                            if (imported.settings) {
                                if (imported.settings.useMirrorValue !== undefined) data.useMirrorValue = imported.settings.useMirrorValue;
                                if (imported.settings.useCowbell0 !== undefined) data.useCowbell0 = imported.settings.useCowbell0;
                            }
                            this.mcs_tr_saveData(data);
                            this.mcs_tr_renderContent();
                        } catch (err) {
                            console.error('[TReasure] Error importing data:', err);
                            alert('Error importing treasure data: ' + err.message);
                        }
                    };
                    reader.readAsText(file);
                };
                input.click();
            }

            mcs_tr_getEdibleToolsChestData() {
                try {
                    const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools'));
                    if (!edibleTools?.Chest_Open_Data) return null;

                    const openData = edibleTools.Chest_Open_Data;
                    const cachedData = CharacterDataStorage.get();
                    const playerId = cachedData?.character?.id;
                    const playerName = cachedData?.character?.name;

                    let playerEntry = null;
                    if (playerId != null) {
                        playerEntry = openData[playerId] || openData[String(playerId)];
                    }

                    if (!playerEntry && playerName) {
                        for (const data of Object.values(openData)) {
                            if (data?.玩家昵称 === playerName) {
                                playerEntry = data;
                                break;
                            }
                        }
                    }

                    if (playerEntry?.开箱数据 && Object.keys(playerEntry.开箱数据).length > 0) {
                        return playerEntry.开箱数据;
                    }

                    for (const data of Object.values(openData)) {
                        if (data?.开箱数据 && Object.keys(data.开箱数据).length > 0) {
                            return data.开箱数据;
                        }
                    }

                    return null;
                } catch (e) {
                    console.error('[TReasure] Error reading Edible Tools data:', e);
                    return null;
                }
            }

            mcs_tr_showEdibleImportDialog() {
                const overlay = document.createElement('div');
                overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.6);z-index:100000;display:flex;align-items:center;justify-content:center';
                const dialog = document.createElement('div');
                dialog.style.cssText = 'background:#2a2a2a;border:1px solid #555;border-radius:8px;padding:20px;min-width:320px;color:#ddd;font-family:sans-serif;text-align:center';
                dialog.innerHTML = '<div style="font-size:15px;font-weight:bold;margin-bottom:12px">Import from Edible Tools</div>' +
                    '<div style="font-size:13px;color:#aaa;margin-bottom:18px;line-height:1.5">' +
                    '<b>Append</b> — add Edible Tools stats to existing data<br>' +
                    '<b>Overwrite</b> — replace all data with Edible Tools data</div>';
                const btnStyle = 'padding:8px 20px;margin:0 6px;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:bold';
                const appendBtn = document.createElement('button');
                appendBtn.textContent = 'Append';
                appendBtn.style.cssText = btnStyle + ';background:#4a7c4a;color:#fff';
                appendBtn.onclick = () => { overlay.remove(); this.mcs_tr_importEdibleTools('append'); };
                const overwriteBtn = document.createElement('button');
                overwriteBtn.textContent = 'Overwrite';
                overwriteBtn.style.cssText = btnStyle + ';background:#7c4a4a;color:#fff';
                overwriteBtn.onclick = () => { overlay.remove(); this.mcs_tr_importEdibleTools('overwrite'); };
                const cancelBtn = document.createElement('button');
                cancelBtn.textContent = 'Cancel';
                cancelBtn.style.cssText = btnStyle + ';background:#555;color:#ccc';
                cancelBtn.onclick = () => overlay.remove();
                dialog.append(appendBtn, overwriteBtn, cancelBtn);
                overlay.appendChild(dialog);
                overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); };
                document.body.appendChild(overlay);
            }

            mcs_tr_importEdibleTools(mode = 'overwrite') {
                try {
                    const ediChests = this.mcs_tr_getEdibleToolsChestData();
                    if (!ediChests) {
                        alert('No Edible Tools chest data found.');
                        return;
                    }

                    const itemDetailMap = InitClientDataCache.getItemDetailMap();
                    const nameToHrid = {};
                    for (const [hrid, detail] of Object.entries(itemDetailMap)) {
                        if (detail?.name) {
                            nameToHrid[detail.name] = hrid;
                        }
                    }

                    const convertedChests = {};
                    let convertedCount = 0;
                    for (const [chestDisplayName, chestData] of Object.entries(ediChests)) {
                        const chestHrid = nameToHrid[chestDisplayName];
                        if (!chestHrid) {
                            console.warn('[TReasure] Could not find hrid for chest:', chestDisplayName);
                            continue;
                        }

                        const loot = {};
                        if (chestData.获得物品) {
                            for (const [itemDisplayName, itemData] of Object.entries(chestData.获得物品)) {
                                const itemHrid = nameToHrid[itemDisplayName];
                                if (!itemHrid) {
                                    console.warn('[TReasure] Could not find hrid for item:', itemDisplayName);
                                    continue;
                                }
                                loot[itemHrid] = itemData.数量 || 0;
                            }
                        }

                        convertedChests[chestHrid] = {
                            total: { opened: chestData.总计开箱数量 || 0, loot },
                            last: { opened: 0, loot: {} }
                        };
                        convertedCount++;
                    }

                    if (convertedCount === 0) {
                        alert('No chest data could be converted. Item names may not match.');
                        return;
                    }

                    const data = this.mcs_tr_loadData();
                    if (mode === 'append') {
                        for (const [chestHrid, imported] of Object.entries(convertedChests)) {
                            if (!data.chests[chestHrid]) {
                                data.chests[chestHrid] = imported;
                            } else {
                                const existing = data.chests[chestHrid];
                                existing.total.opened += imported.total.opened;
                                for (const [itemHrid, count] of Object.entries(imported.total.loot)) {
                                    existing.total.loot[itemHrid] = (existing.total.loot[itemHrid] ?? 0) + count;
                                }
                            }
                        }
                    } else {
                        data.chests = convertedChests;
                    }
                    this.mcs_tr_saveData(data);
                    this.mcs_tr_renderContent();
                } catch (e) {
                    console.error('[TReasure] Error importing Edible Tools data:', e);
                    alert('Error importing Edible Tools data: ' + e.message);
                }
            }

            mcs_tr_getItemIconHtml(itemHrid, size = 24) {
                const itemName = itemHrid.replace('/items/', '');
                return createItemIconHtml(itemName, { width: size, height: size, sprite: 'items_sprite', style: 'vertical-align: middle' });
            }

            mcs_tr_handleLootOpened(data) {
                if (!data || !data.openedItem || !data.gainedItems) return;

                const chestHrid = data.openedItem.itemHrid;
                const chestCount = data.openedItem.count || 1;

                const lootMap = {};
                for (const item of data.gainedItems) {
                    const itemHrid = item.itemHrid;
                    const count = item.count ?? 0;
                    lootMap[itemHrid] = (lootMap[itemHrid] ?? 0) + count;
                }

                const treasureData = this.mcs_tr_loadData();

                if (!treasureData.chests[chestHrid]) {
                    treasureData.chests[chestHrid] = {
                        total: { opened: 0, loot: {} },
                        last: { opened: 0, loot: {} }
                    };
                }

                const chest = treasureData.chests[chestHrid];

                chest.last = {
                    opened: chestCount,
                    loot: { ...lootMap }
                };

                chest.total.opened += chestCount;
                for (const [itemHrid, count] of Object.entries(lootMap)) {
                    chest.total.loot[itemHrid] = (chest.total.loot[itemHrid] ?? 0) + count;
                }

                this.mcs_tr_saveData(treasureData);
                this.mcs_tr_renderContent();
            }

            createTReasurePane() {
                if (document.getElementById('treasure-pane')) return;

                this.mcs_tr_expandedChests = new Set();

                const pane = document.createElement('div');
                pane.id = 'treasure-pane';
                registerPanel('treasure-pane');

                const trData = this.mcs_tr_loadData();
                let initialWidth = 520;
                let initialHeight = 600;
                if (trData.size) {
                    initialWidth = trData.size.width || 520;
                    initialHeight = trData.size.height || 600;
                }

                pane.className = 'mcs-pane mcs-tr-pane';
                pane.style.width = initialWidth + 'px';
                pane.style.height = initialHeight + 'px';

                const header = document.createElement('div');
                header.className = 'mcs-pane-header';

                const titleSection = document.createElement('div');
                titleSection.className = 'mcs-tr-title-section';

                const title = document.createElement('span');
                title.textContent = 'TReasure';
                title.className = 'mcs-tr-title';
                titleSection.appendChild(title);

                const resetAllBtn = document.createElement('span');
                resetAllBtn.id = 'treasure-reset-all-btn';
                resetAllBtn.textContent = 'Reset All';
                resetAllBtn.className = 'mcs-tr-header-btn mcs-tr-reset-all-btn';
                resetAllBtn.onclick = (e) => {
                    e.stopPropagation();
                    if (confirm('Reset ALL treasure tracking data?')) {
                        this.mcs_tr_resetChest(null);
                    }
                };
                titleSection.appendChild(resetAllBtn);

                const mirrorToggleBtn = document.createElement('span');
                mirrorToggleBtn.id = 'treasure-mirror-toggle-btn';
                const updateMirrorToggleAppearance = () => {
                    const currentData = this.mcs_tr_loadData();
                    const useMirror = currentData.useMirrorValue;
                    mirrorToggleBtn.textContent = useMirror ? 'Mirror Value' : 'Token Value';
                    mirrorToggleBtn.style.color = useMirror ? '#9370DB' : '#FFD700';
                    mirrorToggleBtn.style.background = useMirror ? '#4a3a5a' : '#444';
                };
                mirrorToggleBtn.title = 'Toggle cape/quiver/cloak valuation method';
                mirrorToggleBtn.className = 'mcs-tr-header-btn';
                updateMirrorToggleAppearance();
                mirrorToggleBtn.onmouseover = () => mirrorToggleBtn.style.opacity = '0.8';
                mirrorToggleBtn.onmouseout = () => mirrorToggleBtn.style.opacity = '1';
                mirrorToggleBtn.onclick = (e) => {
                    e.stopPropagation();
                    const data = this.mcs_tr_loadData();
                    data.useMirrorValue = !data.useMirrorValue;
                    this.mcs_tr_saveData(data);
                    updateMirrorToggleAppearance();
                    this.mcs_tr_renderContent();
                };
                titleSection.appendChild(mirrorToggleBtn);

                const cowbellToggleBtn = document.createElement('span');
                cowbellToggleBtn.id = 'treasure-cowbell-toggle-btn';
                const updateCowbellToggleAppearance = () => {
                    const currentData = this.mcs_tr_loadData();
                    const useCowbell0 = currentData.useCowbell0;
                    cowbellToggleBtn.textContent = useCowbell0 ? 'Cowbell 0' : 'Cowbell Market';
                    cowbellToggleBtn.style.color = useCowbell0 ? '#888' : '#FFD700';
                    cowbellToggleBtn.style.background = useCowbell0 ? '#3a3a3a' : '#444';
                };
                cowbellToggleBtn.title = 'Toggle cowbell valuation: 0 or market price';
                cowbellToggleBtn.className = 'mcs-tr-header-btn';
                updateCowbellToggleAppearance();
                cowbellToggleBtn.onmouseover = () => cowbellToggleBtn.style.opacity = '0.8';
                cowbellToggleBtn.onmouseout = () => cowbellToggleBtn.style.opacity = '1';
                cowbellToggleBtn.onclick = (e) => {
                    e.stopPropagation();
                    const data = this.mcs_tr_loadData();
                    data.useCowbell0 = !data.useCowbell0;
                    this.mcs_tr_saveData(data);
                    updateCowbellToggleAppearance();
                    this.mcs_tr_renderContent();
                    window.dispatchEvent(new CustomEvent('FlootPricesUpdated'));
                };
                titleSection.appendChild(cowbellToggleBtn);

                const configureBtn = document.createElement('span');
                configureBtn.id = 'treasure-configure-btn';
                configureBtn.innerHTML = '⚙';
                configureBtn.title = 'Configure visible chests';
                configureBtn.className = 'mcs-tr-header-btn mcs-tr-configure-btn';
                configureBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.mcs_tr_configureMode = !this.mcs_tr_configureMode;
                    configureBtn.classList.toggle('active', this.mcs_tr_configureMode);
                    this.mcs_tr_renderContent();
                };
                titleSection.appendChild(configureBtn);

                const exportBtn = document.createElement('span');
                exportBtn.id = 'treasure-export-btn';
                exportBtn.textContent = 'Export';
                exportBtn.title = 'Export treasure data';
                exportBtn.className = 'mcs-tr-header-btn mcs-tr-configure-btn';
                exportBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.mcs_tr_exportData();
                };
                titleSection.appendChild(exportBtn);

                const importBtn = document.createElement('span');
                importBtn.id = 'treasure-import-btn';
                importBtn.textContent = 'Import';
                importBtn.title = 'Import treasure data';
                importBtn.className = 'mcs-tr-header-btn mcs-tr-configure-btn';
                importBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.mcs_tr_importData();
                };
                titleSection.appendChild(importBtn);

                const ediBtn = document.createElement('span');
                ediBtn.id = 'treasure-edi-import-btn';
                ediBtn.innerHTML = '🍴';
                ediBtn.title = 'Import from Edible Tools';
                ediBtn.className = 'mcs-tr-header-btn mcs-tr-configure-btn';
                ediBtn.onclick = (e) => {
                    e.stopPropagation();
                    if (!this.mcs_tr_getEdibleToolsChestData()) {
                        alert('No Edible Tools chest data found.');
                        return;
                    }
                    this.mcs_tr_showEdibleImportDialog();
                };
                titleSection.appendChild(ediBtn);

                this.mcs_tr_configureMode = false;

                const buttonsSection = document.createElement('div');
                buttonsSection.className = 'mcs-button-section';

                const minimizeBtn = document.createElement('span');
                minimizeBtn.id = 'treasure-minimize-btn';
                minimizeBtn.textContent = '−';
                minimizeBtn.className = 'mcs-tr-minimize-btn';

                buttonsSection.appendChild(minimizeBtn);

                header.appendChild(titleSection);
                header.appendChild(buttonsSection);

                const content = document.createElement('div');
                content.id = 'treasure-content';
                content.className = 'mcs-tr-content';

                const minimizedContent = document.createElement('div');
                minimizedContent.id = 'treasure-content-minimized';
                minimizedContent.className = 'mcs-tr-content-minimized mcs-hidden';

                pane.appendChild(header);
                pane.appendChild(content);
                pane.appendChild(minimizedContent);
                document.body.appendChild(pane);

                this.makeTReasureDraggable(pane, header);

                this.treasureIsMinimized = trData.minimized === true;
                if (this.treasureIsMinimized) {
                    content.classList.add('mcs-hidden');
                    minimizedContent.classList.remove('mcs-hidden');
                    pane.classList.add('mcs-width-fit', 'mcs-height-auto');
                    pane.style.minWidth = '50px';
                    pane.style.minHeight = '50px';
                    minimizeBtn.textContent = '+';
                }

                minimizeBtn.onclick = () => {
                    this.treasureIsMinimized = !this.treasureIsMinimized;
                    if (this.treasureIsMinimized) {
                        content.classList.add('mcs-hidden');
                        minimizedContent.classList.remove('mcs-hidden');
                        pane.classList.add('mcs-width-fit', 'mcs-height-auto');
                        pane.style.minWidth = '50px';
                        pane.style.minHeight = '50px';
                        minimizeBtn.textContent = '+';
                    } else {
                        content.classList.remove('mcs-hidden');
                        minimizedContent.classList.add('mcs-hidden');
                        pane.classList.remove('mcs-width-fit', 'mcs-height-auto');
                        pane.style.minWidth = '400px';
                        pane.style.minHeight = '200px';
                        minimizeBtn.textContent = '−';
                    }
                    const data = this.mcs_tr_loadData();
                    data.minimized = this.treasureIsMinimized;
                    this.mcs_tr_saveData(data);
                    this.mcs_tr_renderContent();
                };

                if (trData.position) {
                    pane.style.top = trData.position.top + 'px';
                    pane.style.left = trData.position.left + 'px';
                    pane.style.right = 'auto';
                }

                let resizeTimeout;
                this._trResizeObserver = new ResizeObserver(() => {
                    clearTimeout(resizeTimeout);
                    resizeTimeout = setTimeout(() => {
                        const rect = pane.getBoundingClientRect();
                        const data = window.lootDropsTrackerInstance.mcs_tr_loadData();
                        data.size = {
                            width: Math.round(rect.width),
                            height: Math.round(rect.height)
                        };
                        window.lootDropsTrackerInstance.mcs_tr_saveData(data);
                    }, 300);
                });
                this._trResizeObserver.observe(pane);

                this.mcs_tr_renderContent();

                this._trWsListener = this.mcs_tr_handleWebSocketMessage.bind(this);
                this._trStorageListener = this.mcs_tr_handleStorage.bind(this);
                this._trClickListener = this.mcs_tr_handlePriceToggleClick.bind(this);
                this._trFlootPricesListener = this.mcs_tr_handleFlootPricesUpdated.bind(this);
                window.addEventListener('EquipSpyWebSocketMessage', this._trWsListener);
                window.addEventListener('storage', this._trStorageListener);
                document.addEventListener('click', this._trClickListener, true);
                window.addEventListener('FlootPricesUpdated', this._trFlootPricesListener);

                this.mcs_tr_setupChestModalObserver();

                const treasureInstance = this;
                window.getTreasureUseCowbell0 = () => {
                    try {
                        const data = treasureInstance.mcs_tr_loadData();
                        return data.useCowbell0 === true;
                    } catch (e) {
                        return false;
                    }
                };
            }

            mcs_tr_setupChestModalObserver() {
                const self = this;

                const isModalContainer = (node) => {
                    if (!node.classList) return false;
                    return node.classList.contains('Modal_modalContainer__3B80m') ||
                           node.classList.contains('lll_plainPopup_root');
                };

                this._trModalObserver = new MutationObserver((mutations) => {
                    for (const mutation of mutations) {
                        if (mutation.type === 'childList') {
                            mutation.addedNodes.forEach(addedNode => {
                                if (isModalContainer(addedNode)) {
                                    setTimeout(() => self.mcs_tr_checkAndShowChestPanel(addedNode), 100);
                                }
                            });

                            mutation.removedNodes.forEach(removedNode => {
                                if (isModalContainer(removedNode)) {
                                    self.mcs_tr_removeChestSidePanel();
                                }
                            });
                        }
                    }
                });

                const rootElement = document.getElementById('root');
                if (rootElement) {
                    this._trModalObserver.observe(rootElement, { childList: true, subtree: true });

                    const trObserver = this._trModalObserver;
                    const trRoot = rootElement;
                    document.addEventListener('visibilitychange', () => {
                        if (document.hidden) {
                            trObserver.disconnect();
                        } else {
                            trObserver.observe(trRoot, { childList: true, subtree: true });
                        }
                    });
                }
            }

            mcs_tr_checkAndShowChestPanel(modalContainer) {
                let chestIconElement = null;

                const standardSelector = 'div.Modal_modal__1Jiep div.Item_iconContainer__5z7j4 svg use, div.Modal_modal__1Jiep div.Item_itemContainer__x7kH1 svg use';
                chestIconElement = modalContainer.querySelector(standardSelector);

                if (!chestIconElement) {
                    const lllChestPopup = modalContainer.querySelector('#lll_chestOpenPopup');
                    if (lllChestPopup) {
                        chestIconElement = lllChestPopup.querySelector('svg use');
                    }
                }

                if (!chestIconElement) return;

                const href = chestIconElement.getAttribute('href') || '';
                const match = href.match(/#(.+)$/);
                if (!match) return;

                const itemName = match[1];
                const chestHrid = `/items/${itemName}`;

                const openableItems = this.mcs_tr_getAllOpenableItems();
                if (!openableItems[chestHrid]) return;

                this.mcs_tr_showChestSidePanel(modalContainer, chestHrid);
            }

            mcs_tr_removeChestSidePanel() {
                const existing = document.getElementById('treasure-chest-side-panel');
                if (existing) {
                    existing.remove();
                }
            }

            mcs_tr_showChestSidePanel(modalContainer, chestHrid) {
                this.mcs_tr_removeChestSidePanel();

                const treasureData = this.mcs_tr_loadData();
                const chestData = treasureData.chests[chestHrid];
                const chestName = this.mcs_tr_formatItemName(chestHrid);

                const sidePanel = document.createElement('div');
                sidePanel.id = 'treasure-chest-side-panel';
                sidePanel.className = 'mcs-tr-side-panel';

    let html = `
        <div class="mcs-tr-side-header">
            <div class="mcs-tr-side-title">TReasure - ${chestName}</div>
            <span id="treasure-side-panel-close-btn" class="mcs-tr-close-btn" title="Close">×</span>
        </div>
                `;

                if (!chestData || chestData.last.opened === 0) {
                    html += `<div class="mcs-tr-no-data">No previous opening data</div>`;
                } else {
                    const last = chestData.last;
                    const expectedForLast = this.mcs_tr_calculateExpectedForN(chestHrid, last.opened);

                    let lastActualValue = 0;
                    let lastExpectedValue = 0;
                    for (const [itemHrid, count] of Object.entries(last.loot)) {
                        lastActualValue += count * this.mcs_tr_getItemPrice(itemHrid);
                    }
                    for (const [itemHrid, count] of Object.entries(expectedForLast)) {
                        lastExpectedValue += count * this.mcs_tr_getItemPrice(itemHrid);
                    }

                    const lastPercentDiff = this.mcs_tr_formatPercentDiff(lastActualValue, lastExpectedValue);
                    const lastDiffColor = lastActualValue >= lastExpectedValue ? '#4CAF50' : '#F44336';

                    const useAskPrice = typeof window.getFlootUseAskPrice === 'function' ? window.getFlootUseAskPrice() : false;
                    const priceColor = useAskPrice ? '#6495ED' : '#4CAF50';
                    const priceLabel = useAskPrice ? 'ask' : 'bid';

        html += `
            <div class="mcs-tr-side-section">
                <div class="mcs-tr-side-section-title">Last Opening (x${last.opened})</div>
                <div class="mcs-tr-side-value-row">
                    <span style="color: ${priceColor};">${this.mcs_tr_formatNumber(lastActualValue)} ${priceLabel}</span>
                    <span style="color: ${lastDiffColor}; font-weight: bold;">${lastPercentDiff}</span>
                </div>
            </div>
                    `;

                    html += `<div class="mcs-tr-font-9">`;
                    const lootTable = this.mcs_tr_getChestLootTable(chestHrid);
                    const allItems = lootTable ? [...new Set(lootTable.map(drop => drop.itemHrid))] : Object.keys(last.loot);

                    for (const itemHrid of allItems) {
                        const actual = last.loot[itemHrid] ?? 0;
                        const expected = expectedForLast[itemHrid] ?? 0;

                        if (actual === 0 && expected < 0.01) continue;

                        const itemIconHtml = this.mcs_tr_getItemIconHtml(itemHrid, 16);
                        const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                        const actualValue = actual * itemPrice;
                        const expectedValue = expected * itemPrice;

                        const percentDiff = this.mcs_tr_formatPercentDiff(actual, expected);
                        const diffColor = actual >= expected ? '#4CAF50' : '#F44336';

            html += `
                <div class="mcs-tr-side-item-row">
                    ${itemIconHtml}
                    <div class="mcs-tr-side-item-details">
                        <div class="mcs-tr-side-item-values">
                            <span class="mcs-tr-min-30">${this.mcs_tr_formatNumber(actual)}</span>
                            <span class="mcs-tr-min-45" style="color: ${priceColor};">${actualValue > 0 ? this.mcs_tr_formatNumber(actualValue) : ''}</span>
                            <span class="mcs-tr-font-9" style="color: ${diffColor};">(${percentDiff})</span>
                        </div>
                        <div class="mcs-tr-side-expected-row">
                            <span class="mcs-tr-min-30">${this.mcs_tr_formatExpectedCount(expected)}</span>
                            <span class="mcs-tr-min-45">${expectedValue > 0 ? this.mcs_tr_formatNumber(expectedValue) : ''}</span>
                            <span>expected</span>
                        </div>
                    </div>
                </div>
                        `;
                    }
                    html += `</div>`;

                    if (chestData.total.opened > last.opened) {
                        const totalExpected = this.mcs_tr_calculateExpectedForN(chestHrid, chestData.total.opened);
                        let totalActualValue = 0;
                        let totalExpectedValue = 0;

                        for (const [itemHrid, count] of Object.entries(chestData.total.loot)) {
                            totalActualValue += count * this.mcs_tr_getItemPrice(itemHrid);
                        }
                        for (const [itemHrid, count] of Object.entries(totalExpected)) {
                            totalExpectedValue += count * this.mcs_tr_getItemPrice(itemHrid);
                        }

                        const totalPercentDiff = this.mcs_tr_formatPercentDiff(totalActualValue, totalExpectedValue);
                        const totalDiffColor = totalActualValue >= totalExpectedValue ? '#4CAF50' : '#F44336';

            html += `
                <div class="mcs-tr-side-total">
                    <div class="mcs-tr-side-total-text">
                        Total (x${chestData.total.opened}):
                        <span style="color: ${priceColor};">${this.mcs_tr_formatNumber(totalActualValue)}</span>
                        <span style="color: ${totalDiffColor};"> (${totalPercentDiff})</span>
                    </div>
                </div>
                        `;
                    }

        html += `
            <div class="mcs-tr-side-action-row">
                <button id="treasure-view-full-stats-btn" class="mcs-tr-view-stats-btn" data-chest="${chestHrid}">View Full Stats</button>
            </div>
                    `;
                }

                sidePanel.innerHTML = html;

                const isLLLPopup = modalContainer.classList.contains('lll_plainPopup_root');
                let appendTarget = document.body;

                let lllContainer = null;
                if (isLLLPopup) {
                    lllContainer = modalContainer.querySelector('.lll_plainPopup_container');
                } else {
                    const lllRoot = document.querySelector('.lll_plainPopup_root');
                    if (lllRoot) {
                        lllContainer = lllRoot.querySelector('.lll_plainPopup_container');
                    }
                }

                if (lllContainer) {
                    const containerRect = lllContainer.getBoundingClientRect();
                    sidePanel.style.left = (containerRect.right + 8) + 'px';
                    sidePanel.style.top = containerRect.top + 'px';

                    const lllCloseBtn = lllContainer.querySelector('button.Button_button__1Fe9z');
                    if (lllCloseBtn) {
                        lllCloseBtn.addEventListener('click', () => {
                            this.mcs_tr_removeChestSidePanel();
                        });
                    }

                    const lllRoot = modalContainer.classList.contains('lll_plainPopup_root') ? modalContainer : document.querySelector('.lll_plainPopup_root');
                    if (lllRoot) {
                        const lllBackground = lllRoot.querySelector('.lll_plainPopup_background');
                        if (lllBackground) {
                            lllBackground.addEventListener('click', () => {
                                this.mcs_tr_removeChestSidePanel();
                            });
                        }
                    }
                }
                appendTarget.appendChild(sidePanel);

                const closeBtn = sidePanel.querySelector('#treasure-side-panel-close-btn');
                if (closeBtn) {
                    closeBtn.addEventListener('click', () => {
                        this.mcs_tr_removeChestSidePanel();
                    });
                }

                const viewFullStatsBtn = sidePanel.querySelector('#treasure-view-full-stats-btn');
                if (viewFullStatsBtn) {
                    viewFullStatsBtn.addEventListener('click', () => {
                        const clickedChestHrid = viewFullStatsBtn.dataset.chest;
                        this.mcs_tr_showFullStats(clickedChestHrid);
                    });
                }

                if (!lllContainer) {
                    const modal = modalContainer.querySelector('.Modal_modal__1Jiep');
                    if (modal) {
                        const positionPanel = () => {
                            const modalRect = modal.getBoundingClientRect();
                            const panelWidth = 220;
                            const gap = 8;

                            if (modalRect.right + gap + panelWidth < window.innerWidth) {
                                sidePanel.style.left = (modalRect.right + gap) + 'px';
                            } else {
                                sidePanel.style.left = Math.max(10, modalRect.left - panelWidth - gap) + 'px';
                            }
                            sidePanel.style.top = modalRect.top + 'px';
                        };

                        positionPanel();
                    }
                }
            }

            mcs_tr_showFullStats(chestHrid) {
                const pane = document.getElementById('treasure-pane');
                if (!pane) return;

                if (pane.classList.contains('mcs-hidden')) {
                    pane.classList.remove('mcs-hidden');

                    const checkbox = document.querySelector('input[type="checkbox"][data-tool-panel="treasure-pane"]');
                    if (checkbox && !checkbox.checked) {
                        checkbox.checked = true;
                    }

                    try {
                        const savedStates = ToolVisibilityStorage.get();
                        savedStates['treasure'] = true;
                        ToolVisibilityStorage.set(savedStates);
                    } catch (e) {
                    }
                }

                if (this.treasureIsMinimized) {
                    const content = document.getElementById('treasure-content');
                    const minimizedContent = document.getElementById('treasure-content-minimized');
                    const minimizeBtn = document.getElementById('treasure-minimize-btn');

                    if (content && minimizedContent) {
                        this.treasureIsMinimized = false;
                        content.classList.remove('mcs-hidden');
                        minimizedContent.classList.add('mcs-hidden');
                        pane.classList.remove('mcs-width-fit', 'mcs-height-auto');
                        pane.style.minWidth = '400px';
                        pane.style.minHeight = '200px';
                        if (minimizeBtn) {
                            minimizeBtn.textContent = '−';
                        }
                        const data = this.mcs_tr_loadData();
                        data.minimized = false;
                        this.mcs_tr_saveData(data);
                    }
                }

                if (chestHrid) {
                    this.mcs_tr_expandedChests.add(chestHrid);
                    this.mcs_tr_renderContent();

                    setTimeout(() => {
                        const chestRow = document.querySelector(`.treasure-chest-row[data-chest="${chestHrid}"]`);
                        if (chestRow) {
                            chestRow.scrollIntoView({ behavior: 'smooth', block: 'center' });
                        }
                    }, 100);
                }
            }

            makeTReasureDraggable(pane, header) {
                let startX, startY, startLeft, startTop;

                const onDragMove = (e) => {
                    const dx = e.clientX - startX;
                    const dy = e.clientY - startY;
                    pane.style.left = (startLeft + dx) + 'px';
                    pane.style.top = (startTop + dy) + 'px';
                    pane.style.right = 'auto';
                };

                const onDragUp = () => {
                    document.removeEventListener('mousemove', onDragMove);
                    document.removeEventListener('mouseup', onDragUp);
                    const rect = pane.getBoundingClientRect();
                    const data = this.mcs_tr_loadData();
                    data.position = { left: rect.left, top: rect.top };
                    this.mcs_tr_saveData(data);
                };

                header.addEventListener('mousedown', (e) => {
                    if (e.target.id === 'treasure-minimize-btn') return;
                    startX = e.clientX;
                    startY = e.clientY;
                    const rect = pane.getBoundingClientRect();
                    startLeft = rect.left;
                    startTop = rect.top;
                    e.preventDefault();
                    this._trDragMove = onDragMove;
                    this._trDragUp = onDragUp;
                    document.addEventListener('mousemove', onDragMove);
                    document.addEventListener('mouseup', onDragUp);
                });
            }

            mcs_tr_renderContent() {
                const content = document.getElementById('treasure-content');
                if (!content) return;

                const treasureData = this.mcs_tr_loadData();
                const openableItems = this.mcs_tr_getAllOpenableItems();

                const allChestHrids = Object.keys(openableItems);

                if (allChestHrids.length === 0) {
        content.innerHTML = `
            <div class="mcs-tr-loading">
                Loading chest data...<br>
                Please wait for game data to load.
            </div>
                    `;
                    return;
                }

                allChestHrids.sort((a, b) => {
                    const nameA = this.mcs_tr_formatItemName(a);
                    const nameB = this.mcs_tr_formatItemName(b);
                    return nameA.localeCompare(nameB);
                });

                const hiddenChests = this.mcs_tr_loadHiddenChests();
                const isConfigureMode = this.mcs_tr_configureMode;

                let html = '';

                if (isConfigureMode) {
        html += `
            <div class="mcs-tr-configure-header">
                <strong>Configure Mode</strong> - Click 👁 to show/hide chests
            </div>
                    `;
                }

                if (!isConfigureMode) {
                    html += this.mcs_tr_renderTokenShopSection(treasureData);
                }

                if (!isConfigureMode) {
                    html += this.mcs_tr_renderKeysSection();
                }

                for (const chestHrid of allChestHrids) {
                    const isHidden = hiddenChests.has(chestHrid);

                    if (!isConfigureMode && isHidden) {
                        continue;
                    }

                    const chestData = treasureData.chests[chestHrid] ?? { total: { opened: 0, loot: {} }, last: { opened: 0, loot: {} } };
                    const chestName = this.mcs_tr_formatItemName(chestHrid);
                    const chestIconHtml = this.mcs_tr_getItemIconHtml(chestHrid, 24);
                    const isExpanded = this.mcs_tr_expandedChests.has(chestHrid);
                    const hasBeenOpened = chestData.total.opened > 0;

                    const chestExpectedValue = this.mcs_tr_calculateChestExpectedValue(chestHrid);
                    const chestExpectedValueFormatted = this.mcs_tr_formatNumber(chestExpectedValue);

                    const totalOpened = chestData.total.opened;
                    const expectedForTotal = this.mcs_tr_calculateExpectedForN(chestHrid, totalOpened);

                    let totalActualValue = 0;
                    let totalExpectedValue = 0;

                    for (const [itemHrid, actualCount] of Object.entries(chestData.total.loot)) {
                        const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                        totalActualValue += actualCount * itemPrice;
                    }

                    for (const [itemHrid, expectedCount] of Object.entries(expectedForTotal)) {
                        const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                        totalExpectedValue += expectedCount * itemPrice;
                    }

                    const percentDiff = hasBeenOpened ? this.mcs_tr_formatPercentDiff(totalActualValue, totalExpectedValue) : '';
                    const diffColor = totalActualValue >= totalExpectedValue ? '#4CAF50' : '#F44336';

        const resetBtnHtml = (hasBeenOpened && !isConfigureMode) ? `
            <button class="treasure-reset-btn mcs-tr-reset-btn" data-chest="${chestHrid}">Reset</button>
                    ` : '';

        const visibilityBtnHtml = isConfigureMode ? `
            <button class="treasure-visibility-btn mcs-tr-visibility-btn ${isHidden ? 'mcs-tr-visibility-btn-hidden' : 'mcs-tr-visibility-btn-visible'}" data-chest="${chestHrid}" title="${isHidden ? 'Show this chest' : 'Hide this chest'}">${isHidden ? '👁‍🗨' : '👁'}</button>
                    ` : '';

                    if (isConfigureMode) {
            html += `
                <div class="treasure-chest-row mcs-tr-chest-row" data-chest="${chestHrid}" style="${isHidden ? 'background: #2a2a2a; opacity: 0.6;' : ''}">
                    <div class="treasure-chest-header mcs-tr-chest-header">
                        ${chestIconHtml}
                        <span class="mcs-tr-chest-name">${chestName} <span class="mcs-tr-chest-ev">(${chestExpectedValueFormatted})</span></span>
                        ${visibilityBtnHtml}
                    </div>
                </div>
                        `;
                        continue;
                    }

        html += `
            <div class="treasure-chest-row mcs-tr-chest-row" data-chest="${chestHrid}">
                <div class="treasure-chest-header mcs-tr-chest-header mcs-tr-chest-header-clickable">
                    <span class="treasure-expand-icon mcs-tr-expand-icon mcs-tr-expand-icon-green">
                        ${isExpanded ? '−' : '+'}
                    </span>
                    ${chestIconHtml}
                    <span class="mcs-tr-chest-name">${chestName} <span class="mcs-tr-chest-ev">(${chestExpectedValueFormatted})</span></span>
                    <span class="mcs-tr-chest-count">${hasBeenOpened ? 'x' + totalOpened : ''}</span>
                    <span style="color: ${diffColor};">${percentDiff}</span>
                    ${resetBtnHtml}
                </div>
                ${isExpanded ? this.mcs_tr_renderExpandedChest(chestHrid, chestData) : ''}
            </div>
                    `;
                }

                content.innerHTML = html;

                content.querySelectorAll('.treasure-chest-header').forEach(header => {
                    header.addEventListener('click', (e) => {
                        if (e.target.classList.contains('treasure-reset-btn')) return;
                        if (e.target.classList.contains('treasure-visibility-btn')) return;
                        if (this.mcs_tr_configureMode) return;
                        const chestHrid = header.parentElement.dataset.chest;
                        if (this.mcs_tr_expandedChests.has(chestHrid)) {
                            this.mcs_tr_expandedChests.delete(chestHrid);
                        } else {
                            this.mcs_tr_expandedChests.add(chestHrid);
                        }
                        this.mcs_tr_renderContent();
                    });
                });

                content.querySelectorAll('.treasure-reset-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const chestHrid = btn.dataset.chest;
                        if (confirm(`Reset tracking data for ${this.mcs_tr_formatItemName(chestHrid)}?`)) {
                            this.mcs_tr_resetChest(chestHrid);
                        }
                    });
                });

                content.querySelectorAll('.treasure-visibility-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const chestHrid = btn.dataset.chest;
                        this.mcs_tr_toggleChestVisibility(chestHrid);
                    });
                });

                content.querySelectorAll('.treasure-token-shop-header').forEach(header => {
                    header.addEventListener('click', () => {
                        const tokenHrid = header.dataset.token;
                        const data = this.mcs_tr_loadData();
                        const expandedSet = new Set(data.expandedTokenShops || []);
                        if (expandedSet.has(tokenHrid)) {
                            expandedSet.delete(tokenHrid);
                        } else {
                            expandedSet.add(tokenHrid);
                        }
                        data.expandedTokenShops = [...expandedSet];
                        this.mcs_tr_saveData(data);
                        this.mcs_tr_renderContent();
                    });
                });

                this.mcs_tr_renderMinimizedContent(treasureData, allChestHrids, hiddenChests);
            }

            mcs_tr_renderKeysSection() {
                const keys = [
                    { hrid: '/items/chimerical_entry_key', name: 'Chimerical Entry' },
                    { hrid: '/items/sinister_entry_key', name: 'Sinister Entry' },
                    { hrid: '/items/enchanted_entry_key', name: 'Enchanted Entry' },
                    { hrid: '/items/pirate_entry_key', name: 'Pirate Entry' },
                    { hrid: '/items/chimerical_chest_key', name: 'Chimerical Chest' },
                    { hrid: '/items/sinister_chest_key', name: 'Sinister Chest' },
                    { hrid: '/items/enchanted_chest_key', name: 'Enchanted Chest' },
                    { hrid: '/items/pirate_chest_key', name: 'Pirate Chest' }
                ];

                const priceColor = '#6495ED';

    let html = `<div class="mcs-tr-section-container">
                    <div class="mcs-tr-keys-grid">`;

                for (const key of keys) {
                    const iconHtml = this.mcs_tr_getItemIconHtml(key.hrid, 18);
                    const askPrice = typeof window.getUnitValue === 'function' ? window.getUnitValue(key.hrid, 'live', 0, 'ask') : 0;
                    const priceFormatted = this.mcs_tr_formatNumber(askPrice ?? 0);

        html += `
            <div class="mcs-tr-key-item">
                ${iconHtml}
                <div class="mcs-tr-key-details">
                    <div class="mcs-tr-key-name">${key.name}</div>
                    <div class="mcs-tr-key-price" style="color: ${priceColor};">${priceFormatted}</div>
                </div>
            </div>
                    `;
                }

                html += `</div></div>`;
                return html;
            }

            mcs_tr_renderTokenShopSection(treasureData) {
                const tokenShopData = this.mcs_tr_getTokenShopData();
                const expandedSet = new Set(treasureData.expandedTokenShops || []);
                const useMirrorValue = treasureData.useMirrorValue;

                const useAskPrice = typeof window.getFlootUseAskPrice === 'function' ? window.getFlootUseAskPrice() : false;
                const priceColor = useAskPrice ? '#6495ED' : '#4CAF50';

                let html = `<div class="mcs-tr-section-container">`;

                const tokenOrder = [
                    '/items/chimerical_token',
                    '/items/sinister_token',
                    '/items/enchanted_token',
                    '/items/pirate_token'
                ];

                for (const tokenHrid of tokenOrder) {
                    const shop = tokenShopData[tokenHrid];
                    if (!shop) continue;

                    const isExpanded = expandedSet.has(tokenHrid);
                    const tokenIconHtml = this.mcs_tr_getItemIconHtml(tokenHrid, 20);
                    const valuePerToken = this.mcs_tr_calculateTokenValue(tokenHrid);
                    const valuePerTokenFormatted = valuePerToken.toFixed(1);

                    let bestValuePerToken = 0;
                    let bestItemHrid = null;
                    for (const item of shop.items) {
                        if (item.isCapeItem) continue;
                        const itemPrice = this.mcs_tr_getItemPrice(item.hrid);
                        if (itemPrice > 0) {
                            const vpt = itemPrice / item.cost;
                            if (vpt > bestValuePerToken) {
                                bestValuePerToken = vpt;
                                bestItemHrid = item.hrid;
                            }
                        }
                    }

        html += `
            <div class="treasure-token-shop-row mcs-tr-token-row" data-token="${tokenHrid}">
                <div class="treasure-token-shop-header mcs-tr-token-header" data-token="${tokenHrid}">
                    <span class="treasure-expand-icon mcs-tr-expand-icon mcs-tr-expand-icon-purple">
                        ${isExpanded ? '−' : '+'}
                    </span>
                    ${tokenIconHtml}
                    <span class="mcs-tr-token-name">${shop.name}</span>
                    <span class="mcs-tr-token-value" style="color: ${priceColor};" title="Value per token">${valuePerTokenFormatted}/token</span>
                </div>
                ${isExpanded ? this.mcs_tr_renderTokenShopItems(tokenHrid, shop, bestItemHrid, useMirrorValue, priceColor) : ''}
            </div>
                    `;
                }

                html += `</div>`;
                return html;
            }

            mcs_tr_renderTokenShopItems(tokenHrid, shop, bestItemHrid, useMirrorValue, priceColor) {
                let html = `<div class="mcs-tr-token-items">`;

                let bestNonCapeValuePerToken = 0;
                for (const item of shop.items) {
                    if (item.isCapeItem) continue;
                    const itemPrice = this.mcs_tr_getItemPrice(item.hrid);
                    if (itemPrice > 0) {
                        const vpt = itemPrice / item.cost;
                        if (vpt > bestNonCapeValuePerToken) {
                            bestNonCapeValuePerToken = vpt;
                        }
                    }
                }

                for (const item of shop.items) {
                    const itemIconHtml = this.mcs_tr_getItemIconHtml(item.hrid, 18);

                    let itemPrice;
                    let priceSource = '';
                    let valuePerToken;

                    if (item.isCapeItem) {
                        valuePerToken = bestNonCapeValuePerToken;

                        if (useMirrorValue) {
                            itemPrice = this.mcs_tr_getMirrorPrice();
                            priceSource = ' (mirror)';
                        } else {
                            itemPrice = this.mcs_tr_getCapeItemPrice(tokenHrid, item);
                            priceSource = ' (token)';
                        }
                    } else {
                        itemPrice = this.mcs_tr_getItemPrice(item.hrid);
                        valuePerToken = itemPrice > 0 ? itemPrice / item.cost : 0;
                    }

                    const valuePerTokenFormatted = valuePerToken.toFixed(1);
                    const itemPriceFormatted = this.mcs_tr_formatNumber(itemPrice);

                    const isBestValue = item.hrid === bestItemHrid;
                    const bestBadge = isBestValue ? '<span class="mcs-tr-best-badge">★ BEST</span>' : '';

        html += `
            <div class="mcs-tr-token-item-row ${isBestValue ? 'mcs-tr-best-value' : ''}">
                ${itemIconHtml}
                <span class="mcs-tr-token-item-name">${item.name}${priceSource}${bestBadge}</span>
                <span class="mcs-tr-token-item-cost">${item.cost.toLocaleString()}</span>
                <span class="mcs-tr-token-item-price" style="color: ${priceColor};">${itemPriceFormatted}</span>
                <span class="mcs-tr-token-item-vpt">${valuePerTokenFormatted}/t</span>
            </div>
                    `;
                }

                html += `</div>`;
                return html;
            }

            mcs_tr_renderMinimizedContent(treasureData, allChestHrids, hiddenChests) {
                const minimizedContent = document.getElementById('treasure-content-minimized');
                if (!minimizedContent) return;

                let html = '';

                for (const chestHrid of allChestHrids) {
                    if (hiddenChests.has(chestHrid)) continue;

                    const chestData = treasureData.chests[chestHrid] ?? { total: { opened: 0, loot: {} }, last: { opened: 0, loot: {} } };
                    const hasBeenOpened = chestData.total.opened > 0;

                    if (!hasBeenOpened) continue;

                    const chestIconHtml = this.mcs_tr_getItemIconHtml(chestHrid, 18);
                    const totalOpened = chestData.total.opened;
                    const expectedForTotal = this.mcs_tr_calculateExpectedForN(chestHrid, totalOpened);

                    let totalActualValue = 0;
                    let totalExpectedValue = 0;

                    for (const [itemHrid, actualCount] of Object.entries(chestData.total.loot)) {
                        const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                        totalActualValue += actualCount * itemPrice;
                    }

                    for (const [itemHrid, expectedCount] of Object.entries(expectedForTotal)) {
                        const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                        totalExpectedValue += expectedCount * itemPrice;
                    }

                    const percentDiff = this.mcs_tr_formatPercentDiff(totalActualValue, totalExpectedValue);
                    const diffColor = totalActualValue >= totalExpectedValue ? '#4CAF50' : '#F44336';

        html += `
            <div class="mcs-tr-mini-item">
                ${chestIconHtml}
                <span style="color: ${diffColor}; font-weight: bold;">${percentDiff}</span>
            </div>
                    `;
                }

                minimizedContent.innerHTML = html || '<span class="mcs-tr-no-chests">No chests opened yet</span>';
            }

            mcs_tr_renderExpandedChest(chestHrid, chestData) {
                const lootTable = this.mcs_tr_getChestLootTable(chestHrid);
                if (!lootTable) {
                    return `<div class="mcs-tr-no-loot">Loot table not available</div>`;
                }

                const expectedForOne = this.mcs_tr_calculateExpectedForOne(chestHrid);
                const hasBeenOpened = chestData.total.opened > 0;

                const allItems = [...new Set(lootTable.map(drop => drop.itemHrid))];

                if (!hasBeenOpened) {
        let html = `
            <div class="mcs-tr-expanded">
                <div style="font-size: 11px;">
                    <div class="mcs-tr-col-header" style="margin-bottom: 6px;">
                        EXPECTED LOOT (x1)
                    </div>
                    ${this.mcs_tr_renderExpectedColumn(expectedForOne, allItems)}
                </div>
            </div>
                    `;
                    return html;
                }

                const expectedForTotal = this.mcs_tr_calculateExpectedForN(chestHrid, chestData.total.opened);
                const expectedForLast = this.mcs_tr_calculateExpectedForN(chestHrid, chestData.last.opened);

                let lastActualValue = 0;
                let lastExpectedValue = 0;
                for (const [itemHrid, count] of Object.entries(chestData.last.loot)) {
                    lastActualValue += count * this.mcs_tr_getItemPrice(itemHrid);
                }
                for (const [itemHrid, count] of Object.entries(expectedForLast)) {
                    lastExpectedValue += count * this.mcs_tr_getItemPrice(itemHrid);
                }
                const lastPercentDiff = this.mcs_tr_formatPercentDiff(lastActualValue, lastExpectedValue);
                const lastDiffColor = lastActualValue >= lastExpectedValue ? '#4CAF50' : '#F44336';

                let totalActualValue = 0;
                let totalExpectedValue = 0;
                for (const [itemHrid, count] of Object.entries(chestData.total.loot)) {
                    totalActualValue += count * this.mcs_tr_getItemPrice(itemHrid);
                }
                for (const [itemHrid, count] of Object.entries(expectedForTotal)) {
                    totalExpectedValue += count * this.mcs_tr_getItemPrice(itemHrid);
                }
                const totalPercentDiff = this.mcs_tr_formatPercentDiff(totalActualValue, totalExpectedValue);
                const totalDiffColor = totalActualValue >= totalExpectedValue ? '#4CAF50' : '#F44336';

                let expectedOneValue = 0;
                for (const [itemHrid, count] of Object.entries(expectedForOne)) {
                    expectedOneValue += count * this.mcs_tr_getItemPrice(itemHrid);
                }

                const useAskPrice = typeof window.getFlootUseAskPrice === 'function' ? window.getFlootUseAskPrice() : false;
                const priceColor = useAskPrice ? '#6495ED' : '#4CAF50';

    let html = `
        <div class="mcs-tr-expanded">
            <div class="mcs-tr-grid-3col">
                <div>
                    <div class="mcs-tr-col-header">
                        LAST (x${chestData.last.opened})
                    </div>
                    <div class="mcs-tr-col-value">
                        <span style="color: ${priceColor};">${this.mcs_tr_formatNumber(lastActualValue)}</span>
                        <span style="color: ${lastDiffColor};"> (${lastPercentDiff})</span>
                    </div>
                    ${this.mcs_tr_renderLootColumn(chestData.last.loot, expectedForLast, allItems)}
                </div>
                <div>
                    <div class="mcs-tr-col-header">
                        TOTAL (x${chestData.total.opened})
                    </div>
                    <div class="mcs-tr-col-value">
                        <span style="color: ${priceColor};">${this.mcs_tr_formatNumber(totalActualValue)}</span>
                        <span style="color: ${totalDiffColor};"> (${totalPercentDiff})</span>
                    </div>
                    ${this.mcs_tr_renderLootColumn(chestData.total.loot, expectedForTotal, allItems)}
                </div>
                <div>
                    <div class="mcs-tr-col-header">
                        EXPECTED (x1/x${chestData.total.opened})
                    </div>
                    <div class="mcs-tr-col-value">
                        <span style="color: ${priceColor};">${this.mcs_tr_formatNumber(expectedOneValue)}</span>
                        <span class="mcs-tr-expected-sep"> | </span>
                        <span style="color: ${priceColor};">${this.mcs_tr_formatNumber(totalExpectedValue)}</span>
                    </div>
                    ${this.mcs_tr_renderExpectedColumn(expectedForOne, allItems, chestData.total.opened)}
                </div>
            </div>
        </div>
                `;

                return html;
            }

            mcs_tr_renderLootColumn(actualLoot, expectedLoot, allItems) {
                let html = '';

                const useAskPrice = typeof window.getFlootUseAskPrice === 'function' ? window.getFlootUseAskPrice() : false;
                const priceColor = useAskPrice ? '#6495ED' : '#4CAF50';
                const priceLabel = useAskPrice ? 'ask' : 'bid';

                for (const itemHrid of allItems) {
                    const actual = actualLoot[itemHrid] ?? 0;
                    const expected = expectedLoot[itemHrid] ?? 0;
                    const itemIconHtml = this.mcs_tr_getItemIconHtml(itemHrid, 16);
                    const itemName = this.mcs_tr_formatItemName(itemHrid);

                    const percentDiff = this.mcs_tr_formatPercentDiff(actual, expected);
                    const diffColor = actual >= expected ? '#4CAF50' : '#F44336';

                    const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                    const actualValue = actual * itemPrice;
                    const valueFormatted = actualValue > 0 ? this.mcs_tr_formatNumber(actualValue) : '';

        html += `
            <div class="mcs-tr-loot-row" title="${itemName}: ${actual} actual @ ${this.mcs_tr_formatNumber(itemPrice)} ${priceLabel} = ${valueFormatted}">
                ${itemIconHtml}
                <span class="mcs-tr-loot-count">
                    ${this.mcs_tr_formatNumber(actual)}
                </span>
                <span class="mcs-tr-loot-value" style="color: ${priceColor};">
                    ${valueFormatted}
                </span>
                <span class="mcs-tr-loot-diff" style="color: ${diffColor};">(${percentDiff})</span>
            </div>
                    `;
                }

                return html;
            }

            mcs_tr_renderExpectedColumn(expectedForOne, allItems, totalOpened = 0) {
                let html = '';

                const useAskPrice = typeof window.getFlootUseAskPrice === 'function' ? window.getFlootUseAskPrice() : false;
                const priceColor = useAskPrice ? '#6495ED' : '#4CAF50';
                const priceLabel = useAskPrice ? 'ask' : 'bid';

                for (const itemHrid of allItems) {
                    const expectedOne = expectedForOne[itemHrid] ?? 0;
                    const expectedTotal = expectedOne * totalOpened;
                    const itemIconHtml = this.mcs_tr_getItemIconHtml(itemHrid, 16);
                    const itemName = this.mcs_tr_formatItemName(itemHrid);

                    const itemPrice = this.mcs_tr_getItemPrice(itemHrid);
                    const expectedValueOne = expectedOne * itemPrice;
                    const expectedValueTotal = expectedTotal * itemPrice;
                    const valueOneFormatted = expectedValueOne > 0 ? this.mcs_tr_formatNumber(expectedValueOne) : '';
                    const valueTotalFormatted = expectedValueTotal > 0 ? this.mcs_tr_formatNumber(expectedValueTotal) : '';

                    if (totalOpened > 0) {
            html += `
                <div class="mcs-tr-expected-row" title="${itemName}: x1=${this.mcs_tr_formatExpectedCount(expectedOne)}, x${totalOpened}=${this.mcs_tr_formatExpectedCount(expectedTotal)} @ ${this.mcs_tr_formatNumber(itemPrice)} ${priceLabel}">
                    ${itemIconHtml}
                    <span class="mcs-tr-expected-count">
                        ${this.mcs_tr_formatExpectedCount(expectedOne)}
                    </span>
                    <span class="mcs-tr-expected-value" style="color: ${priceColor};">
                        ${valueOneFormatted}
                    </span>
                    <span class="mcs-tr-expected-sep">|</span>
                    <span class="mcs-tr-expected-count">
                        ${this.mcs_tr_formatExpectedCount(expectedTotal)}
                    </span>
                    <span class="mcs-tr-expected-value" style="color: ${priceColor};">
                        ${valueTotalFormatted}
                    </span>
                </div>
                        `;
                    } else {
            html += `
                <div class="mcs-tr-expected-row-single" title="${itemName}: ${this.mcs_tr_formatExpectedCount(expectedOne)} expected @ ${this.mcs_tr_formatNumber(itemPrice)} ${priceLabel}">
                    ${itemIconHtml}
                    <span class="mcs-tr-expected-count-single">
                        ${this.mcs_tr_formatExpectedCount(expectedOne)}
                    </span>
                    <span class="mcs-tr-expected-value-single" style="color: ${priceColor};">
                        ${valueOneFormatted}
                    </span>
                </div>
                        `;
                    }
                }

                return html;
            }

            destroyTReasure() {
                if (this._trDragMove) {
                    document.removeEventListener('mousemove', this._trDragMove);
                    document.removeEventListener('mouseup', this._trDragUp);
                    this._trDragMove = null;
                    this._trDragUp = null;
                }
                if (this._trResizeObserver) { this._trResizeObserver.disconnect(); this._trResizeObserver = null; }
                if (this._trModalObserver) { this._trModalObserver.disconnect(); this._trModalObserver = null; }
                if (this._trWsListener) { window.removeEventListener('EquipSpyWebSocketMessage', this._trWsListener); this._trWsListener = null; }
                if (this._trStorageListener) { window.removeEventListener('storage', this._trStorageListener); this._trStorageListener = null; }
                if (this._trClickListener) { document.removeEventListener('click', this._trClickListener, true); this._trClickListener = null; }
                if (this._trFlootPricesListener) { window.removeEventListener('FlootPricesUpdated', this._trFlootPricesListener); this._trFlootPricesListener = null; }
                const pane = document.getElementById('treasure-pane');
                if (pane) pane.remove();
            }

// TReasure end

// FLoot start

            spy() {
                const spyPane = document.getElementById('equipment-spy-pane');
                if (spyPane) {
                    const isHiding = spyPane.style.display !== 'none';
                    spyPane.style.display = isHiding ? 'none' : 'flex';
                    if (isHiding) {
                        if (this.purchaseTimerIntervals) {
                            Object.keys(this.purchaseTimerIntervals).forEach(slot => {
                                clearInterval(this.purchaseTimerIntervals[slot]);
                            });
                            this.purchaseTimerIntervals = {};
                        }
                        VisibilityManager.clear('floot-coin-header');
                        VisibilityManager.clear('floot-market-refresh');
                        VisibilityManager.clear('floot-profit-cost');
                        this.coinHeaderInterval = null;
                        this.spyMarketRefreshInterval = null;
                        this.profitCostUpdateInterval = null;
                    } else {
                        if (!this.spyMarketRefreshInterval) {
                            VisibilityManager.register('floot-market-refresh', async () => {
                                if (this.spyIsInteracting) {
                                    return;
                                }
                                await this.loadSpyMarketData();
                                this.updateLastKnownPrices();
                                this.updateSpyDisplay();
                            }, 10 * 60 * 1000);
                            this.spyMarketRefreshInterval = true;
                        }
                        if (!this.coinHeaderInterval) {
                            VisibilityManager.register('floot-coin-header', () => this.updateCoinHeader(), 2000);
                            this.coinHeaderInterval = true;
                        }
                        if (!this.profitCostUpdateInterval) {
                            VisibilityManager.register('floot-profit-cost', () => {
                                if (this.spyIsInteracting) {
                                    return;
                                }
                                this.updateProfitCostDisplay();
                            }, 5000);
                            this.profitCostUpdateInterval = true;
                        }
                        this.updateLockedTimers();
                    }
                } else {
                    const hasCharacterData = CharacterDataStorage.getCurrentCharacterName();
                    const hasClientData = InitClientDataCache.get();

                    if (hasCharacterData && hasClientData) {
                        this.createEquipmentSpy();
                    } else {
                        console.warn('[Floot] Cannot create equipment spy - waiting for character/client data');
                        setTimeout(() => this.spy(), 1000);
                    }
                }
            }
            clearHistory() {
                if (!this.userName) {
                    console.warn("LDT: Cannot clear history - no username");
                    return;
                }
                if (window.confirm(`Are you sure you want to clear your session history for '${this.userName}'? Sessions involving only other players will remain. This cannot be undone.`)) {
                    let currentHistory = readSessionHistory();
                    const originalLength = currentHistory.length;
                    const filteredHistory = currentHistory.filter(s => !s.key.split('@')[0].split(',').includes(this.userName));
                    const removedCount = originalLength - filteredHistory.length;
                    if (removedCount > 0) {
                        writeSessionHistory(filteredHistory);
                        this.sessionHistory = filteredHistory;
                        currentHistory.forEach(session => {
                            if (session.key.split('@')[0].split(',').includes(this.userName)) {
                                clearSessionPriceCache(session.key);
                            }
                        });
                        this.aggregatedHistoryData = null;
                        this.updateHistoryDropdown();
                        if (!this.viewingLive) {
                            const selectedValue = this.domRefs.historySelect?.value;
                            if (selectedValue !== 'live' && selectedValue !== 'combined') {
                                if (!this.sessionHistory.some(s => s.key === selectedValue)) {
                                    if (this.domRefs.historySelect) this.domRefs.historySelect.value = 'live';
                                    this.handleHistorySelectionChange();
                                }
                            } else if (selectedValue === 'combined') {
                                this.aggregatedHistoryData = null;
                                if (!this.isHidden) this.renderCurrentView();
                                if (this.sessionHistory.length === 0) {
                                    const combinedOption = this.domRefs.historySelect?.querySelector('option[value="combined"]');
                                    if (combinedOption) combinedOption.remove();
                                    if (this.domRefs.historySelect) this.domRefs.historySelect.value = 'live';
                                    this.handleHistorySelectionChange();
                                }
                            }
                        } else {
                            if (!this.isHidden) this.renderCurrentView();
                        }
                    }
                }
            }
            handleHistorySelectionChange() {
                if (!this.domRefs.historySelect) return;
                const selectedValue = this.domRefs.historySelect.value;
                const wasViewingLive = this.viewingLive;
                const newViewingLive = (selectedValue === 'live');
                let viewCategoryChanged = false;
                if (newViewingLive !== wasViewingLive) {
                    viewCategoryChanged = true;
                }
                this.viewingLive = newViewingLive;
                this.aggregatedHistoryData = null;
                if (viewCategoryChanged) {
                    if (this.viewingLive) {
                        if (this.isLiveSessionActive) this.startTimer();
                    } else {
                        this.stopTimer();
                    }
                }
                this.updateTimerDisplay();
                if (!this.isHidden) {
                    this.renderCurrentView();
                }
            }
            isViewingCombined() {
                return !this.viewingLive && this.domRefs.historySelect?.value === 'combined';
            }
            getCurrentHistoryViewItem() {
                if (this.viewingLive || this.isViewingCombined() || !this.userName) return null;
                const selectedValue = this.domRefs.historySelect?.value;
                if (!selectedValue || selectedValue === 'live' || selectedValue === 'combined') return null;
                const session = this.sessionHistory.find(s => s.key === selectedValue);
                if (session && session.key.split('@')[0].split(',').includes(this.userName)) {
                    return session;
                }
                return null;
            }
            handleClickOutsideMenu(event) {
                if (!this.isSettingsMenuVisible) return;
                const isClickInsideMenu = this.domRefs.settingsMenu?.contains(event.target);
                const isClickOnButton = this.domRefs.settingsButton?.contains(event.target);
                if (!isClickInsideMenu && !isClickOnButton) {
                    this.hideSettingsMenu();
                }
            }
            toggleSettingsMenu() {
                if (!this.domRefs.settingsMenu) return;
                this.isSettingsMenuVisible = !this.isSettingsMenuVisible;
                this.domRefs.settingsMenu.classList.toggle('visible', this.isSettingsMenuVisible);
            }
            hideSettingsMenu() {
                if (this.domRefs.settingsMenu) {
                    this.domRefs.settingsMenu.classList.remove('visible');
                    this.isSettingsMenuVisible = false;
                }
            }
            handleStartHiddenChange() {
                if (!this.domRefs.startHiddenCheckbox) return;
                this.startHiddenEnabled = this.domRefs.startHiddenCheckbox.checked;
                flStorage.set('start_hidden', this.startHiddenEnabled);
            }
            showTooltip(event) {
                const targetButton = event.currentTarget;
                let tooltipText = targetButton.dataset.tooltip;
                if (targetButton === this.domRefs.clearButton) {
                    tooltipText = `Clear history for '${this.userName || '?'}'`;
                    targetButton.dataset.tooltip = tooltipText;
                } else if (targetButton === this.domRefs.settingsButton && !tooltipText) {
                    tooltipText = "Settings";
                    targetButton.dataset.tooltip = tooltipText;
                }
                const tooltipElement = this.domRefs.tooltip;
                if (!tooltipText || !tooltipElement) return;
                tooltipElement.textContent = tooltipText;
                const btnRect = targetButton.getBoundingClientRect();
                tooltipElement.style.visibility = 'hidden';
                tooltipElement.style.display = 'block';
                const tooltipRect = tooltipElement.getBoundingClientRect();
                tooltipElement.style.display = '';
                tooltipElement.style.visibility = '';
                let top = btnRect.top - tooltipRect.height - 6;
                let left = btnRect.left + (btnRect.width / 2) - (tooltipRect.width / 2);
                if (top < 0) top = btnRect.bottom + 6;
                if (left < 5) left = 5;
                if (left + tooltipRect.width > window.innerWidth - 5) {
                    left = window.innerWidth - tooltipRect.width - 5;
                }
                tooltipElement.style.top = `${top + window.scrollY}px`;
                tooltipElement.style.left = `${left + window.scrollX}px`;
                tooltipElement.classList.add('visible');
            }
            hideTooltip() {
                const tooltipElement = this.domRefs.tooltip;
                if (tooltipElement) tooltipElement.classList.remove('visible');
            }
            cycleSortPreference() {
                this.sortPreference = (this.sortPreference === 'count') ? 'name' : 'count';
                flStorage.set('sort', this.sortPreference);
                this.renderCurrentView();
                this.hideTooltip();
            }
            processBattleUpdate(data) {
                if (!data || typeof data !== 'object' || !Array.isArray(data.players) || !data.combatStartTime) {
                    return;
                }

                if (data.battleId && typeof data.battleId === 'number') {
                    this.encounterCount = data.battleId;
                }

                if (!this.userName) this.findUserName();
                const playerNames = data.players.map(p => p?.name).filter(Boolean);
                const combatStartTimeString = data.combatStartTime;
                const newSessionKey = generateSessionKey(playerNames, combatStartTimeString);
                if (!newSessionKey) {
                    return;
                }
                let needsRender = false;
                let statsUpdated = false;
                if (newSessionKey !== this.currentSessionKey) {
                    if (this.isLiveSessionActive) {
                        this.saveCurrentSessionToHistory(this.lastKnownActionHrid);
                    }

                    let currentHistory = readSessionHistory();
                    const existingSession = currentHistory.find(s => s.key === newSessionKey);

                    this.playerDropStats = {};
                    this.currentSessionKey = newSessionKey;
                    this.isLiveSessionActive = true;
                    this.sessionEndTime = null;
                    this.lastKnownActionHrid = null;
                    window.MCS_IN_COMBAT = true;
                    this.aggregatedHistoryData = null;

                    this.sessionStartTime = Date.now();
                    this.firstBattleSeenTime = Date.now();
                    this.lastBattleTimestamp = Date.now();
                    try {
                        this.startTime = new Date(combatStartTimeString);
                    } catch (e) {
                        this.startTime = new Date();
                    }
                    statsUpdated = this.updatePlayerStatsFromEvent(data);
                    this.updateTimerDisplay();
                    this.startTimer();
                    if (!this.viewingLive) {
                        this.viewingLive = true;
                        if (this.domRefs.historySelect) this.domRefs.historySelect.value = 'live';
                        this.handleHistorySelectionChange();
                    } else {
                        needsRender = true;
                    }
                } else if (this.isLiveSessionActive) {
                    statsUpdated = this.updatePlayerStatsFromEvent(data);

                    if (statsUpdated) {
                        this.aggregatedHistoryData = null;
                    }
                    if (!this.timerInterval) this.startTimer();
                    if (this.viewingLive && statsUpdated && !this.isHidden) {
                        needsRender = true;
                    }
                }
                if (needsRender && !this.isHidden) {
                    if (this.viewingLive || this.isViewingCombined()) {
                        this.renderCurrentView();
                    }
                }
            }
            updatePlayerStatsFromEvent(data) {
                let updated = false;
                data.players.forEach(playerInfo => {
                    if (playerInfo?.name && typeof playerInfo.totalLootMap === 'object') {
                        this.updatePlayerStats(playerInfo);
                        updated = true;
                    }
                });
                return updated;
            }
            handleSessionEnd(detail) {
                const actionHrid = detail?.actionHrid;
                if (!this.isLiveSessionActive) {
                    return;
                }
                this.sessionEndTime = Date.now();
                this.isLiveSessionActive = false;
                this.lastKnownActionHrid = actionHrid;
                window.MCS_IN_COMBAT = false;
                this.stopTimer();
                this.aggregatedHistoryData = null;
                this.saveCurrentSessionToHistory(actionHrid);
                if (this.viewingLive) {
                    if (!this.isHidden) {
                        this.renderCurrentView();
                        this.updateTimerDisplay();
                    }
                } else if (this.isViewingCombined()) {
                    if (!this.isHidden) this.renderCurrentView();
                    this.updateTimerDisplay();
                }
            }
            saveCurrentSessionToHistory(actionHrid) {
                if (!this.currentSessionKey || !this.startTime || !this.userName || !this.playerDropStats[this.userName]) {
                    return;
                }
                const userItems = this.playerDropStats[this.userName].items || {};
                if (Object.keys(userItems).length === 0) {
                    return;
                }
                const endTime = this.sessionEndTime || Date.now();
                const duration = Math.max(0, endTime - this.startTime.getTime());
                if (duration < 5000 && !actionHrid?.includes('tutorial')) {
                    return;
                }
                let currentHistory = readSessionHistory();
                const existingSessionIndex = currentHistory.findIndex(s => s.key === this.currentSessionKey);
                if (existingSessionIndex === -1) {
                    try {
                        const sessionLocation = formatLocationName(actionHrid);
                        const statsToSave = JSON.parse(JSON.stringify(this.playerDropStats));
                        const completedSession = {
                            key: this.currentSessionKey,
                            start: this.startTime.getTime(),
                            end: endTime,
                            duration: duration,
                            location: sessionLocation,
                            stats: statsToSave,
                            encounterCount: this.encounterCount || 0
                        };
                        currentHistory.push(completedSession);
                        currentHistory.sort((a, b) => b.start - a.start);
                        while (currentHistory.length > CONFIG.HISTORY_LIMIT) {
                            currentHistory.pop();
                        }
                        writeSessionHistory(currentHistory);
                        this.sessionHistory = currentHistory;
                        this.updateHistoryDropdown();
                    } catch (e) {
                        console.error("LDT: Error creating or saving session JSON", e);
                    }
                } else {
                    try {
                        const statsToSave = JSON.parse(JSON.stringify(this.playerDropStats));
                        currentHistory[existingSessionIndex].end = endTime;
                        currentHistory[existingSessionIndex].duration = duration;
                        currentHistory[existingSessionIndex].stats = statsToSave;
                        currentHistory[existingSessionIndex].encounterCount = this.encounterCount || 0;
                        writeSessionHistory(currentHistory);
                        this.sessionHistory = currentHistory;
                    } catch (e) {
                        console.error("LDT: Error updating session JSON", e);
                    }
                }
            }
            handleStorageChange(event) {
                if (this.ignoreNextStorageEvent) {
                    this.ignoreNextStorageEvent = false;
                    return;
                }
                if (event.key === this.spyConfig?.STORAGE_LOCKED_KEY) {
                    return;
                }
                if (event.key === CONFIG.STORAGE.sessionHistory && event.newValue !== null) {
                    const oldSelectedKey = this.domRefs.historySelect?.value;
                    this.sessionHistory = readSessionHistory();
                    this.aggregatedHistoryData = null;
                    this.updateHistoryDropdown();
                    if (!this.viewingLive && !this.isViewingCombined()) {
                        const currentViewStillExists = this.sessionHistory.some(s => s.key === oldSelectedKey);
                        if (!currentViewStillExists) {
                            if (this.domRefs.historySelect) this.domRefs.historySelect.value = 'live';
                            this.handleHistorySelectionChange();
                        }
                    } else if (this.isViewingCombined()) {
                        if (!this.isHidden) this.renderCurrentView();
                        this.updateTimerDisplay();
                    }
                }
            }
            startTimer() {
                this.stopTimer();
                if (this.startTime && !this.isLiveSessionActive && !this.sessionEndTime) {
                    console.warn('[Timer] startTimer called in zombie state - cleaning up');
                    this.startTime = null;
                }
                if (!this.startTime || !this.viewingLive || !this.isLiveSessionActive) {
                    this.updateTimerDisplay();
                    return;
                }
                this.updateTimerDisplay();
                VisibilityManager.register('floot-timer', () => {
                    if (this.startTime && this.viewingLive && this.isLiveSessionActive) {
                        this.updateTimerDisplay();
                    } else {
                        this.stopTimer();
                        this.updateTimerDisplay();
                    }
                }, 1000);
            }
            stopTimer() {
                VisibilityManager.clear('floot-timer');
                this.timerInterval = null;
            }
            updateTimerDisplay() {
                if (this.isHidden && !this.domRefs.timerDisplayHidden) return;
                if (!this.isHidden && !this.domRefs.timerDisplay) return;
                const selectedValue = this.domRefs.historySelect?.value;
                let timerText = '--:--:--';
                if (this.viewingLive || selectedValue === 'live') {
                    if (!this.startTime) {
                        timerText = '--:--:--';
                    } else if (!this.isLiveSessionActive && this.sessionEndTime) {
                        const duration = this.sessionEndTime - this.startTime.getTime();
                        timerText = `(${this.formatElapsedTime(duration)}) Ended`;
                    } else if (this.isLiveSessionActive) {
                        const elapsedMs = Date.now() - this.startTime.getTime();
                        timerText = this.formatElapsedTime(elapsedMs);
                    } else {
                        console.warn('[Timer] Detected zombie state - resetting startTime');
                        this.startTime = null;
                        this.sessionEndTime = null;
                        timerText = '--:--:--';
                    }
                } else if (selectedValue === 'combined') {
                    if (this.aggregatedHistoryData === null) this.aggregateSessionHistory();
                    timerText = `(Σ ${this.formatElapsedTime(this.aggregatedHistoryDuration)})`;
                } else {
                    const selectedSession = this.getCurrentHistoryViewItem();
                    if (selectedSession) {
                        timerText = `(${this.formatElapsedTime(selectedSession.duration)})`;
                    } else {
                        timerText = '??:??:??';
                    }
                }
                let displayText = timerText;
                if (this.isLiveSessionActive && this.sessionStartTime && (this.viewingLive || selectedValue === 'live' || !selectedValue)) {
                    const eph = this.calculateEPH();
                    displayText = `${timerText} | ${eph} EPH`;
                } else if (selectedValue && selectedValue !== 'live' && selectedValue !== 'combined') {
                    const selectedSession = this.getCurrentHistoryViewItem();
                    if (selectedSession && selectedSession.encounterCount && selectedSession.duration) {
                        const elapsedSeconds = selectedSession.duration / 1000;
                        if (elapsedSeconds > 0) {
                            const eph = (selectedSession.encounterCount / elapsedSeconds) * 3600;
                            displayText = `${timerText} | ${eph.toFixed(2)} EPH`;
                        }
                    }
                }
                if (this.domRefs.timerDisplay) {
                    this.domRefs.timerDisplay.textContent = displayText;
                }
                if (this.domRefs.timerDisplayHidden) {
                    this.domRefs.timerDisplayHidden.textContent = displayText;
                }
            }
            formatElapsedTime(ms) {
                return mcsFormatDuration((ms || 0) / 1000, 'elapsed');
            }
            calculateEPH() {
                if (!this.startTime || this.encounterCount === 0) {
                    return '0.00';
                }
                const now = Date.now();
                const elapsedMs = now - this.startTime.getTime();
                const elapsedSeconds = elapsedMs / 1000;
                if (elapsedSeconds === 0) {
                    return '0.00';
                }
                const eph = (this.encounterCount / elapsedSeconds) * 3600;
                return eph.toFixed(2);
            }
            startMove(event) {
                if (this.isMoving) return;
                this.isMoving = true;
                const panelRect = this.domRefs.panel.getBoundingClientRect();
                this.moveOffset.y = event.clientY - panelRect.top;
                const winWidth = window.innerWidth;
                const winHeight = window.innerHeight;
                const snapThreshold = 5;
                let wasSnapped = false;
                let unsnapRight = this.initialRight;
                if (panelRect.right >= winWidth - snapThreshold) {
                    wasSnapped = true;
                    unsnapRight = 20;
                }
                else if (panelRect.left <= snapThreshold) {
                    wasSnapped = true;
                    const newLeft = 20;
                    unsnapRight = winWidth - newLeft - panelRect.width;
                }
                if (panelRect.top <= snapThreshold) {
                    wasSnapped = true;
                    this.domRefs.panel.style.top = '20px';
                    this.moveOffset.y = event.clientY - 20;
                }
                else if (panelRect.bottom >= winHeight - snapThreshold) {
                    wasSnapped = true;
                    const newTop = winHeight - panelRect.height - 20;
                    this.domRefs.panel.style.top = newTop + 'px';
                    this.moveOffset.y = event.clientY - newTop;
                }
                if (wasSnapped) {
                    this.domRefs.panel.style.right = unsnapRight + 'px';
                    this.domRefs.panel.style.left = 'auto';
                }
                this.initialRight = parseFloat(this.domRefs.panel.style.right || CONFIG.DEFAULT_POS.right);
                this.initialClientX = event.clientX;
                this.domRefs.panel.style.cursor = 'grabbing';
                this.domRefs.panel.style.transition = 'none';
                this.domRefs.panel.style.opacity = '0.88';
                this.domRefs.panel.style.willChange = 'top, right';
                event.preventDefault();
                event.stopPropagation();
                this.hideSettingsMenu();
                if (!this._boundMovePanel) {
                    this._boundMovePanel = this.movePanel.bind(this);
                    this._boundEndMove = this.endMove.bind(this);
                }
                document.addEventListener('mousemove', this._boundMovePanel, { passive: true });
                document.addEventListener('mouseup', this._boundEndMove);
            }
            movePanel(event) {
                if (!this.isMoving) return;
                const container = this.domRefs.panel;
                let newTop = event.clientY - this.moveOffset.y;
                const dx = event.clientX - this.initialClientX;
                let newRight = this.initialRight - dx;
                const winWidth = window.innerWidth;
                const winHeight = window.innerHeight;
                const rect = container.getBoundingClientRect();
                const overlayWidth = rect.width;
                const overlayHeight = rect.height;
                newTop = Math.max(0, Math.min(newTop, Math.max(0, winHeight - overlayHeight)));
                newRight = Math.max(0, Math.min(newRight, Math.max(0, winWidth - overlayWidth)));
                container.style.top = `${newTop}px`;
                container.style.right = `${newRight}px`;
                container.style.left = 'auto';
            }
            endMove() {
                if (!this.isMoving) return;
                this.isMoving = false;
                document.removeEventListener('mousemove', this._boundMovePanel);
                document.removeEventListener('mouseup', this._boundEndMove);
                this.domRefs.panel.style.cursor = '';
                this.domRefs.panel.style.transition = '';
                this.domRefs.panel.style.opacity = '';
                this.domRefs.panel.style.willChange = '';
                const finalTop = this.domRefs.panel.style.top;
                const finalRight = this.domRefs.panel.style.right;
                if (finalTop && finalTop.endsWith('px') && finalRight && finalRight.endsWith('px')) {
                    const position = { top: finalTop, right: finalRight };
                    flStorage.set('position', position);
                } else {
                    console.warn("LDT: Invalid final position values not saved.", { top: finalTop, right: finalRight });
                }
            }
            findUserName() {
                if (this.userName) return;
                const attemptFind = () => {
                    const nameDiv = document.querySelector(CONFIG.USERNAME_SELECTOR);
                    if (nameDiv && nameDiv.dataset.name) {
                        this.userName = nameDiv.dataset.name;
                        if (this.spyConfig) {
                            this.loadSpySettings();
                        }
                        this.updateHistoryDropdown();
                        if (!this.isHidden) this.renderCurrentView();
                        this.aggregateHistoryData = null;
                    } else {
                        setTimeout(attemptFind, 2000);
                    }
                };
                attemptFind();
            }
            extractItemDetailMapFromPage() {
                try {
                    const data = InitClientDataCache.get();
                    if (data && data.itemDetailMap) {
                        const bridge = document.getElementById('equipspy-data-bridge');
                        if (bridge) {
                            bridge.setAttribute('data-item-detail-map', JSON.stringify(data.itemDetailMap));
                        } else {
                            console.error('[EquipSpy] Bridge element not found');
                        }
                    }
                } catch (e) {
                    console.error('[EquipSpy] Error extracting itemDetailMap:', e);
                }
            }
            setupFeedListener() {
                if (window._lootDropsMessageHooked) {
                    return;
                }
                try {
                    const script = document.createElement('script');
        script.textContent = `

(function() {
    if (window._lootDropsMessageHooked) return;
    window._lootDropsMessageHooked = true;
    console.log('[MCS] WebSocket connected');

    if (!window.CharacterDataStorage) {
        window.CharacterDataStorage = {
            getCurrentCharacterName() {
                if (window.MCS_CHARACTER_DATA_CACHE?.character?.name) {
                    return window.MCS_CHARACTER_DATA_CACHE.character.name;
                }
                return null;
            },

            get(characterName) {
                return window.MCS_CHARACTER_DATA_CACHE || null;
            },

            set(value, characterName) {
                if (typeof value === 'string') {
                    try {
                        window.MCS_CHARACTER_DATA_CACHE = JSON.parse(value);
                    } catch (e) {
                        console.error('[CharacterDataStorage] Error parsing data:', e);
                    }
                } else if (value && typeof value === 'object') {
                    window.MCS_CHARACTER_DATA_CACHE = value;
                }
            },

            getParsed(characterName) {
                return window.MCS_CHARACTER_DATA_CACHE || null;
            },

            setParsed(obj, characterName) {
                window.MCS_CHARACTER_DATA_CACHE = obj;
            }
        };
    }
    const CharacterDataStorage = window.CharacterDataStorage;

    function updateCacheSynchronously(parsed) {
        try {
            if (parsed?.type === 'init_character_data') {
                if (parsed.characterItems) {
                    CharacterDataStorage.set(parsed);
                    const bridge = document.getElementById('equipspy-data-bridge');
                    if (bridge) {
                        try {
                            bridge.setAttribute('data-character-items', JSON.stringify(parsed.characterItems));
                            bridge.setAttribute('data-character-full', JSON.stringify(parsed));
                            bridge.setAttribute('data-character-name', parsed.character?.name || '');
                        } catch (e) {
                            console.error('[EquipSpy] Error setting bridge attribute:', e);
                        }
                    }
                    if (window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.spyCharacterItems = parsed.characterItems;
                    }
                }
                if (parsed.myMarketListings) {
                    if (window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.myMarketListings = parsed.myMarketListings;
                    }
                }
            }
        } catch (e) {
            console.error('[LootDrops] Error in synchronous cache update:', e);
        }
    }

    function processMessage(parsed) {
        try {
            const tabHidden = document.hidden;

            let marketListingsUpdated = false;
            let updatedListings = null;
            if (parsed?.type === 'market_listings_updated' && parsed.endMarketListings) {
                let listings = window.lootDropsTrackerInstance?.myMarketListings;
                if (!listings) {
                    const cachedData = CharacterDataStorage.get();
                    listings = cachedData?.myMarketListings ?? [];
                }
                listings = [...listings];

                for (const updatedListing of parsed.endMarketListings) {
                    const existingIndex = listings.findIndex(l => l.id === updatedListing.id);
                    const isCancelled = updatedListing.status === '/market_listing_status/cancelled';
                    const isFullyFilled = updatedListing.filledQuantity >= updatedListing.orderQuantity;

                    if (isCancelled || isFullyFilled) {
                        if (existingIndex >= 0) {
                            listings.splice(existingIndex, 1);
                        }
                    } else if (existingIndex >= 0) {
                        listings[existingIndex] = updatedListing;
                    } else {
                        listings.push(updatedListing);
                    }
                }

                if (window.lootDropsTrackerInstance) {
                    window.lootDropsTrackerInstance.myMarketListings = listings;
                }

                const cachedData = CharacterDataStorage.get();
                if (cachedData) {
                    cachedData.myMarketListings = listings;
                }

                if (parsed.endCharacterItems && Array.isArray(parsed.endCharacterItems)) {
                    itemsToUpdate = parsed.endCharacterItems;
                    if (window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.spyCharacterItems = itemsToUpdate;
                    }
                    const cachedData2 = CharacterDataStorage.get();
                    if (cachedData2) {
                        cachedData2.characterItems = itemsToUpdate;
                    }
                }

                marketListingsUpdated = true;
                updatedListings = listings;
            }

            let coinCount = null;
            if (parsed?.type === 'action_completed') {
                if (parsed.endCharacterItems && Array.isArray(parsed.endCharacterItems)) {
                    const coinItem = parsed.endCharacterItems.find(item => item.itemHrid === '/items/coin');
                    if (coinItem) {
                        coinCount = coinItem.count;
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData && cachedData.characterItems) {
                            const storedCoin = cachedData.characterItems.find(
                                item => item.itemHrid === '/items/coin'
                            );
                            if (storedCoin) {
                                storedCoin.count = coinItem.count;
                            }
                        }
                    }
                }
            }

            let itemsToUpdate = null;
            if (parsed && typeof parsed === 'object') {
                if (parsed.characterItems && Array.isArray(parsed.characterItems)) {
                    itemsToUpdate = parsed.characterItems;
                } else if (parsed.items && Array.isArray(parsed.items)) {
                    itemsToUpdate = parsed.items;
                } else if (parsed.characterItemsMap && typeof parsed.characterItemsMap === 'object') {
                    itemsToUpdate = Object.values(parsed.characterItemsMap);
                } else if (parsed.character?.items && Array.isArray(parsed.character.items)) {
                    itemsToUpdate = parsed.character.items;
                }
                if (itemsToUpdate && itemsToUpdate.length > 0) {
                    if (window.lootDropsTrackerInstance) {
                        window.lootDropsTrackerInstance.spyCharacterItems = itemsToUpdate;
                    }
                }

                if (parsed.type && (
                    parsed.type === 'item_update' ||
                    parsed.type === 'inventory_update' ||
                    parsed.type === 'character_update' ||
                    parsed.type === 'coins_update' ||
                    parsed.type === 'actions_updated'
                )) {
                    const searchForCoins = (obj, depth = 0) => {
                        if (depth > 5) return null;
                        for (const key in obj) {
                            const val = obj[key];
                            if (typeof val === 'object' && val !== null) {
                                if (val.itemHrid === '/items/coin' && typeof val.count === 'number') {
                                    return val.count;
                                }
                                const result = searchForCoins(val, depth + 1);
                                if (result !== null) return result;
                            }
                        }
                        return null;
                    };

                    const coins = searchForCoins(parsed);
                    if (coins !== null) {
                        if (window.lootDropsTrackerInstance && window.lootDropsTrackerInstance.spyCharacterItems) {
                            let ci = window.lootDropsTrackerInstance.spyCharacterItems.find(
                                item => item.itemHrid === '/items/coin'
                            );
                            if (ci) {
                                ci.count = coins;
                            } else {
                                window.lootDropsTrackerInstance.spyCharacterItems.push({
                                    itemHrid: '/items/coin',
                                    count: coins
                                });
                            }
                        }
                    }

                    const needsCacheUpdate = coins !== null || (itemsToUpdate && itemsToUpdate.length > 0);
                    if (needsCacheUpdate) {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData && cachedData.characterItems) {
                            if (itemsToUpdate && itemsToUpdate.length > 0) {
                                cachedData.characterItems = itemsToUpdate;

                                const crackInventory = {};
                                itemsToUpdate.forEach(item => {
                                    if (item.itemLocationHrid === '/item_locations/inventory' && item.itemHrid) {
                                        const itemName = item.itemHrid.toLowerCase();
                                        const isConsumable = itemName.includes('coffee') || itemName.includes('donut') ||
                                                           itemName.includes('cupcake') || itemName.includes('cake') ||
                                                           itemName.includes('gummy') || itemName.includes('yogurt');
                                        if (isConsumable) {
                                            crackInventory[item.itemHrid] = item.count;
                                        }
                                    }
                                });
                                if (Object.keys(crackInventory).length > 0) {
                                    const crStorage = createModuleStorage('CR');
                                    crStorage.set('consumable_inventory', crackInventory);
                                }

                                if (window.lootDropsTrackerInstance) {
                                    window.lootDropsTrackerInstance.spyCharacterItems = itemsToUpdate;
                                }
                            } else if (coins !== null) {
                                let storedCoin = cachedData.characterItems.find(
                                    item => item.itemHrid === '/items/coin'
                                );
                                if (storedCoin) {
                                    storedCoin.count = coins;
                                } else {
                                    cachedData.characterItems.push({
                                        itemHrid: '/items/coin',
                                        itemLocationHrid: '/item_locations/inventory',
                                        count: coins
                                    });
                                }
                            }
                        }
                    }
                }
            }

            if (parsed?.type === 'init_character_data' && parsed.characterItems) {
                window.dispatchEvent(new CustomEvent('LootTrackerCharacterData', { detail: parsed }));
            }
            if (parsed?.type === 'init_client_data' && parsed.itemDetailMap) {
                window.dispatchEvent(new CustomEvent('LootTrackerClientData', { detail: parsed }));
            }

            if (tabHidden) {
                if (parsed?.type === 'init_character_data' || parsed?.type === 'init_client_data') {
                    window._mcsPendingInitMessages = window._mcsPendingInitMessages || [];
                    window._mcsPendingInitMessages.push(parsed);
                }
                return;
            }

            if (marketListingsUpdated) {
                window.dispatchEvent(new CustomEvent('EquipSpyWebSocketMessage', {
                    detail: { type: 'market_listings_updated', myMarketListings: updatedListings }
                }));
            }

            if (coinCount !== null) {
                window.dispatchEvent(new CustomEvent('EquipSpyCoinUpdate', {
                    detail: { count: coinCount }
                }));
            }

            if (parsed?.type === 'new_battle' &&
                Array.isArray(parsed.players) &&
                parsed.combatStartTime) {
                window.dispatchEvent(
                    new CustomEvent('LootTrackerBattle', {
                        detail: parsed
                    })
                );
            }

            if (itemsToUpdate && itemsToUpdate.length > 0) {
                const bridge = document.getElementById('equipspy-data-bridge');
                if (bridge) {
                    try {
                        bridge.setAttribute('data-character-items', JSON.stringify(itemsToUpdate));
                    } catch (e) { /* stringify may fail on circular refs */ }
                }
            }

            if (parsed && typeof parsed === 'object' && parsed.type && (
                parsed.type === 'item_update' ||
                parsed.type === 'inventory_update' ||
                parsed.type === 'character_update' ||
                parsed.type === 'coins_update' ||
                parsed.type === 'actions_updated'
            )) {
                const cachedData = CharacterDataStorage.get();
                const coins = cachedData?.characterItems?.find(i => i.itemHrid === '/items/coin')?.count;
                if (coins !== null || (itemsToUpdate && itemsToUpdate.length > 0)) {
                    window.dispatchEvent(new CustomEvent('InventoryDataUpdated', {
                        detail: {
                            items: itemsToUpdate || window.lootDropsTrackerInstance?.spyCharacterItems || [],
                            type: parsed.type
                        }
                    }));
                }
            }

            if (parsed?.type) {
                window.dispatchEvent(new CustomEvent('EquipSpyWebSocketMessage', {
                    detail: parsed
                }));
            }

            let combatEnded = false;
            let completedActionHrid = null;
            if (parsed?.type === 'actions_updated' &&
                Array.isArray(parsed.endCharacterActions)) {
                const completedCombatAction = parsed.endCharacterActions.find(
                    action => action?.actionHrid?.startsWith('/actions/combat/') &&
                            action.isDone === true &&
                            action.currentCount > 0
                );
                if (completedCombatAction) {
                    combatEnded = true;
                    completedActionHrid = completedCombatAction.actionHrid;
                }
            } else if (parsed?.type === 'cancel_character_action' &&
                       parsed?.cancelCharacterActionData?.characterActionId) {
                combatEnded = true;
                completedActionHrid = parsed?.cancelCharacterActionData?.actionHrid || null;
            }
            if (combatEnded) {
                window.dispatchEvent(
                    new CustomEvent('LootTrackerCombatEnded', {
                        detail: { actionHrid: completedActionHrid }
                    })
                );
            }
        } catch (e) {
            if (!(e instanceof SyntaxError)) {
                console.error('[LootDrops] Error processing message:', e);
            }
        }
    }

    const originalDescriptor = Object.getOwnPropertyDescriptor(
        MessageEvent.prototype,
        'data'
    );
    const originalGetter = originalDescriptor.get;

    Object.defineProperty(MessageEvent.prototype, 'data', {
        get: function() {
            const data = originalGetter.call(this);
            const socket = this.currentTarget;
            if (socket instanceof WebSocket &&
                socket.url &&
                socket.url.includes('milkywayidle.com')) {
                if (window._MCS_DISABLED) return data;
                if (typeof data === 'string' && data.startsWith('{')) {
                    try {
                        const parsed = JSON.parse(data);
                        if (parsed && parsed.type) {
                            updateCacheSynchronously(parsed);
                            queueMicrotask(() => processMessage(parsed));
                        }
                    } catch (e) {
                    }
                }
            }
            return data;
        },
        configurable: true
    });

    let recoveryCheckCount = 0;
    const recoveryInterval = setInterval(() => {
        recoveryCheckCount++;
        if (recoveryCheckCount > 16) {
            clearInterval(recoveryInterval);
            return;
        }
        if (window.MCS_CHARACTER_DATA_CACHE) {
            clearInterval(recoveryInterval);
            return;
        }
        const nameEl = document.querySelector('[data-name]');
        if (nameEl && nameEl.getAttribute('data-name')) {
            clearInterval(recoveryInterval);
            const reloadKey = 'mcs_init_recovery_reload';
            if (!sessionStorage.getItem(reloadKey)) {
                sessionStorage.setItem(reloadKey, '1');
                console.log('[MCS] Missed init_character_data (late injection after update) — reloading once to recover.');
                window.location.reload();
            }
        }
    }, 500);

    document.addEventListener('visibilitychange', () => {
        if (!document.hidden && window._mcsPendingInitMessages?.length) {
            const pending = window._mcsPendingInitMessages;
            window._mcsPendingInitMessages = [];
            const lastByType = new Map();
            pending.forEach(msg => lastByType.set(msg.type, msg));
            const deduped = Array.from(lastByType.values());
            deduped.forEach((msg, i) => {
                setTimeout(() => {
                    window.dispatchEvent(new CustomEvent('EquipSpyWebSocketMessage', { detail: msg }));
                }, i * 50);
            });
        }
    });
})();
            `;
                    (document.head || document.documentElement).appendChild(script);
                    setTimeout(() => {
                        if (script.parentNode) {
                            script.parentNode.removeChild(script);
                        }
                    }, 100);
                } catch (error) {
                    console.error('[LootDrops] Failed to setup message interceptor:', error);
                }
            }

// FLoot end

        }

        // Class end

// Lucky start

        const LuckyGameData = {
            itemNames: {},
            itemPrices: {},
            monsterNames: {},
            mapNames: {},
            mapData: {},
            playerStats: {},
            currentMapHrid: null,
            currentDifficultyTier: 0,
            hasReceivedFirstBattle: false
        };

        const FlootData = {
            getBattleCount() {
                if (!window.lootDropsTrackerInstance) return 0;
                const instance = window.lootDropsTrackerInstance;

                const storedCount = instance.encounterCount || 0;

                return storedCount > 0 ? storedCount : 1;
            },

            getEPH() {
                if (!window.lootDropsTrackerInstance) return 0;
                const eph = window.lootDropsTrackerInstance.calculateEPH();
                return parseFloat(eph) || 0;
            },

            getSessionTime() {
                if (!window.lootDropsTrackerInstance) return 0;
                if (!window.lootDropsTrackerInstance.startTime) return 0;
                const startTime = window.lootDropsTrackerInstance.startTime;
                const elapsedMs = Date.now() - startTime.getTime();
                return elapsedMs / 1000;
            },

            getPlayerDrops(playerName) {
                if (!window.lootDropsTrackerInstance) return {};
                const playerStats = window.lootDropsTrackerInstance.playerDropStats;
                if (!playerStats || !playerStats[playerName]) return {};
                return playerStats[playerName].items || {};
            },

            getCurrentPlayerName() {
                if (!window.lootDropsTrackerInstance) return null;
                return window.lootDropsTrackerInstance.userName;
            },

            getAllPlayerNames() {
                if (!window.lootDropsTrackerInstance) return [];
                const playerStats = window.lootDropsTrackerInstance.playerDropStats;
                if (!playerStats) return [];
                return Object.keys(playerStats);
            },

            getPartySize() {
                return this.getAllPlayerNames().length;
            }
        };

        const Complex = new class {
            add = (a, b) => [a[0] + b[0], a[1] + b[1]]
            sub = (a, b) => [a[0] - b[0], a[1] - b[1]]
            mul = (a, b) => [a[0] * b[0] - a[1] * b[1], a[0] * b[1] + a[1] * b[0]]
            mulRe = (a, x) => [a[0] * x, a[1] * x]
            div = (a, b) => {
                const mag = b[0] * b[0] + b[1] * b[1];
                return [(a[0] * b[0] + a[1] * b[1]) / mag, (a[1] * b[0] - a[0] * b[1]) / mag];
            }
            abs = (c) => Math.sqrt(c[0] * c[0] + c[1] * c[1])
            pow = (c, x) => {
                const arg = Math.atan2(c[1], c[0]) * x;
                const mag = Math.pow(c[0] * c[0] + c[1] * c[1], x / 2);
                return [mag * Math.cos(arg), mag * Math.sin(arg)];
            }
        };

        const ComplexVector = new class {
            constantRe(n, a) {
                const v = Array(n);
                for (let i = 0; i < n; i += 4) {
                    v[i] = [a, 0]; v[i + 1] = [a, 0]; v[i + 2] = [a, 0]; v[i + 3] = [a, 0];
                }
                return v;
            }
            mul(a, b) {
                const n = a.length, z = Array(n);
                for (let i = 0; i < n;) {
                    z[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                    z[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                    z[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                    z[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                }
                return z;
            }
            mulEq(a, b) {
                const n = a.length;
                for (let i = 0; i < n;) {
                    a[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                    a[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                    a[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                    a[i] = [a[i][0] * b[i][0] - a[i][1] * b[i][1], a[i][0] * b[i][1] + a[i][1] * b[i][0]]; ++i;
                }
                return a;
            }
            mulReEq(a, x) {
                const n = a.length;
                for (let i = 0; i < n;) {
                    a[i][0] *= x; a[i][1] *= x; ++i;
                    a[i][0] *= x; a[i][1] *= x; ++i;
                    a[i][0] *= x; a[i][1] *= x; ++i;
                    a[i][0] *= x; a[i][1] *= x; ++i;
                }
                return a;
            }
            addEq(a, b) {
                const n = a.length;
                for (let i = 0; i < n;) {
                    a[i][0] += b[i][0]; a[i][1] += b[i][1]; ++i;
                    a[i][0] += b[i][0]; a[i][1] += b[i][1]; ++i;
                    a[i][0] += b[i][0]; a[i][1] += b[i][1]; ++i;
                    a[i][0] += b[i][0]; a[i][1] += b[i][1]; ++i;
                }
                return a;
            }
            addMulEq(dest, a, b) {
                const n = dest.length;
                for (let i = 0; i < n;) {
                    dest[i][0] += a[i][0] * b[i][0] - a[i][1] * b[i][1]; dest[i][1] += a[i][0] * b[i][1] + a[i][1] * b[i][0]; ++i;
                    dest[i][0] += a[i][0] * b[i][0] - a[i][1] * b[i][1]; dest[i][1] += a[i][0] * b[i][1] + a[i][1] * b[i][0]; ++i;
                    dest[i][0] += a[i][0] * b[i][0] - a[i][1] * b[i][1]; dest[i][1] += a[i][0] * b[i][1] + a[i][1] * b[i][0]; ++i;
                    dest[i][0] += a[i][0] * b[i][0] - a[i][1] * b[i][1]; dest[i][1] += a[i][0] * b[i][1] + a[i][1] * b[i][0]; ++i;
                }
                return a;
            }
        };

        const CDFUtils = new class {
            #inf = 0x3FFFFFFE;
            floor(n) { return n > this.#inf || n < -this.#inf ? Math.floor(n) : ((n + this.#inf) | 0) - this.#inf; }
            round(n) { return this.floor(n + 0.5); }

            binarySearch(f, l, r, dest, maxIter = 60) {
                for (let i = 0; i < maxIter; ++i) {
                    let mid = (l + r) / 2;
                    if (f(mid) < dest) l = mid;
                    else r = mid;
                }
                return (l + r) / 2;
            }
        };

        const SimpleFFT = new class {
            #cache = {};

            init(n) {
                if (this.#cache[n]) return;
                this.#cache[n] = {
                    cos: new Array(n),
                    sin: new Array(n)
                };
                for (let i = 0; i < n; i++) {
                    const angle = -2 * Math.PI * i / n;
                    this.#cache[n].cos[i] = Math.cos(angle);
                    this.#cache[n].sin[i] = Math.sin(angle);
                }
            }

            fft(re, im) {
                const n = re.length;
                if (n <= 1) return;

                for (let i = 0, j = 0; i < n; i++) {
                    if (i < j) {
                        [re[i], re[j]] = [re[j], re[i]];
                        [im[i], im[j]] = [im[j], im[i]];
                    }
                    let k = n >> 1;
                    while (k > 0 && k <= j) {
                        j -= k;
                        k >>= 1;
                    }
                    j += k;
                }

                for (let len = 2; len <= n; len <<= 1) {
                    const halfLen = len >> 1;
                    const angle = -2 * Math.PI / len;
                    const wlenRe = Math.cos(angle);
                    const wlenIm = Math.sin(angle);

                    for (let i = 0; i < n; i += len) {
                        let wRe = 1;
                        let wIm = 0;

                        for (let j = 0; j < halfLen; j++) {
                            const tRe = wRe * re[i + j + halfLen] - wIm * im[i + j + halfLen];
                            const tIm = wRe * im[i + j + halfLen] + wIm * re[i + j + halfLen];

                            re[i + j + halfLen] = re[i + j] - tRe;
                            im[i + j + halfLen] = im[i + j] - tIm;
                            re[i + j] += tRe;
                            im[i + j] += tIm;

                            const nextWRe = wRe * wlenRe - wIm * wlenIm;
                            wIm = wRe * wlenIm + wIm * wlenRe;
                            wRe = nextWRe;
                        }
                    }
                }
            }
        };

        const CDFConfig = {
            charaFunc: {
                verbose: false,
                cdfIterSpeed: 0.9,
                cdfLimitEps: 1e-4,
                cdfMaxIter: 30,
                cdfEps: 1e-4,
                cdfWrapping: 0.4,
                rescaleSamples: 64,
                samples: (typeof window !== 'undefined' && window.innerWidth < 768) ? 512 : 4096
            }
        };

        const CharaFunc = new class {
            getRoots(a, samples) {
                let sin = Array(samples), cos = Array(samples);
                sin[0] = 0; cos[0] = 1;
                sin[1] = Math.sin(a); cos[1] = Math.cos(a);
                sin[2] = sin[1] * cos[1] + cos[1] * sin[1]; cos[2] = cos[1] * cos[1] - sin[1] * sin[1];
                sin[3] = sin[1] * cos[2] + cos[1] * sin[2]; cos[3] = cos[1] * cos[2] - sin[1] * sin[2];
                for (let i = 4; i < samples; i += 4) {
                    const j = CDFUtils.floor(i / 2), k = i - j;
                    sin[i] = sin[j] * cos[k] + cos[j] * sin[k]; cos[i] = cos[j] * cos[k] - sin[j] * sin[k];
                    sin[i + 1] = sin[j] * cos[k + 1] + cos[j] * sin[k + 1]; cos[i + 1] = cos[j] * cos[k + 1] - sin[j] * sin[k + 1];
                    sin[i + 2] = sin[j + 1] * cos[k + 1] + cos[j + 1] * sin[k + 1]; cos[i + 2] = cos[j + 1] * cos[k + 1] - sin[j + 1] * sin[k + 1];
                    sin[i + 3] = sin[j + 1] * cos[k + 2] + cos[j + 1] * sin[k + 2]; cos[i + 3] = cos[j + 1] * cos[k + 2] - sin[j + 1] * sin[k + 2];
                }
                return [cos, sin];
            }

            constant(x) {
                return (samples, _) => ComplexVector.constantRe(samples, x);
            }

            mul(cf1, cf2) {
                return (samples, scale) => {
                    const z = cf1(samples, scale);
                    const y = cf2(samples, scale);
                    ComplexVector.mulEq(z, y);
                    return z;
                };
            }

            mulList(cfs) {
                if (cfs.length === 0) return this.constant(1);
                return (samples, scale) => {
                    let z = cfs[0](samples, scale);
                    for (let i = 1; i < cfs.length; ++i) {
                        const y = cfs[i](samples, scale);
                        ComplexVector.mulEq(z, y);
                    }
                    return z;
                };
            }

            pow(cf, n) {
                return (samples, scale) => {
                    let z = cf(samples, scale);
                    for (let T = 0; T < samples; ++T) z[T] = Complex.pow(z[T], n);
                    return z;
                };
            }

            getScaledCDF(cf, samples, scale) {
                const padding = 2;
                const offset = CDFConfig.charaFunc.cdfWrapping;

                const N = samples * padding;
                const val = cf(samples, scale * (1 - offset))
                    .concat(Array(N - samples).fill([0, 0]));
                let re = val.map(a => a[0]);
                let im = val.map(a => a[1]);

                const hasNaN = re.some(x => !isFinite(x)) || im.some(x => !isFinite(x));
                if (hasNaN) {
                    throw new Error("CF produced invalid values");
                }

                SimpleFFT.init(N);
                SimpleFFT.fft(re, im);
                re = re.map(a => a - 0.5);
                const sum = re.reduce((acc, x) => acc + x, 0);
                if (Math.abs(sum) < 1e-10) {
                    throw new Error("FFT output sum is zero");
                }
                re = re.map(a => a / sum);

                let cdf = Array(N);
                cdf[0] = (re[0] + re[N - 1]) / 2;
                for (let i = 1; i < N; ++i) {
                    cdf[i] = cdf[i - 1] + (re[i] + re[i - 1]) / 2;
                }

                const movingMedian = (a, siz) => {
                    const n = a.length;
                    let b = Array(n);
                    for (let i = 0; i < n; ++i) {
                        let w = [];
                        for (let j = i - siz + 1; j <= i + siz; ++j) {
                            const p = a[(j + n) % n];
                            const x = j < 0 ? p - 1 : j >= n ? p + 1 : p;
                            w.push(x);
                        }
                        for (let i = 0; i <= siz; ++i) {
                            for (let j = i + 1; j < w.length; ++j) {
                                if (w[i] > w[j]) { const t = w[i]; w[i] = w[j]; w[j] = t; }
                            }
                        }
                        b[i] = (w[siz - 1] + w[siz]) / 2;
                    }
                    return b;
                }
                cdf = movingMedian(cdf, padding);
                let base = cdf[CDFUtils.floor(N * (1 - offset))] - 1;
                for (let i = 0; i < N; ++i) cdf[i] -= base;
                for (let i = 1; i < N; ++i) if (cdf[i] < cdf[i - 1]) cdf[i] = cdf[i - 1];

                const interpolate = (acc, x) => {
                    if (x < 0) return 0;
                    if (x >= 1) return 1;
                    const t = x * (1 - offset) * N - 0.5;
                    const i = CDFUtils.round(t), r = t - i;
                    const L = i - 1 < 0 ? acc[i + N - 1] - 1 : acc[i - 1];
                    const R = i + 1 >= N ? acc[i - N + 1] + 1 : acc[i + 1];
                    const A = (acc[i] + L) / 2, B = (acc[i] + R) / 2;
                    const kA = acc[i] - L, kB = R - acc[i];
                    const ret = 2 * (r + 1) * (r - 0.5) * (r - 0.5) * A
                        + 2 * (1 - r) * (r + 0.5) * (r + 0.5) * B
                        + (r * r - 0.25) * ((r - 0.5) * kA + (r + 0.5) * kB);
                    return ret < 0 ? 0 : ret > 1 ? 1 : ret;
                };
                return (x) => interpolate(cdf, x);
            }

            getCDF(cf, samples, limit = 1e8, rescaleSamples = null) {
                const eps = CDFConfig.charaFunc.cdfEps;
                const speed = CDFConfig.charaFunc.cdfIterSpeed;
                const maxIter = CDFConfig.charaFunc.cdfMaxIter;
                rescaleSamples = rescaleSamples || CDFConfig.charaFunc.rescaleSamples;

                for (let i = 0; i < maxIter; ++i) {
                    let cdf = this.getScaledCDF(cf, rescaleSamples, 1 / limit);
                    if (cdf(speed) < 1 - eps) {
                        break;
                    }
                    const x = CDFUtils.binarySearch(cdf, 0, 1, 1 - eps);
                    if (x / speed > 1 - CDFConfig.charaFunc.cdfLimitEps) {
                        break;
                    }
                    limit *= x / speed;
                }
                let cdf = this.getScaledCDF(cf, samples, 1 / limit);
                return {
                    limit: limit,
                    cdf: (x) => cdf(x / limit),
                };
            }
        };

        const CDFDropAnalyzer = new class {
            charaFunc(data) {
                const { minCount: l, maxCount: r, dropRate, price } = data;
                const eps = 1e-8;
                const L = Math.ceil(l);
                const R = CDFUtils.floor(r);

                if (L > R || r - l < eps) {
                    const p = (l + r) / 2 - R;
                    const pr = p * dropRate;
                    const mpr = (1 - p) * dropRate;
                    const mr = 1 - dropRate;

                    return (samples, scale) => {
                        let val = Array(samples);
                        const base = 2 * Math.PI * scale * price;
                        const [cosR1, sinR1] = CharaFunc.getRoots(base * (R + 1), samples);
                        const [cosR, sinR] = CharaFunc.getRoots(base * R, samples);
                        for (let T = 0; T < samples; ++T) {
                            val[T] = [
                                cosR1[T] * pr + cosR[T] * mpr + mr,
                                sinR1[T] * pr + sinR[T] * mpr
                            ]
                        }
                        return val;
                    };
                }
                if (L == R) {
                    const pL = dropRate * (L - l) * (L - l) / ((r - l) * 2);
                    const pR = dropRate * (r - R) * (r - R) / ((r - l) * 2);
                    const mr = 1 - dropRate;

                    return (samples, scale) => {
                        let val = Array(samples);
                        const base = 2 * Math.PI * scale * price;
                        const [cos, sin] = CharaFunc.getRoots(base, samples);
                        const [cosR, sinR] = CharaFunc.getRoots(base * R, samples);
                        for (let T = 0; T < samples; ++T) {
                            const a = [dropRate + (pL + pR) * (cos[T] - 1), (-pL + pR) * sin[T]];
                            val[T] = Complex.mul([cosR[T], sinR[T]], a);
                            val[T][0] += mr;
                        }
                        return val;
                    };
                }

                const dL = L - l, dR = r - R;
                const dL2 = dL * dL, dR2 = dR * dR;
                const mr = 1 - dropRate;
                const invLen = dropRate / (r - l);
                return (samples, scale) => {
                    let val = Array(samples);
                    const base = 2 * Math.PI * scale * price;
                    const [cos, sin] = CharaFunc.getRoots(base, samples);
                    const [cosR, sinR] = CharaFunc.getRoots(base * R, samples);
                    const [cosL, sinL] = CharaFunc.getRoots(base * L, samples);
                    for (let T = 0; T < samples; ++T) {
                        const ctm1d2 = (cos[T] - 1) / 2, std2 = sin[T] / 2;
                        const elt = [cosL[T], sinL[T]];
                        const ert = [cosR[T], sinR[T]];
                        const fL = Complex.mul([dL + dL2 * ctm1d2, -dL2 * std2], elt);
                        const fR = Complex.mul([dR + dR2 * ctm1d2, dR2 * std2], ert)
                        const irwin = ctm1d2 > -eps && std2 < eps && std2 > -eps ?
                            [(R - L) * elt[0], (R - L) * (elt[1] + std2 * (R - L - 1))] :
                            Complex.div([ert[0] - elt[0], ert[1] - elt[1]], [ctm1d2 * 2, std2 * 2]);
                        const fMid = Complex.mul(irwin, [1 + ctm1d2, std2]);
                        val[T] = [mr + invLen * (fL[0] + fR[0] + fMid[0]), invLen * (fL[1] + fR[1] + fMid[1])];
                    }
                    return val;
                };
            }
        };

        const RuckBattleDropAnalyzer = new class {
            #monsterCF(monsterDrops) {
                const cfs = [];
                for (const drop of monsterDrops) {
                    cfs.push(CDFDropAnalyzer.charaFunc(drop));
                }
                return CharaFunc.mulList(cfs);
            }

            #getSpawnTransGraph(spawnInfo) {
                const { spawns, maxSpawnCount: K, maxTotalStrength: N } = spawnInfo;
                const idMap = {};
                const nodes = [];
                const hasId = (i, j) => { return idMap.hasOwnProperty(i * (K + 1) + j); };
                const getId = (i, j) => {
                    const h = i * (K + 1) + j;
                    if (!hasId(i, j)) {
                        idMap[h] = nodes.length;
                        nodes.push({ init: 0, edges: [] });
                    }
                    return idMap[h];
                };
                getId(0, 0);
                for (let i = 0; i <= N; ++i) {
                    for (let j = 0; j <= K; ++j) {
                        if (!hasId(i, j)) continue;
                        const id = getId(i, j);
                        for (const monster of spawns) {
                            const ni = i + monster.strength, nj = j + 1;
                            if (ni > N || nj > K) {
                                nodes[id].init += monster.rate;
                                continue;
                            }
                            const monsterHrid = monster.combatMonsterHrid || monster.hrid;
                            nodes[id].edges.push({
                                to: getId(ni, nj),
                                hrid: monsterHrid,
                            });
                        }
                    }
                }
                return nodes;
            }

            #normalWaveCF(spawnInfo, monsterDrops) {
                const spawns = spawnInfo.spawns;
                const cfs = {};
                for (const monster of spawns) {
                    const monsterHrid = monster.combatMonsterHrid || monster.hrid;
                    const drops = monsterDrops[monsterHrid] || [];
                    cfs[monsterHrid] = this.#monsterCF(drops);
                }
                const transGraph = this.#getSpawnTransGraph(spawnInfo);
                return (samples, scale) => {
                    const cfTab = {};
                    for (const monster of spawns) {
                        const monsterHrid = monster.combatMonsterHrid || monster.hrid;
                        const z = cfs[monsterHrid](samples, scale);
                        ComplexVector.mulReEq(z, monster.rate);
                        cfTab[monsterHrid] = z;
                    }
                    const val = Array(transGraph.length);
                    for (let u = transGraph.length - 1; u >= 0; --u) {
                        val[u] = ComplexVector.constantRe(samples, transGraph[u].init);
                        for (const e of transGraph[u].edges) {
                            ComplexVector.addMulEq(val[u], val[e.to], cfTab[e.hrid]);
                        }
                    }
                    return val[0];
                };
            }

            battleCF(dropData) {
                const normalCF = this.#normalWaveCF(dropData.spawnInfo, dropData.monsterDrops);
                const bossCF = CharaFunc.mulList(
                    Object.values(dropData.bossDrops).map(m => this.#monsterCF(m)));
                return CharaFunc.mul(
                    CharaFunc.pow(normalCF, dropData.normalCount),
                    CharaFunc.pow(bossCF, dropData.bossCount)
                );
            }

            battleCDF(dropData) {
                const samples = CDFConfig.charaFunc.samples;
                const cf = RuckBattleDropAnalyzer.battleCF(dropData);
                let cdf;
                const minLimit = 1e8;
                const dungeonDrop = dropData.bossDrops?.['_dungeon']?.[0];
                if (!dungeonDrop) {
                    const perWaveLimit = 2e5;
                    const limit = Math.max(minLimit, perWaveLimit * (dropData.bossCount + dropData.normalCount));
                    cdf = CharaFunc.getCDF(cf, samples, limit);
                } else {
                    const chestPrice = LuckyUtils.getItemValue(dungeonDrop.hrid, 1);
                    const epoch = dropData.bossCount;
                    const count = (dungeonDrop.minCount + dungeonDrop.maxCount) / 2;
                    const baseCount = Math.floor(count);
                    const basePrice = chestPrice * baseCount * epoch;
                    const limit = Math.max(samples, epoch);
                    const decCDF = CharaFunc.getCDF(CharaFunc.pow(CDFDropAnalyzer.charaFunc({
                        hrid: dungeonDrop.hrid,
                        minCount: count - baseCount,
                        maxCount: count - baseCount,
                        dropRate: 1,
                        price: 1,
                    }), epoch), samples, limit);
                    cdf = {
                        limit: decCDF.limit * chestPrice + basePrice,
                        cdf: (x) => {
                            const chestCount = (x - basePrice) / chestPrice;
                            return decCDF.cdf(chestCount + 16 / samples);
                        },
                    };
                }
                return cdf;
            }
        };

        const RuckBattleData = new class {
            mapData = {};
            playerStat = {};
            playerList = [];
            playerLoot = {};
            currentMapHrid = null;
            difficultyTier = 0;
            runCount = 0;

            getDropData(mapHrid, runCount = 11, playerName = null) {
                const mapData = this.mapData[mapHrid];
                if (!mapData) return null;
                const bossWave = mapData.spawnInfo.bossWave;
                const bossCount = bossWave ? Math.floor((runCount - 1) / bossWave) : 0;
                const normalCount = bossWave ? bossCount * (bossWave - 1) + (runCount - 1) % bossWave : runCount - 1;
                const dropData = {
                    spawnInfo: mapData.spawnInfo,
                    bossCount: bossCount,
                    normalCount: normalCount,
                    bossDrops: {},
                    monsterDrops: {},
                };
                const processDrop = (item) => {
                    const itemPrice = LuckyUtils.getItemValue(item.itemHrid, 1);
                    let { minCount, maxCount, dropRate } = item;
                    const dropRatePerTier = item.dropRatePerDifficultyTier || 0;
                    if (playerName) {
                        const playerStat = this.playerStat[playerName];
                        if (playerStat) {
                            const commonRateMultiplier = 1 + (playerStat.combatDropRate || 0);
                            const rareRateMultiplier = 1 + (playerStat.combatRareFind || 0);
                            const quantityMultiplier = (1 + (playerStat.combatDropQuantity || 0)) / this.playerList.length * (mapData.type === 'dungeon' ? 5 : 1);
                            const rateMultiplier = item.isRare ? rareRateMultiplier : commonRateMultiplier;
                            minCount *= quantityMultiplier;
                            maxCount *= quantityMultiplier;
                            const len = mapData.type === 'dungeon'? 3 : (mapData.type === 'group'? 6 : 1);
                            dropRate = Array.from({length: len}, (_, n) => {
                                let rate = dropRate + n * dropRatePerTier;
                                rate = rate * (1 + n * 0.1) * rateMultiplier;
                                return Math.min(Math.max(rate, 0), 1);
                            });
                        }
                    }
                    return {
                        hrid: item.itemHrid,
                        price: itemPrice,
                        minCount: minCount,
                        maxCount: maxCount,
                        dropRate: dropRate,
                    };
                };
                for (let [hrid, drops] of Object.entries(mapData.bossDrops || {})){
                    dropData.bossDrops[hrid] = drops.map(drop => processDrop(drop));}
                for (let [hrid, drops] of Object.entries(mapData.monsterDrops || {})){
                    dropData.monsterDrops[hrid] = drops.map(drop => processDrop(drop));}
                return dropData;
            }

            getDropDataDifficulty(mapHrid, runCount = 11, playerName = null) {
                let dropData = this.getDropData(mapHrid, runCount, playerName);
                if (!dropData) return null;
                for (let [hrid, drops] of Object.entries(dropData.bossDrops)) {
                    dropData.bossDrops[hrid] = drops.map(drop => {
                        const newDropRate = drop.dropRate?.[this.difficultyTier];
                        return { ...drop, dropRate: newDropRate };
                    });
                }
                for (let [hrid, drops] of Object.entries(dropData.monsterDrops)) {
                    dropData.monsterDrops[hrid] = drops.map(drop => {
                        const newDropRate = drop.dropRate?.[this.difficultyTier];
                        return { ...drop, dropRate: newDropRate };
                    });
                }
                return dropData
            }

            getCurrentDropData(playerName = null) {
                if (!this.currentMapHrid) return null;
                return this.getDropDataDifficulty(this.currentMapHrid, this.runCount, playerName);
            }

            syncFromLucky() {
                this.mapData = LuckyGameData.mapData;
                this.currentMapHrid = LuckyGameData.currentMapHrid;
                this.difficultyTier = LuckyGameData.currentDifficultyTier;
                this.runCount = FlootData.getBattleCount();
                this.playerList = Object.keys(LuckyGameData.playerStats);
                for (const playerName of this.playerList) {
                    const stats = LuckyGameData.playerStats[playerName];
                    this.playerStat[playerName] = {
                        combatDropQuantity: stats.combatDropQuantity || 0,
                        combatDropRate: stats.combatDropRate || 0,
                        combatRareFind: stats.combatRareFind || 0,
                    };
                }
                for (const playerName of this.playerList) {
                    const drops = FlootData.getPlayerDrops(playerName);
                    const items = [];
                    for (const [hrid, count] of Object.entries(drops)) {
                        items.push({ hrid, count });
                    }
                    this.playerLoot[playerName] = {
                        items,
                        price: () => items.reduce((total, item) => {
                            const price = LuckyUtils.getItemValue(item.hrid, 1);
                            return total + item.count * price;
                        }, 0)
                    };
                }
            }
        };

        const RuckAnalyzeCurrent = (playerName) => {
            RuckBattleData.syncFromLucky();
            const dropData = RuckBattleData.getCurrentDropData(playerName);
            if (!dropData) return null;
            const income = RuckBattleData.playerLoot[playerName]?.price() || 0;
            const luck = RuckBattleDropAnalyzer.battleCDF(dropData).cdf(income);
            return { luck: luck, income: income, dropData: dropData };
        };

        const LuckyDropAnalyzer = {
            spawnCache: {},

            itemCountExpt(drop, tier) {
                let baseDropRate;
                if (typeof drop.dropRate === 'number') {
                    baseDropRate = drop.dropRate;
                } else if (Array.isArray(drop.dropRate)) {
                    baseDropRate = drop.dropRate[tier] || drop.dropRate[0];
                    return baseDropRate * (drop.minCount + drop.maxCount) / 2;
                } else {
                    baseDropRate = 0;
                }
                const dropRatePerTier = drop.dropRatePerDifficultyTier || 0;
                let adjustedDropRate = baseDropRate + tier * dropRatePerTier;
                adjustedDropRate = adjustedDropRate * (1 + tier * 0.1);
                adjustedDropRate = Math.min(Math.max(adjustedDropRate, 0), 1);
                const expected = adjustedDropRate * (drop.minCount + drop.maxCount) / 2;
                return expected;
            },

            getTierDropRate(drop, tier) {
                let baseDropRate;
                if (typeof drop.dropRate === 'number') {
                    baseDropRate = drop.dropRate;
                } else if (Array.isArray(drop.dropRate)) {
                    return drop.dropRate[tier] || drop.dropRate[0];
                } else {
                    return 0;
                }
                const dropRatePerTier = drop.dropRatePerDifficultyTier || 0;
                let adjustedDropRate = baseDropRate + tier * dropRatePerTier;
                adjustedDropRate = adjustedDropRate * (1 + tier * 0.1);
                adjustedDropRate = Math.min(Math.max(adjustedDropRate, 0), 1);
                return adjustedDropRate;
            },

            computeExpectedSpawns(spawnInfo) {
                const cacheKey = LuckyGameData.currentMapHrid;
                if (this.spawnCache[cacheKey]) {
                    return this.spawnCache[cacheKey];
                }
                const spawns = spawnInfo.spawns;
                const maxSpawnCount = spawnInfo.maxSpawnCount;
                const maxTotalStrength = spawnInfo.maxTotalStrength;
                const res = {};
                spawns.forEach(m => { res[m.combatMonsterHrid] = 0; });
                const dp = [];
                for (let i = 0; i <= maxTotalStrength; i++) {
                    dp[i] = new Array(maxSpawnCount + 1).fill(0);
                }
                dp[0][0] = 1;
                for (let i = 0; i <= maxTotalStrength; i++) {
                    for (let j = 0; j <= maxSpawnCount; j++) {
                        if (dp[i][j] === 0) continue;
                        for (const monster of spawns) {
                            const ni = i + monster.strength;
                            const nj = j + 1;
                            if (ni > maxTotalStrength || nj > maxSpawnCount) continue;
                            const val = dp[i][j] * monster.rate;
                            dp[ni][nj] += val;
                            res[monster.combatMonsterHrid] += val;
                        }
                    }
                }
                this.spawnCache[cacheKey] = res;
                return res;
            },

            calculateDropsCommon(mapHrid, runCount, difficultyTier, calcFunc) {
                const mapData = LuckyGameData.mapData[mapHrid];
                if (!mapData) {
                    console.warn('[Lucky] No map data found for:', mapHrid, 'Available maps:', Object.keys(LuckyGameData.mapData));
                    return {};
                }

                const spawnInfo = mapData.spawnInfo;
                let bossWave = spawnInfo.bossWave || 0;
                if (!bossWave && mapData.type === 'dungeon') {
                    bossWave = 1;
                } else if (!bossWave && mapData.type === 'group' && mapData.bossDrops && Object.keys(mapData.bossDrops).length > 0) {
                    bossWave = 10;
                }

                const bossCount = bossWave ? Math.floor((runCount - 1) / bossWave) : 0;
                const normalCount = bossWave ?
                    bossCount * (bossWave - 1) + (runCount - 1) % bossWave :
                    runCount - 1;

                const expectedSpawns = this.computeExpectedSpawns(spawnInfo);
                const drops = {};

                if (mapData.bossDrops) {
                    for (const [monsterHrid, monsterDrops] of Object.entries(mapData.bossDrops)) {
                        for (const drop of monsterDrops) {
                            const value = calcFunc(drop, difficultyTier, bossCount);
                            if (!drops[drop.itemHrid]) {
                                drops[drop.itemHrid] = { count: 0, tierDropRate: this.getTierDropRate(drop, difficultyTier), isRare: drop.isRare || false };
                            }
                            drops[drop.itemHrid].count += value;
                        }
                    }
                }

                if (mapData.monsterDrops) {
                    for (const [monsterHrid, monsterDrops] of Object.entries(mapData.monsterDrops)) {
                        const spawnCount = expectedSpawns[monsterHrid] || 0;
                        for (const drop of monsterDrops) {
                            const value = calcFunc(drop, difficultyTier, spawnCount * normalCount);
                            if (!drops[drop.itemHrid]) {
                                drops[drop.itemHrid] = { count: 0, tierDropRate: this.getTierDropRate(drop, difficultyTier), isRare: drop.isRare || false };
                            }
                            drops[drop.itemHrid].count += value;
                        }
                    }
                }

                return drops;
            },

            calculateExpectedDrops(mapHrid, runCount, difficultyTier, partySize) {
                return this.calculateDropsCommon(mapHrid, runCount, difficultyTier, (drop, tier, count) => {
                    const itemExpt = this.itemCountExpt(drop, tier);
                    return count * itemExpt;
                });
            },

            calculateMaximumDrops(mapHrid, runCount, difficultyTier, partySize) {
                return this.calculateDropsCommon(mapHrid, runCount, difficultyTier, (drop, tier, count) => {
                    const adjustedDropRate = this.getTierDropRate(drop, tier);
                    return count * adjustedDropRate * drop.maxCount;
                });
            }
        };

        const LuckyUtils = {
            formatNumber(num) {
                if (num >= 1000000) {
                    return (num / 1000000).toFixed(2) + 'M';
                }
                if (num >= 1000) {
                    return (num / 1000).toFixed(1) + 'K';
                }
                if (num >= 10) {
                    return num.toFixed(1);
                }
                if (num >= 1) {
                    return num.toFixed(2);
                }
                if (num > 0) {
                    return num.toFixed(3);
                }
                return '0';
            },

            getPercentClass(percent, expected100Mode = false) {
                if (expected100Mode) {
                    if (percent > 105) return 'value-positive';
                    if (percent < 95) return 'value-negative';
                    return 'value-neutral';
                } else {
                    if (percent > 5) return 'value-positive';
                    if (percent < -5) return 'value-negative';
                    return 'value-neutral';
                }
            },

            getPercentColor(percent, expected100Mode = false) {
                const colorMap = {
                    'value-positive': '#4ade80',
                    'value-negative': '#f87171',
                    'value-neutral': '#a8aed4'
                };
                return colorMap[this.getPercentClass(percent, expected100Mode)];
            },

            formatTime(seconds) {
                return mcsFormatDuration(seconds, 'clock');
            },

            getItemName(hrid) {
                return mcsFormatHrid(hrid);
            },

            getItemValue(itemHrid, count = 1) {
                if (typeof window.getUnitValue === 'function') {
                    const unitValue = window.getUnitValue(itemHrid, 'live');
                    if (unitValue !== null) {
                        return unitValue * count;
                    }
                }
                return 0;
            },

            HSVtoRGB(h, s, v) {
                var r, g, b, i, f, p, q, t;
                i = Math.floor(h * 6);
                f = h * 6 - i;
                p = v * (1 - s);
                q = v * (1 - f * s);
                t = v * (1 - (1 - f) * s);
                switch (i % 6) {
                    case 0: r = v; g = t; b = p; break;
                    case 1: r = q; g = v; b = p; break;
                    case 2: r = p; g = v; b = t; break;
                    case 3: r = p; g = q; b = v; break;
                    case 4: r = t; g = p; b = v; break;
                    case 5: r = v; g = p; b = q; break;
                }
                r = Math.round(r * 255);
                g = Math.round(g * 255);
                b = Math.round(b * 255);
                return `rgb(${r}, ${g}, ${b})`;
            },

            getLuckColor(luckPercent) {
                const luck = Math.min(Math.max(luckPercent / 100, 0), 1);
                const h = luck * 0.34;
                const s = 0.9 - luck * 0.25;
                const v = 1 - luck * 0.25;
                return this.HSVtoRGB(h, s, v);
            }
        };

        let _luckyWsListener = null;
        function setupLuckyMessageHandlers() {
            try {
                const clientData = InitClientDataCache.get();

                if (clientData) {
                    processInitClientData(clientData);
                }
            } catch (e) {
                console.error('[Lucky] Error loading cached data:', e);
            }

            try {
                if (typeof GM_getValue !== 'undefined') {
                    const storedCharData = GM_getValue("init_character_data", null);
                    if (storedCharData) {
                        const charData = JSON.parse(storedCharData);
                        if (charData.characterActions && charData.characterActions[0]) {
                            const action = charData.characterActions[0];
                            if (action.actionHrid) {
                                if (LuckyGameData.currentMapHrid !== action.actionHrid) {
                                    LuckyDropAnalyzer.spawnCache = {};
                                }
                                LuckyGameData.currentMapHrid = action.actionHrid;
                                LuckyGameData.currentDifficultyTier = action.difficultyTier || 0;
                            }
                        }
                    }
                }
            } catch (e) {
            }

            _luckyWsListener = (event) => {
                if (window.MCS_MODULES_DISABLED) return;

                const msg = event.detail;
                if (!msg) return;

                if (msg.type === 'init_client_data') {
                    processInitClientData(msg);
                }

                if (msg.type === 'init_character_data') {
                    if (msg.characterActions && msg.characterActions[0]) {
                        const action = msg.characterActions[0];
                        if (action.actionHrid) {
                            if (LuckyGameData.currentMapHrid !== action.actionHrid) {
                                LuckyDropAnalyzer.spawnCache = {};
                            }
                            LuckyGameData.currentMapHrid = action.actionHrid;
                            LuckyGameData.currentDifficultyTier = action.difficultyTier || 0;
                        }
                    }
                }

                if (msg.type === 'new_battle') {
                    if (msg.players && msg.players.length > 0) {
                        LuckyGameData.hasReceivedFirstBattle = true;
                        for (const player of msg.players) {
                            if (!player.character) continue;
                            if (!player.combatDetails || !player.combatDetails.combatStats) continue;
                            const playerName = player.character.name;
                            const stats = player.combatDetails.combatStats;
                            LuckyGameData.playerStats[playerName] = {
                                combatDropQuantity: stats.combatDropQuantity || 0,
                                combatDropRate: stats.combatDropRate || 0,
                                combatRareFind: stats.combatRareFind || 0
                            };
                        }
                    }
                }

                if (msg.type === 'action_completed') {
                    if (msg.endCharacterAction && msg.endCharacterAction.actionHrid) {
                        if (LuckyGameData.currentMapHrid !== msg.endCharacterAction.actionHrid) {
                            LuckyDropAnalyzer.spawnCache = {};
                        }
                        LuckyGameData.currentMapHrid = msg.endCharacterAction.actionHrid;
                        LuckyGameData.currentDifficultyTier = msg.endCharacterAction.difficultyTier || 0;
                    }
                }
            };
            window.addEventListener('EquipSpyWebSocketMessage', _luckyWsListener);
        }

        function processInitClientData(msg) {
            if (!msg) return;

            if (msg.itemDetailMap) {
                for (const [hrid, item] of Object.entries(msg.itemDetailMap)) {
                    LuckyGameData.itemNames[hrid] = item.name;
                    LuckyGameData.itemPrices[hrid] = hrid === '/items/coin' ? 1 : (item.sellPrice || 0);
                }
            }

            if (msg.actionDetailMap && msg.combatMonsterDetailMap) {
                const monsterMap = msg.combatMonsterDetailMap;
                for (const [hrid, monster] of Object.entries(monsterMap)) {
                    if (monster.name) LuckyGameData.monsterNames[hrid] = monster.name;
                }
                const actionDetailMap = msg.actionDetailMap;

                for (const [actionHrid, actionDetail] of Object.entries(actionDetailMap)) {
                    if (!actionHrid.startsWith("/actions/combat/")) continue;
                    if (!actionDetail.combatZoneInfo) continue;

                    LuckyGameData.mapNames[actionHrid] = actionDetail.name;

                    if (actionDetail.combatZoneInfo.isDungeon) {
                        const dungeonInfo = actionDetail.combatZoneInfo.dungeonInfo;
                        LuckyGameData.mapData[actionHrid] = {
                            name: actionDetail.name,
                            type: 'dungeon',
                            spawnInfo: { bossWave: 1, maxSpawnCount: 0, maxTotalStrength: 0, spawns: [] },
                            monsterDrops: {},
                            bossDrops: {
                                '_dungeon': dungeonInfo.rewardDropTable.map(item => ({ isRare: false, ...item }))
                            }
                        };
                        continue;
                    }

                    const fightInfo = actionDetail.combatZoneInfo.fightInfo;
                    if (!fightInfo) continue;

                    const spawnInfo = fightInfo.randomSpawnInfo;
                    if (!spawnInfo || !spawnInfo.spawns || spawnInfo.spawns.length === 0) continue;

                    const mapType = spawnInfo.spawns.length > 1 || spawnInfo.bossWave > 0 ? "group" : "solo";
                    const totalRate = spawnInfo.spawns.reduce((s, x) => s + x.rate, 0);
                    const spawns = spawnInfo.spawns.map(s => ({
                        combatMonsterHrid: s.combatMonsterHrid,
                        strength: s.strength,
                        rate: s.rate / totalRate
                    }));

                    const monsterDrops = {};
                    for (const spawn of spawns) {
                        const monster = monsterMap[spawn.combatMonsterHrid];
                        if (!monster) continue;
                        const drops = [];
                        if (monster.dropTable) {
                            monster.dropTable.forEach(drop => {
                                drops.push({
                                    itemHrid: drop.itemHrid,
                                    dropRate: drop.dropRate,
                                    minCount: drop.minCount,
                                    maxCount: drop.maxCount,
                                    isRare: false,
                                    dropRatePerDifficultyTier: drop.dropRatePerDifficultyTier || 0
                                });
                            });
                        }
                        if (monster.rareDropTable) {
                            monster.rareDropTable.forEach(drop => {
                                drops.push({
                                    itemHrid: drop.itemHrid,
                                    dropRate: drop.dropRate,
                                    minCount: drop.minCount,
                                    maxCount: drop.maxCount,
                                    isRare: true,
                                    dropRatePerDifficultyTier: drop.dropRatePerDifficultyTier || 0
                                });
                            });
                        }
                        monsterDrops[spawn.combatMonsterHrid] = drops;
                    }

                    const bossDrops = {};
                    if (fightInfo.bossSpawns) {
                        for (const bossSpawn of fightInfo.bossSpawns) {
                            const boss = monsterMap[bossSpawn.combatMonsterHrid];
                            if (!boss) continue;
                            const drops = [];
                            if (boss.dropTable) {
                                boss.dropTable.forEach(drop => {
                                    drops.push({
                                        itemHrid: drop.itemHrid,
                                        dropRate: drop.dropRate,
                                        minCount: drop.minCount,
                                        maxCount: drop.maxCount,
                                        isRare: false,
                                        dropRatePerDifficultyTier: drop.dropRatePerDifficultyTier || 0
                                    });
                                });
                            }
                            if (boss.rareDropTable) {
                                boss.rareDropTable.forEach(drop => {
                                    drops.push({
                                        itemHrid: drop.itemHrid,
                                        dropRate: drop.dropRate,
                                        minCount: drop.minCount,
                                        maxCount: drop.maxCount,
                                        isRare: true,
                                        dropRatePerDifficultyTier: drop.dropRatePerDifficultyTier || 0
                                    });
                                });
                            }
                            bossDrops[bossSpawn.combatMonsterHrid] = drops;
                        }
                    }

                    LuckyGameData.mapData[actionHrid] = {
                        name: actionDetail.name,
                        type: mapType,
                        spawnInfo: {
                            maxSpawnCount: spawnInfo.maxSpawnCount,
                            maxTotalStrength: spawnInfo.maxTotalStrength,
                            bossWave: fightInfo.battlesPerBoss || 0,
                            spawns: spawns
                        },
                        monsterDrops: monsterDrops,
                        bossDrops: bossDrops
                    };
                }
            }
        }

        class LuckyPanel {
            get lyStorage() {
                if (!this._lyStorage) {
                    this._lyStorage = createModuleStorage('LY');
                }
                return this._lyStorage;
            }

            constructor() {
                this.panel = null;
                this.isDragging = false;
                this.dragOffset = { x: 0, y: 0 };
                this.updateInterval = null;
                this.isLocked = false;
                this.expected100Mode = false;
                this.snapToGrid = true;
                this.panelVisibility = {
                    stats: true,
                    revenue: true,
                    totals: true,
                    bigExpected: true,
                    bigLuck: true,
                    mobExpected: true
                };
                this.playerPanels = new Map();
                this.lastPlayerNames = [];

                this.cachedExpectedDrops = null;
                this.cachedMaximumDrops = null;
                this.lastDropsCacheKey = null;

                this.cachedLuckResults = new Map();
                this.lastLuckBattleCount = 0;

                this.statsElements = null;
            }

            saveState() {
                if (!this.panel) return;

                const hasExplicitPosition = this.panel.style.left || this.panel.style.top;
                if (!hasExplicitPosition) {
                    return;
                }

                const rect = this.panel.getBoundingClientRect();

                const left = parseFloat(this.panel.style.left) || rect.left;
                const top = parseFloat(this.panel.style.top) || rect.top;

                if (left < -500 || top < -500) {
                    return;
                }

                const state = {
                    x: left,
                    y: top,
                    width: this.panel.style.width || rect.width + 'px',
                    height: this.panel.style.height || rect.height + 'px'
                };
                this.lyStorage.set('panel_state', state);
            }

            loadState() {
                if (!this.panel) {
                    return null;
                }

                try {
                    const state = this.lyStorage.get('panel_state');
                    if (state) {
                        if (typeof state.x === 'number' && typeof state.y === 'number') {
                            this.panel.style.left = state.x + 'px';
                            this.panel.style.top = state.y + 'px';
                            this.panel.style.right = 'auto';
                        }
                        if (state.width) this.panel.style.width = state.width;
                        if (state.height) this.panel.style.height = state.height;
                        return state;
                    }
                } catch (e) {
                    console.error('[Lucky] Error in loadState:', e);
                }
                return null;
            }

            init() {
                this.loadPanelSettings();
                this.createPanel();
                this.applyLockState();
                this.loadState();
                this.startAutoUpdate();

                this.applyDefaultGridIfNeeded();
            }

            createPanel() {
                this.panel = document.createElement('div');
                this.panel.className = 'lucky-panel';
                this.panel.id = 'lucky-panel';
                registerPanel('lucky-panel');

                const content = document.createElement('div');
                content.className = 'lucky-content';
                content.id = 'lucky-content';

                for (let i = 0; i < 15; i++) {
                    const spacer = document.createElement('div');
                    spacer.className = 'lucky-content-spacer';
                    spacer.style.top = (i * 100) + 'px';
                    content.appendChild(spacer);
                }

                const gridOverlay = document.createElement('div');
                gridOverlay.id = 'lucky-grid-overlay';
                gridOverlay.className = 'lucky-grid-overlay';
                content.appendChild(gridOverlay);

                this.createControlIcons(content);

                this.panel.appendChild(content);
                document.body.appendChild(this.panel);

                this.panel.dataset.originalDisplay = 'block';

                this.setupResizeHandles(this.panel);

                this.createOptionsPanel();

                this.setupResizeObserver();
            }

            setupResizeHandles(element, storageId = null) {
                const isMainPanel = (element === this.panel);

                const rightHandle = document.createElement('div');
                rightHandle.className = 'lucky-resize-handle lucky-resize-handle-right';
                element.appendChild(rightHandle);

                const bottomHandle = document.createElement('div');
                bottomHandle.className = 'lucky-resize-handle lucky-resize-handle-bottom';
                element.appendChild(bottomHandle);

                const cornerHandle = document.createElement('div');
                cornerHandle.className = 'lucky-resize-handle lucky-resize-handle-corner';
                element.appendChild(cornerHandle);

                this.setupEdgeResize(element, rightHandle, 'right', storageId);

                this.setupEdgeResize(element, bottomHandle, 'bottom', storageId);

                this.setupEdgeResize(element, cornerHandle, 'corner', storageId);

                if (isMainPanel) {
                    const leftHandle = document.createElement('div');
                    leftHandle.className = 'lucky-resize-handle lucky-resize-handle-left';
                    element.appendChild(leftHandle);

                    const topHandle = document.createElement('div');
                    topHandle.className = 'lucky-resize-handle lucky-resize-handle-top';
                    element.appendChild(topHandle);

                    const cornerTopLeftHandle = document.createElement('div');
                    cornerTopLeftHandle.className = 'lucky-resize-handle lucky-resize-handle-corner-topleft';
                    element.appendChild(cornerTopLeftHandle);

                    const cornerTopRightHandle = document.createElement('div');
                    cornerTopRightHandle.className = 'lucky-resize-handle lucky-resize-handle-corner-topright';
                    element.appendChild(cornerTopRightHandle);

                    const cornerBottomLeftHandle = document.createElement('div');
                    cornerBottomLeftHandle.className = 'lucky-resize-handle lucky-resize-handle-corner-bottomleft';
                    element.appendChild(cornerBottomLeftHandle);

                    this.setupEdgeResize(element, leftHandle, 'left', storageId);

                    this.setupEdgeResize(element, topHandle, 'top', storageId);

                    this.setupEdgeResize(element, cornerTopLeftHandle, 'corner-topleft', storageId);

                    this.setupEdgeResize(element, cornerTopRightHandle, 'corner-topright', storageId);

                    this.setupEdgeResize(element, cornerBottomLeftHandle, 'corner-bottomleft', storageId);
                }
            }

            _trackDocListener(event, fn) {
                if (!this._luckyDocListeners) this._luckyDocListeners = [];
                this._luckyDocListeners.push({ event, fn });
            }

            _cleanupDocListeners() {
                if (this._luckyDocListeners) {
                    for (const { event, fn } of this._luckyDocListeners) {
                        document.removeEventListener(event, fn);
                    }
                    this._luckyDocListeners = null;
                }
            }

            setupEdgeResize(element, handle, type, storageId = null) {
                let startX, startY, startWidth, startHeight, startLeft, startTop;

                const onResizeMove = (e) => {
                    const deltaX = e.clientX - startX;
                    const deltaY = e.clientY - startY;
                    const minWidth = 50;
                    const minHeight = 50;
                    const GRID_SIZE = 10;

                    if (type === 'right' || type === 'corner' || type === 'corner-topright') {
                        let newWidth = startWidth + deltaX;
                        if (this.snapToGrid) newWidth = Math.round(newWidth / GRID_SIZE) * GRID_SIZE;
                        element.style.width = Math.max(minWidth, newWidth) + 'px';
                    }

                    if (type === 'left' || type === 'corner-topleft' || type === 'corner-bottomleft') {
                        let newWidth = startWidth - deltaX;
                        if (this.snapToGrid) newWidth = Math.round(newWidth / GRID_SIZE) * GRID_SIZE;
                        if (newWidth >= minWidth) {
                            element.style.width = newWidth + 'px';
                            element.style.left = (startLeft + deltaX) + 'px';
                        }
                    }

                    if (type === 'bottom' || type === 'corner' || type === 'corner-bottomleft') {
                        let newHeight = startHeight + deltaY;
                        if (this.snapToGrid) newHeight = Math.round(newHeight / GRID_SIZE) * GRID_SIZE;
                        element.style.height = Math.max(minHeight, newHeight) + 'px';
                    }

                    if (type === 'top' || type === 'corner-topleft' || type === 'corner-topright') {
                        let newHeight = startHeight - deltaY;
                        if (this.snapToGrid) newHeight = Math.round(newHeight / GRID_SIZE) * GRID_SIZE;
                        if (newHeight >= minHeight) {
                            element.style.height = newHeight + 'px';
                            element.style.top = (startTop + deltaY) + 'px';
                        }
                    }
                };

                const onResizeUp = () => {
                    document.removeEventListener('mousemove', onResizeMove);
                    document.removeEventListener('mouseup', onResizeUp);
                    if (element === this.panel) {
                        this.saveState();
                    } else if (storageId) {
                        this.savePanelState(element, storageId);
                    }
                };

                handle.addEventListener('mousedown', (e) => {
                    if (this.isLocked) return;
                    startX = e.clientX;
                    startY = e.clientY;
                    startWidth = element.offsetWidth;
                    startHeight = element.offsetHeight;
                    startLeft = element.offsetLeft;
                    startTop = element.offsetTop;
                    e.preventDefault();
                    e.stopPropagation();
                    this._trackDocListener('mousemove', onResizeMove);
                    this._trackDocListener('mouseup', onResizeUp);
                    document.addEventListener('mousemove', onResizeMove);
                    document.addEventListener('mouseup', onResizeUp);
                });
            }

            createControlIcons(content) {
                const controls = document.createElement('div');
                controls.className = 'lucky-content-controls';
                controls.id = 'lucky-content-controls';

                const lockIcon = document.createElement('div');
                lockIcon.className = 'lucky-control-icon';
                lockIcon.id = 'lucky-lock-icon';
                lockIcon.innerHTML = '🔓';
                lockIcon.title = 'Lock panels';
                lockIcon.onclick = () => this.toggleLock();

                const optionsIcon = document.createElement('div');
                optionsIcon.className = 'lucky-control-icon';
                optionsIcon.id = 'lucky-options-icon';
                optionsIcon.innerHTML = '⚙';
                optionsIcon.title = 'Panel options';
                optionsIcon.onclick = () => this.toggleOptions();

                const dragIcon = document.createElement('div');
                dragIcon.className = 'lucky-control-icon';
                dragIcon.id = 'lucky-drag-icon';
                dragIcon.innerHTML = '✥';
                dragIcon.title = 'Drag to reposition panels';
                dragIcon.style.cursor = 'move';

                controls.appendChild(lockIcon);
                controls.appendChild(optionsIcon);
                controls.appendChild(dragIcon);

                content.appendChild(controls);

                this.setupContentDragging(dragIcon);
            }

            createOptionsPanel() {
                const optionsPanel = document.createElement('div');
                optionsPanel.className = 'lucky-options-panel';
                optionsPanel.id = 'lucky-options-panel';

                const statsChecked = this.panelVisibility.stats !== false ? 'checked' : '';
                const revenueChecked = this.panelVisibility.revenue !== false ? 'checked' : '';
                const totalsChecked = this.panelVisibility.totals !== false ? 'checked' : '';
                const bigExpectedChecked = this.panelVisibility.bigExpected !== false ? 'checked' : '';
                const bigLuckChecked = this.panelVisibility.bigLuck !== false ? 'checked' : '';
                const mobExpectedChecked = this.panelVisibility.mobExpected !== false ? 'checked' : '';

                const expected100Checked = this.expected100Mode ? 'checked' : '';

        optionsPanel.innerHTML = `
            <div class="lucky-options-title">Panel Visibility</div>
            <div id="lucky-options-container" class="lucky-options-container">
                <div class="lucky-option-row">
                    <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-stats" data-panel="stats" ${statsChecked}>
                    <label for="lucky-checkbox-stats" class="lucky-option-label">Session Statistics</label>
                </div>
                <div class="lucky-option-row">
                    <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-revenue" data-panel="revenue" ${revenueChecked}>
                    <label for="lucky-checkbox-revenue" class="lucky-option-label">Revenue</label>
                </div>
                <div class="lucky-option-row">
                    <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-totals" data-panel="totals" ${totalsChecked}>
                    <label for="lucky-checkbox-totals" class="lucky-option-label">Totals & Expected</label>
                </div>
                <div class="lucky-option-row">
                    <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-bigExpected" data-panel="bigExpected" ${bigExpectedChecked}>
                    <label for="lucky-checkbox-bigExpected" class="lucky-option-label">Expected</label>
                </div>
                <div class="lucky-option-row">
                    <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-bigLuck" data-panel="bigLuck" ${bigLuckChecked}>
                    <label for="lucky-checkbox-bigLuck" class="lucky-option-label">Luck</label>
                </div>
                <div class="lucky-option-row">
                    <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-mobExpected" data-panel="mobExpected" ${mobExpectedChecked}>
                    <label for="lucky-checkbox-mobExpected" class="lucky-option-label">Mob Expected</label>
                </div>
                <div id="lucky-player-options" style="display: contents;"></div>
            </div>
            <div class="lucky-options-title lucky-options-title-mt">Display Options</div>
            <div class="lucky-option-row">
                <input type="checkbox" id="lucky-checkbox-expected100" ${expected100Checked}>
                <label for="lucky-checkbox-expected100" class="lucky-option-label">100% for Expected (centers on 100% instead of 0%)</label>
            </div>
            <div class="lucky-option-row">
                <input type="checkbox" id="lucky-checkbox-snap-to-grid" ${this.snapToGrid ? 'checked' : ''}>
                <label for="lucky-checkbox-snap-to-grid" class="lucky-option-label">Snap to Grid</label>
            </div>
            <button id="lucky-reset-panels-btn" class="lucky-reset-btn">Reset Panel Positions</button>
            <button id="lucky-auto-grid-btn" class="lucky-auto-grid-btn">Auto Grid (2x4)</button>
                `;

                document.body.appendChild(optionsPanel);

                optionsPanel.querySelectorAll('.lucky-option-checkbox').forEach(checkbox => {
                    checkbox.addEventListener('change', (e) => {
                        const panelId = e.target.getAttribute('data-panel');
                        this.togglePanelVisibility(panelId, e.target.checked);
                    });
                });

                const expected100Checkbox = document.getElementById('lucky-checkbox-expected100');
                if (expected100Checkbox) {
                    expected100Checkbox.addEventListener('change', (e) => {
                        this.expected100Mode = e.target.checked;
                        this.savePanelSettings();
                        this.updateContent();
                    });
                }

                const snapToGridCheckbox = document.getElementById('lucky-checkbox-snap-to-grid');
                if (snapToGridCheckbox) {
                    snapToGridCheckbox.addEventListener('change', (e) => {
                        this.snapToGrid = e.target.checked;
                        this.savePanelSettings();
                    });
                }

                const resetBtn = document.getElementById('lucky-reset-panels-btn');
                if (resetBtn) {
                    resetBtn.addEventListener('click', () => {
                        this.resetPanelPositions();
                    });
                }

                const autoGridBtn = document.getElementById('lucky-auto-grid-btn');
                if (autoGridBtn) {
                    autoGridBtn.addEventListener('click', () => {
                        this.autoGridPanels();
                    });
                }
            }

            setupContentDragging(dragIcon) {
                let startX, startY;

                const onDragMove = (e) => {
                    let newX = e.clientX - startX;
                    let newY = e.clientY - startY;

                    const panelRect = this.panel.getBoundingClientRect();
                    const iconEl = document.getElementById('lucky-drag-icon');
                    const dragIconRect = iconEl?.getBoundingClientRect();

                    if (dragIconRect) {
                        const minX = -dragIconRect.left + panelRect.left;
                        const minY = -dragIconRect.top + panelRect.top;
                        const maxX = window.innerWidth - (dragIconRect.left - panelRect.left) - dragIconRect.width;
                        const maxY = window.innerHeight - (dragIconRect.top - panelRect.top) - dragIconRect.height;
                        newX = Math.max(minX, Math.min(newX, maxX));
                        newY = Math.max(minY, Math.min(newY, maxY));
                    }

                    this.panel.style.left = newX + 'px';
                    this.panel.style.top = newY + 'px';
                    this.panel.style.right = 'auto';
                    this.updateOptionsPanelPosition();
                };

                const onDragUp = () => {
                    document.removeEventListener('mousemove', onDragMove);
                    document.removeEventListener('mouseup', onDragUp);
                    dragIcon.style.cursor = 'move';
                    this.saveState();
                };

                dragIcon.addEventListener('mousedown', (e) => {
                    const rect = this.panel.getBoundingClientRect();
                    startX = e.clientX - rect.left;
                    startY = e.clientY - rect.top;
                    dragIcon.style.cursor = 'grabbing';
                    e.preventDefault();
                    e.stopPropagation();
                    this._trackDocListener('mousemove', onDragMove);
                    this._trackDocListener('mouseup', onDragUp);
                    document.addEventListener('mousemove', onDragMove);
                    document.addEventListener('mouseup', onDragUp);
                });
            }

            updateOptionsPanelPosition() {
                const optionsPanel = document.getElementById('lucky-options-panel');
                if (!optionsPanel || !this.panel) return;

                const rect = this.panel.getBoundingClientRect();
                const optionsRect = optionsPanel.getBoundingClientRect();

                optionsPanel.style.left = rect.left + 'px';
                optionsPanel.style.top = (rect.top - optionsRect.height - 4) + 'px';
                optionsPanel.style.width = rect.width + 'px';
            }

            toggleLock() {
                this.isLocked = !this.isLocked;
                const lockIcon = document.getElementById('lucky-lock-icon');
                if (lockIcon) {
                    lockIcon.innerHTML = this.isLocked ? '🔒' : '🔓';
                    lockIcon.title = this.isLocked ? 'Unlock panels' : 'Lock panels';
                    if (this.isLocked) {
                        lockIcon.classList.add('active');
                    } else {
                        lockIcon.classList.remove('active');
                    }
                }

                const allPanels = document.querySelectorAll('.lucky-floating-panel');
                allPanels.forEach(panel => {
                    if (this.isLocked) {
                        panel.style.pointerEvents = 'none';
                    } else {
                        panel.style.pointerEvents = 'auto';
                    }
                });

                this.savePanelSettings();
            }

            applyLockState() {
                const lockIcon = document.getElementById('lucky-lock-icon');
                if (lockIcon) {
                    lockIcon.innerHTML = this.isLocked ? '🔒' : '🔓';
                    lockIcon.title = this.isLocked ? 'Unlock panels' : 'Lock panels';
                    if (this.isLocked) {
                        lockIcon.classList.add('active');
                    } else {
                        lockIcon.classList.remove('active');
                    }
                }

                const allPanels = document.querySelectorAll('.lucky-floating-panel');
                allPanels.forEach(panel => {
                    if (this.isLocked) {
                        panel.style.pointerEvents = 'none';
                    } else {
                        panel.style.pointerEvents = 'auto';
                    }
                });
            }

            toggleOptions() {
                const optionsPanel = document.getElementById('lucky-options-panel');
                const optionsIcon = document.getElementById('lucky-options-icon');

                if (optionsPanel) {
                    optionsPanel.classList.toggle('visible');
                    if (optionsIcon) {
                        if (optionsPanel.classList.contains('visible')) {
                            optionsIcon.classList.add('active');
                            this.updateOptionsPanelPosition();
                        } else {
                            optionsIcon.classList.remove('active');
                        }
                    }
                }
            }

            togglePanelVisibility(panelId, visible) {
                this.panelVisibility[panelId] = visible;

                let panel;
                if (panelId === 'stats') {
                    panel = document.getElementById('lucky-stats-panel');
                } else if (panelId === 'revenue') {
                    panel = document.getElementById('lucky-revenue-panel');
                } else if (panelId === 'totals') {
                    panel = document.getElementById('lucky-totals-panel');
                } else if (panelId === 'bigExpected') {
                    panel = document.getElementById('lucky-big-expected-panel');
                } else if (panelId === 'bigLuck') {
                    panel = document.getElementById('lucky-big-luck-panel');
                } else if (panelId === 'mobExpected') {
                    panel = document.getElementById('lucky-mob-expected-panel');
                } else if (panelId.startsWith('player-')) {
                    const playerName = panelId.replace('player-', '');
                    panel = document.getElementById(`lucky-player-panel-${playerName}`);
                }

                if (panel) {
                    panel.style.display = visible ? 'block' : 'none';
                }

                this.savePanelSettings();
            }

            savePanelSettings() {
                const settings = {
                    isLocked: this.isLocked,
                    panelVisibility: this.panelVisibility,
                    expected100Mode: this.expected100Mode,
                    snapToGrid: this.snapToGrid
                };
                this.lyStorage.set('settings', settings);
            }

            loadPanelSettings() {
                try {
                    const settings = this.lyStorage.get('settings');
                    if (settings) {
                        if (settings.isLocked !== undefined) {
                            this.isLocked = settings.isLocked;
                        }
                        if (settings.panelVisibility) {
                            this.panelVisibility = { ...this.panelVisibility, ...settings.panelVisibility };
                        }
                        if (settings.expected100Mode !== undefined) {
                            this.expected100Mode = settings.expected100Mode;
                        }
                        if (settings.snapToGrid !== undefined) {
                            this.snapToGrid = settings.snapToGrid;
                        }
                    }
                } catch (e) {
                }
            }

            setupResizeObserver() {
                let resizeTimeout;
                const resizeObserver = new ResizeObserver(() => {
                    this.updateOptionsPanelPosition();

                    clearTimeout(resizeTimeout);
                    resizeTimeout = setTimeout(() => {
                        this.saveState();
                    }, 500);
                });
                resizeObserver.observe(this.panel);
                if (!this._luckyResizeObservers) this._luckyResizeObservers = [];
                this._luckyResizeObservers.push(resizeObserver);
            }

            show() {
                this.panel.style.display = 'block';
                this.updateContent();
                this.updateOptionsPanelPosition();
                this.saveState();
            }

            hide() {
                this.panel.style.display = 'none';
                const optionsPanel = document.getElementById('lucky-options-panel');
                if (optionsPanel) {
                    optionsPanel.classList.remove('visible');
                    const optionsIcon = document.getElementById('lucky-options-icon');
                    if (optionsIcon) {
                        optionsIcon.classList.remove('active');
                    }
                }
                this.saveState();
            }

            startAutoUpdate() {
                this.updateContent();

                VisibilityManager.register('lucky-update', () => {
                    this.updateContent();
                }, 5000);
            }

            updateContent() {
                const content = document.getElementById('lucky-content');
                if (!content) return;

                const sessionTime = FlootData.getSessionTime();
                const playerNames = FlootData.getAllPlayerNames();

                const hasData = playerNames.length > 0 && sessionTime > 0;

                const effectivePlayerNames = hasData ? playerNames : [];
                const playerNamesChanged = JSON.stringify(effectivePlayerNames) !== JSON.stringify(this.lastPlayerNames);
                if (playerNamesChanged || !document.getElementById('lucky-stats-panel')) {
                    this.ensurePanelsExist(effectivePlayerNames);
                    this.lastPlayerNames = [...effectivePlayerNames];
                }

                const oldNoDataMsg = content.querySelector('.lucky-no-data');
                if (oldNoDataMsg) {
                    oldNoDataMsg.remove();
                }

                if (!hasData) {
                    this.updateStatsPanelEmpty();
                    this.updateRevenuePanelEmpty();
                    this.updateBigExpectedPanelEmpty();
                    this.updateBigLuckPanelEmpty();
                    this.updateTotalsPanelEmpty();
                    this.updateMobExpectedPanelEmpty();
                    return;
                }

                const dropsData = this.calculateDropsData(playerNames);

                this.updateStatsPanel();
                this.updateMobExpectedPanel();
                this.updateRevenuePanel(playerNames, dropsData);
                this.updateBigExpectedPanel(playerNames, dropsData);
                this.updateBigLuckPanel(playerNames, dropsData);
                this.updatePlayerPanels(playerNames, dropsData);
                this.updateTotalsPanel(playerNames, dropsData);
            }

            updateStatsPanelEmpty() {
                const statsContent = document.getElementById('lucky-stats-content');
                if (statsContent) {
                    statsContent.innerHTML = '<div class="lucky-empty-state">Waiting for combat...</div>';
                }
            }

            updateRevenuePanelEmpty() {
                const revenueContent = document.getElementById('lucky-revenue-content');
                if (revenueContent) {
                    revenueContent.innerHTML = '<div class="lucky-empty-state">--</div>';
                }
            }

            updateBigExpectedPanelEmpty() {
                const expectedContent = document.getElementById('lucky-big-expected-content');
                if (expectedContent) {
                    expectedContent.innerHTML = '<div class="lucky-empty-state">--</div>';
                }
            }

            updateBigLuckPanelEmpty() {
                const luckContent = document.getElementById('lucky-big-luck-content');
                if (luckContent) {
                    luckContent.innerHTML = '<div class="lucky-empty-state">--</div>';
                }
            }

            updateTotalsPanelEmpty() {
                const totalsContent = document.getElementById('lucky-totals-content');
                if (totalsContent) {
                    totalsContent.innerHTML = '<tr><td colspan="6" class="lucky-empty-state">--</td></tr>';
                }
            }

            ensurePanelsExist(playerNames) {
                const content = document.getElementById('lucky-content');
                if (!content) return;

                if (!document.getElementById('lucky-stats-panel')) {
                    const statsPanel = document.createElement('div');
                    statsPanel.id = 'lucky-stats-panel';
                    statsPanel.className = 'lucky-floating-panel lucky-stats-section';
            statsPanel.innerHTML = `
                <div class="lucky-stats-header" data-panel-id="stats">
                    <div class="lucky-stats-title">Session Statistics</div>
                </div>
                <div id="lucky-stats-content"></div>
                    `;
                    statsPanel.style.display = this.panelVisibility.stats !== false ? 'block' : 'none';
                    content.appendChild(statsPanel);
                    this.setupPanelDragging('lucky-stats-panel', 'stats');
                }

                for (const [playerName, panelRef] of this.playerPanels) {
                    if (!playerNames.includes(playerName)) {
                        if (panelRef && panelRef.parentNode) {
                            panelRef.remove();
                        }
                        this.playerPanels.delete(playerName);
                    }
                }

                playerNames.forEach((playerName, index) => {
                    if (!this.playerPanels.has(playerName)) {
                        const playerPanel = document.createElement('div');
                        playerPanel.id = `lucky-player-panel-${playerName}`;
                        playerPanel.className = 'lucky-floating-panel lucky-data-panel';
                        const defaultLeft = 60 + (index * 50);
                        const defaultTop = 100 + (index * 50);
                        playerPanel.style.left = defaultLeft + 'px';
                        playerPanel.style.top = defaultTop + 'px';
                        playerPanel.style.height = '500px';
                playerPanel.innerHTML = `
                    <div class="lucky-panel-header">
                        <div class="lucky-stats-header" data-panel-id="player-${playerName}">
                            <div class="lucky-stats-title">${playerName}</div>
                        </div>
                        <div id="lucky-player-stats-${playerName}" class="lucky-player-stats-info"></div>
                        <table class="lucky-drop-table">
                            <thead>
                                <tr>
                                    <th>Item</th>
                                    <th>Qty</th>
                                    <th>Value</th>
                                    <th colspan="2">Expected</th>
                                </tr>
                            </thead>
                        </table>
                    </div>
                    <div class="lucky-panel-content-scrollable">
                        <table class="lucky-drop-table">
                            <tbody id="lucky-player-content-${playerName}"></tbody>
                        </table>
                    </div>
                        `;
                        const panelId = `player-${playerName}`;
                        if (this.panelVisibility[panelId] === undefined) {
                            this.panelVisibility[panelId] = true;
                        }
                        playerPanel.style.display = this.panelVisibility[panelId] !== false ? 'block' : 'none';
                        content.appendChild(playerPanel);
                        this.setupPanelDragging(`lucky-player-panel-${playerName}`, `player-${playerName}`);

                        this.playerPanels.set(playerName, playerPanel);
                    }
                });

                if (!document.getElementById('lucky-revenue-panel')) {
                    const revenuePanel = document.createElement('div');
                    revenuePanel.id = 'lucky-revenue-panel';
                    revenuePanel.className = 'lucky-floating-panel lucky-revenue-panel';
                    revenuePanel.style.left = '300px';
                    revenuePanel.style.top = '60px';
            revenuePanel.innerHTML = `
                <div class="lucky-stats-header" data-panel-id="revenue">
                    <div class="lucky-stats-title">Revenue</div>
                </div>
                <div id="lucky-revenue-content"></div>
                    `;
                    revenuePanel.style.display = this.panelVisibility.revenue !== false ? 'block' : 'none';
                    content.appendChild(revenuePanel);
                    this.setupPanelDragging('lucky-revenue-panel', 'revenue');
                }

                if (!document.getElementById('lucky-big-expected-panel')) {
                    const bigExpectedPanel = document.createElement('div');
                    bigExpectedPanel.id = 'lucky-big-expected-panel';
                    bigExpectedPanel.className = 'lucky-floating-panel lucky-big-expected-panel';
                    bigExpectedPanel.style.left = '600px';
                    bigExpectedPanel.style.top = '60px';
            bigExpectedPanel.innerHTML = `
                <div class="lucky-big-expected-header">
                    <div class="lucky-stats-header" data-panel-id="bigExpected">
                        <div class="lucky-stats-title">Expected</div>
                    </div>
                </div>
                <div id="lucky-big-expected-content" class="lucky-big-expected-content"></div>
                    `;
                    bigExpectedPanel.style.display = this.panelVisibility.bigExpected !== false ? 'block' : 'none';
                    content.appendChild(bigExpectedPanel);
                    this.setupPanelDragging('lucky-big-expected-panel', 'bigExpected');
                }

                if (!document.getElementById('lucky-big-luck-panel')) {
                    const bigLuckPanel = document.createElement('div');
                    bigLuckPanel.id = 'lucky-big-luck-panel';
                    bigLuckPanel.className = 'lucky-floating-panel lucky-big-luck-panel';
                    bigLuckPanel.style.left = '1020px';
                    bigLuckPanel.style.top = '60px';
            bigLuckPanel.innerHTML = `
                <div class="lucky-big-luck-header">
                    <div class="lucky-stats-header" data-panel-id="bigLuck">
                        <div class="lucky-stats-title">Luck</div>
                    </div>
                </div>
                <div id="lucky-big-luck-content" class="lucky-big-luck-content"></div>
                    `;
                    bigLuckPanel.style.display = this.panelVisibility.bigLuck !== false ? 'block' : 'none';
                    content.appendChild(bigLuckPanel);
                    this.setupPanelDragging('lucky-big-luck-panel', 'bigLuck');
                }

                if (!document.getElementById('lucky-mob-expected-panel')) {
                    const mobExpectedPanel = document.createElement('div');
                    mobExpectedPanel.id = 'lucky-mob-expected-panel';
                    mobExpectedPanel.className = 'lucky-floating-panel lucky-stats-section';
            mobExpectedPanel.innerHTML = `
                <div class="lucky-stats-header" data-panel-id="mobExpected">
                    <div class="lucky-stats-title">Mob Expected</div>
                </div>
                <div id="lucky-mob-expected-content"></div>
                    `;
                    mobExpectedPanel.style.display = this.panelVisibility.mobExpected !== false ? 'block' : 'none';
                    content.appendChild(mobExpectedPanel);
                    this.setupPanelDragging('lucky-mob-expected-panel', 'mobExpected');
                }

                if (!document.getElementById('lucky-totals-panel')) {
                    const totalsPanel = document.createElement('div');
                    totalsPanel.id = 'lucky-totals-panel';
                    totalsPanel.className = 'lucky-floating-panel lucky-data-panel';
                    const defaultLeft = 60 + (playerNames.length * 50);
                    const defaultTop = 100 + (playerNames.length * 50);
                    totalsPanel.style.left = defaultLeft + 'px';
                    totalsPanel.style.top = defaultTop + 'px';
                    totalsPanel.style.height = '500px';
            totalsPanel.innerHTML = `
                <div class="lucky-panel-header">
                    <div class="lucky-stats-header" data-panel-id="totals">
                        <div class="lucky-stats-title">Totals & Expected</div>
                    </div>
                    <table class="lucky-drop-table">
                        <thead>
                            <tr>
                                <th>Item</th>
                                <th>Total Qty</th>
                                <th>Total Value</th>
                                <th>%</th>
                                <th colspan="2">Expected</th>
                            </tr>
                        </thead>
                    </table>
                </div>
                <div class="lucky-panel-content-scrollable">
                    <table class="lucky-drop-table">
                        <tbody id="lucky-totals-content"></tbody>
                    </table>
                </div>
                    `;
                    totalsPanel.style.display = this.panelVisibility.totals !== false ? 'block' : 'none';
                    content.appendChild(totalsPanel);
                    this.setupPanelDragging('lucky-totals-panel', 'totals');
                }

                this.updatePlayerOptions(playerNames);

                this.applyVisibilitySettings();
            }

            updatePlayerOptions(playerNames) {
                const playerOptionsContainer = document.getElementById('lucky-player-options');
                if (!playerOptionsContainer) return;

                playerOptionsContainer.innerHTML = '';

                playerNames.forEach(playerName => {
                    const panelId = `player-${playerName}`;
                    if (this.panelVisibility[panelId] === undefined) {
                        this.panelVisibility[panelId] = true;
                    }

                    const optionRow = document.createElement('div');
                    optionRow.className = 'lucky-option-row';
            optionRow.innerHTML = `
                <input type="checkbox" class="lucky-option-checkbox" id="lucky-checkbox-${panelId}" data-panel="${panelId}" ${this.panelVisibility[panelId] ? 'checked' : ''}>
                <label for="lucky-checkbox-${panelId}" class="lucky-option-label">${playerName}</label>
                    `;
                    playerOptionsContainer.appendChild(optionRow);

                    const checkbox = optionRow.querySelector('.lucky-option-checkbox');
                    checkbox.addEventListener('change', (e) => {
                        this.togglePanelVisibility(panelId, e.target.checked);
                    });
                });
            }

            applyVisibilitySettings() {
                for (const [panelId, visible] of Object.entries(this.panelVisibility)) {
                    let panel;
                    if (panelId === 'stats') {
                        panel = document.getElementById('lucky-stats-panel');
                    } else if (panelId === 'revenue') {
                        panel = document.getElementById('lucky-revenue-panel');
                    } else if (panelId === 'totals') {
                        panel = document.getElementById('lucky-totals-panel');
                    } else if (panelId === 'bigExpected') {
                        panel = document.getElementById('lucky-big-expected-panel');
                    } else if (panelId === 'bigLuck') {
                        panel = document.getElementById('lucky-big-luck-panel');
                    } else if (panelId === 'mobExpected') {
                        panel = document.getElementById('lucky-mob-expected-panel');
                    } else if (panelId.startsWith('player-')) {
                        const playerName = panelId.replace('player-', '');
                        panel = document.getElementById(`lucky-player-panel-${playerName}`);
                    }

                    if (panel) {
                        panel.style.display = visible ? 'block' : 'none';
                    }
                }
            }

            calculatePercentOfExpected(actual, expected) {
                if (expected <= 0) return 0;
                const basePercent = ((actual / expected) - 1) * 100;
                return this.expected100Mode ? basePercent + 100 : basePercent;
            }

            calculateDropsData(playerNames) {
                return this._calculateDropsDataImpl(playerNames);
            }

            _calculateDropsDataImpl(playerNames) {
                const battleCount = FlootData.getBattleCount();
                const currentMapHrid = LuckyGameData.currentMapHrid;
                const currentTier = LuckyGameData.currentDifficultyTier;
                const partySize = FlootData.getPartySize();
                const runCount = battleCount;

                const cacheKey = `${currentMapHrid}|${battleCount}|${currentTier}|${partySize}`;
                let expectedDropsTotal, maximumDropsTotal;

                if (this.lastDropsCacheKey === cacheKey && this.cachedExpectedDrops && this.cachedMaximumDrops) {
                    expectedDropsTotal = this.cachedExpectedDrops;
                    maximumDropsTotal = this.cachedMaximumDrops;
                } else {
                    expectedDropsTotal = LuckyDropAnalyzer.calculateExpectedDrops(
                        currentMapHrid,
                        runCount,
                        currentTier,
                        partySize
                    );

                    maximumDropsTotal = LuckyDropAnalyzer.calculateMaximumDrops(
                        currentMapHrid,
                        runCount,
                        currentTier,
                        partySize
                    );

                    this.cachedExpectedDrops = expectedDropsTotal;
                    this.cachedMaximumDrops = maximumDropsTotal;
                    this.lastDropsCacheKey = cacheKey;
                }

                const allItems = new Set();
                const playerDropsData = {};

                playerNames.forEach(playerName => {
                    const drops = FlootData.getPlayerDrops(playerName);
                    playerDropsData[playerName] = drops;
                    for (const itemHrid of Object.keys(drops)) {
                        allItems.add(itemHrid);
                    }
                });

                for (const itemHrid of Object.keys(expectedDropsTotal)) {
                    const dropData = expectedDropsTotal[itemHrid];
                    const expectedCount = typeof dropData === 'number' ? dropData : dropData.count;
                    if (expectedCount > 0) {
                        allItems.add(itemHrid);
                    }
                }

                const mapType = LuckyGameData.mapData[LuckyGameData.currentMapHrid]?.type || 'solo';

                const dropsList = [];
                for (const itemHrid of allItems) {
                    const itemName = LuckyUtils.getItemName(itemHrid);
                    const itemPrice = LuckyUtils.getItemValue(itemHrid, 1);

                    const dropData = expectedDropsTotal[itemHrid] || { count: 0, tierDropRate: 1.0, isRare: false };
                    const baseExpectedTotal = typeof dropData === 'number' ? dropData : dropData.count;
                    const tierDropRate = typeof dropData === 'object' ? dropData.tierDropRate : 1.0;
                    const isRareItem = typeof dropData === 'object' ? dropData.isRare : false;

                    const maxDropData = maximumDropsTotal[itemHrid] || { count: 0, tierDropRate: 1.0 };
                    const baseMaximumTotal = typeof maxDropData === 'number' ? maxDropData : maxDropData.count;

                    const playerStatsData = {};
                    let totalActualValue = 0;
                    let totalActualQty = 0;
                    let totalExpectedQty = 0;
                    let totalExpectedValue = 0;

                    for (let i = 0; i < playerNames.length; i++) {
                        const playerName = playerNames[i];
                        const actualCount = playerDropsData[playerName][itemHrid] || 0;
                        const actualValue = actualCount * itemPrice;

                        const stats = LuckyGameData.playerStats[playerName];
                        let playerExpected = baseExpectedTotal;
                        let playerMaximum = baseMaximumTotal;

                        if (stats) {
                            const commonRateMultiplier = 1 + (stats.combatDropRate || 0);
                            const rareRateMultiplier = 1 + (stats.combatRareFind || 0);
                            const rateMultiplier = isRareItem ? rareRateMultiplier : commonRateMultiplier;

                            const dungeonMultiplier = mapType === 'dungeon' ? 5 : 1;
                            const quantityMultiplier = (1 + stats.combatDropQuantity) / playerNames.length * dungeonMultiplier;
                            playerExpected = playerExpected * rateMultiplier * quantityMultiplier;
                            playerMaximum = playerMaximum * rateMultiplier * quantityMultiplier;
                        } else {
                            const dungeonMultiplier = mapType === 'dungeon' ? 5 : 1;
                            playerExpected = playerExpected / playerNames.length * dungeonMultiplier;
                            playerMaximum = playerMaximum / playerNames.length * dungeonMultiplier;
                        }

                        const playerExpectedValue = playerExpected * itemPrice;
                        const playerMaximumValue = playerMaximum * itemPrice;
                        const percentOfExpected = this.calculatePercentOfExpected(actualCount, playerExpected);

                        if (i === 0) {
                            const itemName = itemHrid.split('/').pop();
                        }

                        playerStatsData[playerName] = {
                            actualCount,
                            actualValue,
                            expectedCount: playerExpected,
                            expectedValue: playerExpectedValue,
                            percentOfExpected,
                            maximumCount: playerMaximum,
                            maximumValue: playerMaximumValue
                        };

                        totalActualValue += actualValue;
                        totalActualQty += actualCount;
                        totalExpectedQty += playerExpected;
                        totalExpectedValue += playerExpectedValue;
                    }

                    const totalPercentOfExpected = this.calculatePercentOfExpected(totalActualQty, totalExpectedQty);

                    dropsList.push({
                        itemHrid,
                        itemName,
                        expectedCountTotal: totalExpectedQty,
                        expectedValueTotal: totalExpectedValue,
                        totalPercentOfExpected,
                        playerStats: playerStatsData,
                        totalActualValue,
                        totalActualQty
                    });
                }

                dropsList.sort((a, b) => b.totalActualValue - a.totalActualValue);

                return { dropsList, playerDropsData, expectedDropsTotal };
            }

            updateStatsPanel() {
                return this._updateStatsPanelImpl();
            }

            _updateStatsPanelImpl() {
                if (this.panelVisibility.stats === false) return;

                const statsContent = document.getElementById('lucky-stats-content');
                if (!statsContent) return;

                if (!this.statsElements) {
            statsContent.innerHTML = `
                <div class="lucky-stat-row">
                    <span class="lucky-stat-label">Encounters:</span>
                    <span class="lucky-stat-value" id="lucky-stat-encounters"></span>
                </div>
                <div class="lucky-stat-row">
                    <span class="lucky-stat-label">Session Time:</span>
                    <span class="lucky-stat-value" id="lucky-stat-time"></span>
                </div>
                <div class="lucky-stat-row">
                    <span class="lucky-stat-label">EPH:</span>
                    <span class="lucky-stat-value" id="lucky-stat-eph"></span>
                </div>
                    `;
                    this.statsElements = {
                        encounters: document.getElementById('lucky-stat-encounters'),
                        time: document.getElementById('lucky-stat-time'),
                        eph: document.getElementById('lucky-stat-eph')
                    };
                }

                const battleCount = FlootData.getBattleCount();
                const sessionTime = FlootData.getSessionTime();
                const eph = FlootData.getEPH();

                this.statsElements.encounters.textContent = battleCount;
                this.statsElements.time.textContent = LuckyUtils.formatTime(sessionTime);
                this.statsElements.eph.textContent = eph.toFixed(2);
            }

            updateMobExpectedPanelEmpty() {
                const content = document.getElementById('lucky-mob-expected-content');
                if (content) {
                    content.innerHTML = '<div class="lucky-empty-state">Waiting for combat...</div>';
                }
            }

            updateMobExpectedPanel() {
                if (this.panelVisibility.mobExpected === false) return;

                const content = document.getElementById('lucky-mob-expected-content');
                if (!content) return;

                const currentMapHrid = LuckyGameData.currentMapHrid;
                const mapData = LuckyGameData.mapData[currentMapHrid];
                if (!mapData || !mapData.spawnInfo) {
                    content.innerHTML = '<div class="lucky-empty-state">No map data</div>';
                    return;
                }

                const spawnInfo = mapData.spawnInfo;
                const battleCount = FlootData.getBattleCount();
                const expectedSpawns = LuckyDropAnalyzer.computeExpectedSpawns(spawnInfo);

                let bossWave = spawnInfo.bossWave || 0;
                if (!bossWave && mapData.type === 'dungeon') {
                    bossWave = 1;
                } else if (!bossWave && mapData.type === 'group' && mapData.bossDrops && Object.keys(mapData.bossDrops).length > 0) {
                    bossWave = 10;
                }
                const bossCount = bossWave ? Math.floor((battleCount - 1) / bossWave) : 0;
                const normalCount = bossWave ?
                    bossCount * (bossWave - 1) + (battleCount - 1) % bossWave :
                    battleCount - 1;

                let html = '';

                for (const [monsterHrid, spawnRate] of Object.entries(expectedSpawns)) {
                    const expectedCount = spawnRate * normalCount;
                    const mobName = LuckyGameData.monsterNames[monsterHrid] || monsterHrid.split('/').pop();
            html += `
                <div class="lucky-stat-row">
                    <span class="lucky-stat-label">${mobName}:</span>
                    <span class="lucky-stat-value">${LuckyUtils.formatNumber(expectedCount)}</span>
                </div>
                    `;
                }

                if (mapData.bossDrops) {
                    for (const bossHrid of Object.keys(mapData.bossDrops)) {
                        const bossName = bossHrid === '_dungeon'
                            ? 'Dungeon Boss'
                            : (LuckyGameData.monsterNames[bossHrid] || bossHrid.split('/').pop());
                html += `
                    <div class="lucky-stat-row">
                        <span class="lucky-stat-label">${bossName}:</span>
                        <span class="lucky-stat-value">${LuckyUtils.formatNumber(bossCount)}</span>
                    </div>
                        `;
                    }
                }

                if (!html) {
                    html = '<div class="lucky-empty-state">No mob data</div>';
                }

                content.innerHTML = html;
            }

            updateRevenuePanel(playerNames, dropsData) {
                return this._updateRevenuePanelImpl(playerNames, dropsData);
            }

            _updateRevenuePanelImpl(playerNames, dropsData) {
                if (this.panelVisibility.revenue === false) return;

                const revenueContent = document.getElementById('lucky-revenue-content');
                if (!revenueContent) return;

                if (!LuckyGameData.hasReceivedFirstBattle) {
                    let html = '';
                    playerNames.forEach(playerName => {
                html += `
                    <div class="lucky-revenue-row-container">
                        <div class="lucky-revenue-row">
                            <div class="lucky-revenue-name">${playerName}</div>
                            <div class="lucky-revenue-stats-group">
                                <div class="lucky-revenue-stat">
                                    <span class="lucky-revenue-stat-label">Expected</span>
                                    <span class="lucky-revenue-stat-value">--</span>
                                </div>
                                <div class="lucky-revenue-stat">
                                    <span class="lucky-revenue-stat-label">Actual</span>
                                    <span class="lucky-revenue-stat-value">--</span>
                                </div>
                                <div class="lucky-revenue-stat">
                                    <span class="lucky-revenue-stat-label">Max</span>
                                    <span class="lucky-revenue-stat-value">--</span>
                                </div>
                            </div>
                            <span class="lucky-revenue-stat-value">--</span>
                        </div>
                    </div>
                        `;
                    });
            html += `
                <div class="lucky-revenue-row-container">
                    <div class="lucky-revenue-row">
                        <div class="lucky-revenue-name">TOTAL</div>
                        <div class="lucky-revenue-stats-group">
                            <div class="lucky-revenue-stat">
                                <span class="lucky-revenue-stat-label">Expected</span>
                                <span class="lucky-revenue-stat-value">--</span>
                            </div>
                            <div class="lucky-revenue-stat">
                                <span class="lucky-revenue-stat-label">Actual</span>
                                <span class="lucky-revenue-stat-value">--</span>
                            </div>
                            <div class="lucky-revenue-stat">
                                <span class="lucky-revenue-stat-label">Max</span>
                                <span class="lucky-revenue-stat-value">--</span>
                            </div>
                        </div>
                        <span class="lucky-revenue-stat-value">--</span>
                    </div>
                </div>
                    `;
                    revenueContent.innerHTML = html;
                    return;
                }

                const { dropsList } = dropsData;

                let html = '';

                playerNames.forEach((playerName) => {
                    let playerActual = 0;
                    let playerExpected = 0;
                    let playerActualQty = 0;
                    let playerExpectedQty = 0;
                    let playerMaximumQty = 0;
                    let playerMaximumValue = 0;

                    for (const drop of dropsList) {
                        const playerStats = drop.playerStats[playerName];
                        if (playerStats) {
                            playerActual += playerStats.actualValue;
                            playerExpected += playerStats.expectedValue;
                            playerActualQty += playerStats.actualCount;
                            playerExpectedQty += playerStats.expectedCount;
                            playerMaximumQty += playerStats.maximumCount;
                            playerMaximumValue += playerStats.maximumValue;
                        }
                    }

                    const percentDiff = this.calculatePercentOfExpected(playerActual, playerExpected);
                    const sign = this.expected100Mode ? '' : (percentDiff > 0 ? '+' : '');
                    const color = LuckyUtils.getPercentColor(percentDiff, this.expected100Mode);

            html += `
                <div class="lucky-revenue-row-container">
                    <div class="lucky-revenue-row">
                        <div class="lucky-revenue-name">${playerName}</div>
                        <div class="lucky-revenue-stats-group">
                            <div class="lucky-revenue-stat">
                                <span class="lucky-revenue-stat-label">Expected</span>
                                <span class="lucky-revenue-stat-value">${LuckyUtils.formatNumber(playerExpected)}</span>
                            </div>
                            <div class="lucky-revenue-stat">
                                <span class="lucky-revenue-stat-label">Actual</span>
                                <span class="lucky-revenue-stat-value">${LuckyUtils.formatNumber(playerActual)}</span>
                            </div>
                            <div class="lucky-revenue-stat">
                                <span class="lucky-revenue-stat-label">Max</span>
                                <span class="lucky-revenue-stat-value">${LuckyUtils.formatNumber(playerMaximumValue)}</span>
                            </div>
                        </div>
                        <span class="lucky-revenue-stat-value colored" style="color: ${color};">${sign}${percentDiff.toFixed(1)}%</span>
                    </div>
                </div>
                    `;
                });

                let totalActual = 0;
                let totalExpected = 0;
                let totalActualQty = 0;
                let totalMaximumQty = 0;
                let totalMaximumValue = 0;

                for (const drop of dropsList) {
                    totalActual += drop.totalActualValue;
                    totalExpected += drop.expectedValueTotal;
                    totalActualQty += drop.totalActualQty;

                    for (const playerName of playerNames) {
                        const playerStats = drop.playerStats[playerName];
                        if (playerStats) {
                            totalMaximumQty += playerStats.maximumCount;
                            totalMaximumValue += playerStats.maximumValue;
                        }
                    }
                }

                const totalPercentDiff = this.calculatePercentOfExpected(totalActual, totalExpected);
                const totalSign = this.expected100Mode ? '' : (totalPercentDiff > 0 ? '+' : '');
                const totalColor = LuckyUtils.getPercentColor(totalPercentDiff, this.expected100Mode);

        html += `
            <div class="lucky-revenue-row-container">
                <div class="lucky-revenue-row">
                    <div class="lucky-revenue-name">TOTAL</div>
                    <div class="lucky-revenue-stats-group">
                        <div class="lucky-revenue-stat">
                            <span class="lucky-revenue-stat-label">Expected</span>
                            <span class="lucky-revenue-stat-value">${LuckyUtils.formatNumber(totalExpected)}</span>
                        </div>
                        <div class="lucky-revenue-stat">
                            <span class="lucky-revenue-stat-label">Actual</span>
                            <span class="lucky-revenue-stat-value">${LuckyUtils.formatNumber(totalActual)}</span>
                        </div>
                        <div class="lucky-revenue-stat">
                            <span class="lucky-revenue-stat-label">Max</span>
                            <span class="lucky-revenue-stat-value">${LuckyUtils.formatNumber(totalMaximumValue)}</span>
                        </div>
                    </div>
                    <span class="lucky-revenue-stat-value colored" style="color: ${totalColor};">${totalSign}${totalPercentDiff.toFixed(1)}%</span>
                </div>
            </div>
                `;

                revenueContent.innerHTML = html;
            }

            updateBigExpectedPanel(playerNames, dropsData) {
                return this._updateBigExpectedPanelImpl(playerNames, dropsData);
            }

            _updateBigExpectedPanelImpl(playerNames, dropsData) {
                const bigExpectedContent = document.getElementById('lucky-big-expected-content');
                if (!bigExpectedContent) return;

                if (!LuckyGameData.hasReceivedFirstBattle) {
                    let html = '';
                    playerNames.forEach(playerName => {
                html += `
                    <div class="lucky-big-expected-item">
                        <span class="lucky-big-expected-name">${playerName}</span>
                        <span class="lucky-big-expected-percent">--</span>
                    </div>
                        `;
                    });
            html += `
                <div class="lucky-big-expected-item lucky-big-expected-total">
                    <span class="lucky-big-expected-name">TOTAL</span>
                    <span class="lucky-big-expected-percent">--</span>
                </div>
                    `;
                    bigExpectedContent.innerHTML = html;
                    return;
                }

                const { dropsList } = dropsData;

                let html = '';
                let totalActual = 0;
                let totalExpected = 0;

                playerNames.forEach(playerName => {
                    let playerActual = 0;
                    let playerExpected = 0;

                    for (const drop of dropsList) {
                        const playerStats = drop.playerStats[playerName];
                        if (playerStats) {
                            playerActual += playerStats.actualValue;
                            playerExpected += playerStats.expectedValue;
                        }
                    }

                    totalActual += playerActual;
                    totalExpected += playerExpected;

                    const percentDiff = this.calculatePercentOfExpected(playerActual, playerExpected);
                    const sign = this.expected100Mode ? '' : (percentDiff > 0 ? '+' : '');
                    const color = LuckyUtils.getPercentColor(percentDiff, this.expected100Mode);

            html += `
                <div class="lucky-big-expected-item">
                    <span class="lucky-big-expected-name">${playerName}</span>
                    <span class="lucky-big-expected-percent" style="color: ${color};">${sign}${percentDiff.toFixed(1)}%</span>
                </div>
                    `;
                });

                const totalPercentDiff = this.calculatePercentOfExpected(totalActual, totalExpected);
                const totalSign = this.expected100Mode ? '' : (totalPercentDiff > 0 ? '+' : '');
                const totalColor = LuckyUtils.getPercentColor(totalPercentDiff, this.expected100Mode);

        html += `
            <div class="lucky-big-expected-item lucky-big-expected-total">
                <span class="lucky-big-expected-name">TOTAL</span>
                <span class="lucky-big-expected-percent" style="color: ${totalColor};">${totalSign}${totalPercentDiff.toFixed(1)}%</span>
            </div>
                `;

                bigExpectedContent.innerHTML = html;
            }

            getDropData(playerName = null, battleCount = 1) {
                const mapData = LuckyGameData.mapData[LuckyGameData.currentMapHrid];
                if (!mapData) return null;

                const spawnInfo = mapData.spawnInfo;
                const difficultyTier = LuckyGameData.currentDifficultyTier;
                const partySize = Object.keys(LuckyGameData.playerStats).length || 1;
                const playerStats = playerName ? LuckyGameData.playerStats[playerName] : null;

                const bossWave = spawnInfo.bossWave || 0;
                const bossCount = bossWave ? Math.floor((battleCount - 1) / bossWave) + 1 : (mapData.type === 'dungeon' ? battleCount : 0);
                const normalCount = bossWave ? bossCount * (bossWave - 1) + (battleCount - 1) % bossWave : battleCount - 1;

                const dropData = {
                    spawnInfo: spawnInfo,
                    bossCount: bossCount,
                    normalCount: normalCount,
                    bossDrops: {},
                    monsterDrops: {}
                };

                const processDrop = (item, monsterName = 'unknown') => {
                    const itemPrice = LuckyUtils.getItemValue(item.itemHrid, 1);
                    const itemName = item.itemHrid.split('/').pop();
                    let { minCount, maxCount, dropRate } = item;
                    const dropRatePerTier = item.dropRatePerDifficultyTier || 0;

                    if (playerStats) {
                        const commonRateMultiplier = 1 + (playerStats.combatDropRate || 0);
                        const rareRateMultiplier = 1 + (playerStats.combatRareFind || 0);
                        const quantityMultiplier = (1 + (playerStats.combatDropQuantity || 0)) / partySize * (mapData.type === 'dungeon' ? 5 : 1);
                        const rateMultiplier = item.isRare ? rareRateMultiplier : commonRateMultiplier;

                        const baseMin = minCount;
                        const baseMax = maxCount;
                        const baseRate = dropRate;

                        minCount *= quantityMultiplier;
                        maxCount *= quantityMultiplier;

                        const len = mapData.type === 'dungeon' ? 3 : (mapData.type === 'group' ? 6 : 1);
                        dropRate = Array.from({length: len}, (_, n) => {
                            let rate = baseRate + n * dropRatePerTier;
                            rate = rate * (1 + n * 0.1) * rateMultiplier;
                            return Math.min(Math.max(rate, 0), 1);
                        });
                    }

                    return {
                        hrid: item.itemHrid,
                        price: itemPrice,
                        minCount: minCount,
                        maxCount: maxCount,
                        dropRate: dropRate
                    };
                };

                for (const [hrid, drops] of Object.entries(mapData.bossDrops || {})) {
                    const monsterName = hrid.split('/').pop();
                    dropData.bossDrops[hrid] = drops.map(drop => processDrop(drop, monsterName));
                }

                for (const [hrid, drops] of Object.entries(mapData.monsterDrops || {})) {
                    const monsterName = hrid.split('/').pop();
                    dropData.monsterDrops[hrid] = drops.map(drop => processDrop(drop, monsterName));
                }

                for (const [hrid, drops] of Object.entries(dropData.bossDrops)) {
                    dropData.bossDrops[hrid] = drops.map(drop => ({
                        ...drop,
                        dropRate: Array.isArray(drop.dropRate) ? (drop.dropRate[difficultyTier] || drop.dropRate[0]) : drop.dropRate
                    }));
                }

                for (const [hrid, drops] of Object.entries(dropData.monsterDrops)) {
                    dropData.monsterDrops[hrid] = drops.map(drop => ({
                        ...drop,
                        dropRate: Array.isArray(drop.dropRate) ? (drop.dropRate[difficultyTier] || drop.dropRate[0]) : drop.dropRate
                    }));
                }

                return dropData;
            }

            updateBigLuckPanel(playerNames, dropsData) {
                return this._updateBigLuckPanelImpl(playerNames, dropsData);
            }

            _updateBigLuckPanelImpl(playerNames, dropsData) {
                const bigLuckContent = document.getElementById('lucky-big-luck-content');
                if (!bigLuckContent) return;

                if (!LuckyGameData.hasReceivedFirstBattle) {
                    let html = '';
                    playerNames.forEach(playerName => {
                html += `
                    <div class="lucky-big-luck-item">
                        <span class="lucky-big-luck-name">${playerName}</span>
                        <span class="lucky-big-luck-percent">--</span>
                    </div>
                        `;
                    });
                    bigLuckContent.innerHTML = html;
                    return;
                }

                const { dropsList } = dropsData;
                const battleCount = FlootData.getBattleCount();
                const partySize = playerNames.length;

                const battleCountChanged = battleCount !== this.lastLuckBattleCount;
                if (battleCountChanged) {
                    this.cachedLuckResults.clear();
                    this.lastLuckBattleCount = battleCount;

                    playerNames.forEach(playerName => {
                        const ruckResult = RuckAnalyzeCurrent(playerName);
                        this.cachedLuckResults.set(playerName, ruckResult);
                    });
                }

                let html = '';
                let totalActualValue = 0;

                playerNames.forEach(playerName => {
                    let playerActualValue = 0;

                    for (const drop of dropsList) {
                        const playerStats = drop.playerStats[playerName];
                        if (playerStats) {
                            playerActualValue += playerStats.actualValue;
                        }
                    }

                    totalActualValue += playerActualValue;

                    const ruckResult = this.cachedLuckResults.get(playerName);
                    const luckDecimal = ruckResult?.luck || 0;
                    const luckPercent = luckDecimal * 100;

                    const displayPercent = ruckResult
                        ? luckPercent.toFixed(2)
                        : '--';
                    const color = ruckResult
                        ? LuckyUtils.getLuckColor(luckPercent)
                        : '#ffffff';

            html += `
                <div class="lucky-big-luck-item">
                    <span class="lucky-big-luck-name">${playerName}</span>
                    <span class="lucky-big-luck-percent" style="color: ${color};">${displayPercent}%</span>
                </div>
                    `;
                });

                bigLuckContent.innerHTML = html;
            }

            updatePlayerPanels(playerNames, dropsData) {
                return this._updatePlayerPanelsImpl(playerNames, dropsData);
            }

            _updatePlayerPanelsImpl(playerNames, dropsData) {
                playerNames.forEach(playerName => {
                    const panelId = `player-${playerName}`;
                    if (this.panelVisibility[panelId] === false) return;

                    const playerContent = document.getElementById(`lucky-player-content-${playerName}`);
                    const playerStatsDiv = document.getElementById(`lucky-player-stats-${playerName}`);
                    if (!playerContent) return;

                    if (playerStatsDiv) {
                        const stats = LuckyGameData.playerStats[playerName];
                        if (stats) {
                            const dropQty = (stats.combatDropQuantity * 100).toFixed(3);
                            const dropRate = (stats.combatDropRate * 100).toFixed(3);
                            const rareFind = (stats.combatRareFind * 100).toFixed(3);
                            const newText = `DQ: ${dropQty}% | DR: ${dropRate}% | RF: ${rareFind}%`;
                            if (playerStatsDiv.textContent !== newText) {
                                playerStatsDiv.textContent = newText;
                            }
                        }
                    }

                    if (!LuckyGameData.hasReceivedFirstBattle) {
                        playerContent.innerHTML = '<tr><td colspan="5" class="lucky-empty-state">Waiting for first battle...</td></tr>';
                        return;
                    }

                    const { dropsList } = dropsData;

                    let playerTotalActual = 0;
                    let playerTotalExpected = 0;

                    const rowsData = [];
                    for (const drop of dropsList) {
                        const playerStats = drop.playerStats[playerName];
                        if (!playerStats) {
                            continue;
                        }

                        const percentClass = LuckyUtils.getPercentClass(playerStats.percentOfExpected, this.expected100Mode);
                        const percentSign = this.expected100Mode ? '' : (playerStats.percentOfExpected > 0 ? '+' : '');

                        playerTotalActual += playerStats.actualValue ?? 0;
                        playerTotalExpected += playerStats.expectedValue ?? 0;

                        rowsData.push({
                            itemName: drop.itemName || 'Unknown',
                            actualCount: LuckyUtils.formatNumber(playerStats.actualCount ?? 0),
                            actualValue: LuckyUtils.formatNumber(playerStats.actualValue ?? 0),
                            expectedCount: LuckyUtils.formatNumber(playerStats.expectedCount ?? 0),
                            percentClass: percentClass,
                            percentText: `${percentSign}${(playerStats.percentOfExpected ?? 0).toFixed(1)}%`
                        });
                    }

                    const totalPercentDiff = this.calculatePercentOfExpected(playerTotalActual, playerTotalExpected);
                    const totalPercentClass = LuckyUtils.getPercentClass(totalPercentDiff, this.expected100Mode);
                    const totalPercentSign = this.expected100Mode ? '' : (totalPercentDiff > 0 ? '+' : '');

                    const totalRowData = {
                        actualValue: LuckyUtils.formatNumber(playerTotalActual),
                        expectedValue: LuckyUtils.formatNumber(playerTotalExpected),
                        percentClass: totalPercentClass,
                        percentText: `${totalPercentSign}${totalPercentDiff.toFixed(1)}%`
                    };

                    const rows = playerContent.rows;
                    const neededRows = rowsData.length + 1;

                    while (rows.length > neededRows) {
                        playerContent.deleteRow(-1);
                    }

                    for (let i = 0; i < rowsData.length; i++) {
                        const data = rowsData[i];
                        let row = rows[i];

                        if (!row) {
                            row = playerContent.insertRow();
                            row.innerHTML = '<td class="lucky-item-name"></td><td></td><td></td><td></td><td></td>';
                        } else if (row.cells.length !== 5) {
                            row.innerHTML = '<td class="lucky-item-name"></td><td></td><td></td><td></td><td></td>';
                        }

                        const cells = row.cells;

                        if (cells[0]) cells[0].textContent = data.itemName;
                        if (cells[1]) cells[1].textContent = data.actualCount;
                        if (cells[2]) cells[2].textContent = data.actualValue;
                        if (cells[3]) cells[3].textContent = data.expectedCount;
                        if (cells[4]) cells[4].textContent = data.percentText;

                        const newClass = `lucky-${data.percentClass}`;
                        if (cells[4] && cells[4].className !== newClass) cells[4].className = newClass;
                    }

                    let totalRow = rows[rowsData.length];
                    if (!totalRow) {
                        totalRow = playerContent.insertRow();
                        totalRow.className = 'lucky-total-row';
                        totalRow.innerHTML = '<td class="lucky-item-name">TOTAL</td><td></td><td></td><td></td><td></td>';
                    }

                    const totalCells = totalRow.cells;
                    if (totalCells[2] && totalCells[2].textContent !== totalRowData.actualValue) totalCells[2].textContent = totalRowData.actualValue;
                    if (totalCells[3] && totalCells[3].textContent !== totalRowData.expectedValue) totalCells[3].textContent = totalRowData.expectedValue;
                    if (totalCells[4] && totalCells[4].textContent !== totalRowData.percentText) totalCells[4].textContent = totalRowData.percentText;

                    const newTotalClass = `lucky-${totalRowData.percentClass}`;
                    if (totalCells[4] && totalCells[4].className !== newTotalClass) totalCells[4].className = newTotalClass;
                });
            }

            updateTotalsPanel(playerNames, dropsData) {
                return this._updateTotalsPanelImpl(playerNames, dropsData);
            }

            _updateTotalsPanelImpl(playerNames, dropsData) {
                if (this.panelVisibility.totals === false) return;

                const totalsContent = document.getElementById('lucky-totals-content');
                if (!totalsContent) return;

                if (!LuckyGameData.hasReceivedFirstBattle) {
                    totalsContent.innerHTML = '<tr><td colspan="6" class="lucky-empty-state">Waiting for first battle...</td></tr>';
                    return;
                }

                const { dropsList } = dropsData;

                let summaryTotalActualValue = 0;
                let summaryTotalExpectedValue = 0;
                let summaryTotalActualQty = 0;
                let summaryTotalExpectedQty = 0;

                const rowsData = [];
                for (const drop of dropsList) {
                    const totalPercentClass = LuckyUtils.getPercentClass(drop.totalPercentOfExpected, this.expected100Mode);
                    const totalPercentSign = this.expected100Mode ? '' : (drop.totalPercentOfExpected > 0 ? '+' : '');

                    summaryTotalActualValue += drop.totalActualValue;
                    summaryTotalExpectedValue += drop.expectedValueTotal;
                    summaryTotalActualQty += drop.totalActualQty;
                    summaryTotalExpectedQty += drop.expectedCountTotal;

                    rowsData.push({
                        itemName: drop.itemName || 'Unknown',
                        actualQty: LuckyUtils.formatNumber(drop.totalActualQty ?? 0),
                        actualValue: LuckyUtils.formatNumber(drop.totalActualValue ?? 0),
                        percentClass: totalPercentClass,
                        percentText: `${totalPercentSign}${(drop.totalPercentOfExpected ?? 0).toFixed(1)}%`,
                        expectedQty: LuckyUtils.formatNumber(drop.expectedCountTotal ?? 0),
                        expectedValue: LuckyUtils.formatNumber(drop.expectedValueTotal ?? 0)
                    });
                }

                const totalPercentDiff = this.calculatePercentOfExpected(summaryTotalActualValue, summaryTotalExpectedValue);
                const totalPercentClass = LuckyUtils.getPercentClass(totalPercentDiff, this.expected100Mode);
                const totalPercentSign = this.expected100Mode ? '' : (totalPercentDiff > 0 ? '+' : '');

                const totalRowData = {
                    actualQty: LuckyUtils.formatNumber(summaryTotalActualQty),
                    actualValue: LuckyUtils.formatNumber(summaryTotalActualValue),
                    percentClass: totalPercentClass,
                    percentText: `${totalPercentSign}${totalPercentDiff.toFixed(1)}%`,
                    expectedQty: LuckyUtils.formatNumber(summaryTotalExpectedQty),
                    expectedValue: LuckyUtils.formatNumber(summaryTotalExpectedValue)
                };

                const rows = totalsContent.rows;
                const neededRows = rowsData.length + 1;

                while (rows.length > neededRows) {
                    totalsContent.deleteRow(-1);
                }

                for (let i = 0; i < rowsData.length; i++) {
                    const data = rowsData[i];
                    let row = rows[i];

                    if (!row) {
                        row = totalsContent.insertRow();
                        row.innerHTML = '<td class="lucky-item-name"></td><td></td><td></td><td></td><td></td><td></td>';
                    } else if (row.cells.length !== 6) {
                        row.innerHTML = '<td class="lucky-item-name"></td><td></td><td></td><td></td><td></td><td></td>';
                    }

                    const cells = row.cells;
                    if (cells[0]) cells[0].textContent = data.itemName;
                    if (cells[1]) cells[1].textContent = data.actualQty;
                    if (cells[2]) cells[2].textContent = data.actualValue;
                    if (cells[3]) cells[3].textContent = data.percentText;
                    if (cells[4]) cells[4].textContent = data.expectedQty;
                    if (cells[5]) cells[5].textContent = data.expectedValue;

                    const newClass = `lucky-${data.percentClass}`;
                    if (cells[3] && cells[3].className !== newClass) cells[3].className = newClass;
                }

                let totalRow = rows[rowsData.length];
                if (!totalRow) {
                    totalRow = totalsContent.insertRow();
                    totalRow.className = 'lucky-total-row';
                    totalRow.innerHTML = '<td class="lucky-item-name">TOTAL</td><td></td><td></td><td></td><td></td><td></td>';
                }

                const totalCells = totalRow.cells;
                if (totalCells[1] && totalCells[1].textContent !== totalRowData.actualQty) totalCells[1].textContent = totalRowData.actualQty;
                if (totalCells[2] && totalCells[2].textContent !== totalRowData.actualValue) totalCells[2].textContent = totalRowData.actualValue;
                if (totalCells[3] && totalCells[3].textContent !== totalRowData.percentText) totalCells[3].textContent = totalRowData.percentText;
                if (totalCells[4] && totalCells[4].textContent !== totalRowData.expectedQty) totalCells[4].textContent = totalRowData.expectedQty;
                if (totalCells[5] && totalCells[5].textContent !== totalRowData.expectedValue) totalCells[5].textContent = totalRowData.expectedValue;

                const newTotalClass = `lucky-${totalRowData.percentClass}`;
                if (totalCells[3] && totalCells[3].className !== newTotalClass) totalCells[3].className = newTotalClass;

                const summaryTotals = {
                    players: {},
                    totalActualValue: summaryTotalActualValue,
                    totalExpectedValue: summaryTotalExpectedValue
                };

                for (const playerName of playerNames) {
                    let playerActual = 0;
                    let playerExpected = 0;
                    for (const drop of dropsList) {
                        const playerStats = drop.playerStats[playerName];
                        if (playerStats) {
                            playerActual += playerStats.actualValue;
                            playerExpected += playerStats.expectedValue;
                        }
                    }
                    summaryTotals.players[playerName] = {
                        actualValue: playerActual,
                        expectedValue: playerExpected
                    };
                }
            }

            setupPanelDragging(panelId, storageId) {
                const panel = document.getElementById(panelId);
                const header = panel?.querySelector(`[data-panel-id="${storageId}"]`);

                if (!panel || !header) return;

                this.setupResizeHandles(panel, storageId);

                this.loadPanelState(panel, storageId);

                panel.addEventListener('mousedown', () => {
                    this.bringPanelToFront(panel);
                });

                const GRID_SIZE = 10;
                let startX, startY;
                let initialLeft, initialTop;
                const gridOverlay = document.getElementById('lucky-grid-overlay');

                const snapToGrid = (value) => Math.round(value / GRID_SIZE) * GRID_SIZE;

                const onMouseMove = (e) => {
                    const deltaX = e.clientX - startX;
                    const deltaY = e.clientY - startY;

                    let newLeft = initialLeft + deltaX;
                    let newTop = initialTop + deltaY;

                    if (this.snapToGrid) {
                        newLeft = snapToGrid(newLeft);
                        newTop = snapToGrid(newTop);
                    }

                    const content = document.getElementById('lucky-content');
                    if (content && header) {
                        const contentRect = content.getBoundingClientRect();
                        const panelRect = panel.getBoundingClientRect();

                        if (storageId === 'bigExpected' || storageId === 'bigLuck') {
                            newLeft = Math.max(0, Math.min(newLeft, contentRect.width - panelRect.width));
                            newTop = Math.max(0, Math.min(newTop, contentRect.height - panelRect.height));
                        } else {
                            const headerRect = header.getBoundingClientRect();
                            const headerOffsetX = headerRect.left - panelRect.left;
                            const headerOffsetY = headerRect.top - panelRect.top;

                            newLeft = Math.max(-headerOffsetX, Math.min(newLeft, contentRect.width - headerRect.width - headerOffsetX));
                            newTop = Math.max(-headerOffsetY, Math.min(newTop, contentRect.height - headerRect.height - headerOffsetY));
                        }
                    }

                    panel.style.left = newLeft + 'px';
                    panel.style.top = newTop + 'px';
                    panel.style.right = 'auto';
                };

                const onMouseUp = () => {
                    document.removeEventListener('mousemove', onMouseMove);
                    document.removeEventListener('mouseup', onMouseUp);
                    header.style.cursor = 'move';
                    if (gridOverlay) gridOverlay.style.display = 'none';
                    this.savePanelState(panel, storageId);
                };

                header.addEventListener('mousedown', (e) => {
                    this.bringPanelToFront(panel);
                    startX = e.clientX;
                    startY = e.clientY;
                    const rect = panel.getBoundingClientRect();
                    const content = document.getElementById('lucky-content');
                    const contentRect = content.getBoundingClientRect();
                    initialLeft = rect.left - contentRect.left;
                    initialTop = rect.top - contentRect.top;
                    header.style.cursor = 'grabbing';
                    if (gridOverlay) gridOverlay.style.display = 'block';
                    e.preventDefault();
                    e.stopPropagation();
                    this._trackDocListener('mousemove', onMouseMove);
                    this._trackDocListener('mouseup', onMouseUp);
                    document.addEventListener('mousemove', onMouseMove);
                    document.addEventListener('mouseup', onMouseUp);
                });

                const resizeObserver = new ResizeObserver(() => {
                    if (!this.isDragging) {
                        this.savePanelState(panel, storageId);
                        this.updateScrollableHeight(panel);
                    }
                });
                resizeObserver.observe(panel);
                if (!this._luckyResizeObservers) this._luckyResizeObservers = [];
                this._luckyResizeObservers.push(resizeObserver);

                setTimeout(() => this.updateScrollableHeight(panel), 0);
            }

            updateScrollableHeight(panel) {
                const headerEl = panel.querySelector('.lucky-panel-header');
                const scrollableEl = panel.querySelector('.lucky-panel-content-scrollable');

                if (!headerEl || !scrollableEl) return;

                const panelHeight = panel.clientHeight;
                const headerHeight = headerEl.offsetHeight;
                const padding = 28;

                const scrollableHeight = panelHeight - headerHeight - padding;
                scrollableEl.style.maxHeight = scrollableHeight + 'px';
            }

            bringPanelToFront(panel) {
                if (!panel) return;

                const allPanels = document.querySelectorAll('.lucky-floating-panel');

                let maxZIndex = 10001;
                allPanels.forEach(p => {
                    const zIndex = parseInt(p.style.zIndex || window.getComputedStyle(p).zIndex) || 10001;
                    if (zIndex > maxZIndex) {
                        maxZIndex = zIndex;
                    }
                });

                const currentZIndex = parseInt(panel.style.zIndex || window.getComputedStyle(panel).zIndex) || 10001;
                if (currentZIndex <= maxZIndex) {
                    panel.style.zIndex = maxZIndex + 1;
                }
            }

            resetPanelPositions() {
                const content = document.getElementById('lucky-content');
                if (!content) return;

                const startLeft = 0;
                const startTop = 0;
                const verticalSpacing = 50;
                let offsetIndex = 0;

                const panelConfigs = [
                    { id: 'lucky-stats-panel', storageId: 'stats' },
                    { id: 'lucky-revenue-panel', storageId: 'revenue' },
                    { id: 'lucky-big-expected-panel', storageId: 'bigExpected' },
                    { id: 'lucky-big-luck-panel', storageId: 'bigLuck' },
                    { id: 'lucky-mob-expected-panel', storageId: 'mobExpected' },
                    { id: 'lucky-totals-panel', storageId: 'totals' }
                ];

                panelConfigs.forEach(config => {
                    const panel = document.getElementById(config.id);
                    if (panel && panel.style.display !== 'none') {
                        const left = startLeft;
                        const top = startTop + (offsetIndex * verticalSpacing);
                        const zIndex = 10001 + offsetIndex;
                        panel.style.left = left + 'px';
                        panel.style.top = top + 'px';
                        panel.style.right = 'auto';
                        panel.style.zIndex = zIndex;
                        this.savePanelState(panel, config.storageId);
                        offsetIndex++;
                    }
                });

                const playerNames = FlootData.getAllPlayerNames();
                playerNames.forEach(playerName => {
                    const panel = document.getElementById(`lucky-player-panel-${playerName}`);
                    if (panel && panel.style.display !== 'none') {
                        const left = startLeft;
                        const top = startTop + (offsetIndex * verticalSpacing);
                        const zIndex = 10001 + offsetIndex;
                        panel.style.left = left + 'px';
                        panel.style.top = top + 'px';
                        panel.style.right = 'auto';
                        panel.style.zIndex = zIndex;
                        this.savePanelState(panel, `player-${playerName}`);
                        offsetIndex++;
                    }
                });
            }

            autoGridPanels() {
                const content = document.getElementById('lucky-content');
                if (!content) return;

                const panelWidth = 160;
                const panelHeight = 160;
                const startX = 0;
                const startY = 0;
                const cols = 4;
                let panelIndex = 0;

                const panelConfigs = [
                    { id: 'lucky-stats-panel', storageId: 'stats' },
                    { id: 'lucky-revenue-panel', storageId: 'revenue' },
                    { id: 'lucky-big-expected-panel', storageId: 'bigExpected' },
                    { id: 'lucky-big-luck-panel', storageId: 'bigLuck' },
                    { id: 'lucky-mob-expected-panel', storageId: 'mobExpected' },
                    { id: 'lucky-totals-panel', storageId: 'totals' }
                ];

                panelConfigs.forEach(config => {
                    const panel = document.getElementById(config.id);
                    if (panel && panel.style.display !== 'none') {
                        const col = panelIndex % cols;
                        const row = Math.floor(panelIndex / cols);
                        const x = startX + (col * panelWidth);
                        const y = startY + (row * panelHeight);

                        panel.style.width = panelWidth + 'px';
                        panel.style.height = panelHeight + 'px';
                        panel.style.left = x + 'px';
                        panel.style.top = y + 'px';
                        panel.style.right = 'auto';
                        panel.style.zIndex = 10001 + panelIndex;

                        this.savePanelState(panel, config.storageId);
                        panelIndex++;
                    }
                });

                const playerNames = FlootData.getAllPlayerNames();
                playerNames.forEach(playerName => {
                    const panel = document.getElementById(`lucky-player-panel-${playerName}`);
                    if (panel && panel.style.display !== 'none') {
                        const col = panelIndex % cols;
                        const row = Math.floor(panelIndex / cols);
                        const x = startX + (col * panelWidth);
                        const y = startY + (row * panelHeight);

                        panel.style.width = panelWidth + 'px';
                        panel.style.height = panelHeight + 'px';
                        panel.style.left = x + 'px';
                        panel.style.top = y + 'px';
                        panel.style.right = 'auto';
                        panel.style.zIndex = 10001 + panelIndex;

                        this.savePanelState(panel, `player-${playerName}`);
                        panelIndex++;
                    }
                });
            }

            applyDefaultGridIfNeeded() {
                const panelConfigs = [
                    { storageId: 'stats' },
                    { storageId: 'revenue' },
                    { storageId: 'bigExpected' },
                    { storageId: 'bigLuck' },
                    { storageId: 'mobExpected' },
                    { storageId: 'totals' }
                ];

                let hasSavedState = false;
                for (const config of panelConfigs) {
                    if (this.lyStorage.get(`panel_${config.storageId}`)) {
                        hasSavedState = true;
                        break;
                    }
                }

                if (!hasSavedState) {
                    setTimeout(() => {
                        this.autoGridPanels();
                    }, 500);
                }
            }

            savePanelState(panel, storageId) {
                if (!panel) return;
                const state = {
                    left: panel.style.left,
                    top: panel.style.top,
                    width: panel.style.width || panel.offsetWidth + 'px',
                    height: panel.style.height || panel.offsetHeight + 'px'
                };
                this.lyStorage.set(`panel_${storageId}`, state);
            }

            loadPanelState(panel, storageId) {
                if (!panel) return;
                try {
                    const state = this.lyStorage.get(`panel_${storageId}`);
                    if (state) {
                        if (state.left) panel.style.left = state.left;
                        if (state.top) panel.style.top = state.top;
                        if (state.width) panel.style.width = state.width;
                        if (state.height) panel.style.height = state.height;
                        panel.style.right = 'auto';
                    }
                } catch (e) {
                }
            }

            destroy() {
                if (_luckyWsListener) {
                    window.removeEventListener('EquipSpyWebSocketMessage', _luckyWsListener);
                    _luckyWsListener = null;
                }
                VisibilityManager.clear('lucky-update');

                this._cleanupDocListeners();

                if (this._luckyResizeObservers) {
                    this._luckyResizeObservers.forEach(obs => obs.disconnect());
                    this._luckyResizeObservers = null;
                }

                if (this.panel) {
                    this.panel.remove();
                }
            }
        }

        let luckyPanelInstance = null;

        function initLucky() {
            setupLuckyMessageHandlers();

            let attempts = 0;
            const checkFloot = setInterval(() => {
                attempts++;
                if (window.lootDropsTrackerInstance) {
                    clearInterval(checkFloot);
                    luckyPanelInstance = new LuckyPanel();
                    luckyPanelInstance.init();
                } else if (attempts > 30) {
                    console.error('[Lucky] Timeout waiting for lootDropsTrackerInstance');
                    clearInterval(checkFloot);
                }
            }, 1000);
        }

        window.luckyPanelInstance = luckyPanelInstance;

        if (typeof LootDropsTracker !== 'undefined') {
            LootDropsTracker.prototype.createLuckyPanel = function() {
                if (!window.luckyPanelInstance) {
                    setupLuckyMessageHandlers();
                    window.luckyPanelInstance = new LuckyPanel();
                    window.luckyPanelInstance.init();
                }
            };
        } else {
            console.error('[Lucky] LootDropsTracker not defined!');
        }

// Lucky end

// Main start

        async function main() {
            if (!window.lootDropsTrackerInstance) {
                window.lootDropsTrackerInstance = new LootDropsTracker();
            }
            await loadMarketData();

            window.MCS_MODULES_INITIALIZED = true;
            VisibilityManager.register('skeleton-loot-overlay', () => {
                if (window.lootDropsTrackerInstance) {
                    const coinItem = window.lootDropsTrackerInstance.spyCharacterItems?.find(
                        item => item.itemHrid === '/items/coin'
                    );
                    if (!window._lastGoldAmount) window._lastGoldAmount = 0;
                    if (coinItem && coinItem.count !== window._lastGoldAmount) {
                        window._lastGoldAmount = coinItem.count;
                    }
                }
                const overlay = document.getElementById('milt-loot-drops-display');
                if (!overlay) return;
                const isHidden = overlay.classList.contains('is-hidden');
                injectValuesAndSort();
                if (!isHidden) {
                }
            }, 1000);
            VisibilityManager.register('skeleton-gold-per-day', () => {
                if (typeof updateGoldPerDay === 'function') {
                    updateGoldPerDay();
                }
            }, 1000);
            VisibilityManager.register('skeleton-hwhat-display', () => {
                if (window.lootDropsTrackerInstance && typeof window.lootDropsTrackerInstance.updateHWhatDisplay === 'function') {
                    window.lootDropsTrackerInstance.updateHWhatDisplay();
                }
            }, 1000);
        }

        function injectSuitePanelCSS() {
            if (document.getElementById('mcs-suite-panel-styles')) return;
            const style = document.createElement('style');
            style.id = 'mcs-suite-panel-styles';
            style.textContent = `
                .mcs-hidden { display: none !important; }
                .mcs-suite-header { grid-column: 1 / -1; display: flex; justify-content: center; align-items: center; gap: 8px; padding: 6px 8px 2px 8px; background: rgba(0,0,0,0.3); border-radius: 4px 4px 0 0; font-size: 11px; text-align: center; }
                .mcs-suite-char-mode { color: #87CEEB; font-weight: 600; }
                .mcs-suite-char-name { grid-column: 1 / -1; margin-bottom: 8px; padding: 2px 8px 6px 8px; background: rgba(0,0,0,0.3); border-radius: 0 0 4px 4px; font-size: 11px; color: #FFD700; text-align: center; }
                .mcs-suite-toggle-row { grid-column: 1 / -1; display: flex; justify-content: center; align-items: center; padding: 6px 0; margin-bottom: 6px; border-bottom: 1px solid #444; }
                .mcs-suite-toggle-label { display: flex; align-items: center; gap: 6px; cursor: pointer; font-size: 12px; }
                .mcs-suite-toggle-text { color: #ccc; }
                .mcs-suite-refresh-msg { color: #f44336; font-size: 11px; margin-left: 10px; }
                .mcs-suite-gm-available { color: #4CAF50; }
                .mcs-suite-gm-unavailable { color: #f44336; }
                .mcs-suite-columns { display: flex; gap: 16px; }
                .mcs-suite-col { flex: 1; }
                .mcs-suite-separator { margin: 10px 0; border: none; border-top: 1px solid #444; }
                .mcs-suite-tool-label { display: flex; align-items: center; margin-bottom: 2px; cursor: pointer; user-select: none; }
                .mcs-suite-sub-label { display: flex; align-items: center; margin-bottom: 3px; cursor: pointer; user-select: none; margin-left: 16px; font-size: 11px; }
                .mcs-suite-checkbox { margin-right: 8px; cursor: pointer; }
                .mcs-suite-tool-name { font-size: 13px; }
            `;
            document.head.appendChild(style);
        }

        LootDropsTracker.prototype.setupFeedListener();

        function startMCS() {
            injectSuitePanelCSS();

            if (!document.getElementById('equipspy-data-bridge')) {
                const bridge = document.createElement('div');
                bridge.id = 'equipspy-data-bridge';
                bridge.className = 'mcs-data-bridge';
                document.body.appendChild(bridge);
            }

            function waitForCharacter() {
                const el = document.querySelector('[data-name]');
                const name = el && el.getAttribute('data-name');
                if (name) {
                    const enabled = MCSEnabledStorage.get(name);
                    if (!enabled) {
                        window._MCS_DISABLED = true;
                        console.log('[MCS] Disabled for character:', name);
                        return;
                    }
                    main();
                } else {
                    setTimeout(waitForCharacter, 500);
                }
            }
            waitForCharacter();
        }
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', startMCS);
        } else {
            startMCS();
        }
        (function initCombatSuiteButton() {
            'use strict';
            function waitForDOM() {
                if (document.body && document.head) {
                    createButton();
                } else {
                    setTimeout(waitForDOM, 100);
                }
            }
            function createButton() {
                const styles = `
        #mwi-combat-suite-btn {
            position: fixed;
            top: 0px;
            background: #808080;
            color: white;
            border: 1px solid #666666;
            border-top: none;
            border-radius: 0 0 6px 6px;
            padding: 3px 10px;
            font-weight: bold;
            font-size: 10px;
            cursor: move;
            z-index: 200000;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
            user-select: none;
            transition: background 0.2s ease;
            white-space: nowrap;
        }
        #mwi-combat-suite-btn:hover {
            background: #909090;
        }
        #mwi-combat-suite-btn.dragging {
            cursor: grabbing;
            opacity: 0.8;
        }
        #mwi-combat-suite-panel {
            position: fixed;
            background: rgba(30, 30, 40, 0.95);
            border: 2px solid rgba(255, 255, 255, 0.2);
            border-radius: 8px;
            padding: 16px;
            color: white;
            z-index: 200001;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
            min-width: 200px;
            display: none;
        }
        #mwi-combat-suite-panel.visible {
            display: block;
        }
        .mwi-panel-content {
            font-size: 14px;
        }
        .mcs-emergency-section {
            margin-bottom: 8px;
            border: 1px solid rgba(255, 80, 80, 0.4);
            border-radius: 4px;
            overflow: hidden;
        }
        .mcs-emergency-header {
            background: rgba(255, 50, 50, 0.15);
            color: #ff6b6b;
            padding: 4px 8px;
            cursor: pointer;
            font-size: 11px;
            font-weight: bold;
            user-select: none;
        }
        .mcs-emergency-header:hover {
            background: rgba(255, 50, 50, 0.25);
        }
        .mcs-emergency-body {
            padding: 6px 8px;
            background: rgba(255, 50, 50, 0.05);
            display: flex;
            gap: 6px;
        }
        .mcs-emergency-btn {
            background: rgba(255, 60, 60, 0.3);
            color: #ff9999;
            border: 1px solid rgba(255, 80, 80, 0.5);
            border-radius: 3px;
            padding: 3px 8px;
            font-size: 11px;
            cursor: pointer;
        }
        .mcs-emergency-btn:hover {
            background: rgba(255, 60, 60, 0.5);
            color: white;
        }
    `;
                const styleSheet = document.createElement('style');
                styleSheet.textContent = styles;
                document.head.appendChild(styleSheet);
                const defaultLeft = Math.floor(window.innerWidth * 0.75);
                const savedPosition = JSON.parse(localStorage.getItem('mcs__global_combat_suite_btn_position') || `{"left": ${defaultLeft}}`);
                const button = document.createElement('div');
                button.id = 'mwi-combat-suite-btn';
                button.textContent = 'MWI Combat Suite v0.9.36073 Beta';
                const leftVal = typeof savedPosition.left === 'number' ? savedPosition.left : parseInt(savedPosition.left) || defaultLeft;
                button.style.left = leftVal + 'px';
                document.body.appendChild(button);
                registerPanel('mwi-combat-suite-btn');
                window.addEventListener('resize', () => {
                    const suiteBtn = document.getElementById('mwi-combat-suite-btn');
                    if (!suiteBtn) return;
                    const rect = suiteBtn.getBoundingClientRect();
                    const windowWidth = window.innerWidth;
                    if (rect.left > windowWidth - 100 || rect.right < 50) {
                        const newLeft = Math.max(20, Math.min(rect.left, windowWidth - 150));
                        suiteBtn.style.left = newLeft + 'px';
                        suiteBtn.style.right = 'auto';
                        localStorage.setItem('mcs__global_combat_suite_btn_position', JSON.stringify({
                            left: newLeft
                        }));
                    }
                });
                const panel = document.createElement('div');
                panel.id = 'mwi-combat-suite-panel';
                const tools = [
                    { name: 'Shykai Export', panelId: 'shykai-simulator', isSimulator: true },
                    { name: 'AMazing', panelId: 'amazing-pane' },
                    { name: 'BRead', panelId: 'bread-pane' },
                    { name: 'CRack', panelId: 'consumables-pane' },
                    { name: 'DPs', panelId: 'dps-pane' },
                    { name: 'EWatch', panelId: 'equipment-spy-pane' },
                    { name: 'FLoot', panelId: 'milt-loot-drops-display' },
                    { name: 'GWhiz', panelId: 'gwhiz-pane' },
                    { name: 'HWhat', panelId: 'hwhat-pane' },
                    { name: 'IHurt', panelId: 'ihurt-pane' },
                    { name: 'JHouse', panelId: 'jhouse-pane' },
                    { name: 'KOllection', panelId: 'kollection-pane' },
                    { name: 'LYuck', panelId: 'lucky-panel' },
                    { name: 'MAna', panelId: 'mana-pane' },
                    { name: 'NTally', panelId: 'mcs_nt_pane' },
                    { name: 'OPanel', panelId: 'opanel-pane' },
                    { name: 'PFormance', panelId: 'pformance-pane' },
                    { name: 'QCharm', panelId: 'qcharm-pane' },
                    { name: 'SCrolling Combat Text', panelId: 'meaters-pane' },
                    { name: 'TReasure', panelId: 'treasure-pane' },
                    { name: 'Floating Combat Text', panelId: 'fcb-feature', isFCB: true, isHR: true }
                ];
                let savedStates = {};
                let savedStatesLoaded = false;
                const loadSavedStates = () => {
                    const characterName = CharacterDataStorage.getCurrentCharacterName();
                    if (characterName) {
                        savedStates = ToolVisibilityStorage.get(characterName);
                        savedStatesLoaded = true;
                        return true;
                    }
                    return false;
                };

                function togglePanelVisibility(panelId, visible) {
                    if (panelId === 'qcharm-pane' && typeof window.lootDropsTrackerInstance !== 'undefined') {
                        if (visible) {
                            window.lootDropsTrackerInstance.createQCharmPane();
                        } else {
                            window.lootDropsTrackerInstance.destroyQCharmPane();
                        }
                        return;
                    }

                    const panelElement = document.getElementById(panelId);
                    if (panelElement) {
                        if (visible) {
                            panelElement.classList.remove('mcs-hidden');

                            if (panelId === 'pformance-pane' && typeof window.lootDropsTrackerInstance !== 'undefined') {
                                PerformanceMonitor.enabled = true;
                                StorageMonitor.enabled = true;
                                if (!window.lootDropsTrackerInstance.pformanceRunning) {
                                    VisibilityManager.register('pformance-cpu-update', () => {
                                        window.lootDropsTrackerInstance.pf_updateCpuDisplay();
                                        window.lootDropsTrackerInstance.pf_updateStorageIODisplay();
                                    }, 1000);
                                    window.lootDropsTrackerInstance.pformanceRunning = true;
                                }
                            }

                            if (panelId === 'mcs_nt_pane' && typeof window.lootDropsTrackerInstance !== 'undefined') {
                                window.lootDropsTrackerInstance.mcs_nt_renderContent();
                            }
                        } else {
                            panelElement.classList.add('mcs-hidden');

                            if (panelId === 'pformance-pane') {
                                PerformanceMonitor.enabled = false;
                                StorageMonitor.enabled = false;
                                VisibilityManager.clear('pformance-cpu-update');
                                if (typeof window.lootDropsTrackerInstance !== 'undefined') {
                                    window.lootDropsTrackerInstance.pformanceRunning = false;
                                }
                            }
                        }
                    }
                }
                let visibilityApplied = false;
                let _cachedAddonDisabled = false;
                function _refreshCachedEnabledState() {
                    const currentChar = CharacterDataStorage.getCurrentCharacterName();
                    _cachedAddonDisabled = currentChar ? !MCSEnabledStorage.get(currentChar) : false;
                }
                function applyVisibilityStates() {
                    if (visibilityApplied) return;

                    loadSavedStates();
                    if (!savedStatesLoaded) return;

                    _refreshCachedEnabledState();
                    if (_cachedAddonDisabled) return;
                    visibilityApplied = true;

                    tools.forEach(tool => {
                        const toolKey = tool.name.replace(/\s+/g, '-').toLowerCase();
                        const isVisible = tool.isSimulator ? (savedStatesLoaded && savedStates[toolKey] !== false) : savedStates[toolKey] === true;

                        const checkbox = document.querySelector(`input[data-tool-key="${toolKey}"]`);
                        if (checkbox && checkbox.checked !== isVisible) {
                            checkbox.checked = isVisible;
                        }

                        if (tool.isSimulator) return;
                        togglePanelVisibility(tool.panelId, isVisible);
                    });

                    const flootInventoryCheckbox = document.querySelector('input[data-floot-sub="inventory-value"]');
                    if (flootInventoryCheckbox) {
                        const inventoryValueVisible = savedStates['floot-inventory-value'] === true;
                        if (flootInventoryCheckbox.checked !== inventoryValueVisible) {
                            flootInventoryCheckbox.checked = inventoryValueVisible;
                        }
                    }
                    const flootFullNumbersCheckbox = document.querySelector('input[data-floot-sub="full-numbers"]');
                    if (flootFullNumbersCheckbox) {
                        const fullNumbersVisible = savedStates['floot-full-numbers'] === true;
                        if (flootFullNumbersCheckbox.checked !== fullNumbersVisible) {
                            flootFullNumbersCheckbox.checked = fullNumbersVisible;
                        }
                    }

                    const hwhatFullNumbersCheckbox = document.querySelector('input[data-hwhat-sub="full-numbers"]');
                    if (hwhatFullNumbersCheckbox) {
                        const hwhatFullNumbersVisible = savedStates['hwhat-full-numbers'] === true;
                        if (hwhatFullNumbersCheckbox.checked !== hwhatFullNumbersVisible) {
                            hwhatFullNumbersCheckbox.checked = hwhatFullNumbersVisible;
                        }
                    }
                }
                applyVisibilityStates();
                setTimeout(applyVisibilityStates, 500);
                setTimeout(applyVisibilityStates, 1500);
                setTimeout(applyVisibilityStates, 3000);
                setTimeout(applyVisibilityStates, 5000);
                window.addEventListener('LootTrackerCharacterData', () => applyVisibilityStates(), { once: true });
                const observer = new MutationObserver((mutations) => {
                    if (!savedStatesLoaded) return;
                    const disabled = _cachedAddonDisabled;
                    mutations.forEach((mutation) => {
                        mutation.addedNodes.forEach((node) => {
                            if (node.nodeType === 1 && node.id) {
                                tools.forEach(tool => {
                                    if (tool.isSimulator) return;
                                    if (node.id === tool.panelId) {
                                        if (disabled) {
                                            setTimeout(() => togglePanelVisibility(tool.panelId, false), 100);
                                        } else {
                                            const toolKey = tool.name.replace(/\s+/g, '-').toLowerCase();
                                            const isVisible = savedStates[toolKey] === true;
                                            setTimeout(() => togglePanelVisibility(tool.panelId, isVisible), 100);
                                        }
                                    }
                                });
                            }
                        });
                    });
                });
                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });
                const getCharacterInfo = () => {
                    try {
                        const cachedData = CharacterDataStorage.get();
                        if (cachedData && cachedData.character) {
                            let mode = null;
                            if (cachedData.character.gameMode === 'ironcow') {
                                mode = 'Iron Cow enabled';
                            } else if (cachedData.character.gameMode === 'standard') {
                                mode = 'Market Cow enabled';
                            }
                            const name = cachedData.character.name || null;
                            return { mode, name };
                        }
                    } catch (e) {
                    }
                    return { mode: null, name: null };
                };

                let characterInfo = getCharacterInfo();
                let characterMode = characterInfo.mode || 'Loading...';
                let characterName = characterInfo.name || '';

                const updateCharacterModeDisplay = () => {
                    const info = getCharacterInfo();
                    if (info.mode) {
                        const modeEl = document.getElementById('mcs-character-mode-display');
                        if (modeEl) {
                            modeEl.textContent = info.mode;
                        }
                    }
                    if (info.name) {
                        const nameEl = document.getElementById('mcs-character-name-display');
                        if (nameEl) {
                            nameEl.textContent = info.name;
                            nameEl.classList.remove('mcs-hidden');
                        }
                        const toggle = document.getElementById('mcs-enabled-toggle');
                        const toolsSection = document.getElementById('mcs-suite-tools-section');
                        if (toggle && toolsSection) {
                            const isEnabled = MCSEnabledStorage.get(info.name);
                            _cachedAddonDisabled = !isEnabled;
                            toggle.checked = isEnabled;
                            if (isEnabled) {
                                toolsSection.classList.remove('mcs-hidden');
                            } else {
                                toolsSection.classList.add('mcs-hidden');
                            }
                        }
                    }
                };
                if (characterMode === 'Loading...') {
                    setTimeout(updateCharacterModeDisplay, 1000);
                    setTimeout(updateCharacterModeDisplay, 2000);
                    setTimeout(updateCharacterModeDisplay, 4000);
                }

                loadSavedStates();

                const addonEnabled = window._MCS_DISABLED ? false : (!characterName || MCSEnabledStorage.get(characterName));

                const mainTools = tools.filter(t => !t.isFCB);
                const fcbTool = tools.find(t => t.isFCB);

                function buildToolHTML(tool) {
                    const toolKey = tool.name.replace(/\s+/g, '-').toLowerCase();
                    const isVisible = tool.isSimulator ? (savedStatesLoaded && savedStates[toolKey] !== false) : savedStates[toolKey] === true;
                    let html = `
                <label class="mcs-suite-tool-label">
                    <input type="checkbox"
                           data-tool-panel="${tool.panelId}"
                           data-tool-key="${toolKey}"
                           ${tool.isSimulator ? 'data-simulator="true"' : ''}
                           ${isVisible ? 'checked' : ''}
                           class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">${tool.name}</span>
                </label>`;

                    if (tool.name === 'FLoot') {
                        const inventoryValueVisible = savedStates['floot-inventory-value'] === true;
                        const fullNumbersVisible = savedStates['floot-full-numbers'] === true;
                        html += `
                <label class="mcs-suite-sub-label">
                    <input type="checkbox" data-floot-sub="inventory-value" ${inventoryValueVisible ? 'checked' : ''} class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">Show Inventory Value</span>
                </label>
                <label class="mcs-suite-sub-label">
                    <input type="checkbox" data-floot-sub="full-numbers" ${fullNumbersVisible ? 'checked' : ''} class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">Show Full Numbers</span>
                </label>`;
                        const marketWarningsVisible = savedStates['floot-market-warnings'] !== false;
                        const inventoryWarningsVisible = savedStates['floot-inventory-warnings'] !== false;
                        html += `
                <label class="mcs-suite-sub-label">
                    <input type="checkbox" data-floot-sub="market-warnings" ${marketWarningsVisible ? 'checked' : ''} class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">Market Warnings</span>
                </label>
                <label class="mcs-suite-sub-label">
                    <input type="checkbox" data-floot-sub="inventory-warnings" ${inventoryWarningsVisible ? 'checked' : ''} class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">Inventory Warnings</span>
                </label>`;
                    }

                    if (tool.name === 'HWhat') {
                        const hwhatFullNumbersVisible = savedStates['hwhat-full-numbers'] === true;
                        html += `
                <label class="mcs-suite-sub-label">
                    <input type="checkbox" data-hwhat-sub="full-numbers" ${hwhatFullNumbersVisible ? 'checked' : ''} class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">Show Full Numbers</span>
                </label>`;
                    }

                    return html;
                }

                const half = Math.ceil(mainTools.length / 2);
                const leftTools = mainTools.slice(0, half);
                const rightTools = mainTools.slice(half);

                let fcbHTML = '';
                if (fcbTool) {
                    const fcStorage = createModuleStorage('FC');
                    const fcbKey = fcbTool.name.replace(/\s+/g, '-').toLowerCase();
                    const fcbVisible = fcStorage.get('enabled', false) === true;
                    const enemyDpsVisible = fcStorage.get('enemyd', false) === true;
                    const playerDpsVisible = fcStorage.get('playerd', false) === true;
                    const playerNameRecolor = fcStorage.get('playerc', false) === true;

                    const fcbItems = [
                        { label: fcbTool.name, attrs: `data-tool-panel="${fcbTool.panelId}" data-tool-key="${fcbKey}" data-fcb="true"`, checked: fcbVisible },
                        { label: 'Enemy DPS Numbers', attrs: 'data-fcb-sub="enemy-dps"', checked: enemyDpsVisible },
                        { label: 'Player DPS Numbers', attrs: 'data-fcb-sub="player-dps"', checked: playerDpsVisible },
                        { label: 'Player Name Recolor', attrs: 'data-fcb-sub="player-name-recolor"', checked: playerNameRecolor }
                    ];
                    const fcbLeft = fcbItems.filter((_, i) => i % 2 === 0);
                    const fcbRight = fcbItems.filter((_, i) => i % 2 === 1);
                    const fcbItemHTML = (item) => `
                <label class="mcs-suite-tool-label">
                    <input type="checkbox" ${item.attrs} ${item.checked ? 'checked' : ''} class="mcs-suite-checkbox">
                    <span class="mcs-suite-tool-name">${item.label}</span>
                </label>`;

                    fcbHTML = `
            <hr class="mcs-suite-separator">
            <div class="mcs-suite-columns">
                <div class="mcs-suite-col">${fcbLeft.map(fcbItemHTML).join('')}</div>
                <div class="mcs-suite-col">${fcbRight.map(fcbItemHTML).join('')}</div>
            </div>`;
                }

                const contentHTML = `
        <div class="mwi-panel-content">
            <div class="mcs-emergency-section">
                <div class="mcs-emergency-header" id="mcs-emergency-toggle">Emergency ▸</div>
                <div class="mcs-emergency-body mcs-hidden" id="mcs-emergency-body">
                    <button class="mcs-emergency-btn" id="mcs-shrink-lucky-btn">Set LYuck panel to 500x500</button>
                    <button class="mcs-emergency-btn" id="mcs-center-lucky-btn">Center LYuck in window</button>
                </div>
            </div>
            <div class="mcs-suite-header">
                <span id="mcs-character-mode-display" class="mcs-suite-char-mode">${characterMode}</span>
                <span id="mcs-gm-storage-display" class="${typeof GM_info !== 'undefined' ? 'mcs-suite-gm-available' : 'mcs-suite-gm-unavailable'}">GM Storage ${typeof GM_info !== 'undefined' ? 'Available' : 'Unavailable'}</span>
            </div>
            <div id="mcs-character-name-display" class="mcs-suite-char-name ${characterName ? '' : 'mcs-hidden'}">
                ${characterName}
            </div>
            <div class="mcs-suite-toggle-row">
                <label class="mcs-suite-toggle-label">
                    <input type="checkbox" id="mcs-enabled-toggle" class="mcs-suite-checkbox" ${addonEnabled ? 'checked' : ''}>
                    <span class="mcs-suite-toggle-text">Enabled</span>
                </label>
                <div id="mcs-refresh-msg" class="mcs-suite-refresh-msg mcs-hidden">Refresh to apply</div>
            </div>
            <div id="mcs-suite-tools-section" ${addonEnabled ? '' : 'class="mcs-hidden"'}>
                <div class="mcs-suite-columns">
                    <div class="mcs-suite-col">${leftTools.map(buildToolHTML).join('')}</div>
                    <div class="mcs-suite-col">${rightTools.map(buildToolHTML).join('')}</div>
                </div>
                ${fcbHTML}
            </div>
        </div>
    `;
                panel.innerHTML = contentHTML;
                document.body.appendChild(panel);
                registerPanel('mwi-combat-suite-panel');
                const emergencyToggle = panel.querySelector('#mcs-emergency-toggle');
                const emergencyBody = panel.querySelector('#mcs-emergency-body');
                if (emergencyToggle && emergencyBody) {
                    emergencyToggle.addEventListener('click', () => {
                        const isHidden = emergencyBody.classList.toggle('mcs-hidden');
                        emergencyToggle.textContent = isHidden ? 'Emergency ▸' : 'Emergency ▾';
                    });
                }
                const shrinkLuckyBtn = panel.querySelector('#mcs-shrink-lucky-btn');
                if (shrinkLuckyBtn) {
                    shrinkLuckyBtn.addEventListener('click', () => {
                        const luckyPanel = document.getElementById('lucky-panel');
                        if (luckyPanel) {
                            luckyPanel.style.width = '500px';
                            luckyPanel.style.height = '500px';
                        }
                    });
                }
                const centerLuckyBtn = panel.querySelector('#mcs-center-lucky-btn');
                if (centerLuckyBtn) {
                    centerLuckyBtn.addEventListener('click', () => {
                        const luckyPanel = document.getElementById('lucky-panel');
                        if (luckyPanel) {
                            const rect = luckyPanel.getBoundingClientRect();
                            luckyPanel.style.left = ((window.innerWidth - rect.width) / 2) + 'px';
                            luckyPanel.style.top = ((window.innerHeight - rect.height) / 2) + 'px';
                            luckyPanel.style.right = 'auto';
                        }
                    });
                }
                const enabledToggle = panel.querySelector('#mcs-enabled-toggle');
                if (enabledToggle) {
                    enabledToggle.addEventListener('change', (e) => {
                        const enabled = e.target.checked;
                        const name = CharacterDataStorage.getCurrentCharacterName();
                        if (name) {
                            MCSEnabledStorage.set(name, enabled);
                            _cachedAddonDisabled = !enabled;
                        }
                        const toolsSection = document.getElementById('mcs-suite-tools-section');
                        const refreshMsg = document.getElementById('mcs-refresh-msg');
                        if (refreshMsg) refreshMsg.classList.remove('mcs-hidden');
                        if (enabled) {
                            if (toolsSection) toolsSection.classList.remove('mcs-hidden');
                            visibilityApplied = false;
                            applyVisibilityStates();
                        } else {
                            if (toolsSection) toolsSection.classList.add('mcs-hidden');
                            tools.forEach(tool => {
                                if (!tool.isSimulator) {
                                    togglePanelVisibility(tool.panelId, false);
                                }
                            });
                        }
                    });
                }

                panel.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
                    checkbox.addEventListener('change', (e) => {
                        if (e.target.id === 'mcs-enabled-toggle') return;
                        const flootSub = e.target.dataset.flootSub;
                        const fcbSub = e.target.dataset.fcbSub;

                        if (flootSub) {
                            const isVisible = e.target.checked;
                            savedStates[`floot-${flootSub}`] = isVisible;
                            ToolVisibilityStorage.set(savedStates);

                            if (flootSub === 'inventory-value') {
                                if (typeof window.toggleInventoryPrices === 'function') {
                                    window.toggleInventoryPrices(isVisible);
                                }
                            } else if (flootSub === 'full-numbers') {
                                if (typeof window.toggleFlootFullNumbers === 'function') {
                                    window.toggleFlootFullNumbers(isVisible);
                                }
                            } else if (flootSub === 'market-warnings') {
                                if (typeof window.toggleMarketWarnings === 'function') {
                                    window.toggleMarketWarnings(isVisible);
                                }
                            } else if (flootSub === 'inventory-warnings') {
                                if (typeof window.toggleInventoryWarnings === 'function') {
                                    window.toggleInventoryWarnings(isVisible);
                                }
                            }
                            return;
                        }

                        const hwhatSub = e.target.dataset.hwhatSub;
                        if (hwhatSub) {
                            const isVisible = e.target.checked;
                            savedStates[`hwhat-${hwhatSub}`] = isVisible;
                            ToolVisibilityStorage.set(savedStates);

                            if (hwhatSub === 'full-numbers') {
                                if (window.lootDropsTrackerInstance) {
                                    window.lootDropsTrackerInstance.hwhatShowFullNumbers = isVisible;
                                    if (typeof window.lootDropsTrackerInstance.updateHWhatDisplay === 'function') {
                                        window.lootDropsTrackerInstance.updateHWhatDisplay();
                                    }
                                    if (window.skeletonInstance && typeof window.skeletonInstance.updateOPanelTotalProfit === 'function') {
                                        window.skeletonInstance.updateOPanelTotalProfit();
                                    }
                                }
                            }
                            return;
                        }

                        if (fcbSub) {
                            const isVisible = e.target.checked;

                            if (window.lootDropsTrackerInstance) {
                                if (fcbSub === 'enemy-dps') {
                                    if (typeof window.lootDropsTrackerInstance.fcbToggleEnemyDPS === 'function') {
                                        window.lootDropsTrackerInstance.fcbToggleEnemyDPS(isVisible);
                                    }
                                } else if (fcbSub === 'player-dps') {
                                    if (typeof window.lootDropsTrackerInstance.fcbTogglePlayerDPS === 'function') {
                                        window.lootDropsTrackerInstance.fcbTogglePlayerDPS(isVisible);
                                    }
                                } else if (fcbSub === 'player-name-recolor') {
                                    if (typeof window.lootDropsTrackerInstance.fcbTogglePlayerNameRecolor === 'function') {
                                        window.lootDropsTrackerInstance.fcbTogglePlayerNameRecolor(isVisible);
                                    }
                                }
                            }
                            return;
                        }

                        const panelId = e.target.dataset.toolPanel;
                        const toolKey = e.target.dataset.toolKey;
                        const isSimulator = e.target.dataset.simulator === 'true';
                        const isFCB = e.target.dataset.fcb === 'true';
                        const isVisible = e.target.checked;
                        savedStates[toolKey] = isVisible;
                        ToolVisibilityStorage.set(savedStates);
                        if (isSimulator) {
                            if (isVisible) {
                                GM_setValue('shykai_simulator_enabled', 'true');
                            } else {
                                GM_setValue('shykai_simulator_enabled', 'false');
                            }
                        } else if (isFCB) {
                            if (window.lootDropsTrackerInstance && typeof window.lootDropsTrackerInstance.fcbToggleEnabled === 'function') {
                                window.lootDropsTrackerInstance.fcbToggleEnabled(isVisible);
                            }
                        } else {
                            togglePanelVisibility(panelId, isVisible);
                        }
                    });
                });
                let panelVisible = false;
                let hasMoved = false;
                let startX = 0;
                let startLeft = 0;

                const onBtnDragMove = (e) => {
                    const deltaX = e.clientX - startX;
                    if (Math.abs(deltaX) > 5) {
                        hasMoved = true;
                    }
                    const newLeft = startLeft + deltaX;
                    button.style.left = newLeft + 'px';
                    if (panelVisible) {
                        panel.style.left = newLeft + 'px';
                    }
                };

                const onBtnDragUp = () => {
                    document.removeEventListener('mousemove', onBtnDragMove);
                    document.removeEventListener('mouseup', onBtnDragUp);
                    const position = {
                        left: parseInt(button.style.left) || 0
                    };
                    localStorage.setItem('mcs__global_combat_suite_btn_position', JSON.stringify(position));
                    setTimeout(() => {
                        button.classList.remove('dragging');
                        if (!hasMoved) {
                            panelVisible = !panelVisible;
                            panel.classList.toggle('visible', panelVisible);
                            if (panelVisible) {
                                const btnRect = button.getBoundingClientRect();
                                panel.style.left = btnRect.left + 'px';
                                panel.style.top = (btnRect.bottom + 5) + 'px';
                            }
                        } else if (panelVisible) {
                            const btnRect = button.getBoundingClientRect();
                            panel.style.left = btnRect.left + 'px';
                            panel.style.top = (btnRect.bottom + 5) + 'px';
                        }
                        hasMoved = false;
                    }, 50);
                };

                button.addEventListener('mousedown', (e) => {
                    hasMoved = false;
                    startX = e.clientX;
                    const rect = button.getBoundingClientRect();
                    startLeft = rect.left;
                    button.classList.add('dragging');
                    document.addEventListener('mousemove', onBtnDragMove);
                    document.addEventListener('mouseup', onBtnDragUp);
                });
                document.addEventListener('click', (e) => {
                    if (panelVisible &&
                        !button.contains(e.target) &&
                        !panel.contains(e.target)) {
                        panelVisible = false;
                        panel.classList.remove('visible');
                    }
                });
            }
            waitForDOM();
        })();
    }
})();