Hidey Way Idle

Toggle visibility of various page elements in Milky Way Idle and draggable nav bar

// ==UserScript==
// @name         Hidey Way Idle
// @namespace    http://tampermonkey.net/
// @version      2.4
// @description  Toggle visibility of various page elements in Milky Way Idle and draggable nav bar
// @author       Frotty
// @match        *://milkywayidle.com/*
// @match        *://*.milkywayidle.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Player name storage system
    let currentPlayerName = null;

    function getPlayerName() {
        const characterNameElement = document.querySelector('.CharacterName_name__1amXp[data-name]');
        if (characterNameElement) {
            const dataName = characterNameElement.getAttribute('data-name');
            if (dataName && dataName.trim()) {
                return dataName.trim();
            }
        }
        return null;
    }

    function getStorageKey(key) {
        if (!currentPlayerName) {
            return key;
        }
        return `${key}-${currentPlayerName}`;
    }

    function migrateOldSettings() {
        if (!currentPlayerName) return;
        const oldKeys = ['mwi-element-toggle', 'mwi-panel-position', 'mwi-panel-minimized', 'mwi-navpanel-position'];
        oldKeys.forEach(oldKey => {
            const oldValue = localStorage.getItem(oldKey);
            if (oldValue !== null) {
                const newKey = getStorageKey(oldKey);
                if (localStorage.getItem(newKey) === null) {
                    localStorage.setItem(newKey, oldValue);
                }
            }
        });
    }

    function pollForPlayerName(callback, maxAttempts = 50, interval = 200) {
        let attempts = 0;
        const poll = () => {
            attempts++;
            const newPlayerName = getPlayerName();
            if (newPlayerName && newPlayerName !== currentPlayerName) {
                currentPlayerName = newPlayerName;
                migrateOldSettings();
                callback();
                return;
            }
            if (attempts >= maxAttempts) {
                callback();
                return;
            }
            setTimeout(poll, interval);
        };
        poll();
    }

    // Configuration for elements to toggle
    const elementConfigs = [
        {
            name: 'Navigation Panel',
            selector: 'div[class*="GamePage_navPanel_"]',
            enabled: true
        },
        {
            name: 'Minor Links',
            selector: 'div[class*="NavigationBar_minorNavigationLinks_"]',
            enabled: true
        },
        {
            name: 'Logo/Playercount',
            selector: 'div[class*="Header_navLogoAndPlayerCount_"]',
            enabled: true
        },
        {
            name: 'Toggle Button',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'My Stuff',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Marketplace',
            selector: null, // Will be found by index
            enabled: true,
            inDOM: false
        },
        {
            name: 'Tasks',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Milking',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Foraging',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Woodcutting',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Cheesesmithing',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Crafting',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Tailoring',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Cooking',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Brewing',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Alchemy',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Enhancing',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Combat Panel',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Combat',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Stamina',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Intelligence',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Attack',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Defense',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Melee',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Ranged',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Magic',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Shop',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Cowbell Store',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Loot Tracker',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Social',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Guild',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Leaderboard',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Settings',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'News',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Patch Notes',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Game Guide',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Game Rules',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Game Wiki',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Discord',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Test Server',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Privacy Policy',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Switch Character',
            selector: null,
            enabled: true,
            inDOM: false
        },
        {
            name: 'Logout',
            selector: null,
            enabled: true,
            inDOM: false
        },
        // Optional minor navigation links (may not exist)
        {
            name: 'Send Bug Report',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Combat Sim Shykai',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Profit Calc Cowculator',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Enhancement Sim',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Script Settings',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Edible Tools',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Chest Statistics',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Profit Calc Milkonomy',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Combat Tracker Socko',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Profit Calc Mooneycalc',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        },
        {
            name: 'Milkyway.Market',
            selector: null,
            enabled: true,
            inDOM: false,
            isOptional: true
        }
    ];

    // Load saved settings from localStorage
    function loadSettings() {
        const saved = localStorage.getItem(getStorageKey('mwi-element-toggle'));
        if (saved) {
            try {
                const settings = JSON.parse(saved);
                elementConfigs.forEach(config => {
                    if (settings.hasOwnProperty(config.name)) {
                        config.enabled = settings[config.name];
                    }
                });
            } catch (e) {
                console.error('Failed to load settings:', e);
            }
        }
    }

    // Load saved position from localStorage
    function loadPosition(key, defaultCenter = false) {
        const saved = localStorage.getItem(getStorageKey(key));
        if (saved) {
            try {
                return JSON.parse(saved);
            } catch (e) {
                console.error('Failed to load position:', e);
            }
        }
        // If no saved position and defaultCenter is true, calculate center position
        if (defaultCenter) {
            return {
                x: (window.innerWidth / 2) - 100, // Subtract half of approximate panel width
                y: (window.innerHeight / 2) - 100, // Subtract half of approximate panel height
                isInitial: true
            };
        }
        return { x: 0, y: 0 };
    }

    // Save position to localStorage
    function savePosition(key, x, y) {
        localStorage.setItem(getStorageKey(key), JSON.stringify({ x, y }));
    }

    // Save minimize state to localStorage
    function saveMinimizeState(isMinimized) {
        localStorage.setItem(getStorageKey('mwi-panel-minimized'), JSON.stringify(isMinimized));
    }

    // Load minimize state from localStorage
    function loadMinimizeState() {
        const saved = localStorage.getItem(getStorageKey('mwi-panel-minimized'));
        if (saved) {
            try {
                return JSON.parse(saved);
            } catch (e) {
                console.error('Failed to load minimize state:', e);
            }
        }
        return false; // Default to expanded
    }

    // Find and map navigation links to configs
    function updateNavigationLinks() {
        // Reset inDOM status
        elementConfigs.forEach(config => {
            if (!config.selector) {
                config.inDOM = false;
                config.element = null;
            }
        });

        // Check for Toggle Button (appears at certain screen widths)
        const toggleButton = document.querySelector('div[class*="NavigationBar_navToggleButton_"]');
        if (toggleButton) {
            const config = elementConfigs.find(c => c.name === 'Toggle Button');
            if (config) {
                config.inDOM = true;
                config.element = toggleButton;
                config.originalDisplay = '';

            }
        }

        // Main navigation link names (direct children of navigationLinks)
        const mainLinkNames = [
            'My Stuff',
            'Marketplace',
            'Tasks',
            'Milking',
            'Foraging',
            'Woodcutting',
            'Cheesesmithing',
            'Crafting',
            'Tailoring',
            'Cooking',
            'Brewing',
            'Alchemy',
            'Enhancing',
            'Combat Panel',
            'Shop',
            'Cowbell Store',
            'Loot Tracker',
            'Social',
            'Guild',
            'Leaderboard',
            'Settings'
        ];

        // Minor navigation link names (with class NavigationBar_minorNavigationLink_)
        const minorLinkNames = [
            'News',
            'Patch Notes',
            'Game Guide',
            'Game Rules',
            'Game Wiki',
            'Discord',
            'Test Server',
            'Privacy Policy',
            'Switch Character',
            'Logout'
        ];

        // Optional minor navigation link names (may not exist)
        const optionalMinorLinkNames = [
            'Send Bug Report',
            'Combat Sim Shykai',
            'Combat sim shykai', // lowercase variant
            'Profit Calc Cowculator',
            'Profit calc Cowculator', // lowercase variant
            'Enhancement Sim',
            'Enhancement sim', // lowercase variant
            'Script Settings',
            'Script settings', // lowercase variant
            'Edible Tools',
            'Chest Statistics',
            'Profit Calc Milkonomy',
            'Profit calc Milkonomy', // lowercase variant
            'Combat Tracker Socko',
            'Combat tracker Socko', // lowercase variant
            'Profit Calc Mooneycalc',
            'Profit calc Mooneycalc' // lowercase variant
        ];

        // Combat-specific names (within the Combat Panel's NavigationBar_nav)
        const combatNames = [
            'Combat'
        ];

        // Combat sub-skill names (within NavigationBar_subSkills_)
        const subSkillNames = [
            'Stamina',
            'Intelligence',
            'Attack',
            'Defense',
            'Melee',
            'Ranged',
            'Magic'
        ];

        // Find the navigation links container
        const navLinksContainer = document.querySelector('div[class*="NavigationBar_navigationLinks_"]');

        if (!navLinksContainer) {

            return;
        }



        // Get all direct children that are navigation links
        const navigationLinkDivs = navLinksContainer.querySelectorAll('div[class*="NavigationBar_navigationLink_"]');



        navigationLinkDivs.forEach((navLinkDiv, index) => {
            // Get the full text content to check for Combat Panel
            const fullText = navLinkDiv.textContent.trim();


            // Special handling for Combat Panel - check if full text starts with "Combat" and has numbers
            if (fullText.startsWith('Combat') && /\d/.test(fullText)) {
                const config = elementConfigs.find(c => c.name === 'Combat Panel');
                if (config) {
                    config.inDOM = true;
                    config.element = navLinkDiv;
                    config.originalDisplay = "";

                }
            }

            // Check for main navigation links (direct text in first span)
            const firstSpan = navLinkDiv.querySelector('div[class*="NavigationBar_nav_"] > div[class*="NavigationBar_contentContainer_"] > div[class*="NavigationBar_textContainer_"] > span');
            if (firstSpan) {
                const text = firstSpan.textContent.trim();


                // Check other main link names (excluding Combat Panel since we handled it above)
                mainLinkNames.forEach(linkName => {
                    if (linkName !== 'Combat Panel' && (text === linkName || text.startsWith(linkName))) {
                        const config = elementConfigs.find(c => c.name === linkName);
                        if (config) {
                            config.inDOM = true;
                            config.element = navLinkDiv;
                            config.originalDisplay = "";

                        }
                    }
                });
            }

            // Check for Combat nav element (the NavigationBar_nav_ that contains Combat text)
            const combatNav = navLinkDiv.querySelector('div[class*="NavigationBar_nav_"]');
            if (combatNav) {
                const combatSpan = combatNav.querySelector('div[class*="NavigationBar_contentContainer_"] > div[class*="NavigationBar_textContainer_"] > span');
                if (combatSpan) {
                    const combatText = combatSpan.textContent.trim();

                    combatNames.forEach(combatName => {
                        if (combatText === combatName || combatText.startsWith(combatName)) {
                            const config = elementConfigs.find(c => c.name === combatName);
                            if (config) {
                                config.inDOM = true;
                                config.element = combatNav; // Store the NavigationBar_nav_ element
                                config.originalDisplay = "";

                            }
                        }
                    });
                }
            }

            // Check for sub-skills (within NavigationBar_subSkills_)
            const subSkillsContainer = navLinkDiv.querySelector('div[class*="NavigationBar_subSkills_"]');
            if (subSkillsContainer) {


                // Find all nav elements within the subSkills container
                const subSkillNavs = subSkillsContainer.querySelectorAll('div[class*="NavigationBar_nav_"]');

                subSkillNavs.forEach((subSkillNav, subIndex) => {
                    const subSpan = subSkillNav.querySelector('div[class*="NavigationBar_contentContainer_"] > div[class*="NavigationBar_textContainer_"] > span');
                    if (subSpan) {
                        const subText = subSpan.textContent.trim();


                        // Check if this matches any sub-skill names
                        subSkillNames.forEach(skillName => {
                            if (subText === skillName || subText.startsWith(skillName)) {
                                const config = elementConfigs.find(c => c.name === skillName);
                                if (config) {
                                    config.inDOM = true;
                                    config.element = subSkillNav; // Store the nav element, not the parent
                                    config.originalDisplay = "";

                                }
                            }
                        });
                    }
                });
            }
        });

        // Special check for Milkyway.Market - standalone button with id="cst-view"
        const milkywayButton = document.querySelector('button#cst-view');
        if (milkywayButton) {
            const config = elementConfigs.find(c => c.name === 'Milkyway.Market');
            if (config) {
                config.inDOM = true;
                config.element = milkywayButton;
                config.originalDisplay = "";

            }
        }

        // Search for minor navigation links (NavigationBar_minorNavigationLink_)
        const minorNavLinks = document.querySelectorAll('div[class*="NavigationBar_minorNavigationLink_"]');


        minorNavLinks.forEach((minorLink, index) => {
            const text = minorLink.textContent.trim();


            // Check regular minor link names first
            minorLinkNames.forEach(linkName => {
                if (text === linkName || text.startsWith(linkName)) {
                    const config = elementConfigs.find(c => c.name === linkName);
                    if (config) {
                        config.inDOM = true;
                        config.element = minorLink;
                        config.originalDisplay = "";

                    }
                }
            });

            // Check optional minor link names
            optionalMinorLinkNames.forEach(linkName => {
                if (text.toLowerCase().includes(linkName.toLowerCase())) {
                    // Find the config with matching name (normalize the case)
                    const config = elementConfigs.find(c =>
                        c.isOptional &&
                        (c.name === linkName ||
                         c.name.toLowerCase() === linkName.toLowerCase() ||
                         text.toLowerCase().includes(c.name.toLowerCase()))
                    );
                    if (config) {
                        config.inDOM = true;
                        config.element = minorLink;
                        config.originalDisplay = "";

                    }
                }
            });
        });

        // Log current DOM status
        const inDomLinks = elementConfigs.filter(c => c.inDOM).map(c => c.name);

    }

    // Save settings to localStorage
    function saveSettings() {
        const settings = {};
        elementConfigs.forEach(config => {
            settings[config.name] = config.enabled;
        });
        localStorage.setItem(getStorageKey('mwi-element-toggle'), JSON.stringify(settings));
    }

    // Make the game's navigation panel draggable
    function makeNavPanelDraggable() {
        const navPanels = document.querySelectorAll('div[class*="GamePage_navPanel_"]');

        navPanels.forEach(navPanel => {
            // Check if already made draggable
            if (navPanel.dataset.draggableAdded) return;
            navPanel.dataset.draggableAdded = 'true';

            // Remove any fixed height to allow dynamic sizing
            navPanel.style.height = 'auto';
            navPanel.style.minHeight = 'auto';
            navPanel.style.maxHeight = 'none';

            // Also remove fixed height from NavigationBar_navigationBarContainer_
            const navBarContainer = navPanel.querySelector('div[class*="NavigationBar_navigationBarContainer_"]');
            if (navBarContainer) {
                navBarContainer.style.height = 'auto';
                navBarContainer.style.minHeight = 'auto';
                navBarContainer.style.maxHeight = 'none';
            }

            // Create drag header
            const dragHeader = document.createElement('div');
            dragHeader.style.cssText = `
                height: 10px;
                background: rgba(52, 73, 94, 0.8);
                cursor: grab;
                user-select: none;
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                z-index: 1000;
            `;
            dragHeader.title = 'Drag to move panel';

            // Make the nav panel positioned so the drag header can be absolute
            const currentPosition = window.getComputedStyle(navPanel).position;
            if (currentPosition === 'static') {
                navPanel.style.position = 'relative';
            }

            // Insert drag header at the beginning
            navPanel.insertBefore(dragHeader, navPanel.firstChild);

            // Add padding to top of nav panel to account for drag header
            const currentPaddingTop = window.getComputedStyle(navPanel).paddingTop;
            const paddingValue = parseInt(currentPaddingTop) || 0;
            navPanel.style.paddingTop = (paddingValue + 10) + 'px';

            // Load saved position (center on first load)
            const savedPos = loadPosition('mwi-navpanel-position', true);
            let xOffset = savedPos.x;
            let yOffset = savedPos.y;

            // Apply initial position
            if (xOffset !== 0 || yOffset !== 0) {
                navPanel.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
            }

            // If this was the initial centered position, save it
            if (savedPos.isInitial) {
                savePosition('mwi-navpanel-position', xOffset, yOffset);
            }

            // Dragging functionality
            let isDragging = false;
            let currentX;
            let currentY;
            let initialX;
            let initialY;

            dragHeader.addEventListener('mousedown', dragStart);
            document.addEventListener('mousemove', drag);
            document.addEventListener('mouseup', dragEnd);

            function dragStart(e) {
                initialX = e.clientX - xOffset;
                initialY = e.clientY - yOffset;

                if (e.target === dragHeader) {
                    isDragging = true;
                    dragHeader.style.cursor = 'grabbing';
                }
            }

            function drag(e) {
                if (isDragging) {
                    e.preventDefault();

                    // Calculate new position
                    let newX = e.clientX - initialX;
                    let newY = e.clientY - initialY;

                    // Get current panel position
                    const rect = navPanel.getBoundingClientRect();

                    // Calculate where the header would be with the new offset
                    const headerLeft = rect.left - xOffset + newX;
                    const headerTop = rect.top - yOffset + newY;
                    const headerRight = headerLeft + rect.width;
                    const headerBottom = headerTop + 10; // Header height

                    // Constrain header to screen bounds
                    if (headerLeft < 0) newX -= headerLeft;
                    if (headerRight > window.innerWidth) newX -= (headerRight - window.innerWidth);
                    if (headerTop < 0) newY -= headerTop;
                    if (headerBottom > window.innerHeight) newY -= (headerBottom - window.innerHeight);

                    xOffset = newX;
                    yOffset = newY;

                    setTranslate(newX, newY, navPanel);
                }
            }

            function dragEnd(e) {
                if (isDragging) {
                    initialX = currentX;
                    initialY = currentY;
                    isDragging = false;
                    dragHeader.style.cursor = 'grab';

                    // Save position
                    savePosition('mwi-navpanel-position', xOffset, yOffset);
                }
            }

            function setTranslate(xPos, yPos, el) {
                el.style.transform = `translate(${xPos}px, ${yPos}px)`;
            }
        });
    }

    // Apply visibility based on current settings
    function applyVisibility() {
        elementConfigs.forEach(config => {
            if (config.selector) {
                // Handle elements with selectors (Navigation Panel, Minor Links)
                const elements = document.querySelectorAll(config.selector);
                elements.forEach(el => {
                    el.style.display = config.enabled ? '' : 'none';
                });
            } else if (config.element) {
                // Handle navigation links that have been found
                // When enabling, restore original display value; when disabling, set to none
                if (config.enabled) {
                    config.element.style.display = config.originalDisplay || '';
                } else {
                    config.element.style.display = 'none';
                }
            }
        });
    }

    // Create the control panel UI
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'mwi-toggle-panel';
        panel.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            background: #2c3e50;
            color: #ecf0f1;
            padding: 0;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.3);
            z-index: 10000;
            font-family: Arial, sans-serif;
            font-size: 14px;
            min-width: 200px;
        `;

        // Add drag header with title and minimize button
        const dragHeader = document.createElement('div');
        dragHeader.style.cssText = `
            height: 20px;
            background: #7f8c8d;
            border-radius: 8px 8px 0 0;
            cursor: grab;
            user-select: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 10px;
            color: white;
            font-weight: bold;
            font-size: 12px;
        `;
        dragHeader.title = 'Drag to move';

        const title = document.createElement('span');
        title.textContent = 'Hidey Way Idle';
        title.style.cssText = `
            flex: 1;
            pointer-events: none;
        `;

        const minimizeBtn = document.createElement('button');
        minimizeBtn.textContent = '−';
        minimizeBtn.style.cssText = `
            width: 16px;
            height: 16px;
            padding: 0;
            margin-left: 4px;
            background: #5a6c7d;
            color: white;
            border: 1px solid #4a5c6d;
            border-radius: 3px;
            cursor: pointer;
            font-size: 14px;
            line-height: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        `;

        dragHeader.appendChild(title);
        dragHeader.appendChild(minimizeBtn);
        panel.appendChild(dragHeader);

        // Load saved position (stays in top-right by default)
        const savedPos = loadPosition('mwi-panel-position', false);
        let xOffset = savedPos.x;
        let yOffset = savedPos.y;

        // Apply saved position if it exists
        if (xOffset !== 0 || yOffset !== 0) {
            panel.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
        }

        // Add dragging functionality
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;

        dragHeader.addEventListener('mousedown', dragStart);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', dragEnd);

        function dragStart(e) {
            // Don't start dragging if clicking the minimize button
            if (e.target === minimizeBtn) return;

            initialX = e.clientX - xOffset;
            initialY = e.clientY - yOffset;

            if (e.target === dragHeader || e.target === title) {
                isDragging = true;
                dragHeader.style.cursor = 'grabbing';
            }
        }

        function drag(e) {
            if (isDragging) {
                e.preventDefault();

                // Calculate new position
                let newX = e.clientX - initialX;
                let newY = e.clientY - initialY;

                // Get current panel position
                const rect = panel.getBoundingClientRect();

                // Calculate where the header would be with the new offset
                const headerLeft = rect.left - xOffset + newX;
                const headerTop = rect.top - yOffset + newY;
                const headerRight = headerLeft + rect.width;
                const headerBottom = headerTop + 20; // Header height

                // Constrain header to screen bounds
                if (headerLeft < 0) newX -= headerLeft;
                if (headerRight > window.innerWidth) newX -= (headerRight - window.innerWidth);
                if (headerTop < 0) newY -= headerTop;
                if (headerBottom > window.innerHeight) newY -= (headerBottom - window.innerHeight);

                xOffset = newX;
                yOffset = newY;

                setTranslate(newX, newY, panel);
            }
        }

        function dragEnd(e) {
            if (isDragging) {
                initialX = currentX;
                initialY = currentY;
                isDragging = false;
                dragHeader.style.cursor = 'grab';

                // Save position
                savePosition('mwi-panel-position', xOffset, yOffset);
            }
        }

        function setTranslate(xPos, yPos, el) {
            el.style.transform = `translate(${xPos}px, ${yPos}px)`;
        }

        // Add content container with padding
        const contentContainer = document.createElement('div');
        contentContainer.style.cssText = `
            padding: 15px;
        `;

        const optionsContainer = document.createElement('div');
        optionsContainer.style.cssText = `
            max-height: 400px;
            overflow-y: auto;
        `;

        // Add scanning status notice at the top
        const scanningNotice = document.createElement('div');
        scanningNotice.style.cssText = `
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            background: #f39c12;
            color: white;
            border-radius: 4px;
            text-align: center;
            font-size: 12px;
            font-weight: bold;
            display: none;
        `;
        optionsContainer.appendChild(scanningNotice);

        // Add refresh button
        const refreshButton = document.createElement('button');
        refreshButton.textContent = '🔄 Refresh DOM Scan';
        refreshButton.style.cssText = `
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            background: #3498db;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            font-weight: bold;
        `;
        refreshButton.title = 'Manually rescan the page for navigation elements';

        refreshButton.addEventListener('click', () => {
            // Visual feedback
            refreshButton.textContent = '🔄 Scanning...';
            refreshButton.disabled = true;
            refreshButton.style.background = '#95a5a6';

            // Perform the scan
            updateNavigationLinks();
            applyVisibility();
            refreshUI();
            makeNavPanelDraggable();

            // Reset button after a short delay
            setTimeout(() => {
                refreshButton.textContent = '🔄 Refresh DOM Scan';
                refreshButton.disabled = false;
                refreshButton.style.background = '#3498db';
            }, 500);
        });

        optionsContainer.appendChild(refreshButton);

        // Auto-scanning logic
        let scanInterval = null;
        let countdownInterval = null;
        let secondsUntilScan = 3;
        let extendedScanStartTime = null;
        const EXTENDED_SCAN_DURATION = 20000; // 20 seconds in milliseconds

        function checkIfAllRequiredFound() {
            // Only count required (non-optional) elements
            const requiredConfigs = elementConfigs.filter(c => !c.isOptional);
            const foundCount = requiredConfigs.filter(c => c.selector || c.inDOM).length;
            const totalCount = requiredConfigs.length;

            // Return true when 100% of required elements are found
            return foundCount === totalCount;
        }

        function checkIfAllFound() {
            // Check if ALL elements (including optional) are found
            const foundCount = elementConfigs.filter(c => c.selector || c.inDOM).length;
            const totalCount = elementConfigs.length;

            // Return true when 100% of all elements are found
            return foundCount === totalCount;
        }

        function performScan() {
            updateNavigationLinks();
            applyVisibility();
            refreshUI();
            makeNavPanelDraggable();

            // Check if we found all required elements
            if (checkIfAllRequiredFound()) {
                // Start extended scanning for optional elements if not already started
                if (extendedScanStartTime === null) {
                    extendedScanStartTime = Date.now();

                }

                // If ALL elements (including optional) are found, stop immediately
                if (checkIfAllFound()) {

                    stopAutoScanning();
                    return;
                }

                // Check if extended scan time has elapsed
                const elapsedTime = Date.now() - extendedScanStartTime;
                if (elapsedTime >= EXTENDED_SCAN_DURATION) {
                    stopAutoScanning();
                }
            }
        }

        function updateCountdown() {
            if (secondsUntilScan > 0) {
                // If in extended scan mode, show different message
                if (extendedScanStartTime !== null) {
                    const remainingTime = Math.ceil((EXTENDED_SCAN_DURATION - (Date.now() - extendedScanStartTime)) / 1000);
                    scanningNotice.textContent = `Scanning for optional elements... ${remainingTime}s`;
                } else {
                    scanningNotice.textContent = `Scanning in ${secondsUntilScan}...`;
                }
                secondsUntilScan--;
            } else {
                if (extendedScanStartTime !== null) {
                    const remainingTime = Math.ceil((EXTENDED_SCAN_DURATION - (Date.now() - extendedScanStartTime)) / 1000);
                    scanningNotice.textContent = `Scanning for optional elements... ${remainingTime}s`;
                } else {
                    scanningNotice.textContent = 'Scanning now...';
                }
                performScan();
                secondsUntilScan = 3; // Reset for next cycle
            }
        }

        function startAutoScanning() {
            scanningNotice.style.display = 'block';
            secondsUntilScan = 0; // Start with immediate scan
            updateCountdown();

            // Update countdown every second
            countdownInterval = setInterval(updateCountdown, 1000);
        }

        function stopAutoScanning() {
            if (scanInterval) clearInterval(scanInterval);
            if (countdownInterval) clearInterval(countdownInterval);
            scanningNotice.style.display = 'none';

        }

        // Start auto-scanning when panel is created
        startAutoScanning();

        elementConfigs.forEach((config, index) => {
            const option = document.createElement('div');
            const isAvailable = config.selector || config.inDOM; // Available if has selector OR is in DOM
            option.style.cssText = `
                margin: 8px 0;
                display: flex;
                align-items: center;
                opacity: ${isAvailable ? '1' : '0.5'};
            `;
            option.id = `mwi-option-${index}`;

            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.id = `mwi-toggle-${index}`;
            checkbox.checked = config.enabled;
            checkbox.disabled = !isAvailable;
            checkbox.style.cssText = `
                margin-right: 8px;
                cursor: ${checkbox.disabled ? 'not-allowed' : 'pointer'};
            `;

            checkbox.addEventListener('change', () => {
                config.enabled = checkbox.checked;
                saveSettings();
                applyVisibility();
            });

            const label = document.createElement('label');
            label.htmlFor = `mwi-toggle-${index}`;
            label.textContent = config.name;
            label.style.cssText = `
                cursor: ${checkbox.disabled ? 'not-allowed' : 'pointer'};
                user-select: none;
                ${config.isOptional ? 'font-style: italic; color: #aaa;' : ''}
            `;

            // Add DOM status indicator for navigation links (not for selector-based elements)
            if (!config.selector) {
                const statusIndicator = document.createElement('span');
                statusIndicator.style.cssText = `
                    margin-left: 5px;
                    font-size: 10px;
                    color: ${config.inDOM ? '#2ecc71' : '#e74c3c'};
                `;
                statusIndicator.textContent = config.inDOM ? '●' : '○';
                statusIndicator.title = config.inDOM ? 'In DOM' : 'Not in DOM';
                label.appendChild(statusIndicator);
            }

            option.appendChild(checkbox);
            option.appendChild(label);
            optionsContainer.appendChild(option);
        });

        // Add reset button at the bottom
        const resetButton = document.createElement('button');
        resetButton.textContent = 'Reset, Set Visible, Reload Page';
        resetButton.style.cssText = `
            width: 100%;
            padding: 8px;
            margin-top: 15px;
            background: #e74c3c;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            font-weight: bold;
        `;
        resetButton.title = 'Clear all storage, set all options to visible, and reload page';

        resetButton.addEventListener('click', () => {
            // Clear all localStorage items related to this script
            localStorage.removeItem(getStorageKey('mwi-element-toggle'));
            localStorage.removeItem(getStorageKey('mwi-panel-position'));
            localStorage.removeItem(getStorageKey('mwi-panel-minimized'));
            localStorage.removeItem(getStorageKey('mwi-navpanel-position'));

            // Set all configs to enabled
            elementConfigs.forEach(config => {
                config.enabled = true;
            });

            // Save the reset state
            saveSettings();

            // Reload the page to apply changes
            location.reload();
        });

        optionsContainer.appendChild(resetButton);

        contentContainer.appendChild(optionsContainer);

        // Load saved minimize state
        const isMinimized = loadMinimizeState();
        if (isMinimized) {
            contentContainer.style.display = 'none';
            minimizeBtn.textContent = '+';
            panel.style.minWidth = 'auto';
            dragHeader.style.borderRadius = '8px'; // Fully rounded when minimized
        }

        // Minimize button functionality
        minimizeBtn.addEventListener('click', () => {
            const isMinimized = contentContainer.style.display === 'none';
            contentContainer.style.display = isMinimized ? 'block' : 'none';
            minimizeBtn.textContent = isMinimized ? '−' : '+';
            panel.style.minWidth = isMinimized ? '200px' : 'auto';
            // Update header border radius - fully rounded when minimized
            dragHeader.style.borderRadius = isMinimized ? '8px 8px 0 0' : '8px';
            // Save minimize state
            saveMinimizeState(!isMinimized);
        });

        panel.appendChild(contentContainer);
        document.body.appendChild(panel);
    }

    // Debounce helper
    let updateTimeout = null;
    function debounce(func, delay) {
        return function() {
            clearTimeout(updateTimeout);
            updateTimeout = setTimeout(func, delay);
        };
    }

    // MutationObserver to handle dynamically loaded content
    function observeDOM() {
        const debouncedUpdate = debounce(() => {
            updateNavigationLinks(); // Re-scan for navigation links
            applyVisibility(); // Apply visibility settings
            refreshUI(); // Update UI indicators
            makeNavPanelDraggable(); // Make any new nav panels draggable
        }, 500); // Wait 500ms after last change before updating

        const observer = new MutationObserver((mutations) => {
            // Only react if navigation-related classes are involved
            const hasNavigationChange = mutations.some(mutation => {
                if (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0) {
                    const nodes = [...mutation.addedNodes, ...mutation.removedNodes];
                    return nodes.some(node => {
                        if (node.nodeType === 1) { // Element node
                            const className = node.className || '';
                            // Check if className is a string or DOMTokenList
                            if (typeof className === 'string') {
                                return className.includes('NavigationBar_navigationLink_') ||
                                       className.includes('GamePage_navPanel_') ||
                                       className.includes('NavigationBar_navigationLinks_') ||
                                       className.includes('NavigationBar_navToggleButton_') ||
                                       className.includes('NavigationBar_minorNavigationLink_');
                            } else if (className.constructor && className.constructor.name === 'DOMTokenList') {
                                // For DOMTokenList, convert to string
                                return className.toString().includes('NavigationBar_navigationLink_') ||
                                       className.toString().includes('GamePage_navPanel_') ||
                                       className.toString().includes('NavigationBar_navigationLinks_') ||
                                       className.toString().includes('NavigationBar_navToggleButton_') ||
                                       className.toString().includes('NavigationBar_minorNavigationLink_');
                            }
                        }
                        return false;
                    });
                }
                return false;
            });

            if (hasNavigationChange) {
                debouncedUpdate();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true,
            attributes: false, // Don't watch attribute changes
            characterData: false // Don't watch text changes
        });
    }

    // Refresh the UI to update DOM status indicators
    function refreshUI() {
        elementConfigs.forEach((config, index) => {
            const checkbox = document.getElementById(`mwi-toggle-${index}`);
            const option = document.getElementById(`mwi-option-${index}`);

            if (checkbox && option) {
                const isAvailable = config.selector || config.inDOM; // Available if has selector OR is in DOM
                checkbox.disabled = !isAvailable;
                checkbox.style.cursor = checkbox.disabled ? 'not-allowed' : 'pointer';
                option.style.opacity = isAvailable ? '1' : '0.5';

                // Update status indicator (only for non-selector elements)
                if (!config.selector) {
                    const label = option.querySelector('label');
                    if (label) {
                        const statusIndicator = label.querySelector('span');
                        if (statusIndicator) {
                            statusIndicator.style.color = config.inDOM ? '#2ecc71' : '#e74c3c';
                            statusIndicator.textContent = config.inDOM ? '●' : '○';
                            statusIndicator.title = config.inDOM ? 'In DOM' : 'Not in DOM';
                        }
                    }
                }
            }
        });
    }

    // Initialize the script
    function init() {
        const continueInit = () => {
            loadSettings();

            // Wait for the page to be ready
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', () => {
                    createControlPanel();
                    updateNavigationLinks(); // Find all navigation links first
                    applyVisibility(); // Then apply visibility settings
                    refreshUI(); // Refresh UI after initial visibility check
                    makeNavPanelDraggable(); // Make nav panel draggable
                    observeDOM();
                });
            } else {
                // Document already loaded, start immediately
                createControlPanel();
                updateNavigationLinks(); // Find all navigation links first
                applyVisibility(); // Then apply visibility settings
                refreshUI(); // Refresh UI after initial visibility check
                makeNavPanelDraggable(); // Make nav panel draggable
                observeDOM();
            }
        };

        // Poll for player name before continuing
        pollForPlayerName(continueInit);
    }

    init();
})();