Infinite Craft - Auto Dragger Pro - Element Sync Plugin

Sync ALL elements

目前為 2025-11-23 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Infinite Craft - Auto Dragger Pro - Element Sync Plugin
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Sync ALL elements
// @author       Silverfox0338
// @license      CC-BY-NC-ND-4.0
// @match        https://neal.fun/infinite-craft/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=neal.fun
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // ============================================================================
    // CONSTANTS & CONFIGURATION
    // ============================================================================

    const CONFIG = {
        VERSION: 'v1.1',

        // Performance
        SCROLL_INTERVAL: 8,                    // ms between scrolls (was 10)
        UI_UPDATE_THROTTLE: 50,                // ms between UI updates
        OPTIMIZATION_DELAY: 300,               // ms to wait after hiding elements
        RESTORE_DELAY: 200,                    // ms before restoring elements

        // Retry Logic
        MAX_INIT_ATTEMPTS: 40,
        INIT_CHECK_INTERVAL: 500,
        MAX_NO_CHANGE_COUNT: 40,
        RETRY_RAPID_SCROLL_THRESHOLD: 10,
        RETRY_SCROLL_RESET_THRESHOLD: 20,
        RETRY_DEEP_SCAN_THRESHOLD: 30,
        MAX_RETRY_ATTEMPTS: 5,
        MIN_ACCEPTABLE_PERCENT: 95,

        // UI
        TOAST_DURATION: 3000,
        TOAST_ANIMATION_DURATION: 300,
        MODAL_ANIMATION_DURATION: 300,
        LIST_PREVIEW_LIMIT: 15,

        // Storage
        STORAGE_KEY_ELEMENTS: 'infinecraft_synced_elements',
        STORAGE_KEY_THEME: 'infinecraft_theme_preset',
        STORAGE_KEY_VERSION: 'sync_last_version',
        STORAGE_KEY_EXPORT_HISTORY: 'sync_export_history',
        MAX_EXPORT_HISTORY: 10,

        // Scroll Recovery
        RECOVERY_SCROLL_POSITIONS: [0, 0.2, 0.4, 0.6, 0.8, 1.0],
        RECOVERY_POSITION_DELAY: 100,
        RAPID_SCROLL_COUNT: 5,
        RAPID_SCROLL_DELAY: 50,

        // History tracking
        SPEED_HISTORY_WINDOW: 3000,            // ms to keep speed history

        // Animation
        MODAL_FADE_DURATION: '0.3s',
        TOAST_SLIDE_DURATION: '0.3s'
    };

    // ============================================================================
    // STATE MANAGEMENT
    // ============================================================================

    const state = {
        allElements: [],
        pluginInitialized: false,
        isScanning: false,
        loadingOverlay: null,
        hiddenElements: { elements: [], styles: [] },
        boundListeners: [],
        rafId: null,
        lastUIUpdate: 0,
        exportHistory: []
    };

    // ============================================================================
    // PERFORMANCE OPTIMIZATION - SAFE MODE
    // ============================================================================

    function hideGameElements() {
        console.log('[SYNC] 🚀 Optimizing performance (safe mode)...');

        try {
            const instances = document.querySelector('.instances');
            if (instances) {
                state.hiddenElements.elements.push({
                    element: instances,
                    display: instances.style.display,
                    visibility: instances.style.visibility
                });
                instances.style.visibility = 'hidden';
                console.log('[SYNC] ✓ Hidden .instances');
            }

            // Batch DOM operations
            const craftedItems = document.querySelectorAll('.instance');
            const fragment = document.createDocumentFragment();

            craftedItems.forEach(item => {
                state.hiddenElements.elements.push({
                    element: item,
                    display: item.style.display,
                    visibility: item.style.visibility
                });
                item.style.visibility = 'hidden';
            });

            if (craftedItems.length > 0) {
                console.log(`[SYNC] ✓ Hidden ${craftedItems.length} items`);
            }

            const canvases = document.querySelectorAll('canvas');
            canvases.forEach(canvas => {
                if (!canvas.closest('#sidebar')) {
                    state.hiddenElements.elements.push({
                        element: canvas,
                        visibility: canvas.style.visibility
                    });
                    canvas.style.visibility = 'hidden';
                }
            });

            const style = document.createElement('style');
            style.id = 'turbo-sync-optimization';
            style.textContent = `
                * {
                    animation-duration: 0s !important;
                    animation-delay: 0s !important;
                    transition-duration: 0s !important;
                }
                #sidebar, #sidebar * {
                    animation: none !important;
                    transition: none !important;
                }
            `;
            document.head.appendChild(style);
            state.hiddenElements.styles.push(style);

            console.log('[SYNC] 🚀 Safe performance mode ACTIVE!');

        } catch (e) {
            console.warn('[SYNC] Warning during optimization:', e);
        }
    }

    function restoreGameElements() {
        console.log('[SYNC] 🔄 Restoring game elements...');

        try {
            // Batch restore
            state.hiddenElements.elements.forEach(({ element, display, visibility }) => {
                if (element) {
                    if (display !== undefined) element.style.display = display || '';
                    if (visibility !== undefined) element.style.visibility = visibility || '';
                }
            });

            state.hiddenElements.styles.forEach(style => {
                if (style?.parentNode) {
                    style.parentNode.removeChild(style);
                }
            });

            console.log('[SYNC] ✓ Restored all game elements');
            state.hiddenElements = { elements: [], styles: [] };

        } catch (e) {
            console.warn('[SYNC] Warning during restoration:', e);

            // Failsafe
            const optimizationStyle = document.getElementById('turbo-sync-optimization');
            optimizationStyle?.remove();

            try {
                document.querySelectorAll('.instances, .instance').forEach(el => {
                    el.style.visibility = '';
                    el.style.display = '';
                });
            } catch (e2) {
                console.error('[SYNC] Failed to force restore:', e2);
            }
        }
    }

    // ============================================================================
    // UTILITY FUNCTIONS
    // ============================================================================

    function waitForMainScript() {
        return new Promise((resolve) => {
            let attempts = 0;

            const checkInterval = setInterval(() => {
                attempts++;
                const mainPanel = document.getElementById('auto-dragger-panel');

                if (mainPanel || attempts >= CONFIG.MAX_INIT_ATTEMPTS) {
                    clearInterval(checkInterval);
                    resolve(true);
                }
            }, CONFIG.INIT_CHECK_INTERVAL);
        });
    }

    function isAutoDraggerRunning() {
        const statusText = document.getElementById('status-text');
        return statusText?.textContent.trim() === 'RUNNING';
    }

    function getCurrentTheme() {
        try {
            const badge = document.querySelector('.theme-badge');
            if (badge) return badge.textContent.toLowerCase().trim();
        } catch (e) {}
        return localStorage.getItem(CONFIG.STORAGE_KEY_THEME) || 'hacker';
    }

    // Memoized theme colors for performance
    let cachedTheme = null;
    let cachedColors = null;

    function getThemeColors() {
        const currentTheme = getCurrentTheme();

        if (cachedTheme === currentTheme && cachedColors) {
            return cachedColors;
        }

        const themes = {
            hacker: {
                bg: '#000',
                bgOverlay: 'rgba(0, 20, 0, 0.98)',
                border: '#0f0',
                text: '#0f0',
                textSecondary: '#0a0',
                accent: '#0f0',
                accentDim: 'rgba(0, 255, 0, 0.2)',
                success: '#10b981',
                error: '#ef4444',
                warning: '#f59e0b',
                info: '#3b82f6',
                btnBg: '#001a00',
                surface: 'rgba(0, 255, 0, 0.05)',
                font: "'Courier New', monospace"
            },
            furry: {
                bg: '#fff0f5',
                bgOverlay: 'rgba(255, 240, 245, 0.98)',
                border: '#ff69b4',
                text: '#880044',
                textSecondary: '#ff8da1',
                accent: '#ff1493',
                accentDim: 'rgba(255, 105, 180, 0.1)',
                success: '#ff1493',
                error: '#ff0000',
                warning: '#ffca00',
                info: '#00bfff',
                btnBg: '#ffe4f0',
                surface: 'rgba(255, 255, 255, 0.6)',
                font: "'Comic Sans MS', 'Chalkboard SE', sans-serif"
            },
            synthwave: {
                bg: '#140028',
                bgOverlay: 'rgba(20, 0, 40, 0.98)',
                border: '#00f3ff',
                text: '#ff00ff',
                textSecondary: '#bd00ff',
                accent: '#00f3ff',
                accentDim: 'rgba(0, 243, 255, 0.15)',
                success: '#00ff9d',
                error: '#ff2a2a',
                warning: '#ffdd00',
                info: '#00f3ff',
                btnBg: '#2a0050',
                surface: 'rgba(255, 0, 255, 0.05)',
                font: "'Courier New', monospace"
            }
        };

        cachedTheme = currentTheme;
        cachedColors = themes[currentTheme] || themes.hacker;
        return cachedColors;
    }

    function formatETA(seconds) {
        if (seconds < 60) return `${Math.ceil(seconds)}s`;
        if (seconds < 3600) {
            const mins = Math.floor(seconds / 60);
            const secs = Math.ceil(seconds % 60);
            return `${mins}m ${secs}s`;
        }
        const hours = Math.floor(seconds / 3600);
        const mins = Math.floor((seconds % 3600) / 60);
        return `${hours}h ${mins}m`;
    }

    // ============================================================================
    // UI HELPERS - WITH ACCESSIBILITY
    // ============================================================================

    function showModal(title, message, type = 'info', buttons = [{ text: 'OK', action: null }]) {
        return new Promise((resolve) => {
            const colors = getThemeColors();
            const modal = document.createElement('div');
            modal.setAttribute('role', 'dialog');
            modal.setAttribute('aria-modal', 'true');
            modal.setAttribute('aria-labelledby', 'modal-title');
            modal.setAttribute('aria-describedby', 'modal-message');

            modal.style.cssText = `
                position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                background: ${colors.bg}ee; backdrop-filter: blur(10px); z-index: 100000;
                display: flex; align-items: center; justify-content: center;
                font-family: ${colors.font}; animation: modalFadeIn ${CONFIG.MODAL_FADE_DURATION} ease;
            `;

            const typeIcons = { info: 'ℹ️', success: '✓', error: '✗', warning: '⚠️', question: '?' };
            const typeColors = {
                info: colors.accent,
                success: colors.success,
                error: colors.error,
                warning: colors.warning,
                question: colors.accent
            };
            const icon = typeIcons[type] || typeIcons.info;
            const iconColor = typeColors[type] || typeColors.info;

            modal.innerHTML = `
                <style>
                    @keyframes modalFadeIn { from { opacity: 0; } to { opacity: 1; } }
                    @keyframes modalSlideIn { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
                    .modal-box {
                        background: ${colors.bgOverlay}; border: 2px solid ${colors.border};
                        border-radius: 8px; padding: 30px 40px; box-shadow: 0 0 40px ${colors.border}80;
                        min-width: 400px; max-width: 600px; animation: modalSlideIn ${CONFIG.MODAL_FADE_DURATION} ease;
                    }
                    .modal-icon { font-size: 48px; text-align: center; margin-bottom: 20px; color: ${iconColor}; text-shadow: 0 0 20px ${iconColor}; font-weight: 700; }
                    .modal-title { font-size: 20px; font-weight: 700; text-align: center; margin-bottom: 20px; color: ${colors.text}; text-transform: uppercase; letter-spacing: 2px; }
                    .modal-message { font-size: 14px; line-height: 1.8; text-align: center; margin-bottom: 25px; color: ${colors.textSecondary}; white-space: pre-line; }
                    .modal-buttons { display: flex; gap: 12px; justify-content: center; }
                    .modal-btn {
                        padding: 12px 30px; border: 2px solid ${colors.border}; border-radius: 4px; background: ${colors.btnBg};
                        color: ${colors.text}; font-family: ${colors.font}; font-size: 12px; font-weight: 700;
                        cursor: pointer; transition: all 0.2s ease; text-transform: uppercase; letter-spacing: 1px;
                    }
                    .modal-btn:hover { background: ${colors.accent}; color: ${colors.bg}; box-shadow: 0 0 15px ${colors.accent}; transform: scale(1.05); }
                    .modal-btn:focus { outline: 2px solid ${colors.accent}; outline-offset: 2px; }
                    .modal-btn.primary { background: ${colors.accent}; color: ${colors.bg}; border-color: ${colors.accent}; }
                    .modal-btn.primary:hover { box-shadow: 0 0 20px ${colors.accent}; }
                </style>
                <div class="modal-box">
                    <div class="modal-icon" aria-hidden="true">${icon}</div>
                    <div class="modal-title" id="modal-title">${title}</div>
                    <div class="modal-message" id="modal-message">${message}</div>
                    <div class="modal-buttons" id="modal-buttons"></div>
                </div>
            `;

            document.body.appendChild(modal);
            const buttonsContainer = modal.querySelector('#modal-buttons');

            buttons.forEach((btn, index) => {
                const button = document.createElement('button');
                button.className = index === 0 ? 'modal-btn primary' : 'modal-btn';
                button.textContent = btn.text;
                button.setAttribute('type', 'button');

                button.addEventListener('click', () => {
                    modal.style.opacity = '0';
                    modal.style.transition = `opacity ${CONFIG.MODAL_FADE_DURATION} ease`;
                    setTimeout(() => {
                        modal.remove();
                        resolve(btn.value !== undefined ? btn.value : true);
                        if (btn.action) btn.action();
                    }, CONFIG.TOAST_ANIMATION_DURATION);
                });

                buttonsContainer.appendChild(button);
                if (index === 0) button.focus(); // Auto-focus primary button
            });

            // ESC to close
            const handleEsc = (e) => {
                if (e.key === 'Escape') {
                    modal.querySelector('.modal-btn').click();
                    document.removeEventListener('keydown', handleEsc);
                }
            };
            document.addEventListener('keydown', handleEsc);
        });
    }

    function showPluginToast(message, type = 'info') {
        const colors = getThemeColors();
        const typeColors = {
            success: colors.success,
            error: colors.error,
            info: colors.accent,
            warning: colors.warning
        };
        const bgColor = typeColors[type] || typeColors.info;
        const textColor = getCurrentTheme() === 'furry' ? '#fff' : '#000';

        const toast = document.createElement('div');
        toast.setAttribute('role', 'status');
        toast.setAttribute('aria-live', 'polite');

        toast.style.cssText = `
            position: fixed; top: 140px; right: 20px; background: ${bgColor}; padding: 16px 24px;
            border-radius: 8px; color: ${textColor}; font-family: ${colors.font}; font-size: 13px;
            box-shadow: 0 0 20px ${bgColor}; z-index: 10005; max-width: 300px; word-wrap: break-word;
            font-weight: 700; border: 2px solid ${colors.border}; animation: pluginSlideIn ${CONFIG.TOAST_SLIDE_DURATION} ease-out;
        `;

        const theme = getCurrentTheme();
        const prefix = theme === 'hacker' ? '⚡ ' : theme === 'furry' ? '★ ' : '◆ ';
        const suffix = theme === 'furry' ? ' UwU' : '';
        toast.textContent = prefix + '[SYNC] ' + message + suffix;

        if (!document.getElementById('plugin-toast-styles')) {
            const style = document.createElement('style');
            style.id = 'plugin-toast-styles';
            style.textContent = `
                @keyframes pluginSlideIn { from { transform: translateX(400px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
                @keyframes pluginSlideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(400px); opacity: 0; } }
            `;
            document.head.appendChild(style);
        }

        document.body.appendChild(toast);
        setTimeout(() => {
            toast.style.animation = `pluginSlideOut ${CONFIG.TOAST_SLIDE_DURATION} ease-out`;
            setTimeout(() => toast.remove(), CONFIG.TOAST_ANIMATION_DURATION);
        }, CONFIG.TOAST_DURATION);
    }

    // ============================================================================
    // LOADING OVERLAY - WITH RAF OPTIMIZATION
    // ============================================================================

    function createLoadingOverlay() {
        const colors = getThemeColors();
        state.loadingOverlay = document.createElement('div');
        state.loadingOverlay.id = 'element-sync-loading';
        state.loadingOverlay.setAttribute('role', 'alert');
        state.loadingOverlay.setAttribute('aria-live', 'assertive');
        state.loadingOverlay.setAttribute('aria-busy', 'true');

        state.loadingOverlay.style.cssText = `
            position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: ${colors.bg}ee;
            z-index: 99999; display: flex; flex-direction: column; align-items: center; justify-content: center;
            font-family: ${colors.font}; color: ${colors.text}; backdrop-filter: blur(10px);
        `;

        state.loadingOverlay.innerHTML = `
            <style>
                @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
                @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.7; transform: scale(0.95); } }
                .loading-spinner {
                    width: 60px; height: 60px; border: 4px solid ${colors.accentDim}; border-top: 4px solid ${colors.accent};
                    border-radius: 50%; animation: spin 0.3s linear infinite; margin-bottom: 30px;
                }
                .loading-box {
                    background: ${colors.bgOverlay}; border: 2px solid ${colors.border}; border-radius: 8px;
                    padding: 40px 60px; box-shadow: 0 0 40px ${colors.border}80; text-align: center; max-width: 600px;
                }
                .loading-title { font-size: 24px; font-weight: 700; margin-bottom: 20px; text-transform: uppercase; letter-spacing: 2px; text-shadow: 0 0 10px ${colors.accent}; }
                .loading-status { font-size: 14px; margin-bottom: 15px; animation: pulse 2s ease-in-out infinite; color: ${colors.textSecondary}; }
                .loading-progress { font-size: 20px; font-weight: 700; margin-bottom: 10px; color: ${colors.accent}; }
                .loading-eta { font-size: 16px; font-weight: 600; margin-bottom: 20px; color: ${colors.warning}; }
                .loading-speed { font-size: 12px; margin-bottom: 20px; color: ${colors.textSecondary}; }
                .loading-bar-container {
                    width: 400px; height: 20px; background: ${colors.accentDim}; border-radius: 10px;
                    overflow: hidden; margin-bottom: 20px; border: 1px solid ${colors.border};
                }
                .loading-bar {
                    height: 100%; background: ${colors.accent}; width: 0%;
                    transition: width 0.3s ease; box-shadow: 0 0 10px ${colors.accent};
                    will-change: width;
                }
                .loading-info { font-size: 11px; opacity: 0.7; margin-top: 20px; line-height: 1.6; color: ${colors.textSecondary}; }
            </style>
            <div class="loading-box">
                <div class="loading-spinner" aria-hidden="true"></div>
                <div class="loading-title">⚡ SYNCING ELEMENTS ⚡</div>
                <div class="loading-status" id="loading-status">Optimizing...</div>
                <div class="loading-progress" id="loading-progress" aria-live="polite">0 / 0</div>
                <div class="loading-eta" id="loading-eta">Calculating ETA...</div>
                <div class="loading-speed" id="loading-speed">Speed: 0 items/s</div>
                <div class="loading-bar-container"><div class="loading-bar" id="loading-bar"></div></div>
                <div class="loading-info">
                    <div style="font-weight:700;margin-bottom:8px;">⚡ ULTRA-OPTIMIZED MODE ⚡</div>
                    <div>RAF-powered updates • Smart batching • Maximum velocity</div>
                </div>
            </div>
        `;

        document.body.appendChild(state.loadingOverlay);
    }

    // Use RAF for smooth 60fps updates
    function updateLoadingOverlay(status, current, total, eta = null, speed = null) {
        if (!state.loadingOverlay) return;

        const now = performance.now();
        if (now - state.lastUIUpdate < CONFIG.UI_UPDATE_THROTTLE) return;

        if (state.rafId) cancelAnimationFrame(state.rafId);

        state.rafId = requestAnimationFrame(() => {
            const statusEl = document.getElementById('loading-status');
            const progressEl = document.getElementById('loading-progress');
            const etaEl = document.getElementById('loading-eta');
            const speedEl = document.getElementById('loading-speed');
            const barEl = document.getElementById('loading-bar');

            if (statusEl) statusEl.textContent = status;
            if (progressEl) progressEl.textContent = `${current.toLocaleString()} / ${total.toLocaleString()}`;
            if (etaEl) etaEl.textContent = eta !== null && eta > 0 ? `ETA: ${formatETA(eta)}` : 'Calculating...';
            if (speedEl) speedEl.textContent = speed !== null ? `⚡ ${speed.toFixed(0)} items/s` : 'Calculating...';
            if (barEl && total > 0) {
                const percentage = Math.min(100, (current / total) * 100);
                barEl.style.width = percentage + '%';
            }

            state.lastUIUpdate = now;
            state.rafId = null;
        });
    }

    function removeLoadingOverlay() {
        if (state.rafId) {
            cancelAnimationFrame(state.rafId);
            state.rafId = null;
        }

        if (state.loadingOverlay) {
            state.loadingOverlay.style.opacity = '0';
            state.loadingOverlay.style.transition = 'opacity 0.5s ease';
            setTimeout(() => {
                if (state.loadingOverlay) {
                    state.loadingOverlay.remove();
                    state.loadingOverlay = null;
                }
            }, 500);
        }
    }

    // ============================================================================
    // ELEMENT SCANNING - ULTRA OPTIMIZED
    // ============================================================================

    function getTotalItemCount() {
        const searchInput = document.querySelector('.sidebar-input');
        if (!searchInput) return null;
        const placeholder = searchInput.getAttribute('placeholder') || '';
        const match = placeholder.match(/\(([0-9,]+)\)/);
        return match ? parseInt(match[1].replace(/,/g, '')) : null;
    }

    async function scrollAndLoadAllItems(sidebar, totalExpected) {
        updateLoadingOverlay('⚡ TURBO SCROLLING...', 0, totalExpected);

        const itemsInner = sidebar.querySelector('.items-inner');
        if (!itemsInner) {
            throw new Error(
                'Cannot find element list!\n\n' +
                'The game layout may have changed.\n' +
                'Try refreshing the page and scanning again.'
            );
        }

        const startTime = Date.now();
        let itemHistory = [];
        let updateCounter = 0;
        let noChangeCounter = 0;
        let lastCount = 0;
        let retryAttempts = 0;

        while (true) {
            const currentItemCount = itemsInner.querySelectorAll('[data-item]').length;

            updateCounter++;

            // Throttled UI updates
            if (updateCounter % 10 === 0) {
                const now = Date.now();
                itemHistory.push({ count: currentItemCount, time: now });
                itemHistory = itemHistory.filter(h => now - h.time < CONFIG.SPEED_HISTORY_WINDOW);

                let loadingSpeed = 0;
                if (itemHistory.length >= 2) {
                    const oldest = itemHistory[0];
                    const newest = itemHistory[itemHistory.length - 1];
                    const timeDiff = (newest.time - oldest.time) / 1000;
                    const itemDiff = newest.count - oldest.count;
                    if (timeDiff > 0) loadingSpeed = itemDiff / timeDiff;
                }

                let eta = null;
                if (loadingSpeed > 0 && currentItemCount < totalExpected) {
                    eta = (totalExpected - currentItemCount) / loadingSpeed;
                }

                const percentLoaded = (currentItemCount / totalExpected) * 100;
                updateLoadingOverlay(
                    `⚡ ULTRA: ${currentItemCount.toLocaleString()} / ${totalExpected.toLocaleString()} (${percentLoaded.toFixed(1)}%)`,
                    currentItemCount, totalExpected, eta, loadingSpeed
                );
            }

            if (currentItemCount >= totalExpected) {
                console.log(`[SYNC] ✓ 100% Target reached: ${currentItemCount} items`);
                break;
            }

            if (currentItemCount === lastCount) {
                noChangeCounter++;
                const percentLoaded = (currentItemCount / totalExpected) * 100;

                if (noChangeCounter === CONFIG.RETRY_RAPID_SCROLL_THRESHOLD) {
                    console.log(`[SYNC] ⚠ Slow loading at ${percentLoaded.toFixed(1)}% - rapid scrolls...`);
                    updateLoadingOverlay(`⚠ Recovery: Rapid Scrolls (${percentLoaded.toFixed(1)}%)`, currentItemCount, totalExpected);

                    for (let i = 0; i < CONFIG.RAPID_SCROLL_COUNT; i++) {
                        sidebar.scrollTop = sidebar.scrollHeight;
                        await new Promise(resolve => setTimeout(resolve, CONFIG.RAPID_SCROLL_DELAY));
                    }
                }

                if (noChangeCounter === CONFIG.RETRY_SCROLL_RESET_THRESHOLD) {
                    console.log(`[SYNC] ⚠ Still stuck - scroll reset...`);
                    updateLoadingOverlay(`⚠ Recovery: Scroll Reset (${percentLoaded.toFixed(1)}%)`, currentItemCount, totalExpected);

                    sidebar.scrollTop = 0;
                    await new Promise(resolve => setTimeout(resolve, CONFIG.RECOVERY_POSITION_DELAY));
                    sidebar.scrollTop = sidebar.scrollHeight;
                    await new Promise(resolve => setTimeout(resolve, CONFIG.RECOVERY_POSITION_DELAY * 2));
                }

                if (noChangeCounter === CONFIG.RETRY_DEEP_SCAN_THRESHOLD) {
                    if (retryAttempts < CONFIG.MAX_RETRY_ATTEMPTS) {
                        retryAttempts++;
                        console.log(`[SYNC] ⚠ Retry ${retryAttempts}/${CONFIG.MAX_RETRY_ATTEMPTS}`);
                        updateLoadingOverlay(`⚠ Retry ${retryAttempts}/${CONFIG.MAX_RETRY_ATTEMPTS}: Deep Scan`, currentItemCount, totalExpected);

                        for (const ratio of CONFIG.RECOVERY_SCROLL_POSITIONS) {
                            sidebar.scrollTop = sidebar.scrollHeight * ratio;
                            await new Promise(resolve => setTimeout(resolve, CONFIG.RECOVERY_POSITION_DELAY));
                        }

                        sidebar.scrollTop = sidebar.scrollHeight;
                        await new Promise(resolve => setTimeout(resolve, 500));

                        const recheckCount = itemsInner.querySelectorAll('[data-item]').length;
                        if (recheckCount > currentItemCount) {
                            console.log(`[SYNC] ✓ Retry successful! +${recheckCount - currentItemCount}`);
                            noChangeCounter = 0;
                            lastCount = recheckCount;
                            continue;
                        }

                        noChangeCounter = 0;
                        continue;
                    }
                }

                if (noChangeCounter >= CONFIG.MAX_NO_CHANGE_COUNT) {
                    const finalPercent = (currentItemCount / totalExpected) * 100;

                    if (finalPercent >= CONFIG.MIN_ACCEPTABLE_PERCENT) {
                        console.log(`[SYNC] ✓ ${finalPercent.toFixed(1)}% loaded - acceptable`);
                        break;
                    }

                    throw new Error(
                        `Could not load all items!\n\n` +
                        `Loaded: ${currentItemCount.toLocaleString()} / ${totalExpected.toLocaleString()} (${finalPercent.toFixed(1)}%)\n\n` +
                        `Recovery suggestions:\n` +
                        `1. Refresh the page and wait 5 seconds\n` +
                        `2. Close other heavy tabs\n` +
                        `3. Clear browser cache\n` +
                        `4. Try again with fewer browser extensions`
                    );
                }
            } else {
                noChangeCounter = 0;
                if (currentItemCount > lastCount + 50) retryAttempts = 0;
            }

            lastCount = currentItemCount;
            sidebar.scrollTop = sidebar.scrollHeight;
            await new Promise(resolve => setTimeout(resolve, CONFIG.SCROLL_INTERVAL));
        }

        const finalItemCount = itemsInner.querySelectorAll('[data-item]').length;
        const elapsedTime = (Date.now() - startTime) / 1000;
        const percentLoaded = (finalItemCount / totalExpected) * 100;

        console.log(`[SYNC] ✓ Complete: ${finalItemCount}/${totalExpected} (${percentLoaded.toFixed(1)}%) in ${elapsedTime.toFixed(1)}s`);

        return {
            totalItems: finalItemCount,
            itemsInner,
            percentLoaded,
            expectedTotal: totalExpected
        };
    }

    async function scanAllElements() {
        if (state.isScanning) {
            showPluginToast('Already scanning...', 'warning');
            return;
        }

        if (isAutoDraggerRunning()) {
            await showModal(
                'AUTO DRAGGER RUNNING',
                'Please stop the Auto Dragger before scanning.\n\nClick [STOP] then try again.',
                'error',
                [{ text: 'OK' }]
            );
            return;
        }

        state.isScanning = true;
        state.allElements = [];

        const startBtn = document.getElementById('start-btn');
        const wasStartDisabled = startBtn?.disabled;
        if (startBtn) {
            startBtn.disabled = true;
            startBtn.textContent = '[SCANNING]';
        }

        const scanBtn = document.getElementById('sync-scan-btn');
        if (scanBtn) {
            scanBtn.textContent = '[SCANNING...]';
            scanBtn.disabled = true;
        }

        createLoadingOverlay();

        try {
            updateLoadingOverlay('⚡ Optimizing performance...', 0, 0);
            hideGameElements();
            await new Promise(resolve => setTimeout(resolve, CONFIG.OPTIMIZATION_DELAY));

            updateLoadingOverlay('Reading item count...', 0, 0);
            const totalExpected = getTotalItemCount();
            if (!totalExpected) {
                throw new Error(
                    'Cannot read item count!\n\n' +
                    'Make sure the sidebar is visible.\n' +
                    'Refresh the page and try again.'
                );
            }

            updateLoadingOverlay('Finding sidebar...', 0, totalExpected);
            const sidebar = document.getElementById('sidebar');
            if (!sidebar) {
                throw new Error(
                    'Sidebar not found!\n\n' +
                    'The game layout may have changed.\n' +
                    'Please refresh and try again.'
                );
            }

            const { totalItems, itemsInner, percentLoaded, expectedTotal } = await scrollAndLoadAllItems(sidebar, totalExpected);

            updateLoadingOverlay('⚡ Extracting elements...', 0, totalItems);

            // Optimized extraction with Set for O(1) lookups
            const allItems = itemsInner.querySelectorAll('[data-item]');
            const seenIds = new Set();
            const seenTexts = new Set();
            const elements = [];

            allItems.forEach((item) => {
                const emoji = item.getAttribute('data-item-emoji') || '';
                const text = item.getAttribute('data-item-text') || '';
                const id = item.getAttribute('data-item-id') || '';
                const isDiscovery = item.hasAttribute('data-item-discovery');

                if (text && !((id && seenIds.has(id)) || seenTexts.has(text))) {
                    if (id) seenIds.add(id);
                    seenTexts.add(text);

                    elements.push({
                        id,
                        name: emoji ? `${emoji} ${text}` : text,
                        emoji,
                        text,
                        isFirstDiscovery: isDiscovery,
                        scanned: new Date().toISOString(),
                        scannedDate: new Date().toLocaleString()
                    });
                }
            });

            // Efficient sort with numeric comparison
            elements.sort((a, b) => {
                const idA = parseInt(a.id);
                const idB = parseInt(b.id);
                if (!isNaN(idA) && !isNaN(idB)) return idA - idB;
                return 0;
            });

            // Add indices
            elements.forEach((e, idx) => e.index = idx + 1);

            state.allElements = elements;
            const foundCount = elements.length;

            saveElements();
            updateLoadingOverlay('✓ Complete! Restoring...', foundCount, foundCount);

            await new Promise(resolve => setTimeout(resolve, CONFIG.RESTORE_DELAY));
            restoreGameElements();

            setTimeout(async () => {
                removeLoadingOverlay();
                showPluginToast(`Synced ${foundCount} elements!`, 'success');
                updatePluginUI();

                const firstDiscoveryCount = state.allElements.filter(e => e.isFirstDiscovery).length;

                let message = `⚡ SYNC COMPLETE ⚡\n\n`;
                message += `Scanned: ${totalItems.toLocaleString()} / ${expectedTotal.toLocaleString()} items (${percentLoaded.toFixed(1)}%)\n`;
                message += `Total Elements: ${foundCount}\n`;
                message += `First Discoveries: ${firstDiscoveryCount}\n`;

                if (percentLoaded < 100) {
                    message += `\n⚠️ WARNING: Only ${percentLoaded.toFixed(1)}% loaded!\n`;
                    message += `Some items may be missing.\n`;
                    message += `Consider rescanning for complete results.`;
                }

                message += `\n\nReady to export!`;

                await showModal(
                    percentLoaded >= 100 ? 'SYNC COMPLETE' : 'SYNC COMPLETE (PARTIAL)',
                    message,
                    percentLoaded >= 100 ? 'success' : 'warning',
                    [{ text: 'AWESOME!' }]
                );
            }, 500);

        } catch (e) {
            console.error('[SYNC]', e);
            restoreGameElements();
            removeLoadingOverlay();
            showPluginToast(`Scan failed!`, 'error');
            await showModal('SYNC ERROR', `${e.message}`, 'error', [{ text: 'OK' }]);
        } finally {
            state.isScanning = false;
            if (startBtn && !wasStartDisabled) {
                startBtn.disabled = false;
                startBtn.textContent = '[START]';
            }
            if (scanBtn) {
                scanBtn.textContent = '⚡ [SYNC ALL] ⚡';
                scanBtn.disabled = false;
            }
        }
    }

    // ============================================================================
    // DATA MANAGEMENT - WITH QUOTA HANDLING
    // ============================================================================

    function saveElements() {
        try {
            localStorage.setItem(CONFIG.STORAGE_KEY_ELEMENTS, JSON.stringify(state.allElements));
            return true;
        } catch (e) {
            console.error('[SYNC] Save failed:', e);
            if (e.name === 'QuotaExceededError') {
                showPluginToast('Storage full! Export to free space.', 'error');
                showModal(
                    'STORAGE FULL',
                    'Your browser storage is full!\n\n' +
                    'Please export your data, then clear it to free up space.\n\n' +
                    'Your current scan is safe, but cannot be saved.',
                    'error',
                    [{ text: 'OK' }]
                );
            } else {
                showPluginToast('Save failed! Check console.', 'error');
            }
            return false;
        }
    }

    function loadElements() {
        try {
            const saved = localStorage.getItem(CONFIG.STORAGE_KEY_ELEMENTS);
            if (saved) {
                state.allElements = JSON.parse(saved);
                console.log(`[SYNC] ✓ Loaded ${state.allElements.length} elements from storage`);
            }
        } catch (e) {
            console.error('[SYNC] Load failed:', e);
            state.allElements = [];
            showPluginToast('Failed to load saved data', 'warning');
        }
    }

    function loadExportHistory() {
        try {
            const saved = localStorage.getItem(CONFIG.STORAGE_KEY_EXPORT_HISTORY);
            if (saved) state.exportHistory = JSON.parse(saved);
        } catch (e) {
            state.exportHistory = [];
        }
    }

    function saveExportHistory(type, count) {
        state.exportHistory.push({
            date: Date.now(),
            dateFormatted: new Date().toLocaleString(),
            count,
            type
        });

        // Keep only last 10
        state.exportHistory = state.exportHistory.slice(-CONFIG.MAX_EXPORT_HISTORY);

        try {
            localStorage.setItem(CONFIG.STORAGE_KEY_EXPORT_HISTORY, JSON.stringify(state.exportHistory));
        } catch (e) {
            console.warn('[SYNC] Could not save export history:', e);
        }
    }

    // ============================================================================
    // EXPORT FUNCTIONS - OPTIMIZED
    // ============================================================================

    function exportAsJSON() {
        if (state.allElements.length === 0) {
            showPluginToast('No elements! Sync first.', 'warning');
            return;
        }

        const firstDiscoveryCount = state.allElements.filter(e => e.isFirstDiscovery).length;

        const exportData = {
            pluginVersion: CONFIG.VERSION,
            exportDate: new Date().toISOString(),
            exportDateFormatted: new Date().toLocaleString(),
            totalElements: state.allElements.length,
            totalFirstDiscoveries: firstDiscoveryCount,
            elements: state.allElements.map((e) => ({
                index: e.index,
                id: e.id,
                name: e.name,
                emoji: e.emoji,
                text: e.text,
                isFirstDiscovery: e.isFirstDiscovery,
                scannedAt: e.scannedDate,
                timestamp: e.scanned
            }))
        };

        try {
            const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `infinite-craft-ALL-ELEMENTS-${Date.now()}.json`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            saveExportHistory('JSON', state.allElements.length);
            showPluginToast(`Exported ${state.allElements.length} elements!`, 'success');
        } catch (e) {
            console.error('[SYNC] Export failed:', e);
            showPluginToast('Export failed! Check console.', 'error');
        }
    }

    function exportAsCSV() {
        if (state.allElements.length === 0) {
            showPluginToast('No elements!', 'warning');
            return;
        }

        let csv = 'Index,ID,Emoji,Name,First Discovery,Scanned At\n';
        state.allElements.forEach(e => {
            const name = e.text.replace(/"/g, '""');
            csv += `${e.index},${e.id},"${e.emoji}","${name}",${e.isFirstDiscovery ? 'YES' : 'NO'},"${e.scannedDate}"\n`;
        });

        try {
            const blob = new Blob([csv], { type: 'text/csv' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `infinite-craft-ALL-ELEMENTS-${Date.now()}.csv`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            saveExportHistory('CSV', state.allElements.length);
            showPluginToast(`Exported CSV!`, 'success');
        } catch (e) {
            console.error('[SYNC] CSV export failed:', e);
            showPluginToast('CSV failed!', 'error');
        }
    }

    function exportAsTxt() {
        if (state.allElements.length === 0) {
            showPluginToast('No elements!', 'warning');
            return;
        }

        const firstDiscoveryCount = state.allElements.filter(e => e.isFirstDiscovery).length;

        let txt = `INFINITE CRAFT - ALL ELEMENTS\n`;
        txt += `Total Elements: ${state.allElements.length}\n`;
        txt += `First Discoveries: ${firstDiscoveryCount}\n`;
        txt += `Exported: ${new Date().toLocaleString()}\n${'='.repeat(60)}\n\n`;

        state.allElements.forEach(e => {
            txt += `${e.index}. ${e.name}`;
            if (e.isFirstDiscovery) txt += ' 🌟';
            txt += '\n';
        });

        try {
            const blob = new Blob([txt], { type: 'text/plain' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `infinite-craft-ALL-ELEMENTS-${Date.now()}.txt`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            saveExportHistory('TXT', state.allElements.length);
            showPluginToast(`Exported TXT!`, 'success');
        } catch (e) {
            console.error('[SYNC] TXT export failed:', e);
            showPluginToast('TXT failed!', 'error');
        }
    }

    async function clearElements() {
        if (state.allElements.length === 0) {
            showPluginToast('No data!', 'info');
            return;
        }

        const confirmed = await showModal(
            'CLEAR DATA',
            `Delete all ${state.allElements.length} synced elements?\n\nThis cannot be undone!`,
            'warning',
            [{ text: 'DELETE', value: true }, { text: 'CANCEL', value: false }]
        );

        if (confirmed) {
            state.allElements = [];
            saveElements();
            updatePluginUI();
            showPluginToast('Cleared!', 'info');
        }
    }

    // ============================================================================
    // UI FUNCTIONS - OPTIMIZED
    // ============================================================================

    function updatePluginUI() {
        // Batch DOM reads/writes
        requestAnimationFrame(() => {
            const counter = document.getElementById('sync-element-count');
            if (counter) counter.textContent = state.allElements.length.toLocaleString();

            const discoveryCounter = document.getElementById('sync-discovery-count');
            if (discoveryCounter) {
                const firstDiscoveries = state.allElements.filter(e => e.isFirstDiscovery).length;
                discoveryCounter.textContent = firstDiscoveries.toLocaleString();
            }

            const list = document.getElementById('sync-element-list');
            if (list) {
                if (state.allElements.length === 0) {
                    list.innerHTML = '<div style="font-size:11px;opacity:0.7;font-style:italic;text-align:center;padding:20px;">Click [SYNC ALL] to begin!</div>';
                } else {
                    const displayItems = state.allElements.slice(0, CONFIG.LIST_PREVIEW_LIMIT);
                    const fragment = document.createDocumentFragment();

                    displayItems.forEach((e) => {
                        const div = document.createElement('div');
                        div.className = 'element-item';
                        div.style.cssText = `margin-bottom:4px;padding:6px 8px;background:var(--theme-surface);border-radius:3px;border-left:3px solid ${e.isFirstDiscovery ? 'var(--theme-success)' : 'var(--theme-info)'}`;
                        div.innerHTML = `
                            <div style="display:flex;justify-content:space-between;align-items:center;gap:8px;">
                                <span style="font-weight:700;font-size:11px;flex:1;">#${e.index} ${e.name} ${e.isFirstDiscovery ? '🌟' : ''}</span>
                                <span style="font-size:9px;opacity:0.6;font-weight:600;">ID:${e.id}</span>
                            </div>
                        `;
                        fragment.appendChild(div);
                    });

                    list.innerHTML = '';
                    list.appendChild(fragment);

                    if (state.allElements.length > CONFIG.LIST_PREVIEW_LIMIT) {
                        const moreDiv = document.createElement('div');
                        moreDiv.style.cssText = 'font-size:10px;opacity:0.6;text-align:center;margin-top:8px;font-weight:700;padding:6px;background:var(--theme-accentDim);border-radius:3px;';
                        moreDiv.textContent = `...${state.allElements.length - CONFIG.LIST_PREVIEW_LIMIT} more (Total: ${state.allElements.length})`;
                        list.appendChild(moreDiv);
                    }
                }
            }
        });
    }

    function injectPluginUI() {
        if (document.getElementById('element-sync-plugin-section')) return true;

        const mainPanel = document.getElementById('auto-dragger-panel');

        if (mainPanel) {
            const settingsTab = document.querySelector('[data-tab-content="settings"]');
            if (settingsTab) {
                const pluginSection = createPluginSection();
                settingsTab.insertBefore(pluginSection, settingsTab.firstChild);
                setupEventListeners();
                updatePluginUI();
                return true;
            }
        }

        createStandalonePanel();
        setupEventListeners();
        updatePluginUI();
        return true;
    }

    function createPluginSection() {
        const section = document.createElement('div');
        section.id = 'element-sync-plugin-section';
        section.className = 'section';
        section.style.cssText = 'border: 2px solid var(--theme-info); box-shadow: 0 0 10px var(--theme-info);';
        section.innerHTML = `
            <div class="section-title" style="display:flex;justify-content:space-between;align-items:center;">
                <span>⚡ ELEMENT SYNC ULTRA</span>
                <span style="font-size:9px;opacity:0.8;font-weight:700;">${CONFIG.VERSION}</span>
            </div>

            <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px;">
                <div class="data-box">
                    <div class="data-box-header">Total Elements</div>
                    <div class="data-box-value" id="sync-element-count" style="font-size:32px;text-shadow:0 0 10px var(--theme-info);">0</div>
                </div>
                <div class="data-box">
                    <div class="data-box-header">First Discoveries</div>
                    <div class="data-box-value" id="sync-discovery-count" style="font-size:32px;text-shadow:0 0 10px var(--theme-success);">0</div>
                </div>
            </div>

            <div style="display:flex;gap:8px;margin-bottom:12px;">
                <button id="sync-scan-btn" class="small-btn" style="flex:1;background:var(--theme-info);color:#000;border:2px solid var(--theme-info);padding:14px !important;font-weight:700;font-size:13px !important;text-shadow:0 0 5px rgba(0,0,0,0.3);">
                    ⚡ [SYNC ALL] ⚡
                </button>
            </div>

            <div class="discoveries" id="sync-element-list" style="max-height:280px;margin-bottom:12px;overflow-y:auto;border:1px solid var(--theme-border);border-radius:4px;padding:8px;background:var(--theme-accentDim);">
                <div style="font-size:11px;opacity:0.7;font-style:italic;text-align:center;padding:20px;">Click [SYNC ALL] to begin!</div>
            </div>

            <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:8px;">
                <button id="sync-export-json-btn" class="small-btn" style="background:transparent;color:var(--theme-info);border:2px solid var(--theme-info);padding:10px !important;font-weight:700;font-size:11px;">
                    [JSON]
                </button>
                <button id="sync-export-csv-btn" class="small-btn" style="background:transparent;color:var(--theme-info);border:2px solid var(--theme-info);padding:10px !important;font-weight:700;font-size:11px;">
                    [CSV]
                </button>
                <button id="sync-export-txt-btn" class="small-btn" style="background:transparent;color:var(--theme-info);border:2px solid var(--theme-info);padding:10px !important;font-weight:700;font-size:11px;">
                    [TXT]
                </button>
            </div>

            <div style="display:flex;gap:8px;margin-bottom:10px;">
                <button id="sync-clear-btn" class="small-btn" style="flex:1;background:transparent;color:var(--theme-error);border:2px solid var(--theme-error);padding:10px !important;font-weight:700;font-size:11px;">
                    [CLEAR DATA]
                </button>
            </div>

            <div style="font-size:9px;color:var(--theme-textSecondary);padding:10px;background:var(--theme-surface);border-radius:4px;border:1px solid var(--theme-border);line-height:1.7;">
                <div style="font-weight:700;margin-bottom:8px;color:var(--theme-text);font-size:10px;">⚡ ULTRA-OPTIMIZED:</div>
                <div>• RAF-powered 60fps updates</div>
                <div>• Smart batching & caching</div>
                <div>• 8ms scroll intervals (20% faster)</div>
                <div>• Storage quota protection</div>
                <div>• Auto-retry with 5 recovery modes</div>
                <div>• Marks first discoveries with 🌟</div>
                <div style="margin-top:8px;padding-top:8px;border-top:1px solid var(--theme-border);font-weight:600;">
                    Alt+Y = Sync | Alt+E = Export JSON
                </div>
            </div>
        `;
        return section;
    }

    function createStandalonePanel() {
        const colors = getThemeColors();
        const panel = document.createElement('div');
        panel.id = 'element-sync-standalone-panel';
        panel.style.cssText = `
            position: fixed; top: 20px; left: 20px; background: ${colors.bgOverlay};
            border: 2px solid ${colors.border}; border-radius: 8px; padding: 20px; z-index: 10000;
            min-width: 440px; max-width: 500px; font-family: ${colors.font}; color: ${colors.text};
            box-shadow: 0 0 40px ${colors.border}80;
        `;

        const section = createPluginSection();
        section.style.border = 'none';
        section.style.boxShadow = 'none';
        panel.appendChild(section);
        document.body.appendChild(panel);
        makeDraggable(panel);
    }

    function makeDraggable(element) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        const header = element.querySelector('.section-title') || element;
        header.style.cursor = 'move';

        header.onmousedown = (e) => {
            if (e.target.tagName === 'BUTTON') return;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;

            document.onmouseup = () => {
                document.onmouseup = null;
                document.onmousemove = null;
            };

            document.onmousemove = (e) => {
                e.preventDefault();
                pos1 = pos3 - e.clientX;
                pos2 = pos4 - e.clientY;
                pos3 = e.clientX;
                pos4 = e.clientY;

                // Boundary checks
                let newTop = element.offsetTop - pos2;
                let newLeft = element.offsetLeft - pos1;

                // Keep within viewport
                newTop = Math.max(0, Math.min(newTop, window.innerHeight - element.offsetHeight));
                newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - element.offsetWidth));

                element.style.top = newTop + "px";
                element.style.left = newLeft + "px";
            };
        };
    }

    function cleanup() {
        state.boundListeners.forEach(({ el, evt, fn }) => {
            if (el) el.removeEventListener(evt, fn);
        });
        state.boundListeners = [];
    }

    function setupEventListeners() {
        cleanup(); // Remove old listeners first

        const scanBtn = document.getElementById('sync-scan-btn');
        const exportJsonBtn = document.getElementById('sync-export-json-btn');
        const exportCsvBtn = document.getElementById('sync-export-csv-btn');
        const exportTxtBtn = document.getElementById('sync-export-txt-btn');
        const clearBtn = document.getElementById('sync-clear-btn');

        const listeners = [
            { el: scanBtn, evt: 'click', fn: scanAllElements },
            { el: exportJsonBtn, evt: 'click', fn: exportAsJSON },
            { el: exportCsvBtn, evt: 'click', fn: exportAsCSV },
            { el: exportTxtBtn, evt: 'click', fn: exportAsTxt },
            { el: clearBtn, evt: 'click', fn: clearElements }
        ];

        listeners.forEach(({ el, evt, fn }) => {
            if (el) {
                el.addEventListener(evt, fn);
                state.boundListeners.push({ el, evt, fn });
            }
        });
    }

    // ============================================================================
    // VERSION CHECKING
    // ============================================================================

    function checkForUpdates() {
        const lastVersion = localStorage.getItem(CONFIG.STORAGE_KEY_VERSION);

        if (lastVersion && lastVersion !== CONFIG.VERSION) {
            showModal(
                'PLUGIN UPDATED',
                `${lastVersion} → ${CONFIG.VERSION}\n\n` +
                `✨ New in this version:\n` +
                `• 20% faster scrolling (8ms intervals)\n` +
                `• RAF-powered 60fps UI updates\n` +
                `• Smart batching & caching\n` +
                `• Storage quota protection\n` +
                `• Better accessibility (ARIA)\n` +
                `• Viewport boundary checks\n\n` +
                `Performance is now ULTRA! 🚀`,
                'success',
                [{ text: 'AWESOME!' }]
            );
        }

        localStorage.setItem(CONFIG.STORAGE_KEY_VERSION, CONFIG.VERSION);
    }

    // ============================================================================
    // KEYBOARD SHORTCUTS
    // ============================================================================

    document.addEventListener('keydown', (e) => {
        if (e.target.matches('input, textarea')) return;

        if (e.altKey && e.key.toLowerCase() === 'e') {
            e.preventDefault();
            if (state.pluginInitialized) exportAsJSON();
        }

        if (e.altKey && e.key.toLowerCase() === 'y') {
            e.preventDefault();
            if (state.pluginInitialized && !state.isScanning) scanAllElements();
        }
    });

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

    async function initPlugin() {
        if (state.pluginInitialized) return;

        console.log(`[SYNC] Initializing ${CONFIG.VERSION}...`);

        await waitForMainScript();
        loadElements();
        loadExportHistory();

        setTimeout(() => {
            injectPluginUI();
            state.pluginInitialized = true;
            checkForUpdates();
            showPluginToast('Element Sync ULTRA ready!', 'success');
            console.log(`[SYNC] ✓ Initialized with ${state.allElements.length} elements`);
        }, 2000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initPlugin);
    } else {
        setTimeout(initPlugin, 1000);
    }

    // ============================================================================
    // PUBLIC API
    // ============================================================================

    window.elementSyncPlugin = {
        version: CONFIG.VERSION,
        scan: scanAllElements,
        exportJSON: exportAsJSON,
        exportCSV: exportAsCSV,
        exportTXT: exportAsTxt,
        clear: clearElements,
        getElements: () => state.allElements,
        getCount: () => state.allElements.length,
        getFirstDiscoveries: () => state.allElements.filter(e => e.isFirstDiscovery),
        getTotalItems: getTotalItemCount,
        getConfig: () => ({ ...CONFIG }),
        getExportHistory: () => state.exportHistory
    };

    console.log(`[SYNC] ${CONFIG.VERSION} loaded - Type elementSyncPlugin in console for API`);

})();