☰

The Club Enhancer

Filters, highlights, search history, panic mode, UI cleanup for XXXClub

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

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         The Club Enhancer
// @namespace    https://xxxclub.to/
// @version      5.1
// @description  Filters, highlights, search history, panic mode, UI cleanup for XXXClub
// @author       sadman
// @match        https://xxxclub.to/*
// @match        https://*.xxxclub.to/*
// @match        https://xxxclub.cc/*
// @match        https://*.xxxclub.cc/*
// @match        https://xxxclub.me/*
// @match        https://*.xxxclub.me/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';

    const DEFAULT_WORDS = [
        '21Naturals',
        'LittleDickClub',
        'KarupsPC',
        '18Lust',
        '480p',
        '4KCFNM',
        '540p',
        'AllOver30',
        'ALSAngels',
        'ALSScan',
        'AngelsLove',
        'Anilos',
        'Arousins',
        'ATKExotics',
        'ATKGalleria',
        'ATKGirlfriends',
        'ATKHairy',
        'AuntJudys',
        'AuntJudysXXX',
        'BadMommyPOV',
        'BBVideo',
        'Beauty-Angels',
        'bellesafilms',
        'BellesaHouse',
        'BigGulpGirls',
        'BJRaw',
        'BrokenLatinaWhores',
        'BTS',
        'Cartoon',
        'CatalinaCruz',
        'CathysCraving',
        'CharlieForde',
        'Cherry-Candle',
        'CherryPimps',
        'Cosmid',
        'CosplayXGirls',
        'Creampie-Angels',
        'DeepThroatSirens',
        'DickHDDaily',
        'DigitalDesire',
        'DoeGirls',
        'EternalDesire',
        'EvolvedFights',
        'EvolvedFightsLez',
        'FaceFuckingKing',
        'FacialAbuse',
        'FakeTaxi',
        'FemJoy',
        'FTVMilfs',
        'Futanari',
        'GirlsOutWest',
        'GloryHoleSecrets',
        'GloryholeSwallow',
        'Hegre',
        'HijabHookup',
        'HijabMylfs',
        'HomeGrownEurope',
        'HotGuysFuck',
        'HouseHumpers',
        'IndustryInvaders',
        'JackOffGirls',
        'JapanLust',
        'JaysPOV',
        'JerkOffWithMe',
        'JesseLoadsMonsterFacials',
        'JimSlip',
        'Johanvilde',
        'JOIBabes',
        'JuliaAnnLive',
        'KarupsHA',
        'LadyVoyeurs',
        'LetsPostIt',
        'Little Puck',
        'LittleAsians',
        'LittleCaprice-Dreams',
        'Lustery',
        'ManoJob',
        'MassageSins',
        'MaxineX',
        'MetArt',
        'MetArtX',
        'Mia-Nins',
        'MommyBlowsBest',
        'MommyJOI',
        'MylfBlows',
        'NebraskaCoeds',
        'NickMarxx',
        'Nicole Doshi',
        'NiksIndian',
        'Nookies',
        'Nubiles',
        'NudeYogaPorn',
        'NylonPerv',
        'OnlyFans',
        'PascalsSubSluts',
        'Penthouse',
        'Perfect18',
        'PlayboyPlus',
        'POVMasters',
        'PublicAgent',
        'PureCFNM',
        'Rim4K',
        'S3XUS',
        'ScandalousGFs',
        'SeeHimFuck',
        'SeeMomSuck',
        'SensationalVideo',
        'SensualHeat',
        'SensualLove',
        'SexArt',
        'ShadySpa',
        'Shoplyfter',
        'SinDeluxe',
        'SinnSage',
        'Stunning18',
        'Swallowed',
        'TeenageCorruption',
        'ThaiSwinger',
        'TheDickSuckers',
        'TheLifeErotic',
        'Throated',
        'UltraFilms',
        'UnratedStories',
        'Vertical',
        'VivThomas',
        'Watch4Beauty',
        'WetAndPuffy',
        'WoodmanCastingX',
        'WowGirls',
        'X-Angels',
        'XXXJobInterviews'
    ];

    // ========== BANCO DE DESTACADOS (solo se usa la primera vez) ==========
    const DEFAULT_HIGHLIGHTS = [
        // Ejemplo: 'Vixen', 'Blacked', 'Tushy'
    ];

    // ========== CONFIG ==========
    const STORAGE_KEY = 'xxxclub_filter_words';
    const HIGHLIGHT_KEY = 'xxxclub_highlight_words';
    const VISITED_KEY = 'xxxclub_visited_links';
    const SEARCH_HIST_KEY = 'xxxclub_search_history';
    const ENABLED_KEY = 'xxxclub_filter_enabled';
    const INVERT_KEY = 'xxxclub_filter_invert';
    const HIGHLIGHT_ENABLED_KEY = 'xxxclub_highlight_enabled';
    const PANIC_KEY = 'xxxclub_panic_hide';
    const SIDEBAR_KEY = 'xxxclub_sidebar_open';

    const FAKE_TITLES = [
        'The Shawshank Redemption', 'The Godfather', 'The Dark Knight', 'Pulp Fiction',
        'Forrest Gump', 'Inception', 'Fight Club', 'The Matrix', 'Goodfellas',
        'Interstellar', 'The Green Mile', 'Se7en', 'The Silence of the Lambs',
        'Saving Private Ryan', 'The Prestige', 'Whiplash', 'Gladiator', 'Alien',
        'Blade Runner 2049', 'Parasite', 'Joker', 'Django Unchained', 'Wall-E',
        'Toy Story', 'Up', 'Coco', 'Spirited Away', 'Your Name', 'Amélie',
        'La La Land', 'Arrival', 'Mad Max: Fury Road', 'John Wick', 'Dune'
    ];

    const SUGGESTED_SEARCHES = [
        'Vixen 1080', 'Blacked 1080', 'Tushy 1080', 'Deeper 1080',
        'EvilAngel 1080', 'BangBros 1080', 'Brazzers 1080', 'NubileFilms 1080'
    ];

    // ========== STATE ==========
    let words = loadList(STORAGE_KEY, DEFAULT_WORDS);
    let highlights = loadList(HIGHLIGHT_KEY, DEFAULT_HIGHLIGHTS);
    let visited = loadVisited();
    let searchHistory = loadSearchHistory();
    let enabled = localStorage.getItem(ENABLED_KEY) !== 'false';
    let invert = localStorage.getItem(INVERT_KEY) === 'true';
    let highlightEnabled = localStorage.getItem(HIGHLIGHT_ENABLED_KEY) !== 'false';
    let panicOn = localStorage.getItem(PANIC_KEY) === 'true';

    // ========== STORAGE HELPERS ==========
    function loadList(key, fallback) {
        try {
            const raw = localStorage.getItem(key);
            if (raw) return JSON.parse(raw).map(w => String(w).trim()).filter(Boolean);
        } catch {}
        return [...fallback];
    }
    function saveList(key, list) {
        const clean = list.map(w => String(w).trim()).filter(Boolean);
        localStorage.setItem(key, JSON.stringify(clean));
        return clean;
    }
    function loadVisited() {
        try {
            const raw = localStorage.getItem(VISITED_KEY);
            if (raw) {
                const arr = JSON.parse(raw);
                return new Set(Array.isArray(arr) ? arr : []);
            }
        } catch {}
        return new Set();
    }
    function saveVisited() {
        let arr = [...visited];
        if (arr.length > 5000) arr = arr.slice(-5000);
        localStorage.setItem(VISITED_KEY, JSON.stringify(arr));
    }
    function loadSearchHistory() {
        try {
            const raw = localStorage.getItem(SEARCH_HIST_KEY);
            if (raw) {
                const arr = JSON.parse(raw);
                return Array.isArray(arr) ? arr.slice(0, 10) : [];
            }
        } catch {}
        return [];
    }
    function saveSearchHistory() {
        localStorage.setItem(SEARCH_HIST_KEY, JSON.stringify(searchHistory.slice(0, 10)));
    }
    function addSearchToHistory(q) {
        q = (q || '').trim();
        if (!q) return;
        searchHistory = [q, ...searchHistory.filter(x => x.toLowerCase() !== q.toLowerCase())].slice(0, 10);
        saveSearchHistory();
        renderSidebarHistory();
    }

    function normalize(text) {
        return String(text).toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
    }
    function escapeRegExp(s) {
        return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }
    function containsWord(text, word) {
        const nw = normalize(word.trim());
        if (!nw) return false;
        return new RegExp(`\\b${escapeRegExp(nw)}\\b`, 'i').test(normalize(text));
    }
    function isWordInList(word, list) {
        const key = normalize(word);
        return list.some(w => normalize(w) === key);
    }
    function normalizeUrl(href) {
        try {
            const u = new URL(href, location.origin);
            return u.pathname + u.search;
        } catch { return href; }
    }

    // ========== SYNC TABS ==========
    window.addEventListener('storage', (e) => {
        if (!e.key) return;
        if (e.key === STORAGE_KEY) {
            words = loadList(STORAGE_KEY, DEFAULT_WORDS);
            renderWordList(); applyAll(); updateCollectionButtons();
        }
        if (e.key === HIGHLIGHT_KEY) {
            highlights = loadList(HIGHLIGHT_KEY, DEFAULT_HIGHLIGHTS);
            renderHighlightList(); applyAll(); updateCollectionButtons();
        }
        if (e.key === VISITED_KEY) {
            visited = loadVisited();
            applyVisitedLinks();
        }
        if (e.key === SEARCH_HIST_KEY) {
            searchHistory = loadSearchHistory();
            renderSidebarHistory();
        }
        if (e.key === ENABLED_KEY) {
            enabled = e.newValue !== 'false';
            const cb = document.getElementById('xxx-enabled');
            if (cb) cb.checked = enabled;
            applyAll();
        }
        if (e.key === INVERT_KEY) {
            invert = e.newValue === 'true';
            const cb = document.getElementById('xxx-invert');
            if (cb) cb.checked = invert;
            applyAll();
        }
        if (e.key === HIGHLIGHT_ENABLED_KEY) {
            highlightEnabled = e.newValue !== 'false';
            const cb = document.getElementById('xxx-highlight-enabled');
            if (cb) cb.checked = highlightEnabled;
            applyAll();
        }
        if (e.key === PANIC_KEY) {
            panicOn = e.newValue === 'true';
            applyPanic(panicOn);
        }
    });

    // ========== FILTER / HIGHLIGHT ==========
    function shouldHide(li) {
        if (!enabled || !words.length) return false;
        const text = li.textContent || '';
        const matches = words.some(w => containsWord(text, w));
        return invert ? !matches : matches;
    }
    function shouldHighlight(li) {
        if (!highlightEnabled || !highlights.length) return false;
        return highlights.some(w => containsWord(li.textContent || '', w));
    }

    function applyVisitedLinks() {
        document.querySelectorAll('a[href*="/torrents/details/"]').forEach(a => {
            if (visited.has(normalizeUrl(a.href))) a.classList.add('xxx-visited');
            else a.classList.remove('xxx-visited');
        });
    }
    function markLinkVisited(href) {
        const key = normalizeUrl(href);
        if (!visited.has(key)) {
            visited.add(key);
            saveVisited();
        }
    }
    function setupVisitedTracking() {
        if (window.__xxxVisitedBound) return;
        window.__xxxVisitedBound = true;
        document.addEventListener('click', (e) => {
            const a = e.target.closest('a[href*="/torrents/details/"]');
            if (!a) return;
            markLinkVisited(a.href);
            a.classList.add('xxx-visited');
        }, true);
        if (location.pathname.includes('/torrents/details/')) {
            markLinkVisited(location.href);
        }
    }

    // ========== TABLE: THUMBS + HIDE COLUMNS ==========
    function enhanceTable() {
        // Solo ocultar columnas Category y Uploader (sin thumbnails)
        document.querySelectorAll('.browsetableinside ul > li:first-child, ul.tsearch > li:first-child').forEach(header => {
            const spans = header.querySelectorAll(':scope > span');
            spans.forEach(sp => {
                const txt = (sp.textContent || '').trim().toLowerCase();
                if (txt === 'category' || txt === 'uploader') {
                    sp.style.display = 'none';
                }
            });
        });

        document.querySelectorAll('.browsetableinside ul > li, ul.tsearch > li').forEach(li => {
            const cat = li.querySelector('.catlabe');
            if (cat) cat.style.display = 'none';
            const up = li.querySelector('.uploadertable');
            if (up) up.style.display = 'none';
        });
    }

    // ========== APPLY ALL ==========
    function applyAll() {
        enhanceTable();

        const items = document.querySelectorAll(
            '.browsetableinside ul > li, ul.torrent-list > li, .torrent-list li, div.browsetableinside li, ul.tsearch > li'
        );
        let hiddenCount = 0, highlightCount = 0;

        items.forEach(li => {
            if (li.querySelector('.catlabe') === null && !li.querySelector('a[href*="/torrents/details/"]')) return;

            const oldStar = li.querySelector('.xxx-star');
            if (oldStar) oldStar.remove();
            li.classList.remove('xxx-highlighted');

            const titleLink = li.querySelector('a[href*="/torrents/details/"]');
            if (titleLink) {
                titleLink.style.fontSize = '';
                titleLink.style.color = '';
                titleLink.style.fontWeight = '';
            }

            if (shouldHide(li)) {
                li.style.display = 'none';
                li.dataset.filtered = '1';
                hiddenCount++;
                return;
            }
            li.style.display = '';
            delete li.dataset.filtered;

            if (shouldHighlight(li) && titleLink) {
                li.classList.add('xxx-highlighted');
                highlightCount++;
                const currentSize = parseFloat(window.getComputedStyle(titleLink).fontSize) || 14;
                titleLink.style.fontSize = (currentSize + 2) + 'px';
                titleLink.style.color = '#5af';
                titleLink.style.fontWeight = '600';
                if (!titleLink.querySelector('.xxx-star')) {
                    const star = document.createElement('span');
                    star.className = 'xxx-star';
                    star.textContent = '⭐ ';
                    titleLink.insertBefore(star, titleLink.firstChild);
                }
            }
        });

        applyVisitedLinks();
        if (panicOn) applyPanicTitles(true);
        updateCounter(hiddenCount, highlightCount);
        updateFabBadge(hiddenCount, highlightCount);
    }

    // ========== COLLECTION BUTTONS ==========
    function addCollectionButtons() {
        document.querySelectorAll('li').forEach(li => {
            if (li.querySelector('.xxx-quick-add') || li.querySelector('.xxx-quick-highlight')) return;
            let labelSpan = null;
            for (const span of li.querySelectorAll('span')) {
                const t = span.textContent.trim();
                if (t === 'Collection' || t === 'Tag') { labelSpan = span; break; }
            }
            if (!labelSpan) return;
            const link = li.querySelector('a[href*="/torrents/search/all/tag:"], a[href*="tag:"]');
            if (!link) return;
            const collectionName = (link.textContent || '').trim();
            if (!collectionName) return;

            const btnExcluir = document.createElement('button');
            btnExcluir.className = 'xxx-quick-add';
            btnExcluir.type = 'button';
            btnExcluir.dataset.word = collectionName;
            updateQuickBtnState(btnExcluir, isWordInList(collectionName, words), 'exclude');
            btnExcluir.addEventListener('click', (e) => {
                e.preventDefault(); e.stopPropagation();
                toggleWord(collectionName, 'exclude');
            });

            const btnDestacar = document.createElement('button');
            btnDestacar.className = 'xxx-quick-highlight';
            btnDestacar.type = 'button';
            btnDestacar.dataset.word = collectionName;
            updateQuickBtnState(btnDestacar, isWordInList(collectionName, highlights), 'highlight');
            btnDestacar.addEventListener('click', (e) => {
                e.preventDefault(); e.stopPropagation();
                toggleWord(collectionName, 'highlight');
            });

            const wrap = document.createElement('span');
            wrap.className = 'xxx-quick-wrap';
            wrap.appendChild(btnExcluir);
            wrap.appendChild(btnDestacar);
            labelSpan.replaceWith(wrap);
        });
    }

    function toggleWord(word, type) {
        const list = type === 'highlight' ? highlights : words;
        if (isWordInList(word, list)) {
            const idx = list.findIndex(w => normalize(w) === normalize(word));
            if (idx !== -1) list.splice(idx, 1);
        } else {
            list.push(word);
        }
        if (type === 'highlight') {
            highlights = saveList(HIGHLIGHT_KEY, list);
            renderHighlightList();
        } else {
            words = saveList(STORAGE_KEY, list);
            renderWordList();
        }
        applyAll();
        updateCollectionButtons();
    }

    function updateQuickBtnState(btn, active, type) {
        if (active) {
            btn.textContent = '✅';
            btn.classList.add('active');
            btn.title = type === 'exclude' ? 'In exclusion list — click to remove' : 'Highlighted — click to remove';
        } else {
            btn.textContent = type === 'exclude' ? '🚫' : '⭐';
            btn.classList.remove('active');
            btn.title = type === 'exclude' ? 'Add to exclusions' : 'Add to highlights';
        }
    }
    function updateCollectionButtons() {
        document.querySelectorAll('.xxx-quick-add').forEach(btn => {
            if (btn.dataset.word) updateQuickBtnState(btn, isWordInList(btn.dataset.word, words), 'exclude');
        });
        document.querySelectorAll('.xxx-quick-highlight').forEach(btn => {
            if (btn.dataset.word) updateQuickBtnState(btn, isWordInList(btn.dataset.word, highlights), 'highlight');
        });
    }

    // ========== PANIC TOTAL ==========
    function applyPanic(on) {
        panicOn = on;
        document.body.classList.toggle('xxx-panic-hide', on);
        document.body.classList.toggle('xxx-panic-total', on);
        const panicFab = document.getElementById('xxx-panic-fab');
        if (panicFab) {
            panicFab.classList.toggle('active', on);
            panicFab.title = on
                ? 'Panic ON — Ctrl+Shift+H to disable'
                : 'Panic mode (Ctrl+Shift+H)';
        }
        applyPanicTitles(on);
        localStorage.setItem(PANIC_KEY, on);
    }

    function applyPanicTitles(on) {
        document.querySelectorAll('a[href*="/torrents/details/"]').forEach((a, i) => {
            if (on) {
                if (!a.dataset.xxxRealTitle) {
                    a.dataset.xxxRealTitle = a.textContent;
                }
                a.textContent = FAKE_TITLES[i % FAKE_TITLES.length];
            } else if (a.dataset.xxxRealTitle) {
                a.textContent = a.dataset.xxxRealTitle;
                delete a.dataset.xxxRealTitle;
            }
        });
        // Recommended section titles
        document.querySelectorAll('.recimg a, a[title*="Details Of"]').forEach((a, i) => {
            if (on) {
                if (!a.dataset.xxxRealTitleAttr && a.title) {
                    a.dataset.xxxRealTitleAttr = a.title;
                    a.title = FAKE_TITLES[i % FAKE_TITLES.length];
                }
            } else if (a.dataset.xxxRealTitleAttr) {
                a.title = a.dataset.xxxRealTitleAttr;
                delete a.dataset.xxxRealTitleAttr;
            }
        });
    }

    function togglePanic() {
        applyPanic(!document.body.classList.contains('xxx-panic-hide'));
    }

    // ========== SEARCH HISTORY + 1080p ==========
    function setupSearchFeatures() {
        // Capture current search from URL or input
        const params = new URLSearchParams(location.search);
        let q = params.get('q') || '';
        // Also path style: /torrents/search/all/WORD%201080
        const pathMatch = location.pathname.match(/\/torrents\/search\/(?:all\/)?(.+)/i);
        if (!q && pathMatch) {
            try { q = decodeURIComponent(pathMatch[1].replace(/\+/g, ' ')); } catch { q = pathMatch[1]; }
        }
        if (q) addSearchToHistory(q);

        // Form submit
        const form = document.querySelector('form#search, form[action*="search"]');
        if (form && !form.dataset.xxxBound) {
            form.dataset.xxxBound = '1';
            form.addEventListener('submit', () => {
                const input = form.querySelector('input[name="q"], input.searchboxtextinput');
                if (input && input.value.trim()) addSearchToHistory(input.value.trim());
            });
        }

        // 1080p button next to search
        const searchBox = document.querySelector('.search-box-input, #search-box');
        if (searchBox && !document.getElementById('xxx-1080-btn')) {
            const btn = document.createElement('button');
            btn.id = 'xxx-1080-btn';
            btn.type = 'button';
            btn.textContent = '+1080';
            btn.title = 'Append 1080 to search and go';
            btn.addEventListener('click', () => {
                const input = document.querySelector('input[name="q"], input.searchboxtextinput');
                if (!input) return;
                let v = input.value.trim();
                if (!/\b1080\b/i.test(v)) v = (v + ' 1080').trim();
                input.value = v;
                // Prefer path-style search if site uses it
                const encoded = encodeURIComponent(v).replace(/%20/g, '%20');
                location.href = '/torrents/search/all/' + encoded;
            });
            searchBox.appendChild(btn);
        }
    }

    function doSearch(q) {
        q = (q || '').trim();
        if (!q) return;
        addSearchToHistory(q);
        location.href = '/torrents/search/all/' + encodeURIComponent(q);
    }

    // ========== FAVICON ==========
    function setCircleFavicon() {
        const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
            <circle cx="32" cy="32" r="30" fill="#1a1a2e" stroke="#5af" stroke-width="4"/>
            <circle cx="32" cy="32" r="12" fill="#5af"/>
        </svg>`;
        const url = 'data:image/svg+xml,' + encodeURIComponent(svg);
        document.querySelectorAll('link[rel*="icon"]').forEach(l => l.remove());
        const link = document.createElement('link');
        link.rel = 'icon';
        link.type = 'image/svg+xml';
        link.href = url;
        document.head.appendChild(link);
    }

    // ========== SIDEBAR ==========
    function createSidebar() {
        if (document.getElementById('xxx-sidebar')) return;

        const sb = document.createElement('div');
        sb.id = 'xxx-sidebar';
        if (localStorage.getItem(SIDEBAR_KEY) === 'true') sb.classList.add('open');

        sb.innerHTML = `
            <button id="xxx-sidebar-toggle" title="History de búsquedas">🔍</button>
            <div class="xxx-sidebar-body">
                <div class="xxx-sb-section">
                    <h4>History</h4>
                    <div id="xxx-hist-list"></div>
                    <button id="xxx-hist-clear" class="xxx-sb-btn">Clear history</button>
                </div>
                <div class="xxx-sb-section">
                    <h4>Suggested</h4>
                    <div id="xxx-sug-list"></div>
                </div>
            </div>
        `;
        document.body.appendChild(sb);

        document.getElementById('xxx-sidebar-toggle').addEventListener('click', () => {
            sb.classList.toggle('open');
            localStorage.setItem(SIDEBAR_KEY, sb.classList.contains('open'));
        });
        document.getElementById('xxx-hist-clear').addEventListener('click', () => {
            searchHistory = [];
            saveSearchHistory();
            renderSidebarHistory();
        });

        renderSidebarHistory();
        renderSidebarSuggestions();
    }

    function renderSidebarHistory() {
        const el = document.getElementById('xxx-hist-list');
        if (!el) return;
        if (!searchHistory.length) {
            el.innerHTML = '<div class="xxx-sb-empty">No searches</div>';
            return;
        }
        el.innerHTML = searchHistory.map(q =>
            `<button class="xxx-sb-item" data-q="${q.replace(/"/g, '&quot;')}">${escapeHtml(q)}</button>`
        ).join('');
        el.querySelectorAll('.xxx-sb-item').forEach(btn => {
            btn.addEventListener('click', () => doSearch(btn.dataset.q));
        });
    }

    function renderSidebarSuggestions() {
        const el = document.getElementById('xxx-sug-list');
        if (!el) return;
        el.innerHTML = SUGGESTED_SEARCHES.map(q =>
            `<button class="xxx-sb-item sug" data-q="${q.replace(/"/g, '&quot;')}">${escapeHtml(q)}</button>`
        ).join('');
        el.querySelectorAll('.xxx-sb-item').forEach(btn => {
            btn.addEventListener('click', () => doSearch(btn.dataset.q));
        });
    }

    function escapeHtml(s) {
        return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
    }

    // ========== GLOBAL STYLES ==========
    function injectStyles() {
        if (document.getElementById('xxx-enhancer-css')) return;
        const style = document.createElement('style');
        style.id = 'xxx-enhancer-css';
        style.textContent = `
            /* ===== Dark mode forzado (más negro) ===== */
            html, body, .maincontainer, .middle, .main-content, .browsediv,
            .browsetablediv, .browsetableinside, .internalbrowsediv,
            .page-header, .sub-header, .side-bar, .page-footer {
                background: #0a0a0a !important;
                background-color: #0a0a0a !important;
                color: #ddd !important;
            }
            .page-header, #myHeader, .nav-bar, .sub-header, #sub-header {
                background: #111 !important;
                border-color: #222 !important;
            }
            .side-bar-list, .recdiv, .belowheading, ul.tsearch > li, .browsetableinside ul > li {
                background: #121212 !important;
                border-color: #222 !important;
            }
            .browsetableinside ul > li:hover, ul.tsearch > li:hover {
                background: #1a1a1a !important;
            }
            input, select, textarea, .searchboxtextinput, button.filterbutton, button.clearfilter {
                background: #1a1a1a !important;
                color: #eee !important;
                border-color: #333 !important;
            }
            a { color: #8ab4f8 !important; }
            a:hover { color: #a8c7fa !important; }

            /* Reemplazar deeppink / #ff1493 por azul claro */
            mark {
                background: rgba(80, 140, 255, 0.25) !important;
                color: #7eb6ff !important;
            }
            .catla, .catah, lable.catla, .catlabe a,
            a[style*="ff1493"], .see, font.see {
                /* keep seeders green-ish */
            }
            /* pink badges -> blue */
            .catla, lable.catla {
                background: #2563eb !important;
                color: #fff !important;
            }

            
            /* Larger hover preview (+60%) */
            img.floaterimg {
                transform: scale(1.6) !important;
                transform-origin: top left !important;
                z-index: 99990 !important;
                max-width: none !important;
                box-shadow: 0 8px 24px rgba(0,0,0,0.6) !important;
                border: 2px solid #333 !important;
                border-radius: 4px !important;
            }

            /* Hide category & uploader columns */
            .catlabe, .uploadertable,
            .browsetableinside ul > li:first-child > span:first-child,
            ul.tsearch > li:first-child > span:first-child {
                display: none !important;
            }

            /* ===== Visited (localStorage) ===== */
            a.xxx-visited { color: #e33 !important; }
            .xxx-highlighted a.xxx-visited { color: #5af !important; }
            .xxx-highlighted {
                background: rgba(40, 100, 200, 0.15) !important;
            }

            /* ===== Quick buttons ===== */
            .xxx-quick-wrap {
                display: inline-flex;
                align-items: center;
                gap: 2px;
                vertical-align: middle;
            }
            .xxx-quick-add, .xxx-quick-highlight {
                margin: 0; padding: 0 1px; border: none;
                background: transparent; font-size: 13px; line-height: 1;
                cursor: pointer; opacity: 0.5;
                transition: opacity 0.15s, transform 0.1s;
            }
            .xxx-quick-add:hover, .xxx-quick-highlight:hover { opacity: 1; transform: scale(1.2); }
            .xxx-quick-add.active, .xxx-quick-highlight.active { opacity: 1; }

            /* ===== Panic ===== */
            body.xxx-panic-hide img,
            body.xxx-panic-hide .floaterimg,
            body.xxx-panic-hide .img-thumbnail,
            body.xxx-panic-hide [style*="background-image"] {
                visibility: hidden !important;
                opacity: 0 !important;
            }
            body.xxx-panic-total .recdiv,
            body.xxx-panic-total .internalbrowsediv h3 {
                visibility: hidden;
            }

            /* ===== FABs ===== */
            #xxx-fab, #xxx-panic-fab {
                position: fixed; width: 52px; height: 52px;
                background: #1a1a1a; border: 1px solid #333;
                border-radius: 50%; box-shadow: 0 4px 16px rgba(0,0,0,0.5);
                display: flex; align-items: center; justify-content: center;
                cursor: pointer; z-index: 99998;
                transition: transform 0.15s, background 0.15s;
                user-select: none;
            }
            #xxx-fab { bottom: 20px; right: 20px; }
            #xxx-panic-fab { bottom: 20px; right: 82px; }
            #xxx-fab:hover, #xxx-panic-fab:hover { background: #2a2a2a; transform: scale(1.08); }
            #xxx-panic-fab.active { background: #622; border-color: #a44; }
            #xxx-fab .xxx-fab-icon, #xxx-panic-fab .xxx-fab-icon { font-size: 22px; line-height: 1; }
            #xxx-fab .xxx-fab-badge {
                position: absolute;
                color: #fff; font-size: 10px; font-weight: 600;
                min-width: 18px; height: 18px; border-radius: 9px;
                display: flex; align-items: center; justify-content: center;
                padding: 0 4px;
                box-shadow: 0 1px 3px rgba(0,0,0,0.4);
            }
            #xxx-fab .xxx-fab-badge-hide {
                top: -4px; right: -4px;
                background: #e33;
            }
            #xxx-fab .xxx-fab-badge-hl {
                top: -4px; left: -4px;
                background: #2563eb;
            }

            /* ===== Panel ===== */
            #xxx-filter-panel {
                position: fixed; bottom: 84px; right: 20px; width: 340px;
                background: #141414; color: #eee; border: 1px solid #333;
                border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.6);
                font-family: system-ui, sans-serif; font-size: 13px;
                z-index: 99999; overflow: hidden; display: none; user-select: none;
            }
            #xxx-filter-panel.visible { display: block; }
            #xxx-filter-panel .xxx-header {
                display: flex; justify-content: space-between; align-items: center;
                padding: 8px 12px; background: #1e1e1e; cursor: move;
            }
            #xxx-filter-panel .xxx-header strong { font-size: 14px; }
            #xxx-filter-panel .xxx-header button {
                background: none; border: none; color: #aaa; font-size: 18px; cursor: pointer;
            }
            #xxx-filter-panel .xxx-body { padding: 10px 12px; }
            .xxx-tabs { display: flex; gap: 4px; margin-bottom: 10px; }
            .xxx-tab {
                flex: 1; padding: 6px 8px; border: none; border-radius: 5px;
                background: #222; color: #aaa; cursor: pointer; font-size: 12px;
            }
            .xxx-tab.active { background: #2563eb; color: #fff; }
            .xxx-tab[data-tab="highlight"].active { background: #1d4ed8; }
            #xxx-filter-panel .xxx-controls { display: flex; gap: 16px; margin-bottom: 10px; }
            #xxx-filter-panel .xxx-controls label { display: flex; align-items: center; gap: 5px; cursor: pointer; }
            #xxx-filter-panel .xxx-add { display: flex; gap: 6px; margin-bottom: 10px; }
            #xxx-filter-panel input[type="text"] {
                flex: 1; padding: 6px 8px; border: 1px solid #333;
                border-radius: 5px; background: #1a1a1a; color: #fff; outline: none;
            }
            #xxx-filter-panel button {
                padding: 6px 10px; border: none; border-radius: 5px;
                background: #2563eb; color: #fff; cursor: pointer; font-size: 12px;
            }
            #xxx-filter-panel button:hover { background: #3b82f6; }
            #xxx-filter-panel #xxx-reset { background: #444; }
            #xxx-filter-panel #xxx-edit-list { background: #1e3a5f; }
            #xxx-filter-panel #xxx-export { background: #4c1d95; }
            #xxx-filter-panel #xxx-export-json { background: #0f766e; }
            #xxx-filter-panel #xxx-import-json { background: #a16207; }
            #xxx-filter-panel .xxx-list {
                max-height: 150px; overflow-y: auto; margin-bottom: 8px;
                border: 1px solid #2a2a2a; border-radius: 5px; background: #111;
            }
            #xxx-filter-panel .xxx-word-item {
                display: flex; justify-content: space-between; align-items: center;
                padding: 5px 8px; border-bottom: 1px solid #222;
            }
            #xxx-filter-panel .xxx-word-item span {
                flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
            }
            #xxx-filter-panel .xxx-word-item button {
                background: #633; padding: 2px 7px; font-size: 11px;
            }
            #xxx-filter-panel .xxx-footer {
                display: flex; justify-content: space-between; align-items: flex-start;
                font-size: 12px; color: #888; gap: 8px;
            }

            /* Modal */
            #xxx-edit-modal {
                display: none; position: fixed; inset: 0;
                background: rgba(0,0,0,0.75); z-index: 100000;
                align-items: center; justify-content: center;
            }
            #xxx-edit-modal.visible { display: flex; }
            #xxx-edit-modal .xxx-modal-content {
                background: #141414; border: 1px solid #333; border-radius: 10px;
                width: 90%; max-width: 480px; max-height: 80vh;
                display: flex; flex-direction: column;
            }
            #xxx-edit-modal .xxx-modal-header {
                display: flex; justify-content: space-between; align-items: center;
                padding: 12px 16px; background: #1e1e1e;
            }
            #xxx-edit-modal .xxx-modal-header button {
                background: none; border: none; color: #aaa; font-size: 22px; cursor: pointer;
            }
            #xxx-edit-modal .xxx-modal-body { padding: 12px 16px; flex: 1; display: flex; flex-direction: column; }
            #xxx-edit-modal #xxx-edit-textarea {
                width: 100%; height: 280px; padding: 10px;
                border: 1px solid #333; border-radius: 6px;
                background: #111; color: #eee; font-family: monospace; font-size: 13px;
                resize: vertical; outline: none;
            }
            #xxx-edit-modal .xxx-modal-footer {
                display: flex; justify-content: flex-end; gap: 8px;
                padding: 12px 16px; border-top: 1px solid #222;
            }
            #xxx-edit-modal .xxx-modal-footer button {
                padding: 7px 16px; border: none; border-radius: 5px; cursor: pointer; font-size: 13px;
            }
            #xxx-modal-cancel { background: #333; color: #ddd; }
            #xxx-modal-save { background: #2563eb; color: #fff; }

            /* ===== 1080 button ===== */
            #xxx-1080-btn {
                margin-left: 6px; padding: 6px 12px;
                background: #2563eb !important; color: #fff !important;
                border: none !important; border-radius: 5px;
                cursor: pointer; font-weight: 600; font-size: 13px;
            }
            #xxx-1080-btn:hover { background: #3b82f6 !important; }

            /* ===== Sidebar derecha ===== */
            #xxx-sidebar {
                position: fixed; top: 80px; right: 0; z-index: 99990;
                display: flex; align-items: flex-start;
            }
            #xxx-sidebar-toggle {
                width: 36px; height: 40px;
                background: #1a1a1a; border: 1px solid #333; border-right: none;
                border-radius: 8px 0 0 8px; color: #eee; cursor: pointer;
                font-size: 16px; box-shadow: -2px 2px 8px rgba(0,0,0,0.4);
            }
            #xxx-sidebar-toggle:hover { background: #252525; }
            .xxx-sidebar-body {
                width: 0; overflow: hidden; background: #111;
                border: 1px solid #333; border-right: none;
                max-height: 70vh; transition: width 0.2s ease;
            }
            #xxx-sidebar.open .xxx-sidebar-body {
                width: 220px; overflow-y: auto; padding: 10px;
            }
            .xxx-sb-section { margin-bottom: 14px; }
            .xxx-sb-section h4 {
                margin: 0 0 8px; font-size: 12px; color: #8ab4f8;
                text-transform: uppercase; letter-spacing: 0.04em;
            }
            .xxx-sb-item {
                display: block; width: 100%; text-align: left;
                padding: 6px 8px; margin-bottom: 4px;
                background: #1a1a1a; border: 1px solid #2a2a2a;
                border-radius: 4px; color: #ccc; cursor: pointer;
                font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
            }
            .xxx-sb-item:hover { background: #252525; color: #fff; border-color: #3b82f6; }
            .xxx-sb-item.sug { border-left: 2px solid #2563eb; }
            .xxx-sb-empty { color: #555; font-size: 12px; padding: 4px; }
            .xxx-sb-btn {
                width: 100%; padding: 5px; margin-top: 6px;
                background: #333; border: none; border-radius: 4px;
                color: #aaa; cursor: pointer; font-size: 11px;
            }
            .xxx-sb-btn:hover { background: #444; color: #fff; }

            /* Logo area slight dark */
            .logoimg { opacity: 0.9; }
        `;
        document.head.appendChild(style);
    }

    // ========== PANEL UI ==========
    function createUI() {
        if (document.getElementById('xxx-filter-panel')) return;

        const fab = document.createElement('div');
        fab.id = 'xxx-fab';
        fab.innerHTML = `<span class="xxx-fab-icon">⭐</span>
            <span class="xxx-fab-badge xxx-fab-badge-hide" id="xxx-fab-badge" style="display:none;">0</span>
            <span class="xxx-fab-badge xxx-fab-badge-hl" id="xxx-fab-badge-hl" style="display:none;">0</span>`;
        fab.title = 'The Club Enhancer';

        const panicFab = document.createElement('div');
        panicFab.id = 'xxx-panic-fab';
        panicFab.innerHTML = `<span class="xxx-fab-icon">🙈</span>`;
        panicFab.title = 'Panic mode (Ctrl+Shift+H)';

        const panel = document.createElement('div');
        panel.id = 'xxx-filter-panel';
        panel.innerHTML = `
            <div class="xxx-header">
                <strong>The Club Enhancer</strong>
                <button id="xxx-toggle-panel" title="Close">×</button>
            </div>
            <div class="xxx-body">
                <div class="xxx-tabs">
                    <button class="xxx-tab active" data-tab="exclude">Exclusions</button>
                    <button class="xxx-tab" data-tab="highlight">Highlights</button>
                </div>
                <div class="xxx-tab-content" id="xxx-tab-exclude">
                    <div class="xxx-controls">
                        <label><input type="checkbox" id="xxx-enabled" ${enabled ? 'checked' : ''}> Enabled</label>
                        <label><input type="checkbox" id="xxx-invert" ${invert ? 'checked' : ''}> Invert</label>
                    </div>
                    <div class="xxx-add">
                        <input type="text" id="xxx-word-input" placeholder="Word to exclude..." maxlength="80">
                        <button id="xxx-add-btn">Add</button>
                    </div>
                    <div class="xxx-list" id="xxx-word-list"></div>
                </div>
                <div class="xxx-tab-content" id="xxx-tab-highlight" style="display:none;">
                    <div class="xxx-controls">
                        <label><input type="checkbox" id="xxx-highlight-enabled" ${highlightEnabled ? 'checked' : ''}> Enabled</label>
                    </div>
                    <div class="xxx-add">
                        <input type="text" id="xxx-highlight-input" placeholder="Word to highlight..." maxlength="80">
                        <button id="xxx-highlight-add-btn">Add</button>
                    </div>
                    <div class="xxx-list" id="xxx-highlight-list"></div>
                </div>
                <div class="xxx-footer">
                    <span id="xxx-counter">Hidden: 0 · ⭐ 0</span>
                    <div style="display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;">
                        <button id="xxx-edit-list">Edit list</button>
                        <button id="xxx-export-json" title="Download full backup JSON">Export JSON</button>
                        <button id="xxx-import-json" title="Import backup JSON">Import JSON</button>
                        <button id="xxx-export" title="Copy current tab as JS array">Export code</button>
                        <button id="xxx-reset">Reset</button>
                    </div>
                    <input type="file" id="xxx-import-file" accept="application/json,.json" style="display:none;">
                </div>
            </div>
        `;

        const modal = document.createElement('div');
        modal.id = 'xxx-edit-modal';
        modal.innerHTML = `
            <div class="xxx-modal-content">
                <div class="xxx-modal-header">
                    <strong id="xxx-modal-title">Edit list</strong>
                    <button id="xxx-modal-close">×</button>
                </div>
                <div class="xxx-modal-body">
                    <p style="margin:0 0 8px;color:#888;font-size:12px;">One word per line.</p>
                    <textarea id="xxx-edit-textarea" spellcheck="false"></textarea>
                </div>
                <div class="xxx-modal-footer">
                    <button id="xxx-modal-cancel">Cancel</button>
                    <button id="xxx-modal-save">Save</button>
                </div>
            </div>
        `;

        document.body.appendChild(fab);
        document.body.appendChild(panicFab);
        document.body.appendChild(panel);
        document.body.appendChild(modal);

        let currentTab = 'exclude';
        panel.querySelectorAll('.xxx-tab').forEach(tab => {
            tab.addEventListener('click', () => {
                currentTab = tab.dataset.tab;
                panel.querySelectorAll('.xxx-tab').forEach(t => t.classList.remove('active'));
                tab.classList.add('active');
                document.getElementById('xxx-tab-exclude').style.display = currentTab === 'exclude' ? '' : 'none';
                document.getElementById('xxx-tab-highlight').style.display = currentTab === 'highlight' ? '' : 'none';
            });
        });

        fab.addEventListener('click', () => panel.classList.toggle('visible'));
        document.getElementById('xxx-toggle-panel').addEventListener('click', () => panel.classList.remove('visible'));
        panicFab.addEventListener('click', togglePanic);

        document.addEventListener('keydown', (e) => {
            if (e.ctrlKey && e.shiftKey && (e.key === 'H' || e.key === 'h')) {
                const tag = (e.target && e.target.tagName) || '';
                if (tag === 'INPUT' || tag === 'TEXTAREA' || e.target.isContentEditable) return;
                e.preventDefault();
                togglePanic();
            }
        });

        document.getElementById('xxx-add-btn').addEventListener('click', () => addToList('exclude'));
        document.getElementById('xxx-word-input').addEventListener('keydown', e => { if (e.key === 'Enter') addToList('exclude'); });
        document.getElementById('xxx-highlight-add-btn').addEventListener('click', () => addToList('highlight'));
        document.getElementById('xxx-highlight-input').addEventListener('keydown', e => { if (e.key === 'Enter') addToList('highlight'); });

        document.getElementById('xxx-enabled').addEventListener('change', e => {
            enabled = e.target.checked;
            localStorage.setItem(ENABLED_KEY, enabled);
            applyAll();
        });
        document.getElementById('xxx-invert').addEventListener('change', e => {
            invert = e.target.checked;
            localStorage.setItem(INVERT_KEY, invert);
            applyAll();
        });
        document.getElementById('xxx-highlight-enabled').addEventListener('change', e => {
            highlightEnabled = e.target.checked;
            localStorage.setItem(HIGHLIGHT_ENABLED_KEY, highlightEnabled);
            applyAll();
        });

        document.getElementById('xxx-reset').addEventListener('click', () => {
            if (currentTab === 'exclude') {
                if (!confirm('Reset exclusions to defaults?')) return;
                words = saveList(STORAGE_KEY, [...DEFAULT_WORDS]);
                renderWordList();
            } else {
                if (!confirm('Reset highlights to defaults?')) return;
                highlights = saveList(HIGHLIGHT_KEY, [...DEFAULT_HIGHLIGHTS]);
                renderHighlightList();
            }
            applyAll(); updateCollectionButtons();
        });

        document.getElementById('xxx-edit-list').addEventListener('click', () => openEditModal(currentTab));
        document.getElementById('xxx-export').addEventListener('click', () => exportCode(currentTab));
        document.getElementById('xxx-export-json').addEventListener('click', exportFullJson);
        document.getElementById('xxx-import-json').addEventListener('click', () => {
            document.getElementById('xxx-import-file').click();
        });
        document.getElementById('xxx-import-file').addEventListener('change', (e) => {
            const f = e.target.files && e.target.files[0];
            if (f) importFullJson(f);
            e.target.value = '';
        });
        document.getElementById('xxx-modal-close').addEventListener('click', closeEditModal);
        document.getElementById('xxx-modal-cancel').addEventListener('click', closeEditModal);
        document.getElementById('xxx-modal-save').addEventListener('click', () => saveFromTextarea(currentTab));
        document.addEventListener('keydown', e => {
            if (e.key === 'Escape') {
                if (modal.classList.contains('visible')) closeEditModal();
                else panel.classList.remove('visible');
            }
        });
        modal.addEventListener('click', e => { if (e.target === modal) closeEditModal(); });

        makeDraggable(panel);
        renderWordList();
        renderHighlightList();

        if (panicOn) applyPanic(true);
    }

    function openEditModal(tab) {
        const modal = document.getElementById('xxx-edit-modal');
        document.getElementById('xxx-modal-title').textContent = tab === 'highlight' ? 'Edit highlights' : 'Edit exclusions';
        document.getElementById('xxx-edit-textarea').value = (tab === 'highlight' ? highlights : words).join('\n');
        modal.dataset.tab = tab;
        modal.classList.add('visible');
    }
    function closeEditModal() {
        document.getElementById('xxx-edit-modal').classList.remove('visible');
    }
    function saveFromTextarea(tab) {
        const lines = document.getElementById('xxx-edit-textarea').value.split('\n').map(l => l.trim()).filter(Boolean);
        const unique = []; const seen = new Set();
        for (const w of lines) {
            const k = normalize(w);
            if (!seen.has(k)) { seen.add(k); unique.push(w); }
        }
        if (tab === 'highlight') {
            highlights = saveList(HIGHLIGHT_KEY, unique);
            renderHighlightList();
        } else {
            words = saveList(STORAGE_KEY, unique);
            renderWordList();
        }
        applyAll(); updateCollectionButtons(); closeEditModal();
    }
    function exportCode(tab) {
        const list = tab === 'highlight' ? highlights : words;
        const name = tab === 'highlight' ? 'DEFAULT_HIGHLIGHTS' : 'DEFAULT_WORDS';
        const sorted = [...list].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
        const lines = sorted.map(w => "        '" + w.replace(/'/g, "\\'") + "'");
        const code = "    const " + name + " = [\n" + lines.join(",\n") + "\n    ];";
        navigator.clipboard.writeText(code).then(() => {
            const btn = document.getElementById('xxx-export');
            const o = btn.textContent; btn.textContent = 'Copied!';
            setTimeout(() => { btn.textContent = o; }, 1500);
        }).catch(() => prompt('Copy:', code));
    }
    function addToList(type) {
        const input = document.getElementById(type === 'highlight' ? 'xxx-highlight-input' : 'xxx-word-input');
        const raw = input.value.trim();
        if (!raw) return;
        const list = type === 'highlight' ? highlights : words;
        if (isWordInList(raw, list)) { input.value = ''; return; }
        list.push(raw);
        if (type === 'highlight') { highlights = saveList(HIGHLIGHT_KEY, list); renderHighlightList(); }
        else { words = saveList(STORAGE_KEY, list); renderWordList(); }
        input.value = ''; applyAll(); updateCollectionButtons();
    }
    function removeFromList(index, type) {
        if (type === 'highlight') {
            highlights.splice(index, 1);
            highlights = saveList(HIGHLIGHT_KEY, highlights);
            renderHighlightList();
        } else {
            words.splice(index, 1);
            words = saveList(STORAGE_KEY, words);
            renderWordList();
        }
        applyAll(); updateCollectionButtons();
    }
    function renderWordList() {
        const list = document.getElementById('xxx-word-list');
        if (!list) return;
        if (!words.length) { list.innerHTML = '<div style="padding:8px;color:#555;text-align:center;">No exclusions</div>'; return; }
        list.innerHTML = words.map((w, i) => `<div class="xxx-word-item"><span title="${w}">${w}</span><button data-i="${i}">×</button></div>`).join('');
        list.querySelectorAll('button').forEach(btn => btn.addEventListener('click', () => removeFromList(+btn.dataset.i, 'exclude')));
    }
    function renderHighlightList() {
        const list = document.getElementById('xxx-highlight-list');
        if (!list) return;
        if (!highlights.length) { list.innerHTML = '<div style="padding:8px;color:#555;text-align:center;">No highlights</div>'; return; }
        list.innerHTML = highlights.map((w, i) => `<div class="xxx-word-item"><span title="${w}">⭐ ${w}</span><button data-i="${i}">×</button></div>`).join('');
        list.querySelectorAll('button').forEach(btn => btn.addEventListener('click', () => removeFromList(+btn.dataset.i, 'highlight')));
    }
    function updateCounter(h, hl) {
        const el = document.getElementById('xxx-counter');
        if (el) el.textContent = `Hidden: ${h} · ⭐ ${hl}`;
    }
    function updateFabBadge(hiddenCount, highlightCount) {
        const badge = document.getElementById('xxx-fab-badge');
        const badgeHl = document.getElementById('xxx-fab-badge-hl');
        if (badge) {
            if (hiddenCount > 0 && enabled) {
                badge.textContent = hiddenCount > 99 ? '99+' : String(hiddenCount);
                badge.style.display = 'flex';
                badge.title = hiddenCount + ' hidden';
            } else {
                badge.style.display = 'none';
            }
        }
        if (badgeHl) {
            if (highlightCount > 0 && highlightEnabled) {
                badgeHl.textContent = highlightCount > 99 ? '99+' : String(highlightCount);
                badgeHl.style.display = 'flex';
                badgeHl.title = highlightCount + ' highlighted';
            } else {
                badgeHl.style.display = 'none';
            }
        }
    }

    // ========== JSON BACKUP ==========
    function exportFullJson() {
        const data = {
            version: 1,
            exportedAt: new Date().toISOString(),
            exclusions: words,
            highlights: highlights,
            visited: [...visited],
            searchHistory: searchHistory,
            settings: {
                filterEnabled: enabled,
                invert: invert,
                highlightEnabled: highlightEnabled
            }
        };
        const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'club-enhancer-backup-' + new Date().toISOString().slice(0, 10) + '.json';
        document.body.appendChild(a);
        a.click();
        a.remove();
        URL.revokeObjectURL(url);

        const btn = document.getElementById('xxx-export-json');
        if (btn) {
            const o = btn.textContent;
            btn.textContent = 'Saved!';
            setTimeout(() => { btn.textContent = o; }, 1500);
        }
    }

    function importFullJson(file) {
        if (!file) return;
        const reader = new FileReader();
        reader.onload = () => {
            try {
                const data = JSON.parse(reader.result);
                if (!data || typeof data !== 'object') throw new Error('Invalid file');

                if (Array.isArray(data.exclusions)) {
                    words = saveList(STORAGE_KEY, data.exclusions);
                }
                if (Array.isArray(data.highlights)) {
                    highlights = saveList(HIGHLIGHT_KEY, data.highlights);
                }
                if (Array.isArray(data.visited)) {
                    visited = new Set(data.visited.map(String));
                    saveVisited();
                }
                if (Array.isArray(data.searchHistory)) {
                    searchHistory = data.searchHistory.map(String).filter(Boolean).slice(0, 10);
                    saveSearchHistory();
                    renderSidebarHistory();
                }
                if (data.settings && typeof data.settings === 'object') {
                    if (typeof data.settings.filterEnabled === 'boolean') {
                        enabled = data.settings.filterEnabled;
                        localStorage.setItem(ENABLED_KEY, enabled);
                        const cb = document.getElementById('xxx-enabled');
                        if (cb) cb.checked = enabled;
                    }
                    if (typeof data.settings.invert === 'boolean') {
                        invert = data.settings.invert;
                        localStorage.setItem(INVERT_KEY, invert);
                        const cb = document.getElementById('xxx-invert');
                        if (cb) cb.checked = invert;
                    }
                    if (typeof data.settings.highlightEnabled === 'boolean') {
                        highlightEnabled = data.settings.highlightEnabled;
                        localStorage.setItem(HIGHLIGHT_ENABLED_KEY, highlightEnabled);
                        const cb = document.getElementById('xxx-highlight-enabled');
                        if (cb) cb.checked = highlightEnabled;
                    }
                }

                renderWordList();
                renderHighlightList();
                applyAll();
                updateCollectionButtons();
                alert('Import complete.\nExclusions: ' + words.length +
                      '\nHighlights: ' + highlights.length +
                      '\nVisited: ' + visited.size +
                      '\nSearch history: ' + searchHistory.length);
            } catch (err) {
                console.error(err);
                alert('Import failed: ' + (err && err.message ? err.message : 'invalid JSON'));
            }
        };
        reader.readAsText(file);
    }

    function makeDraggable(el) {
        const header = el.querySelector('.xxx-header');
        let drag = false, sx, sy, sl, st;
        header.addEventListener('mousedown', e => {
            if (e.target.tagName === 'BUTTON') return;
            drag = true; sx = e.clientX; sy = e.clientY;
            const r = el.getBoundingClientRect();
            sl = r.left; st = r.top;
            el.style.right = 'auto'; el.style.bottom = 'auto';
            el.style.left = sl + 'px'; el.style.top = st + 'px';
            e.preventDefault();
        });
        document.addEventListener('mousemove', e => {
            if (!drag) return;
            el.style.left = (sl + e.clientX - sx) + 'px';
            el.style.top = (st + e.clientY - sy) + 'px';
        });
        document.addEventListener('mouseup', () => { drag = false; });
    }


    // ========== SITE SIDEBAR CLEANUP ==========
    function cleanSiteSidebar() {
        // Remove entire "Links" side-bar-list block
        document.querySelectorAll('.side-bar .side-bar-list').forEach(block => {
            const label = block.querySelector('label');
            const text = (label && label.textContent || '').toLowerCase();
            if (text.includes('links')) {
                block.style.display = 'none';
                return;
            }
            if (text.includes('categories')) {
                block.querySelectorAll('ul > li').forEach(li => {
                    const a = li.querySelector('a');
                    if (!a) return;
                    const href = a.getAttribute('href') || '';
                    const title = (a.getAttribute('title') || '') + ' ' + (a.textContent || '');
                    // Remove 480p, IMAGESET, Pack, VR
                    if (
                        href.includes('/browse/0/') ||
                        href.includes('/browse/5/') ||
                        href.includes('/browse/6/') ||
                        href.includes('/browse/7/') ||
                        /480p|imageset|pack\/megapack|virtualreality|\bvr\b/i.test(title)
                    ) {
                        li.style.display = 'none';
                    }
                });
            }
        });

        // Also hide matching items in header Categories dropdown
        document.querySelectorAll('#category-drop a, .catdrop a').forEach(a => {
            const href = a.getAttribute('href') || '';
            const title = (a.getAttribute('title') || '') + ' ' + (a.textContent || '');
            if (
                href.includes('/browse/0/') ||
                href.includes('/browse/5/') ||
                href.includes('/browse/6/') ||
                href.includes('/browse/7/') ||
                /480p|imageset|pack\/megapack|virtualreality|\bvr\b/i.test(title)
            ) {
                a.style.display = 'none';
            }
        });
    }

    // ========== INIT ==========
    function init() {
        if (!localStorage.getItem(STORAGE_KEY)) saveList(STORAGE_KEY, words);
        if (!localStorage.getItem(HIGHLIGHT_KEY)) saveList(HIGHLIGHT_KEY, highlights);

        injectStyles();
        setCircleFavicon();
        createUI();
        createSidebar();
        setupVisitedTracking();
        setupSearchFeatures();
        applyAll();
        addCollectionButtons();

        const observer = new MutationObserver(() => {
            clearTimeout(window.__xxxFilterTimeout);
            window.__xxxFilterTimeout = setTimeout(() => {
                applyAll();
                addCollectionButtons();
                cleanSiteSidebar();
            }, 150);
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    function safeInit() {
        try {
            init();
        } catch (err) {
            console.error('[The Club Enhancer] Error:', err);
        }
    }

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