Focus Engine | Pandemonium

A high‑end site blocker that locks your browser into focus mode or whitelist‑only mode. Designed for deep concentration when you absolutely cannot afford distractions.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Focus Engine | Pandemonium
// @namespace    https://github.com/ishaansucksatlife/Focus-Engine-Pandemonium
// @version      3.0
// @description  A high‑end site blocker that locks your browser into focus mode or whitelist‑only mode. Designed for deep concentration when you absolutely cannot afford distractions.
// @author       ishaansucksatlife
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @run-at       document-start
// @license      MIT
// @supportURL   https://github.com/ishaansucksatlife/Focus-Engine-Pandemonium/issues
// @homepageURL  https://github.com/ishaansucksatlife/Focus-Engine-Pandemonium
// ==/UserScript==

(function() {
    'use strict';

    // ==================== CONFIGURATION ====================
    const CONFIG = {
        VERSION: '3.0',
        KEY_PREFIX: 'pndm_v34_',
        VOID_ICON: 'data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 100 100\'%3E%3Ccircle cx=\'50\' cy=\'50\' r=\'45\' fill=\'%23000\' stroke=\'%230ff\' stroke-width=\'2\'/%3E%3Ccircle cx=\'50\' cy=\'50\' r=\'5\' fill=\'%230ff\'/%3E%3C/svg%3E',
        TIMER_UPDATE_INTERVAL: 1000,
        STORAGE_KEYS: ['bl', 'wl', 'deep', 'startTime']
    };

    // ==================== PERSISTENCE ====================
    const DB = {
        get: (key, defaultValue) => {
            try {
                const fullKey = CONFIG.KEY_PREFIX + key;
                const value = GM_getValue(fullKey, defaultValue);
                if (key === 'bl' || key === 'wl') return Array.isArray(value) ? value : [];
                if (key === 'deep') return typeof value === 'boolean' ? value : false;
                if (key === 'startTime') return (value === null || typeof value === 'number') ? value : null;
                return value;
            } catch {
                return defaultValue;
            }
        },
        set: (key, value) => {
            try {
                const fullKey = CONFIG.KEY_PREFIX + key;
                if ((key === 'bl' || key === 'wl') && !Array.isArray(value)) value = [];
                GM_setValue(fullKey, value);
                return true;
            } catch {
                return false;
            }
        },
        migrate: () => {
            try {
                GM_listValues().forEach(key => {
                    if (/^pndm_v(29|30|31|32|33)_/.test(key)) GM_deleteValue(key);
                });
            } catch {}
        }
    };

    // ==================== STATE ====================
    let pndm = {
        bl: DB.get('bl', []),
        wl: DB.get('wl', []),
        deep: DB.get('deep', false),
        startTime: DB.get('startTime', null)
    };
    let originalTitle = '';
    let shadow = null;
    let engineHost = null;
    let isInitialized = false;
    let animationFrame = null;
    let guiVisible = false;

    // ==================== HELPER FUNCTIONS ====================
    const getCurrentHost = () => window.location.hostname.toLowerCase().replace(/^www\./, '');

    const isMatched = (arr) => {
        const host = getCurrentHost();
        return arr.some(kw => kw && typeof kw === 'string' && host.includes(kw.toLowerCase().trim()));
    };

    const isBlocked = () => pndm.deep ? !isMatched(pndm.wl) : isMatched(pndm.bl);

    const getFlowTime = () => {
        if (!pndm.startTime || pndm.startTime > Date.now()) return "00:00:00";
        const diff = Date.now() - pndm.startTime;
        const h = Math.floor(diff / 3600000).toString().padStart(2, '0');
        const m = Math.floor((diff % 3600000) / 60000).toString().padStart(2, '0');
        const s = Math.floor((diff % 60000) / 1000).toString().padStart(2, '0');
        return `${h}:${m}:${s}`;
    };

    const getHostStatus = () => {
        const host = getCurrentHost();
        if (pndm.deep) return pndm.wl.includes(host) ? 'sanctuary' : 'void';
        return pndm.bl.includes(host) ? 'blackhole' : 'normal';
    };

    const isHostInCurrentList = () => {
        const host = getCurrentHost();
        return pndm.deep ? pndm.wl.includes(host) : pndm.bl.includes(host);
    };

    // Safe DOM operations
    const safeQS = (el, sel) => { try { return el ? el.querySelector(sel) : null; } catch { return null; } };
    const safeAdd = (el, ev, fn) => { if (el && typeof el.addEventListener === 'function') el.addEventListener(ev, fn); };

    // ==================== SHADOW DOM SETUP ====================
    const setupShadowDOM = () => {
        if (isInitialized) return;
        try {
            engineHost = document.createElement('div');
            engineHost.id = 'pndm-engine-host';
            engineHost.style.cssText = "position:fixed; top:0; left:0; width:0; height:0; z-index:2147483647; pointer-events:none;";
            (document.documentElement || document.body || document).appendChild(engineHost);
            shadow = engineHost.attachShadow({ mode: 'closed' });
            isInitialized = true;
        } catch {
            setTimeout(() => {
                if (!isInitialized && document.body) {
                    engineHost = document.createElement('div');
                    engineHost.id = 'pndm-engine-host-fallback';
                    engineHost.style.cssText = "position:fixed; top:0; left:0; width:0; height:0; z-index:2147483647;";
                    document.body.appendChild(engineHost);
                    shadow = engineHost.attachShadow({ mode: 'closed' });
                    isInitialized = true;
                }
            }, 0);
        }
    };

    // ==================== MASTER STYLESHEET ====================
    const createStyles = () => {
        const ss = new CSSStyleSheet();
        ss.replaceSync(`
            @import url('https://fonts.googleapis.com/css2?family=Inter:wght@200;400;700;900&display=swap');
            * { font-family: 'Inter', sans-serif; box-sizing: border-box; margin:0; padding:0; }

            /* ----- VOID OVERLAY (REDESIGNED) ----- */
            #pndm-void-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100vw;
                height: 100vh;
                background: radial-gradient(circle at 30% 30%, #0a0a0a, #000000);
                display: flex;
                align-items: center;
                justify-content: center;
                z-index: 2147483640;
                pointer-events: auto;
                color: #fff;
                animation: fadeIn 0.4s ease-out;
                overflow: hidden;
            }
            #pndm-void-overlay::before {
                content: '';
                position: absolute;
                top: -50%;
                left: -50%;
                width: 200%;
                height: 200%;
                background: repeating-radial-gradient(circle at 20% 30%, rgba(0,255,255,0.02) 0px, transparent 2px);
                animation: drift 20s linear infinite;
                pointer-events: none;
            }
            @keyframes drift {
                0% { transform: translate(0, 0); }
                100% { transform: translate(10%, 10%); }
            }
            #pndm-void-overlay .watermark {
                position: absolute;
                bottom: 20px;
                right: 30px;
                font-size: 12vw;
                font-weight: 900;
                color: rgba(0,255,255,0.02);
                letter-spacing: 20px;
                text-transform: uppercase;
                pointer-events: none;
                white-space: nowrap;
                user-select: none;
            }
            .void-card {
                background: rgba(10,10,10,0.7);
                backdrop-filter: blur(20px) saturate(180%);
                -webkit-backdrop-filter: blur(20px) saturate(180%);
                border: 1px solid rgba(0,255,255,0.2);
                border-radius: 60px;
                padding: 60px 80px;
                text-align: center;
                box-shadow: 0 40px 80px rgba(0,0,0,0.8), 0 0 0 2px rgba(0,255,255,0.1) inset;
                animation: float 6s ease-in-out infinite;
                max-width: 90vw;
            }
            @keyframes float {
                0% { transform: translateY(0px); }
                50% { transform: translateY(-10px); }
                100% { transform: translateY(0px); }
            }
            .void-title {
                font-size: 14px;
                font-weight: 900;
                letter-spacing: 12px;
                color: rgba(0,255,255,0.5);
                margin-bottom: 20px;
                text-transform: uppercase;
            }
            .void-message {
                font-size: clamp(32px, 8vw, 56px);
                font-weight: 200;
                line-height: 1.1;
                margin-bottom: 20px;
            }
            .void-timer {
                font-family: monospace;
                font-size: 24px;
                color: #0ff;
                background: rgba(0,255,255,0.1);
                display: inline-block;
                padding: 12px 30px;
                border-radius: 60px;
                border: 1px solid rgba(0,255,255,0.3);
                margin: 30px 0 20px;
                backdrop-filter: blur(5px);
            }
            .void-btn {
                background: transparent;
                border: 2px solid #0ff;
                color: #0ff;
                padding: 16px 48px;
                border-radius: 40px;
                font-weight: 700;
                font-size: 14px;
                letter-spacing: 3px;
                text-transform: uppercase;
                cursor: pointer;
                transition: all 0.3s;
                margin-top: 20px;
            }
            .void-btn:hover {
                background: #0ff;
                color: #000;
                transform: scale(1.05);
                box-shadow: 0 0 30px #0ff;
            }
            .void-btn:active {
                transform: scale(0.98);
            }
            .void-hint {
                color: #444;
                font-size: 11px;
                margin-top: 30px;
                letter-spacing: 1px;
            }

            /* ----- GUI (unchanged from previous perfection) ----- */
            #pndm-gui-wrapper {
                position:fixed; top:0; left:0; width:100vw; height:100vh;
                background:rgba(0,0,0,0.85); backdrop-filter:blur(50px);
                display:none; align-items:center; justify-content:center;
                z-index:2147483646; pointer-events:auto; animation:fadeIn 0.2s;
            }
            #pndm-modal {
                width:min(900px,95vw); height:min(600px,90vh);
                background:rgba(15,15,15,0.98); border-radius:40px;
                border:1px solid rgba(255,255,255,0.08); display:flex; overflow:hidden;
                color:#fff; box-shadow:0 60px 120px #000;
            }
            #side { width:240px; background:rgba(0,0,0,0.4); border-right:1px solid rgba(255,255,255,0.05); padding:60px 0; display:flex; flex-direction:column; }
            .side-header { padding:0 45px 60px; font-weight:900; letter-spacing:6px; font-size:11px; color:#0ff; }
            .tab { padding:20px 45px; cursor:pointer; color:#555; font-weight:700; font-size:10px; letter-spacing:3px; border:none; background:none; text-align:left; transition:all 0.4s; text-transform:uppercase; outline:none; }
            .tab:hover { color:#0ff; background:linear-gradient(90deg,rgba(0,255,255,0.02) 0%,transparent); }
            .tab.active { color:#0ff; background:linear-gradient(90deg,rgba(0,255,255,0.08) 0%,transparent); border-right:4px solid #0ff; }
            .pane { display:none; flex:1; padding:40px; position:relative; flex-direction:column; overflow-y:auto; }
            .pane.active { display:flex; }
            .pane-title { font-size:28px; font-weight:900; letter-spacing:-1px; margin-bottom:5px; }
            .pane-subtitle { color:#666; font-size:12px; margin-bottom:20px; }
            .host-badge { display:inline-block; padding:4px 12px; border-radius:20px; font-size:10px; font-weight:700; letter-spacing:1px; text-transform:uppercase; margin-left:10px; }
            .badge-blackhole { background:rgba(255,59,48,0.2); color:#ff3b30; border:1px solid rgba(255,59,48,0.3); }
            .badge-sanctuary { background:rgba(0,255,255,0.2); color:#0ff; border:1px solid rgba(0,255,255,0.3); }
            .badge-normal { background:rgba(255,255,255,0.1); color:#888; border:1px solid rgba(255,255,255,0.1); }
            .badge-void { background:rgba(255,255,255,0.05); color:#444; border:1px solid rgba(255,255,255,0.05); }
            .switch { position:relative; display:inline-block; width:52px; height:28px; }
            .switch input { opacity:0; width:0; height:0; }
            .slider { position:absolute; cursor:pointer; top:0; left:0; right:0; bottom:0; background-color:rgba(255,255,255,0.15); transition:.3s; border-radius:34px; border:1px solid rgba(255,255,255,0.1); }
            .slider:before { position:absolute; content:""; height:20px; width:20px; left:4px; bottom:3px; background-color:white; transition:.3s; border-radius:50%; }
            input:checked + .slider { background-color:#0ff; }
            input:checked + .slider:before { transform:translateX(24px); background-color:#000; }
            .input-box { background:rgba(255,255,255,0.03); border:1px solid rgba(255,255,255,0.08); padding:16px; color:#fff; border-radius:15px; width:100%; outline:none; font-size:14px; transition:all 0.3s; margin-bottom:20px; }
            .input-box:focus { border-color:#0ff; background:rgba(0,255,255,0.05); box-shadow:0 0 0 3px rgba(0,255,255,0.1); }
            .list-container { margin-top:10px; overflow-y:auto; flex:1; border-radius:16px; background:rgba(0,0,0,0.2); padding:10px; }
            .list-item { display:flex; justify-content:space-between; align-items:center; padding:12px 15px; border-bottom:1px solid rgba(255,255,255,0.03); color:#aaa; font-size:13px; transition:background 0.2s; border-radius:8px; }
            .list-item:hover { background:rgba(255,255,255,0.03); }
            .rmv-btn { color:#ff3b30; cursor:pointer; font-weight:bold; font-size:18px; opacity:0.5; transition:0.2s; width:28px; height:28px; display:flex; align-items:center; justify-content:center; border-radius:50%; }
            .rmv-btn:hover { opacity:1; background:rgba(255,59,48,0.15); }
            .action-btn { width:100%; padding:18px; border-radius:16px; border:1px solid; font-weight:800; font-size:11px; cursor:pointer; text-transform:uppercase; transition:all 0.3s; letter-spacing:1.5px; margin-bottom:12px; overflow:hidden; }
            .btn-reload { background:rgba(255,255,255,0.03); border-color:rgba(255,255,255,0.1); color:#fff; }
            .btn-reload:hover { background:rgba(255,255,255,0.1); transform:translateY(-1px); }
            .btn-primary { border-color:#0ff; background:transparent; color:#0ff; }
            .btn-primary:hover { background:#0ff; color:#000; transform:translateY(-2px); box-shadow:0 10px 30px rgba(0,255,255,0.2); }
            .btn-success { border-color:#00ff00; background:transparent; color:#00ff00; }
            .btn-success:hover { background:#00ff00; color:#000; transform:translateY(-2px); box-shadow:0 10px 30px rgba(0,255,0,0.2); }
            .btn-danger { border-color:#ff3b30; background:transparent; color:#ff3b30; }
            .btn-danger:hover { background:#ff3b30; color:#000; transform:translateY(-2px); box-shadow:0 10px 30px rgba(255,59,48,0.2); }
            .btn-group { display:flex; gap:10px; margin-top:20px; }
            .btn-group .action-btn { margin-bottom:0; flex:1; }
            #led { width:12px; height:12px; border-radius:50%; box-shadow:0 0 20px; position:fixed; bottom:40px; right:40px; z-index:2147483648; animation:pulse 2s infinite; display:block; pointer-events:none; }
            #led.deep-active { background:#00ff00; box-shadow:0 0 20px #00ff00; }
            #led.normal { background:#0ff; box-shadow:0 0 20px #0ff; }
            @keyframes pulse { 0% { opacity:1; transform:scale(1); } 50% { opacity:0.5; transform:scale(0.8); } 100% { opacity:1; transform:scale(1); } }
            .close-x { position:absolute; top:20px; right:20px; background:none; border:none; color:#666; font-size:28px; cursor:pointer; transition:0.2s; width:40px; height:40px; display:flex; align-items:center; justify-content:center; border-radius:50%; z-index:10; }
            .close-x:hover { color:#fff; background:rgba(255,255,255,0.1); }
            .host-info { background:rgba(0,255,255,0.03); padding:20px; border-radius:20px; border:1px solid rgba(0,255,255,0.1); margin-bottom:25px; transition:all 0.3s; }
            .host-url { font-family:monospace; font-size:14px; color:#0ff; word-break:break-all; margin-bottom:10px; }
            .status-chip { display:inline-flex; align-items:center; gap:8px; padding:6px 16px; border-radius:30px; font-size:12px; font-weight:600; text-transform:uppercase; transition:all 0.3s; }
            .timer-display { background:rgba(0,255,255,0.02); padding:30px; border-radius:24px; border:1px solid rgba(0,255,255,0.08); text-align:center; }
            .timer-value { font-size:48px; font-weight:200; letter-spacing:-2px; font-family:monospace; color:#0ff; }
            .timer-label { color:#0ff; font-weight:900; font-size:10px; letter-spacing:2px; margin-bottom:5px; }
            .empty-state { text-align:center; color:#444; padding:40px 20px; font-size:12px; letter-spacing:1px; }
            .toast-message { position:fixed; bottom:30px; left:50%; transform:translateX(-50%); background:rgba(0,255,255,0.9); color:#000; padding:12px 24px; border-radius:40px; font-size:12px; font-weight:700; letter-spacing:1px; z-index:2147483649; animation:slideUp 0.3s; box-shadow:0 10px 30px rgba(0,255,255,0.3); }
            @keyframes slideUp { from { opacity:0; transform:translate(-50%,20px); } to { opacity:1; transform:translate(-50%,0); } }
        `);
        return ss;
    };

    // ==================== TOAST ====================
    const showToast = (msg, isErr = false) => {
        if (!shadow) return;
        const toast = document.createElement('div');
        toast.className = 'toast-message';
        toast.textContent = msg;
        toast.style.background = isErr ? 'rgba(255,59,48,0.9)' : 'rgba(0,255,255,0.9)';
        shadow.appendChild(toast);
        setTimeout(() => {
            if (toast.parentNode) {
                toast.style.animation = 'fadeIn 0.3s reverse';
                setTimeout(() => toast.remove(), 200);
            }
        }, 2000);
    };

    // ==================== MUTUAL EXCLUSIVITY ====================
    const addKeywordExclusive = (keyword, targetList) => {
        keyword = keyword.toLowerCase().trim();
        if (!keyword) return false;
        const other = targetList === 'bl' ? 'wl' : 'bl';
        if (pndm[targetList].includes(keyword)) {
            showToast(`⚠️ Already in ${targetList === 'bl' ? 'Blackhole' : 'Sanctuary'}`, true);
            return false;
        }
        if (pndm[other].includes(keyword)) {
            pndm[other] = pndm[other].filter(k => k !== keyword);
            showToast(`⚠️ Moved from ${other === 'bl' ? 'Blackhole' : 'Sanctuary'}`);
        }
        pndm[targetList] = [...pndm[targetList], keyword];
        return true;
    };

    const removeKeyword = (keyword, list) => {
        if (!pndm[list].includes(keyword)) return false;
        pndm[list] = pndm[list].filter(k => k !== keyword);
        return true;
    };

    // ==================== GUI CREATION ====================
    const createGUI = () => {
        if (!shadow) return;
        try {
            while (shadow.firstChild) shadow.removeChild(shadow.firstChild);

            const host = getCurrentHost();
            const status = getHostStatus();
            const inList = isHostInCurrentList();

            const wrapper = document.createElement('div');
            wrapper.id = 'pndm-gui-wrapper';
            wrapper.innerHTML = `
                <div id="pndm-modal">
                    <div id="side">
                        <div class="side-header">PANDEMONIUM</div>
                        <button class="tab active" data-t="dash">FLOW_STATE</button>
                        <button class="tab" data-t="bl">BLACKHOLE <span style="color:#0ff; margin-left:5px;">${pndm.bl.length}</span></button>
                        <button class="tab" data-t="wl">SANCTUARY <span style="color:#0ff; margin-left:5px;">${pndm.wl.length}</span></button>
                    </div>
                    <div id="main-content" style="flex:1; display:flex;">
                        <!-- Dashboard -->
                        <div id="pane-dash" class="pane active">
                            <button class="close-x" id="close-gui">×</button>
                            <h2 class="pane-title">Flow State</h2>
                            <div class="pane-subtitle">Current session metrics</div>
                            <div class="host-info" id="host-info-panel">
                                <div class="host-url">${host}</div>
                                <div id="status-chip" class="status-chip ${status === 'blackhole' ? 'badge-blackhole' : status === 'sanctuary' ? 'badge-sanctuary' : status === 'void' ? 'badge-void' : 'badge-normal'}">
                                    <span>●</span><span id="status-text">${status.toUpperCase()}</span>
                                </div>
                            </div>
                            <div style="margin-bottom:25px;">
                                <div style="display:flex; justify-content:space-between; align-items:center; background:rgba(255,255,255,0.02); padding:20px; border-radius:20px; border:1px solid rgba(255,255,255,0.05);">
                                    <div><div style="font-weight:700; margin-bottom:5px;">Deep Focus Mode</div><div style="color:#666; font-size:12px;">Lock session to Sanctuary only</div></div>
                                    <label class="switch"><input type="checkbox" id="deep-tog" ${pndm.deep ? 'checked' : ''}><span class="slider"></span></label>
                                </div>
                            </div>
                            <div class="timer-display"><div class="timer-label">SESSION CHRONO</div><div class="timer-value" id="gui-timer">${getFlowTime()}</div></div>
                            <div class="btn-group">
                                <button id="reload-btn" class="action-btn btn-reload">⟳ RELOAD</button>
                                <button id="toggle-host-btn" class="action-btn ${inList ? 'btn-danger' : 'btn-primary'}">${inList ? '⚡ RELEASE' : '🌀 ABSORB'}</button>
                            </div>
                        </div>
                        <!-- Blackhole -->
                        <div id="pane-bl" class="pane">
                            <h2 class="pane-title">Blackhole</h2>
                            <div class="pane-subtitle">Sites to consume <span style="color:#0ff;">${pndm.bl.length}</span></div>
                            <input type="text" id="bl-in" class="input-box" placeholder="Add keyword... (press Enter)" autocomplete="off">
                            <div class="btn-group" style="margin-bottom:15px;">
                                <button id="bl-add-current" class="action-btn btn-primary">➕ ADD CURRENT SITE</button>
                                <button id="bl-remove-current" class="action-btn btn-danger" ${!pndm.bl.includes(host) ? 'disabled style="opacity:0.3; pointer-events:none;"' : ''}>✖️ REMOVE CURRENT</button>
                            </div>
                            <div id="bl-list" class="list-container"></div>
                            ${pndm.bl.length ? '<button id="clear-bl" class="action-btn btn-danger" style="margin-top:15px;">🗑️ CLEAR ALL</button>' : ''}
                        </div>
                        <!-- Sanctuary -->
                        <div id="pane-wl" class="pane">
                            <h2 class="pane-title">Sanctuary</h2>
                            <div class="pane-subtitle">Protected sites <span style="color:#0ff;">${pndm.wl.length}</span></div>
                            <input type="text" id="wl-in" class="input-box" placeholder="Add keyword... (press Enter)" autocomplete="off">
                            <div class="btn-group" style="margin-bottom:15px;">
                                <button id="wl-add-current" class="action-btn btn-success">➕ ADD CURRENT SITE</button>
                                <button id="wl-remove-current" class="action-btn btn-danger" ${!pndm.wl.includes(host) ? 'disabled style="opacity:0.3; pointer-events:none;"' : ''}>✖️ REMOVE CURRENT</button>
                            </div>
                            <div id="wl-list" class="list-container"></div>
                            ${pndm.wl.length ? '<button id="clear-wl" class="action-btn btn-danger" style="margin-top:15px;">🗑️ CLEAR ALL</button>' : ''}
                        </div>
                    </div>
                </div>
                <div id="led" class="${pndm.deep ? 'deep-active' : 'normal'}" title="${pndm.deep ? 'Deep Focus Active' : 'Normal Mode'}"></div>
            `;

            shadow.adoptedStyleSheets = [createStyles()];
            shadow.appendChild(wrapper);

            // --- Event listeners ---
            safeAdd(safeQS(shadow, '#close-gui'), 'click', toggleGUI);
            safeAdd(safeQS(shadow, '#reload-btn'), 'click', () => { showToast('⟳ Reloading...'); setTimeout(() => location.reload(), 100); });

            const toggleBtn = safeQS(shadow, '#toggle-host-btn');
            if (toggleBtn) safeAdd(toggleBtn, 'click', () => {
                const h = getCurrentHost();
                const list = pndm.deep ? 'wl' : 'bl';
                const display = pndm.deep ? 'Sanctuary' : 'Blackhole';
                if (pndm[list].includes(h)) {
                    pndm[list] = pndm[list].filter(x => x !== h);
                    showToast(`⚡ Released from ${display}`);
                } else if (addKeywordExclusive(h, list)) {
                    showToast(`🌀 Absorbed into ${display}`);
                }
                save(); enforceVoid(); updateDynamicUI(); renderLists();
            });

            const deepTog = safeQS(shadow, '#deep-tog');
            if (deepTog) safeAdd(deepTog, 'change', (e) => {
                pndm.deep = e.target.checked;
                save(); enforceVoid(); updateDynamicUI();
                showToast(pndm.deep ? '🔮 Deep Focus ACTIVE' : '🌐 Deep Focus inactive');
            });

            // Blackhole buttons
            const blAdd = safeQS(shadow, '#bl-add-current');
            if (blAdd) safeAdd(blAdd, 'click', () => {
                const h = getCurrentHost();
                if (addKeywordExclusive(h, 'bl')) {
                    save(); enforceVoid(); updateDynamicUI(); renderLists();
                    showToast(`🌀 Added "${h}" to Blackhole`);
                }
            });
            const blRemove = safeQS(shadow, '#bl-remove-current');
            if (blRemove) safeAdd(blRemove, 'click', () => {
                const h = getCurrentHost();
                if (removeKeyword(h, 'bl')) {
                    save(); enforceVoid(); updateDynamicUI(); renderLists();
                    showToast(`✖️ Removed "${h}" from Blackhole`);
                }
            });

            // Sanctuary buttons
            const wlAdd = safeQS(shadow, '#wl-add-current');
            if (wlAdd) safeAdd(wlAdd, 'click', () => {
                const h = getCurrentHost();
                if (addKeywordExclusive(h, 'wl')) {
                    save(); enforceVoid(); updateDynamicUI(); renderLists();
                    showToast(`✨ Added "${h}" to Sanctuary`);
                }
            });
            const wlRemove = safeQS(shadow, '#wl-remove-current');
            if (wlRemove) safeAdd(wlRemove, 'click', () => {
                const h = getCurrentHost();
                if (removeKeyword(h, 'wl')) {
                    save(); enforceVoid(); updateDynamicUI(); renderLists();
                    showToast(`✖️ Removed "${h}" from Sanctuary`);
                }
            });

            // Clear buttons
            const clearBl = safeQS(shadow, '#clear-bl');
            if (clearBl) safeAdd(clearBl, 'click', () => { pndm.bl = []; save(); renderLists(); updateDynamicUI(); showToast('🗑️ Blackhole cleared'); });
            const clearWl = safeQS(shadow, '#clear-wl');
            if (clearWl) safeAdd(clearWl, 'click', () => { pndm.wl = []; save(); renderLists(); updateDynamicUI(); showToast('🗑️ Sanctuary cleared'); });

            // Tab switching
            shadow.querySelectorAll('.tab').forEach(tab => safeAdd(tab, 'click', () => {
                shadow.querySelectorAll('.tab, .pane').forEach(el => el.classList.remove('active'));
                tab.classList.add('active');
                const pane = shadow.getElementById(`pane-${tab.dataset.t}`);
                if (pane) pane.classList.add('active');
            }));

            // Input handlers
            const setupInput = (id, list, display) => {
                const inp = safeQS(shadow, id);
                if (inp) safeAdd(inp, 'keydown', (e) => {
                    if (e.key === 'Enter' && e.target.value.trim()) {
                        e.preventDefault();
                        const val = e.target.value.trim().toLowerCase();
                        if (addKeywordExclusive(val, list)) {
                            e.target.value = '';
                            save(); renderLists(); updateDynamicUI();
                            showToast(`✨ Added "${val}" to ${display}`);
                        }
                    }
                });
            };
            setupInput('#bl-in', 'bl', 'Blackhole');
            setupInput('#wl-in', 'wl', 'Sanctuary');

            renderLists();
            updateDynamicUI();
        } catch (e) { console.error('[Pandemonium] GUI error:', e); }
    };

    // ==================== RENDER LISTS ====================
    const renderLists = () => {
        if (!shadow) return;
        const render = (items, containerId, listName) => {
            const container = safeQS(shadow, containerId);
            if (!container) return;
            if (!items.length) { container.innerHTML = '<div class="empty-state">✨ No keywords added yet</div>'; return; }
            container.innerHTML = items.map(item => `<div class="list-item"><span style="word-break:break-word;">${escapeHTML(item)}</span><span class="rmv-btn" data-value="${escapeHTML(item)}" data-list="${listName}">×</span></div>`).join('');
            container.querySelectorAll('.rmv-btn').forEach(btn => safeAdd(btn, 'click', (e) => {
                e.stopPropagation();
                const val = btn.dataset.value, list = btn.dataset.list;
                if (val && list && pndm[list]) {
                    pndm[list] = pndm[list].filter(k => k !== val);
                    save(); renderLists(); updateDynamicUI();
                    showToast(`✖️ Removed "${val}" from ${list === 'bl' ? 'Blackhole' : 'Sanctuary'}`);
                }
            }));
        };
        render(pndm.bl, '#bl-list', 'bl');
        render(pndm.wl, '#wl-list', 'wl');
    };

    const escapeHTML = (str) => String(str).replace(/[&<>"']/g, m => ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#039;' })[m]);

    // ==================== DYNAMIC UI UPDATE ====================
    const updateDynamicUI = () => {
        if (!shadow || !guiVisible) return;
        try {
            const host = getCurrentHost();
            const status = getHostStatus();
            const inList = isHostInCurrentList();

            const statusChip = safeQS(shadow, '#status-chip');
            const statusText = safeQS(shadow, '#status-text');
            if (statusChip && statusText) {
                statusChip.className = `status-chip ${
                    status === 'blackhole' ? 'badge-blackhole' : status === 'sanctuary' ? 'badge-sanctuary' : status === 'void' ? 'badge-void' : 'badge-normal'
                }`;
                statusText.textContent = status.toUpperCase();
            }

            const toggleBtn = safeQS(shadow, '#toggle-host-btn');
            if (toggleBtn) {
                toggleBtn.textContent = inList ? '⚡ RELEASE' : '🌀 ABSORB';
                toggleBtn.className = `action-btn ${inList ? 'btn-danger' : 'btn-primary'}`;
            }

            const deepTog = safeQS(shadow, '#deep-tog');
            if (deepTog) deepTog.checked = pndm.deep;

            // Tab counters
            const blTab = Array.from(shadow.querySelectorAll('.tab')).find(t => t.dataset.t === 'bl');
            const wlTab = Array.from(shadow.querySelectorAll('.tab')).find(t => t.dataset.t === 'wl');
            if (blTab) {
                let span = blTab.querySelector('span');
                if (!span) { span = document.createElement('span'); blTab.appendChild(span); }
                span.textContent = pndm.bl.length;
                span.style.cssText = "color:#0ff; margin-left:5px;";
            }
            if (wlTab) {
                let span = wlTab.querySelector('span');
                if (!span) { span = document.createElement('span'); wlTab.appendChild(span); }
                span.textContent = pndm.wl.length;
                span.style.cssText = "color:#0ff; margin-left:5px;";
            }

            // LED
            const led = safeQS(shadow, '#led');
            if (led) {
                led.className = pndm.deep ? 'deep-active' : 'normal';
                led.title = pndm.deep ? 'Deep Focus Active' : 'Normal Mode';
            }

            // Enable/disable remove buttons
            const blRemove = safeQS(shadow, '#bl-remove-current');
            if (blRemove) {
                if (pndm.bl.includes(host)) { blRemove.disabled = false; blRemove.style.opacity = ''; blRemove.style.pointerEvents = ''; }
                else { blRemove.disabled = true; blRemove.style.opacity = '0.3'; blRemove.style.pointerEvents = 'none'; }
            }
            const wlRemove = safeQS(shadow, '#wl-remove-current');
            if (wlRemove) {
                if (pndm.wl.includes(host)) { wlRemove.disabled = false; wlRemove.style.opacity = ''; wlRemove.style.pointerEvents = ''; }
                else { wlRemove.disabled = true; wlRemove.style.opacity = '0.3'; wlRemove.style.pointerEvents = 'none'; }
            }
        } catch (e) { console.error('[Pandemonium] UI update error:', e); }
    };

    // ==================== GUI TOGGLE ====================
    const toggleGUI = () => {
        if (!shadow) return;
        try {
            const wrapper = safeQS(shadow, '#pndm-gui-wrapper');
            if (!wrapper) { createGUI(); setTimeout(() => { const w = safeQS(shadow, '#pndm-gui-wrapper'); if (w) { w.style.display = 'flex'; guiVisible = true; updateDynamicUI(); renderLists(); } }, 50); return; }
            guiVisible = wrapper.style.display !== 'flex';
            wrapper.style.display = guiVisible ? 'flex' : 'none';
            if (guiVisible) { updateDynamicUI(); renderLists(); }
        } catch (e) { console.error('[Pandemonium] Toggle error:', e); }
    };

    // ==================== SYNC GUI (TIMER) ====================
    const syncGUI = () => {
        if (!shadow) return;
        if (guiVisible) {
            const t = safeQS(shadow, '#gui-timer');
            if (t) t.textContent = getFlowTime();
        }
        const vt = safeQS(shadow, '#v-time');
        if (vt) vt.textContent = getFlowTime();
    };

    // ==================== IMPROVED VOID OVERLAY ====================
    const ensureVoidOverlay = () => {
        if (!shadow) return;
        let overlay = safeQS(shadow, '#pndm-void-overlay');
        if (!overlay) {
            overlay = document.createElement('div');
            overlay.id = 'pndm-void-overlay';
            overlay.innerHTML = `
                <div class="watermark">PANDEMONIUM</div>
                <div class="void-card">
                    <div class="void-title">FOCUS ENGINE</div>
                    <div class="void-message">Void Protocol Active</div>
                    <div class="void-timer" id="v-time">${getFlowTime()}</div>
                    <button class="void-btn" id="v-open">OPEN SANCTUARY</button>
                    <div class="void-hint">Alt+S to open panel</div>
                </div>
            `;
            shadow.appendChild(overlay);
            safeAdd(safeQS(shadow, '#v-open'), 'click', (e) => { e.stopPropagation(); toggleGUI(); });
        }
        const timerSpan = safeQS(shadow, '#v-time');
        if (timerSpan) timerSpan.textContent = getFlowTime();
    };

    // ==================== VOID ENFORCEMENT ====================
    const enforceVoid = () => {
        if (!isInitialized) return;
        try {
            const blocked = isBlocked();
            if (blocked) {
                if (!pndm.startTime) { pndm.startTime = Date.now(); DB.set('startTime', pndm.startTime); }
                // Nuke page content
                if (document.body) {
                    Array.from(document.body.children).forEach(child => {
                        if (child !== engineHost && child.id !== 'pndm-engine-host-fallback') child.remove();
                    });
                    document.body.style.cssText = 'background:#020202!important; overflow:hidden!important; margin:0!important; padding:0!important; height:100vh!important; width:100vw!important;';
                }
                document.title = `⏳ ${getFlowTime()} | Pandemonium`;
                try {
                    let link = document.querySelector("link[rel*='icon']") || document.createElement('link');
                    if (!link.parentNode) { link.rel = 'icon'; document.head.appendChild(link); }
                    link.href = CONFIG.VOID_ICON;
                } catch {}

                if (shadow) ensureVoidOverlay();
            } else {
                if (shadow) {
                    const ov = safeQS(shadow, '#pndm-void-overlay');
                    if (ov) ov.remove();
                }
                if (pndm.startTime) { pndm.startTime = null; DB.set('startTime', null); document.title = originalTitle; }
                if (document.body) document.body.style.cssText = '';
            }
        } catch (e) { console.error('[Pandemonium] Enforcement error:', e); }
    };

    // ==================== SAVE STATE ====================
    const save = () => {
        try {
            DB.set('bl', pndm.bl);
            DB.set('wl', pndm.wl);
            DB.set('deep', pndm.deep);
            DB.set('startTime', pndm.startTime);
        } catch {}
    };

    // ==================== INITIALIZATION ====================
    const init = () => {
        try {
            originalTitle = document.title;
            DB.migrate();
            setupShadowDOM();
            if (isInitialized) createGUI();
            const loop = () => { enforceVoid(); animationFrame = requestAnimationFrame(loop); };
            loop();
            setInterval(syncGUI, CONFIG.TIMER_UPDATE_INTERVAL);
            window.addEventListener('keydown', (e) => {
                if (e.altKey && e.code === 'KeyS' && !e.ctrlKey && !e.metaKey) {
                    e.preventDefault(); e.stopPropagation(); toggleGUI();
                }
            }, true);
            console.log('[Pandemonium] v34.0 ready');
        } catch (e) { console.error('[Pandemonium] Init error:', e); }
    };

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

    window.addEventListener('beforeunload', () => { if (animationFrame) cancelAnimationFrame(animationFrame); });
})();