Hide Web Elements Pro

Stealth element hider, Shadow DOM UI, persistent freeze, link extractor, time skipper, enhanced reveal, dock button visibility, stable Reveal & Unblock Engine, plus media downloader with preview. Automatic Protection. Now with Anti-Paywall, Auto-Close Modals, Cookie Bypass, and Bulk Filter Lists.

2026-08-20 기준 버전입니다. 최신 버전을 확인하세요.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Hide Web Elements Pro
// @version      12.3
// @description  Stealth element hider, Shadow DOM UI, persistent freeze, link extractor, time skipper, enhanced reveal, dock button visibility, stable Reveal & Unblock Engine, plus media downloader with preview. Automatic Protection. Now with Anti-Paywall, Auto-Close Modals, Cookie Bypass, and Bulk Filter Lists.
// @author       KTZ
// @match        *://*/*
// @icon         https://cdn.corenexis.com/f/v9leABxGUbJ.png
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addValueChangeListener
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @grant        unsafeWindow
// @connect      *
// @run-at       document-start
// @license      MIT
// @namespace    https://greasyfork.org/users/1620673
// ==/UserScript==

(function() {
    'use strict';

    // ---------- Safe Storage ----------
    const gv = (key, def) => {
        try {
            if (typeof GM_getValue !== 'undefined') return GM_getValue(key, def);
            const item = localStorage.getItem(key);
            return item !== null ? JSON.parse(item) : def;
        } catch {
            return def;
        }
    };

    let isSyncingStorage = false;
    const sv = (key, val) => {
        try {
            if (typeof GM_setValue !== 'undefined') {
                GM_setValue(key, val);
            } else {
                localStorage.setItem(key, JSON.stringify(val));
            }
        } catch {}

        if (!isSyncingStorage) {
            isSyncingStorage = true;
            try {
                if (typeof syncCache === 'function') syncCache();
                if (typeof requestUpdateStyles === 'function') requestUpdateStyles();
                if (isTop && typeof broadcastState === 'function') broadcastState();
            } finally {
                isSyncingStorage = false;
            }
        }
    };

    const doc = document, win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
    const UI_HOST_ID = 'hider-ui-root', STEPPER_BAR_ID = 'hider-stepper-bar';
    
    let isTop = false;
    try { isTop = (window.self === window.top); } catch { isTop = false; }

    let shadowRoot = null;
    const shadowBy = id => shadowRoot ? shadowRoot.getElementById(id) : null;

    // ---------- Persistent Settings ----------
    let initialMem = gv('hider_freeze_memory', null) || (gv('hider_autono_global', false) ? 'block_all' : 'ask');
    const CACHE = { 
        blockedDomainsList: [], blockedDomainsSet: new Set(), 
        allowedDomainsList: [], allowedDomainsSet: new Set(),
        customRules: [], isFrozen: gv('hider_freeze_global', false), 
        freezeMemory: initialMem, logs: null,
        autoTimeSkipper: gv('hider_auto_time_skipper', false),
        autoScroll: gv('hider_auto_scroll', true),
        enableContextMenu: gv('hider_enable_contextmenu', true),
        autoRemoveBlur: gv('hider_auto_remove_blur', false),
        universalProtect: true,
        // Rule-breaker features
        antiPaywall: gv('hider_anti_paywall', false),
        autoCloseModals: gv('hider_auto_close_modals', false),
        cookieConsentMode: gv('hider_cookie_consent_mode', 'ask'), // 'accept', 'reject', 'ask'
        filterLists: gv('hider_filter_lists', []) // array of {name, selectors: []}
    };

    // ---------- Dock Button Visibility ----------
    const DOCK_BUTTONS = [
        { id: 'btn-select', label: '🎯 Hide' },
        { id: 'btn-scope', label: '🌐 Scope' },
        { id: 'btn-reveal-quick', label: '👁️ Reveal' },
        { id: 'btn-links', label: '🔗 Links' },
        { id: 'btn-skip-30', label: '⏩ +30s' },
        { id: 'btn-freeze', label: '❄️ Freeze' }
    ];

    function getHiddenDockButtons() {
        return gv('hider_hidden_dock_buttons', []);
    }
    function setHiddenDockButtons(arr) {
        sv('hider_hidden_dock_buttons', arr);
    }
    function applyDockButtonVisibility() {
        if (!shadowRoot) return;
        const hidden = new Set(getHiddenDockButtons());
        DOCK_BUTTONS.forEach(btn => {
            const el = shadowRoot.getElementById(btn.id);
            if (el) {
                el.style.setProperty('display', hidden.has(btn.id) ? 'none' : 'flex', 'important');
            }
        });
        const menuBtn = shadowRoot.getElementById('btn-manage');
        if (menuBtn) menuBtn.style.setProperty('display', 'flex', 'important');
    }
    function renderDockButtonOptions() {
        if (!shadowRoot) return;
        const container = shadowRoot.getElementById('dock-buttons-list');
        if (!container) return;
        const hidden = new Set(getHiddenDockButtons());
        container.innerHTML = '';
        DOCK_BUTTONS.forEach(btn => {
            const label = document.createElement('label');
            label.style.cssText = 'font-size:10px!important;color:#cbd5e1!important;display:flex!important;align-items:center!important;gap:6px;cursor:pointer;user-select:none;';
            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.dataset.btnId = btn.id;
            checkbox.checked = !hidden.has(btn.id);
            checkbox.style.cssText = 'accent-color:#38bdf8;cursor:pointer;';
            checkbox.addEventListener('change', function() {
                const id = this.dataset.btnId;
                let hiddenArr = getHiddenDockButtons();
                if (this.checked) {
                    hiddenArr = hiddenArr.filter(h => h !== id);
                } else {
                    if (!hiddenArr.includes(id)) hiddenArr.push(id);
                }
                setHiddenDockButtons(hiddenArr);
                applyDockButtonVisibility();
            });
            label.appendChild(checkbox);
            const span = document.createElement('span');
            span.textContent = btn.label;
            label.appendChild(span);
            container.appendChild(label);
        });
    }

    // ---------- Core Variables ----------
    let isSelecting = false, isFrozen = CACHE.isFrozen, currentScope = 'site', previewElement = null;
    let stepperStack = [], userApprovedNavigation = false, cachedCssString = null, lastUrl = location.href;
    let stepperPos = { x: null, y: null }, isDraggingStepper = false, isDraggingDock = false, logSaveTimer = null;
    let collapseTimer = null, editingRuleId = null, scrollAnimationFrame = null, styleUpdateRAF = null;
    let linkPanelEl = null;
    let linkDisplayMode = 'text';
    let isProtected = false;
    let featuresEnabled = true;
    let CURRENT_DOMAIN = '', CURRENT_URL = '';
    let previewOutsideListener = null;
    let lastHiddenSelector = null; // for undo
    let globalScopeTemp = false;

    // ---------- Cleanup (Memory Leak Prevention) ----------
    const timers = {
        scrollInterval: null,
        blurInterval: null,
        protectionPoller: null,
        logSaveTimer: null,
        collapseTimer: null,
        paywallObserver: null,
        modalObserver: null,
        cookieObserver: null
    };
    const observers = {
        protectionObserver: null,
        blurObserver: null,
        urlChangeObserver: null,
        paywallObserver: null,
        modalObserver: null,
        cookieObserver: null
    };
    const styleElements = {
        scrollStyleEl: null,
        contextMenuStyleEl: null,
        blurGlobalStyle: null
    };

    function dispose() {
        // Clear intervals
        Object.keys(timers).forEach(key => {
            if (timers[key]) {
                clearInterval(timers[key]);
                clearTimeout(timers[key]);
                timers[key] = null;
            }
        });
        // Disconnect observers
        Object.keys(observers).forEach(key => {
            if (observers[key]) {
                observers[key].disconnect();
                observers[key] = null;
            }
        });
        // Remove injected styles
        Object.values(styleElements).forEach(el => {
            if (el && el.parentNode) el.remove();
        });
        // Remove any leftover UI elements
        const host = doc.getElementById(UI_HOST_ID);
        if (host) host.remove();
        // Remove stepper if present
        const stepper = shadowBy(STEPPER_BAR_ID);
        if (stepper) stepper.remove();
        // Remove link panel
        if (linkPanelEl && linkPanelEl.parentNode) linkPanelEl.remove();
        // Remove prompt modals
        const prompt = shadowBy('hider-freeze-prompt');
        if (prompt) prompt.remove();
        // Remove toast
        const toast = doc.getElementById('hider-toast');
        if (toast) toast.remove();
        // Remove dynamic styles
        const dyn = doc.getElementById('hider-dynamic-styles');
        if (dyn) dyn.remove();
    }

    window.addEventListener('beforeunload', dispose);

    // ---------- Context Menu Override (Safe) ----------
    const contextMenuHandler = function(e) {
        if (!CACHE.enableContextMenu) return;
        const path = e.composedPath ? e.composedPath() : [];
        if (path.some(el => el.id === UI_HOST_ID || (el.closest && el.closest('#' + UI_HOST_ID)))) {
            e.stopPropagation();
            return;
        }
    };
    document.addEventListener('contextmenu', contextMenuHandler, true);

    // ---------- Freeze Mode ----------
    const FREEZE_LABELS = {
        'ask': '❓ Ask Every Time', 'block_all': '⛔ Auto-Block All Navigations',
        'allow_same': '🔗 Allow Same Domain Only', 'allow_all': '🟢 Allow All Navigations'
    };

    const resolveUrl = u => {
        if (!u || typeof u !== 'string') return '';
        const trimmed = u.trim();
        if (trimmed === '*') return '*';
        if (!/^[a-zA-Z][a-zA-Z0-9+-.]*:\/\//.test(trimmed)) {
            if (trimmed.startsWith('//')) return 'http:' + trimmed;
            if (!trimmed.startsWith('/') && !trimmed.startsWith('./') && !trimmed.startsWith('../')) {
                return 'http://' + trimmed;
            }
        }
        try { return new URL(trimmed, win.location.href).href; } catch { return trimmed; }
    };

    const cleanUrl = () => CURRENT_URL || (CURRENT_URL = location.origin + location.pathname);
    const cleanDomain = url => {
        try { 
            if (!url) return '';
            if (url === '*') return '*';
            const abs = resolveUrl(url);
            return new URL(abs).hostname.replace(/^www\./, '').toLowerCase(); 
        } catch { 
            return String(url).trim().toLowerCase(); 
        }
    };

    const updateCurrentLocCache = () => {
        CURRENT_URL = location.origin + location.pathname;
        CURRENT_DOMAIN = cleanDomain(location.href);
        updateProtectionFlag();
        applyAllSettings();
    };

    function getParentDomain(url) {
        if (!url) return '';
        try {
            const host = cleanDomain(url);
            if (!host || host === '*') return host;
            const parts = host.split('.');
            if (parts.length <= 2) return host;
            const multiPartTlds = ['co.uk', 'com.au', 'org.uk', 'gov.uk', 'co.jp', 'com.br', 'co.id', 'or.id', 'ac.uk', 'net.au', 'com.tw', 'co.nz', 'com.sg', 'com.mx', 'co.kr', 'com.tr'];
            const lastTwo = parts.slice(-2).join('.');
            return (multiPartTlds.includes(lastTwo) && parts.length > 2) ? parts.slice(-3).join('.') : lastTwo;
        } catch {
            return cleanDomain(url) || '';
        }
    }

    const FEATURE_BLACKLIST = ['facebook.com', 'fb.com', 'facebook'];
    let blacklistToastShown = false;

    function isFeatureBlacklisted() {
        if (!CURRENT_DOMAIN) return false;
        return FEATURE_BLACKLIST.some(domain => 
            CURRENT_DOMAIN.includes(domain) || CURRENT_DOMAIN.endsWith('.' + domain)
        );
    }

    // ============ REVEAL & UNBLOCK ENGINE ============
    function isProtectedPage() {
        try {
            if (win.__cf_chl_opt || win.__cfRLUnblockHandlers || win._cf) return true;
            if (win.turnstile) {
                if (doc.querySelector('.cf-turnstile, #turnstile-wrapper, .turnstile-container, #cf-challenge')) return true;
            }
            const challengeSelectors = [
                '#challenge-running', '#cf-please-wait', '.cf-browser-verification',
                '#cf-content', '#cf-stage', '#cf-challenge', '.cf-challenge',
                '#cf-error-details', '#cf-waiting', '.cf-please-wait',
                '#cf-content-wrapper', '#challenge-form', '.challenge-form', '#cf-intercept'
            ];
            for (const sel of challengeSelectors) {
                if (doc.querySelector(sel)) return true;
            }
            if (doc.querySelector('.ray-id, [data-ray-id], [data-cf-ray]')) return true;
            const title = doc.title || '';
            if (title.includes('Just a moment...') || title.includes('Attention Required!') ||
                title.includes('Security Check') || title.includes('Verify you are human') ||
                title.includes('Checking your browser')) {
                return true;
            }
            const forms = doc.querySelectorAll('form[action*="__cf_chl"], form[action*="cf-challenge"]');
            if (forms.length > 0) return true;
            const scripts = doc.querySelectorAll('script[src*="challenges.cloudflare.com"], script[src*="/cdn-cgi/challenge-platform/"]');
            if (scripts.length > 0) return true;
            if (doc.querySelector('meta[name="cf-options"]')) return true;
        } catch (e) { /* ignore */ }
        return false;
    }

    function updateProtectionFlag() {
        const was = isProtected;
        isProtected = isProtectedPage();
        featuresEnabled = isProtected ? !CACHE.universalProtect : true;
        if (was !== isProtected) {
            applyAllSettings();
            requestUpdateStyles();
        }
    }

    function setupProtectionObserver() {
        if (observers.protectionObserver) return;
        observers.protectionObserver = new MutationObserver(() => {
            const was = isProtected;
            updateProtectionFlag();
            if (was !== isProtected) {
                applyAllSettings();
                requestUpdateStyles();
            }
        });
        observers.protectionObserver.observe(doc.documentElement, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeOldValue: false
        });

        let checks = 0;
        const rapidInterval = setInterval(() => {
            checks++;
            const was = isProtected;
            updateProtectionFlag();
            if (was !== isProtected) {
                applyAllSettings();
                requestUpdateStyles();
            }
            if (checks >= 10) clearInterval(rapidInterval);
        }, 1000);
        timers.protectionPoller = rapidInterval;

        if (!window.__hider_protection_poller) {
            window.__hider_protection_poller = setInterval(() => {
                const was = isProtected;
                updateProtectionFlag();
                if (was !== isProtected) {
                    applyAllSettings();
                    requestUpdateStyles();
                }
            }, 5000);
        }
    }

    // ---------- Scroll Defeater ----------
    function forceEnableScroll() {
        if (!CACHE.autoScroll) return;
        if (isFeatureBlacklisted() || !featuresEnabled) return;
        const html = doc.documentElement, body = doc.body;
        if (!html && !body) return;
        if (!styleElements.scrollStyleEl) {
            styleElements.scrollStyleEl = doc.createElement('style');
            styleElements.scrollStyleEl.id = 'hider-force-scroll-style';
            (doc.head || doc.documentElement)?.appendChild(styleElements.scrollStyleEl);
        }
        styleElements.scrollStyleEl.textContent = `
            html, body {
                overflow: auto !important;
                overflow-x: auto !important;
                overflow-y: auto !important;
                position: static !important;
                height: auto !important;
                max-height: none !important;
                touch-action: auto !important;
                -webkit-overflow-scrolling: touch !important;
            }
        `;
    }

    function checkAndAutoUnblockScroll() {
        if (!CACHE.autoScroll || isFeatureBlacklisted() || !featuresEnabled) {
            stopScrollDefeater();
            return;
        }
        const html = doc.documentElement, body = doc.body;
        if (!html || !body) return;
        try {
            const hStyle = win.getComputedStyle(html), bStyle = win.getComputedStyle(body);
            if (
                hStyle.overflow === 'hidden' || hStyle.overflowY === 'hidden' ||
                bStyle.overflow === 'hidden' || bStyle.overflowY === 'hidden' ||
                bStyle.position === 'fixed' || hStyle.position === 'fixed'
            ) {
                forceEnableScroll();
            }
        } catch {}
    }

    function startScrollDefeater() {
        if (isFeatureBlacklisted() || !featuresEnabled) {
            stopScrollDefeater();
            return;
        }
        if (timers.scrollInterval) clearInterval(timers.scrollInterval);
        if (CACHE.autoScroll) {
            forceEnableScroll();
            timers.scrollInterval = setInterval(checkAndAutoUnblockScroll, 2000);
        }
    }

    function stopScrollDefeater() {
        if (timers.scrollInterval) {
            clearInterval(timers.scrollInterval);
            timers.scrollInterval = null;
        }
        if (styleElements.scrollStyleEl) {
            styleElements.scrollStyleEl.remove();
            styleElements.scrollStyleEl = null;
        }
    }

    // ---------- Context Menu Styles (Safe) ----------
    function updateContextMenuStyles() {
        if (isFeatureBlacklisted() || !featuresEnabled) {
            if (styleElements.contextMenuStyleEl) {
                styleElements.contextMenuStyleEl.remove();
                styleElements.contextMenuStyleEl = null;
            }
            return;
        }
        if (!CACHE.enableContextMenu) {
            if (styleElements.contextMenuStyleEl) {
                styleElements.contextMenuStyleEl.remove();
                styleElements.contextMenuStyleEl = null;
            }
            return;
        }
        if (!styleElements.contextMenuStyleEl) {
            styleElements.contextMenuStyleEl = doc.createElement('style');
            styleElements.contextMenuStyleEl.id = 'hider-contextmenu-style';
            (doc.head || doc.documentElement)?.appendChild(styleElements.contextMenuStyleEl);
        }
        styleElements.contextMenuStyleEl.textContent = `
            * {
                -webkit-touch-callout: default !important;
                -webkit-user-select: text !important;
                user-select: text !important;
            }
        `;
    }

    // ---------- Blur Removal ----------
    function removeBlurFromElements() {
        if (!CACHE.autoRemoveBlur || isFeatureBlacklisted() || !featuresEnabled) {
            stopBlurRemoval();
            return;
        }
        const all = doc.querySelectorAll('*');
        const uiHost = doc.getElementById(UI_HOST_ID);
        for (const el of all) {
            if (el === uiHost || (el.closest && el.closest('#' + UI_HOST_ID))) continue;
            if (el.classList && el.classList.contains('hider-stealth-target')) continue;
            try {
                const style = win.getComputedStyle(el);
                if (style.filter && style.filter.includes('blur')) {
                    el.style.setProperty('filter', 'none', 'important');
                    el.style.setProperty('backdrop-filter', 'none', 'important');
                    el.style.setProperty('-webkit-backdrop-filter', 'none', 'important');
                }
                if (el.style.filter && el.style.filter.includes('blur')) {
                    el.style.setProperty('filter', 'none', 'important');
                }
                if (el.style.backdropFilter && el.style.backdropFilter.includes('blur')) {
                    el.style.setProperty('backdrop-filter', 'none', 'important');
                    el.style.setProperty('-webkit-backdrop-filter', 'none', 'important');
                }
            } catch {}
        }
    }

    function scheduleBlurRemoval() {
        if (isFeatureBlacklisted() || !featuresEnabled) {
            stopBlurRemoval();
            return;
        }
        if (CACHE.autoRemoveBlur && !styleElements.blurGlobalStyle) {
            styleElements.blurGlobalStyle = doc.createElement('style');
            styleElements.blurGlobalStyle.id = 'hider-blur-global-style';
            styleElements.blurGlobalStyle.textContent = `
                *:not(#hider-ui-root):not(#hider-ui-root *) {
                    filter: none !important;
                    backdrop-filter: none !important;
                    -webkit-backdrop-filter: none !important;
                }
            `;
            (doc.head || doc.documentElement)?.appendChild(styleElements.blurGlobalStyle);
        } else if (!CACHE.autoRemoveBlur && styleElements.blurGlobalStyle) {
            styleElements.blurGlobalStyle.remove();
            styleElements.blurGlobalStyle = null;
        }

        if (timers.blurInterval) clearInterval(timers.blurInterval);
        if (CACHE.autoRemoveBlur) {
            removeBlurFromElements();
            timers.blurInterval = setInterval(removeBlurFromElements, 2000);
            if (!observers.blurObserver) {
                observers.blurObserver = new MutationObserver(() => {
                    if (CACHE.autoRemoveBlur) {
                        removeBlurFromElements();
                    }
                });
                observers.blurObserver.observe(doc.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
            }
        } else {
            if (observers.blurObserver) {
                observers.blurObserver.disconnect();
                observers.blurObserver = null;
            }
        }
    }

    function stopBlurRemoval() {
        if (timers.blurInterval) {
            clearInterval(timers.blurInterval);
            timers.blurInterval = null;
        }
        if (observers.blurObserver) {
            observers.blurObserver.disconnect();
            observers.blurObserver = null;
        }
        if (styleElements.blurGlobalStyle) {
            styleElements.blurGlobalStyle.remove();
            styleElements.blurGlobalStyle = null;
        }
    }

    // ---------- SAFE HELPER: Check if element is main content ----------
    function isMainContentElement(el) {
        if (!el) return false;
        // Never hide html or body
        if (el === doc.documentElement || el === doc.body) return true;
        // If element is our UI host, never hide
        if (el.id === UI_HOST_ID || el.closest && el.closest('#' + UI_HOST_ID)) return true;
        // If element contains a lot of text (> 500 characters) and is not an overlay, consider it main content
        const text = el.textContent || '';
        if (text.length > 500) {
            // Check if it's positioned fixed/absolute with high z-index – could be overlay
            const style = win.getComputedStyle(el);
            if (style.position === 'fixed' || style.position === 'absolute') {
                const z = parseInt(style.zIndex, 10);
                if (z > 1000) return false; // high z-index overlay
            }
            return true; // likely main content
        }
        // If it's a structural element (article, main, section) with substantial text
        if (el.matches && el.matches('article, main, section, div[role="main"]')) {
            if (text.length > 100) return true;
        }
        return false;
    }

    // ---------- Rule-Breaker Engines (with safety) ----------
    function setupPaywallBypass() {
        if (observers.paywallObserver) {
            observers.paywallObserver.disconnect();
            observers.paywallObserver = null;
        }
        if (!CACHE.antiPaywall || !featuresEnabled || isFeatureBlacklisted()) return;

        const paywallKeywords = ['adblock', 'paywall', 'premium', 'subscribe', 'whitelist', 'disable adblock', 'ad blocker'];
        const paywallSelectors = [
            '[class*="paywall"]', '[id*="paywall"]', '[class*="adblock"]', '[id*="adblock"]',
            '[class*="premium"]', '[id*="premium"]', '[class*="subscribe"]', '[id*="subscribe"]',
            '[class*="overlay"]', '[id*="overlay"]', '[class*="modal"]', '[id*="modal"]'
        ];

        function removePaywallElement(el) {
            if (!el || el === doc.documentElement || el === doc.body) return;
            if (el.closest && el.closest('#' + UI_HOST_ID)) return;
            // Skip if it's main content
            if (isMainContentElement(el)) return;

            const text = el.textContent.toLowerCase();
            // Check if it matches paywall criteria
            let isPaywall = false;
            if (el.matches && el.matches(paywallSelectors.join(','))) isPaywall = true;
            if (paywallKeywords.some(kw => text.includes(kw))) isPaywall = true;

            if (isPaywall) {
                // Additional check: element should be either fixed/absolute or have high z-index
                const style = win.getComputedStyle(el);
                const pos = style.position;
                const z = parseInt(style.zIndex, 10);
                if (pos === 'fixed' || pos === 'absolute' || z > 100) {
                    try {
                        el.style.setProperty('display', 'none', 'important');
                        el.style.setProperty('visibility', 'hidden', 'important');
                        // Also remove overflow hiding on body/html
                        forceEnableScroll();
                    } catch {}
                }
            }
        }

        function scanAndRemove(node) {
            if (node.nodeType === Node.ELEMENT_NODE) {
                removePaywallElement(node);
                node.querySelectorAll('*').forEach(child => removePaywallElement(child));
            }
        }

        observers.paywallObserver = new MutationObserver(mutations => {
            for (const mutation of mutations) {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        scanAndRemove(node);
                    });
                }
            }
        });
        observers.paywallObserver.observe(doc.documentElement, { childList: true, subtree: true });

        // Initial scan
        doc.querySelectorAll('*').forEach(removePaywallElement);
        forceEnableScroll();
    }

    function setupModalAutoClose() {
        if (observers.modalObserver) {
            observers.modalObserver.disconnect();
            observers.modalObserver = null;
        }
        if (!CACHE.autoCloseModals || !featuresEnabled || isFeatureBlacklisted()) return;

        const closeKeywords = ['accept', 'close', 'dismiss', 'continue', 'agree', 'ok', 'got it', 'i understand'];
        const modalSelectors = [
            '[role="dialog"]', '[role="alertdialog"]', '.modal', '.overlay', '.popup', '.lightbox',
            '[class*="modal"]', '[id*="modal"]', '[class*="overlay"]', '[id*="overlay"]'
        ];

        function tryCloseModal() {
            const modals = doc.querySelectorAll(modalSelectors.join(','));
            for (const modal of modals) {
                if (modal === doc.body || modal === doc.documentElement) continue;
                if (modal.closest && modal.closest('#' + UI_HOST_ID)) continue;
                const style = win.getComputedStyle(modal);
                if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;
                // Skip if it's main content
                if (isMainContentElement(modal)) continue;

                // Look for buttons inside
                const buttons = modal.querySelectorAll('button, a[role="button"], input[type="button"], input[type="submit"]');
                for (const btn of buttons) {
                    const text = btn.textContent.trim().toLowerCase();
                    if (closeKeywords.some(kw => text.includes(kw))) {
                        if (btn.offsetParent !== null) {
                            try { btn.click(); } catch {}
                            // After click, try to hide modal if still visible
                            setTimeout(() => {
                                if (modal.parentNode && !isMainContentElement(modal)) {
                                    modal.style.setProperty('display', 'none', 'important');
                                }
                            }, 200);
                            return;
                        }
                    }
                }
                // If no button, hide if it's a backdrop/overlay
                if (modal.matches('.overlay, .modal-backdrop, .modal-overlay')) {
                    if (!isMainContentElement(modal)) {
                        modal.style.setProperty('display', 'none', 'important');
                    }
                }
            }
        }

        observers.modalObserver = new MutationObserver(() => {
            tryCloseModal();
        });
        observers.modalObserver.observe(doc.documentElement, { childList: true, subtree: true });

        setTimeout(tryCloseModal, 500);
        setTimeout(tryCloseModal, 1500);
    }

    function setupCookieConsent() {
        if (observers.cookieObserver) {
            observers.cookieObserver.disconnect();
            observers.cookieObserver = null;
        }
        if (CACHE.cookieConsentMode === 'ask' || !featuresEnabled || isFeatureBlacklisted()) return;

        const cookieSelectors = [
            '#cookie-consent', '#cookie-banner', '.cookie-consent', '.cookie-banner',
            '[class*="cookie"]', '[id*="cookie"]', '[aria-label*="cookie"]'
        ];
        const acceptKeywords = ['accept', 'agree', 'allow', 'yes', 'ok', 'got it'];
        const rejectKeywords = ['reject', 'decline', 'no', 'deny'];

        function handleCookieBanner() {
            const banners = doc.querySelectorAll(cookieSelectors.join(','));
            for (const banner of banners) {
                if (banner === doc.body || banner === doc.documentElement) continue;
                if (banner.closest && banner.closest('#' + UI_HOST_ID)) continue;
                const style = win.getComputedStyle(banner);
                if (style.display === 'none' || style.visibility === 'hidden') continue;
                if (isMainContentElement(banner)) continue;

                const buttons = banner.querySelectorAll('button, a[role="button"], input[type="button"]');
                const mode = CACHE.cookieConsentMode;
                let targetTexts = mode === 'accept' ? acceptKeywords : rejectKeywords;
                for (const btn of buttons) {
                    const text = btn.textContent.trim().toLowerCase();
                    if (targetTexts.some(kw => text.includes(kw))) {
                        try { btn.click(); } catch {}
                        return;
                    }
                }
                // Try close button
                const closeBtn = banner.querySelector('[aria-label*="close"], [aria-label*="Close"], .close, .dismiss');
                if (closeBtn) {
                    try { closeBtn.click(); } catch {}
                }
            }
        }

        observers.cookieObserver = new MutationObserver(() => {
            handleCookieBanner();
        });
        observers.cookieObserver.observe(doc.documentElement, { childList: true, subtree: true });

        setTimeout(handleCookieBanner, 500);
        setTimeout(handleCookieBanner, 2000);
    }

    // ---------- Apply all settings ----------
    function applyAllSettings() {
        if (isFeatureBlacklisted() && !blacklistToastShown) {
            showToast('⚠️ Some Reveal features disabled on this domain');
            blacklistToastShown = true;
        }

        if (CACHE.autoScroll) startScrollDefeater();
        else stopScrollDefeater();

        updateContextMenuStyles();

        if (CACHE.autoRemoveBlur) scheduleBlurRemoval();
        else stopBlurRemoval();

        updateProtectionFlag();

        setupPaywallBypass();
        setupModalAutoClose();
        setupCookieConsent();
    }

    // ---------- Sync Cache ----------
    function syncCache() {
        CACHE.blockedDomainsList = gv('hider_blocked_domains', []);
        CACHE.blockedDomainsSet = new Set(CACHE.blockedDomainsList.map(cleanDomain).filter(Boolean));
        CACHE.allowedDomainsList = gv('hider_allowed_domains', []);
        CACHE.allowedDomainsSet = new Set(CACHE.allowedDomainsList.map(cleanDomain).filter(Boolean));
        CACHE.customRules = gv('hider_custom_rules_v4', []);
        CACHE.isFrozen = gv('hider_freeze_global', false);
        isFrozen = CACHE.isFrozen;
        CACHE.freezeMemory = gv('hider_freeze_memory', CACHE.freezeMemory);
        CACHE.autoTimeSkipper = gv('hider_auto_time_skipper', false);
        CACHE.autoScroll = gv('hider_auto_scroll', true);
        CACHE.enableContextMenu = gv('hider_enable_contextmenu', true);
        CACHE.autoRemoveBlur = gv('hider_auto_remove_blur', false);
        CACHE.universalProtect = true;
        CACHE.antiPaywall = gv('hider_anti_paywall', false);
        CACHE.autoCloseModals = gv('hider_auto_close_modals', false);
        CACHE.cookieConsentMode = gv('hider_cookie_consent_mode', 'ask');
        CACHE.filterLists = gv('hider_filter_lists', []);
        if (gv('hider_last_log_clear_day', '') !== new Date().toDateString()) {
            CACHE.logs = []; sv('hider_global_logs', []); sv('hider_last_log_clear_day', new Date().toDateString());
        }
        applyAllSettings();
    }
    syncCache();

    function disableFreezeMode() {
        isFrozen = false; CACHE.isFrozen = false;
        sv('hider_freeze_global', false);
        shadowBy('btn-freeze')?.classList.remove('is-frozen');
        broadcastState();
    }

    // ---------- Stealth Engine (unchanged) ----------
    const styleProxyCache = new WeakMap();
    try {
        const origGetComputedStyle = win.getComputedStyle;
        win.getComputedStyle = function(el, pseudo) {
            const style = origGetComputedStyle.apply(this, arguments);
            if (el && el instanceof Element && el.classList?.contains('hider-stealth-target')) {
                let cachedProxy = styleProxyCache.get(style);
                if (!cachedProxy) {
                    cachedProxy = new Proxy(style, {
                        get(target, prop) {
                            switch(prop) {
                                case 'display': return 'block';
                                case 'visibility': return 'visible';
                                case 'opacity': return '1';
                                case 'pointerEvents': return 'auto';
                                default: 
                                    const val = target[prop];
                                    return typeof val === 'function' ? val.bind(target) : val;
                            }
                        }
                    });
                    styleProxyCache.set(style, cachedProxy);
                }
                return cachedProxy;
            }
            return style;
        };
    } catch {}

    const isSameDomain = u => cleanDomain(u) && cleanDomain(u) === CURRENT_DOMAIN;
    
    const isDomainBlocked = u => {
        if (!u || !CACHE.blockedDomainsSet.size) return false;
        const d = cleanDomain(u), lower = String(u).toLowerCase();
        return d && (CACHE.blockedDomainsSet.has(d) || [...CACHE.blockedDomainsSet].some(b => b !== '*' && (d.endsWith('.' + b) || lower.includes(b))));
    };

    const isDomainAllowed = u => {
        if (!u || !CACHE.allowedDomainsSet.size) return false;
        const d = cleanDomain(u), lower = String(u).toLowerCase();
        return d && (CACHE.allowedDomainsSet.has('*') || CACHE.allowedDomainsSet.has(d) || [...CACHE.allowedDomainsSet].some(a => a !== '*' && (d.endsWith('.' + a) || lower.includes(a))));
    };

    function convertToWildcardSelector(sel) {
        if (!sel || typeof sel !== 'string') return '';
        return sel.replace(/(#|\.)([a-zA-Z0-9_-]+)/g, (m, p, name) => {
            if (name.startsWith('hider-')) return '';
            const base = (name.match(/^([a-zA-Z_-]+?)[0-9a-fA-F_-]{3,}$/)?.[1] || name.replace(/[0-9a-fA-F]{4,}$/, '')).replace(/[-_]+$/, '');
            return base ? (p === '#' ? `[id*="${base}"]` : `[class*="${base}"]`) : '';
        }).replace(/\s*>\s*/g, ' ');
    }

    function logBlockedAttempt(url, triggerType) {
        if (!CACHE.logs) CACHE.logs = gv('hider_global_logs', []);
        CACHE.logs.unshift({ url: url || 'about:blank', time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }), type: triggerType || 'Popup' });
        if (CACHE.logs.length > 50) CACHE.logs.pop();
        if (!timers.logSaveTimer) timers.logSaveTimer = setTimeout(() => { timers.logSaveTimer = null; sv('hider_global_logs', CACHE.logs); }, 1000);
    }

    // ---------- Freeze FX ----------
    function triggerFreezeFx() {
        const fx = doc.createElement('div');
        fx.className = 'hider-freeze-snow-overlay';
        const frag = doc.createDocumentFragment();
        const flakeChars = ['❄', '❅', '❆', '✨', '⚡'];
        for (let i = 0; i < 22; i++) {
            const flake = doc.createElement('div');
            flake.className = 'hider-snow-flake';
            flake.textContent = flakeChars[Math.floor(Math.random() * flakeChars.length)];
            flake.style.cssText = `left:${Math.random() * 98}vw; top:${Math.random() * 60}vh; animation-delay:${Math.random() * 0.35}s; font-size:${14 + Math.random() * 18}px;`;
            frag.appendChild(flake);
        }
        fx.appendChild(frag);
        (doc.body || doc.documentElement)?.appendChild(fx);
        setTimeout(() => fx.remove(), 1450);
    }

    function forceExposeAndPlayVideos() {
        doc.querySelectorAll('video').forEach(v => {
            ['display', 'visibility', 'opacity', 'pointer-events'].forEach(p => v.style.setProperty(p, p === 'display' ? 'block' : p === 'pointer-events' ? 'auto' : '1', 'important'));
            v.play()?.catch?.(() => {});
        });
    }

    function triggerVideoResumeChain() {
        forceExposeAndPlayVideos(); 
        [150, 400, 800].forEach(t => setTimeout(forceExposeAndPlayVideos, t));
        broadcastToFrames(window, { type: 'HIDER_RESUME_VIDEOS' });
    }

    function simulateAdWindowSuccess() {
        try {
            win.dispatchEvent(new Event('blur')); doc.dispatchEvent(new Event('visibilitychange'));
            win.onblur?.();
            setTimeout(() => { win.dispatchEvent(new Event('focus')); win.onfocus?.(); }, 60);
            triggerVideoResumeChain();
        } catch {}
    }

    function createDummyWindow() {
        const dummy = {
            closed: false, focus(){}, blur(){}, close(){ this.closed = true; }, postMessage(){},
            location: { href: 'about:blank', replace(u){ if(isDomainBlocked(u)) logBlockedAttempt(u, 'Blocked Dummy Replace'); }, assign(u){ if(isDomainBlocked(u)) logBlockedAttempt(u, 'Blocked Dummy Assign'); } },
            document: { write(){}, close(){}, body:{} }, opener: win
        };
        return new Proxy(dummy, {
            get: (t, p) => p in t ? t[p] : () => {},
            set: (t, p, v) => { if (p === 'location' && isDomainBlocked(v)) logBlockedAttempt(v, 'Blocked Dummy Location Set'); else t[p] = v; return true; }
        });
    }

    function handleFreezeNavigation(url, triggerType, onConfirm, onDeny) {
        if (isDomainBlocked(url)) {
            logBlockedAttempt(url, triggerType + ' (Auto-Block Domain)');
            onDeny?.(); simulateAdWindowSuccess(); return;
        }
        if (isDomainAllowed(url)) {
            userApprovedNavigation = true; onConfirm?.();
            setTimeout(() => userApprovedNavigation = false, 300); return;
        }
        const mem = CACHE.freezeMemory || 'ask';
        if (mem === 'allow_all') {
            disableFreezeMode(); userApprovedNavigation = true; onConfirm?.();
            setTimeout(() => userApprovedNavigation = false, 300); return;
        }
        if (mem === 'block_all') {
            logBlockedAttempt(url, triggerType + ' (Auto-Block)');
            onDeny?.(); simulateAdWindowSuccess(); return;
        }
        if (mem === 'allow_same' && isSameDomain(url)) {
            const domain = getParentDomain(url) || cleanDomain(url);
            if (domain) executeAddAllowedDomain(domain);
            userApprovedNavigation = true; onConfirm?.();
            setTimeout(() => userApprovedNavigation = false, 300); return;
        }
        showFreezePrompt(url, triggerType, onConfirm, onDeny);
    }

    // ---------- Interceptors ----------
    let interceptorsInstalled = false;

    function installInterceptors() {
        if (interceptorsInstalled) return;
        interceptorsInstalled = true;

        try {
            const lp = win.Location ? win.Location.prototype : Object.getPrototypeOf(win.location);
            if (lp) {
                const origA = lp.assign, origR = lp.replace, hrefDesc = Object.getOwnPropertyDescriptor(lp, 'href');

                const checkAndInterceptNav = (u, origFn, contextThis, triggerName) => {
                    if (!featuresEnabled) {
                        return origFn.call(contextThis, u);
                    }
                    if (isDomainBlocked(u)) {
                        logBlockedAttempt(u, `Blocked ${triggerName}`);
                        showToast(`⛔ Blocked ${triggerName}`); simulateAdWindowSuccess(); return;
                    }
                    if (isFrozen && !userApprovedNavigation) {
                        if (isDomainAllowed(u)) {
                            userApprovedNavigation = true; const res = origFn.call(contextThis, u);
                            setTimeout(() => userApprovedNavigation = false, 300); return res;
                        }
                        handleFreezeNavigation(u, triggerName, () => {
                            userApprovedNavigation = true; origFn.call(contextThis, u);
                            setTimeout(() => userApprovedNavigation = false, 300);
                        }, simulateAdWindowSuccess);
                        return;
                    }
                    return origFn.call(contextThis, u);
                };

                if (origA) lp.assign = function(u) { return checkAndInterceptNav(u, origA, this, 'Redirect (assign)'); };
                if (origR) lp.replace = function(u) { return checkAndInterceptNav(u, origR, this, 'Redirect (replace)'); };
                if (hrefDesc?.set) {
                    try {
                        Object.defineProperty(lp, 'href', {
                            set(u) { checkAndInterceptNav(u, hrefDesc.set, this, 'Redirect (href)'); },
                            get() { return hrefDesc.get.call(this); }
                        });
                    } catch {}
                }
            }

            const origClick = HTMLAnchorElement.prototype.click;
            HTMLAnchorElement.prototype.click = function() {
                if (!featuresEnabled) return origClick.apply(this, arguments);
                if (isDomainBlocked(this.href)) { logBlockedAttempt(this.href, 'Blocked Click'); showToast('⛔ Blocked link click'); simulateAdWindowSuccess(); return; }
                if (isFrozen && !userApprovedNavigation) {
                    if (isDomainAllowed(this.href)) {
                        userApprovedNavigation = true; const res = origClick.apply(this, arguments);
                        setTimeout(() => userApprovedNavigation = false, 300); return res;
                    }
                    handleFreezeNavigation(this.href, 'Anchor Click', () => {
                        userApprovedNavigation = true; origClick.apply(this, arguments);
                        setTimeout(() => userApprovedNavigation = false, 300);
                    }, simulateAdWindowSuccess);
                    return;
                }
                return origClick.apply(this, arguments);
            };

            const origOpen = win.open;
            win.open = function(url, target, features) {
                if (!featuresEnabled) return origOpen.apply(win, arguments);
                if (isDomainBlocked(url)) { logBlockedAttempt(url || 'about:blank', 'Blocked Popup'); simulateAdWindowSuccess(); showToast('⛔ Blocked Popup'); return createDummyWindow(); }
                if (!url || url === 'about:blank') {
                    const realWin = origOpen.apply(win, arguments);
                    return realWin ? new Proxy(realWin, {
                        get: (t, p) => p === 'location' ? new Proxy(t.location, { set: (l, lp, lv) => (lp==='href'||lp==='assign') && isDomainBlocked(lv) ? (logBlockedAttempt(lv, 'Blocked Popup Nav'), showToast('⛔ Blocked popup nav'), t.close(), true) : (l[lp]=lv, true) }) : (typeof t[p]==='function'?t[p].bind(t):t[p]),
                        set: (t, p, v) => p === 'location' && isDomainBlocked(v) ? (logBlockedAttempt(v, 'Blocked Popup Location'), showToast('⛔ Blocked popup nav'), t.close(), true) : (t[p]=v, true)
                    }) : createDummyWindow();
                }
                if (isFrozen && !userApprovedNavigation) { 
                    if (isDomainAllowed(url)) {
                        userApprovedNavigation = true; const res = origOpen.apply(win, arguments);
                        setTimeout(() => userApprovedNavigation = false, 300); return res;
                    }
                    handleFreezeNavigation(url, 'win.open()', () => {
                        userApprovedNavigation = true; origOpen.call(win, url, target, features);
                        setTimeout(() => userApprovedNavigation = false, 300);
                    }, () => {}); 
                    return createDummyWindow(); 
                }
                return origOpen.apply(win, arguments);
            };
        } catch {}
    }

    // ---------- Broadcast / Sync ----------
    function broadcastToFrames(w, msg) { try { for (let i = 0; i < w.frames.length; i++) { w.frames[i].postMessage(msg, '*'); broadcastToFrames(w.frames[i], msg); } } catch {} }
    function broadcastState() { if (isTop) broadcastToFrames(window, { type: 'HIDER_SYNC_STATE', isSelecting, currentScope, isFrozen }); }

    window.addEventListener('message', e => {
        if (!e.data) return;
        if (e.data.type === 'HIDER_REQUEST_STATE' && isTop) broadcastState();
        if (e.data.type === 'HIDER_SYNC_STATE') {
            ({ isSelecting, currentScope, isFrozen } = e.data);
            CACHE.isFrozen = isFrozen;
            syncCache(); requestUpdateStyles();
            shadowBy('btn-select')?.classList.toggle('active', isSelecting);
            shadowBy('btn-scope')?.classList.toggle('active', currentScope === 'link');
            shadowBy('btn-freeze')?.classList.toggle('is-frozen', isFrozen);
            if (!isSelecting) clearSelectionState();
            applyDockButtonVisibility();
        }
        if (e.data.type === 'HIDER_RESUME_VIDEOS') triggerVideoResumeChain();
        if (e.data.type === 'HIDER_SKIP_30') skip30Seconds();
    });

    window.addEventListener('storage', e => {
        if (e.key && e.key.startsWith('hider_')) {
            syncCache(); requestUpdateStyles();
            if (isTop) broadcastState();
            applyDockButtonVisibility();
        }
    });

    if (typeof GM_addValueChangeListener !== 'undefined') {
        ['hider_freeze_global', 'hider_freeze_memory', 'hider_blocked_domains', 'hider_allowed_domains', 'hider_custom_rules_v4', 'hider_auto_time_skipper',
         'hider_auto_scroll', 'hider_enable_contextmenu', 'hider_auto_remove_blur', 'hider_hidden_dock_buttons',
         'hider_anti_paywall', 'hider_auto_close_modals', 'hider_cookie_consent_mode', 'hider_filter_lists'
        ].forEach(key => {
            try { GM_addValueChangeListener(key, () => { syncCache(); requestUpdateStyles(); if (isTop) broadcastState(); applyDockButtonVisibility(); }); } catch {}
        });
    }

    if (!isTop) try { window.top.postMessage({ type: 'HIDER_REQUEST_STATE' }, '*'); } catch {}

    // ---------- Style Update ----------
    function requestUpdateStyles() {
        if (styleUpdateRAF) return;
        styleUpdateRAF = requestAnimationFrame(() => {
            styleUpdateRAF = null;
            updateStyles();
        });
    }

    function updateStyles() {
        let el = doc.getElementById('hider-dynamic-styles');
        if (!el) { el = doc.createElement('style'); el.id = 'hider-dynamic-styles'; (doc.head || doc.documentElement)?.appendChild(el); }
        
        const host = location.hostname;
        const siteRules = gv('hider_site_' + host, []);
        const linkRules = gv('hider_link_' + cleanUrl(), []);
        
        const customActiveRules = (CACHE.customRules || []).filter(r => {
            if (!r?.selector) return false;
            const t = cleanDomain(r.target);
            return t === '*' || t === host || (t && host.endsWith('.' + t));
        }).map(r => r.selector);

        const combined = [...new Set([...siteRules, ...linkRules, ...customActiveRules])].filter(Boolean);
        // Safety: never hide html or body
        const safeCombined = combined.filter(sel => !sel.match(/^(html|body|document)/i));
        const hideCss = (featuresEnabled && safeCombined.length) ? `${safeCombined.join(',')}{opacity:0!important;pointer-events:none!important;position:absolute!important;top:-99999px!important;left:-99999px!important;width:0!important;height:0!important;max-width:0!important;max-height:0!important;overflow:hidden!important;visibility:hidden!important;clip:rect(0,0,0,0)!important}` : '';
        
        const baseAnimationCss = `
        .hider-preview-highlight { outline: none !important; border: 2px solid #38bdf8 !important; background: rgba(56, 189, 248, 0.15) !important; box-shadow: 0 0 24px rgba(56, 189, 248, 0.6), inset 0 0 12px rgba(56, 189, 248, 0.3) !important; transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1) !important; position: relative !important; z-index: 2147483640 !important; cursor: crosshair !important; border-radius: 6px !important; }
        .hider-freeze-snow-overlay { position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; pointer-events: none !important; z-index: 2147483647 !important; overflow: hidden !important; background: radial-gradient(circle at center, rgba(56, 189, 248, 0.18) 0%, transparent 70%) !important; animation: hiderSnowOverlayFade 1.4s cubic-bezier(0.16, 1, 0.3, 1) forwards !important; }
        @keyframes hiderSnowOverlayFade { 0% { opacity: 0; backdrop-filter: blur(0px); } 30% { opacity: 1; backdrop-filter: blur(3px); } 80% { opacity: 1; backdrop-filter: blur(3px); } 100% { opacity: 0; backdrop-filter: blur(0px); } }
        .hider-snow-flake { position: absolute !important; color: #e0f2fe !important; user-select: none !important; pointer-events: none !important; opacity: 0.95 !important; animation: hiderSnowFall 1.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards !important; filter: drop-shadow(0 0 8px rgba(56, 189, 248, 0.9)) !important; }
        @keyframes hiderSnowFall { 0% { transform: translateY(-25px) scale(0.5) rotate(0deg); opacity: 0; } 20% { opacity: 1; } 100% { transform: translateY(140px) scale(1.15) rotate(180deg); opacity: 0; } }`;

        const css = baseAnimationCss + '\n' + hideCss;

        if (cachedCssString !== css) { 
            cachedCssString = css; el.textContent = css; 
            if (featuresEnabled) {
                safeCombined.forEach(s => {
                    try { doc.querySelectorAll(s).forEach(targetEl => targetEl.classList.add('hider-stealth-target')); } catch {}
                });
            }
        }

        if (CACHE.autoScroll && featuresEnabled) checkAndAutoUnblockScroll();
    }
    updateStyles();

    // ---------- Selector Helpers ----------
    function safeCSSEscape(str) { return (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') ? CSS.escape(str) : str.replace(/([!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~])/g, '\\$1'); }

    function getExactSelector(el) {
        if (!el || el.nodeType !== 1) return '';
        const path = []; let curr = el;
        while (curr && curr.nodeType === 1 && curr.tagName.toLowerCase() !== 'html') {
            let tag = curr.tagName.toLowerCase();
            if (tag === 'body') { path.unshift('body'); break; }
            if (curr.id && !curr.id.startsWith('hider-') && !/^\d+$/.test(curr.id) && curr.id.length < 18) { path.unshift(`#${safeCSSEscape(curr.id)}`); break; }
            const rawC = typeof curr.className === 'string' ? curr.className : curr.getAttribute('class') || '';
            const classes = rawC.trim().split(/\s+/).filter(c => c.length > 1 && !c.startsWith('hider-') && !/^[a-zA-Z0-9]{10,}$/.test(c) && !/^hover:/i.test(c));
            if (classes.length) { tag += `.${safeCSSEscape(classes[0])}` + (classes[1] ? `.${safeCSSEscape(classes[1])}` : ''); }
            else {
                let idx = 1, sib = curr.previousElementSibling;
                while (sib) { if (sib.tagName === curr.tagName) idx++; sib = sib.previousElementSibling; }
                tag += `:nth-of-type(${idx})`;
            }
            path.unshift(tag); curr = curr.parentElement;
        }
        return path.join(' > ');
    }

    // ---------- Drag Listeners ----------
    function attachDragListeners(barEl, handleEl) {
        if (!handleEl) return;
        let startX, startY, initialX, initialY;

        const onMove = e => {
            if (!isDraggingStepper) return;
            if (e.cancelable) e.preventDefault();
            const p = e.touches ? e.touches[0] : e, maxX = win.innerWidth - barEl.offsetWidth, maxY = win.innerHeight - barEl.offsetHeight;
            stepperPos = { x: Math.max(0, Math.min(maxX, initialX + (p.clientX - startX))), y: Math.max(0, Math.min(maxY, initialY + (p.clientY - startY))) };
            barEl.style.setProperty('left', `${stepperPos.x}px`, 'important'); barEl.style.setProperty('top', `${stepperPos.y}px`, 'important');
            barEl.style.setProperty('right', 'auto', 'important'); barEl.style.setProperty('bottom', 'auto', 'important'); barEl.style.setProperty('transform', 'none', 'important');
        };

        const onEnd = () => {
            if (isDraggingStepper) { isDraggingStepper = false; }
            win.removeEventListener('mousemove', onMove); win.removeEventListener('mouseup', onEnd);
            win.removeEventListener('touchmove', onMove); win.removeEventListener('touchend', onEnd); win.removeEventListener('touchcancel', onEnd);
        };

        const onStart = e => {
            if (e.target.tagName === 'BUTTON') return;
            if (e.cancelable) e.preventDefault();
            isDraggingStepper = true;
            const p = e.touches ? e.touches[0] : e, r = barEl.getBoundingClientRect();
            startX = p.clientX; startY = p.clientY; initialX = r.left; initialY = r.top;
            barEl.style.setProperty('right', 'auto', 'important');
            barEl.style.setProperty('bottom', 'auto', 'important');
            barEl.style.setProperty('transform', 'none', 'important');
            barEl.style.setProperty('margin', '0', 'important');
            barEl.style.setProperty('left', `${initialX}px`, 'important');
            barEl.style.setProperty('top', `${initialY}px`, 'important');
            win.addEventListener('mousemove', onMove, { passive: false }); win.addEventListener('mouseup', onEnd);
            win.addEventListener('touchmove', onMove, { passive: false }); win.addEventListener('touchend', onEnd); win.addEventListener('touchcancel', onEnd);
        };
        handleEl.addEventListener('mousedown', onStart, { passive: false });
        handleEl.addEventListener('touchstart', onStart, { passive: false });
    }

    function clearSelectionState() {
        previewElement?.classList.remove('hider-preview-highlight'); previewElement = null; stepperStack = [];
        const stepper = shadowBy(STEPPER_BAR_ID);
        if (stepper) {
            stepper.remove();
        }
        globalScopeTemp = false;
    }

    function turnOffHideMode() {
        if (isSelecting) {
            isSelecting = false; shadowBy('btn-select')?.classList.remove('active');
            clearSelectionState(); broadcastState();
            showToast('🎯 Selection mode OFF');
        }
        globalScopeTemp = false;
    }

    function closeAllMenus(e, force = false) {
        if (!shadowRoot) return false;
        if (!force) {
            if (isSelecting || isDraggingDock || isDraggingStepper) return false; 
            const active = shadowRoot.activeElement || doc.activeElement;
            if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA')) return false;
            const path = e?.composedPath?.() || [];
            if (path.length > 0 && path.some(el => el.id === UI_HOST_ID || el.id === STEPPER_BAR_ID)) return false;
            if (shadowBy('hider-panel')?.querySelector('.is-editing')) return false;
        }

        const panel = shadowBy('hider-panel'), menu = shadowBy('hider-dock-menu'), mainBtn = shadowBy('btn-toggle-dock'), dockEl = shadowBy('hider-main-dock');
        let closed = false;
        shadowRoot.querySelectorAll('.h-custom-select').forEach(c => c.classList.remove('is-open'));

        if (linkPanelEl && linkPanelEl.classList.contains('is-visible')) {
            linkPanelEl.classList.remove('is-visible');
            setTimeout(() => linkPanelEl.style.display = 'none', 300);
            closed = true;
        }

        if (panel && panel.classList.contains('is-visible')) { 
            panel.classList.remove('is-visible'); 
            setTimeout(()=> { if(!panel.classList.contains('is-visible')) panel.style.display='none'; }, 300); 
            shadowBy('btn-manage')?.classList.remove('active'); 
            closed = true; 
        }
        if (menu && menu.classList.contains('is-open')) {
            menu.classList.remove('is-open'); mainBtn?.classList.remove('expanded'); dockEl?.classList.remove('expanded'); dockEl?.classList.add('manual-hidden');
            if (timers.collapseTimer) clearTimeout(timers.collapseTimer);
            timers.collapseTimer = setTimeout(() => { dockEl?.classList.add('is-collapsed'); timers.collapseTimer = null; }, 1000);
            closed = true;
        }
        return closed;
    }

    // ---------- Stepper UI ----------
    function renderTouchStepperUI() {
        if (!shadowRoot) return;
        let stepper = shadowBy(STEPPER_BAR_ID);
        if (!previewElement) { stepper?.remove(); return; }
        if (!stepper) { 
            stepper = doc.createElement('div'); stepper.id = STEPPER_BAR_ID; 
            shadowRoot.appendChild(stepper); 
        }

        stepper.className = 'h-glass h-stepper-pill';
        if (stepperPos.x !== null && stepperPos.y !== null) {
            stepper.style.setProperty('left', `${stepperPos.x}px`, 'important'); 
            stepper.style.setProperty('top', `${stepperPos.y}px`, 'important');
            stepper.style.setProperty('bottom', 'auto', 'important'); 
            stepper.style.setProperty('right', 'auto', 'important');
            stepper.style.setProperty('transform', 'none', 'important'); 
            stepper.style.setProperty('margin', '0', 'important');
        } else {
            stepper.style.setProperty('left', '50%', 'important');
            stepper.style.setProperty('top', 'auto', 'important');
            stepper.style.setProperty('bottom', '24px', 'important');
            stepper.style.setProperty('right', 'auto', 'important');
            stepper.style.setProperty('transform', 'translateX(-50%)', 'important');
            stepper.style.setProperty('margin', '0', 'important');
        }

        const tag = previewElement.tagName.toLowerCase(), c = typeof previewElement.className === 'string' ? previewElement.className.trim().split(/\s+/)[0] : '';
        const classStr = c && !c.startsWith('hider-') ? `.${c}` : '', idStr = previewElement.id && !previewElement.id.startsWith('hider-') ? `#${previewElement.id}` : '';
        const fullText = `${tag}${idStr}${classStr}`;
        const isLongText = fullText.length > 14;

        stepper.innerHTML = `
            <div id="hider-drag-handle" class="h-drag-dots" title="Drag Selector Bar">⠿</div>
            <div class="h-stepper-row">
                <button id="hider-step-up" class="h-btn-icon" title="Select Parent Element">▲</button>
                <button id="hider-step-down" class="h-btn-icon" title="Select Child Element">▼</button>
            </div>
            <div class="h-tag-badge-box" title="${fullText}">
                <span class="h-tag-badge-text ${isLongText ? 'is-animating' : ''}">${fullText}</span>
            </div>
            <button id="hider-step-confirm" class="h-btn-pill btn-blue">🙈 Hide</button>
            <button id="hider-step-confirm-global" class="h-btn-pill btn-purple" style="background:linear-gradient(135deg,#a855f7,#7e22ce)!important;">🌐 Global</button>
            <button id="hider-step-cancel" class="h-btn-pill btn-gray">✖ Cancel</button>
        `;

        attachDragListeners(stepper, stepper.querySelector('#hider-drag-handle'));

        stepper.querySelector('#hider-step-up').onclick = e => {
            e.stopPropagation(); const p = previewElement.parentElement;
            if (p && p !== doc.body && p !== doc.documentElement && p.id !== UI_HOST_ID) {
                previewElement.classList.remove('hider-preview-highlight'); stepperStack.push(previewElement);
                previewElement = p; previewElement.classList.add('hider-preview-highlight'); renderTouchStepperUI();
            } else showToast('⛰️ Top parent reached');
        };
        stepper.querySelector('#hider-step-down').onclick = e => {
            e.stopPropagation();
            if (stepperStack.length || previewElement.firstElementChild) {
                previewElement.classList.remove('hider-preview-highlight');
                previewElement = stepperStack.length ? stepperStack.pop() : previewElement.firstElementChild;
                previewElement.classList.add('hider-preview-highlight'); renderTouchStepperUI();
            }
        };
        stepper.querySelector('#hider-step-confirm').onclick = e => { e.stopPropagation(); confirmHideSelectedElement(false); };
        stepper.querySelector('#hider-step-confirm-global').onclick = e => { e.stopPropagation(); confirmHideSelectedElement(true); };
        stepper.querySelector('#hider-step-cancel').onclick = e => { 
            e.stopPropagation(); 
            clearSelectionState(); 
            showToast('❌ Selection cancelled');
        };
    }

    function confirmHideSelectedElement(global = false) {
        if (!previewElement) return;
        const el = previewElement;
        el.classList.remove('hider-preview-highlight'); el.classList.add('hider-stealth-target');
        const sel = getExactSelector(el);
        if (sel) {
            // Prevent hiding body or html
            if (sel.match(/^(html|body)/i)) {
                showToast('⚠️ Cannot hide body or html');
                return;
            }
            lastHiddenSelector = sel;
            if (global) {
                const rule = { id: 'rule_' + Date.now(), selector: sel, target: '*' };
                CACHE.customRules.push(rule);
                sv('hider_custom_rules_v4', CACHE.customRules);
                showToast('🌐 Global hide rule added!');
            } else {
                const key = currentScope === 'site' ? 'hider_site_' + location.hostname : 'hider_link_' + cleanUrl();
                const s = gv(key, []); if (!s.includes(sel)) { s.push(sel); sv(key, s); }
                showToast('🙈 Element Hidden!');
            }
        }
        requestUpdateStyles(); clearSelectionState();
    }

    // ---------- Undo Last Hide ----------
    function undoLastHide() {
        if (!lastHiddenSelector) {
            showToast('⚠️ No hidden element to undo');
            return;
        }
        let found = false;
        for (let i = 0; i < CACHE.customRules.length; i++) {
            if (CACHE.customRules[i].selector === lastHiddenSelector) {
                CACHE.customRules.splice(i, 1);
                sv('hider_custom_rules_v4', CACHE.customRules);
                found = true;
                break;
            }
        }
        if (!found) {
            const key = currentScope === 'site' ? 'hider_site_' + location.hostname : 'hider_link_' + cleanUrl();
            let rules = gv(key, []);
            const idx = rules.indexOf(lastHiddenSelector);
            if (idx !== -1) {
                rules.splice(idx, 1);
                sv(key, rules);
                found = true;
            }
        }
        if (found) {
            try {
                doc.querySelectorAll(lastHiddenSelector).forEach(el => el.classList.remove('hider-stealth-target'));
            } catch {}
            requestUpdateStyles();
            showToast('↩️ Undone last hide');
            lastHiddenSelector = null;
        } else {
            showToast('⚠️ Selector not found in rules');
        }
    }

    // ---------- Toast ----------
    function showToast(msg) {
        let targetRoot = shadowRoot;
        if (!targetRoot) targetRoot = doc.body;
        if (!targetRoot) return;

        const existing = targetRoot.querySelector('#hider-toast');
        if (existing) existing.remove();

        const toast = doc.createElement('div');
        toast.id = 'hider-toast';
        toast.className = 'h-glass h-toast';
        toast.textContent = msg;

        Object.assign(toast.style, {
            position: 'fixed',
            bottom: '70px',
            left: '50%',
            transform: 'translateX(-50%) translateY(16px)',
            opacity: '0',
            padding: '6px 16px',
            fontSize: '11px',
            fontWeight: '700',
            zIndex: '2147483647',
            pointerEvents: 'none',
            transition: 'all .3s ease',
            textAlign: 'center',
            borderRadius: '20px',
            border: '1px solid rgba(56,189,248,.5)',
            color: '#e0f2fe',
            background: 'rgba(13,18,30,0.95)',
            backdropFilter: 'blur(12px)',
            WebkitBackdropFilter: 'blur(12px)',
            boxShadow: '0 12px 30px rgba(0,0,0,0.6)',
            fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, sans-serif',
            lineHeight: '1.3',
            maxWidth: '90vw',
            whiteSpace: 'nowrap'
        });

        targetRoot.appendChild(toast);
        requestAnimationFrame(() => {
            toast.style.opacity = '1';
            toast.style.transform = 'translateX(-50%) translateY(0)';
        });

        setTimeout(() => {
            toast.style.opacity = '0';
            toast.style.transform = 'translateX(-50%) translateY(12px)';
            setTimeout(() => {
                if (toast.parentNode) toast.remove();
            }, 400);
        }, 2500);
    }

    // ---------- Clipboard ----------
    function copyToClipboard(text) {
        if (!text) return;
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(text).then(() => {
                showToast('📋 Copied!');
            }).catch(() => {
                fallbackCopy(text);
            });
        } else {
            fallbackCopy(text);
        }
    }

    function fallbackCopy(text) {
        const textarea = document.createElement('textarea');
        textarea.value = text;
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        textarea.style.left = '-9999px';
        textarea.style.top = '-9999px';
        textarea.style.width = '1px';
        textarea.style.height = '1px';
        document.body.appendChild(textarea);
        textarea.select();
        try {
            document.execCommand('copy');
            showToast('📋 Copied!');
        } catch (err) {
            showToast('❌ Copy failed');
        }
        document.body.removeChild(textarea);
    }

    // ---------- Custom Dropdown ----------
    function setupCustomDropdown(container, initialValue, onChangeCallback) {
        if (!container) return;
        const trigger = container.querySelector('.h-custom-trigger'), textSpan = container.querySelector('.h-custom-value-text'), options = container.querySelectorAll('.h-custom-opt');
        let currentVal = initialValue || 'ask'; textSpan.textContent = FREEZE_LABELS[currentVal] || FREEZE_LABELS['ask'];

        options.forEach(opt => {
            opt.classList.toggle('is-selected', opt.getAttribute('data-val') === currentVal);
            opt.onclick = e => {
                e.stopPropagation(); currentVal = opt.getAttribute('data-val');
                textSpan.textContent = FREEZE_LABELS[currentVal] || opt.textContent.trim();
                options.forEach(o => o.classList.toggle('is-selected', o === opt)); container.classList.remove('is-open'); onChangeCallback?.(currentVal);
            };
        });
        trigger.onclick = e => {
            e.stopPropagation(); const isOpen = container.classList.contains('is-open');
            shadowRoot.querySelectorAll('.h-custom-select').forEach(c => c.classList.remove('is-open'));
            if (!isOpen) container.classList.add('is-open');
        };
    }

    // ---------- Domain Management ----------
    function executeAddBlockDomain(parentDomain, triggerType, onDeny, promptEl) {
        if (parentDomain && !CACHE.blockedDomainsSet.has(parentDomain)) {
            CACHE.blockedDomainsList.push(parentDomain); CACHE.blockedDomainsSet.add(parentDomain);
            sv('hider_blocked_domains', CACHE.blockedDomainsList);
        }
        logBlockedAttempt(parentDomain, triggerType + ' (User Domain Block)'); promptEl?.remove();
        showToast(`🚫 Blocked ${parentDomain}! Managed in Control Panel.`); onDeny?.(); simulateAdWindowSuccess();
    }

    function executeAddAllowedDomain(parentDomain) {
        if (parentDomain && !CACHE.allowedDomainsSet.has(parentDomain)) {
            CACHE.allowedDomainsList.push(parentDomain); CACHE.allowedDomainsSet.add(parentDomain);
            sv('hider_allowed_domains', CACHE.allowedDomainsList);
            if (shadowBy('hider-panel')?.classList.contains('is-visible')) renderList();
        }
    }

    function showFreezePrompt(url, triggerType, onConfirm, onDeny) {
        if (!shadowRoot) return;
        shadowBy('hider-freeze-prompt')?.remove();
        const promptEl = Object.assign(doc.createElement('div'), { id: 'hider-freeze-prompt', className: 'h-glass h-prompt' });
        const displayUrl = url ? (url.length > 38 ? url.substring(0, 35) + '...' : url) : 'another page';
        const parentDomain = getParentDomain(url) || 'unknown domain';

        promptEl.innerHTML = `
            <div style="font-weight:800;color:#38bdf8;font-size:11px!important;text-transform:uppercase!important;letter-spacing:0.5px">❄️ Navigation Intercepted</div>
            <div style="font-size:11px!important;color:#f8fafc!important;font-weight:600">Proceed to page?</div>
            <div class="h-url-box">${displayUrl}</div>
            <div class="h-custom-select" id="hider-modal-custom-dropdown">
                <div class="h-custom-trigger"><span class="h-custom-value-text">${FREEZE_LABELS[CACHE.freezeMemory] || FREEZE_LABELS['ask']}</span><span class="h-custom-arrow">▼</span></div>
                <div class="h-custom-options"><div class="h-custom-opt" data-val="ask">❓ Ask Every Time</div><div class="h-custom-opt" data-val="block_all">⛔ Auto-Block All Navigations</div><div class="h-custom-opt" data-val="allow_same">🔗 Allow Same Domain Only</div><div class="h-custom-opt" data-val="allow_all">🟢 Allow All Navigations</div></div>
            </div>
            <div style="display:flex;gap:6px;width:100%;margin-top:4px"><button id="hider-freeze-yes" class="h-btn-pill btn-green" style="flex:1">Allow Once</button><button id="hider-freeze-no" class="h-btn-pill btn-red" style="flex:1">Deny</button></div>
            <button id="hider-freeze-allow-btn" class="h-btn-pill" style="width:100%;margin-top:4px;background:rgba(16,185,129,0.15)!important;border:1px solid rgba(16,185,129,0.4)!important;color:#34d399!important;">🟢 Always Allow (${parentDomain})</button>
            <button id="hider-freeze-block-btn" class="h-btn-pill" style="width:100%;margin-top:4px;background:rgba(239,68,68,0.15)!important;border:1px solid rgba(239,68,68,0.4)!important;color:#fca5a5!important;">🚫 Always Block (${parentDomain})</button>
        `;

        shadowRoot.appendChild(promptEl); let selectedMem = CACHE.freezeMemory || 'ask';
        setupCustomDropdown(promptEl.querySelector('#hider-modal-custom-dropdown'), selectedMem, v => { selectedMem = v; });

        setTimeout(() => { promptEl.style.opacity = '1'; promptEl.style.transform = 'translateX(-50%) translateY(0)'; }, 10);

        const saveMem = () => { if (selectedMem !== CACHE.freezeMemory) { CACHE.freezeMemory = selectedMem; sv('hider_freeze_memory', selectedMem); } };

        promptEl.querySelector('#hider-freeze-yes').onclick = () => { 
            saveMem(); if (selectedMem === 'allow_all') disableFreezeMode(); else if (selectedMem === 'allow_same' && parentDomain !== 'unknown domain') executeAddAllowedDomain(parentDomain);
            promptEl.remove(); onConfirm?.(); 
        };
        promptEl.querySelector('#hider-freeze-no').onclick = () => { 
            saveMem(); if (selectedMem === 'allow_all') disableFreezeMode();
            logBlockedAttempt(url, triggerType + ' (User)'); promptEl.remove(); onDeny?.(); simulateAdWindowSuccess(); 
        };
        promptEl.querySelector('#hider-freeze-allow-btn').onclick = () => {
            saveMem(); if (parentDomain !== 'unknown domain') executeAddAllowedDomain(parentDomain);
            if (selectedMem === 'allow_all') disableFreezeMode();
            promptEl.remove(); showToast(`🟢 Allowed ${parentDomain}!`); onConfirm?.();
        };
        promptEl.querySelector('#hider-freeze-block-btn').onclick = () => {
            saveMem(); const skipConfirm = gv('hider_skip_block_confirm', false);
            if (skipConfirm) { executeAddBlockDomain(parentDomain, triggerType, onDeny, promptEl); return; }

            promptEl.innerHTML = `
                <div style="font-weight:800;color:#ef4444;font-size:11px!important;text-transform:uppercase!important;">🚫 Confirm Domain Block</div>
                <div style="font-size:11px!important;color:#f8fafc!important;text-align:center;margin:2px 0">Block all future requests to:<br><strong style="color:#38bdf8;font-size:12px!important">${parentDomain}</strong>?</div>
                <label style="font-size:10px!important;color:#cbd5e1!important;display:flex;align-items:center;gap:4px;cursor:pointer;margin:4px 0;user-select:none"><input type="checkbox" id="hider-dont-ask-block" style="cursor:pointer;accent-color:#38bdf8;width:12px!important;height:12px!important"> Don't ask confirmation again</label>
                <div style="display:flex;gap:6px;width:100%;margin-top:4px"><button id="hider-confirm-block-yes" class="h-btn-pill btn-red" style="flex:1">Yes, Block</button><button id="hider-confirm-block-no" class="h-btn-pill" style="flex:1;background:rgba(255,255,255,0.1)!important;color:#f1f5f9!important;border:1px solid rgba(255,255,255,0.15)!important;">Cancel</button></div>
            `;
            promptEl.querySelector('#hider-confirm-block-yes').onclick = () => {
                if (promptEl.querySelector('#hider-dont-ask-block')?.checked) sv('hider_skip_block_confirm', true);
                executeAddBlockDomain(parentDomain, triggerType, onDeny, promptEl);
            };
            promptEl.querySelector('#hider-confirm-block-no').onclick = () => { showFreezePrompt(url, triggerType, onConfirm, onDeny); };
        };
    }

    // ---------- Enhanced Reveal (Quick) ----------
    function revealHiddenElements() {
        if (!doc.body) return;

        const isHiddenByUs = el => 
            el.id === UI_HOST_ID || 
            el.closest('#' + UI_HOST_ID) || 
            el.classList.contains('hider-stealth-target');

        const targets = new Set();

        const inlineHidden = doc.querySelectorAll([
            '[style*="display:none"]',
            '[style*="display: none"]',
            '[style*="visibility:hidden"]',
            '[style*="visibility: hidden"]',
            '[style*="opacity:0"]',
            '[style*="opacity: 0"]',
            '[style*="filter:blur"]',
            '[style*="filter: blur"]',
            '[style*="backdrop-filter:blur"]',
            '[style*="backdrop-filter: blur"]'
        ].join(','));
        inlineHidden.forEach(el => targets.add(el));

        const overlaySelector = [
            'div[style*="position:fixed"]',
            'div[style*="position: fixed"]',
            'div[style*="position:absolute"]',
            'div[style*="position: absolute"]',
            'div[style*="z-index: 999"]',
            'div[style*="z-index:999"]',
            'div[style*="z-index: 9999"]',
            'div[style*="z-index:9999"]',
            'div[style*="z-index: 99999"]',
            'div[style*="z-index:99999"]'
        ].join(',');
        const overlayCandidates = doc.querySelectorAll(overlaySelector);
        overlayCandidates.forEach(el => {
            const rect = el.getBoundingClientRect();
            if (rect.width < 100 || rect.height < 100) return;
            if (el.innerText.length > 200) return;
            if (el.querySelector('article, main, p, h1, h2, h3, h4, h5, h6')) return;
            targets.add(el);
        });

        doc.querySelectorAll([
            '.modal', '.overlay', '.popup', '.lightbox', '.blocker', 
            '.paywall', '.gate', '.wall', '.restricted', '.locked',
            '[data-overlay]', '[data-modal]', '[data-popup]', '[data-paywall]'
        ].join(',')).forEach(el => {
            if (!isHiddenByUs(el)) targets.add(el);
        });

        doc.querySelectorAll('*').forEach(el => {
            if (isHiddenByUs(el)) return;
            const style = win.getComputedStyle(el);
            if (style.filter && style.filter.includes('blur')) {
                targets.add(el);
            }
            if (style.backdropFilter && style.backdropFilter.includes('blur')) {
                targets.add(el);
            }
            if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
                targets.add(el);
            }
        });

        let count = 0;
        let blurCount = 0, hiddenCount = 0, overlayCount = 0;

        const processBatch = (arr, start) => {
            const end = Math.min(start + 50, arr.length);
            for (let i = start; i < end; i++) {
                const el = arr[i];
                if (isHiddenByUs(el)) continue;

                const style = win.getComputedStyle(el);
                let changed = false;

                if (style.filter && style.filter.includes('blur')) {
                    el.style.setProperty('filter', 'none', 'important');
                    el.style.setProperty('backdrop-filter', 'none', 'important');
                    el.style.setProperty('-webkit-backdrop-filter', 'none', 'important');
                    blurCount++;
                    changed = true;
                }

                if (style.display === 'none') {
                    el.style.setProperty('display', 'block', 'important');
                    hiddenCount++;
                    changed = true;
                }
                if (style.visibility === 'hidden') {
                    el.style.setProperty('visibility', 'visible', 'important');
                    hiddenCount++;
                    changed = true;
                }
                if (style.opacity === '0') {
                    el.style.setProperty('opacity', '1', 'important');
                    hiddenCount++;
                    changed = true;
                }

                if (style.pointerEvents === 'none') {
                    el.style.setProperty('pointer-events', 'auto', 'important');
                }
                if (style.userSelect === 'none') {
                    el.style.setProperty('user-select', 'text', 'important');
                    el.style.setProperty('-webkit-user-select', 'text', 'important');
                }

                if (style.position === 'fixed' || style.position === 'absolute') {
                    const z = parseInt(style.zIndex, 10);
                    if (z > 900) {
                        el.style.setProperty('position', 'static', 'important');
                        el.style.setProperty('z-index', 'auto', 'important');
                        overlayCount++;
                        changed = true;
                    }
                }

                if (changed) count++;
            }

            if (end < arr.length) {
                requestAnimationFrame(() => processBatch(arr, end));
            } else {
                const parts = [];
                if (hiddenCount) parts.push(`${hiddenCount} hidden`);
                if (blurCount) parts.push(`${blurCount} blurred`);
                if (overlayCount) parts.push(`${overlayCount} overlays`);
                const summary = parts.length ? `👁️ Revealed: ${parts.join(', ')}` : '👁️ No hidden/blurred elements found.';
                showToast(summary);
                if (CACHE.autoScroll && featuresEnabled) forceEnableScroll();
            }
        };

        const targetArray = Array.from(targets);
        if (targetArray.length === 0) {
            showToast('👁️ No hidden/blurred elements found.');
            return;
        }
        requestAnimationFrame(() => processBatch(targetArray, 0));
    }

    // ---------- Time Skipper ----------
    function skip30Seconds() {
        let mediaCount = 0;
        doc.querySelectorAll('video, audio').forEach(el => {
            try {
                if (!isNaN(el.duration) && isFinite(el.duration)) {
                    el.currentTime = Math.min(el.duration, el.currentTime + 30);
                } else {
                    el.currentTime += 30;
                }
                mediaCount++;
            } catch {}
        });

        let timerCount = 0;
        const timerElements = doc.querySelectorAll(
            '[class*="timer"], [class*="countdown"], [id*="timer"], [id*="countdown"], ' +
            '[class*="time"], [id*="time"], [class*="remaining"], [id*="remaining"]'
        );
        timerElements.forEach(el => {
            const text = el.textContent.trim();
            if (/^\d{1,2}:\d{2}$/.test(text) || /^\d+\s*(s|sec|seconds?)$/i.test(text) || /^\d{1,2}:\d{2}\s*$/.test(text)) {
                el.textContent = '0';
                el.dispatchEvent(new Event('input', { bubbles: true }));
                timerCount++;
            }
        });

        doc.querySelectorAll('*:not([class*="timer"]):not([id*="timer"]):not([class*="countdown"]):not([id*="countdown"])')
            .forEach(el => {
                const text = el.textContent.trim();
                if (/^(?:[0-9]{1,2}:[0-5][0-9]|[1-9][0-9]?s?)$/i.test(text)) {
                    el.textContent = '0';
                    el.dispatchEvent(new Event('input', { bubbles: true }));
                    timerCount++;
                }
            });

        let clickCount = 0;
        const skipBtns = doc.querySelectorAll('button, a[role="button"], [role="button"]');
        skipBtns.forEach(btn => {
            const text = btn.textContent.trim().toLowerCase();
            if (text && (text.includes('skip') || text.includes('close') || text.includes('dismiss'))) {
                const rect = btn.getBoundingClientRect();
                if (rect.width > 0 && rect.height > 0) {
                    try { btn.click(); clickCount++; } catch {}
                }
            }
        });

        broadcastToFrames(window, { type: 'HIDER_SKIP_30' });

        const msgParts = [];
        if (mediaCount) msgParts.push(`${mediaCount} media`);
        if (timerCount) msgParts.push(`${timerCount} timers`);
        if (clickCount) msgParts.push(`${clickCount} buttons`);
        const summary = msgParts.length ? `⏩ Skipped: ${msgParts.join(', ')}` : '⏩ Skipped +30s';
        showToast(summary);
    }

    function autoSkipTimers() {
        if (!CACHE.autoTimeSkipper) return;
        if (!featuresEnabled) return;
        let timerCount = 0, clickCount = 0;

        const timerSelectors = [
            '[class*="timer"]', '[class*="countdown"]', '[id*="timer"]', '[id*="countdown"]',
            '[class*="time"]', '[id*="time"]', '[class*="remaining"]', '[id*="remaining"]'
        ];
        timerSelectors.forEach(sel => {
            doc.querySelectorAll(sel).forEach(el => {
                const text = el.textContent.trim();
                if (/^\d{1,2}:\d{2}$/.test(text) || /^\d+\s*(s|sec|seconds?)$/i.test(text) || /^\d{1,2}:\d{2}\s*$/.test(text)) {
                    el.textContent = '0';
                    el.dispatchEvent(new Event('input', { bubbles: true }));
                    timerCount++;
                }
            });
        });

        doc.querySelectorAll('*:not([class*="timer"]):not([id*="timer"]):not([class*="countdown"]):not([id*="countdown"])')
            .forEach(el => {
                const text = el.textContent.trim();
                if (/^(?:[0-9]{1,2}:[0-5][0-9]|[1-9][0-9]?s?)$/i.test(text)) {
                    el.textContent = '0';
                    el.dispatchEvent(new Event('input', { bubbles: true }));
                    timerCount++;
                }
            });

        const skipBtns = doc.querySelectorAll('button, a[role="button"], [role="button"]');
        skipBtns.forEach(btn => {
            const text = btn.textContent.trim().toLowerCase();
            if (text && (text.includes('skip') || text.includes('close') || text.includes('dismiss'))) {
                const rect = btn.getBoundingClientRect();
                if (rect.width > 0 && rect.height > 0) {
                    try { btn.click(); clickCount++; } catch {}
                }
            }
        });

        if (timerCount || clickCount) {
            showToast(`⏩ Auto-skipped: ${timerCount} timers, ${clickCount} buttons`);
        }
    }

    // ========== AGGRESSIVE PAUSE ==========
    function pauseAllVideos() {
        function pauseMedia(el) {
            try {
                if (el.tagName === 'VIDEO' || el.tagName === 'AUDIO') {
                    el.pause();
                    el.currentTime = 0;
                    el.loop = false;
                }
            } catch(e) {}
        }

        function traverse(node) {
            if (!node) return;
            if (node.nodeType === Node.ELEMENT_NODE) {
                pauseMedia(node);
                if (node.shadowRoot) {
                    traverse(node.shadowRoot);
                }
                if (node.tagName === 'IFRAME' || node.tagName === 'FRAME') {
                    try {
                        if (node.contentDocument) {
                            traverse(node.contentDocument);
                        }
                    } catch(e) {}
                }
                if (node.childNodes) {
                    node.childNodes.forEach(child => traverse(child));
                }
            } else if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.DOCUMENT_NODE) {
                if (node.childNodes) {
                    node.childNodes.forEach(child => traverse(child));
                }
            }
        }

        traverse(document);
        document.querySelectorAll('video, audio').forEach(pauseMedia);
    }

    // ========== LINK EXTRACTOR ==========
    function isDirectMedia(url) {
        if (!url) return false;
        const lower = url.toLowerCase();
        if (lower.startsWith('blob:')) return true;
        const mediaExts = [
            '.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico', '.tiff', '.tif', '.avif', '.heic', '.heif',
            '.mp4', '.webm', '.ogg', '.ogv', '.mov', '.avi', '.mkv', '.ts', '.m4v', '.wmv', '.flv', '.m3u8',
            '.mp3', '.wav', '.flac', '.m4a', '.aac', '.ogg', '.wma'
        ];
        return mediaExts.some(ext => lower.includes(ext));
    }

    function getMediaType(url) {
        if (!url) return null;
        const lower = url.toLowerCase();
        const imgExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico', '.tiff', '.tif', '.avif', '.heic', '.heif'];
        if (imgExts.some(ext => lower.includes(ext))) return 'image';
        const vidExts = ['.mp4', '.webm', '.ogg', '.ogv', '.mov', '.avi', '.mkv', '.ts', '.m4v', '.wmv', '.flv', '.m3u8'];
        if (vidExts.some(ext => lower.includes(ext))) return 'video';
        const audExts = ['.mp3', '.wav', '.flac', '.m4a', '.aac', '.ogg', '.wma'];
        if (audExts.some(ext => lower.includes(ext))) return 'audio';
        if (lower.startsWith('blob:')) return 'image';
        return null;
    }

    function isMediaUrl(url) {
        return getMediaType(url) !== null;
    }

    function getAllLinks() {
        const linkMap = new Map();

        function addLink(url, text, type = 'link') {
            if (!url) return;
            try {
                const abs = new URL(url, location.href).href;
                if (abs.startsWith('javascript:') || abs.startsWith('mailto:') || abs.startsWith('tel:') || abs === '#') return;
                let finalType = type;
                const mediaType = getMediaType(abs);
                if (mediaType) finalType = 'media';
                if (!linkMap.has(abs)) {
                    linkMap.set(abs, { url: abs, text: text || abs, type: finalType, mediaSubtype: mediaType });
                } else {
                    const existing = linkMap.get(abs);
                    if (finalType === 'media' && existing.type === 'link') {
                        existing.type = 'media';
                        existing.mediaSubtype = mediaType;
                    }
                    if (text && text !== abs && (existing.text === existing.url || !existing.text)) {
                        existing.text = text;
                    }
                }
            } catch (e) { /* ignore */ }
        }

        function traverse(node) {
            if (!node) return;
            if (node.nodeType === Node.ELEMENT_NODE) {
                const el = node;

                if (el.tagName === 'VIDEO' || el.tagName === 'AUDIO') {
                    const src = el.getAttribute('src') || el.currentSrc;
                    if (src) {
                        const text = el.getAttribute('title') || el.getAttribute('aria-label') || el.getAttribute('alt') || el.textContent.trim() || src;
                        addLink(src, text, 'media');
                    }
                    el.querySelectorAll('source').forEach(source => {
                        const s = source.getAttribute('src');
                        if (s) {
                            const label = source.getAttribute('label') || source.getAttribute('title') || s;
                            addLink(s, label, 'media');
                        }
                    });
                    const poster = el.getAttribute('poster');
                    if (poster && isMediaUrl(poster)) {
                        addLink(poster, 'Poster image', 'media');
                    }
                }

                if (el.tagName === 'IMG') {
                    const src = el.getAttribute('src') || el.currentSrc;
                    if (src) {
                        const text = el.alt || el.title || el.getAttribute('aria-label') || src;
                        addLink(src, text, 'media');
                    }
                    const srcset = el.getAttribute('srcset');
                    if (srcset) {
                        const urls = srcset.split(',').map(s => s.trim().split(/\s+/)[0]).filter(Boolean);
                        urls.forEach(u => {
                            if (u) addLink(u, el.alt || el.title || u, 'media');
                        });
                    }
                    const lazyAttrs = ['data-src', 'data-original', 'data-lazy-src', 'data-srcset'];
                    lazyAttrs.forEach(attr => {
                        const val = el.getAttribute(attr);
                        if (val) {
                            if (attr === 'data-srcset') {
                                const urls = val.split(',').map(s => s.trim().split(/\s+/)[0]).filter(Boolean);
                                urls.forEach(u => addLink(u, el.alt || el.title || u, 'media'));
                            } else {
                                addLink(val, el.alt || el.title || val, 'media');
                            }
                        }
                    });
                }

                if (el.tagName === 'SOURCE' && el.closest('picture')) {
                    const s = el.getAttribute('src');
                    if (s) {
                        const label = el.getAttribute('label') || el.getAttribute('title') || s;
                        addLink(s, label, 'media');
                    }
                    const srcset = el.getAttribute('srcset');
                    if (srcset) {
                        const urls = srcset.split(',').map(s => s.trim().split(/\s+/)[0]).filter(Boolean);
                        urls.forEach(u => addLink(u, el.getAttribute('label') || u, 'media'));
                    }
                }

                const dataAttrs = ['src', 'url', 'link', 'video-src', 'audio-src', 'media-url', 'file', 'image', 'img', 'photo'];
                for (const attr of dataAttrs) {
                    const val = el.getAttribute('data-' + attr);
                    if (val && isMediaUrl(val)) {
                        const text = el.textContent.trim() || el.title || el.getAttribute('aria-label') || val;
                        addLink(val, text, 'media');
                    }
                }

                if (el.matches('a[href], area[href]')) {
                    const href = el.getAttribute('href');
                    if (href && isMediaUrl(href)) {
                        const text = el.textContent.trim() || el.title || el.getAttribute('aria-label') || href;
                        addLink(href, text, 'media');
                    } else if (href) {
                        const text = el.textContent.trim() || el.title || el.getAttribute('aria-label') || href;
                        addLink(href, text, 'link');
                    }
                }

                const onclick = el.getAttribute('onclick');
                if (onclick) {
                    const matches = onclick.match(/(?:location\.href|window\.open)\s*\(\s*['"]([^'"]+)['"]/gi);
                    if (matches) {
                        matches.forEach(m => {
                            const urlMatch = m.match(/['"]([^'"]+)['"]/);
                            if (urlMatch) {
                                const url = urlMatch[1];
                                if (isMediaUrl(url)) {
                                    const text = el.textContent.trim() || el.title || el.getAttribute('aria-label') || url;
                                    addLink(url, text, 'media');
                                }
                            }
                        });
                    }
                }

                if (el.matches('form[action]')) {
                    const action = el.getAttribute('action');
                    if (action && isMediaUrl(action)) {
                        const text = el.getAttribute('name') || el.id || 'Form action';
                        addLink(action, text, 'media');
                    }
                }

                if (el.tagName === 'IFRAME') {
                    const iframeSrc = el.getAttribute('src');
                    if (iframeSrc) {
                        const text = el.getAttribute('title') || el.getAttribute('aria-label') || 'iframe';
                        addLink(iframeSrc, text, 'link');
                    }
                }

                if (el.shadowRoot) {
                    traverseShadow(el.shadowRoot);
                }
            }

            if (node.childNodes) {
                for (const child of node.childNodes) {
                    traverse(child);
                }
            }
        }

        function traverseShadow(root) {
            if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
                for (const child of root.children) {
                    traverse(child);
                }
            }
        }

        traverse(document);
        return Array.from(linkMap.values());
    }

    // ---------- Preview Modal ----------
    function closePreviewModal(modalEl) {
        const modal = modalEl || shadowBy('hider-link-preview-modal');
        if (modal && modal.parentNode) {
            modal.remove();
        }
        if (previewOutsideListener) {
            document.removeEventListener('click', previewOutsideListener);
            previewOutsideListener = null;
        }
    }

    function showLinkPreview(url) {
        const existing = shadowBy('hider-link-preview-modal');
        if (existing) {
            closePreviewModal(existing);
        }

        const mediaType = getMediaType(url);
        const isDirect = isDirectMedia(url);

        const modal = doc.createElement('div');
        modal.id = 'hider-link-preview-modal';
        modal.className = 'h-glass';
        modal.style.cssText = `
            position: fixed !important;
            top: 50% !important;
            left: 50% !important;
            transform: translate(-50%, -50%) !important;
            z-index: 2147483647 !important;
            padding: 16px !important;
            border-radius: 16px !important;
            background: rgba(13, 18, 30, 0.96) !important;
            backdrop-filter: blur(16px) !important;
            border: 1px solid rgba(255,255,255,0.15) !important;
            box-shadow: 0 24px 48px rgba(0,0,0,0.8) !important;
            min-width: 280px !important;
            max-width: 90vw !important;
            max-height: 90vh !important;
            pointer-events: auto !important;
            display: flex !important;
            flex-direction: column !important;
            gap: 10px !important;
            color: #f8fafc !important;
            overflow-y: auto !important;
        `;

        let typeIcon = '🔗';
        if (mediaType === 'image') typeIcon = '🖼️';
        else if (mediaType === 'video') typeIcon = '🎬';
        else if (mediaType === 'audio') typeIcon = '🔊';

        const title = doc.createElement('div');
        title.style.cssText = 'font-weight:800; font-size:12px; color:#38bdf8; text-transform:uppercase; letter-spacing:0.5px;';
        title.textContent = `${typeIcon} ${mediaType ? mediaType.toUpperCase() : 'Link'} Preview`;
        modal.appendChild(title);

        if (mediaType) {
            const mediaWrapper = doc.createElement('div');
            mediaWrapper.style.cssText = `
                display:flex; justify-content:center; align-items:center; 
                background: rgba(0,0,0,0.4); border-radius:8px; padding:4px;
                min-height: 80px; max-height: 55vh; overflow:hidden;
            `;

            if (mediaType === 'image') {
                const img = doc.createElement('img');
                img.src = url;
                img.style.cssText = 'max-width:100%; max-height:55vh; object-fit:contain; border-radius:4px;';
                img.onerror = () => { 
                    img.alt = '❌ Failed to load image';
                    img.style.cssText += 'height:60px; width:auto;';
                };
                mediaWrapper.appendChild(img);
            } else if (mediaType === 'video') {
                if (isDirect) {
                    const video = doc.createElement('video');
                    video.src = url;
                    video.controls = true;
                    video.preload = 'metadata';
                    video.style.cssText = 'max-width:100%; max-height:55vh; border-radius:4px; background:#000;';
                    video.onerror = () => {
                        video.innerHTML = '<div style="padding:20px;color:#f87171;font-size:12px;">❌ Failed to load video</div>';
                    };
                    mediaWrapper.appendChild(video);
                } else {
                    mediaWrapper.textContent = '🎬 Video – click "Open" to watch in new tab.';
                    mediaWrapper.style.cssText += 'padding:20px;color:#94a3b8;font-size:12px;';
                }
            } else if (mediaType === 'audio') {
                const audio = doc.createElement('audio');
                audio.src = url;
                audio.controls = true;
                audio.preload = 'metadata';
                audio.style.cssText = 'width:100%;';
                audio.onerror = () => {
                    audio.innerHTML = '<div style="padding:20px;color:#f87171;font-size:12px;">❌ Failed to load audio</div>';
                };
                mediaWrapper.appendChild(audio);
            } else {
                mediaWrapper.textContent = 'Media preview not available';
                mediaWrapper.style.cssText += 'padding:20px;color:#94a3b8;font-size:12px;';
            }
            modal.appendChild(mediaWrapper);
        } else {
            const linkPreview = doc.createElement('div');
            linkPreview.textContent = '🔗 Link Preview';
            linkPreview.style.cssText = 'font-size:12px;color:#94a3b8;padding:10px;';
            modal.appendChild(linkPreview);
        }

        const urlDisplay = doc.createElement('div');
        urlDisplay.style.cssText = 'font-size:10px; word-break:break-all; background:rgba(0,0,0,0.3); padding:6px 8px; border-radius:6px; border:1px solid rgba(255,255,255,0.1); font-family:monospace; max-height:80px; overflow-y:auto;';
        urlDisplay.textContent = url;
        modal.appendChild(urlDisplay);

        const btnGroup = doc.createElement('div');
        btnGroup.style.cssText = 'display:flex; gap:6px; justify-content:flex-end; flex-wrap:wrap;';

        const copyBtn = doc.createElement('button');
        copyBtn.className = 'hider-btn-small btn-blue';
        copyBtn.textContent = '📋 Copy';
        copyBtn.onclick = () => {
            copyToClipboard(url);
            showToast('📋 URL copied!');
        };
        btnGroup.appendChild(copyBtn);

        if (isDirect && (mediaType === 'image' || mediaType === 'video' || mediaType === 'audio')) {
            const downloadBtn = doc.createElement('button');
            downloadBtn.className = 'hider-btn-small btn-green';
            downloadBtn.textContent = '⬇️ Download';
            downloadBtn.onclick = function(e) {
                e.stopPropagation();
                let filename = url.split('/').pop().split(/[?#]/)[0] || 'media_file';
                if (!filename.includes('.')) {
                    if (mediaType === 'image') filename += '.jpg';
                    else if (mediaType === 'video') filename += '.mp4';
                    else if (mediaType === 'audio') filename += '.mp3';
                    else filename += '.bin';
                }
                try {
                    GM_download({
                        url: url,
                        name: filename,
                        onerror: function(err) {
                            console.error('GM_download failed, trying fetch fallback', err);
                            fetch(url).then(res => {
                                if (!res.ok) throw new Error('Network error');
                                return res.blob();
                            }).then(blob => {
                                const a = document.createElement('a');
                                const objectUrl = URL.createObjectURL(blob);
                                a.href = objectUrl;
                                a.download = filename;
                                document.body.appendChild(a);
                                a.click();
                                document.body.removeChild(a);
                                URL.revokeObjectURL(objectUrl);
                                showToast('⬇️ Downloaded using fallback');
                            }).catch(() => {
                                showToast('❌ Download failed – opening in new tab');
                                window.open(url, '_blank');
                            });
                        }
                    });
                    showToast(`⬇️ Downloading: ${filename}`);
                } catch (err) {
                    console.error('GM_download error:', err);
                    showToast('❌ Download error – opening in new tab');
                    window.open(url, '_blank');
                }
            };
            btnGroup.appendChild(downloadBtn);
        }

        const openBtn = doc.createElement('button');
        openBtn.className = 'hider-btn-small btn-purple';
        openBtn.textContent = '↗ Open';
        openBtn.onclick = () => {
            win.open(url, '_blank');
        };
        btnGroup.appendChild(openBtn);

        const closeBtn = doc.createElement('button');
        closeBtn.className = 'hider-btn-small btn-gray';
        closeBtn.textContent = '✖ Close';
        closeBtn.onclick = () => closePreviewModal(modal);
        btnGroup.appendChild(closeBtn);

        modal.appendChild(btnGroup);
        shadowRoot.appendChild(modal);

        const closeModalHandler = (e) => {
            if (!modal.parentNode) {
                document.removeEventListener('click', closeModalHandler);
                return;
            }
            const path = e.composedPath ? e.composedPath() : [];
            if (path.some(el => el === modal || (el && el.contains && el.contains(modal)))) {
                return;
            }
            if (path.some(el => el.id === UI_HOST_ID || el.id === STEPPER_BAR_ID)) {
                return;
            }
            closePreviewModal(modal);
        };
        if (previewOutsideListener) {
            document.removeEventListener('click', previewOutsideListener);
        }
        previewOutsideListener = closeModalHandler;
        setTimeout(() => {
            document.addEventListener('click', previewOutsideListener);
        }, 10);
    }

    // ----- Grid item for Media Mode -----
    function buildGridItem(link) {
        const div = doc.createElement('div');
        div.className = 'hider-grid-item';
        div.style.cssText = `
            position: relative;
            background: rgba(255,255,255,0.04);
            border-radius: 8px;
            overflow: hidden;
            aspect-ratio: 1 / 1;
            cursor: pointer;
            border: 1px solid rgba(255,255,255,0.08);
            transition: transform 0.2s ease, box-shadow 0.2s ease;
        `;
        div.onmouseover = () => { div.style.transform = 'scale(1.03)'; div.style.boxShadow = '0 4px 12px rgba(0,0,0,0.6)'; };
        div.onmouseout = () => { div.style.transform = 'scale(1)'; div.style.boxShadow = 'none'; };

        const mediaType = link.mediaSubtype || getMediaType(link.url);
        const isDirect = isDirectMedia(link.url);
        let icon = '📎';
        if (mediaType === 'image') icon = '🖼️';
        else if (mediaType === 'video') icon = '🎬';
        else if (mediaType === 'audio') icon = '🔊';

        let thumbnail = '';
        if (mediaType === 'image') {
            thumbnail = `<img src="${link.url}" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display='none';">`;
        } else if (mediaType === 'video' && isDirect) {
            thumbnail = `<video src="${link.url}" muted preload="metadata" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display='none';"></video>`;
        } else {
            thumbnail = `<div style="display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-size:48px;color:#94a3b8;background:rgba(0,0,0,0.3);">${icon}</div>`;
        }

        div.innerHTML = thumbnail;

        const overlay = doc.createElement('div');
        overlay.style.cssText = `
            position: absolute;
            bottom: 4px;
            left: 4px;
            background: rgba(0,0,0,0.7);
            padding: 2px 6px;
            border-radius: 4px;
            font-size: 8px;
            color: #e0f2fe;
            backdrop-filter: blur(4px);
            pointer-events: none;
            font-weight: 600;
            letter-spacing: 0.3px;
            text-transform: uppercase;
        `;
        overlay.textContent = mediaType || 'media';
        div.appendChild(overlay);

        if (isDirect && (mediaType === 'image' || mediaType === 'video' || mediaType === 'audio')) {
            const downloadBtn = doc.createElement('button');
            downloadBtn.className = 'hider-btn-small';
            downloadBtn.textContent = '⬇️';
            downloadBtn.title = 'Download this media';
            downloadBtn.style.cssText = `
                position: absolute;
                bottom: 4px;
                right: 4px;
                background: rgba(0,0,0,0.7) !important;
                backdrop-filter: blur(4px);
                border: none;
                border-radius: 4px;
                color: #fff;
                padding: 2px 6px;
                font-size: 10px;
                cursor: pointer;
                z-index: 2;
                pointer-events: auto;
                transition: background 0.2s;
            `;
            downloadBtn.onmouseover = () => { downloadBtn.style.background = 'rgba(56,189,248,0.8) !important'; };
            downloadBtn.onmouseout = () => { downloadBtn.style.background = 'rgba(0,0,0,0.7) !important'; };

            downloadBtn.addEventListener('click', function(e) {
                e.stopPropagation();
                const url = link.url;
                if (!url) {
                    showToast('❌ No media URL');
                    return;
                }
                let filename = url.split('/').pop().split(/[?#]/)[0] || 'media_file';
                if (!filename.includes('.')) {
                    if (mediaType === 'image') filename += '.jpg';
                    else if (mediaType === 'video') filename += '.mp4';
                    else if (mediaType === 'audio') filename += '.mp3';
                    else filename += '.bin';
                }
                try {
                    GM_download({
                        url: url,
                        name: filename,
                        onerror: function(err) {
                            console.error('GM_download failed, trying fetch fallback', err);
                            fetch(url).then(res => {
                                if (!res.ok) throw new Error('Network error');
                                return res.blob();
                            }).then(blob => {
                                const a = document.createElement('a');
                                const objectUrl = URL.createObjectURL(blob);
                                a.href = objectUrl;
                                a.download = filename;
                                document.body.appendChild(a);
                                a.click();
                                document.body.removeChild(a);
                                URL.revokeObjectURL(objectUrl);
                                showToast('⬇️ Downloaded using fallback');
                            }).catch(() => {
                                showToast('❌ Download failed – opening in new tab');
                                window.open(url, '_blank');
                            });
                        }
                    });
                    showToast(`⬇️ Downloading: ${filename}`);
                } catch (err) {
                    console.error('GM_download error:', err);
                    showToast('❌ Download error – opening in new tab');
                    window.open(url, '_blank');
                }
            });

            div.appendChild(downloadBtn);
        }

        div.addEventListener('click', (e) => {
            if (e.target.closest('button')) return;
            showLinkPreview(link.url);
        });

        return div;
    }

    // ----- List item for normal mode -----
    function buildListItem(link, filterText, hideInternal, mediaOnly) {
        const currentHost = location.hostname;
        if (hideInternal) {
            try {
                const urlObj = new URL(link.url);
                if (urlObj.hostname === currentHost) return null;
            } catch { /* ignore */ }
        }
        if (mediaOnly && link.type !== 'media') return null;

        if (filterText) {
            const lower = filterText.toLowerCase();
            if (!link.text.toLowerCase().includes(lower) && !link.url.toLowerCase().includes(lower)) {
                return null;
            }
        }

        const div = doc.createElement('div');
        div.className = 'list-item';
        div.style.cssText = 'display:flex; justify-content:space-between; align-items:center; gap:4px;';
        
        let icon = '🔗';
        if (link.type === 'media') {
            const subtype = link.mediaSubtype || getMediaType(link.url);
            if (subtype === 'image') icon = '🖼️';
            else if (subtype === 'video') icon = '🎬';
            else if (subtype === 'audio') icon = '🔊';
            else icon = '🎬';
        }

        let displayText = link.text;
        if (link.type === 'media') {
            displayText = icon + ' ' + displayText;
        }
        if (linkDisplayMode === 'url') {
            displayText = link.url + (link.type === 'media' ? ' ' + icon : '');
        }

        const textSpan = doc.createElement('span');
        textSpan.className = 'rule-text';
        textSpan.textContent = displayText;
        textSpan.title = link.url;
        textSpan.style.cssText = 'flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;';
        
        const btnGroup = doc.createElement('div');
        btnGroup.style.cssText = 'display:flex; gap:2px; flex-shrink:0;';

        const previewBtn = doc.createElement('button');
        previewBtn.className = 'hider-btn-small btn-purple';
        previewBtn.textContent = '🔍';
        previewBtn.title = 'Preview full link (media preview if applicable)';
        previewBtn.onclick = (e) => {
            e.stopPropagation();
            showLinkPreview(link.url);
        };
        btnGroup.appendChild(previewBtn);

        const copyBtn = doc.createElement('button');
        copyBtn.className = 'hider-btn-small btn-blue';
        copyBtn.textContent = '📋';
        copyBtn.title = 'Copy URL';
        copyBtn.onclick = (e) => {
            e.stopPropagation();
            copyToClipboard(link.url);
            showToast('📋 Copied!');
        };
        btnGroup.appendChild(copyBtn);

        const openBtn = doc.createElement('button');
        openBtn.className = 'hider-btn-small btn-green';
        openBtn.textContent = '↗';
        openBtn.title = 'Open in new tab';
        openBtn.onclick = (e) => {
            e.stopPropagation();
            win.open(link.url, '_blank');
        };
        btnGroup.appendChild(openBtn);

        div.appendChild(textSpan);
        div.appendChild(btnGroup);
        return div;
    }

    function populateLinkList() {
        const listContainer = shadowBy('hider-link-list');
        if (!listContainer) return;
        const searchInput = shadowBy('hider-link-search');
        const hideInternalCheck = shadowBy('hider-link-hide-internal');
        const mediaModeCheck = shadowBy('hider-link-media-mode');
        const filterText = searchInput ? searchInput.value.toLowerCase() : '';
        const hideInternal = hideInternalCheck ? hideInternalCheck.checked : false;
        const mediaMode = mediaModeCheck ? mediaModeCheck.checked : false;

        const links = getAllLinks();
        const title = shadowBy('link-panel-title');
        if (title) title.textContent = `🔗 Extracted Links (${links.length})`;

        listContainer.innerHTML = '';
        let displayed = 0;
        const frag = doc.createDocumentFragment();

        if (mediaMode) {
            const grid = doc.createElement('div');
            grid.style.cssText = 'display:grid;grid-template-columns:repeat(3,1fr);gap:6px;';
            links.forEach(link => {
                if (link.type !== 'media') return;
                if (filterText) {
                    const lower = filterText;
                    if (!link.text.toLowerCase().includes(lower) && !link.url.toLowerCase().includes(lower)) return;
                }
                if (hideInternal) {
                    try {
                        const urlObj = new URL(link.url);
                        if (urlObj.hostname === location.hostname) return;
                    } catch {}
                }
                const item = buildGridItem(link);
                grid.appendChild(item);
                displayed++;
            });
            if (displayed === 0) {
                const empty = doc.createElement('div');
                empty.style.cssText = 'font-size:9px!important;color:#94a3b8!important;padding:8px!important;text-align:center!important;border:1px dashed rgba(255,255,255,0.12)!important;border-radius:6px!important;grid-column:1/4;';
                empty.textContent = 'No media items.';
                grid.appendChild(empty);
            }
            frag.appendChild(grid);
        } else {
            links.forEach(link => {
                const item = buildListItem(link, filterText, hideInternal, false);
                if (item) {
                    frag.appendChild(item);
                    displayed++;
                }
            });
            if (displayed === 0) {
                const empty = doc.createElement('div');
                empty.style.cssText = 'font-size:9px!important;color:#94a3b8!important;padding:8px!important;text-align:center!important;border:1px dashed rgba(255,255,255,0.12)!important;border-radius:6px!important;';
                empty.textContent = 'No matching links.';
                frag.appendChild(empty);
            }
        }

        listContainer.appendChild(frag);
        if (title) title.textContent = `🔗 Extracted Links (${displayed} shown)`;
    }

    // --- Link panel with Refresh button ---
    function createLinkPanel() {
        if (linkPanelEl) return linkPanelEl;

        const panel = doc.createElement('div');
        panel.id = 'hider-link-panel';
        panel.className = 'h-glass';
        panel.style.cssText = `
            position: fixed !important;
            right: 14px !important;
            top: 55px !important;
            z-index: 2147483645 !important;
            width: min(310px, 90vw) !important;
            max-height: min(580px, 82vh) !important;
            border-radius: 16px !important;
            padding: 10px !important;
            display: none;
            flex-direction: column !important;
            overflow-y: auto !important;
            overscroll-behavior: contain !important;
            touch-action: pan-y !important;
            pointer-events: auto !important;
            gap: 6px !important;
            opacity: 0;
            transform: scale(0.96) translateY(-8px);
            transition: opacity 0.2s ease, transform 0.2s ease !important;
        `;

        const header = doc.createElement('div');
        header.className = 'panel-header';
        header.style.cssText = 'display:flex; justify-content:space-between; align-items:center;';
        const title = doc.createElement('span');
        title.id = 'link-panel-title';
        title.textContent = '🔗 Extracted Links';
        const headerRight = doc.createElement('div');
        headerRight.style.cssText = 'display:flex; gap:4px;';

        const modeBtn = doc.createElement('button');
        modeBtn.className = 'hider-btn-small btn-gray';
        modeBtn.textContent = '📝';
        modeBtn.title = 'Toggle display: text / URL';
        modeBtn.onclick = (e) => {
            e.stopPropagation();
            linkDisplayMode = linkDisplayMode === 'text' ? 'url' : 'text';
            modeBtn.textContent = linkDisplayMode === 'text' ? '📝' : '🔗';
            populateLinkList();
        };
        headerRight.appendChild(modeBtn);

        const refreshBtn = doc.createElement('button');
        refreshBtn.className = 'hider-btn-small btn-purple';
        refreshBtn.textContent = '🔄';
        refreshBtn.title = 'Refresh links & pause media';
        refreshBtn.onclick = (e) => {
            e.stopPropagation();
            pauseAllVideos();
            populateLinkList();
            showToast('🔄 Links refreshed');
        };
        headerRight.appendChild(refreshBtn);

        const closeBtn = doc.createElement('button');
        closeBtn.className = 'hider-btn-small';
        closeBtn.style.cssText = 'background:rgba(255,255,255,0.12)!important; padding:2px 6px!important;';
        closeBtn.textContent = '✖';
        closeBtn.onclick = () => { toggleLinkPanel(); };
        headerRight.appendChild(closeBtn);

        header.appendChild(title);
        header.appendChild(headerRight);
        panel.appendChild(header);

        const searchWrapper = doc.createElement('div');
        searchWrapper.style.cssText = 'display:flex; gap:4px; align-items:center; margin-bottom:2px; flex-wrap:wrap;';
        const searchInput = doc.createElement('input');
        searchInput.id = 'hider-link-search';
        searchInput.className = 'h-select';
        searchInput.placeholder = '🔍 Filter links...';
        searchInput.style.cssText = 'flex:1; height:26px; font-size:10px; min-width:80px;';
        searchInput.oninput = () => populateLinkList();
        searchWrapper.appendChild(searchInput);

        const hideCheck = doc.createElement('label');
        hideCheck.style.cssText = 'font-size:9px; color:#cbd5e1; display:flex; align-items:center; gap:4px; cursor:pointer; user-select:none; white-space:nowrap;';
        const checkBox = doc.createElement('input');
        checkBox.id = 'hider-link-hide-internal';
        checkBox.type = 'checkbox';
        checkBox.style.cssText = 'accent-color:#38bdf8; width:12px; height:12px; cursor:pointer;';
        checkBox.onchange = () => populateLinkList();
        hideCheck.appendChild(checkBox);
        hideCheck.appendChild(doc.createTextNode('Hide internal'));
        searchWrapper.appendChild(hideCheck);

        const mediaCheck = doc.createElement('label');
        mediaCheck.style.cssText = 'font-size:9px; color:#cbd5e1; display:flex; align-items:center; gap:4px; cursor:pointer; user-select:none; white-space:nowrap;';
        const mediaBox = doc.createElement('input');
        mediaBox.id = 'hider-link-media-mode';
        mediaBox.type = 'checkbox';
        mediaBox.style.cssText = 'accent-color:#f59e0b; width:12px; height:12px; cursor:pointer;';
        mediaBox.onchange = () => populateLinkList();
        mediaCheck.appendChild(mediaBox);
        mediaCheck.appendChild(doc.createTextNode('📺 Media mode'));
        searchWrapper.appendChild(mediaCheck);

        panel.appendChild(searchWrapper);

        const listContainer = doc.createElement('div');
        listContainer.id = 'hider-link-list';
        listContainer.style.cssText = 'display:flex; flex-direction:column; gap:4px; overflow-y:auto; flex:1; overscroll-behavior:contain;';
        panel.appendChild(listContainer);

        shadowRoot.appendChild(panel);
        linkPanelEl = panel;

        return panel;
    }

    function toggleLinkPanel() {
        if (!shadowRoot) return;
        if (!linkPanelEl || !linkPanelEl.parentNode) {
            linkPanelEl = createLinkPanel();
        }

        const isVisible = linkPanelEl.classList.contains('is-visible');
        if (isVisible) {
            linkPanelEl.classList.remove('is-visible');
            setTimeout(() => linkPanelEl.style.display = 'none', 300);
        } else {
            pauseAllVideos();
            populateLinkList();
            linkPanelEl.style.display = 'flex';
            void linkPanelEl.offsetWidth;
            linkPanelEl.classList.add('is-visible');
        }
    }

    // ---------- UI Creation ----------
    function createShadowUI() {
        if (!isTop) return;
        const parentEl = doc.documentElement || doc.body;
        if (!parentEl) return;

        let hostEl = doc.getElementById(UI_HOST_ID);
        if (!hostEl) {
            hostEl = doc.createElement('div'); hostEl.id = UI_HOST_ID;
            hostEl.style.cssText = 'position:fixed!important;top:0!important;left:0!important;width:0!important;height:0!important;z-index:2147483647!important;pointer-events:none!important;display:block!important;visibility:visible!important;opacity:1!important;overflow:visible!important;';
            parentEl.appendChild(hostEl);
        }

        shadowRoot = hostEl.shadowRoot || hostEl.attachShadow({ mode: 'open' });
        const style = doc.createElement('style');
        
        style.textContent = `
        * { box-sizing: border-box !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, sans-serif !important; line-height: 1.3 !important; }
        
        .h-glass { 
            background: rgba(13, 18, 30, 0.92) !important; 
            backdrop-filter: blur(12px) !important; 
            -webkit-backdrop-filter: blur(12px) !important; 
            border: 1px solid rgba(255, 255, 255, 0.12) !important; 
            color: #f8fafc !important; 
            border-radius: 14px !important; 
            box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6) !important; 
        }

        ::-webkit-scrollbar { width: 4px !important; height: 4px !important; }
        ::-webkit-scrollbar-track { background: transparent !important; }
        ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2) !important; border-radius: 8px !important; }

        #hider-panel { 
            position: fixed !important; 
            right: 14px !important; 
            top: 55px !important; 
            z-index: 2147483645 !important; 
            width: min(480px, 92vw) !important; 
            max-height: min(700px, 85vh) !important;
            border-radius: 16px !important; 
            padding: 0 !important; 
            display: none; 
            flex-direction: column !important; 
            overflow: hidden !important; 
            pointer-events: auto !important; 
            opacity: 0; 
            transform: scale(0.96) translateY(-8px); 
            transition: opacity 0.2s ease, transform 0.2s ease !important; 
        }
        #hider-panel.is-visible { 
            opacity: 1 !important; 
            transform: scale(1) translateY(0) !important; 
            display: flex !important; 
        }

        #hider-link-panel.is-visible {
            opacity: 1 !important;
            transform: scale(1) translateY(0) !important;
            display: flex !important;
        }

        .panel-header {
            padding: 8px 12px;
            border-bottom: 1px solid rgba(255,255,255,0.08);
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-shrink: 0;
        }
        .panel-header .title {
            font-weight: 800;
            font-size: 12px;
            color: #f8fafc;
        }
        .panel-header .close-btn {
            background: rgba(255,255,255,0.08);
            border: none;
            border-radius: 6px;
            color: #cbd5e1;
            padding: 2px 8px;
            cursor: pointer;
            font-size: 11px;
        }
        .panel-header .close-btn:hover { background: rgba(255,255,255,0.16); }

        .panel-body {
            display: flex;
            flex: 1;
            overflow: hidden;
        }

        .panel-sidebar {
            flex: 0 0 110px;
            background: rgba(0,0,0,0.2);
            padding: 6px 4px;
            overflow-y: auto;
            border-right: 1px solid rgba(255,255,255,0.06);
        }

        .panel-sidebar .tab-btn {
            display: block;
            width: 100%;
            text-align: left;
            background: transparent;
            border: none;
            border-radius: 6px;
            padding: 5px 8px;
            color: #94a3b8;
            font-size: 10px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.15s ease;
            margin-bottom: 2px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .panel-sidebar .tab-btn:hover {
            background: rgba(255,255,255,0.08);
            color: #e2e8f0;
        }
        .panel-sidebar .tab-btn.active {
            background: rgba(56,189,248,0.15);
            color: #38bdf8;
            border-left: 2px solid #38bdf8;
        }

        .panel-content {
            flex: 1;
            padding: 8px 10px;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
            gap: 6px;
        }

        .panel-content .tab-content {
            display: none;
            flex-direction: column;
            gap: 6px;
        }
        .panel-content .tab-content.active {
            display: flex;
        }

        .h-dock { 
            position: fixed !important; right: 10px !important; top: 35%; z-index: 2147483643 !important; 
            display: flex !important; flex-direction: column !important; align-items: center !important; gap: 5px !important; 
            padding: 5px !important; pointer-events: auto !important; transition: transform 0.3s ease, opacity 0.3s ease !important; 
            user-select: none !important; border-radius: 20px !important;
        }
        .h-dock.is-collapsed { transform: translateX(65%) !important; opacity: 0.5 !important; } 
        .h-dock.manual-hidden { transform: translateX(65%) !important; opacity: 0.5 !important; } 
        .h-dock.is-collapsed:not(.manual-hidden):hover, .h-dock.expanded { transform: translateX(0) !important; opacity: 1 !important; }
        
        .h-dock-main { 
            width: 34px !important; height: 34px !important; font-size: 16px !important; 
            background: linear-gradient(135deg, rgba(56, 189, 248, 0.3), rgba(37, 99, 235, 0.4)) !important; 
            border: 1px solid rgba(56, 189, 248, 0.4) !important; cursor: grab !important; border-radius: 50% !important;
            flex-shrink: 0 !important; min-height: 34px !important; min-width: 34px !important; display: flex !important; align-items: center !important; justify-content: center !important;
        } 
        .h-dock-main.expanded { 
            background: linear-gradient(135deg, #0ea5e9, #2563eb) !important; color: #fff !important; 
            box-shadow: 0 0 12px rgba(14, 165, 233, 0.5) !important; border-color: transparent !important;
        }
        
        .h-dock-menu { display: flex; flex-direction: column !important; gap: 5px !important; overflow: hidden !important; max-height: 0; opacity: 0; transition: max-height 0.3s ease, opacity 0.2s ease !important; }
        .h-dock-menu.is-open { max-height: 450px; opacity: 1; }
        
        .h-dock-btn { 
            width: 32px !important; height: 32px !important; border-radius: 10px !important; 
            border: 1px solid rgba(255, 255, 255, 0.1) !important; background: rgba(255, 255, 255, 0.06) !important; 
            color: #cbd5e1 !important; font-size: 11px !important; font-weight: 700 !important; display: flex !important; 
            flex-direction: column !important; align-items: center !important; justify-content: center !important; 
            cursor: pointer !important; transition: all 0.2s ease !important; margin: 0 !important; padding: 0 !important; 
            flex-shrink: 0 !important; min-height: 32px !important; min-width: 32px !important;
        }
        .h-dock-btn:hover { background: rgba(255, 255, 255, 0.18) !important; color: #fff !important; transform: scale(1.05) !important; } 
        .h-dock-btn.active { background: linear-gradient(135deg, #0ea5e9, #2563eb) !important; color: #fff !important; border-color: transparent !important; } 
        .h-dock-btn.scope-link { background: linear-gradient(135deg, #10b981, #059669) !important; color: #fff !important; border-color: transparent !important; } 
        .h-dock-btn.is-frozen { background: linear-gradient(135deg, #8b5cf6, #6d28d9) !important; color: #fff !important; border-color: transparent !important; } 
        .h-dock-btn span { font-size: 7px !important; font-weight: 800 !important; margin-top: 1px !important; letter-spacing: 0.3px !important; text-transform: uppercase !important; }
        
        .btn-blue { background: linear-gradient(135deg, #0ea5e9, #0284c7) !important; color: #fff !important; border: 1px solid rgba(255,255,255,0.2) !important; }
        .btn-green { background: linear-gradient(135deg, #10b981, #059669) !important; color: #fff !important; border: 1px solid rgba(255,255,255,0.2) !important; }
        .btn-red { background: linear-gradient(135deg, #f43f5e, #e11d48) !important; color: #fff !important; border: 1px solid rgba(255,255,255,0.2) !important; }
        .btn-purple { background: linear-gradient(135deg, #a855f7, #7e22ce) !important; color: #fff !important; border: 1px solid rgba(255,255,255,0.2) !important; }
        .btn-gray { background: linear-gradient(135deg, #475569, #334155) !important; color: #fff !important; border: 1px solid rgba(255,255,255,0.15) !important; }

        .h-stepper-pill { 
            position: fixed !important; bottom: 20px !important; left: 50% !important; transform: translateX(-50%) !important; 
            z-index: 2147483644 !important; padding: 6px 8px !important; display: flex !important; flex-direction: column !important; 
            align-items: center !important; gap: 4px !important; pointer-events: auto !important; width: 130px !important; 
            user-select: none !important; border-radius: 12px !important; 
        }
        .h-stepper-row { display: flex !important; gap: 4px !important; width: 100% !important; justify-content: center !important; }
        .h-stepper-row .h-btn-icon { flex: 1 !important; }
        .h-drag-dots { cursor: grab !important; color: #64748b !important; font-size: 11px !important; width: 100% !important; text-align: center !important; line-height: 1 !important; letter-spacing: 2px !important; } 
        .h-btn-icon { width: 100% !important; height: 22px !important; border-radius: 6px !important; border: 1px solid rgba(255,255,255,.12) !important; background: rgba(255,255,255,.08) !important; color: #f1f5f9 !important; font-size: 9px !important; font-weight: 700 !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: center !important; } 
        .h-btn-icon:hover { background: rgba(255,255,255,.2) !important; } 
        
        .h-tag-badge-box { width: 100% !important; height: 22px !important; overflow: hidden !important; position: relative !important; background: rgba(0, 0, 0, 0.5) !important; border: 1px solid rgba(56, 189, 248, 0.3) !important; border-radius: 6px !important; display: flex !important; align-items: center !important; flex-shrink: 0 !important; }
        .h-tag-badge-text { color: #38bdf8 !important; font-size: 9px !important; font-family: monospace !important; font-weight: 700 !important; display: block !important; width: 100% !important; text-align: center !important; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; line-height: 22px !important; }
        .h-tag-badge-text.is-animating { position: absolute !important; left: 0 !important; width: auto !important; padding-left: 100% !important; text-align: left !important; animation: hiderMarqueeR2L 8s linear infinite !important; }
        @keyframes hiderMarqueeR2L { 0% { transform: translate3d(0,0,0); } 100% { transform: translate3d(-100%,0,0); } }

        .h-btn-pill { height: 22px !important; min-height: 22px !important; width: 100% !important; padding: 0 6px !important; border-radius: 6px !important; font-size: 9px !important; font-weight: 800 !important; border: none !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: center !important; } 
        .h-btn-pill:hover { filter: brightness(1.15) !important; } 

        .h-toast { /* overridden by inline styles */ }
        .h-prompt { position: fixed !important; top: 25px !important; left: 50% !important; transform: translateX(-50%) translateY(-15px) !important; opacity: 0; padding: 12px 14px !important; z-index: 2147483646 !important; display: flex !important; flex-direction: column !important; align-items: center !important; gap: 6px !important; pointer-events: auto !important; width: min(290px, 88vw) !important; max-height: 85vh !important; transition: all 0.3s ease !important; } 
        .h-url-box { font-size: 10px !important; color: #94a3b8 !important; word-break: break-all !important; max-height: 32px !important; overflow: hidden !important; background: rgba(0,0,0,.4) !important; padding: 4px 8px !important; border-radius: 6px !important; width: 100% !important; border: 1px solid rgba(255,255,255,.1) !important; font-family: monospace !important; } 
        .h-select { width: 100% !important; background: rgba(255,255,255,.06) !important; border: 1px solid rgba(255,255,255,.14) !important; border-radius: 6px !important; color: #fff !important; padding: 4px 8px !important; font-size: 10px !important; outline: 0 !important; height: 28px !important; } 
        
        .h-custom-select { position: relative !important; width: 100% !important; user-select: none !important; margin-top: 2px !important; z-index: 10 !important; } 
        .h-custom-trigger { background: rgba(30,41,59,.85) !important; border: 1px solid rgba(96,165,250,.4) !important; border-radius: 8px !important; color: #f1f5f9 !important; padding: 6px 10px !important; font-size: 10px !important; font-weight: 700 !important; cursor: pointer !important; display: flex !important; justify-content: space-between !important; align-items: center !important; height: 30px !important; } 
        .h-custom-arrow { font-size: 9px !important; color: #38bdf8 !important; transition: transform .2s ease !important; } 
        .h-custom-select.is-open .h-custom-arrow { transform: rotate(-180deg) !important; } 
        .h-custom-options { display: none; position: relative !important; z-index: 100 !important; flex-direction: column !important; background: rgba(15,23,42,0.98) !important; border: 1px solid rgba(255,255,255,.2) !important; border-radius: 8px !important; max-height: 160px !important; overflow-y: auto !important; margin-top: 4px !important; } 
        .h-custom-select.is-open .h-custom-options { display: flex !important; } 
        .h-custom-opt { padding: 6px 10px !important; color: #cbd5e1 !important; font-size: 10px !important; cursor: pointer !important; border-bottom: 1px solid rgba(255,255,255,.05) !important; } 
        .h-custom-opt:hover, .h-custom-opt.is-selected { background: rgba(56,189,248,.2) !important; color: #38bdf8 !important; font-weight: 700 !important; }
        
        .panel-header { font-weight: 800 !important; font-size: 11px !important; border-bottom: 1px solid rgba(255,255,255,.12) !important; padding-bottom: 6px !important; display: flex !important; justify-content: space-between !important; align-items: center !important; margin-bottom: 2px !important; color: #f8fafc !important; }
        .list-item { font-size: 10px !important; background: rgba(255,255,255,.04) !important; border: 1px solid rgba(255,255,255,.08) !important; border-radius: 6px !important; padding: 4px 6px !important; display: flex !important; justify-content: space-between !important; align-items: center !important; gap: 6px !important; } 
        .list-item span.rule-text { word-break: break-all !important; color: #e2e8f0 !important; font-family: monospace !important; font-size: 9px !important; flex: 1 !important; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; } 
        .hider-btn-small { cursor: pointer !important; border: none !important; border-radius: 4px !important; padding: 2px 6px !important; color: #fff !important; font-weight: 700 !important; font-size: 9px !important; height: 20px !important; display: flex; align-items: center; justify-content: center; } 
        `;
        const container = doc.createElement('div');
        container.innerHTML = `
        <div class="h-glass h-dock is-collapsed manual-hidden" id="hider-main-dock">
            <button class="h-dock-btn h-dock-main" id="btn-toggle-dock" title="Toggle Control Dock">🛡️</button>
            <div class="h-dock-menu" id="hider-dock-menu">
                <button class="h-dock-btn" id="btn-select" title="Target Element to Hide">🎯<span>Hide</span></button>
                <button class="h-dock-btn" id="btn-scope" title="Toggle Scope (Site/Page)">🌐<span>SITE</span></button>
                <button class="h-dock-btn" id="btn-reveal-quick" title="Reveal hidden/blurred elements">👁️<span>Reveal</span></button>
                <button class="h-dock-btn" id="btn-links" title="Extract all links from the page">🔗<span>Links</span></button>
                <button class="h-dock-btn" id="btn-skip-30" title="Skip 30 seconds forward">⏩<span>+30s</span></button>
                <button class="h-dock-btn ${isFrozen?'is-frozen':''}" id="btn-freeze" title="Toggle Navigation Freeze">❄️<span>Freeze</span></button>
                <button class="h-dock-btn" id="btn-manage" title="Open Control Panel">⚙️<span>Menu</span></button>
            </div>
        </div>

        <!-- Control Panel (two-column layout) -->
        <div id="hider-panel" class="h-glass">
            <div class="panel-header">
                <span class="title">🛡️ Hide Web Elements Pro</span>
                <button class="close-btn" id="close-p">✖</button>
            </div>
            <div class="panel-body">
                <div class="panel-sidebar" id="panel-sidebar"></div>
                <div class="panel-content" id="panel-content"></div>
            </div>
        </div>`;

        shadowRoot.innerHTML = ''; shadowRoot.appendChild(style); shadowRoot.appendChild(container);
        buildPanelTabs();
        setupShadowUIEvents();
        applyDockButtonVisibility();
        renderDockButtonOptions();

        // ---- ISOLATE PANEL EVENTS FROM MAIN PAGE ----
        const panel = shadowRoot.getElementById('hider-panel');
        if (panel) {
            const stopProp = (e) => e.stopPropagation();
            panel.addEventListener('wheel', stopProp, { passive: true, capture: true });
            panel.addEventListener('touchmove', stopProp, { passive: true, capture: true });
            panel.addEventListener('scroll', stopProp, { passive: true, capture: true });
            panel.addEventListener('pointerdown', stopProp, { capture: true });
            panel.addEventListener('mousedown', stopProp, { capture: true });
        }
        const linkPanel = shadowRoot.getElementById('hider-link-panel');
        if (linkPanel) {
            const stopProp = (e) => e.stopPropagation();
            linkPanel.addEventListener('wheel', stopProp, { passive: true, capture: true });
            linkPanel.addEventListener('touchmove', stopProp, { passive: true, capture: true });
            linkPanel.addEventListener('scroll', stopProp, { passive: true, capture: true });
            linkPanel.addEventListener('pointerdown', stopProp, { capture: true });
            linkPanel.addEventListener('mousedown', stopProp, { capture: true });
        }
        const stepper = shadowRoot.getElementById(STEPPER_BAR_ID);
        if (stepper) {
            const stopProp = (e) => e.stopPropagation();
            stepper.addEventListener('wheel', stopProp, { passive: true, capture: true });
            stepper.addEventListener('touchmove', stopProp, { passive: true, capture: true });
            stepper.addEventListener('pointerdown', stopProp, { capture: true });
        }
    }

    // ---------- Build Panel Tabs ----------
    function buildPanelTabs() {
        const sidebar = shadowBy('panel-sidebar');
        const content = shadowBy('panel-content');
        if (!sidebar || !content) return;

        const tabs = [
            { id: 'tab-tools', label: '🛠️ Tools', html: `
                <div style="display:flex;flex-direction:column;gap:4px;">
                    <label style="font-size:10px;color:#cbd5e1;display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;">
                        <input type="checkbox" id="chk-auto-scroll" ${CACHE.autoScroll?'checked':''} style="accent-color:#38bdf8;"> Auto Anti‑Scroll Lock
                    </label>
                    <label style="font-size:10px;color:#cbd5e1;display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;">
                        <input type="checkbox" id="chk-enable-contextmenu" ${CACHE.enableContextMenu?'checked':''} style="accent-color:#38bdf8;"> Auto Right‑Click / Long‑Press
                    </label>
                    <label style="font-size:10px;color:#cbd5e1;display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;">
                        <input type="checkbox" id="chk-auto-remove-blur" ${CACHE.autoRemoveBlur?'checked':''} style="accent-color:#38bdf8;"> Auto Remove Blur
                    </label>
                    <label style="font-size:10px;color:#cbd5e1;display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;margin-top:4px;">
                        <input type="checkbox" id="chk-auto-time-skipper" ${CACHE.autoTimeSkipper?'checked':''} style="accent-color:#f59e0b;"> Auto Time Skipper
                    </label>
                    <!-- Rule-breaker toggles -->
                    <label style="font-size:10px;color:#cbd5e1;display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;margin-top:4px;border-top:1px solid rgba(255,255,255,0.06);padding-top:4px;">
                        <input type="checkbox" id="chk-anti-paywall" ${CACHE.antiPaywall?'checked':''} style="accent-color:#f59e0b;"> Anti‑Paywall / Anti‑Adblock
                    </label>
                    <label style="font-size:10px;color:#cbd5e1;display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;">
                        <input type="checkbox" id="chk-auto-close-modals" ${CACHE.autoCloseModals?'checked':''} style="accent-color:#f59e0b;"> Auto‑Close Modals & Overlays
                    </label>
                    <div style="display:flex;align-items:center;gap:6px;margin-top:2px;">
                        <span style="font-size:10px;color:#94a3b8;">🍪 Cookie Consent:</span>
                        <select id="cookie-consent-mode" style="background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.14);border-radius:6px;color:#fff;padding:2px 6px;font-size:9px;height:22px;flex:1;">
                            <option value="ask" ${CACHE.cookieConsentMode === 'ask' ? 'selected' : ''}>Ask</option>
                            <option value="accept" ${CACHE.cookieConsentMode === 'accept' ? 'selected' : ''}>Accept</option>
                            <option value="reject" ${CACHE.cookieConsentMode === 'reject' ? 'selected' : ''}>Reject</option>
                        </select>
                    </div>
                    <div style="margin-top:4px;border-top:1px solid rgba(255,255,255,0.06);padding-top:4px;">
                        <div style="font-size:10px;color:#94a3b8;margin-bottom:2px;">❄️ Freeze Behaviour</div>
                        <div class="h-custom-select" id="freeze-custom-panel-dropdown">
                            <div class="h-custom-trigger"><span class="h-custom-value-text">${FREEZE_LABELS[CACHE.freezeMemory] || FREEZE_LABELS['ask']}</span><span class="h-custom-arrow">▼</span></div>
                            <div class="h-custom-options">
                                <div class="h-custom-opt" data-val="ask">❓ Ask Every Time</div>
                                <div class="h-custom-opt" data-val="block_all">⛔ Auto‑Block All</div>
                                <div class="h-custom-opt" data-val="allow_same">🔗 Allow Same Domain Only</div>
                                <div class="h-custom-opt" data-val="allow_all">🟢 Allow All</div>
                            </div>
                        </div>
                        <button id="btn-reset-block-confirm" class="hider-btn-small" style="background:rgba(255,255,255,0.06);color:#cbd5e1;margin-top:4px;width:100%;padding:4px;height:auto;font-size:9px;">Reset "Don't Ask Block" Prompt</button>
                        <button id="btn-undo-hide" class="hider-btn-small" style="background:rgba(255,255,255,0.06);color:#cbd5e1;margin-top:4px;width:100%;padding:4px;height:auto;font-size:9px;">↩️ Undo Last Hide</button>
                    </div>
                    <div style="margin-top:4px;border-top:1px solid rgba(255,255,255,0.06);padding-top:4px;">
                        <div style="font-size:10px;color:#94a3b8;margin-bottom:2px;">🔘 Dock Button Visibility</div>
                        <div id="dock-buttons-list" style="display:flex;flex-direction:column;gap:4px;"></div>
                    </div>
                </div>
            ` },
            { id: 'tab-rules', label: '✏️ Rules', html: `
                <div style="display:flex;flex-direction:column;gap:4px;">
                    <div style="display:flex;gap:4px;">
                        <input type="text" id="manual-rule-input" placeholder="CSS Selector (e.g. .ad-banner)" class="h-select" style="flex:1;">
                        <input type="text" id="manual-target-input" placeholder="Target Domain (* Global)" class="h-select" style="flex:1;">
                        <button class="hider-btn-small btn-blue" id="save-rule-btn" style="height:28px;padding:0 8px;">Save</button>
                    </div>
                    <!-- Bulk Add -->
                    <div style="display:flex;gap:4px;margin-top:2px;">
                        <textarea id="bulk-rules-input" placeholder="Paste multiple selectors (one per line)" style="flex:1;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);border-radius:6px;color:#fff;padding:4px 6px;font-size:9px;height:40px;resize:vertical;"></textarea>
                        <button class="hider-btn-small btn-purple" id="bulk-add-rules" style="height:40px;padding:0 8px;">➕ Bulk Add</button>
                    </div>
                    <div style="display:flex;flex-direction:column;gap:4px;">
                        <div style="display:flex;justify-content:space-between;font-size:10px;color:#94a3b8;">
                            <span>Custom Rules (<span id="cnt-custom">0</span>)</span>
                            <button class="hider-btn-small btn-red" id="clear-custom-rules" style="font-size:8px;padding:1px 5px;height:18px;">Clear All</button>
                        </div>
                        <div id="list-custom-rules" style="display:flex;flex-direction:column;gap:3px;"></div>
                    </div>
                    <div style="border-top:1px solid rgba(255,255,255,0.06);padding-top:4px;">
                        <div style="display:flex;justify-content:space-between;font-size:10px;color:#94a3b8;">
                            <span>🌐 Site‑Wide (<span id="cnt-site">0</span>)</span>
                            <button class="hider-btn-small btn-red" id="clear-site-rules" style="font-size:8px;padding:1px 5px;height:18px;">Clear All</button>
                        </div>
                        <div id="list-site" style="display:flex;flex-direction:column;gap:3px;"></div>
                    </div>
                    <div style="border-top:1px solid rgba(255,255,255,0.06);padding-top:4px;">
                        <div style="display:flex;justify-content:space-between;font-size:10px;color:#94a3b8;">
                            <span>📄 Page‑Only (<span id="cnt-link">0</span>)</span>
                            <button class="hider-btn-small btn-red" id="clear-page-rules" style="font-size:8px;padding:1px 5px;height:18px;">Clear All</button>
                        </div>
                        <div id="list-link" style="display:flex;flex-direction:column;gap:3px;"></div>
                    </div>
                </div>
            ` },
            { id: 'tab-domains', label: '🌐 Domains', html: `
                <div style="display:flex;flex-direction:column;gap:6px;">
                    <div style="display:flex;gap:4px;">
                        <input type="text" id="manual-domain-input" placeholder="Block domain (e.g. bad.com)" class="h-select" style="flex:1;">
                        <button class="hider-btn-small btn-red" id="add-domain-btn" style="height:28px;padding:0 8px;">Block</button>
                    </div>
                    <div>
                        <div style="font-size:10px;color:#f87171;font-weight:700;margin-bottom:2px;">🚫 Blocked Domains</div>
                        <div id="list-blocked-domains" style="display:flex;flex-direction:column;gap:3px;"></div>
                    </div>
                    <div style="border-top:1px solid rgba(255,255,255,0.06);padding-top:6px;">
                        <div style="display:flex;gap:4px;">
                            <input type="text" id="manual-allowed-domain-input" placeholder="Allow domain (e.g. trusted.com)" class="h-select" style="flex:1;">
                            <button class="hider-btn-small btn-green" id="add-allowed-domain-btn" style="height:28px;padding:0 8px;">Allow</button>
                        </div>
                        <div>
                            <div style="font-size:10px;color:#34d399;font-weight:700;margin-top:4px;margin-bottom:2px;">🟢 Allowed Domains</div>
                            <div id="list-allowed-domains" style="display:flex;flex-direction:column;gap:3px;"></div>
                        </div>
                    </div>
                </div>
            ` },
            { id: 'tab-logs', label: '📋 Logs', html: `
                <div style="display:flex;justify-content:space-between;align-items:center;">
                    <span style="font-size:10px;color:#94a3b8;">Blocked (<span id="cnt-logs">0</span>)</span>
                    <button class="hider-btn-small btn-gray" id="clear-log-btn" style="font-size:8px;padding:1px 5px;height:18px;">Clear</button>
                </div>
                <div id="list-blocked-log" style="display:flex;flex-direction:column;gap:3px;margin-top:4px;"></div>
            ` },
            { id: 'tab-export', label: '💾 Export', html: `
                <div style="display:flex;gap:4px;flex-wrap:wrap;align-items:center;">
                    <button class="hider-btn-small btn-blue" id="btn-export-settings" style="flex:1;min-width:70px;height:26px;">📤 Export All</button>
                    <button class="hider-btn-small btn-green" id="btn-import-settings" style="flex:1;min-width:70px;height:26px;">📥 Import All</button>
                    <input type="file" id="import-file-input" accept=".json" style="display:none;">
                </div>
                <div style="font-size:9px;color:#94a3b8;margin-top:4px;">Export/Import all settings (rules, domains, toggles, logs).</div>
                <div style="margin-top:8px;border-top:1px solid rgba(255,255,255,0.06);padding-top:6px;">
                    <div style="font-size:10px;color:#94a3b8;margin-bottom:4px;">🍪 Cookie Manager</div>
                    <div style="display:flex;gap:4px;margin-bottom:4px;">
                        <button class="hider-btn-small btn-blue" id="cookie-refresh" style="flex:1;height:24px;">🔄 Refresh</button>
                        <button class="hider-btn-small btn-green" id="cookie-export" style="flex:1;height:24px;">📤 Export</button>
                        <button class="hider-btn-small btn-purple" id="cookie-import" style="flex:1;height:24px;">📥 Import</button>
                        <input type="file" id="cookie-import-file" accept=".json" style="display:none;">
                    </div>
                    <div style="display:flex;gap:4px;margin-bottom:4px;">
                        <input type="text" id="cookie-new-name" placeholder="name" style="flex:1;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);border-radius:6px;color:#fff;padding:2px 6px;font-size:9px;height:22px;">
                        <input type="text" id="cookie-new-value" placeholder="value" style="flex:1;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);border-radius:6px;color:#fff;padding:2px 6px;font-size:9px;height:22px;">
                        <button class="hider-btn-small btn-green" id="cookie-add" style="height:22px;padding:0 8px;">Add</button>
                    </div>
                    <div id="cookie-list" style="display:flex;flex-direction:column;gap:3px;max-height:180px;overflow-y:auto;"></div>
                </div>
            ` },
            { id: 'tab-about', label: 'ℹ️ About', html: `
                <div style="font-size:10px;color:#cbd5e1;line-height:1.6;padding:4px 0;">
                    <h3 style="font-size:11px;font-weight:800;color:#f8fafc;margin:0 0 6px 0;">🛡️ Hide Web Elements Pro</h3>
                    <p> A powerful element hider with advanced navigation control, media extraction, and automatic challenge protection.</p>
                    
                    <h4 style="font-size:10px;font-weight:700;color:#94a3b8;margin:8px 0 4px 0;">✨ Core Features</h4>
                    <ul style="margin:0;padding-left:16px;">
                        <li><strong>🎯 Hide</strong> – Click any element to hide it (site‑wide, page‑only, or global).</li>
                        <li><strong>❄️ Freeze</strong> – Block or allow navigation popups/redirects with fine‑grained rules.</li>
                        <li><strong>🔗 Link Extractor</strong> – Scan the page for all links, with media preview and download.</li>
                        <li><strong>⏩ Time Skipper</strong> – Jump forward 30 seconds on videos/audio and skip timers.</li>
                        <li><strong>👁️ Reveal</strong> – Unhide hidden/blurred elements (overlays, modals, etc.).</li>
                        <li><strong>📥 Media Downloader</strong> – Direct download of images, videos, and audio from extracted links.</li>
                        <li><strong>🛡️ Automatic Protection</strong> – Detects Cloudflare/challenge pages and temporarily disables features to avoid interference.</li>
                        <li><strong>🚫 Anti‑Paywall</strong> – Removes paywall and adblock overlays automatically.</li>
                        <li><strong>🗑️ Auto‑Close Modals</strong> – Dismisses cookie banners, newsletters, and popups.</li>
                        <li><strong>🍪 Cookie Bypass</strong> – Accepts or rejects cookies automatically based on your choice.</li>
                    </ul>

                    <h4 style="font-size:10px;font-weight:700;color:#94a3b8;margin:8px 0 4px 0;">🔒 Protection Logic</h4>
                    <p>The script automatically pauses all hiding/freezing/scroll‑override features when it detects a Cloudflare challenge, "Just a moment..." page, or other anti‑bot screens. This ensures that the script never interferes with the challenge process. Once the page loads normally, features resume instantly.</p>

                    <h4 style="font-size:10px;font-weight:700;color:#94a3b8;margin:8px 0 4px 0;">💾 Persistent Storage</h4>
                    <p>All rules, domains, freeze settings, and logs are saved locally (via GM_setValue or localStorage). Your customisations persist across browser restarts and site visits.</p>

                    <h4 style="font-size:10px;font-weight:700;color:#94a3b8;margin:8px 0 4px 0;">⌨️ Keyboard Shortcuts</h4>
                    <ul style="margin:0;padding-left:16px;">
                        <li><kbd>Esc</kbd> – Cancel selection mode / close panels.</li>
                        <li><kbd>Ctrl+Click</kbd> / <kbd>Middle‑click</kbd> – Bypass freeze for that link.</li>
                    </ul>

                    <p style="margin-top:8px;font-size:9px;color:#64748b;">Made with ❤️ by KTZ • Open Source under MIT</p>
                </div>
            ` }
        ];

        tabs.forEach((tab, index) => {
            const btn = document.createElement('button');
            btn.className = 'tab-btn' + (index === 0 ? ' active' : '');
            btn.dataset.tab = tab.id;
            btn.textContent = tab.label;
            btn.title = tab.label;
            sidebar.appendChild(btn);

            const contentDiv = document.createElement('div');
            contentDiv.className = 'tab-content' + (index === 0 ? ' active' : '');
            contentDiv.id = tab.id;
            contentDiv.innerHTML = tab.html;
            content.appendChild(contentDiv);
        });

        sidebar.addEventListener('click', (e) => {
            const btn = e.target.closest('.tab-btn');
            if (!btn) return;
            const tabId = btn.dataset.tab;
            sidebar.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
            content.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
            btn.classList.add('active');
            const contentDiv = content.querySelector('#' + tabId);
            if (contentDiv) contentDiv.classList.add('active');
        });
    }

    // ---------- Shadow UI Events ----------
    function setupShadowUIEvents() {
        shadowBy('close-p').onclick = e => { if (e) { e.stopPropagation(); e.preventDefault(); } turnOffHideMode(); closeAllMenus(e, true); };

        setupCustomDropdown(shadowBy('freeze-custom-panel-dropdown'), CACHE.freezeMemory, val => {
            CACHE.freezeMemory = val; sv('hider_freeze_memory', val);
            const label = FREEZE_LABELS[val] || val;
            if (val === 'allow_all') { disableFreezeMode(); showToast(`🟢 Freeze Mode Disabled (Allow All)`); } 
            else showToast(`❄️ Memory updated: ${label}`);
        });

        shadowBy('btn-reset-block-confirm').onclick = () => { sv('hider_skip_block_confirm', false); showToast('🔄 Reset Block Domain confirmation!'); };
        shadowBy('btn-undo-hide').onclick = undoLastHide;

        // Rule-breaker toggles
        const chkPaywall = shadowBy('chk-anti-paywall');
        if (chkPaywall) {
            chkPaywall.onchange = e => {
                CACHE.antiPaywall = e.target.checked;
                sv('hider_anti_paywall', CACHE.antiPaywall);
                applyAllSettings();
                showToast(`🚫 Anti-Paywall: ${CACHE.antiPaywall ? 'ON' : 'OFF'}`);
            };
        }

        const chkModal = shadowBy('chk-auto-close-modals');
        if (chkModal) {
            chkModal.onchange = e => {
                CACHE.autoCloseModals = e.target.checked;
                sv('hider_auto_close_modals', CACHE.autoCloseModals);
                applyAllSettings();
                showToast(`🗑️ Auto-Close Modals: ${CACHE.autoCloseModals ? 'ON' : 'OFF'}`);
            };
        }

        const cookieMode = shadowBy('cookie-consent-mode');
        if (cookieMode) {
            cookieMode.onchange = e => {
                CACHE.cookieConsentMode = e.target.value;
                sv('hider_cookie_consent_mode', CACHE.cookieConsentMode);
                applyAllSettings();
                showToast(`🍪 Cookie mode: ${CACHE.cookieConsentMode === 'accept' ? 'Accept' : CACHE.cookieConsentMode === 'reject' ? 'Reject' : 'Ask'}`);
            };
        }

        const chkScroll = shadowBy('chk-auto-scroll');
        if (chkScroll) {
            chkScroll.onchange = e => {
                CACHE.autoScroll = e.target.checked;
                sv('hider_auto_scroll', CACHE.autoScroll);
                if (CACHE.autoScroll) {
                    startScrollDefeater();
                    showToast('🔓 Auto Anti-Scroll Lock enabled');
                } else {
                    stopScrollDefeater();
                    showToast('🔒 Auto Anti-Scroll Lock disabled');
                }
            };
        }

        const chkContext = shadowBy('chk-enable-contextmenu');
        if (chkContext) {
            chkContext.onchange = e => {
                CACHE.enableContextMenu = e.target.checked;
                sv('hider_enable_contextmenu', CACHE.enableContextMenu);
                updateContextMenuStyles();
                showToast(`🖱️ Auto Right-Click/Long-Press: ${CACHE.enableContextMenu ? 'ON' : 'OFF'}`);
            };
        }

        const chkBlur = shadowBy('chk-auto-remove-blur');
        if (chkBlur) {
            chkBlur.onchange = e => {
                CACHE.autoRemoveBlur = e.target.checked;
                sv('hider_auto_remove_blur', CACHE.autoRemoveBlur);
                if (CACHE.autoRemoveBlur) {
                    scheduleBlurRemoval();
                    showToast('👁️ Auto Remove Blur enabled (aggressive)');
                } else {
                    stopBlurRemoval();
                    showToast('👁️ Auto Remove Blur disabled');
                }
            };
        }

        const autoSkipChk = shadowBy('chk-auto-time-skipper');
        if (autoSkipChk) {
            autoSkipChk.onchange = e => {
                CACHE.autoTimeSkipper = e.target.checked;
                sv('hider_auto_time_skipper', CACHE.autoTimeSkipper);
                if (CACHE.autoTimeSkipper) {
                    autoSkipTimers();
                    showToast('⏩ Auto Time Skipper enabled');
                } else {
                    showToast('⏩ Auto Time Skipper disabled');
                }
            };
        }

        const dockEl = shadowBy('hider-main-dock'), mainBtn = shadowBy('btn-toggle-dock');
        const savedY = gv('hider_dock_y', null); if (savedY) dockEl.style.top = savedY;
        dockEl.addEventListener('mouseleave', () => dockEl.classList.remove('manual-hidden'));

        let dockStartX, dockStartY, dockInitY, dockMoved = false;
        const onDockMove = e => {
            if (!isDraggingDock) return;
            const p = e.touches ? e.touches[0] : e, dy = p.clientY - dockStartY;
            if (Math.hypot(p.clientX - dockStartX, dy) > 8) {
                dockMoved = true; if (e.cancelable) e.preventDefault();
                dockEl.style.top = `${Math.max(0, Math.min(dockInitY + dy, win.innerHeight - dockEl.offsetHeight))}px`;
            }
        };

        const onDockEnd = () => {
            if (isDraggingDock) { isDraggingDock = false; dockEl.style.transition = ''; if (dockMoved) sv('hider_dock_y', dockEl.style.top); }
            win.removeEventListener('mousemove', onDockMove); win.removeEventListener('mouseup', onDockEnd);
            win.removeEventListener('touchmove', onDockMove); win.removeEventListener('touchend', onDockEnd); win.removeEventListener('touchcancel', onDockEnd);
        };

        const onDockStart = e => {
            if (e.target.tagName === 'BUTTON' && e.target.id !== 'btn-toggle-dock') return;
            const p = e.touches ? e.touches[0] : e;
            dockStartX = p.clientX; dockStartY = p.clientY; dockInitY = dockEl.getBoundingClientRect().top;
            isDraggingDock = true; dockMoved = false; dockEl.style.transition = 'none';
            win.addEventListener('mousemove', onDockMove, { passive: false }); win.addEventListener('mouseup', onDockEnd);
            win.addEventListener('touchmove', onDockMove, { passive: false }); win.addEventListener('touchend', onDockEnd); win.addEventListener('touchcancel', onDockEnd);
        };
        mainBtn.addEventListener('mousedown', onDockStart, { passive: false });
        mainBtn.addEventListener('touchstart', onDockStart, { passive: false });

        mainBtn.onclick = e => {
            e.stopPropagation(); if (dockMoved) { dockMoved = false; return; }
            if (timers.collapseTimer) { clearTimeout(timers.collapseTimer); timers.collapseTimer = null; }
            const menu = shadowBy('hider-dock-menu'), isOpening = !menu.classList.contains('is-open');
            
            menu.classList.toggle('is-open', isOpening); 
            mainBtn.classList.toggle('expanded', isOpening); 
            dockEl.classList.toggle('expanded', isOpening); 
            dockEl.classList.toggle('is-collapsed', !isOpening);

            if (!isOpening) {
                turnOffHideMode(); 
                const panel = shadowBy('hider-panel');
                if (panel.classList.contains('is-visible')) { panel.classList.remove('is-visible'); setTimeout(()=> panel.style.display='none', 300); }
                shadowBy('btn-manage')?.classList.remove('active'); 
                dockEl.classList.add('manual-hidden');
                timers.collapseTimer = setTimeout(() => { dockEl.classList.add('is-collapsed'); timers.collapseTimer = null; }, 1000);
            } else dockEl.classList.remove('manual-hidden');
        };

        shadowBy('btn-reveal-quick').onclick = (e) => {
            e.stopPropagation();
            revealHiddenElements();
        };

        shadowBy('btn-links').onclick = (e) => {
            e.stopPropagation();
            toggleLinkPanel();
        };

        shadowBy('btn-skip-30').onclick = (e) => {
            e.stopPropagation();
            skip30Seconds();
        };

        // Bulk add rules
        shadowBy('bulk-add-rules').onclick = () => {
            const textarea = shadowBy('bulk-rules-input');
            if (!textarea) return;
            const selectors = textarea.value.split('\n').map(s => s.trim()).filter(s => s.length > 0);
            if (selectors.length === 0) { showToast('⚠️ Enter at least one selector'); return; }
            let added = 0;
            selectors.forEach(sel => {
                // Ensure selector doesn't target body/html
                if (sel.match(/^(html|body)/i)) {
                    showToast('⚠️ Skipping selector targeting body/html');
                    return;
                }
                const rule = { id: 'rule_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4), selector: sel, target: '*' };
                CACHE.customRules.push(rule);
                added++;
            });
            sv('hider_custom_rules_v4', CACHE.customRules);
            textarea.value = '';
            requestUpdateStyles();
            renderList();
            showToast(`➕ Added ${added} global rules`);
        };

        shadowBy('save-rule-btn').onclick = () => {
            const ruleInput = shadowBy('manual-rule-input'), targetInput = shadowBy('manual-target-input'), sel = (ruleInput.value || '').trim(), target = cleanDomain(targetInput.value) || '*';
            if (!sel) { showToast('⚠️ Enter a selector'); return; }
            if (sel.match(/^(html|body)/i)) { showToast('⚠️ Cannot hide body or html'); return; }
            if (editingRuleId) {
                const idx = CACHE.customRules.findIndex(r => r.id === editingRuleId);
                if (idx !== -1) { CACHE.customRules[idx] = { id: editingRuleId, selector: sel, target: target }; showToast('✏️ Rule updated'); }
                editingRuleId = null; shadowBy('save-rule-btn').textContent = 'Save';
            } else { CACHE.customRules.push({ id: 'rule_' + Date.now(), selector: sel, target: target }); showToast('✨ Custom Rule Added!'); }
            sv('hider_custom_rules_v4', CACHE.customRules); ruleInput.value = ''; targetInput.value = ''; requestUpdateStyles(); renderList();
        };

        const addAllowedDomain = () => {
            const input = shadowBy('manual-allowed-domain-input'), d = cleanDomain(input.value);
            if (d && !CACHE.allowedDomainsSet.has(d)) { CACHE.allowedDomainsList.push(d); CACHE.allowedDomainsSet.add(d); sv('hider_allowed_domains', CACHE.allowedDomainsList); showToast(`🟢 Allowed: ${d}`); }
            input.value = ''; renderList();
        };
        shadowBy('add-allowed-domain-btn').onclick = addAllowedDomain; shadowBy('manual-allowed-domain-input').onkeypress = e => e.key === 'Enter' && addAllowedDomain();

        const addDomain = () => {
            const input = shadowBy('manual-domain-input'), d = cleanDomain(input.value);
            if (d && !CACHE.blockedDomainsSet.has(d)) { CACHE.blockedDomainsList.push(d); CACHE.blockedDomainsSet.add(d); sv('hider_blocked_domains', CACHE.blockedDomainsList); showToast(`🚫 Blocked: ${d}`); }
            input.value = ''; renderList();
        };
        shadowBy('add-domain-btn').onclick = addDomain; shadowBy('manual-domain-input').onkeypress = e => e.key === 'Enter' && addDomain();

        shadowBy('btn-select').onclick = e => {
            e.stopPropagation(); isSelecting = !isSelecting; e.currentTarget.classList.toggle('active', isSelecting);
            const p = shadowBy('hider-panel');
            if (isSelecting) { 
                if(p.classList.contains('is-visible')) { p.classList.remove('is-visible'); setTimeout(()=> p.style.display='none', 300); } shadowBy('btn-manage').classList.remove('active'); 
                showToast('🎯 Selection mode ON – Click element to hide (or use Global)');
            } else {
                clearSelectionState();
                showToast('🎯 Selection mode OFF');
            }
            broadcastState();
        };

        const btnScope = shadowBy('btn-scope');
        btnScope.onclick = e => {
            e.stopPropagation(); currentScope = currentScope === 'site' ? 'link' : 'site'; btnScope.querySelector('span').textContent = currentScope.toUpperCase();
            btnScope.classList.toggle('scope-link', currentScope === 'link'); 
            const label = currentScope === 'site' ? '🌐 Site-wide' : '📄 Page-only';
            showToast(`Scope: ${label}`); broadcastState();
        };

        const btnFreeze = shadowBy('btn-freeze');
        btnFreeze.onclick = e => {
            e.stopPropagation(); isFrozen = !isFrozen; CACHE.isFrozen = isFrozen; sv('hider_freeze_global', isFrozen);
            if (isFrozen && CACHE.freezeMemory === 'allow_all') { CACHE.freezeMemory = 'ask'; sv('hider_freeze_memory', 'ask'); }
            btnFreeze.classList.toggle('is-frozen', isFrozen); if (isFrozen) triggerFreezeFx(); 
            showToast(isFrozen ? '🥶 Freeze ON' : '🔥 Freeze OFF'); broadcastState();
        };

        shadowBy('btn-manage').onclick = e => {
            e.stopPropagation(); const p = shadowBy('hider-panel'), isHidden = p.style.display === 'none' || p.style.display === '';
            
            if (isHidden) {
                p.style.display = 'flex';
                void p.offsetWidth;
                p.classList.add('is-visible');
                e.currentTarget.classList.add('active');
                turnOffHideMode(); renderList();
            } else {
                p.classList.remove('is-visible');
                setTimeout(() => p.style.display = 'none', 300);
                e.currentTarget.classList.remove('active');
            }
        };

        shadowBy('clear-log-btn').onclick = e => { if (e) e.stopPropagation(); CACHE.logs = []; sv('hider_global_logs', []); renderList(); showToast('🧹 Logs cleared'); };

        // Clear All Rules
        shadowBy('clear-custom-rules').onclick = () => {
            if (confirm('Delete all custom rules?')) {
                CACHE.customRules = [];
                sv('hider_custom_rules_v4', CACHE.customRules);
                renderList(); requestUpdateStyles();
                showToast('🧹 Custom rules cleared');
            }
        };
        shadowBy('clear-site-rules').onclick = () => {
            const key = 'hider_site_' + location.hostname;
            if (confirm('Delete all site-wide rules?')) {
                sv(key, []);
                renderList(); requestUpdateStyles();
                showToast('🧹 Site rules cleared');
            }
        };
        shadowBy('clear-page-rules').onclick = () => {
            const key = 'hider_link_' + cleanUrl();
            if (confirm('Delete all page-only rules?')) {
                sv(key, []);
                renderList(); requestUpdateStyles();
                showToast('🧹 Page rules cleared');
            }
        };

        // Export/Import
        const exportBtn = shadowBy('btn-export-settings');
        const importBtn = shadowBy('btn-import-settings');
        const fileInput = shadowBy('import-file-input');
        if (exportBtn) exportBtn.onclick = () => {
            const data = getAllSettings();
            const json = JSON.stringify(data, null, 2);
            const blob = new Blob([json], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `hider_backup_${new Date().toISOString().slice(0,10)}.json`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            showToast('📤 Settings exported');
        };
        if (importBtn) importBtn.onclick = () => fileInput?.click();
        if (fileInput) {
            fileInput.onchange = function() {
                if (this.files && this.files[0]) {
                    const reader = new FileReader();
                    reader.onload = function(e) {
                        try {
                            const data = JSON.parse(e.target.result);
                            let count = 0;
                            for (const [key, val] of Object.entries(data)) {
                                if (key.startsWith('hider_')) {
                                    sv(key, val);
                                    count++;
                                }
                            }
                            syncCache();
                            requestUpdateStyles();
                            renderList();
                            applyDockButtonVisibility();
                            showToast(`📥 Imported ${count} settings`);
                        } catch (err) {
                            showToast('❌ Invalid JSON file');
                        }
                    };
                    reader.readAsText(this.files[0]);
                    this.value = '';
                }
            };
        }

        // Cookie Manager
        const cookieRefresh = shadowBy('cookie-refresh');
        const cookieExport = shadowBy('cookie-export');
        const cookieImport = shadowBy('cookie-import');
        const cookieFileInput = shadowBy('cookie-import-file');
        const cookieAdd = shadowBy('cookie-add');
        const cookieName = shadowBy('cookie-new-name');
        const cookieValue = shadowBy('cookie-new-value');

        function getCookies() {
            return document.cookie.split(';').map(c => c.trim()).filter(Boolean).map(c => {
                const eq = c.indexOf('=');
                return { name: c.slice(0, eq), value: c.slice(eq + 1) };
            });
        }

        function renderCookies() {
            const list = shadowBy('cookie-list');
            if (!list) return;
            const cookies = getCookies();
            if (cookies.length === 0) {
                list.innerHTML = '<div style="font-size:9px;color:#94a3b8;text-align:center;padding:4px;">No cookies for this domain.</div>';
                return;
            }
            list.innerHTML = '';
            cookies.forEach((c, idx) => {
                const row = document.createElement('div');
                row.style.cssText = 'display:flex;align-items:center;gap:4px;font-size:9px;padding:2px 4px;background:rgba(255,255,255,.04);border-radius:4px;';
                const nameSpan = document.createElement('span');
                nameSpan.textContent = c.name;
                nameSpan.style.cssText = 'font-weight:700;color:#38bdf8;min-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
                const valSpan = document.createElement('span');
                valSpan.textContent = c.value;
                valSpan.style.cssText = 'flex:1;color:#e2e8f0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
                const btnGroup = document.createElement('div');
                btnGroup.style.cssText = 'display:flex;gap:2px;flex-shrink:0;';
                const editBtn = document.createElement('button');
                editBtn.className = 'hider-btn-small btn-blue';
                editBtn.textContent = '✏️';
                editBtn.style.cssText = 'padding:0 4px;height:16px;font-size:7px;';
                editBtn.onclick = function(e) {
                    e.stopPropagation();
                    const newVal = prompt(`Edit value for "${c.name}":`, c.value);
                    if (newVal !== null) {
                        document.cookie = `${c.name}=${newVal}; path=/; domain=${location.hostname}`;
                        renderCookies();
                        showToast(`🍪 Updated cookie: ${c.name}`);
                    }
                };
                const delBtn = document.createElement('button');
                delBtn.className = 'hider-btn-small btn-red';
                delBtn.textContent = '✖';
                delBtn.style.cssText = 'padding:0 4px;height:16px;font-size:7px;';
                delBtn.onclick = function(e) {
                    e.stopPropagation();
                    if (confirm(`Delete cookie "${c.name}"?`)) {
                        document.cookie = `${c.name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${location.hostname}`;
                        renderCookies();
                        showToast(`🍪 Deleted cookie: ${c.name}`);
                    }
                };
                btnGroup.appendChild(editBtn);
                btnGroup.appendChild(delBtn);
                row.appendChild(nameSpan);
                row.appendChild(valSpan);
                row.appendChild(btnGroup);
                list.appendChild(row);
            });
        }

        if (cookieAdd) {
            cookieAdd.onclick = function() {
                const name = cookieName ? cookieName.value.trim() : '';
                const value = cookieValue ? cookieValue.value.trim() : '';
                if (!name) { showToast('⚠️ Enter cookie name'); return; }
                document.cookie = `${name}=${value}; path=/; domain=${location.hostname}`;
                renderCookies();
                if (cookieName) cookieName.value = '';
                if (cookieValue) cookieValue.value = '';
                showToast(`🍪 Added cookie: ${name}`);
            };
        }
        if (cookieName) cookieName.onkeypress = e => e.key === 'Enter' && cookieAdd?.click();
        if (cookieValue) cookieValue.onkeypress = e => e.key === 'Enter' && cookieAdd?.click();
        if (cookieRefresh) cookieRefresh.onclick = renderCookies;
        if (cookieExport) {
            cookieExport.onclick = function() {
                const cookies = getCookies();
                const json = JSON.stringify(cookies, null, 2);
                const blob = new Blob([json], { type: 'application/json' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `cookies_${location.hostname}_${new Date().toISOString().slice(0,10)}.json`;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
                showToast('🍪 Cookies exported');
            };
        }
        if (cookieImport) cookieImport.onclick = () => cookieFileInput?.click();
        if (cookieFileInput) {
            cookieFileInput.onchange = function() {
                if (this.files && this.files[0]) {
                    const reader = new FileReader();
                    reader.onload = function(e) {
                        try {
                            const cookies = JSON.parse(e.target.result);
                            if (!Array.isArray(cookies)) throw new Error('Not an array');
                            cookies.forEach(c => {
                                if (c.name && c.value !== undefined) {
                                    document.cookie = `${c.name}=${c.value}; path=/; domain=${location.hostname}`;
                                }
                            });
                            renderCookies();
                            showToast(`🍪 Imported ${cookies.length} cookies`);
                        } catch (err) {
                            showToast('❌ Invalid cookie JSON');
                        }
                    };
                    reader.readAsText(this.files[0]);
                    this.value = '';
                }
            };
        }

        function getAllSettings() {
            const settings = {};
            const knownKeys = [
                'hider_freeze_memory', 'hider_freeze_global', 'hider_blocked_domains',
                'hider_allowed_domains', 'hider_custom_rules_v4', 'hider_auto_time_skipper',
                'hider_auto_scroll', 'hider_enable_contextmenu', 'hider_auto_remove_blur',
                'hider_hidden_dock_buttons', 'hider_global_logs',
                'hider_last_log_clear_day', 'hider_skip_block_confirm', 'hider_dock_y',
                'hider_anti_paywall', 'hider_auto_close_modals', 'hider_cookie_consent_mode'
            ];
            knownKeys.forEach(k => {
                const val = gv(k, undefined);
                if (val !== undefined) settings[k] = val;
            });
            try {
                for (let i = 0; i < localStorage.length; i++) {
                    const key = localStorage.key(i);
                    if (key && (key.startsWith('hider_site_') || key.startsWith('hider_link_'))) {
                        const val = localStorage.getItem(key);
                        try { settings[key] = JSON.parse(val); } catch { settings[key] = val; }
                    }
                }
            } catch {}
            return settings;
        }
    }

    // ---------- Render List ----------
    function renderList() {
        if (!shadowRoot) return;
        if (!CACHE.logs) CACHE.logs = gv('hider_global_logs', []);
        const siteKey = 'hider_site_' + location.hostname, linkKey = 'hider_link_' + cleanUrl();
        const siteData = gv(siteKey, []), linkData = gv(linkKey, []);

        const cCustom = shadowBy('list-custom-rules'), cAllowed = shadowBy('list-allowed-domains'), cDomains = shadowBy('list-blocked-domains'), cSite = shadowBy('list-site'), cLink = shadowBy('list-link'), cLog = shadowBy('list-blocked-log');
        if (!cSite || !cLink) return;

        ['cnt-custom', 'cnt-allowed', 'cnt-domains', 'cnt-logs', 'cnt-site', 'cnt-link'].forEach((id, i) => {
            const el = shadowBy(id); 
            if(el) el.textContent = [CACHE.customRules.length, CACHE.allowedDomainsList.length, CACHE.blockedDomainsList.length, CACHE.logs.length, siteData.length, linkData.length][i];
        });

        const buildFrag = (arr, emptyMsg, renderItem) => {
            const frag = doc.createDocumentFragment();
            if (!arr.length) { const d = doc.createElement('div'); d.style.cssText = 'font-size:9px!important;color:#94a3b8!important;padding:4px!important;text-align:center!important;border:1px dashed rgba(255,255,255,0.12)!important;border-radius:6px!important;'; d.textContent = emptyMsg; frag.appendChild(d); return frag; }
            arr.forEach((item, i) => frag.appendChild(renderItem(item, i))); return frag;
        };

        if (cCustom) {
            cCustom.innerHTML = '';
            cCustom.appendChild(buildFrag(CACHE.customRules, 'No custom rules', rule => {
                const div = doc.createElement('div'); div.className = 'list-item';
                div.innerHTML = `<span class="rule-text" title="${rule.selector}">${rule.selector} <span style="color:${rule.target === '*' ? '#38bdf8' : '#34d399'}!important; font-weight:bold!important;">[${rule.target}]</span></span><div style="display:flex;gap:2px"><button class="hider-btn-small btn-blue btn-edit">✏️</button><button class="hider-btn-small btn-red btn-del">✖</button></div>`;
                div.querySelector('.btn-edit').onclick = () => {
                    editingRuleId = rule.id; shadowBy('manual-rule-input').value = rule.selector; shadowBy('manual-target-input').value = rule.target; shadowBy('save-rule-btn').textContent = 'Update';
                    const sidebar = shadowBy('panel-sidebar');
                    const content = shadowBy('panel-content');
                    if (sidebar && content) {
                        const tabBtn = sidebar.querySelector('[data-tab="tab-rules"]');
                        if (tabBtn) tabBtn.click();
                    }
                };
                div.querySelector('.btn-del').onclick = () => { 
                    CACHE.customRules = CACHE.customRules.filter(r => r.id !== rule.id); 
                    sv('hider_custom_rules_v4', CACHE.customRules); 
                    requestUpdateStyles(); renderList(); 
                    showToast('🗑️ Rule removed');
                };
                return div;
            }));
        }

        if (cAllowed) {
            cAllowed.innerHTML = '';
            cAllowed.appendChild(buildFrag(CACHE.allowedDomainsList, 'No allowed domains', (d, i) => {
                const div = doc.createElement('div'); div.className = 'list-item'; div.innerHTML = `<span class="rule-text" title="${d}">${d}</span><button class="hider-btn-small btn-red">✖</button>`;
                div.querySelector('button').onclick = () => { 
                    CACHE.allowedDomainsList.splice(i, 1); 
                    CACHE.allowedDomainsSet.delete(cleanDomain(d)); 
                    sv('hider_allowed_domains', CACHE.allowedDomainsList); 
                    renderList(); 
                    showToast('🟢 Allowed domain removed');
                };
                return div;
            }));
        }

        if (cDomains) {
            cDomains.innerHTML = '';
            cDomains.appendChild(buildFrag(CACHE.blockedDomainsList, 'No blocked domains', (d, i) => {
                const div = doc.createElement('div'); div.className = 'list-item'; div.innerHTML = `<span class="rule-text" title="${d}">${d}</span><button class="hider-btn-small btn-red">✖</button>`;
                div.querySelector('button').onclick = () => { 
                    CACHE.blockedDomainsList.splice(i, 1); 
                    CACHE.blockedDomainsSet.delete(cleanDomain(d)); 
                    sv('hider_blocked_domains', CACHE.blockedDomainsList); 
                    renderList(); 
                    showToast('🚫 Blocked domain removed');
                };
                return div;
            }));
        }

        if (cLog) {
            cLog.innerHTML = '';
            cLog.appendChild(buildFrag(CACHE.logs, 'No logs today', item => {
                const row = doc.createElement('div'); row.style.cssText = 'font-size:9px!important;border-bottom:1px solid rgba(255,255,255,0.08)!important;padding:2px 0!important;';
                row.innerHTML = `<div style="display:flex;justify-content:space-between;color:#6ee7b7!important;font-weight:700!important;"><span>${item.type}</span><span style="color:#94a3b8!important;font-weight:normal!important;">${item.time}</span></div><div style="color:#cbd5e1!important;word-break:break-all!important;font-family:monospace!important;opacity:0.8;">${item.url}</div>`; return row;
            }));
        }

        const renderEditableHiddenItems = (data, key, container) => {
            container.innerHTML = '';
            container.appendChild(buildFrag(data, 'None', (sel, i) => {
                const div = doc.createElement('div'); div.className = 'list-item';
                div.innerHTML = `<span class="rule-text" title="${sel}">${sel}</span><div style="display:flex;gap:2px;align-items:center"><button class="hider-btn-small btn-blue btn-edit" title="Edit Rule Inline">✏️</button><button class="hider-btn-small btn-purple btn-wild" title="Convert Wildcard">🪄</button><button class="hider-btn-small btn-red btn-del" title="Delete Rule">✖</button></div>`;
                const textSpan = div.querySelector('.rule-text'), editBtn = div.querySelector('.btn-edit');

                editBtn.onclick = () => {
                    if (div.classList.contains('is-editing')) return;
                    div.classList.add('is-editing');
                    const input = doc.createElement('input'); input.type = 'text'; input.value = data[i]; input.className = 'h-select'; input.style.cssText = 'font-size:9px!important;padding:2px 4px!important;height:20px!important;flex:1!important;margin-right:4px!important;';
                    const saveBtn = doc.createElement('button'); saveBtn.className = 'hider-btn-small btn-green'; saveBtn.textContent = '✓';
                    textSpan.replaceWith(input); editBtn.replaceWith(saveBtn); input.focus();

                    const saveHandler = () => {
                        const newVal = input.value.trim();
                        if (newVal) { data[i] = newVal; sv(key, data); requestUpdateStyles(); showToast('✏️ Hidden rule updated'); }
                        renderList();
                    };
                    saveBtn.onclick = saveHandler; input.onkeypress = e => e.key === 'Enter' && saveHandler();
                };

                div.querySelector('.btn-wild').onclick = () => { 
                    data[i] = convertToWildcardSelector(data[i]); 
                    sv(key, data); requestUpdateStyles(); renderList(); 
                    showToast(`🪄 Wildcard applied`);
                };
                div.querySelector('.btn-del').onclick = () => {
                    const removed = data.splice(i, 1)[0]; sv(key, data);
                    try { doc.querySelectorAll(removed).forEach(el => el.classList.remove('hider-stealth-target')); } catch {}
                    requestUpdateStyles(); renderList();
                    showToast('🗑️ Hidden rule removed');
                };
                return div;
            }));
        };

        renderEditableHiddenItems(siteData, siteKey, cSite); renderEditableHiddenItems(linkData, linkKey, cLink);

        renderDockButtonOptions();
        applyDockButtonVisibility();
    }

    // ---------- Navigation Click Handler ----------
    function handleNavigationClick(e) {
        const path = e.composedPath?.() || [];
        if (isSelecting || path.some(el => el.id === UI_HOST_ID || el.id === STEPPER_BAR_ID)) return;
        const link = e.target.closest('a[href], area[href]');
        if (link?.href) {
            const rawHref = link.getAttribute('href') || '';
            if (rawHref.startsWith('#') || rawHref.toLowerCase().startsWith('javascript:')) return;
            const targetUrl = link.href;
            if (isDomainBlocked(targetUrl)) {
                e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
                logBlockedAttempt(targetUrl, 'Blocked Link Click'); simulateAdWindowSuccess(); showToast('⛔ Force Blocked'); return;
            }
            if (!isFrozen || isDomainAllowed(targetUrl)) return;

            e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
            const isNewTab = link.target === '_blank' || e.ctrlKey || e.metaKey || e.button === 1;
            handleFreezeNavigation(targetUrl, 'Link Click', () => {
                userApprovedNavigation = true; if (isNewTab) win.open(targetUrl, '_blank'); else win.location.href = targetUrl;
                setTimeout(() => userApprovedNavigation = false, 300);
            }, simulateAdWindowSuccess);
        }
    }

    // ---------- Scroll auto-close ----------
    function setupScrollAutoClose() {
        win.addEventListener('scroll', () => {
            if (scrollAnimationFrame) return;
            scrollAnimationFrame = win.requestAnimationFrame(() => {
                scrollAnimationFrame = null;
                closeAllMenus(null);
                closePreviewModal();
            });
        }, { passive: true, capture: true });
    }

    // ---------- Keyboard shortcuts ----------
    window.addEventListener('keydown', e => { if (e.key === 'Escape') { if (isSelecting) { turnOffHideMode(); showToast('🎯 Selection mode cancelled'); } else { closeAllMenus(null, true); closePreviewModal(); } } }, true);

    // ---------- Selection mode blockers ----------
    ['mousedown', 'pointerdown', 'mouseup'].forEach(evtType => {
        window.addEventListener(evtType, e => {
            if (!isSelecting) return;
            if (e.composedPath?.().some(el => el.id === UI_HOST_ID || el.id === STEPPER_BAR_ID)) return;
            e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
        }, true);
    });

    // ---------- Click handling for selection ----------
    window.addEventListener('click', e => {
        const path = e.composedPath?.() || [];
        const isUI = path.some(el => el.id === UI_HOST_ID || el.id === STEPPER_BAR_ID);
        
        if (!isUI) { closeAllMenus(e); shadowRoot?.querySelectorAll('.h-custom-select').forEach(c => c.classList.remove('is-open')); }
        if (isUI) return;
        
        handleNavigationClick(e); 
        if (!isSelecting) return;
        
        e.preventDefault(); e.stopPropagation();
        if (previewElement === e.target) confirmHideSelectedElement(false);
        else {
            previewElement?.classList.remove('hider-preview-highlight'); stepperStack = [];
            previewElement = e.target; previewElement.classList.add('hider-preview-highlight'); renderTouchStepperUI();
        }
    }, true);

    window.addEventListener('auxclick', handleNavigationClick, true);

    window.addEventListener('submit', e => {
        const path = e.composedPath?.() || [];
        if (path.some(el => el.id === UI_HOST_ID || el.id === STEPPER_BAR_ID)) return;
        const form = e.target, action = form.action || location.href;
        if (isDomainBlocked(action)) {
            e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
            logBlockedAttempt(action, 'Blocked Form Submit'); simulateAdWindowSuccess(); showToast('⛔ Blocked Form'); return;
        }
        if (!isFrozen || isDomainAllowed(action)) return;
        e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
        handleFreezeNavigation(action, 'Form Submit', () => { userApprovedNavigation = true; form.submit(); setTimeout(() => userApprovedNavigation = false, 300); }, simulateAdWindowSuccess);
    }, true);

    window.addEventListener('touchstart', e => {
        if (!e.touches?.[0]) return;
        const x = e.touches[0].clientX;
        if (x <= 40 || x >= (win.innerWidth - 40)) { userApprovedNavigation = true; setTimeout(() => { userApprovedNavigation = false; }, 1500); }
    }, { passive: true, capture: true });

    // ---------- History navigation ----------
    ['back', 'forward', 'go'].forEach(method => {
        const orig = history[method];
        if (orig) { history[method] = function() { userApprovedNavigation = true; setTimeout(() => { userApprovedNavigation = false; }, 1000); return orig.apply(this, arguments); }; }
    });

    try { win.navigation?.addEventListener('navigate', e => { if (e.navigationType === 'traverse' || e.navigationType === 'reload') { userApprovedNavigation = true; setTimeout(() => { userApprovedNavigation = false; }, 1000); } }); } catch {}

    win.addEventListener('beforeunload', e => {
        if (userApprovedNavigation) return;
        if (isFrozen && !isDomainAllowed(location.href) && (CACHE.freezeMemory === 'ask' || CACHE.freezeMemory === 'block_all')) { e.preventDefault(); return (e.returnValue = 'Page navigation is currently frozen site-wide.'); }
    }, true);

    // ---------- URL change detection ----------
    const checkUrlChange = () => {
        if (location.href !== lastUrl) { 
            lastUrl = location.href; 
            updateCurrentLocCache();
            requestUpdateStyles(); 
            if (shadowBy('hider-panel')?.classList.contains('is-visible')) renderList(); 
        }
    };

    ['pushState', 'replaceState'].forEach(fn => { const orig = history[fn]; if (orig) history[fn] = function() { orig.apply(this, arguments); checkUrlChange(); }; });
    window.addEventListener('popstate', () => { userApprovedNavigation = true; checkUrlChange(); setTimeout(() => { userApprovedNavigation = false; }, 500); }, { passive: true });
    window.addEventListener('hashchange', checkUrlChange, { passive: true });
    window.addEventListener('pageshow', () => { userApprovedNavigation = false; checkUrlChange(); }, { passive: true });

    // ---------- Low-power heartbeat ----------
    function setupLowPowerHeartbeat() {
        const scheduleIdle = fn => (win.requestIdleCallback ? win.requestIdleCallback(fn, { timeout: 2000 }) : setTimeout(fn, 1000));
        const performHealthCheck = () => {
            if (isTop && !doc.getElementById(UI_HOST_ID)) createShadowUI();
            if (!doc.getElementById('hider-dynamic-styles')) requestUpdateStyles();
            if (!isTop) try { window.top.postMessage({ type: 'HIDER_REQUEST_STATE' }, '*'); } catch {}
            scheduleIdle(performHealthCheck);
        };
        scheduleIdle(performHealthCheck);
    }

    // ---------- Init ----------
    function init() {
        updateCurrentLocCache();
        installInterceptors();
        createShadowUI();
        requestUpdateStyles();
        setupScrollAutoClose();
        setupLowPowerHeartbeat();
        setupProtectionObserver();

        applyAllSettings();

        if (CACHE.autoTimeSkipper && featuresEnabled) {
            setTimeout(autoSkipTimers, 500);
        }
    }

    if (doc.readyState === 'loading') doc.addEventListener('DOMContentLoaded', init); else init();
})();