bygone-yt

youtube time-machine. pick a date, see videos from that era. filters out all videos made after that date. V3 VORAPIS REQUIRED!

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Advertisement:

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

Advertisement:

// ==UserScript==
// @name         bygone-yt
// @namespace    http://tampermonkey.net/
// @license      MIT
// @version      472
// @description  youtube time-machine. pick a date, see videos from that era. filters out all videos made after that date. V3 VORAPIS REQUIRED!
// @author       relicofatime
// @match        https://www.youtube.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_addStyle
// @grant        GM_info
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @connect      youtube.com
// @connect      greasyfork.org
// @connect      update.greasyfork.org
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    const SCRIPT_VERSION = 472;

    let _v3Detected = false;
    function _checkV3() {
        if (_v3Detected) return true;
        const mark = () => { _v3Detected = true; return true; };
        const RX = /vlturbo|vorapis|turbopipe/i;
        const de = document.documentElement;
        try {
            if (de.hasAttribute('v3') || de.hasAttribute('vorapis')) return mark();
            for (const a of de.attributes) {
                if (a.name === 'v3' || RX.test(a.name) || RX.test(a.value || '')) return mark();
            }
            if (RX.test(de.className || '')) return mark();
        } catch (_) {}
        try {
            for (let i = 0; i < localStorage.length; i++) {
                const k = localStorage.key(i);
                if (k && (RX.test(k) || /^v3[_-]/i.test(k))) return mark();
            }
        } catch (_) {}
        try {
            const pw = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
            for (const w of [pw, window]) {
                if (w && (w.PatcherJSC_TURBOPIPE || w.VLTURBO || w.VORAPIS)) return mark();
            }
        } catch (_) {}
        try {
            if (document.querySelector('.lohp-large-shelf-container, .lohp-medium-shelf, ' +
                'ytm-browse, [class*="vorapis" i], [id*="vorapis" i], [class*="vlturbo" i]')) return mark();
        } catch (_) {}
        return false;
    }

    function _checkStarTube() {
        try {
            const pw = (typeof unsafeWindow !== 'undefined' && unsafeWindow) || window;
            if (pw.globalDataPoints || window.globalDataPoints || document.globalDataPoints) return true;
            if (localStorage.getItem('ST_STABLE_SETTINGS')) return true;
            if (localStorage.getItem('starTubeConfigCreated')) return true;
        } catch (_) {}
        return !!document.querySelector(
            '#startube-settings-window-entity, #startube-settings-window, ' +
            '#st-watch-below, #st-actions-info-row, [id^="st-"], [class^="st-"], [class*=" st-"]'
        );
    }

    function _isKioskOrMobileLayout() {
        if (_isKioskOrMobileLayout._latched) return true;
        try {
            const ua = (navigator && navigator.userAgent) || '';
            if (/Android|Mobile|Tablet|iPhone|iPad|iPod/i.test(ua)) {
                _isKioskOrMobileLayout._latched = true;
                return true;
            }
        } catch (_) {}
        try {
            if (document.getElementById('bygone-kiosk-bottom-nav')) {
                _isKioskOrMobileLayout._latched = true;
                return true;
            }
        } catch (_) {}
        return false;
    }

    function _kioskEffectiveWidth() {
        const vals = [];
        const add = (v) => {
            const n = Number(v);
            if (Number.isFinite(n) && n > 0) vals.push(n);
        };
        try { add(window.innerWidth); } catch (_) {}
        try { add(document.documentElement && document.documentElement.clientWidth); } catch (_) {}
        try { add(window.visualViewport && window.visualViewport.width); } catch (_) {}
        try {
            if (window.screen) {
                add(window.screen.width);
                add(window.screen.height);
                add(window.screen.availWidth);
                add(window.screen.availHeight);
            }
        } catch (_) {}
        return vals.length ? Math.min.apply(null, vals) : 0;
    }

    function _kioskVisibleWidth() {
        const vals = [];
        const add = (v) => {
            const n = Number(v);
            if (Number.isFinite(n) && n > 0) vals.push(n);
        };
        try { add(window.visualViewport && window.visualViewport.width); } catch (_) {}
        try { add(document.documentElement && document.documentElement.clientWidth); } catch (_) {}
        try { add(window.innerWidth); } catch (_) {}
        try { if (!vals.length && window.screen) add(window.screen.width); } catch (_) {}
        return vals.length ? Math.min.apply(null, vals) : 0;
    }

    const Interceptor = (() => {
        const POOL_LS_KEY = 'bygone_v3_pool';
        try {
            const lastVersion = (typeof GM_getValue === 'function') ? Number(GM_getValue('bygone_last_version', 0)) : 0;
            if (!Number.isFinite(lastVersion) || lastVersion < SCRIPT_VERSION) {
                localStorage.removeItem(POOL_LS_KEY);
                localStorage.removeItem('wbt_v3_pool');
            }
        } catch (_) {}
        try {
            const old = localStorage.getItem('wbt_v3_pool');
            if (old && !localStorage.getItem(POOL_LS_KEY)) localStorage.setItem(POOL_LS_KEY, old);
        } catch (_) {}
        let videoPool = [];
        let active = false;
        let _userPaused = false;
        let _poolReadyCbs = [];
        function _onPoolReady(fn) { if (active && videoPool.length) fn(); else _poolReadyCbs.push(fn); }
        function _firePoolReady() { for (const fn of _poolReadyCbs) try { fn(); } catch (_) {} _poolReadyCbs = []; }

        const _idMap = new Map();
        const _usedReplacements = new Set();
        let _sweepStats = {};
        let _lastHomeChannelPromoPruned = 0;
        let _lastHomeChannelPromoLeft = 0;
        let _responseSeen = new Set();
        let _displayedIdsCache = null;
        let _poolIdsSet = new Set();
        const _keptNaturalIds = new Set();
        let _poolCursor = 0;

        function startResponseScope() {
            _responseSeen = new Set();
            _displayedIdsCache = null;
        }

        let BYGONE_DEBUG = false, BYGONE_NO_POKE = false;
        try { BYGONE_DEBUG = localStorage.getItem('bygone_debug') === '1'; } catch (_) {}
        try { BYGONE_NO_POKE = localStorage.getItem('bygone_no_poke') === '1'; } catch (_) {}
        try {
            const pw = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
            if (pw && pw.__bygoneDebug) BYGONE_DEBUG = true;
        } catch (_) {}

        const _navT0 = Date.now();
        let _navTrace = [];
        try {
            const _raw = sessionStorage.getItem('bygone_nav_trace');
            if (_raw) { const _p = JSON.parse(_raw); if (Array.isArray(_p)) _navTrace = _p; }
        } catch (_) {}
        const _NAV_TRACE_CAP = 40;
        let _settledTimer = null;

        function _sidebarCardCount() {
            try {
                const ids = new Set();
                ['watch7-sidebar-contents', 'watch7-sidebar', 'related', 'secondary', 'secondary-inner']
                    .forEach(id => {
                        const c = document.getElementById(id);
                        if (!c) return;
                        c.querySelectorAll('a[href*="/watch?v="]').forEach(a => {
                            const m = (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]{11})/);
                            if (m) ids.add(m[1]);
                        });
                    });
                return ids.size;
            } catch (_) { return -1; }
        }

        function _navState() {
            const path = location.pathname;
            const onWatch = path.startsWith('/watch');
            const onHome = path === '/' || path === '';
            let cards = -1, sidebar = -1;
            try { cards = _findCards(document).length; } catch (_) {}
            if (onWatch) sidebar = _sidebarCardCount();
            const looksBroken = (onHome && cards >= 0 && cards < 5) || (onWatch && sidebar === 0);
            return {
                path, search: location.search, poolSize: videoPool.length,
                used: _usedReplacements.size, idMapSize: _idMap.size,
                cards, sidebarCards: sidebar, looksBroken, noPoke: BYGONE_NO_POKE,
            };
        }

        function _persistNavTrace() {
            try { sessionStorage.setItem('bygone_nav_trace', JSON.stringify(_navTrace)); } catch (_) {}
        }
        function _pushNav(type, extra) {
            try {
                const last = _navTrace[_navTrace.length - 1];
                if (type === 'homeCleanup' && last && last.type === 'homeCleanup') {
                    last.t = Math.round((Date.now() - _navT0) / 100) / 10;
                    last.repeats = (last.repeats || 1) + 1;
                    if (extra) {
                        last.shelves = (last.shelves || 0) + (extra.shelves || 0);
                        last.watchChrome = (last.watchChrome || 0) + (extra.watchChrome || 0);
                        last.staleCards = (last.staleCards || 0) + (extra.staleCards || 0);
                        last.promoPruned = (last.promoPruned || 0) + (extra.promoPruned || 0);
                        last.promoLeft = extra.promoLeft || 0;
                    }
                    _persistNavTrace();
                    return;
                }
                const e = _navState();
                e.t = Math.round((Date.now() - _navT0) / 100) / 10;
                e.type = type;
                if (extra) for (const k in extra) e[k] = extra[k];
                _navTrace.push(e);
                if (_navTrace.length > _NAV_TRACE_CAP) _navTrace.shift();
                _persistNavTrace();
                if (BYGONE_DEBUG) { try { console.log('[bygone-nav]', type, JSON.stringify(e)); } catch (_) {} }
            } catch (_) {}
        }

        function _navSnapshot(type) {
            _pushNav(type);
            try {
                if (_settledTimer) clearTimeout(_settledTimer);
                _settledTimer = setTimeout(() => _pushNav(type + '+settled'), 2500);
            } catch (_) {}
        }

        function _navTraceDump(mode) {
            try {
                if (mode === 'clear') {
                    _navTrace.length = 0;
                    try { sessionStorage.removeItem('bygone_nav_trace'); } catch (_) {}
                    return 'nav-trace cleared';
                }
                if (!_navTrace.length) return '(no nav events captured)';
                const skip = { t: 1, type: 1, path: 1, search: 1, cards: 1, sidebarCards: 1, poolSize: 1, used: 1, idMapSize: 1, looksBroken: 1, noPoke: 1 };
                return _navTrace.map(e => {
                    const base = 't=' + e.t + 's ' + (e.noPoke ? '[NO-POKE] ' : '') + e.type + ' ' + e.path + (e.search || '') +
                        ' cards=' + e.cards + ' sidebar=' + e.sidebarCards +
                        ' pool=' + e.poolSize + ' used=' + e.used + ' idMap=' + e.idMapSize +
                        (e.looksBroken ? '  <<< LOOKS BROKEN' : '');
                    const extras = Object.keys(e).filter(k => !skip[k]);
                    const ex = extras.length ? '  ' + extras.map(k => k + '=' + JSON.stringify(e[k])).join(' ') : '';
                    return '  ' + base + ex;
                }).join('\n');
            } catch (err) { return 'nav-trace dump err: ' + (err && err.message); }
        }
        try { window.__bygoneNav = _navTraceDump; } catch (_) {}
        try { if (typeof unsafeWindow !== 'undefined' && unsafeWindow) unsafeWindow.__bygoneNav = _navTraceDump; } catch (_) {}

        function _getDisplayedIds() {
            if (_displayedIdsCache) return _displayedIdsCache;
            const ids = new Set();
            document.querySelectorAll('a[href*="/watch"]').forEach(a => {
                const h = a.getAttribute('href') || '';
                const m = h.match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (m) ids.add(m[1]);
            });
            _displayedIdsCache = ids;
            return ids;
        }

        function mapVideo(origId, opts) {
            if (!videoPool.length) return null;
            const dedupInResponse = !!(opts && opts.dedupInResponse);
            const avoidDisplayed = !!(opts && opts.avoidDisplayedOnFreshPick);
            const rejectDisplayedStable = !!(opts && opts.rejectDisplayedStable);
            const displayed = (dedupInResponse || avoidDisplayed || rejectDisplayedStable) ? _getDisplayedIds() : null;
            const stableClash = (id) =>
                (dedupInResponse && _responseSeen.has(id)) ||
                (rejectDisplayedStable && displayed && displayed.has(id));
            const freshClash = (id) =>
                (dedupInResponse && _responseSeen.has(id)) ||
                (displayed && displayed.has(id));

            if (origId && _poolIdsSet.has(origId)) {
                const found = videoPool.find(p => p.id === origId);
                if (found) {
                    _usedReplacements.add(found.id);
                    if (dedupInResponse) _responseSeen.add(found.id);
                    return found;
                }
            }

            if (origId && _idMap.has(origId)) {
                const stable = _idMap.get(origId);
                if (!stableClash(stable.id)) {
                    _usedReplacements.add(stable.id);
                    if (dedupInResponse) _responseSeen.add(stable.id);
                    return stable;
                }
            }

            const alreadyMapped = new Set();
            for (const v of _idMap.values()) if (v && v.id) alreadyMapped.add(v.id);

            let v = _findVideo(c => !alreadyMapped.has(c.id) && !freshClash(c.id));
            if (!v) v = _findVideo(c => !alreadyMapped.has(c.id));
            if (!v) v = _findVideo(c => !freshClash(c.id));
            if (!v) v = _findVideo(() => true);
            if (!v) return null;

            if (origId) _idMap.set(origId, v);
            _usedReplacements.add(v.id);
            if (dedupInResponse) _responseSeen.add(v.id);
            _maybeFetchMore();
            return v;
        }

        function _findVideo(pred) {
            for (let i = 0; i < videoPool.length; i++) {
                const cand = videoPool[(_poolCursor + i) % videoPool.length];
                if (pred(cand)) {
                    _poolCursor = (_poolCursor + i + 1) % videoPool.length;
                    return cand;
                }
            }
            return null;
        }

        function hydrateFromLocalStorage() {
            try {
                const raw = localStorage.getItem(POOL_LS_KEY);
                if (!raw) return false;
                const parsed = JSON.parse(raw);
                if (parsed && Array.isArray(parsed.videos) && parsed.videos.length) {
                    videoPool = parsed.videos;
                    _poolIdsSet = new Set(videoPool.map(v => v.id));
                    active = true;
                    _firePoolReady();
                    return true;
                }
            } catch (_) {}
            return false;
        }

        function _persistPool() {
            try {
                localStorage.setItem(POOL_LS_KEY, JSON.stringify({
                    videos: videoPool,
                    savedAt: Date.now(),
                }));
            } catch (_) {}
        }

        const _VALID_VID = /^[A-Za-z0-9_-]{11}$/;

        function _pruneMappingStateForPool() {
            for (const [origId, mapped] of _idMap) {
                if (!mapped || !mapped.id || !_poolIdsSet.has(mapped.id)) _idMap.delete(origId);
            }
            for (const id of Array.from(_usedReplacements)) {
                if (!_poolIdsSet.has(id)) _usedReplacements.delete(id);
            }
            _displayedIdsCache = null;
        }

        function setVideos(videos) {
            if (!Array.isArray(videos) || !videos.length) return 0;
            const _seen = new Set();
            videoPool = videos.filter(v => {
                if (!v || !v.id || !_VALID_VID.test(v.id) || _seen.has(v.id)) return false;
                _seen.add(v.id);
                return true;
            });
            if (!videoPool.length) return 0;
            _poolIdsSet = new Set(videoPool.map(v => v.id));
            _poolCursor = 0;
            _pruneMappingStateForPool();
            if (_keptNaturalIds.size > 500) _keptNaturalIds.clear();
            active = true;
            _persistPool();
            _firePoolReady();
            return videoPool.length;
        }

        function appendVideos(videos) {
            if (!Array.isArray(videos) || !videos.length) return 0;
            let added = 0;
            for (const v of videos) {
                if (!v || !v.id || !_VALID_VID.test(v.id)) continue;
                if (_poolIdsSet.has(v.id)) continue;
                videoPool.push(v);
                _poolIdsSet.add(v.id);
                added++;
            }
            if (added > 0) _persistPool();
            return added;
        }

        function clearPool() {
            videoPool = [];
            active = false;
            _poolIdsSet = new Set();
            _idMap.clear();
            _usedReplacements.clear();
            _responseSeen = new Set();
            _displayedIdsCache = null;
            _keptNaturalIds.clear();
            _poolCursor = 0;
            try { localStorage.removeItem(POOL_LS_KEY); } catch (_) {}
        }

        function removeVideos(ids) {
            if (!Array.isArray(ids) || !ids.length) return 0;
            const drop = new Set(ids);
            const before = videoPool.length;
            videoPool = videoPool.filter(v => !drop.has(v.id));
            const removed = before - videoPool.length;
            if (!removed) return 0;
            _poolIdsSet = new Set(videoPool.map(v => v.id));
            _poolCursor = 0;
            _pruneMappingStateForPool();
            if (!videoPool.length) active = false;
            _persistPool();
            return removed;
        }

        function forceResweep() {
            try {
                document.querySelectorAll('[data-bygone-swept],[data-bygone-ok],[data-bygone-keep],[data-bygone-redated]')
                    .forEach(el => {
                        el.removeAttribute('data-bygone-swept');
                        el.removeAttribute('data-bygone-ok');
                        el.removeAttribute('data-bygone-keep');
                        el.removeAttribute('data-bygone-redated');
                    });
            } catch (_) {}
            _idMap.clear();
            _usedReplacements.clear();
            _responseSeen = new Set();
            _displayedIdsCache = null;
            _poolCursor = 0;
            try { _sweep(); } catch (_) {}
            try { _sidebarSweep(); } catch (_) {}
        }

        let _lazyFetcher = null;
        let _fetchingMore = false;
        let _morePage = 2;
        function setLazyFetcher(fn) { _lazyFetcher = fn; }

        function _maybeFetchMore() {
            if (_fetchingMore || !_lazyFetcher || !videoPool.length) return;
            if (_usedReplacements.size / videoPool.length < 0.7) return;
            _fetchingMore = true;
            const page = _morePage++;
            Promise.resolve()
                .then(() => _lazyFetcher(page))
                .then(more => { if (more && more.length) appendVideos(more); })
                .catch(() => { _morePage--; })
                .then(() => { _fetchingMore = false; });
        }

        function isInnerTubeUrl(url) {
            return !!url && url.indexOf('/youtubei/v1/') !== -1;
        }

        const RENDERER_KEYS = [
            'videoRenderer',
            'gridVideoRenderer',
            'compactVideoRenderer',
            'lockupViewModel',
        ];

        const _REL_RE = /(?:Streamed\s+)*(\d+)\s*(year|month|week|day|hour|minute|second)s?\s+ago/i;
        const _VIDEO_ABS_DATE_RE = /(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\.?\s+\d{1,2},?\s+\d{4}/i;
        const _REL_COMPACT_RE = /\b\d+\s*(?:y|yrs?|mos?|wks?|w|d|hrs?|h|mins?|m|secs?|s)\.?\s+ago\b/i;

        function _relTextAtOrBeforeSet(relText) {
            if (!relText) return false;
            let setDateStr;
            try { setDateStr = Store.getCurrentDate(); } catch { return false; }
            if (!setDateStr) return false;
            const setDate = new Date(setDateStr);
            if (isNaN(setDate.getTime())) return false;
            const approx = DateHelper.approxPublishDate(relText);
            if (!approx) return false;
            return approx.getTime() <= setDate.getTime() + DateHelper.approxSlackMs(relText);
        }

        function _rendererRelText(r) {
            const p = r.publishedTimeText;
            if (!p) return '';
            return p.simpleText || (p.runs && p.runs[0] && p.runs[0].text) || '';
        }

        function _lockupRelText(r) {
            try {
                const rows = r.metadata?.lockupMetadataViewModel?.metadata
                    ?.contentMetadataViewModel?.metadataRows || [];
                for (const row of rows) {
                    for (const part of (row.metadataParts || [])) {
                        const txt = (part && part.text && part.text.content) || '';
                        if (_REL_RE.test(txt)) return txt;
                    }
                }
            } catch {}
            return '';
        }

        function _rewriteLockupDate(r, newText) {
            try {
                const rows = r.metadata?.lockupMetadataViewModel?.metadata
                    ?.contentMetadataViewModel?.metadataRows || [];
                for (const row of rows) {
                    for (const part of (row.metadataParts || [])) {
                        const txt = (part && part.text && part.text.content) || '';
                        if (_REL_RE.test(txt)) { part.text.content = newText; return; }
                    }
                }
            } catch {}
        }

        let _replaceCount = 0;
        function replaceRenderer(r) {
            if (!r || typeof r !== 'object') return;
            const origId = r.videoId || '';
            if (!origId) return;
            if (_poolIdsSet.has(origId)) return;
            const _keepRel = _rendererRelText(r);
            if (_relTextAtOrBeforeSet(_keepRel)) {
                _keptNaturalIds.add(origId);
                try {
                    const sd = Store.getCurrentDate();
                    if (sd && r.publishedTimeText) {
                        const nd = DateHelper.recalcForKept(_keepRel, sd, origId);
                        if (nd) {
                            if (r.publishedTimeText.simpleText !== undefined) r.publishedTimeText.simpleText = nd;
                            else if (r.publishedTimeText.runs) r.publishedTimeText.runs = [{ text: nd }];
                        }
                    }
                } catch (_) {}
                return;
            }
            const v = mapVideo(origId, { dedupInResponse: true, avoidDisplayedOnFreshPick: true, rejectDisplayedStable: true });
            if (!v) return;
            const vid = v.id;
            _replaceCount++;

            r.videoId = vid;
            r.title = { simpleText: v.title || '', runs: [{ text: v.title || '' }] };
            r.thumbnail = { thumbnails: [
                { url: 'https://i.ytimg.com/vi/' + vid + '/mqdefault.jpg', width: 320, height: 180 },
            ] };
            if (v.viewCountFormatted || v.viewCount) {
                const viewsText = _isStuckAt301(vid) ? '301 views' : (v.viewCountFormatted || (v.viewCount + ' views'));
                r.viewCountText = { simpleText: viewsText };
                r.shortViewCountText = { simpleText: viewsText };
            } else {
                delete r.viewCountText;
                delete r.shortViewCountText;
            }
            let dateStr = v.relativeDate || '';
            try {
                const setDate = Store.getCurrentDate();
                if (setDate && dateStr) {
                    dateStr = DateHelper.recalcForFeed(dateStr, setDate, vid) || dateStr;
                }
            } catch (_) {}
            if (dateStr) r.publishedTimeText = { simpleText: dateStr };
            else delete r.publishedTimeText;

            const dur = v.duration || '';
            r.lengthText = { simpleText: dur, accessibility: { accessibilityData: { label: dur } } };
            r.lengthSeconds = v.lengthSeconds || 0;

            const chan = v.channel || '';
            const cid = v.channelId || '';
            const byline = { runs: [{
                text: chan,
                navigationEndpoint: cid ? {
                    browseEndpoint: { browseId: cid, canonicalBaseUrl: '/channel/' + cid },
                    commandMetadata: { webCommandMetadata: { url: '/channel/' + cid, webPageType: 'WEB_PAGE_TYPE_CHANNEL' } },
                } : undefined,
            }] };
            if (chan) {
                r.shortBylineText = byline;
                r.longBylineText = byline;
                r.ownerText = byline;
            }

            r.navigationEndpoint = {
                watchEndpoint: { videoId: vid },
                commandMetadata: { webCommandMetadata: { url: '/watch?v=' + vid, webPageType: 'WEB_PAGE_TYPE_WATCH' } },
            };

            r.thumbnailOverlays = dur ? [{
                thumbnailOverlayTimeStatusRenderer: {
                    text: { simpleText: dur, accessibility: { accessibilityData: { label: dur } } },
                    style: 'DEFAULT',
                },
            }] : [];

            delete r.descriptionSnippet;
            delete r.detailedMetadataSnippets;
            delete r.richThumbnail;
            delete r.menu;
            delete r.badges;
            delete r.ownerBadges;
            delete r.videoInfo;
        }

        function replaceLockupViewModel(r) {
            if (!r || typeof r !== 'object') return;
            const origId = r.contentId || '';
            if (!origId) return;
            if (_poolIdsSet.has(origId)) return;
            const _keepRel = _lockupRelText(r);
            if (_relTextAtOrBeforeSet(_keepRel)) {
                _keptNaturalIds.add(origId);
                try {
                    const sd = Store.getCurrentDate();
                    if (sd) {
                        const nd = DateHelper.recalcForKept(_keepRel, sd, origId);
                        if (nd) _rewriteLockupDate(r, nd);
                    }
                } catch (_) {}
                return;
            }
            const v = mapVideo(origId, { dedupInResponse: true, avoidDisplayedOnFreshPick: true, rejectDisplayedStable: true });
            if (!v) return;
            const vid = v.id;
            _replaceCount++;

            const thumbUrl = 'https://i.ytimg.com/vi/' + vid + '/mqdefault.jpg';
            r.contentId = vid;
            r.contentType = 'LOCKUP_CONTENT_TYPE_VIDEO';

            if (!r.metadata) r.metadata = {};
            if (!r.metadata.lockupMetadataViewModel) r.metadata.lockupMetadataViewModel = {};
            const meta = r.metadata.lockupMetadataViewModel;
            meta.title = { content: v.title || '', styleRuns: [] };

            let dateStr = v.relativeDate || '';
            try {
                const setDate = Store.getCurrentDate();
                if (setDate && dateStr) dateStr = DateHelper.recalcForFeed(dateStr, setDate, vid) || dateStr;
            } catch (_) {}

            const viewsText = _isStuckAt301(vid) ? '301 views' : (v.viewCountFormatted || (v.viewCount ? v.viewCount + ' views' : ''));
            meta.metadata = { contentMetadataViewModel: { metadataRows: [
                { metadataParts: [{
                    text: {
                        content: v.channel || '',
                        commandRuns: v.channelId ? [{
                            startIndex: 0,
                            length: (v.channel || '').length,
                            onTap: { innertubeCommand: {
                                browseEndpoint: { browseId: v.channelId, canonicalBaseUrl: '/channel/' + v.channelId },
                                commandMetadata: { webCommandMetadata: { url: '/channel/' + v.channelId, webPageType: 'WEB_PAGE_TYPE_CHANNEL' } },
                            } },
                        }] : [],
                    },
                }] },
                { metadataParts: [
                    viewsText ? { text: { content: viewsText } } : null,
                    dateStr ? { text: { content: dateStr } } : null,
                ].filter(Boolean) },
            ] } };

            if (!r.contentImage || typeof r.contentImage !== 'object') r.contentImage = {};
            if (!r.contentImage.thumbnailViewModel || typeof r.contentImage.thumbnailViewModel !== 'object') {
                r.contentImage.thumbnailViewModel = {};
            }
            const tvm = r.contentImage.thumbnailViewModel;
            if (!tvm.image || typeof tvm.image !== 'object') tvm.image = {};
            tvm.image.sources = [{ url: thumbUrl, width: 480, height: 360 }];
            tvm.overlays = v.duration ? [{
                thumbnailOverlayBadgeViewModel: { thumbnailBadges: [{
                    thumbnailBadgeViewModel: { text: v.duration, badgeStyle: 'THUMBNAIL_OVERLAY_BADGE_STYLE_DEFAULT' },
                }] },
            }] : [];

            const a11y = (v.title || '') + (v.channel ? ' by ' + v.channel : '');
            if (typeof r.accessibilityText === 'string') r.accessibilityText = a11y;
            if (!r.rendererContext || typeof r.rendererContext !== 'object') r.rendererContext = {};
            const rc = r.rendererContext;
            rc.commandContext = { onTap: { innertubeCommand: {
                watchEndpoint: { videoId: vid },
                commandMetadata: { webCommandMetadata: { url: '/watch?v=' + vid, webPageType: 'WEB_PAGE_TYPE_WATCH' } },
            } } };
            if (!rc.accessibilityContext || typeof rc.accessibilityContext !== 'object') rc.accessibilityContext = {};
            rc.accessibilityContext.label = a11y;
        }

        function walkAndReplace(node, depth) {
            if (!node || depth > 40 || typeof node !== 'object') return;
            if (Array.isArray(node)) {
                for (let i = 0; i < node.length; i++) walkAndReplace(node[i], depth + 1);
                return;
            }
            for (const k in node) {
                if (RENDERER_KEYS.indexOf(k) !== -1) {
                    const r = node[k];
                    if (r) {
                        if (k === 'lockupViewModel') { if (r.contentId) replaceLockupViewModel(r); }
                        else if (r.videoId) replaceRenderer(r);
                    }
                }
                walkAndReplace(node[k], depth + 1);
            }
        }

        function _relTextOf(obj) {
            if (!obj) return '';
            if (typeof obj === 'string') return obj;
            if (obj.simpleText) return obj.simpleText;
            if (obj.content) return obj.content;
            if (Array.isArray(obj.runs)) return obj.runs.map(r => (r && r.text) || '').join('');
            return '';
        }

        function _rewriteWatchDate(vpir, setDateStr) {
            const rd = vpir.relativeDateText;
            const raw = _relTextOf(rd);
            if (!raw) return;
            const approx = DateHelper.approxPublishDate(raw);
            if (!approx) return;
            const newText = DateHelper.recalcRelative(raw, setDateStr);
            if (rd.simpleText !== undefined) rd.simpleText = newText;
            else if (Array.isArray(rd.runs)) rd.runs = [{ text: newText }];
        }

        function _walkWatchDate(node, depth, setDateStr) {
            if (!node || depth > 45 || typeof node !== 'object') return;
            if (Array.isArray(node)) {
                for (let i = 0; i < node.length; i++) _walkWatchDate(node[i], depth + 1, setDateStr);
                return;
            }
            if (node.videoPrimaryInfoRenderer) {
                try { _rewriteWatchDate(node.videoPrimaryInfoRenderer, setDateStr); } catch (_) {}
            }
            for (const k in node) _walkWatchDate(node[k], depth + 1, setDateStr);
        }

        function _processCommentsAndDates(json) {
            if (!json || typeof json !== 'object') return;
            if (json.contents && json.contents.twoColumnBrowseResultsRenderer) return;
            let setDateStr = null;
            try { setDateStr = Store.getCurrentDate(); } catch (_) {}
            if (!setDateStr) return;
            if (isNaN(new Date(setDateStr).getTime())) return;
            _walkWatchDate(json, 0, setDateStr);
        }

        function waitForPool(timeoutMs) {
            if (_userPaused) return Promise.resolve(false);
            if (active && videoPool.length) return Promise.resolve(true);
            return new Promise(resolve => {
                const start = Date.now();
                const tick = () => {
                    if (_userPaused) return resolve(false);
                    if (active && videoPool.length) return resolve(true);
                    if (Date.now() - start > timeoutMs) return resolve(false);
                    setTimeout(tick, 30);
                };
                tick();
            });
        }

        function rewriteJsonText(text) {
            if (!active || !videoPool.length || !text || text.length < 20) return text;
            try {
                const json = JSON.parse(text);
                _replaceCount = 0;
                startResponseScope();
                walkAndReplace(json, 0);
                try { _processCommentsAndDates(json); } catch (_) {}
                return JSON.stringify(json);
            } catch (_) { return text; }
        }

        function _isChannelPage() {
            return /^\/(channel\/|@|c\/|user\/)/.test(location.pathname);
        }

        function _shouldReplace(url) {
            if (!isInnerTubeUrl(url)) return false;
            if (url.indexOf('/youtubei/v1/search') !== -1) return false;
            if (url.indexOf('/youtubei/v1/player') !== -1) return false;
            if (url.indexOf('/youtubei/v1/notification') !== -1) return false;
            if (url.indexOf('/youtubei/v1/reel') !== -1) return false;
            if (_isChannelPage() && url.indexOf('/youtubei/v1/browse') !== -1) return false;
            return true;
        }

        function install() {
            const origRespText = Response.prototype.text;
            try {
                const origRespJson = Response.prototype.json;

                Response.prototype.json = async function () {
                    const url = this.url || '';
                    if (!_shouldReplace(url)) return origRespJson.call(this);
                    const ready = await waitForPool(8000);
                    if (!ready || !active || !videoPool.length) return origRespJson.call(this);
                    const json = await origRespJson.call(this);
                    try {
                        _replaceCount = 0;
                        startResponseScope();
                        walkAndReplace(json, 0);
                        try { _processCommentsAndDates(json); } catch (_) {}
                        if (url.indexOf('/youtubei/v1/next') !== -1) {
                            setTimeout(() => { try { _sidebarSweep(); } catch (_) {} }, 100);
                            setTimeout(() => { try { _sidebarSweep(); } catch (_) {} }, 500);
                            setTimeout(() => { try { _sidebarSweep(); } catch (_) {} }, 1500);
                            setTimeout(() => { try { _maybeExtendSidebar(); } catch (_) {} }, 700);
                            setTimeout(() => { try { _maybeExtendSidebar(); } catch (_) {} }, 2200);
                        }
                    } catch (_) {}
                    return json;
                };

                Response.prototype.text = async function () {
                    const url = this.url || '';
                    if (!_shouldReplace(url)) return origRespText.call(this);
                    const ready = await waitForPool(8000);
                    if (!ready || !active || !videoPool.length) return origRespText.call(this);
                    const text = await origRespText.call(this);
                    return rewriteJsonText(text);
                };
            } catch (e) { console.warn('[bygone] Response patch failed', e); }

            const origFetch = window.fetch ? window.fetch.bind(window) : null;
            if (origFetch) {
                window.fetch = function (input, init) {
                    const url = typeof input === 'string' ? input : (input && input.url) || '';
                    const p = origFetch(input, init);
                    if (!_shouldReplace(url)) return p;
                    return p.then(response => {
                        if (!response || !response.ok) return response;
                        return waitForPool(8000).then(ready => {
                            if (!ready) return response;
                            return origRespText.call(response.clone()).then(text => {
                                const out = rewriteJsonText(text);
                                if (out === text) return response;
                                return new Response(out, {
                                    status: response.status,
                                    statusText: response.statusText,
                                    headers: new Headers(response.headers),
                                });
                            }).catch(() => response);
                        });
                    });
                };
            }
        }

        let _origFetch = null;
        try {
            _origFetch = window.fetch ? window.fetch.bind(window) : null;
            install();
        } catch (e) { console.warn('[bygone] install failed', e); }
        hydrateFromLocalStorage();

        function _injectHideCss() {
            try {
                if (document.getElementById('bygone-hide-css')) return;
                const s = document.createElement('style');
                s.id = 'bygone-hide-css';
                s.textContent = `
                    ytd-rich-item-renderer,
                    ytd-grid-video-renderer,
                    ytd-video-renderer,
                    ytd-compact-video-renderer,
                    yt-lockup-view-model,
                    .yt-lockup-view-model,
                    .lohp-large-shelf-container,
                    .lohp-medium-shelf {
                        visibility: hidden !important;
                    }
                    [data-bygone-ok="1"],
                    [data-bygone-swept] {
                        visibility: visible !important;
                    }
                    [data-bygone-ok="1"] .yt-lockup,
                    [data-bygone-swept] .yt-lockup,
                    [data-bygone-ok="1"] .context-data-item.yt-lockup,
                    [data-bygone-swept] .context-data-item.yt-lockup,
                    [data-bygone-ok="1"] .yt-lockup-content,
                    [data-bygone-swept] .yt-lockup-content,
                    [data-bygone-ok="1"] .yt-lockup-title,
                    [data-bygone-swept] .yt-lockup-title,
                    [data-bygone-ok="1"] .yt-lockup-title a,
                    [data-bygone-swept] .yt-lockup-title a,
                    [data-bygone-ok="1"] .lohp-media-object-content,
                    [data-bygone-swept] .lohp-media-object-content,
                    [data-bygone-ok="1"] .lohp-video-link,
                    [data-bygone-swept] .lohp-video-link {
                        visibility: visible !important;
                    }
                    html:has(.lohp-newspaper-shelf, .lohp-large-shelf-container) .feed-item-container:has(.multirow-shelf),
                    html:has(.lohp-newspaper-shelf, .lohp-large-shelf-container) .feed-item-container:has(.yt-shelf-grid),
                    html:has(.lohp-newspaper-shelf, .lohp-large-shelf-container) .multirow-shelf,
                    html:has(.lohp-newspaper-shelf, .lohp-large-shelf-container) .yt-shelf-grid {
                        display: none !important;
                    }
                    ytd-watch-flexy #primary,
                    ytd-watch-flexy #primary-inner,
                    ytd-watch-flexy #above-the-fold,
                    ytd-watch-flexy #owner,
                    ytd-watch-flexy #meta,
                    ytd-watch-flexy #info,
                    ytd-watch-flexy #info-contents,
                    ytd-watch-flexy #upload-info,
                    ytd-watch-flexy #menu,
                    ytd-watch-flexy #menu-container,
                    ytd-watch-flexy #top-level-buttons-computed,
                    ytd-watch-flexy ytd-watch-metadata,
                    ytd-watch-flexy ytd-video-owner-renderer,
                    #watch7-main-container,
                    #watch7-content,
                    #watch-header,
                    #watch-description,
                    .watch-main-col,
                    .watch-info,
                    .watch-actions,
                    .watch-action-buttons,
                    .watch-extras-section {
                        visibility: visible !important;
                    }
                    img.bygone-thumb,
                    img[data-bygone-thumb] {
                        display: inline-block !important;
                        visibility: visible !important;
                        width: 100% !important;
                        max-width: none !important;
                        height: auto !important;
                        max-height: none !important;
                        aspect-ratio: 16 / 9 !important;
                        object-fit: cover !important;
                        object-position: center center !important;
                        vertical-align: top;
                        margin-right: 8px;
                        margin-bottom: 4px;
                    }
                    .html5-video-player [data-bygone-player-card-blocked="1"],
                    #movie_player [data-bygone-player-card-blocked="1"],
                    .ytp-autonav-endscreen-countdown-container,
                    .ytp-autonav-endscreen-countdown-overlay {
                        display: none !important;
                    }
                    [data-bygone-comment-hidden] {
                        display: none !important;
                        height: 0 !important;
                        max-height: 0 !important;
                        overflow: hidden !important;
                        margin: 0 !important;
                        padding: 0 !important;
                        border: 0 !important;
                        min-height: 0 !important;
                        visibility: hidden !important;
                    }
                    [data-bygone-comment-hidden] + .post,
                    [data-bygone-comment-hidden] + li,
                    [data-bygone-comment-gap="1"] + .post,
                    [data-bygone-comment-gap="1"] + li {
                        margin-top: 0 !important;
                        border-top: 0 !important;
                    }
                    [data-bygone-comment-gap="1"],
                    [data-bygone-home-promo-removed="1"] {
                        display: none !important;
                        height: 0 !important;
                        max-height: 0 !important;
                        min-height: 0 !important;
                        overflow: hidden !important;
                        margin: 0 !important;
                        padding: 0 !important;
                        border: 0 !important;
                        visibility: hidden !important;
                    }
                    .bygone-meta {
                        display: block !important;
                        visibility: visible !important;
                        color: #aaa;
                        font-size: 11px;
                        margin-top: 2px;
                    }
                    .bygone-meta .yt-user-name {
                        color: #4e7ab5;
                    }
                    .bygone-meta .view-count,
                    .bygone-meta .content-item-time-created {
                        color: #999;
                    }
                `;
                if (_userPaused) s.media = 'not all';
                (document.head || document.documentElement).appendChild(s);
            } catch (_) {}
        }
        _injectHideCss();
        setInterval(() => { if (!document.getElementById('bygone-hide-css')) _injectHideCss(); }, 3000);

        function setPaused(p) {
            _userPaused = !!p;
            try {
                const s = document.getElementById('bygone-hide-css');
                if (s) s.media = _userPaused ? 'not all' : 'all';
            } catch (_) {}
        }

        const _poolIdSet = () => _poolIdsSet;

        const _HOME_ROOT_SEL = [
            '.lohp-newspaper-shelf',
            '#c3-content-items',
            '#browse-items-primary',
            '#feed',
            '#feed-list',
            '.feed-list',
            '.channels-browse-content-grid',
            '.expanded-shelf-content-list',
            '.yt-shelf-grid',
            '.yt-rich-grid',
            'ytd-browse[page-subtype="home"] #contents',
            'ytd-rich-grid-renderer #contents'
        ].join(',');

        const _WATCH_CHROME_SEL = [
            'ytd-watch-flexy',
            '#watch7-container',
            '#watch7-main-container',
            '#watch7-content',
            '#watch7-sidebar',
            '#watch7-sidebar-contents',
            '#watch7-sidebar-modules',
            '#watch-header',
            '#watch-description',
            '#watch-discussion',
            '.watch-main-col',
            '.watch-sidebar',
            '.watch-card',
            '#above-the-fold',
            '#owner',
            '#meta'
        ].join(',');

        const _STALE_HOME_CARD_SEL = [
            'ytd-rich-item-renderer',
            'ytd-video-renderer',
            'ytd-compact-video-renderer',
            'yt-lockup-view-model',
            '.yt-lockup-view-model',
            '.video-list-item',
            '.feed-item-container .yt-lockup',
            '.context-data-item.yt-lockup',
            '.yt-shelf-grid-item',
            '.yt-uix-shelfslider-item',
            '.expanded-shelf-content-item',
            '.channels-content-item'
        ].join(',');

        const _HOME_CHANNEL_PROMO_SEL = [
            '.channels-content-item',
            '.yt-lockup-channel',
            '.yt-lockup.yt-lockup-channel',
            '.context-data-item.yt-lockup',
            'yt-lockup-view-model',
            'ytd-channel-renderer',
            '[class*="branded-page-module"]'
        ].join(',');

        const _CHANNEL_LINK_SEL = [
            'a[href^="/channel/"]',
            'a[href^="/user/"]',
            'a[href^="/c/"]',
            'a[href^="/@"]'
        ].join(',');

        const _HOME_LOHP_SEL = '.lohp-newspaper-shelf, .lohp-large-shelf-container, ' +
            '.lohp-medium-shelf, .lohp-media-object';

        function _hasAnyLink(el, sel) {
            return !!(el && el.querySelector && el.querySelector(sel));
        }

        function _hasWatchLink(el) {
            return _hasAnyLink(el, 'a[href*="/watch"]');
        }

        function _hasChannelLink(el) {
            return _hasAnyLink(el, _CHANNEL_LINK_SEL);
        }

        function _hasSubscribeButton(el) {
            if (!el || !el.querySelector) return false;
            if (el.querySelector(
                '.yt-uix-subscription-button, .yt-uix-button-subscribe-branded, ' +
                'ytd-subscribe-button-renderer, [class*="subscribe-button-renderer"], ' +
                'yt-subscribe-button-view-model, [class*="subscription-button"]'
            )) return true;
            const btns = el.querySelectorAll('button, [role="button"]');
            for (const b of btns) {
                const aria = ((b.getAttribute && b.getAttribute('aria-label')) || '').trim().toLowerCase();
                if (/^subscribe\b/.test(aria)) return true;
                const t = (b.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase();
                if (t === 'subscribe' || /^subscribe\b/.test(t)) return true;
            }
            return false;
        }

        function _homeCardText(el) {
            return ((el && el.textContent) || '').replace(/\s+/g, ' ').trim();
        }

        function _homeChannelTopicSignal(el) {
            if (!el || !el.querySelector) return false;
            const sig = ((el.className || '') + ' ' + (el.id || '')).toString();
            if (/yt-lockup-channel|channel-renderer|compact-channel|channel-lockup/i.test(sig)) return true;
            if (el.matches && el.matches('.yt-lockup-channel,.yt-lockup.yt-lockup-channel,ytd-channel-renderer')) return true;
            if (el.querySelector('.yt-lockup-channel,.yt-lockup.yt-lockup-channel,ytd-channel-renderer,[class*="channel-renderer"],[class*="channel-lockup"]')) return true;

            const titleLink = el.querySelector('.yt-lockup-title a,h3 a,.yt-uix-tile-link,a.title');
            const titleHref = titleLink && (titleLink.getAttribute('href') || '');
            if (titleHref && /^\/(?:channel\/|user\/|c\/|@)/.test(titleHref)) return true;

            const text = _homeCardText(el);
            const channelName = Array.from(el.querySelectorAll(_CHANNEL_LINK_SEL))
                .map(a => (a.textContent || '').trim())
                .filter(Boolean)
                .join(' ');
            const topicName = /\btopic\b/i.test(channelName) || /-\s*topic\b/i.test(channelName);
            const promoWords = /\b(?:subscribers?|videos?|channel|official artist channel|auto-generated by youtube)\b/i.test(text);
            const videoMeta = /\bviews?\b|\b\d+\s+(?:years?|months?|weeks?|days?|hours?|minutes?|seconds?)\s+ago\b/i.test(text);
            return !!(_hasChannelLink(el) && promoWords && (topicName || !videoMeta));
        }

        function _promoProtected(el) {
            if (!el) return false;
            const sel = '[data-bygone-swept],[data-bygone-ok],[data-bygone-keep]';
            if (el.closest && el.closest(sel)) return true;
            return !!(el.querySelector && el.querySelector(sel));
        }

        function _isDefiniteHomePromo(el) {
            if (!el || !el.querySelector) return false;
            if (el.closest && el.closest('[class*="branded-page-module"]')) return true;
            const sig = ((el.className || '') + ' ' + (el.id || '')).toString();
            if (/yt-lockup-channel|channel-renderer|compact-channel|channel-lockup/i.test(sig)) return true;
            if (el.matches && el.matches('.yt-lockup-channel,.yt-lockup.yt-lockup-channel,ytd-channel-renderer')) return true;
            if (_hasSubscribeButton(el)) return true;
            const titleLink = el.querySelector('.yt-lockup-title a,h3 a,.yt-uix-tile-link,a.title,.lohp-video-link');
            const titleHref = titleLink && (titleLink.getAttribute('href') || '');
            if (titleHref && /^\/(?:channel\/|user\/|c\/|@)/.test(titleHref)) return true;
            return false;
        }

        const _promoSuspects = new WeakMap();
        function _promoSuspectSettled(el) {
            const now = Date.now();
            const text = _homeCardText(el).slice(0, 220);
            const rec = _promoSuspects.get(el);
            if (!rec || rec.text !== text) {
                _promoSuspects.set(el, { text, first: now, ticks: 1 });
                return false;
            }
            rec.ticks++;
            return rec.ticks >= 3 && now - rec.first >= 1200;
        }

        function _isHomeChannelTopicPromo(el) {
            if (!el || !el.querySelector) return false;
            if (_promoProtected(el)) return false;
            if (_isDefiniteHomePromo(el)) return true;
            if (!_hasChannelLink(el) && !_homeChannelTopicSignal(el)) return false;
            if (!_hasWatchLink(el)) return true;
            const titleLink = el.querySelector('.yt-lockup-title a,h3 a,.yt-uix-tile-link,a.title,.lohp-video-link');
            const titleHref = titleLink && (titleLink.getAttribute('href') || '');
            if (titleHref && titleHref.indexOf('/watch') !== -1) return false;
            const text = _homeCardText(el);
            const promoWords = /\b(?:subscribers?|videos?|channel|official artist channel|auto-generated by youtube)\b/i.test(text);
            const videoMeta = /\bviews?\b|\b\d+\s+(?:years?|months?|weeks?|days?|hours?|minutes?|seconds?)\s+ago\b/i.test(text);
            return !!(_homeChannelTopicSignal(el) && promoWords && !videoMeta);
        }

        function _homePromoRemovalTarget(el, roots) {
            if (!el) return null;
            let target = el;
            const slotSel = [
                '.feed-item-container',
                '.yt-shelf-grid-item',
                '.yt-uix-shelfslider-item',
                '.expanded-shelf-content-item',
                '.channels-content-item',
                '.context-data-item.yt-lockup',
                'yt-lockup-view-model',
                'ytd-channel-renderer',
                '[class*="branded-page-module"]',
            ].join(',');
            for (let p = el; p && p !== document.body; p = p.parentElement) {
                if (p.matches && p.matches(slotSel)) target = p;
                if (_insideAnyRoot(p, roots) && p !== el && !(p.matches && p.matches(slotSel))) break;
            }
            return target;
        }

        function _removeHomeChannelTopicPromos(roots) {
            let pruned = 0;
            let left = 0;
            if (!roots || !roots.length) return { pruned, left };
            document.querySelectorAll(_HOME_CHANNEL_PROMO_SEL + ',' + _CHANNEL_LINK_SEL).forEach(el => {
                const card = el.matches && el.matches(_CHANNEL_LINK_SEL)
                    ? (el.closest('.yt-lockup,.channels-content-item,yt-lockup-view-model,ytd-channel-renderer,.context-data-item') || el)
                    : el;
                if (!_insideAnyRoot(card, roots)) return;
                if (_insideWatchChrome(card)) return;
                if (card.closest && card.closest('#masthead, #guide, #guide-container, #wbt-panel')) return;
                if (_promoProtected(card)) { _promoSuspects.delete(card); return; }
                if (!_isHomeChannelTopicPromo(card)) { _promoSuspects.delete(card); return; }
                if (!_isDefiniteHomePromo(card) && !_promoSuspectSettled(card)) return;
                const target = _homePromoRemovalTarget(card, roots) || card;
                if (target.querySelector && target.querySelector(_HOME_LOHP_SEL)) return;
                if (target !== card && _promoProtected(target)) return;
                try {
                    target.setAttribute('data-bygone-home-promo-removed', '1');
                    target.remove();
                    pruned++;
                } catch (_) {
                    try {
                        target.setAttribute('data-bygone-home-promo-removed', '1');
                        target.style.setProperty('display', 'none', 'important');
                        pruned++;
                    } catch (__) {}
                }
            });
            document.querySelectorAll(_HOME_CHANNEL_PROMO_SEL).forEach(el => {
                if (!_insideAnyRoot(el, roots)) return;
                if (_insideWatchChrome(el)) return;
                if (el.closest && el.closest('#masthead, #guide, #guide-container, #wbt-panel')) return;
                if (_isHomeChannelTopicPromo(el)) {
                    try {
                        const cs = getComputedStyle(el);
                        if (cs.display !== 'none' && cs.visibility !== 'hidden') left++;
                    } catch (_) {}
                }
            });
            return { pruned, left };
        }

        function _isHomeLikePath() {
            const p = location.pathname;
            return p === '/' || p === '' || p === '/feed/trending';
        }

        function _homeRoots(root) {
            const scope = root || document;
            const out = [];
            const add = el => { if (el && out.indexOf(el) === -1) out.push(el); };
            if (scope.matches && scope.matches(_HOME_ROOT_SEL)) add(scope);
            if (scope.querySelectorAll) scope.querySelectorAll(_HOME_ROOT_SEL).forEach(add);
            return out.filter(el => !(el.closest && el.closest(_WATCH_CHROME_SEL)));
        }

        function _insideAnyRoot(el, roots) {
            for (const root of roots || []) {
                if (root === el || (root.contains && root.contains(el))) return true;
            }
            return false;
        }

        function _insideWatchChrome(el) {
            return !!(el && el.closest && el.closest(_WATCH_CHROME_SEL));
        }

        function _cleanupHomeSpaArtifacts() {
            if (_userPaused || !_isHomeLikePath()) return;
            let _dbgShelves = 0, _dbgWatchChrome = 0, _dbgStale = 0;

            if (document.querySelector(_HOME_LOHP_SEL)) {
                const kill = new Set();
                const WRAP_RE = /feed-item|shelf-wrapper|multirow-shelf|yt-shelf-grid|expander/i;
                document.querySelectorAll('.multirow-shelf, .yt-shelf-grid').forEach(shelf => {
                    if (shelf.querySelector(_HOME_LOHP_SEL)) return;
                    if (shelf.closest('#masthead, #guide, #guide-container, #wbt-panel')) return;
                    let target = shelf;
                    let p = shelf.parentElement;
                    while (p && p !== document.body) {
                        const cls = (p.className && p.className.toString) ? p.className.toString() : '';
                        if (!WRAP_RE.test(cls)) break;
                        if (p.querySelector(_HOME_LOHP_SEL)) break;
                        target = p;
                        p = p.parentElement;
                    }
                    kill.add(target);
                });
                kill.forEach(el => {
                    try { el.remove(); } catch (_) {
                        try { el.style.setProperty('display', 'none', 'important'); } catch (__) {}
                    }
                });
                _dbgShelves = kill.size;
            }

            const roots = _homeRoots(document);
            let channelPromoPruned = 0;
            let channelPromoLeft = 0;
            document.querySelectorAll(_WATCH_CHROME_SEL).forEach(el => {
                if (_insideAnyRoot(el, roots)) return;
                _dbgWatchChrome++;
                try { el.remove(); } catch (_) {
                    try { el.style.setProperty('display', 'none', 'important'); } catch (__) {}
                }
            });
            if (roots.length) {
                document.querySelectorAll(_STALE_HOME_CARD_SEL).forEach(el => {
                    if (_insideAnyRoot(el, roots)) return;
                    if (!el.querySelector || !el.querySelector('a[href*="/watch"]')) return;
                    if (el.closest && el.closest('#masthead, #guide, #guide-container, #wbt-panel')) return;
                    _dbgStale++;
                    try { el.remove(); } catch (_) {
                        try { el.style.setProperty('display', 'none', 'important'); } catch (__) {}
                    }
                });
                const promo = _removeHomeChannelTopicPromos(roots);
                channelPromoPruned += promo.pruned;
                channelPromoLeft += promo.left;
            }
            _lastHomeChannelPromoPruned = channelPromoPruned;
            _lastHomeChannelPromoLeft = channelPromoLeft;
            if (_dbgShelves || _dbgWatchChrome || _dbgStale || channelPromoPruned || channelPromoLeft) {
                _pushNav('homeCleanup', {
                    shelves: _dbgShelves, watchChrome: _dbgWatchChrome,
                    staleCards: _dbgStale, promoPruned: channelPromoPruned, promoLeft: channelPromoLeft,
                });
            }
        }

        let _homeSpaFixTimer = null;
        function _burstHomeSpaFix() {
            if (_homeSpaFixTimer) { clearInterval(_homeSpaFixTimer); _homeSpaFixTimer = null; }
            let elapsed = 0;
            const run = () => {
                try { _cleanupHomeSpaArtifacts(); } catch (_) {}
                try { _sweep(); } catch (_) {}
            };
            run();
            _homeSpaFixTimer = setInterval(() => {
                run();
                elapsed += 150;
                if (elapsed >= 4500) {
                    clearInterval(_homeSpaFixTimer);
                    _homeSpaFixTimer = null;
                }
            }, 150);
        }

        function _nextDomVideoFor(origId) {
            return mapVideo(origId, {
                dedupInResponse: false,
                avoidDisplayedOnFreshPick: true,
            });
        }

        function _freshDomVideoAvoiding(avoidIds) {
            return _findVideo(v => v && v.id && !avoidIds.has(v.id));
        }

        function _findCards(root) {
            const sels = [
                'ytd-rich-item-renderer',
                'ytd-video-renderer',
                'ytd-grid-video-renderer',
                'ytd-compact-video-renderer',
                'yt-lockup-view-model',
                '.lohp-large-shelf-container',
                '.lohp-medium-shelf',
                '.lohp-media-object',
                '.video-list-item',
                '.feed-item-container .yt-lockup',
                '.yt-shelf-grid-item',
                '.yt-uix-shelfslider-item',
                '.expanded-shelf-content-item',
                '.channels-content-item',
            ];
            const set = new Set();
            for (const s of sels) root.querySelectorAll(s).forEach(el => set.add(el));
            let arr = Array.from(set).filter(c => c.querySelector('a[href*="/watch"]'));
            if (_isHomeLikePath()) {
                const roots = _homeRoots(root);
                arr = arr.filter(c => !_isDefiniteHomePromo(c));
                if (roots.length) {
                    arr = arr.filter(c => _insideAnyRoot(c, roots) && !_insideWatchChrome(c));
                } else {
                    arr = arr.filter(c =>
                        !_insideWatchChrome(c) &&
                        !(c.closest && c.closest('#masthead, #guide, #guide-container, #wbt-panel')) &&
                        !(c.closest && c.closest('.multirow-shelf'))
                    );
                }
            }

            arr = arr.filter(c => {
                const cText = (c.textContent || '').trim();
                if (cText.length >= 20) return true;
                for (const outer of arr) {
                    if (outer === c || !outer.contains(c)) continue;
                    return false;
                }
                return true;
            });

            arr.sort((a, b) => a.contains(b) ? 1 : b.contains(a) ? -1 : 0);
            return arr;
        }

        function _innerCardsOf(card, allCards) {
            if (!allCards) return [];
            const out = [];
            for (const c of allCards) if (c !== card && card.contains(c)) out.push(c);
            return out;
        }

        function _ownedBy(el, innerCards) {
            for (const inner of innerCards) if (inner.contains(el)) return false;
            return true;
        }

        function _primaryWatchLink(card, innerCards) {
            const inner = innerCards || [];
            const links = Array.from(card.querySelectorAll('a[href*="/watch"]'))
                .filter(a => _ownedBy(a, inner));
            for (const a of links) if (a.querySelector('img')) return a;
            return links[0] || null;
        }

        const _diagT0 = Date.now();
        function _bygoneDiagRun() {
            try {
                const cards = _findCards(document);
                const idOf = function (el) {
                    const inner = _innerCardsOf(el, cards);
                    const a = _primaryWatchLink(el, inner) || el.querySelector('a[href*="/watch?v="]');
                    const m = a && (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]{11})/);
                    return m ? m[1] : null;
                };
                let vis = 0, hid = 0, hidId = 0, noImg = 0;
                const allIds = new Set(), visIds = new Set(), hiddenIds = [];
                const visCounts = {};
                const samp = [];
                for (const c of cards) {
                    const id = idOf(c);
                    if (id) allIds.add(id);
                    if (getComputedStyle(c).visibility === 'hidden') {
                        hid++;
                        if (id) { hidId++; hiddenIds.push(id); }
                        if (samp.length < 6) samp.push((c.className || '').toString().trim().slice(0, 36));
                    } else {
                        vis++;
                        if (id) visIds.add(id);
                        if (id) visCounts[id] = (visCounts[id] || 0) + 1;
                        const hasImg = Array.from(c.querySelectorAll('img')).some(function (im) {
                            return (im.getAttribute('src') || '').length > 10 && im.getBoundingClientRect().width > 10;
                        });
                        if (!hasImg) noImg++;
                    }
                }
                let dupHidden = 0;
                let visDupes = 0, visDupeGroups = 0;
                for (const count of Object.values(visCounts)) {
                    if (count > 1) {
                        visDupeGroups++;
                        visDupes += count - 1;
                    }
                }
                const distinctHidden = new Set();
                for (const id of hiddenIds) { distinctHidden.add(id); if (visIds.has(id)) dupHidden++; }
                const msg = 'BYGONE-DIAG t=' + Math.round((Date.now() - _diagT0) / 1000) + 's' +
                    ' cards=' + cards.length + ' vis=' + vis + ' HIDDEN=' + hid +
                    ' hiddenWithId=' + hidId + ' visNoImg=' + noImg +
                    ' visDupes=' + visDupes + ' visDupeGroups=' + visDupeGroups +
                    ' chanPromoPruned=' + _lastHomeChannelPromoPruned +
                    ' chanPromoLeft=' + _lastHomeChannelPromoLeft +
                    ' POOL=' + videoPool.length + ' used=' + _usedReplacements.size +
                    ' idMap=' + _idMap.size + ' active=' + active;
                const msg2 = '  distinctAll=' + allIds.size + ' distinctVisible=' + visIds.size +
                    ' distinctHidden=' + distinctHidden.size + ' dupHidden=' + dupHidden +
                    ' (hidden cards whose id is ALSO on a visible card)';
                console.log(msg);
                console.log(msg2);
                console.log('  sweepBranches: ' + JSON.stringify(_sweepStats));
                if (samp.length) console.log('  hidden: ' + samp.join(' / '));
                return msg;
            } catch (e) { console.log('BYGONE-DIAG err ' + e.message); return 'err: ' + e.message; }
        }
        function _bygoneDiag(mode) {
            if (mode === 'watch') {
                let n = 0;
                const id = setInterval(function () { _bygoneDiagRun(); if (++n >= 20) clearInterval(id); }, 3000);
                return 'BYGONE-DIAG watching for 60s…';
            }
            return _bygoneDiagRun();
        }
        try { window.__bygoneDiag = _bygoneDiag; } catch (_) {}
        try { if (typeof unsafeWindow !== 'undefined' && unsafeWindow) unsafeWindow.__bygoneDiag = _bygoneDiag; } catch (_) {}

        function _inTitleEl(node) {
            const p = node && node.parentElement;
            return !!(p && p.closest && p.closest('h3, [id*="video-title"], [class*="title"]'));
        }

        function _cardRelText(card) {
            const walker = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, null);
            let node;
            while ((node = walker.nextNode())) {
                const m = (node.nodeValue || '').match(_REL_RE);
                if (m) return m[0];
            }
            return '';
        }

        function _cardIsNaturallyOld(card, innerCards) {
            const src = card.getAttribute && card.getAttribute('data-bygone-date-source');
            if (src && _relTextAtOrBeforeSet(src)) return true;
            const info = _cardDateTextInfo(card, innerCards || []);
            if (info && info.kind === 'relative' && _relTextAtOrBeforeSet(info.raw)) return true;
            if (info && info.kind === 'absolute') {
                let setDateStr;
                try { setDateStr = Store.getCurrentDate(); } catch { return false; }
                if (setDateStr) {
                    const iso = DateHelper.parseExactDateText(info.raw);
                    if (iso && new Date(iso).getTime() <= new Date(setDateStr).getTime()) return true;
                }
            }
            if (!info && _relTextAtOrBeforeSet(_cardRelText(card))) return true;
            return false;
        }

        function _videoIdFromHref(href) {
            const m = (href || '').match(/[?&]v=([A-Za-z0-9_-]{11})/);
            return m ? m[1] : '';
        }

        function _cardVideoId(card, innerCards) {
            const a = _primaryWatchLink(card, innerCards);
            if (!a) return '';
            return _videoIdFromHref(a.getAttribute('href') || '');
        }

        function _cardDateTextInfo(card, innerCards) {
            if (!card) return null;
            const owns = (el) => _ownedBy(el, innerCards || []);
            const walker = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, {
                acceptNode: (node) => owns(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT,
            });
            let node;
            while ((node = walker.nextNode())) {
                const v = node.nodeValue || '';
                let m = v.match(_REL_RE);
                if (m) return { node, raw: m[0], full: v, kind: 'relative' };
                m = v.match(_REL_COMPACT_RE);
                if (m) return { node, raw: m[0], full: v, kind: 'relative' };
                m = v.match(_VIDEO_ABS_DATE_RE);
                if (m) return { node, raw: m[0], full: v, kind: 'absolute' };
            }
            return null;
        }

        function _displayDateForVideo(video, fallbackText, videoId, kept) {
            let setDate;
            try { setDate = Store.getCurrentDate(); } catch { return fallbackText || ''; }
            if (!setDate) return fallbackText || '';
            const id = videoId || (video && video.id) || '';
            const base = (video && video.relativeDate) || fallbackText || '';
            try {
                if (_VIDEO_ABS_DATE_RE.test(base)) {
                    const iso = DateHelper.parseExactDateText(base);
                    if (iso) return DateHelper.relativeToDate(new Date(iso), setDate, id);
                }
                const out = kept
                    ? DateHelper.recalcForKept(base, setDate, id)
                    : DateHelper.recalcForFeed(base, setDate, id);
                return out || base || '';
            } catch (_) {
                return base || '';
            }
        }

        function _writeCardDate(card, video, innerCards, fallbackText, kept) {
            const isKept = kept !== undefined ? !!kept :
                !!(card && card.getAttribute && card.getAttribute('data-bygone-keep'));
            const id = (video && video.id) || _cardVideoId(card, innerCards);
            const info = _cardDateTextInfo(card, innerCards);
            const raw = (video && video.relativeDate) || fallbackText || (info && info.raw) || '';
            if (!((video && video.relativeDate) || fallbackText)) {
                let hasExact = false;
                try { hasExact = !!(id && Store.getExactDate(id)); } catch (_) {}
                if (!hasExact) return false;
            }
            const display = _displayDateForVideo(video, raw, id, isKept);
            if (!display) return false;
            try {
                if (raw) card.setAttribute('data-bygone-date-source', raw);
                card.setAttribute('data-bygone-date-display', display);
            } catch (_) {}
            if (!info || !info.node) return false;
            const full = info.full || info.node.nodeValue || '';
            const next = full.indexOf(info.raw) !== -1 ? full.replace(info.raw, display) : display;
            if (info.node.nodeValue !== next) info.node.nodeValue = next;
            try {
                const walker = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, {
                    acceptNode: (n) => _ownedBy(n, innerCards || []) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT,
                });
                let n;
                while ((n = walker.nextNode())) {
                    if (n === info.node || _inTitleEl(n)) continue;
                    const val = n.nodeValue || '';
                    const cleaned = val.replace(_REL_RE, '').replace(_REL_COMPACT_RE, '').replace(_VIDEO_ABS_DATE_RE, '');
                    if (cleaned !== val) n.nodeValue = cleaned;
                }
            } catch (_) {}
            return true;
        }

        function _redateKeptCard(card, vid, innerCards) {
            if (!card || !card.getAttribute) return false;
            if (card.getAttribute('data-bygone-redated') === '1') return true;
            const inner = innerCards || [];
            const info = _cardDateTextInfo(card, inner);
            const stored = card.getAttribute('data-bygone-date-source') || '';
            const source = stored || (info && info.raw) || '';
            if (!source) return false;
            if (!stored && !_relTextAtOrBeforeSet(source) && !_VIDEO_ABS_DATE_RE.test(source)) {
                card.setAttribute('data-bygone-redated', '1');
                return true;
            }
            const ok = _writeCardDate(card, { id: vid, relativeDate: source }, inner, source, true);
            if (ok) card.setAttribute('data-bygone-redated', '1');
            return ok;
        }

        function _setCardChannel(card, video, innerCards) {
            if (!card || !video || !video.channel) return;
            const want = video.channel;
            const href = video.channelId ? '/channel/' + video.channelId : null;
            const inner = innerCards || [];
            const owns = (el) => _ownedBy(el, inner);
            const ownedFirst = (sel) => {
                for (const e of card.querySelectorAll(sel)) if (owns(e)) return e;
                return null;
            };

            let hitAnchor = false;
            card.querySelectorAll(
                'a[href^="/channel/"], a[href^="/user/"], a[href^="/c/"], a[href^="/@"]'
            ).forEach(link => {
                if (!owns(link)) return;
                if (link.querySelector('img')) return;
                if ((link.textContent || '').trim() !== want) link.textContent = want;
                if (href && link.getAttribute('href') !== href) link.setAttribute('href', href);
                hitAnchor = true;
            });
            if (hitAnchor) return;

            let el = ownedFirst('.attribution .g-hovercard')
                || ownedFirst('.attribution .yt-user-name')
                || ownedFirst('.attribution');
            if (!el) {
                el = ownedFirst(
                    '.chan-name, .yt-user-name, .video-user-name, ' +
                    '#channel-name, .ytd-channel-name'
                );
            }
            if (!el) return;
            if (el.matches && el.matches('[class*="title"], #video-title, h3, h3 *')) return;

            const cur = el.textContent || '';
            const byMatch = cur.match(/^(\s*by\s+)/i);
            const desired = (byMatch ? byMatch[1] : '') + want;
            if (cur.trim() !== desired.trim()) el.textContent = desired;
        }

        function _displayThumbUrl(video, videoId) {
            const id = videoId || (video && video.id) || '';
            const fallback = id ? ('https://i.ytimg.com/vi/' + id + '/mqdefault.jpg') : '';
            const raw = (video && video.thumbnail) || fallback;
            if (!raw) return fallback;
            return String(raw).replace(/\/(default|hqdefault|sddefault)\.(jpg|webp)(\?.*)?$/i, '/mqdefault.$2$3');
        }

        function _rewriteCard(card, video, innerCards) {
            const vid = video.id;
            const watchUrl = '/watch?v=' + vid;
            const thumbUrl = _displayThumbUrl(video, vid);
            const inner = innerCards || [];
            const owns = (el) => _ownedBy(el, inner);
            const ownedQS = (sel) =>
                Array.from(card.querySelectorAll(sel)).filter(owns);

            ownedQS('a').forEach(a => {
                const href = a.getAttribute('href') || '';
                if (href.includes('/watch')) a.setAttribute('href', watchUrl);
            });

            const primaryLink = _primaryWatchLink(card, inner);
            const targetImgs = new Set();
            if (primaryLink) primaryLink.querySelectorAll('img').forEach(im => {
                if (owns(im) && !_imgInButton(im) && !_isAvatarImg(im)) targetImgs.add(im);
            });
            ownedQS('img').forEach(im => {
                if (_imgInButton(im) || _isAvatarImg(im)) return;
                const cls = (im.className || '') + ' ' + (im.parentElement && im.parentElement.className || '');
                if (/thumb|preview|video/i.test(cls)) targetImgs.add(im);
            });
            if (!targetImgs.size) {
                const fi = ownedQS('img').find(im => !_imgInButton(im) && !_isAvatarImg(im));
                if (fi) targetImgs.add(fi);
            }
            if (!targetImgs.size) {
                const thumbImg = document.createElement('img');
                thumbImg.src = thumbUrl;
                thumbImg.alt = video.title || '';
                thumbImg.className = 'bygone-thumb';
                thumbImg.setAttribute('data-bygone-thumb', '1');
                const link = ownedQS('a[href*="/watch"]')[0];
                if (link) link.insertBefore(thumbImg, link.firstChild);
                else card.insertBefore(thumbImg, card.firstChild);
                _applyThumbInlineStyle(thumbImg);
            } else {
                targetImgs.forEach(img => {
                    _writeThumbImage(img, thumbUrl, video.title || '');
                    _showThumbParents(img, card);
                });
            }
            ownedQS('source').forEach(s => {
                if (s.hasAttribute('srcset')) s.setAttribute('srcset', thumbUrl);
                if (s.hasAttribute('src')) s.setAttribute('src', thumbUrl);
            });
            ownedQS('[style*="ytimg"], [style*="background-image"]').forEach(el => {
                try { el.style.backgroundImage = 'url(' + thumbUrl + ')'; } catch (_) {}
            });
            ownedQS('[data-thumb], [data-thumbnail], [data-thumb-url]').forEach(el => {
                if (el.hasAttribute('data-thumb')) el.setAttribute('data-thumb', thumbUrl);
                if (el.hasAttribute('data-thumbnail')) el.setAttribute('data-thumbnail', thumbUrl);
                if (el.hasAttribute('data-thumb-url')) el.setAttribute('data-thumb-url', thumbUrl);
            });

            const titleSels = [
                '.yt-lockup-title a[href*="/watch"]',
                'h3.yt-lockup-title a[href*="/watch"]',
                'a.yt-uix-tile-link[href*="/watch"]',
                'a.yt-uix-sessionlink[href*="/watch"]',
                '.lohp-video-link[href*="/watch"]',
                '#video-title-link',
                'a#video-title',
                'span#video-title',
                '#video-title',
                'a[href*="/watch"] .yt-ui-ellipsis-wrapper',
                'a[href*="/watch"] .title',
                'a.related-video span.title',
                '.related-video .title',
                'span.title',
                '.title',
            ];
            let titleEl = null;
            for (const sel of titleSels) {
                const candidates = ownedQS(sel).filter(e => {
                    if (!e || (e.querySelector && e.querySelector('img'))) return false;
                    if (e.closest && e.closest('.yt-lockup-meta, .lohp-video-metadata, .attribution')) return false;
                    const a = e.matches && e.matches('a') ? e : (e.closest && e.closest('a'));
                    return !a || ((a.getAttribute('href') || '').indexOf('/watch') !== -1);
                });
                titleEl = candidates.find(e => (e.textContent || '').trim()) || candidates[0] || null;
                if (titleEl) break;
            }
            if (titleEl && video.title) {
                titleEl.textContent = video.title;
                if (titleEl.hasAttribute('title')) titleEl.setAttribute('title', video.title);
                const titleAnchor = titleEl.matches && titleEl.matches('a') ? titleEl : (titleEl.closest && titleEl.closest('a'));
                if (titleAnchor) {
                    titleAnchor.setAttribute('href', watchUrl);
                    titleAnchor.setAttribute('title', video.title);
                }
            }

            _setCardChannel(card, video, inner);

            const walker = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, {
                acceptNode: (node) => owns(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT,
            });
            let node, viewsNode = null;
            const extraViewsNodes = [];
            const watchingNodes = [];
            while ((node = walker.nextNode())) {
                if (_inTitleEl(node)) continue;
                const v = node.nodeValue || '';
                if (/\b\d[\d,.]*\s*[KkMmBb]?\s*views?\b/.test(v)) {
                    if (!viewsNode) viewsNode = node;
                    else extraViewsNodes.push(node);
                }
                if (/\b\d[\d,.]*\s*[KkMmBb]?\s+watching\b/i.test(v)) watchingNodes.push(node);
            }
            if (viewsNode && (video.viewCountFormatted || video.viewCount)) {
                viewsNode.nodeValue = _isStuckAt301(video.id) ? '301 views' : (video.viewCountFormatted || (video.viewCount + ' views'));
            }
            for (const extra of extraViewsNodes) {
                extra.nodeValue = (extra.nodeValue || '').replace(/\b\d[\d,.]*\s*[KkMmBb]?\s*views?\b/g, '');
            }
            for (const w of watchingNodes) {
                w.nodeValue = (w.nodeValue || '').replace(/\b\d[\d,.]*\s*[KkMmBb]?\s+watching(\s+now)?\b/gi, '');
            }
            _writeCardDate(card, video, inner, video.relativeDate || '');

            const durEl = ownedQS('.video-time, .ytd-thumbnail-overlay-time-status-renderer, .badge-shape-wiz__text')[0];
            if (durEl) durEl.textContent = video.duration || '';

            card.setAttribute('data-bygone-swept', vid);
        }

        function _refreshCardDate(card, video, inner) {
            if (!card || !video || !video.id) return;
            const setDate = Store.getCurrentDate();
            if (!setDate) return;
            const stored = card.getAttribute && card.getAttribute('data-bygone-date-source');
            _writeCardDate(card, video, inner, stored || video.relativeDate || '');
        }

        function refreshAllDates() {
            try {
                if (!Store.getCurrentDate()) return;
                const cards = _findCards(document);
                for (const card of cards) {
                    const inner = _innerCardsOf(card, cards);
                    const vid = _cardVideoId(card, inner);
                    if (!vid) continue;
                    const video = videoPool.find(v => v.id === vid);
                    const stored = card.getAttribute && card.getAttribute('data-bygone-date-source');
                    let hasExact = false;
                    try { hasExact = !!Store.getExactDate(vid); } catch (_) {}
                    if (!video && !stored && !hasExact) continue;
                    _refreshCardDate(card, video || { id: vid }, inner);
                }
            } catch (_) {}
        }

        function _imgSourceText(img) {
            if (!img) return '';
            return [
                img.currentSrc || '',
                img.getAttribute('src') || '',
                img.getAttribute('srcset') || '',
                img.getAttribute('data-src') || '',
                img.getAttribute('data-thumb') || '',
                img.getAttribute('data-thumbnail') || '',
                img.getAttribute('data-thumb-url') || '',
            ].join(' ');
        }

        function _imgHasAnySource(img, videoId) {
            const text = _imgSourceText(img);
            if (videoId) return text.indexOf(videoId) !== -1;
            if (text.length <= 10) return false;
            return !/data:image|blank|transparent|placeholder/i.test(text);
        }

        function _showThumbNode(el, isImg) {
            if (!el || !el.style) return;
            try {
                el.style.setProperty('visibility', 'visible', 'important');
                el.style.setProperty('opacity', '1', 'important');
                if (isImg) {
                    el.style.setProperty('display', 'block', 'important');
                    el.style.setProperty('max-width', '100%', 'important');
                }
            } catch (_) {}
        }

        function _showThumbParents(el, stop) {
            for (let p = el && el.parentElement; p && p !== stop && p !== document.body; p = p.parentElement) {
                const sig = ((p.className || '') + ' ' + (p.id || '')).toString();
                if (/thumb|thumbnail|video-thumb|yt-thumb|ux-thumb|image|preview/i.test(sig)) {
                    _showThumbNode(p, false);
                }
            }
        }

        function _isStuckAt301(videoId) {
            if (!videoId) return false;
            for (var h = 0, i = 0; i < videoId.length; i++)
                h = ((h << 5) - h + videoId.charCodeAt(i)) | 0;
            return (((h < 0 ? -h : h) >>> 0) % 10000) === 0;
        }

        function _imgInButton(el) {
            for (var e = el && el.parentElement; e; e = e.parentElement) {
                var tag = e.tagName;
                if (tag === 'BUTTON' || (e.getAttribute && e.getAttribute('role') === 'button')) return true;
                if (/video-thumb|yt-lockup|context-data-item/.test((e.className || '').toString())) return false;
            }
            return false;
        }

        const _AVATAR_SIG_RE = /avatar|actor|author|byline|channel-thumb|user-photo|user-thumb|profile|yt-thumb-2[04-9]\b|yt-thumb-[3-8][0-9]\b/i;
        function _isAvatarImg(img) {
            if (!img) return false;
            if (/yt3\.ggpht\.com|\/photo\.jpg/i.test(_imgSourceText(img))) return true;
            if (_isCommentishArea(img)) return true;
            var ownSig = ((img.className || '') + ' ' + (img.id || '') + ' ' +
                ((img.parentElement && img.parentElement.className) || '')).toString();
            if (_AVATAR_SIG_RE.test(ownSig)) return true;
            var a = img.closest && img.closest('a[href]');
            if (a) {
                var href = a.getAttribute('href') || '';
                if (/^\/(channel\/|user\/|c\/|@)/.test(href)) return true;
                if (href.indexOf('/watch') !== -1) return false;
            }
            var sig = ownSig;
            var e = img.parentElement;
            for (var i = 0; e && i < 4; e = e.parentElement, i++) {
                sig += ' ' + ((e.className || '') + ' ' + (e.id || '')).toString();
            }
            if (_AVATAR_SIG_RE.test(sig)) return true;
            var w = parseInt(img.getAttribute('width') || '', 10) || img.naturalWidth || 0;
            var h = parseInt(img.getAttribute('height') || '', 10) || img.naturalHeight || 0;
            return !!(w && h && w === h && w <= 88);
        }

        function _applyThumbInlineStyle(img) {
            if (!img || !img.style) return;
            if (_imgInButton(img)) return;
            if (_isAvatarImg(img)) return;
            try {
                for (var p = img.parentElement; p; p = p.parentElement) {
                    var pcls = (p.className || '').toString();
                    if (/sidethumb|side-thumbs|yt-pl-thumb-side/.test(pcls)) return;
                    if (/context-data-item|yt-lockup|shelf-content|video-list-item|related-list-item/.test(pcls)) break;
                }

                var st = img.style;
                st.setProperty('width', '100%', 'important');
                st.setProperty('height', 'auto', 'important');
                st.setProperty('max-width', '100%', 'important');
                st.setProperty('max-height', 'none', 'important');
                st.setProperty('aspect-ratio', '16 / 9', 'important');
                st.setProperty('object-fit', 'cover', 'important');
                st.setProperty('object-position', 'center center', 'important');
                st.setProperty('display', 'block', 'important');
                st.setProperty('position', 'static', 'important');
                st.setProperty('top', 'auto', 'important');
                st.setProperty('left', 'auto', 'important');
                st.setProperty('margin', '0', 'important');
                st.setProperty('transform', 'none', 'important');

                var slot = null;
                for (var e = img.parentElement, i = 0; e && i < 8; e = e.parentElement, i++) {
                    if (/\bvideo-thumb\b/.test((e.className || '').toString())) { slot = e; break; }
                }
                if (slot) {
                    if (img.parentElement !== slot) slot.appendChild(img);
                    slot.style.setProperty('overflow', 'hidden', 'important');
                    slot.style.setProperty('padding', '0', 'important');
                    var clips = slot.querySelectorAll('.yt-thumb-default, .yt-thumb-clip, .yt-thumb-clip-inner');
                    for (var c = 0; c < clips.length; c++) {
                        clips[c].style.setProperty('display', 'none', 'important');
                    }
                    slot.setAttribute('data-bygone-clip-fixed', '1');
                }
            } catch (_) {}
        }

        function _fixAllV3Clips() {
            try {
                var slots = document.querySelectorAll('.video-thumb');
                for (var si = 0; si < slots.length; si++) {
                    var slot = slots[si];
                    if (slot.getAttribute('data-bygone-clip-fixed')) continue;

                    var skip = false;
                    for (var p = slot.parentElement; p; p = p.parentElement) {
                        if (/sidethumb|side-thumbs|yt-pl-thumb-side/.test((p.className || '').toString())) { skip = true; break; }
                        if (/context-data-item|yt-lockup|shelf-content|video-list-item|related-list-item/.test((p.className || '').toString())) break;
                    }
                    if (skip) continue;

                    var clip = slot.querySelector('.yt-thumb-clip');
                    if (!clip) continue;

                    var img = clip.querySelector('img');
                    if (!img || _imgInButton(img) || _isAvatarImg(img)) continue;

                    if (img.parentElement !== slot) slot.appendChild(img);
                    slot.style.setProperty('overflow', 'hidden', 'important');
                    slot.style.setProperty('padding', '0', 'important');

                    var st = img.style;
                    st.setProperty('width', '100%', 'important');
                    st.setProperty('height', 'auto', 'important');
                    st.setProperty('max-width', '100%', 'important');
                    st.setProperty('max-height', 'none', 'important');
                    st.setProperty('aspect-ratio', '16 / 9', 'important');
                    st.setProperty('object-fit', 'cover', 'important');
                    st.setProperty('object-position', 'center center', 'important');
                    st.setProperty('display', 'block', 'important');
                    st.setProperty('position', 'static', 'important');
                    st.setProperty('top', 'auto', 'important');
                    st.setProperty('left', 'auto', 'important');
                    st.setProperty('margin', '0', 'important');
                    st.setProperty('transform', 'none', 'important');

                    var clips = slot.querySelectorAll('.yt-thumb-default, .yt-thumb-clip, .yt-thumb-clip-inner');
                    for (var c = 0; c < clips.length; c++) {
                        clips[c].style.setProperty('display', 'none', 'important');
                    }
                    slot.setAttribute('data-bygone-clip-fixed', '1');
                }
            } catch (_) {}
        }

        function _writeThumbImage(img, thumbUrl, title) {
            if (!img || !thumbUrl) return false;
            if (_isAvatarImg(img)) return false;
            try {
                img.setAttribute('src', thumbUrl);
                img.removeAttribute('srcset');
                img.setAttribute('data-src', thumbUrl);
                img.setAttribute('data-thumb', thumbUrl);
                img.setAttribute('data-thumbnail', thumbUrl);
                img.setAttribute('data-thumb-url', thumbUrl);
                img.setAttribute('data-bygone-thumb', '1');
                _applyThumbInlineStyle(img);
                img.alt = title || '';
                _showThumbNode(img, true);
                return true;
            } catch (_) {
                return false;
            }
        }

        function _cleanupBygoneThumbs(card, inner, videoId) {
            const owns = (el) => _ownedBy(el, inner || []);
            const thumbs = Array.from(card.querySelectorAll('img.bygone-thumb')).filter(owns);
            if (!thumbs.length) return false;
            const nativeImgs = Array.from(card.querySelectorAll('img'))
                .filter(img => owns(img) && !img.classList.contains('bygone-thumb'));
            if (!nativeImgs.some(img => _imgHasAnySource(img, videoId))) return false;
            for (const thumb of thumbs) {
                try { thumb.remove(); } catch (_) {}
            }
            return true;
        }

        function _fillExistingThumbImg(card, videoId, inner) {
            const owns = (el) => _ownedBy(el, inner || []);
            const primary = _primaryWatchLink(card, inner || []);
            const imgRoot = primary || card;
            const imgs = Array.from(imgRoot.querySelectorAll('img'))
                .filter(img => owns(img) && !img.classList.contains('bygone-thumb') && !_imgInButton(img) && !_isAvatarImg(img));
            if (!imgs.length) return false;
            const alreadyGood = imgs.find(img => _imgHasAnySource(img, videoId));
            if (alreadyGood) {
                _showThumbNode(alreadyGood, true);
                _showThumbParents(alreadyGood, card);
                return true;
            }
            const target = imgs.find(img => {
                const cls = ((img.className || '') + ' ' +
                    ((img.parentElement && img.parentElement.className) || '')).toString();
                return /thumb|preview|video/i.test(cls);
            }) || imgs[0];
            const thumbUrl = _displayThumbUrl(null, videoId);
            const ok = _writeThumbImage(target, thumbUrl, target.alt || '');
            if (ok) _showThumbParents(target, card);
            return ok;
        }

        function _ensureThumbOnCard(card, videoId, inner) {
            if (_cleanupBygoneThumbs(card, inner, videoId)) return;
            const owns = (el) => _ownedBy(el, inner || []);
            const existingBygone = Array.from(card.querySelectorAll('img.bygone-thumb')).find(owns);
            if (existingBygone) {
                _applyThumbInlineStyle(existingBygone);
                _showThumbNode(existingBygone, true);
                _showThumbParents(existingBygone, card);
                return;
            }
            if (_fillExistingThumbImg(card, videoId, inner)) return;
            const thumbUrl = _displayThumbUrl(null, videoId);
            const thumbImg = document.createElement('img');
            thumbImg.src = thumbUrl;
            thumbImg.className = 'bygone-thumb';
            thumbImg.setAttribute('data-bygone-thumb', '1');
            thumbImg.setAttribute('data-src', thumbUrl);
            thumbImg.setAttribute('data-thumb', thumbUrl);
            thumbImg.setAttribute('data-thumbnail', thumbUrl);
            _showThumbNode(thumbImg, true);
            const scaffold = Array.from(card.querySelectorAll(
                '.yt-thumb-clip-inner, .yt-thumb-clip, .yt-thumb, .video-thumb, ' +
                '.thumb-wrapper, .yt-lockup-thumbnail, ytd-thumbnail, picture'
            )).filter(owns)[0];
            if (scaffold) {
                _showThumbNode(scaffold, false);
                scaffold.insertBefore(thumbImg, scaffold.firstChild);
                _applyThumbInlineStyle(thumbImg);
                return;
            }
            const link = Array.from(card.querySelectorAll('a[href*="/watch"]')).filter(owns)[0];
            if (link) link.insertBefore(thumbImg, link.firstChild);
            else card.insertBefore(thumbImg, card.firstChild);
            _applyThumbInlineStyle(thumbImg);
        }

        const _VIEWS_TEST_RE = /\b\d[\d,.]*\s*[KkMmBb]?\s*views?\b/;
        const _VIEWS_STRIP_RE = /\b\d[\d,.]*\s*[KkMmBb]?\s*views?\b/g;
        const _WATCHING_TEST_RE = /\b\d[\d,.]*\s*[KkMmBb]?\s+watching\b/i;
        const _WATCHING_STRIP_RE = /\b\d[\d,.]*\s*[KkMmBb]?\s+watching(\s+now)?\b/gi;
        function _stripLeakedCardMeta(card, video, innerCards) {
            try {
                const owns = (el) => _ownedBy(el, innerCards || []);
                const walker = document.createTreeWalker(card, NodeFilter.SHOW_TEXT, {
                    acceptNode: (n) => owns(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT,
                });
                const expected = (video && _isStuckAt301(video.id)) ? '301 views' :
                    ((video && (video.viewCountFormatted ||
                    (video.viewCount && video.viewCount + ' views'))) || '');
                const viewNodes = [];
                let keeper = null;
                let n;
                while ((n = walker.nextNode())) {
                    if (_inTitleEl(n)) continue;
                    const v = n.nodeValue || '';
                    if (_VIEWS_TEST_RE.test(v)) {
                        viewNodes.push(n);
                        if (!keeper && expected && v.indexOf(expected) !== -1) keeper = n;
                    }
                    if (_WATCHING_TEST_RE.test(v)) {
                        n.nodeValue = v.replace(_WATCHING_STRIP_RE, '');
                    }
                }
                if (!keeper) keeper = viewNodes[0] || null;
                for (const vn of viewNodes) {
                    if (vn === keeper) continue;
                    vn.nodeValue = (vn.nodeValue || '').replace(_VIEWS_STRIP_RE, '');
                }
            } catch (_) {}
        }

        function _ensureMetadata(card, videoId, inner) {
            const owns = (el) => _ownedBy(el, inner || []);
            const contentArea = Array.from(card.querySelectorAll(
                '.lohp-media-object-content, .yt-lockup-content'
            )).filter(owns)[0];
            if (!contentArea) return;
            const seenGeneratedMeta = new Set();
            Array.from(contentArea.querySelectorAll('.bygone-meta')).filter(owns).forEach(el => {
                const sig = (el.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase();
                if (!sig || seenGeneratedMeta.has(sig)) {
                    try { el.remove(); } catch (_) {}
                    return;
                }
                seenGeneratedMeta.add(sig);
            });
            const hasChannel = contentArea.querySelector('.yt-user-name, a[href*="/channel/"]');
            const hasViews = /\b\d[\d,.]*\s*(?:[KkMmBb]\s*)?views?\b/i.test(contentArea.textContent || '');
            const hasDate = !!_cardDateTextInfo(card, inner || []);
            if (card.getAttribute('data-bygone-meta') === '1' && hasChannel && hasViews && hasDate) return;
            if (hasChannel && hasViews && hasDate) { card.setAttribute('data-bygone-meta', '1'); return; }
            const video = videoPool.find(v => v.id === videoId);
            if (!video) return;
            if (!hasChannel && video.channel) {
                const d = document.createElement('div');
                d.className = 'lohp-video-metadata bygone-meta';
                const chanHref = video.channelId ? '/channel/' + video.channelId : '#';
                d.innerHTML = '<span class="run run-text ">by </span>' +
                    '<a class="yt-user-name" href="' + chanHref + '">' +
                    video.channel.replace(/</g, '&lt;') + '</a>';
                contentArea.appendChild(d);
            }
            const viewsText = video.viewCountFormatted || (video.viewCount ? video.viewCount + ' views' : '');
            if (!hasViews || !hasDate) {
                const d = document.createElement('div');
                d.className = 'lohp-video-metadata bygone-meta';
                const dateStr = _displayDateForVideo(video, video.relativeDate || '', videoId);
                const parts = [];
                if (!hasViews && viewsText) parts.push('<span class="view-count">' + viewsText.replace(/</g, '&lt;') + '</span>');
                if (!hasDate && dateStr) parts.push('<span class="content-item-time-created">' + dateStr.replace(/</g, '&lt;') + '</span>');
                d.innerHTML = '<span>' + parts.join(' ') + '</span>';
                contentArea.appendChild(d);
                if (dateStr) {
                    try {
                        card.setAttribute('data-bygone-date-source', video.relativeDate || dateStr);
                        card.setAttribute('data-bygone-date-display', dateStr);
                    } catch (_) {}
                }
            }
            card.setAttribute('data-bygone-meta', '1');
        }

        function _hasRevealedInnerCard(innerCards) {
            for (const inner of innerCards || []) {
                if (!inner || !inner.getAttribute) continue;
                if (inner.getAttribute('data-bygone-ok') === '1') return true;
                if (inner.getAttribute('data-bygone-swept')) return true;
                if (inner.getAttribute('data-bygone-keep')) return true;
            }
            return false;
        }

        function _poolVideoVisiblyInCard(card) {
            if (!card || !videoPool.length) return null;
            try {
                const imgs = card.querySelectorAll ? Array.from(card.querySelectorAll('img')) : [];
                for (const img of imgs) {
                    const src = _imgSourceText(img);
                    if (!src) continue;
                    for (const v of videoPool) {
                        if (v && v.id && src.indexOf(v.id) !== -1) return v;
                    }
                }
                const text = card.textContent || '';
                if (!text) return null;
                for (const v of videoPool) {
                    if (v && v.id && v.title && text.indexOf(v.title) !== -1) return v;
                }
            } catch (_) {}
            return null;
        }

        function _poolCardNeedsResync(card, video, inner) {
            if (!card || !video || !video.id) return false;
            const expectedId = video.id;
            try {
                const linkedId = _cardVideoId(card, inner || []);
                if (linkedId && linkedId !== expectedId) return true;
                if (card.getAttribute && card.getAttribute('data-bygone-swept') !== expectedId) return true;
                if (video.title && (card.textContent || '').indexOf(video.title) === -1) return true;

                const owned = (el) => _ownedBy(el, inner || []);
                const primary = _primaryWatchLink(card, inner || []);
                const imgs = primary
                    ? Array.from(primary.querySelectorAll('img')).filter(owned)
                    : [];
                if (imgs.length && !imgs.some(img => _imgSourceText(img).indexOf(expectedId) !== -1)) return true;
            } catch (_) {}
            return false;
        }

        const _cardSyncAt = new WeakMap();
        function _syncPoolCard(card, video, inner, st) {
            if (!card || !video || !video.id) return;
            if (_poolCardNeedsResync(card, video, inner)) {
                try {
                    _rewriteCard(card, video, inner);
                    if (st) st.rewritten++;
                } catch (_) {
                    if (st) st.rewriteThrew++;
                }
            } else {
                try {
                    card.setAttribute('data-bygone-swept', video.id);
                    card.setAttribute('data-bygone-ok', '1');
                } catch (_) {}
                if (Date.now() - (_cardSyncAt.get(card) || 0) < 2500) return;
            }
            _cardSyncAt.set(card, Date.now());
            try { _setCardChannel(card, video, inner || []); } catch (_) {}
            try { _ensureThumbOnCard(card, video.id, inner || []); } catch (_) {}
            try { _ensureMetadata(card, video.id, inner || []); } catch (_) {}
            try { _refreshCardDate(card, video, inner || []); } catch (_) {}
            _stripLeakedCardMeta(card, video, inner || []);
        }

        function _searchSweep() {
            if (!active || _userPaused) return;
            const _p = location.pathname;
            if (_p !== '/results' && _p !== '/results/') return;
            const cards = _findCards(document);
            for (const card of cards) {
                if (card.getAttribute && card.getAttribute('data-bygone-search-dated')) continue;
                const inner = _innerCardsOf(card, cards);
                const vid = _cardVideoId(card, inner);
                if (!vid) continue;
                card.setAttribute('data-bygone-ok', '1');
                const stored = card.getAttribute('data-bygone-date-source');
                if (_writeCardDate(card, { id: vid }, inner, stored || '')) {
                    card.setAttribute('data-bygone-search-dated', '1');
                }
            }
        }

        function _sweep() {
            if (!active || _userPaused || !videoPool.length) return;
            const _p = location.pathname;
            if (_p === '/results' || _p === '/results/' || _isChannelPage()) return;
            if (_isHomeLikePath()) _cleanupHomeSpaArtifacts();
            startResponseScope();
            const poolIds = _poolIdSet();
            const cards = _findCards(document);
            const st = {
                total: cards.length, alreadySwept: 0, keep: 0, noOwnedLink: 0,
                badHref: 0, isPool: 0, natural: 0, mapNull: 0, dupSkip: 0,
                dupReuse: 0, dupFixed: 0, wrapperReveal: 0, rewritten: 0, rewriteThrew: 0
            };
            _sweepStats = st;
            if (!cards.length) return;
            let swept = 0;
            const poolById = new Map();
            for (const v of videoPool) if (v && v.id) poolById.set(v.id, v);

            const seenOnPage = new Set();
            for (const card of cards) {
                const inner = _innerCardsOf(card, cards);
                const a = _primaryWatchLink(card, inner);
                if (!a) continue;
                const m = (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (m && poolIds.has(m[1])) seenOnPage.add(m[1]);
            }
            const keptPoolThisSweep = new Set();

            for (const card of cards) {
                const inner = _innerCardsOf(card, cards);
                if (card.getAttribute && card.getAttribute('data-bygone-swept')) {
                    const sweptVid = card.getAttribute('data-bygone-swept');
                    const visibleVid = _cardVideoId(card, inner) || sweptVid;
                    const targetVid = (visibleVid && poolIds.has(visibleVid)) ? visibleVid : sweptVid;
                    if (poolIds.has(targetVid)) {
                        seenOnPage.add(targetVid);
                        keptPoolThisSweep.add(targetVid);
                    }
                    const sweptVideo = poolById.get(targetVid);
                    if (sweptVideo) {
                        _syncPoolCard(card, sweptVideo, inner, st);
                    }
                    st.alreadySwept++;
                    continue;
                }
                if (card.getAttribute && card.getAttribute('data-bygone-keep')) {
                    const keepVid = _cardVideoId(card, inner);
                    if (keepVid) _redateKeptCard(card, keepVid, inner);
                    card.setAttribute('data-bygone-ok', '1');
                    st.keep++;
                    continue;
                }
                const a = _primaryWatchLink(card, inner);
                if (!a) {
                    st.noOwnedLink++;
                    if (_hasRevealedInnerCard(inner)) {
                        card.setAttribute('data-bygone-ok', '1');
                        st.wrapperReveal++;
                    }
                    continue;
                }
                const m = (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (!m) { card.setAttribute('data-bygone-ok', '1'); st.badHref++; continue; }
                const currentVid = m[1];

                if (poolIds.has(currentVid)) {
                    seenOnPage.add(currentVid);
                    keptPoolThisSweep.add(currentVid);
                    card.setAttribute('data-bygone-ok', '1');
                    const currentVideo = poolById.get(currentVid);
                    if (currentVideo) {
                        _syncPoolCard(card, currentVideo, inner, st);
                    }
                    st.isPool++;
                    continue;
                }

                if (_keptNaturalIds.has(currentVid) || _cardIsNaturallyOld(card, inner)) {
                    _keptNaturalIds.add(currentVid);
                    _redateKeptCard(card, currentVid, inner);
                    card.setAttribute('data-bygone-ok', '1');
                    card.setAttribute('data-bygone-keep', '1');
                    _ensureThumbOnCard(card, currentVid, inner);
                    _ensureMetadata(card, currentVid, inner);
                    st.natural++;
                    continue;
                }

                let next = _nextDomVideoFor(currentVid);
                if (!next) { st.mapNull++; continue; }
                if (seenOnPage.has(next.id)) {
                    const alt = _freshDomVideoAvoiding(seenOnPage);
                    if (alt) { next = alt; st.dupReuse++; }
                    else st.dupSkip++;
                }
                seenOnPage.add(next.id);
                keptPoolThisSweep.add(next.id);
                try { _rewriteCard(card, next, inner); swept++; st.rewritten++; } catch (_) { st.rewriteThrew++; }
            }
        }

        let _sidebarObs = null;
        let _sidebarObsTarget = null;

        function _sidebarSweep() {
            let resumeTarget = null;
            if (_sidebarObs && _sidebarObsTarget) {
                try { _sidebarObs.disconnect(); resumeTarget = _sidebarObsTarget; } catch (_) {}
            }
            try { _sidebarSweepCore(); }
            finally {
                if (_sidebarObs && resumeTarget) {
                    try { _sidebarObs.observe(resumeTarget, { childList: true, subtree: true }); } catch (_) {}
                }
            }
        }

        function _sidebarSweepCore() {
            if (!active || _userPaused || !videoPool.length) return;
            if (!location.pathname.startsWith('/watch')) return;
            startResponseScope();
            const poolIds = _poolIdSet();
            const poolById = new Map();
            for (const v of videoPool) poolById.set(v.id, v);

            const rewriteIfNeeded = (card) => {
                if (!card) return;
                if (card.getAttribute && card.getAttribute('data-bygone-swept')) {
                    const sweptVid = card.getAttribute('data-bygone-swept');
                    const visibleVid = _cardVideoId(card) || sweptVid;
                    const targetVid = (visibleVid && poolIds.has(visibleVid)) ? visibleVid : sweptVid;
                    const vobj = poolById.get(targetVid);
                    if (vobj) {
                        _syncPoolCard(card, vobj, [], null);
                    }
                    return;
                }
                if (card.getAttribute && card.getAttribute('data-bygone-keep')) {
                    const keepVid = _cardVideoId(card);
                    if (keepVid) _redateKeptCard(card, keepVid);
                    card.setAttribute('data-bygone-ok', '1');
                    return;
                }
                const a = _primaryWatchLink(card);
                if (!a) return;
                const m = (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (!m) return;
                const cur = m[1];
                if (poolIds.has(cur)) {
                    card.setAttribute('data-bygone-ok', '1');
                    const vobj = poolById.get(cur);
                    if (vobj) {
                        _syncPoolCard(card, vobj, [], null);
                    }
                    return;
                }
                if (_keptNaturalIds.has(cur) || _cardIsNaturallyOld(card)) {
                    _keptNaturalIds.add(cur);
                    _redateKeptCard(card, cur);
                    card.setAttribute('data-bygone-ok', '1');
                    card.setAttribute('data-bygone-keep', '1');
                    try { _ensureThumbOnCard(card, cur); } catch (_) {}
                    try { _ensureMetadata(card, cur); } catch (_) {}
                    return;
                }
                const next = _nextDomVideoFor(cur);
                if (!next) {
                    const stored = card.getAttribute('data-bygone-date-source');
                    _writeCardDate(card, { id: cur }, [], stored || '');
                    card.setAttribute('data-bygone-ok', '1');
                    return;
                }
                try { _rewriteCard(card, next); } catch (_) {}
            };

            document.querySelectorAll(
                '#watch7-sidebar-contents ol > li, #watch7-sidebar ol > li, ' +
                '#watch7-sidebar-modules li.video-list-item, .watch-sidebar-body li'
            ).forEach(rewriteIfNeeded);

            const containers = [
                document.getElementById('watch7-sidebar-contents'),
                document.getElementById('watch7-sidebar'),
                document.getElementById('watch7-sidebar-modules'),
                document.getElementById('related'),
                document.getElementById('secondary'),
                document.getElementById('secondary-inner'),
            ].filter(Boolean);
            const seenCards = new Set();
            for (const c of containers) {
                const classicMatches = c.querySelectorAll(
                    '.video-list-item, .related-list-item, ytd-compact-video-renderer, ' +
                    'yt-lockup-view-model, yt-collection-thumbnail-view-model, ' +
                    '.ytd-watch-next-secondary-results-renderer'
                );
                const cards = new Set(Array.from(classicMatches));
                c.querySelectorAll('a[href*="/watch?v="]').forEach(a => {
                    let p = a;
                    for (let i = 0; i < 8 && p && p !== c; i++) {
                        if (p.querySelector && p.querySelector('img')) { cards.add(p); break; }
                        p = p.parentElement;
                    }
                });
                cards.forEach(card => {
                    if (seenCards.has(card)) return;
                    seenCards.add(card);
                    rewriteIfNeeded(card);
                });
            }
            _hideSidebarLoadMore();
        }

        function _hideSidebarLoadMore() {
            const containers = document.querySelectorAll(
                '#watch7-sidebar, #watch7-sidebar-modules, #watch7-sidebar-contents, ' +
                '.watch-sidebar, .watch-sidebar-body, #related, #secondary'
            );
            for (const c of containers) {
                const cands = c.querySelectorAll(
                    'button, [role="button"], [id*="more-related"], .yt-uix-load-more, ' +
                    '.load-more-button, [class*="load-more"], [class*="show-more"], ' +
                    '[class*="paginator"], .jfk-button'
                );
                for (const el of cands) {
                    if (el.getAttribute('data-bygone-more-hidden') === '1') continue;
                    if (el.closest('#watch-discussion, #comments, #comment-section-renderer, #movie_player')) continue;
                    if (el.querySelector('a[href*="/watch"]')) continue;
                    const text = (el.textContent || '').trim();
                    if (text.length > 40) continue;
                    const sig = ((el.id || '') + ' ' + (typeof el.className === 'string' ? el.className : '')).toLowerCase();
                    const sigHit = /more-related|load-more|show-more/.test(sig);
                    const textHit = /^(load|show)\s+more(\s+suggestions?|\s+videos?|\s+related)?$/i.test(text);
                    if (!sigHit && !textHit) continue;
                    try {
                        el.style.setProperty('display', 'none', 'important');
                        el.setAttribute('data-bygone-more-hidden', '1');
                    } catch (_) {}
                }
            }
        }

        let _lastSidebarExtend = 0;
        function _sidebarContainer() {
            return document.getElementById('watch7-sidebar-contents')
                || document.getElementById('watch7-sidebar')
                || document.getElementById('watch7-sidebar-modules')
                || document.querySelector('.watch-sidebar-body')
                || document.querySelector('#related')
                || document.querySelector('#secondary-inner')
                || document.querySelector('#secondary');
        }

        function _ensureSidebarList() {
            const existing = document.querySelector(
                '#watch7-sidebar-contents ol, #watch7-sidebar ol, ' +
                '#watch7-sidebar-modules ol, .watch-sidebar-body ol, ' +
                '#bygone-watch-sidebar-fallback'
            );
            if (existing) return existing;
            const host = _sidebarContainer();
            if (!host) return null;
            const ol = document.createElement('ol');
            ol.id = 'bygone-watch-sidebar-fallback';
            ol.className = 'video-list';
            try {
                ol.style.setProperty('list-style', 'none', 'important');
                ol.style.setProperty('margin', '0', 'important');
                ol.style.setProperty('padding', '0', 'important');
            } catch (_) {}
            host.appendChild(ol);
            return ol;
        }

        const _CLONE_MARK_ATTRS = [
            'data-bygone-swept', 'data-bygone-ok', 'data-bygone-keep', 'data-bygone-redated',
            'data-bygone-date-source', 'data-bygone-date-display', 'data-bygone-meta',
            'data-bygone-search-dated', 'data-bygone-home-extend',
        ];
        function _stripCloneMarks(clone) {
            for (const a of _CLONE_MARK_ATTRS) {
                try {
                    clone.removeAttribute(a);
                    if (clone.querySelectorAll) clone.querySelectorAll('[' + a + ']').forEach(el => el.removeAttribute(a));
                } catch (_) {}
            }
        }

        function _titleTokens(v) {
            const m = ((v && v.title) || '').toLowerCase().match(/[a-z0-9]{4,}/g);
            return m ? m.slice(0, 3) : [];
        }

        function _pickSpreadFromPool(shown, n) {
            const cands = [];
            for (const v of videoPool) if (v && v.id && !shown.has(v.id)) cands.push(v);
            for (let i = cands.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                const t = cands[i]; cands[i] = cands[j]; cands[j] = t;
            }
            const picks = [];
            const rest = [];
            let lastCh = '', lastSrc = '', lastTok = [];
            for (const v of cands) {
                if (picks.length >= n) break;
                const ch = (v.channelId || v.channel || '').toString();
                const src = (v.source || '').toString();
                const tok = _titleTokens(v);
                const clash = picks.length && (
                    (ch && ch === lastCh) ||
                    (src && src === lastSrc && tok.some(t => lastTok.indexOf(t) !== -1))
                );
                if (clash) { rest.push(v); continue; }
                picks.push(v);
                lastCh = ch; lastSrc = src; lastTok = tok;
            }
            for (const v of rest) { if (picks.length >= n) break; picks.push(v); }
            return picks;
        }

        function _fallbackSidebarTemplate() {
            const li = document.createElement('li');
            li.className = 'video-list-item related-list-item';
            li.setAttribute('data-bygone-sidebar-fallback', '1');
            li.innerHTML = [
                '<a class="content-link yt-uix-sessionlink" href="/watch?v=___________">',
                '<span class="thumb-wrapper" style="display:block;float:left;width:120px;margin-right:8px;">' +
                '<span class="yt-thumb video-thumb" style="display:block;width:120px;height:67px;overflow:hidden;">' +
                '<span class="yt-thumb-clip"><img class="thumb" alt="" style="display:block;width:120px;height:67px;object-fit:cover;"></span></span></span>',
                '<span class="content-wrapper yt-lockup-content">',
                '<span class="title"></span>',
                '<span class="stat attribution"><span class="g-hovercard yt-user-name"></span></span>',
                '<span class="metadata lohp-video-metadata"><span class="view-count">0 views</span> <span class="content-item-time-created">1 day ago</span></span>',
                '</span>',
                '</a>',
            ].join('');
            return li;
        }

        function _maybeExtendSidebar() {
            if (!active || _userPaused || !videoPool.length) return;
            if (!location.pathname.startsWith('/watch')) return;
            _hideSidebarLoadMore();
            const ol = _ensureSidebarList();
            if (!ol) return;
            const items = ol.querySelectorAll('li');
            const olBottom = ol.getBoundingClientRect().bottom;
            if (items.length && olBottom - window.innerHeight > 800) return;
            if (Date.now() - _lastSidebarExtend < 500) return;
            _lastSidebarExtend = Date.now();

            const shown = new Set();
            items.forEach(li => {
                const a = _primaryWatchLink(li);
                if (!a) return;
                const m = (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (m) shown.add(m[1]);
            });

            const picks = _pickSpreadFromPool(shown, 10);
            if (!picks.length) {
                _maybeFetchMore();
                return;
            }

            const template = items[0] || _fallbackSidebarTemplate();
            for (const v of picks) {
                try {
                    const clone = template.cloneNode(true);
                    _stripCloneMarks(clone);
                    _rewriteCard(clone, v);
                    clone.setAttribute('data-bygone-ok', '1');
                    ol.appendChild(clone);
                } catch (_) {}
            }
        }

        window.addEventListener('scroll', _maybeExtendSidebar, { passive: true });
        document.addEventListener('scroll', _maybeExtendSidebar, { passive: true, capture: true });

        function _currentWatchVideoId() {
            try {
                const u = new URL(location.href);
                const v = u.searchParams.get('v') || '';
                return _VALID_VID.test(v) ? v : '';
            } catch (_) {
                const m = (location.href || '').match(/[?&]v=([A-Za-z0-9_-]{11})/);
                return m ? m[1] : '';
            }
        }

        function _poolVideoById(id) {
            if (!id) return null;
            for (const v of videoPool) if (v && v.id === id) return v;
            return null;
        }

        function _extractVideoIdFromText(text) {
            if (!text) return '';
            const m = String(text).match(/(?:[?&]v=|\/(?:vi|embed|shorts)\/)([A-Za-z0-9_-]{11})/);
            return m ? m[1] : '';
        }

        function _playerRecVideoId(el) {
            if (!el) return '';
            const attrs = ['data-video-id', 'data-vid', 'data-videoid', 'video-id', 'videoid'];
            for (const a of attrs) {
                try {
                    const v = el.getAttribute && el.getAttribute(a);
                    if (v && _VALID_VID.test(v)) return v;
                } catch (_) {}
            }
            try {
                const link = el.matches && el.matches('a[href]') ? el : el.querySelector('a[href]');
                const id = link && _extractVideoIdFromText(link.getAttribute('href') || '');
                if (id) return id;
            } catch (_) {}
            try {
                const nodes = [el].concat(Array.from(el.querySelectorAll('[style], img, source')));
                for (const n of nodes) {
                    const id = _extractVideoIdFromText(
                        (n.getAttribute && (
                            n.getAttribute('src') || n.getAttribute('srcset') ||
                            n.getAttribute('style') || n.getAttribute('data-thumb') ||
                            n.getAttribute('data-thumbnail') || ''
                        )) || ''
                    );
                    if (id) return id;
                }
            } catch (_) {}
            return '';
        }

        function _pickPlayerPoolVideo(origId) {
            const current = _currentWatchVideoId();
            if (origId && _poolIdsSet.has(origId) && origId !== current) {
                const alreadyPool = _poolVideoById(origId);
                if (alreadyPool) return alreadyPool;
            }
            let mapped = null;
            if (origId && !_poolIdsSet.has(origId)) {
                try { mapped = _nextDomVideoFor(origId); } catch (_) {}
                if (mapped && mapped.id && mapped.id !== current) return mapped;
            }
            const avoid = new Set();
            if (current) avoid.add(current);
            if (origId) avoid.add(origId);
            try {
                const fresh = _freshDomVideoAvoiding(avoid);
                if (fresh) return fresh;
            } catch (_) {}
            for (const v of videoPool) {
                if (v && v.id && !avoid.has(v.id)) return v;
            }
            return videoPool[0] || null;
        }

        function _setFirstText(root, selectors, text) {
            if (!text) return false;
            for (const sel of selectors) {
                const els = root.querySelectorAll ? root.querySelectorAll(sel) : [];
                for (const el of els) {
                    if (!el || el.querySelector && el.querySelector('img')) continue;
                    try {
                        el.textContent = text;
                        if (el.hasAttribute && el.hasAttribute('title')) el.setAttribute('title', text);
                        return true;
                    } catch (_) {}
                }
            }
            return false;
        }

        function _rewritePlayerRecCard(card, video) {
            if (!card || !video || !video.id) return false;
            const vid = video.id;
            const watchUrl = '/watch?v=' + vid;
            const thumbUrl = _displayThumbUrl(video, vid);
            try {
                if (card.matches && card.matches('a[href]')) card.setAttribute('href', watchUrl);
                card.querySelectorAll('a[href]').forEach(a => {
                    const href = a.getAttribute('href') || '';
                    if (href.indexOf('/watch') !== -1 || href.indexOf('/shorts') !== -1 || href.indexOf('/embed') !== -1) {
                        a.setAttribute('href', watchUrl);
                    }
                });
            } catch (_) {}
            try {
                const nodes = [card].concat(Array.from(card.querySelectorAll('*')));
                for (const n of nodes) {
                    ['data-video-id', 'data-vid', 'data-videoid', 'video-id', 'videoid'].forEach(a => {
                        try { if (n.hasAttribute && n.hasAttribute(a)) n.setAttribute(a, vid); } catch (_) {}
                    });
                }
            } catch (_) {}
            try {
                card.querySelectorAll('img').forEach(img => {
                    _writeThumbImage(img, thumbUrl, video.title || '');
                    _showThumbParents(img, card);
                });
                card.querySelectorAll('source').forEach(s => {
                    if (s.hasAttribute('src')) s.setAttribute('src', thumbUrl);
                    if (s.hasAttribute('srcset')) s.setAttribute('srcset', thumbUrl);
                });
                [card].concat(Array.from(card.querySelectorAll('[style]'))).forEach(n => {
                    const style = n.getAttribute && (n.getAttribute('style') || '');
                    if (/ytimg|background-image/i.test(style)) n.style.backgroundImage = 'url("' + thumbUrl + '")';
                });
                card.querySelectorAll(
                    '.ytp-videowall-still-image, .ytp-ce-video-image, .ytp-ce-covering-image, ' +
                    '.ytp-ce-expanding-image, .ytp-autonav-endscreen-upnext-thumbnail'
                ).forEach(n => {
                    try { n.style.setProperty('background-image', 'url("' + thumbUrl + '")', 'important'); } catch (_) {}
                });
            } catch (_) {}
            _setFirstText(card, [
                '.ytp-ce-video-title',
                '.ytp-videowall-still-info-title',
                '.ytp-autonav-endscreen-upnext-title',
                '.ytp-suggestion-title',
                '.ytp-ce-expanding-overlay-title',
                '[class*="title"]'
            ], video.title || '');
            _setFirstText(card, [
                '.ytp-ce-video-metadata',
                '.ytp-videowall-still-info-author',
                '.ytp-autonav-endscreen-upnext-author',
                '.ytp-suggestion-author',
                '[class*="metadata"]'
            ], video.channel || '');
            try {
                card.setAttribute('data-bygone-player-card-ok', '1');
                card.setAttribute('data-bygone-player-video', vid);
                card.removeAttribute('data-bygone-player-card-blocked');
            } catch (_) {}
            return true;
        }

        function _looksLikePlayerRecCard(el) {
            if (!el || !el.closest || !el.closest('.html5-video-player, #movie_player')) return false;
            const cls = (el.className || '').toString();
            if (/ytp-(ce-video|videowall-still|autonav-endscreen-upnext|suggestion)/i.test(cls)) return true;
            return !!_playerRecVideoId(el);
        }

        function _playerRecCards() {
            const roots = document.querySelectorAll('.html5-video-player, #movie_player');
            const out = new Set();
            roots.forEach(root => {
                root.querySelectorAll([
                    '.ytp-ce-video',
                    '.ytp-ce-element',
                    '.ytp-videowall-still',
                    '.ytp-autonav-endscreen-upnext-container',
                    '.ytp-suggestion-link',
                    'a.ytp-suggestion-link'
                ].join(',')).forEach(el => {
                    if (_looksLikePlayerRecCard(el)) out.add(el);
                });
            });
            return Array.from(out);
        }

        let _lastAutoplayDisableAttempt = 0;
        let _autoplayDisableKey = '';
        let _autoplayDisableTries = 0;
        function _tryDisableAutoplayControl(el) {
            if (!el) return;
            const now = Date.now();
            if (now - _lastAutoplayDisableAttempt < 8000) return;
            const key = location.pathname + location.search;
            if (_autoplayDisableKey !== key) {
                _autoplayDisableKey = key;
                _autoplayDisableTries = 0;
            }
            if (_autoplayDisableTries >= 3) return;
            _autoplayDisableTries++;
            _lastAutoplayDisableAttempt = now;
            try { el.setAttribute('data-bygone-autoplay-disable-attempt', String(now)); } catch (_) {}
            try { el.click(); } catch (_) {}
        }
        function _disableNativeAutoplay() {
            if (!location.pathname.startsWith('/watch')) return;
            try {
                document.querySelectorAll('.ytp-autonav-toggle-button, .ytp-autonav-toggle-button-container button').forEach(btn => {
                    const state = (btn.getAttribute('aria-checked') || btn.getAttribute('aria-pressed') || '').toLowerCase();
                    const label = (btn.getAttribute('aria-label') || btn.getAttribute('title') || '').toLowerCase();
                    if (!(state === 'true' || /autoplay.*on|on.*autoplay/.test(label))) return;
                    _tryDisableAutoplayControl(btn);
                });
                document.querySelectorAll('.autoplay-bar input[type="checkbox"]:checked').forEach(_tryDisableAutoplayControl);
                document.querySelectorAll('.ytp-autonav-endscreen-countdown-container, .ytp-autonav-endscreen-countdown-overlay')
                    .forEach(el => el.setAttribute('data-bygone-player-card-blocked', '1'));
            } catch (_) {}
        }

        function _sweepPlayerRecommendations() {
            if (!active || _userPaused || !videoPool.length) return;
            if (!location.pathname.startsWith('/watch')) return;
            _disableNativeAutoplay();
            for (const card of _playerRecCards()) {
                const orig = _playerRecVideoId(card);
                const v = _pickPlayerPoolVideo(orig);
                if (!v) {
                    try { card.setAttribute('data-bygone-player-card-blocked', '1'); } catch (_) {}
                    continue;
                }
                _rewritePlayerRecCard(card, v);
            }
        }

        function _playerRecClickTarget(target) {
            if (!target || !target.closest) return null;
            return target.closest(
                '.ytp-next-button, .ytp-ce-video, .ytp-videowall-still, ' +
                '.ytp-autonav-endscreen-upnext-container, .ytp-suggestion-link'
            );
        }

        function _navigateToPoolVideo(video) {
            if (!video || !video.id) return false;
            try {
                Store.addClickEvent({
                    videoId: video.id, channelId: video.channelId || null,
                    channel: video.channel || '', title: video.title || '',
                    source: video.source || 'unknown', ts: Date.now(),
                });
                Store.markFeedClicked(video.id);
                Store.recordSourceClick(video.source || 'unknown');
            } catch (_) {}
            location.href = location.origin + '/watch?v=' + video.id;
            return true;
        }

        setInterval(_sweepPlayerRecommendations, 500);

        function _jitFixPlayerRec(e) {
            if (!active || _userPaused || !videoPool.length) return;
            try {
                const card = _playerRecClickTarget(e.target);
                if (!card || card.matches('.ytp-next-button')) return;
                const tagged = card.getAttribute && card.getAttribute('data-bygone-player-video');
                const v = (tagged && _poolVideoById(tagged)) || _pickPlayerPoolVideo(_playerRecVideoId(card));
                if (v) _rewritePlayerRecCard(card, v);
            } catch (_) {}
        }
        document.addEventListener('mousedown', _jitFixPlayerRec, true);
        document.addEventListener('touchstart', _jitFixPlayerRec, true);

        let _autoplayKickKey = '';
        let _autoplayKickTries = 0;
        function _watchVideoElement() {
            return document.querySelector('#movie_player video, .html5-video-player video, video.html5-main-video');
        }
        function _isFreshPausedWatchVideo(vid) {
            if (!vid || !vid.paused || vid.ended) return false;
            if (!isNaN(vid.duration) && vid.duration === 0) return false;
            return !isFinite(vid.currentTime) || vid.currentTime < 0.75;
        }
        function _ensureWatchAutoplay() {
            if (!active || _userPaused) return;
            if (!location.pathname.startsWith('/watch')) return;
            const key = location.search;
            if (_autoplayKickKey !== key) {
                _autoplayKickKey = key;
                _autoplayKickTries = 0;
            }
            if (_autoplayKickTries >= 10) return;
            const vid = _watchVideoElement();
            if (!vid || isNaN(vid.duration) || vid.duration === 0) return;
            if (vid.paused && vid.currentTime < 0.5) {
                _autoplayKickTries++;
                const p = vid.play();
                if (p && typeof p.catch === 'function') p.catch(() => {});
            } else {
                _autoplayKickTries = 10;
            }
        }
        setInterval(_ensureWatchAutoplay, 600);

        const _PLAYER_CHROME_CSS = [
            '.html5-video-player .ytp-gradient-bottom,.html5-video-player .ytp-gradient-top,.html5-video-player .ytp-heat-map-container{display:none!important;}',
            '.html5-video-player .ytp-chrome-bottom{left:0!important;right:0!important;width:100%!important;margin:0!important;background:linear-gradient(#2c2c2c,#080808)!important;border-top:1px solid rgba(255,255,255,.18)!important;box-sizing:border-box!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-chrome-bottom{bottom:0!important;height:38px!important;padding-top:6px!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-chrome-controls{height:32px!important;line-height:32px!important;background:transparent!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-chrome-controls .ytp-button{height:32px!important;width:34px!important;padding:0!important;color:#eee!important;filter:drop-shadow(0 -1px 0 rgba(0,0,0,.8))!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-time-display{height:32px!important;line-height:32px!important;font:12px/32px Arial,sans-serif!important;color:#ddd!important;text-shadow:0 -1px 0 #000!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-progress-bar-container{position:absolute!important;left:0!important;right:0!important;bottom:38px!important;width:100%!important;height:8px!important;padding:0!important;box-sizing:border-box!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-progress-bar{height:8px!important;}',
            '.html5-video-player .ytp-progress-bar{background:#454545!important;}',
            '.html5-video-player .ytp-load-progress{background:#777!important;}',
            '.html5-video-player .ytp-play-progress{background:#c00!important;}',
            '.html5-video-player:not(.ytp-fullscreen) .ytp-scrubber-button{width:12px!important;height:12px!important;margin-top:-2px!important;background:#eee!important;border:1px solid #333!important;border-radius:10px!important;}',
            '.html5-video-player .ytp-large-play-button{background:rgba(0,0,0,.78)!important;border:1px solid rgba(255,255,255,.35)!important;border-radius:4px!important;}',
            '.html5-video-player.ytp-autohide:not(.ytp-fullscreen):hover{cursor:auto!important;}',
            '.html5-video-player.ytp-autohide:not(.ytp-fullscreen):hover .ytp-chrome-bottom{opacity:1!important;transform:none!important;pointer-events:auto!important;}',
            '.watch-stage-mode #player{width:100%!important;max-width:none!important;float:none!important;}',
            '.watch-stage-mode #player-api,.watch-stage-mode [id^="player-api"],.watch-stage-mode #player-mole-container{width:100%!important;max-width:none!important;height:auto!important;aspect-ratio:16/9!important;max-height:calc(100vh - 140px)!important;margin:0 auto!important;float:none!important;position:relative!important;}',
            '.watch-stage-mode #player-api #movie_player,.watch-stage-mode [id^="player-api"] #movie_player,.watch-stage-mode #player-mole-container #movie_player,.watch-stage-mode #player-api .html5-video-player{width:100%!important;height:100%!important;left:0!important;top:0!important;}',
            '.watch-stage-mode #movie_player .html5-video-container{width:100%!important;height:100%!important;left:0!important;top:0!important;margin:0!important;}',
            '.watch-stage-mode #movie_player video.html5-main-video{width:100%!important;height:100%!important;left:0!important;top:0!important;object-fit:contain!important;}'
        ].join('\n');

        let _playerChromeSheet = null;
        function _ensurePlayerChromeCss() {
            const off = _userPaused || _isKioskOrMobileLayout();
            try {
                if (typeof CSSStyleSheet !== 'undefined' && document.adoptedStyleSheets !== undefined) {
                    if (!_playerChromeSheet) {
                        _playerChromeSheet = new CSSStyleSheet();
                        _playerChromeSheet.replaceSync(_PLAYER_CHROME_CSS);
                    }
                    _playerChromeSheet.disabled = off;
                    if (document.adoptedStyleSheets.indexOf(_playerChromeSheet) === -1) {
                        document.adoptedStyleSheets = document.adoptedStyleSheets.concat([_playerChromeSheet]);
                    }
                    return;
                }
            } catch (_) {}
            try {
                let s = document.getElementById('bygone-player-chrome-css');
                if (!s) {
                    s = document.createElement('style');
                    s.id = 'bygone-player-chrome-css';
                    s.textContent = _PLAYER_CHROME_CSS;
                    (document.head || document.documentElement).appendChild(s);
                }
                s.media = off ? 'not all' : 'all';
            } catch (_) {}
        }

        let _stagePokeKey = '';
        let _stagePokes = 0;
        let _stagePokeAt = 0;
        function _pokeStageResize() {
            if (_userPaused || _isKioskOrMobileLayout()) return;
            if (!location.pathname.startsWith('/watch')) {
                _stagePokeKey = '';
                _stagePokes = 0;
                return;
            }
            const stage = document.querySelector('.watch-stage-mode, ytd-watch-flexy[theater]');
            const key = location.search + '|' + (stage ? '1' : '0');
            if (key !== _stagePokeKey) {
                _stagePokeKey = key;
                _stagePokes = 0;
            }
            if (!stage || _stagePokes >= 5) return;
            const mp = document.getElementById('movie_player') || document.querySelector('.html5-video-player');
            const vid = mp && mp.querySelector('video');
            if (!mp || !vid) return;
            const now = Date.now();
            if (now - _stagePokeAt < 1200) return;
            const mr = mp.getBoundingClientRect();
            const vr = vid.getBoundingClientRect();
            if (!mr.width || !mr.height || !vr.width || !vr.height) return;
            if (mr.width - vr.width > 24 && mr.height - vr.height > 24) {
                _stagePokes++;
                _stagePokeAt = now;
                try { window.dispatchEvent(new Event('resize')); } catch (_) {}
            }
        }

        _ensurePlayerChromeCss();
        setInterval(() => {
            try { _ensurePlayerChromeCss(); } catch (_) {}
            try { _pokeStageResize(); } catch (_) {}
        }, 1000);

        let _watchTapGuard = { key: '', upAt: 0, pausedAtDown: null, changed: false };
        function _watchTapKey() {
            return location.pathname + location.search;
        }
        function _isWatchPlaySurface(target) {
            if (!location.pathname.startsWith('/watch')) return false;
            if (!target || !target.closest) return false;
            const player = target.closest('#movie_player, .html5-video-player');
            if (!player) return false;
            const playSurface = target.closest('video, .html5-video-container, .ytp-large-play-button, .ytp-play-button');
            if (!playSurface) return false;
            if (target.closest('.ytp-chrome-bottom') && !target.closest('.ytp-play-button')) return false;
            return true;
        }
        function _rememberWatchTapStart(e) {
            if (!_isWatchPlaySurface(e.target)) return;
            const vid = _watchVideoElement();
            _watchTapGuard = {
                key: _watchTapKey(),
                upAt: 0,
                pausedAtDown: vid ? !!vid.paused : null,
                changed: false,
            };
        }
        function _rememberWatchTapEnd(e) {
            if (!_isWatchPlaySurface(e.target)) return;
            const key = _watchTapKey();
            const before = _watchTapGuard.key === key ? _watchTapGuard.pausedAtDown : null;
            _watchTapGuard.key = key;
            _watchTapGuard.upAt = Date.now();
            setTimeout(() => {
                const vid = _watchVideoElement();
                if (!vid || _watchTapGuard.key !== key || before === null) return;
                if (!!vid.paused !== before) _watchTapGuard.changed = true;
            }, 0);
        }
        function _playFreshWatchVideoFromGesture(e) {
            const vid = _watchVideoElement();
            if (!_isFreshPausedWatchVideo(vid)) return false;
            e.preventDefault();
            e.stopImmediatePropagation();
            _autoplayKickKey = location.search;
            _autoplayKickTries = 10;
            const p = vid.play();
            if (p && typeof p.catch === 'function') p.catch(() => {});
            return true;
        }
        function _guardWatchPlayClick(e) {
            if (!_isWatchPlaySurface(e.target)) return;
            const recentTouchToggle = _watchTapGuard.key === _watchTapKey() &&
                _watchTapGuard.changed &&
                Date.now() - _watchTapGuard.upAt < 900;
            if (recentTouchToggle) {
                e.preventDefault();
                e.stopImmediatePropagation();
                _watchTapGuard.changed = false;
                return;
            }
            _playFreshWatchVideoFromGesture(e);
        }
        document.addEventListener('touchstart', _rememberWatchTapStart, { capture: true, passive: true });
        document.addEventListener('touchend', _rememberWatchTapEnd, { capture: true, passive: true });
        document.addEventListener('pointerdown', (e) => {
            if (!e.pointerType || e.pointerType === 'mouse') return;
            _rememberWatchTapStart(e);
        }, true);
        document.addEventListener('pointerup', (e) => {
            if (!e.pointerType || e.pointerType === 'mouse') return;
            _rememberWatchTapEnd(e);
        }, true);
        document.addEventListener('click', _guardWatchPlayClick, true);

        let _lastHomeExtend = 0;
        let _homeExtendCount = 0;
        let _homeExtendPausedUntil = 0;
        const _MAX_HOME_EXTENDS = 20;
        const _HOME_FEATURE_SEL = '.lohp-large-shelf-container, .lohp-medium-shelf';
        const _HOME_EXTEND_CONTAINER_SEL = [
            '#c3-content-items',
            '#browse-items-primary',
            '#feed',
            '#feed-list',
            '.feed-list',
            '.channels-browse-content-grid',
            '.expanded-shelf-content-list',
            '.yt-shelf-grid',
            '.yt-rich-grid',
            'ytd-rich-grid-renderer #contents'
        ].join(',');

        function _isHomeFeature(el) {
            return !!(el && el.matches && el.matches(_HOME_FEATURE_SEL));
        }

        function _isInsideHomeFeature(el) {
            return !!(el && el.closest && el.closest(_HOME_FEATURE_SEL));
        }

        function _containsHomeFeature(el) {
            return !!(el && el.querySelector && el.querySelector(_HOME_FEATURE_SEL));
        }

        function _countDirectVideoChildren(container) {
            if (!container || !container.children) return 0;
            let n = 0;
            for (const child of container.children) {
                if (_isHomeFeature(child) || _isInsideHomeFeature(child) || _containsHomeFeature(child)) continue;
                if (child.querySelector && child.querySelector('a[href*="/watch"]')) n++;
            }
            return n;
        }

        function _watchLinkCount(el) {
            if (!el || !el.querySelectorAll) return 0;
            const ids = new Set();
            el.querySelectorAll('a[href*="/watch"]').forEach(a => {
                const h = a.getAttribute('href') || '';
                const m = h.match(/[?&]v=([A-Za-z0-9_-]+)/);
                ids.add(m ? m[1] : h);
            });
            return ids.size;
        }

        function _watchAnchorCount(el) {
            return el && el.querySelectorAll ? el.querySelectorAll('a[href*="/watch"]').length : 0;
        }

        function _isSingleVideoTemplate(el) {
            if (!el || _isHomeFeature(el) || _isInsideHomeFeature(el) || _containsHomeFeature(el)) return false;
            return _watchLinkCount(el) === 1 && _watchAnchorCount(el) <= 3;
        }

        function _templateFromHomeContainer(container, cards) {
            if (!container || _isHomeFeature(container) || _isInsideHomeFeature(container)) return null;
            const direct = [];
            for (const child of Array.from(container.children || [])) {
                if (_isSingleVideoTemplate(child)) direct.push(child);
            }
            if (direct.length) return direct[direct.length - 1];

            for (let i = cards.length - 1; i >= 0; i--) {
                let node = cards[i];
                if (!_isSingleVideoTemplate(node)) continue;
                while (node && node.parentElement && node.parentElement !== container) node = node.parentElement;
                if (node && node.parentElement === container && _isSingleVideoTemplate(node)) {
                    return node;
                }
            }
            return null;
        }

        function _findHomeExtendTarget(cards) {
            const sidebarAncestorSel = [
                '#watch7-sidebar-contents',
                '#watch7-sidebar',
                '#watch7-sidebar-modules',
                '#related',
                '#secondary',
                '#secondary-inner'
            ].join(',');
            const badAncestorSel = [
                _HOME_FEATURE_SEL,
                sidebarAncestorSel
            ].join(',');

            const knownContainers = [
                '#c3-content-items',
                '#browse-items-primary',
                '#feed',
                '#feed-list',
                '.feed-list',
                '.channels-browse-content-grid',
                '.expanded-shelf-content-list',
                '.yt-shelf-grid',
                '.yt-rich-grid',
                'ytd-rich-grid-renderer #contents'
            ];
            for (const sel of knownContainers) {
                for (const container of document.querySelectorAll(sel)) {
                    if (!container || (container.closest && container.closest(sidebarAncestorSel))) continue;
                    const template = _templateFromHomeContainer(container, cards);
                    if (template) return { container, template };
                }
            }

            for (let i = cards.length - 1; i >= 0; i--) {
                const template = cards[i];
                if (!template || !template.parentElement) continue;
                if (_isHomeFeature(template) || _isInsideHomeFeature(template) || _containsHomeFeature(template)) continue;
                if (template.closest && template.closest(badAncestorSel)) continue;

                let container = template.parentElement;
                for (let depth = 0; depth < 5 && container; depth++, container = container.parentElement) {
                    if (_isHomeFeature(container) || _isInsideHomeFeature(container) || _containsHomeFeature(container)) break;
                    if (container.closest && container.closest('#watch7-sidebar-contents,#watch7-sidebar,#watch7-sidebar-modules,#related,#secondary,#secondary-inner')) break;

                    const tag = (container.tagName || '').toLowerCase();
                    const cls = (container.className || '').toString();
                    const directVideoChildren = _countDirectVideoChildren(container);
                    const listLike = tag === 'ol' || tag === 'ul' || /items|grid|list|feed|shelf|browse|content/i.test(cls);

                    if (listLike && directVideoChildren >= 2) {
                        return { container, template };
                    }
                }
            }
            return null;
        }

        function _maybeExtendHome() {
            if (!active || _userPaused || !videoPool.length) return;
            const path = location.pathname;
            if (path !== '/' && path !== '' && path !== '/feed/trending') return;
            if (_homeExtendCount >= _MAX_HOME_EXTENDS) return;
            if (Date.now() - _lastHomeExtend < 600) return;

            const docBottom = document.documentElement.scrollHeight;
            if (docBottom - window.scrollY - window.innerHeight > 1200) return;
            _lastHomeExtend = Date.now();

            const cards = _findCards(document);
            if (!cards.length) return;

            const shown = new Set();
            for (const c of cards) {
                const a = _primaryWatchLink(c);
                if (!a) continue;
                const m = (a.getAttribute('href') || '').match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (m) shown.add(m[1]);
            }

            const picks = _pickSpreadFromPool(shown, 12);
            if (!picks.length) { _maybeFetchMore(); return; }

            const target = _findHomeExtendTarget(cards);
            if (!target) return;
            const { container, template } = target;

            for (const v of picks) {
                try {
                    const clone = template.cloneNode(true);
                    _stripCloneMarks(clone);
                    _rewriteCard(clone, v);
                    clone.setAttribute('data-bygone-ok', '1');
                    clone.setAttribute('data-bygone-home-extend', '1');
                    container.appendChild(clone);
                    shown.add(v.id);
                } catch (_) {}
            }
            _homeExtendCount++;
            _maybeFetchMore();
        }

        function _resetHomeExtend() { _homeExtendCount = 0; }

        window.addEventListener('scroll', _maybeExtendHome, { passive: true });
        document.addEventListener('scroll', _maybeExtendHome, { passive: true, capture: true });
        window.addEventListener('yt-navigate-finish', _resetHomeExtend);
        window.addEventListener('popstate', _resetHomeExtend);

        const _C_DATE_RE = /(?:Streamed\s+)?(\d+)\s+(year|month|week|day|hour|minute|second)s?\s+ago/i;
        const _C_ABS_DATE_RE = /(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\.?\s+\d{1,2},?\s+\d{4}/i;
        let _cDiag = { found: 0, hidden: 0, kept: 0, notime: 0 };

        let _commentDrain = {
            key: '',
            clicks: 0,
            done: false,
            capped: false,
            stall: 0,
            lastCount: 0,
            lastClickAt: 0,
            lastClickCount: -1,
            lastLogAt: 0,
        };

        const _COMMENT_V2_TARGET_VISIBLE = 35;
        const _COMMENT_V2_MAX_CLICKS = 260;
        const _COMMENT_V2_MIN_CLICK_MS = 260;
        const _COMMENT_V2_WAIT_SAME_COUNT_MS = 900;
        const _COMMENT_V2_STALL_TICKS = 36;

        function _commentPageKey() {
            const m = location.search.match(/[?&]v=([A-Za-z0-9_-]+)/);
            return location.pathname + '|' + (m ? m[1] : location.search);
        }

        function _commentRoots() {
            const selectors = [
                'ytd-comments',
                '#comments',
                '#watch-comments',
                '#watch-comments-section',
                '#watch-discussion',
                '#watch-discussion-section',
                '#watch7-discussion',
                '#watch7-discussion-contents',
                '#comment-section-renderer',
                '#comment-section-renderer-items',
                '.comment-section',
                '.comments-section',
                '.comment-list',
                '.comments-list',
                '.comments'
            ];
            const out = [];
            const seen = new Set();
            for (const sel of selectors) {
                try {
                    document.querySelectorAll(sel).forEach(el => {
                        if (!seen.has(el)) { seen.add(el); out.push(el); }
                    });
                } catch (_) {}
            }
            return out;
        }

        function _commentRoot() {
            const roots = _commentRoots();
            return roots[0] || null;
        }

        function _isCommentishArea(el) {
            if (!el || !el.closest) return false;
            return !!el.closest(
                'ytd-comments, #comments, #watch-comments, #watch-comments-section, ' +
                '#watch-discussion, #watch-discussion-section, #watch7-discussion, ' +
                '#comment-section-renderer, .comment-section, .comments-section, ' +
                '.comment-list, .comments-list, .comments'
            );
        }

        function _commentThreadCount(el) {
            if (!el || !el.querySelectorAll) return 0;
            return el.querySelectorAll(
                'div.comment[data-id], ytd-comment-thread-renderer, ytd-comment-view-model, ' +
                '.comment-thread-renderer, .comment-item'
            ).length;
        }

        function _addCommentThread(out, seen, node) {
            if (!node || seen.has(node) || !node.isConnected) return;
            if (node.getAttribute && node.getAttribute('data-bygone-comment-hidden') === '1') return;
            for (const old of Array.from(seen)) {
                if (old.contains && old.contains(node)) return;
                if (node.contains && node.contains(old)) {
                    seen.delete(old);
                    const idx = out.indexOf(old);
                    if (idx !== -1) out.splice(idx, 1);
                }
            }
            seen.add(node);
            out.push(node);
        }

        function _collectCommentThreads() {
            const out = [];
            const seen = new Set();
            const roots = _commentRoots();
            const scopes = roots.length ? roots : [document];
            const selectors = [
                'ytd-comment-thread-renderer',
                'ytd-comment-view-model',
                '.comment-thread-renderer',
                '.comment-item',
                'div.comment[data-id]'
            ].join(',');
            for (const root of scopes) {
                try {
                    root.querySelectorAll(selectors).forEach(node => {
                        if (node.matches && node.matches('ytd-comment-view-model') &&
                            node.closest('ytd-comment-thread-renderer')) return;
                        _addCommentThread(out, seen, node);
                    });
                } catch (_) {}
            }
            return out;
        }

        function _commentTimeElement(thread) {
            if (!thread || !thread.querySelectorAll) return null;
            const direct = thread.querySelector(
                '#published-time-text a, #published-time-text yt-formatted-string, ' +
                '#published-time-text yt-core-attributed-string, ' +
                '.published-time-text a, .published-time-text yt-core-attributed-string, ' +
                'span.metadata span.detail a.detail_link:not(.detail_link_full), ' +
                '.metadata a.detail_link:not(.detail_link_full), ' +
                'a.detail_link:not(.detail_link_full), .metadata .time, ' +
                '.comment .time, .time a, .time, .comment-time, .comment-date, ' +
                'a.comment-author-time, time'
            );
            if (direct) return direct;
            const scan = thread.querySelectorAll('a, span, div, time, yt-core-attributed-string, yt-formatted-string');
            for (const el of scan) {
                if (el.children && el.children.length > 2) continue;
                const t = (el.textContent || '').trim();
                if (!t || t.length > 80) continue;
                if (_C_DATE_RE.test(t) || _C_ABS_DATE_RE.test(t)) return el;
            }
            return null;
        }

        function _commentApproxDate(raw) {
            raw = (raw || '').trim();
            const m = raw.match(_C_DATE_RE);
            if (m) return DateHelper.approxPublishDate(m[0]);
            const am = raw.match(_C_ABS_DATE_RE);
            if (am) {
                const d = new Date(am[0]);
                if (!isNaN(d.getTime())) return d;
            }
            return null;
        }

        function _commentSlotFor(thread) {
            if (!thread) return null;
            if (thread.closest) {
                const fast = thread.closest(
                    'ytd-comment-thread-renderer, .comment-thread-renderer, ' +
                    '.comment-item, .post'
                );
                if (fast && _commentThreadCount(fast) <= 1) return fast;
            }
            const root = _commentRoot();
            let best = thread;
            for (let el = thread; el && el !== document.body && el !== root; el = el.parentElement) {
                const cls = (el.className || '').toString();
                const tag = (el.tagName || '').toLowerCase();
                const isSlot = tag === 'li' ||
                    /^(ytd-comment-thread-renderer|ytd-comment-view-model)$/i.test(tag) ||
                    /(^|\s)(post|comment-thread|comment-item|comment-entry|comment-container|comment-renderer)(\s|$)/i.test(cls);
                if (isSlot && _commentThreadCount(el) <= 1) best = el;
                if (el.parentElement === root) break;
            }
            return best;
        }

        function _hardCollapseNode(el) {
            if (!el || !el.setAttribute) return;
            try {
                el.setAttribute('data-bygone-comment-hidden', '1');
                el.setAttribute('aria-hidden', 'true');
                el.style.setProperty('display', 'none', 'important');
                el.style.setProperty('height', '0', 'important');
                el.style.setProperty('min-height', '0', 'important');
                el.style.setProperty('max-height', '0', 'important');
                el.style.setProperty('overflow', 'hidden', 'important');
                el.style.setProperty('margin', '0', 'important');
                el.style.setProperty('padding', '0', 'important');
                el.style.setProperty('border', '0', 'important');
                el.style.setProperty('visibility', 'hidden', 'important');
            } catch (_) {}
        }

        function _removeNode(el) {
            if (!el) return false;
            try { el.remove(); return true; } catch (_) {}
            _hardCollapseNode(el);
            return false;
        }

        function _isReplyLoaderNode(el) {
            if (!el || !el.textContent) return false;
            const cls = ((el.className || '') + ' ' + (el.id || '')).toString().toLowerCase();
            const text = (el.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase();
            if (/more comments|load more comments|show more comments/.test(text)) return false;
            if (/view all\s+\d*\s*repl|show all\s+\d*\s*repl|load\s+\d*\s*repl/.test(text)) return true;
            return /comment-repl|reply|replies|\brepl\b/.test(cls) && /reply|replies|\brepl\b/.test(text);
        }

        function _isReplySidecarNode(el) {
            if (!el) return false;
            const cls = ((el.className || '') + ' ' + (el.id || '')).toString().toLowerCase();
            const text = (el.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase();
            if (/more comments|load more comments|show more comments/.test(text)) return false;
            if (/comment-repl|comment_reply|comment-reply|replies|reply-list|reply-list|reply-thread|reply-section/.test(cls)) return true;
            if (/view all\s+\d*\s*repl|show all\s+\d*\s*repl|load\s+\d*\s*repl|view\s+\d+\s*repl/.test(text)) return true;
            return false;
        }

        function _removeAdjacentCommentJunk(slot) {
            if (!slot) return;
            try {
                slot.querySelectorAll(
                    '.comment-replies, .comment-replies-renderer, .comment-reply, ' +
                    '.comment-repl, [class*="reply"], [class*="repl"]'
                ).forEach(el => {
                    if (_isReplySidecarNode(el) || _isReplyLoaderNode(el)) _removeNode(el);
                });
            } catch (_) {}

            const scan = (dir) => {
                let sib = dir === 'next' ? slot.nextElementSibling : slot.previousElementSibling;
                let guard = 0;
                while (sib && guard++ < 14) {
                    const next = dir === 'next' ? sib.nextElementSibling : sib.previousElementSibling;
                    const topLevelThread = sib.matches && sib.matches('.post, ytd-comment-thread-renderer, .comment-thread-renderer, .comment-item');
                    const text = (sib.textContent || '').replace(/\s+/g, ' ').trim();
                    const cls = ((sib.className || '') + ' ' + (sib.id || '')).toString();
                    if (_isReplySidecarNode(sib) || _isReplyLoaderNode(sib) || (!text && /spacer|separator|reply|repl|loader/i.test(cls))) {
                        _removeNode(sib);
                        sib = next;
                        continue;
                    }
                    if (_commentThreadCount(sib) > 0 || topLevelThread) break;
                    break;
                }
            };
            scan('next');
            scan('prev');
        }

        function _collapseEmptyCommentAncestors(start, root) {
            let el = start;
            let guard = 0;
            while (el && el !== document.body && el !== root && guard++ < 12) {
                const next = el.parentElement;
                const sig = ((el.className || '') + ' ' + (el.id || '')).toString();
                const tag = (el.tagName || '').toLowerCase();
                const slotish = tag === 'li' || /post|comment|thread|item|entry|container|spacer|separator|clear/i.test(sig);
                if (!slotish) break;
                if (_commentShellProtected(el)) break;
                const text = (el.textContent || '').replace(/\s+/g, '').trim();
                if (_commentThreadCount(el) === 0 && text.length < 8) _removeNode(el);
                else break;
                el = next;
            }
        }

        function _commentShellProtected(el) {
            if (!el || !el.querySelector) return false;
            return !!el.querySelector(
                'textarea, input, select, [contenteditable="true"], ' +
                '.comment-simplebox, [class*="simplebox"], [class*="sort-menu"], ' +
                '.load-more-button, .yt-uix-load-more, [class*="paginator"], [class*="continuation"]'
            );
        }

        function _isCommentShellCandidate(el) {
            if (!el || !el.matches || !_isCommentishArea(el)) return false;
            if (_isUsableCommentButton(el)) return false;
            if (_commentThreadCount(el) > 0) return false;
            if (_commentShellProtected(el)) return false;
            const sig = ((el.className || '') + ' ' + (el.id || '') + ' ' + (el.tagName || '')).toString();
            if (!/comment|reply|repl|post|thread|item|entry|container|spacer|separator|clear|continuation|expander/i.test(sig)) return false;
            const text = (el.textContent || '').replace(/\s+/g, ' ').trim();
            if (/load more comments|show more comments|view more comments|more comments/i.test(text)) return false;
            return text.length < 14;
        }

        function _markCommentGap(el) {
            if (!el || !el.setAttribute) return;
            try {
                el.setAttribute('data-bygone-comment-gap', '1');
                el.style.setProperty('display', 'none', 'important');
                el.style.setProperty('height', '0', 'important');
                el.style.setProperty('min-height', '0', 'important');
                el.style.setProperty('max-height', '0', 'important');
                el.style.setProperty('overflow', 'hidden', 'important');
                el.style.setProperty('margin', '0', 'important');
                el.style.setProperty('padding', '0', 'important');
                el.style.setProperty('border', '0', 'important');
            } catch (_) {}
        }

        function _pruneCommentGapShells(root) {
            if (!root || !root.querySelectorAll) return;
            const sel = [
                '[data-bygone-comment-gap="1"]',
                '.post',
                '.comment',
                '.comment-thread-renderer',
                '.comment-item',
                '.comment-entry',
                '.comment-container',
                '.comment-renderer',
                '.comment-replies',
                '.comment-replies-renderer',
                '.comment-reply',
                '.comment-repl',
                'li',
                '.yt-uix-expander',
                '[class*="comment-spacer"]',
                '[class*="comment-separator"]',
                '[class*="reply-spacer"]',
                '[class*="repl-spacer"]',
                '[class*="clear"]',
            ].join(',');
            try {
                root.querySelectorAll(sel).forEach(el => {
                    if (!_isCommentShellCandidate(el)) return;
                    _markCommentGap(el);
                    _removeNode(el);
                });
            } catch (_) {}
        }

        function _nukeCommentThread(thread) {
            const slot = _commentSlotFor(thread);
            if (!slot) return;
            const root = _commentRoot();
            const parent = slot.parentElement;
            _removeAdjacentCommentJunk(slot);
            _removeNode(slot);
            _collapseEmptyCommentAncestors(parent, root);
        }

        const _COMMENT_THREAD_SEL = 'div.comment[data-id], ytd-comment-thread-renderer, ' +
            'ytd-comment-view-model, .comment-thread-renderer, .comment-item';

        function _pruneBetweenThreadDebris(root) {
            const slotSel = _COMMENT_THREAD_SEL + ', .post';
            const parents = new Set();
            try {
                root.querySelectorAll(slotSel).forEach(t => {
                    if (t.parentElement) parents.add(t.parentElement);
                });
            } catch (_) { return; }
            const skipGaps = (el, dir) => {
                let s = dir === 'prev' ? el.previousElementSibling : el.nextElementSibling;
                while (s && s.getAttribute && (
                    s.getAttribute('data-bygone-comment-gap') === '1' ||
                    s.getAttribute('data-bygone-comment-hidden') === '1'
                )) s = dir === 'prev' ? s.previousElementSibling : s.nextElementSibling;
                return s;
            };
            for (const par of parents) {
                for (const child of Array.from(par.children)) {
                    if (child.matches && child.matches(_COMMENT_THREAD_SEL)) continue;
                    if (_commentThreadCount(child) > 0) continue;
                    if (child.getAttribute && (
                        child.getAttribute('data-bygone-comment-gap') === '1' ||
                        child.getAttribute('data-bygone-comment-hidden') === '1'
                    )) continue;
                    if (_commentShellProtected(child)) continue;
                    if (_isUsableCommentButton(child)) continue;
                    if (_commentTimeElement(child)) continue;
                    const prev = skipGaps(child, 'prev');
                    const next = skipGaps(child, 'next');
                    const threadish = (el) => !!(el && ((el.matches && el.matches(slotSel)) || _commentThreadCount(el) > 0));
                    if (!threadish(prev) || !threadish(next)) continue;
                    const text = (child.textContent || '').replace(/\s+/g, ' ').trim();
                    if (/comments are|sign in|load more|show more|view more|loading/i.test(text)) continue;
                    if (text.length >= 120) continue;
                    _markCommentGap(child);
                    _removeNode(child);
                }
            }
        }

        function _pruneOldCommentShells() {
            if (!_cDiag.found && !_cDiag.hidden && !_cDiag.kept) return;
            const roots = _commentRoots();
            for (const root of roots) {
                try {
                    root.querySelectorAll('[data-bygone-comment-hidden="1"]').forEach(_removeNode);
                    root.querySelectorAll('.comment-replies, .comment-replies-renderer, [class*="comment-repl"]').forEach(el => {
                        const prev = el.previousElementSibling;
                        const next = el.nextElementSibling;
                        const nearThread = (prev && _commentThreadCount(prev) > 0) || (next && _commentThreadCount(next) > 0);
                        const nearHidden = (prev && prev.getAttribute && prev.getAttribute('data-bygone-comment-hidden') === '1') ||
                            (next && next.getAttribute && next.getAttribute('data-bygone-comment-hidden') === '1');
                        if (!nearThread || nearHidden) _removeNode(el);
                    });
                    root.querySelectorAll('.yt-uix-expander, [class*="expander"]').forEach(el => {
                        if (el.closest && el.closest(
                            'div.comment[data-id], ytd-comment-thread-renderer, ytd-comment-view-model, ' +
                            '.comment-thread-renderer, .comment-item, .post'
                        )) return;
                        if (_commentThreadCount(el) > 0) return;
                        if (!_isReplySidecarNode(el) && !_isReplyLoaderNode(el)) return;
                        _removeNode(el);
                    });
                    root.querySelectorAll('.post, .comment, .comment-thread-renderer, .comment-item, .comment-entry, .comment-container, .comment-renderer, li').forEach(el => {
                        if (_commentShellProtected(el)) return;
                        const text = (el.textContent || '').replace(/\s+/g, '').trim();
                        if (_commentThreadCount(el) === 0 && text.length < 8) _removeNode(el);
                    });
                    _pruneCommentGapShells(root);
                    _pruneBetweenThreadDebris(root);
                    _repackCommentLists(root);
                } catch (_) {}
            }
        }

        const _COMMENT_KEEP_TEXT_RE = /\bcomments?\b|sign in|signed in|loading|load more|show more|view more|sort by|newest|discussion/i;

        const _repackSuspects = new WeakMap();
        function _repackSettled(el) {
            const now = Date.now();
            const text = ((el.textContent || '').replace(/\s+/g, ' ').trim()).slice(0, 160);
            const rec = _repackSuspects.get(el);
            if (!rec || rec.text !== text) {
                _repackSuspects.set(el, { text, first: now, ticks: 1 });
                return false;
            }
            rec.ticks++;
            return rec.ticks >= 2 && now - rec.first >= 600;
        }

        function _liveThreadInside(el) {
            if (!el || !el.querySelectorAll) return false;
            const threads = el.querySelectorAll(_COMMENT_THREAD_SEL);
            for (const t of threads) {
                if (t.getAttribute('data-bygone-comment-status') !== 'removed' &&
                    t.getAttribute('data-bygone-comment-hidden') !== '1') return true;
            }
            return false;
        }

        function _repackCommentLists(root) {
            if (!root || !root.querySelectorAll) return;
            const parents = new Set();
            try {
                root.querySelectorAll(_COMMENT_THREAD_SEL + ', .post').forEach(t => {
                    if (t.parentElement) parents.add(t.parentElement);
                });
            } catch (_) { return; }
            for (const par of parents) {
                for (const child of Array.from(par.children)) {
                    if (!child || !child.getAttribute) continue;
                    if (child.getAttribute('data-bygone-comment-gap') === '1' ||
                        child.getAttribute('data-bygone-comment-hidden') === '1') {
                        _removeNode(child);
                        continue;
                    }
                    if (_commentShellProtected(child)) continue;
                    if (_isUsableCommentButton(child)) continue;
                    const isThread = child.matches && child.matches(_COMMENT_THREAD_SEL);
                    if (isThread) {
                        if (child.getAttribute('data-bygone-comment-status') === 'removed') _removeNode(child);
                        continue;
                    }
                    if (_liveThreadInside(child)) continue;
                    if (_commentThreadCount(child) === 0 && _commentTimeElement(child)) continue;
                    const text = (child.textContent || '').replace(/\s+/g, ' ').trim();
                    if (_commentThreadCount(child) === 0 && _COMMENT_KEEP_TEXT_RE.test(text)) continue;
                    if (!_repackSettled(child)) continue;
                    _markCommentGap(child);
                    _removeNode(child);
                }
            }
        }

        function _visibleCommentCount() {
            let n = 0;
            for (const thread of _collectCommentThreads()) {
                const slot = _commentSlotFor(thread) || thread;
                if (!slot || !slot.isConnected) continue;
                if (slot.getAttribute && slot.getAttribute('data-bygone-comment-hidden') === '1') continue;
                try {
                    const cs = getComputedStyle(slot);
                    if (cs.display === 'none' || cs.visibility === 'hidden') continue;
                } catch (_) {}
                n++;
            }
            return n;
        }

        function _commentSweep() {
            if (!active || _userPaused || !location.pathname.startsWith('/watch')) return;
            let setDateStr;
            try { setDateStr = Store.getCurrentDate(); } catch { return; }
            const setDate = setDateStr ? new Date(setDateStr) : null;
            if (!setDate || isNaN(setDate.getTime())) return;
            const cutoff = new Date(setDate);
            cutoff.setFullYear(cutoff.getFullYear() + 2);

            const batch = { found: 0, removed: 0, kept: 0, notime: 0 };
            for (const thread of _collectCommentThreads()) {
                if (!thread || !thread.isConnected) continue;
                if (thread.getAttribute && thread.getAttribute('data-bygone-comment-status') === 'kept') continue;
                batch.found++;
                const timeEl = _commentTimeElement(thread);
                if (!timeEl) { batch.notime++; continue; }
                const raw = (timeEl.textContent || '').trim();
                const approx = _commentApproxDate(raw);
                if (!approx || isNaN(approx.getTime())) { batch.notime++; continue; }

                if (approx.getTime() > cutoff.getTime()) {
                    batch.removed++;
                    _cDiag.hidden++;
                    try { thread.setAttribute('data-bygone-comment-status', 'removed'); } catch (_) {}
                    _nukeCommentThread(thread);
                    continue;
                }

                batch.kept++;
                _cDiag.kept++;
                try {
                    thread.setAttribute('data-bygone-comment-status', 'kept');
                    const edited = /\(edited\)/i.test(raw) ? ' (edited)' : '';
                    timeEl.textContent = DateHelper.relativeToDate(approx, setDate) + edited;
                } catch (_) {}
            }
            _cDiag.found += batch.found;
            _cDiag.notime += batch.notime;
            _pruneOldCommentShells();

            if ((batch.removed || batch.kept || batch.notime) && !_commentSweep._lastReport) {
                _commentSweep._lastReport = true;
                console.log('[bygone] comments v382:',
                    'batch=' + batch.found,
                    'removed=' + batch.removed,
                    'kept=' + batch.kept,
                    'notime=' + batch.notime,
                    'visible=' + _visibleCommentCount(),
                    'cutoff=' + cutoff.toISOString().slice(0, 10));
                setTimeout(() => { _commentSweep._lastReport = false; }, 3500);
            }
        }

        function _resetCommentDrain() {
            _cDiag = { found: 0, hidden: 0, kept: 0, notime: 0 };
            _commentSweep._lastReport = false;
            _commentDrain = {
                key: _commentPageKey(),
                clicks: 0,
                done: false,
                capped: false,
                stall: 0,
                lastCount: 0,
                lastClickAt: 0,
                lastClickCount: -1,
                lastLogAt: 0,
            };
        }

        function _commentButtonText(el) {
            if (!el) return '';
            return [
                el.getAttribute && el.getAttribute('aria-label'),
                el.getAttribute && el.getAttribute('title'),
                el.value,
                el.textContent,
            ].filter(Boolean).join(' ').replace(/\s+/g, ' ').trim();
        }

        function _commentClickable(el) {
            if (!el) return null;
            const sel = 'button, a, [role="button"], input[type="button"], input[type="submit"], ' +
                '.load-more-button, .yt-uix-load-more, .jfk-button';
            if (el.matches && el.matches(sel)) return el;
            return el.querySelector && el.querySelector(sel);
        }

        function _isUsableCommentButton(el) {
            const clickEl = _commentClickable(el);
            if (!clickEl) return false;
            if (clickEl.disabled || clickEl.getAttribute('aria-disabled') === 'true') return false;
            if (clickEl.closest && clickEl.closest(
                'div.comment[data-id], ytd-comment-thread-renderer, ytd-comment-view-model, ' +
                '.comment-thread-renderer, .comment-item, .post'
            )) return false;
            try {
                if (clickEl.tagName === 'A' && clickEl.href) {
                    const u = new URL(clickEl.href, location.href);
                    if (!/(^|\.)youtube\.com$/i.test(u.hostname)) return false;
                }
            } catch (_) {}
            const text = _commentButtonText(el).toLowerCase();
            const sig = (text + ' ' + ((el.className || '') + ' ' + (el.id || '') + ' ' +
                ((clickEl.className || '') + ' ' + (clickEl.id || '')))).toLowerCase();
            if (/reply|replies|\brepl\b|transcript|description|playlist|share|sort|newest|top comments|learn more/.test(sig)) return false;
            const positive = /load more comments|show more comments|view more comments|more comments|load comments|show comments/.test(sig) ||
                (_isCommentishArea(el) && /(load more|show more|view more|\bmore\b|continuation|paginator|load-more)/.test(sig));
            if (!positive) return false;
            try {
                const cs = getComputedStyle(clickEl);
                if (cs.display === 'none' || cs.visibility === 'hidden' || cs.pointerEvents === 'none') return false;
                if (clickEl.offsetParent === null && cs.position !== 'fixed') return false;
            } catch (_) {}
            try {
                const li = clickEl.querySelector && clickEl.querySelector('[class*="loading"]');
                if (li) {
                    const lcs = getComputedStyle(li);
                    if (lcs.display !== 'none' && lcs.visibility !== 'hidden') return false;
                }
            } catch (_) {}
            return true;
        }

        function _findCommentLoadButton() {
            const selectors = [
                'button',
                'a',
                '[role="button"]',
                'input[type="button"]',
                'input[type="submit"]',
                '.yt-uix-load-more',
                '.yt-uix-button',
                '.load-more-button',
                '.load-more',
                '.comment-section-renderer-paginator',
                '.comments-pagination',
                '.comment-pager',
                '[class*="continuation"]',
                '[class*="paginator"]',
                '[class*="load-more"]'
            ].join(',');
            const scopes = _commentRoots();
            if (!scopes.length) scopes.push(document);
            const seen = new Set();
            for (const scope of scopes) {
                let candidates = [];
                try { candidates = Array.from(scope.querySelectorAll(selectors)); } catch (_) {}
                for (const el of candidates) {
                    if (seen.has(el)) continue;
                    seen.add(el);
                    if (_isUsableCommentButton(el)) return _commentClickable(el);
                }
            }
            return null;
        }

        function _clickCommentLoadButton(btn) {
            if (!btn) return false;
            try {
                ['pointerover', 'mouseover', 'pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click'].forEach(type => {
                    btn.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, view: window }));
                });
                return true;
            } catch (_) {
                try { btn.click(); return true; } catch (__) {}
            }
            return false;
        }

        function _nearCommentBottom() {
            const root = _commentRoot();
            if (!root) return true;
            try {
                const r = root.getBoundingClientRect();
                return r.bottom < window.innerHeight + 1100 ||
                    window.scrollY + window.innerHeight > document.documentElement.scrollHeight - 1400;
            } catch (_) {
                return true;
            }
        }

        function _commentShouldLoadMore(visible) {
            if (visible < _COMMENT_V2_TARGET_VISIBLE) return true;
            return _nearCommentBottom();
        }

        function _commentDrainTick() {
            if (!active || _userPaused || !location.pathname.startsWith('/watch')) return;
            const key = _commentPageKey();
            if (_commentDrain.key !== key) _resetCommentDrain();
            if (_commentDrain.capped) return;

            try { _commentSweep(); } catch (_) {}

            const total = _collectCommentThreads().length;
            const btn = _findCommentLoadButton();
            if (!btn) {
                if (total !== _commentDrain.lastCount) {
                    _commentDrain.lastCount = total;
                    _commentDrain.stall = 0;
                    _commentDrain.done = false;
                } else if (_commentDrain.clicks) {
                    _commentDrain.stall++;
                }
                if (_commentDrain.clicks && !_commentDrain.done && _commentDrain.stall >= _COMMENT_V2_STALL_TICKS) {
                    _commentDrain.done = true;
                    console.log('[bygone] comment drain exhausted:',
                        'clicks=' + _commentDrain.clicks,
                        'visible=' + _visibleCommentCount(),
                        'threads=' + total,
                        'removed=' + _cDiag.hidden,
                        'kept=' + _cDiag.kept);
                }
                return;
            }

            const visible = _visibleCommentCount();
            _commentDrain.done = false;
            if (!_commentShouldLoadMore(visible)) return;
            if (_commentDrain.clicks >= _COMMENT_V2_MAX_CLICKS) {
                _commentDrain.done = true;
                _commentDrain.capped = true;
                console.log('[bygone] comment drain capped:',
                    'clicks=' + _commentDrain.clicks,
                    'visible=' + visible,
                    'threads=' + total);
                return;
            }

            const now = Date.now();
            if (now - _commentDrain.lastClickAt < _COMMENT_V2_MIN_CLICK_MS) return;
            if (total === _commentDrain.lastClickCount &&
                now - _commentDrain.lastClickAt < _COMMENT_V2_WAIT_SAME_COUNT_MS) return;

            if (_clickCommentLoadButton(btn)) {
                _commentDrain.clicks++;
                _commentDrain.lastClickAt = now;
                _commentDrain.lastClickCount = total;
                _commentDrain.lastCount = total;
                _commentDrain.stall = 0;
                [60, 180, 420, 900].forEach(ms => setTimeout(() => {
                    try { _commentSweep(); } catch (_) {}
                }, ms));
                if (_commentDrain.clicks === 1 || now - _commentDrain.lastLogAt > 3000) {
                    _commentDrain.lastLogAt = now;
                    console.log('[bygone] comment drain loading:',
                        'clicks=' + _commentDrain.clicks,
                        'visible=' + visible,
                        'threads=' + total,
                        'button="' + _commentButtonText(btn).slice(0, 80) + '"');
                }
            }
        }

        let _commentObs = null;
        let _commentObsRoot = null;
        let _commentSweepQueued = false;
        function _queueCommentSweep() {
            if (_commentSweepQueued) return;
            _commentSweepQueued = true;
            setTimeout(() => {
                _commentSweepQueued = false;
                try { _commentSweep(); _commentDrainTick(); } catch (_) {}
            }, 25);
        }

        function _installCommentObserver() {
            if (!location.pathname.startsWith('/watch')) return;
            const root = _commentRoot();
            if (!root) { setTimeout(_installCommentObserver, 500); return; }
            if (_commentObs && _commentObsRoot === root) return;
            if (_commentObs) { try { _commentObs.disconnect(); } catch (_) {} }
            _commentObsRoot = root;
            _commentObs = new MutationObserver(_queueCommentSweep);
            try { _commentObs.observe(root, { childList: true, subtree: true }); } catch (_) {}
            _queueCommentSweep();
        }

        setInterval(_sweep, 800);
        setInterval(_searchSweep, 800);
        setInterval(_sidebarSweep, 1000);
        setInterval(_fixAllV3Clips, 800);
        setInterval(_commentSweep, 300);
        setInterval(_commentDrainTick, 250);
        if (document.readyState !== 'loading') _installCommentObserver();
        else document.addEventListener('DOMContentLoaded', _installCommentObserver);
        window.addEventListener('yt-navigate-finish', (e) => {
            if (e.detail && e.detail._bygonePoke) return;
            _resetCommentDrain();
            if (location.pathname.startsWith('/watch')) {
                setTimeout(_installCommentObserver, 200);
            } else if (_commentObs) {
                try { _commentObs.disconnect(); } catch (_) {}
                _commentObs = null;
                _commentObsRoot = null;
            }
            [300, 800, 1600, 3000].forEach(ms => setTimeout(() => {
                try { _commentSweep(); _commentDrainTick(); } catch (_) {}
            }, ms));
        });
        setInterval(() => { try { _maybeExtendSidebar(); } catch (_) {} }, 1500);
        let _gridBurstTimer = null;
        function _burstGridSweep() {
            if (_gridBurstTimer) { clearInterval(_gridBurstTimer); _gridBurstTimer = null; }
            let elapsed = 0;
            try { _sweep(); } catch (_) {}
            _gridBurstTimer = setInterval(() => {
                try { _sweep(); } catch (_) {}
                elapsed += 120;
                if (elapsed >= 4000) { clearInterval(_gridBurstTimer); _gridBurstTimer = null; }
            }, 120);
        }
        if (document.readyState !== 'loading') _burstGridSweep();
        else document.addEventListener('DOMContentLoaded', _burstGridSweep);
        _onPoolReady(() => { _burstGridSweep(); _sidebarSweep(); _sweepPlayerRecommendations(); });

        let _lastV3Poke = 0;
        let _poking = false;
        let _pokeTimeout1 = null;
        let _pokeTimeout2 = null;
        function _navSweepBurst() {
            if (_isHomeLikePath()) _burstHomeSpaFix();
            else _burstGridSweep();
            _pokeRetries = 0;
            if (_pokeTimeout1) clearTimeout(_pokeTimeout1);
            if (_pokeTimeout2) clearTimeout(_pokeTimeout2);
            _pokeTimeout1 = setTimeout(_maybePokeV3, 1200);
            _pokeTimeout2 = setTimeout(_maybePokeV3, 3000);
        }

        let _pokeRetries = 0;
        function _maybePokeV3() {
            try {
                if (BYGONE_NO_POKE) return;
                if (!_checkV3()) return;
                const path = location.pathname;
                if (path !== '/' && path !== '') return;
                if (!active || !videoPool.length) return;
                if (Date.now() - _lastV3Poke < 8000) return;

                const hasFeatured = !!document.querySelector('.lohp-large-shelf-container, .lohp-medium-shelf');
                const cardCount = _findCards(document).length;
                if (hasFeatured && cardCount >= 5) { _pokeRetries = 0; return; }

                _lastV3Poke = Date.now();
                _pushNav('pokeV3', { hasFeatured, cardCount, retries: _pokeRetries });
                _poking = true;
                try { window.dispatchEvent(new CustomEvent('yt-navigate-start',  { detail: { pageType: 'home', url: location.href, _bygonePoke: true } })); } catch (_) {}
                try { window.dispatchEvent(new CustomEvent('yt-navigate-finish', { detail: { pageType: 'home', url: location.href, response: {}, _bygonePoke: true } })); } catch (_) {}
                try { window.dispatchEvent(new PopStateEvent('popstate', { state: history.state })); } catch (_) {}
                _poking = false;
                [400, 900, 1600, 2600].forEach(ms => setTimeout(() => { try { _sweep(); } catch (_) {} }, ms));

                _pokeRetries++;
                if (_pokeRetries < 3) {
                    setTimeout(_maybePokeV3, 3000);
                } else {
                    _pokeRetries = 0;
                }
            } catch (_) {}
        }
        window.addEventListener('yt-navigate-finish', (e) => {
            if (_poking || (e.detail && e.detail._bygonePoke)) return;
            startResponseScope();
            _navSweepBurst();
            _navSnapshot('navFinish');
        });
        window.addEventListener('popstate', () => {
            if (_poking) return;
            startResponseScope();
            _resetCommentDrain();
            if (location.pathname.startsWith('/watch')) {
                setTimeout(_installCommentObserver, 200);
            } else if (_commentObs) {
                try { _commentObs.disconnect(); } catch (_) {}
                _commentObs = null;
                _commentObsRoot = null;
            }
            _navSweepBurst();
            _navSnapshot('popstate');
        });

        let _watchPokeRetries = 0;
        let _lastWatchPoke = 0;
        function _visibleEnough(el) {
            if (!el) return false;
            try {
                const cs = getComputedStyle(el);
                if (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0') return false;
                const r = el.getBoundingClientRect();
                if (r.width <= 1 || r.height <= 1) return false;
            } catch (_) {}
            return true;
        }
        function _watchMetaState() {
            const ownerSelectors = [
                '#owner ytd-channel-name',
                '#owner #channel-name',
                '#upload-info ytd-channel-name',
                '#upload-info #channel-name',
                '#watch7-content .yt-user-name',
                '#watch-header .yt-user-name',
                '.watch-main-col .yt-user-name',
                '.watch-user-name',
                '.yt-user-info',
                'a[href^="/channel/UC"]'
            ];
            const actionSelectors = [
                '#top-level-buttons-computed',
                '#menu-container',
                '#menu ytd-toggle-button-renderer',
                'ytd-menu-renderer',
                '.watch-actions',
                '.watch-action-buttons',
                '#watch8-sentiment-actions',
                '.like-button-renderer',
                '.yt-uix-button-content'
            ];
            const firstVisible = (selectors) => {
                for (const sel of selectors) {
                    const els = document.querySelectorAll(sel);
                    for (const el of els) {
                        if (!_visibleEnough(el)) continue;
                        const text = (el.textContent || '').trim();
                        if (text || el.querySelector('button, a, img, yt-icon')) return el;
                    }
                }
                return null;
            };
            const owner = firstVisible(ownerSelectors);
            const actions = firstVisible(actionSelectors);
            return {
                owner: !!owner,
                actions: !!actions,
                ownerSel: owner ? (owner.tagName.toLowerCase() + (owner.id ? '#' + owner.id : '') + (owner.className ? '.' + String(owner.className).split(/\s+/)[0] : '')) : '',
                actionsSel: actions ? (actions.tagName.toLowerCase() + (actions.id ? '#' + actions.id : '') + (actions.className ? '.' + String(actions.className).split(/\s+/)[0] : '')) : ''
            };
        }
        try { window.__bygoneWatchDiag = _watchMetaState; } catch (_) {}
        try { if (typeof unsafeWindow !== 'undefined' && unsafeWindow) unsafeWindow.__bygoneWatchDiag = _watchMetaState; } catch (_) {}
        function _maybePokeWatch() {
            try {
                if (BYGONE_NO_POKE) return;
                if (!_checkV3()) return;
                if (!location.pathname.startsWith('/watch')) return;
                if (!active || !videoPool.length) return;
                if (Date.now() - _lastWatchPoke < 4000) return;

                const metaState = _watchMetaState();
                const hasMeta = metaState.owner && metaState.actions;
                if (hasMeta) { _watchPokeRetries = 0; return; }

                _lastWatchPoke = Date.now();
                _pushNav('pokeWatch', { metaState });
                try { console.log('[bygone] watch metadata missing; poking V3', metaState); } catch (_) {}
                _poking = true;
                try { window.dispatchEvent(new CustomEvent('yt-navigate-start',  { detail: { pageType: 'watch', url: location.href, _bygonePoke: true } })); } catch (_) {}
                try { window.dispatchEvent(new CustomEvent('yt-navigate-finish', { detail: { pageType: 'watch', url: location.href, response: {}, _bygonePoke: true } })); } catch (_) {}
                try { window.dispatchEvent(new PopStateEvent('popstate', { state: history.state })); } catch (_) {}
                _poking = false;

                _watchPokeRetries++;
                if (_watchPokeRetries < 4) {
                    setTimeout(_maybePokeWatch, 2000);
                } else {
                    _watchPokeRetries = 0;
                }
            } catch (_) {}
        }
        window.addEventListener('yt-navigate-finish', (e) => {
            if (e.detail && e.detail._bygonePoke) return;
            if (location.pathname.startsWith('/watch')) {
                _watchPokeRetries = 0;
                setTimeout(_maybePokeWatch, 1500);
                setTimeout(_maybePokeWatch, 3500);
            }
        });
        window.addEventListener('popstate', () => {
            if (_poking) return;
            if (location.pathname.startsWith('/watch')) {
                _watchPokeRetries = 0;
                setTimeout(_maybePokeWatch, 1500);
            }
        });

        let _sidebarSweepScheduled = false;
        function _scheduleSidebarSweep() {
            if (_sidebarSweepScheduled) return;
            _sidebarSweepScheduled = true;
            requestAnimationFrame(() => {
                _sidebarSweepScheduled = false;
                try { _sidebarSweep(); } catch (_) {}
            });
        }
        function _installSidebarObserver() {
            const target = document.getElementById('watch7-sidebar-contents')
                || document.getElementById('watch7-sidebar')
                || document.querySelector('#secondary');
            if (!target) { setTimeout(_installSidebarObserver, 1000); return; }
            if (_sidebarObs) { try { _sidebarObs.disconnect(); } catch (_) {} }
            _sidebarObsTarget = target;
            _sidebarObs = new MutationObserver(_scheduleSidebarSweep);
            _sidebarObs.observe(target, { childList: true, subtree: true });
        }
        if (document.readyState !== 'loading') _installSidebarObserver();
        else document.addEventListener('DOMContentLoaded', _installSidebarObserver);
        window.addEventListener('yt-navigate-finish', () => setTimeout(_installSidebarObserver, 500));
        window.addEventListener('popstate', () => setTimeout(_installSidebarObserver, 500));

        let _burstTimer = null;
        function _burstSidebarSweep() {
            if (_burstTimer) { clearInterval(_burstTimer); _burstTimer = null; }
            let elapsed = 0;
            _burstTimer = setInterval(() => {
                try { _sidebarSweep(); } catch (_) {}
                try { _sweepPlayerRecommendations(); } catch (_) {}
                try { _maybeExtendSidebar(); } catch (_) {}
                elapsed += 200;
                if (elapsed >= 10000) { clearInterval(_burstTimer); _burstTimer = null; }
            }, 200);
        }
        window.addEventListener('yt-navigate-finish', _burstSidebarSweep);
        window.addEventListener('popstate', _burstSidebarSweep);
        if (location.pathname.startsWith('/watch')) {
            if (document.readyState !== 'loading') _burstSidebarSweep();
            else document.addEventListener('DOMContentLoaded', _burstSidebarSweep);
        }

        function _findClickTarget(target) {
            let el = target, link = null, sweptCard = null, keepCard = null;
            for (let i = 0; i < 14 && el && el !== document.body; i++) {
                if (!link && el.tagName === 'A') {
                    const h = el.getAttribute('href') || '';
                    if (h.indexOf('/watch') !== -1 && h.indexOf('v=') !== -1) link = el;
                }
                if (!sweptCard && el.hasAttribute && el.hasAttribute('data-bygone-swept')) sweptCard = el;
                if (!keepCard && el.hasAttribute && el.hasAttribute('data-bygone-keep')) keepCard = el;
                el = el.parentElement;
            }
            return { link, sweptCard, keepCard };
        }

        function _resolveTarget(link, sweptCard, keepCard) {
            const origId = link ? _videoIdFromHref(link.getAttribute('href') || '') : '';
            if (origId && _poolIdsSet.has(origId)) return origId;
            if (keepCard && origId) return origId;
            if (sweptCard) {
                const visible = _poolVideoVisiblyInCard(sweptCard);
                if (visible && visible.id) return visible.id;
                const id = sweptCard.getAttribute('data-bygone-swept');
                if (id && _poolIdsSet.has(id)) return id;
            }
            if (!origId) return null;
            const v = mapVideo(origId);
            return v ? v.id : null;
        }

        const _onResultsPage = () => {
            const p = location.pathname;
            return p === '/results' || p === '/results/';
        };

        function _isHomeNavClick(target) {
            if (!target || !target.closest) return false;
            const a = target.closest('a');
            const href = a && (a.getAttribute('href') || '');
            let homeHref = false;
            if (href) {
                try {
                    const u = new URL(href, location.origin);
                    homeHref = u.origin === location.origin && u.pathname === '/';
                } catch (_) {
                    homeHref = href === '/' || href.indexOf('/?') === 0;
                }
            }
            const logoHit = target.closest(
                '#logo, #logo-container, #masthead-logo-link, #logo-icon, ' +
                '.v3-logo, .yt-masthead-logo, .appbar-logo, ytd-topbar-logo-renderer, ' +
                'a[title="YouTube"], a[aria-label="YouTube"], a[aria-label="Home"]'
            );
            return homeHref || !!logoHit;
        }

        function _scheduleHomeSpaFixFromClick() {
            [80, 220, 500, 1000, 1800].forEach(ms => setTimeout(() => {
                if (_isHomeLikePath()) _burstHomeSpaFix();
            }, ms));
        }

        window.addEventListener('click', function (e) {
            if (_userPaused) return;
            const playerRecTarget = _playerRecClickTarget(e.target);
            if (playerRecTarget && active && videoPool.length) {
                e.preventDefault();
                e.stopImmediatePropagation();
                if (!e.isTrusted) {
                    return;
                }
                const tagged = playerRecTarget.getAttribute && playerRecTarget.getAttribute('data-bygone-player-video');
                const video = (tagged && _poolVideoById(tagged)) || _pickPlayerPoolVideo(_playerRecVideoId(playerRecTarget));
                if (video) _navigateToPoolVideo(video);
                return;
            }
            if (!e.isTrusted) return;
            if (e.button !== 0 || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
            if (_isHomeNavClick(e.target)) {
                _scheduleHomeSpaFixFromClick();
                return;
            }
            if (!active || !videoPool.length) return;

            if (_onResultsPage()) {
                const { link } = _findClickTarget(e.target);
                if (!link) return;
                const href = link.getAttribute('href') || '';
                if (href.indexOf('/watch') === -1) return;
                e.preventDefault();
                e.stopImmediatePropagation();
                _pushNav('clickReloadResults', {});
                try { location.href = new URL(href, location.origin).href; }
                catch (_) { location.href = href; }
                return;
            }

            const { link, sweptCard, keepCard } = _findClickTarget(e.target);
            if (!sweptCard && !link) return;
            const targetId = _resolveTarget(link, sweptCard, keepCard);
            if (!targetId) return;
            try {
                const pv = videoPool.find(v => v.id === targetId);
                if (pv) {
                    Store.addClickEvent({
                        videoId: targetId, channelId: pv.channelId || null,
                        channel: pv.channel || '', title: pv.title || '',
                        source: pv.source || 'unknown', ts: Date.now(),
                    });
                    Store.markFeedClicked(targetId);
                    Store.recordSourceClick(pv.source || 'unknown');
                }
            } catch (_) {}
            if (link) link.setAttribute('href', '/watch?v=' + targetId);
            _pushNav('clickReload', { targetId });
            e.preventDefault();
            e.stopImmediatePropagation();
            location.href = location.origin + '/watch?v=' + targetId;
        }, true);

        document.addEventListener('auxclick', function (e) {
            if (!active || _userPaused || !videoPool.length) return;
            if (_onResultsPage()) return;
            if (e.button !== 1) return;
            const { link, sweptCard, keepCard } = _findClickTarget(e.target);
            const targetId = _resolveTarget(link, sweptCard, keepCard);
            if (!targetId || !link) return;
            const href = link.getAttribute('href') || '';
            link.setAttribute('href', href.replace(/([?&]v=)[A-Za-z0-9_-]+/, '$1' + targetId));
        }, true);

        return {
            setVideos,
            appendVideos,
            clearPool,
            removeVideos,
            forceResweep,
            setPaused,
            isPaused: () => _userPaused,
            setLazyFetcher,
            isActive: () => active,
            poolSize: () => videoPool.length,
            usedCount: () => _usedReplacements.size,
            origFetch: _origFetch,
            sweep: _sweep,
            mapVideo,
            getPoolVideo: (id) => videoPool.find(v => v.id === id) || null,
            getPoolIds: () => new Set(_poolIdsSet),
            getPool: () => videoPool,
            isKeptNatural: (id) => _keptNaturalIds.has(id),
            getKeptNaturalIds: () => Array.from(_keptNaturalIds),
            rewriteCard: _rewriteCard,
            findCards: _findCards,
            refreshAllDates,
            isChannelPage: _isChannelPage,
        };
    })();

    const VERSION = SCRIPT_VERSION;

    const CONFIG = {
        api: { maxResults: 25, cooldownMs: 250, maxSearchPages: 5 },
        feed: {
            dateWindowDays: 7,
            futureGraceDays: 0,
            maxHomepageVideos: 300,
            weights: {
                subscriptions: 0.27,
                searchTerms:   0.15,
                categories:    0.17,
                topics:        0.09,
                similar:       0.15,
                trending:      0.17,
            },
        },
        cache: {
            subscriptions: 14400000,
            searchTerms:    7200000,
            categories:     7200000,
            topics:         7200000,
            similar:        3600000,
            trending:       1800000,
        },
        defaultGlobalNegatives: ['for kids', 'nursery rhymes', 'cocomelon', 'baby shark'],
        installUrls: {
            v3: 'https://vorapis.pages.dev/#/home/download',
            starTube: 'https://greasyfork.org/scripts/485622-startube',
        },
        update: {
            scriptPage: 'https://greasyfork.org/en/scripts/580843-bygone-yt',
            metaUrl: 'https://update.greasyfork.org/scripts/580843/bygone-yt.meta.js',
            userUrl: 'https://update.greasyfork.org/scripts/580843/bygone-yt.user.js',
            checkIntervalMs: 6 * 60 * 60 * 1000,
            alertRepeatMs: 24 * 60 * 60 * 1000,
        },
        categories: {
            1: 'Film & Animation', 2: 'Autos & Vehicles', 10: 'Music',
            15: 'Pets & Animals', 17: 'Sports', 19: 'Travel & Events',
            20: 'Gaming', 22: 'People & Blogs', 23: 'Comedy',
            24: 'Entertainment', 25: 'News & Politics', 26: 'How-to & Style',
            27: 'Education', 28: 'Science & Technology',
        },
        discoveryQueries: [
            '', 'music video', 'trailer', 'funny', 'review', 'highlights',
            'how to', 'compilation', 'reaction', 'vlog', 'tutorial', 'news',
            'challenge', 'unboxing', 'animation', 'top 10', 'best of', 'cover',
            'remix', 'documentary', 'interview', 'gameplay', 'montage',
        ],
    };

    class Store {
        static _migrated = false;
        static _migrateFromWbt() {
            if (this._migrated) return;
            this._migrated = true;
            try {
                if (GM_getValue('bygone_migrated', false)) return;
                const allKeys = GM_listValues();
                let found = 0;
                for (const k of allKeys) {
                    if (!k.startsWith('wbt_')) continue;
                    const newKey = 'bygone_' + k.slice(4);
                    if (GM_getValue(newKey, undefined) !== undefined) continue;
                    const val = GM_getValue(k, undefined);
                    if (val !== undefined) { GM_setValue(newKey, val); found++; }
                }
                GM_setValue('bygone_migrated', true);
                if (found) console.log('[bygone] migrated', found, 'keys from wbt_ → bygone_');
            } catch (e) { console.warn('[bygone] migration error', e); }
        }

        static _get(k, d) {
            this._migrateFromWbt();
            try { const r = GM_getValue(k, undefined); if (r === undefined) return d; return typeof r === 'string' ? JSON.parse(r) : r; }
            catch { return d; }
        }
        static _set(k, v) { GM_setValue(k, JSON.stringify(v)); }
        static _del(k) { GM_deleteValue(k); }
        static _has(o, k) { return Object.prototype.hasOwnProperty.call(o || {}, k); }
        static _parseImportJson(json) {
            const text = String(json == null ? '' : json).replace(/^\uFEFF/, '');
            const data = JSON.parse(text);
            if (!data || typeof data !== 'object') throw new Error('Import file is not a JSON object');
            return data;
        }
        static defaultEraDate() {
            const now = new Date();
            const month = now.getMonth();
            let day = now.getDate();
            if (month === 1 && day === 29) day = 28;
            return this._formatLocalDate(new Date(2014, month, day));
        }
        static _legacyFiveYearDefaultDate() {
            const d = new Date();
            d.setFullYear(d.getFullYear() - 5);
            return this._formatLocalDate(d);
        }
        static shouldUpgradeLegacyDefaultDate(dateStr) {
            if (!dateStr) return true;
            if (dateStr === this._legacyFiveYearDefaultDate()) return true;
            const m = String(dateStr).match(/^(\d{4})-(\d{2})-(\d{2})$/);
            if (!m) return false;
            const now = new Date();
            if (+m[1] !== now.getFullYear() - 5) return false;
            const oldDefault = this._parseLocalDate(this._legacyFiveYearDefaultDate());
            const candidate = this._parseLocalDate(dateStr);
            return Math.abs(candidate.getTime() - oldDefault.getTime()) <= 10 * 86400000;
        }

        static getDate()           { return this._get('bygone_date', null); }
        static setDate(d)          { this._set('bygone_date', d); }

        static getSubscriptions()  { return this._get('bygone_subscriptions', []); }
        static setSubscriptions(s) { this._set('bygone_subscriptions', s); }
        static getSearchTerms()    { return this._get('bygone_search_terms', []); }
        static setSearchTerms(t)   { this._set('bygone_search_terms', t); }
        static getCategories()     { return this._get('bygone_categories', [20, 10, 24]); }
        static setCategories(c)    { this._set('bygone_categories', c); }
        static getTopics()         { return this._get('bygone_topics', []); }
        static setTopics(t)        { this._set('bygone_topics', t); }
        static getBlockedChannels(){ return this._get('bygone_blocked_channels', []); }
        static setBlockedChannels(b){ this._set('bygone_blocked_channels', b); }

        static _exactCache = null;
        static getExactDates()      { return this._get('bygone_exact_dates', {}); }
        static getExactDate(id) {
            if (!id) return null;
            if (!this._exactCache) this._exactCache = this.getExactDates();
            return this._exactCache[id] || null;
        }
        static addExactDates(map) {
            if (!map) return;
            if (!this._exactCache) this._exactCache = this.getExactDates();
            Object.assign(this._exactCache, map);
            this._set('bygone_exact_dates', this._exactCache);
        }

        static isActive()          { return this._get('bygone_active', true); }
        static setActive(v)        { this._set('bygone_active', v); }
        static hasSeenDependencyPrompt(){ return this._get('bygone_dependency_prompt_seen', false); }
        static markDependencyPromptSeen(){ this._set('bygone_dependency_prompt_seen', true); }
        static isDiscoveryEnabled(){ return this._get('bygone_discovery', true); }
        static setDiscoveryEnabled(v){ this._set('bygone_discovery', v); }
        static isSimilarEnabled()  { return this._get('bygone_similar_enabled', true); }
        static setSimilarEnabled(v){ this._set('bygone_similar_enabled', v); }
        static isLearningEnabled() { return this._get('bygone_learning', true); }
        static setLearningEnabled(v){ this._set('bygone_learning', v); }

        static isAutoSyncSubs()    { return this._get('bygone_auto_sync_subs', true); }
        static setAutoSyncSubs(v)  { this._set('bygone_auto_sync_subs', v); }
        static getSyncedSubIds()   { return this._get('bygone_synced_sub_ids', []); }
        static setSyncedSubIds(ids){ this._set('bygone_synced_sub_ids', ids); }
        static markSubSynced(id) {
            if (!id) return;
            const ids = this.getSyncedSubIds();
            if (!ids.includes(id)) { ids.push(id); this.setSyncedSubIds(ids); }
        }

        static getGlobalNegatives()  { return this._get('bygone_global_negatives', CONFIG.defaultGlobalNegatives.slice()); }
        static setGlobalNegatives(v) { this._set('bygone_global_negatives', v); }

        static getHiddenIds()      { return this._get('bygone_hidden_ids', []); }
        static setHiddenIds(ids)   { this._set('bygone_hidden_ids', ids); }
        static hideVideoId(id) {
            const ids = this.getHiddenIds();
            if (!ids.includes(id)) {
                ids.push(id);
                if (ids.length > 2000) ids.splice(0, ids.length - 2000);
                this.setHiddenIds(ids);
            }
        }

        static getProfiles()       { return this._get('bygone_profiles', {}); }
        static setProfiles(p)      { this._set('bygone_profiles', p); }
        static saveProfile(name) {
            const profiles = this.getProfiles();
            profiles[name] = {
                date: this.getDate(),
                subscriptions: this.getSubscriptions(),
                searchTerms: this.getSearchTerms(),
                categories: this.getCategories(),
                topics: this.getTopics(),
                blockedChannels: this.getBlockedChannels(),
                customLogo: this.getCustomLogo(),
                discovery: this.isDiscoveryEnabled(),
                similar: this.isSimilarEnabled(),
                learning: this.isLearningEnabled(),
                globalNegatives: this.getGlobalNegatives(),
                savedAt: Date.now(),
            };
            this.setProfiles(profiles);
        }
        static createBlankProfile(name) {
            const profiles = this.getProfiles();
            profiles[name] = {
                date: this.getDate() || '',
                subscriptions: [],
                searchTerms: [],
                categories: [20, 10, 24],
                topics: [],
                blockedChannels: [],
                customLogo: '',
                discovery: true,
                similar: true,
                learning: true,
                globalNegatives: CONFIG.defaultGlobalNegatives.slice(),
                savedAt: Date.now(),
            };
            this.setProfiles(profiles);
        }
        static loadProfile(name) {
            const p = this.getProfiles()[name];
            if (!p) return false;
            if (p.date)             this.setDate(p.date);
            if (p.subscriptions)    this.setSubscriptions(p.subscriptions);
            if (p.searchTerms)      this.setSearchTerms(p.searchTerms);
            if (p.categories)       this.setCategories(p.categories);
            if (p.topics)           this.setTopics(p.topics);
            if (p.blockedChannels)  this.setBlockedChannels(p.blockedChannels);
            if (p.discovery !== undefined) this.setDiscoveryEnabled(p.discovery);
            if (p.similar   !== undefined) this.setSimilarEnabled(p.similar);
            if (p.learning  !== undefined) this.setLearningEnabled(p.learning);
            if (p.globalNegatives)  this.setGlobalNegatives(p.globalNegatives);
            if (p.customLogo)       this.setCustomLogo(p.customLogo);
            else                    this.clearCustomLogo();
            this.stopClock();
            return true;
        }
        static deleteProfile(name) {
            const profiles = this.getProfiles();
            delete profiles[name];
            this.setProfiles(profiles);
        }
        static exportProfile(name) {
            const p = this.getProfiles()[name];
            return p ? JSON.stringify({ name, ...p }, null, 2) : null;
        }
        static importProfile(json) {
            const data = this._parseImportJson(json);
            const name = data.name;
            if (!name) throw new Error('Profile has no name');
            delete data.name;
            const profiles = this.getProfiles();
            profiles[name] = data;
            this.setProfiles(profiles);
            return name;
        }

        static exportAll() {
            return JSON.stringify({
                _bygone_export: true,
                _version: VERSION,
                _exportedAt: Date.now(),
                date: this.getDate(),
                active: this.isActive(),
                subscriptions: this.getSubscriptions(),
                searchTerms: this.getSearchTerms(),
                categories: this.getCategories(),
                topics: this.getTopics(),
                blockedChannels: this.getBlockedChannels(),
                exactDates: this.getExactDates(),
                globalNegatives: this.getGlobalNegatives(),
                hiddenIds: this.getHiddenIds(),
                customLogo: this.getCustomLogo(),
                kioskDarkMode: this.getKioskDarkMode(),
                kioskZoom: this.getKioskZoom(),
                discovery: this.isDiscoveryEnabled(),
                similar: this.isSimilarEnabled(),
                learning: this.isLearningEnabled(),
                autoSyncSubs: this.isAutoSyncSubs(),
                syncedSubIds: this.getSyncedSubIds(),
                profiles: this.getProfiles(),
                clockActive: this.isClockActive(),
                clockRealStart: this.getClockRealStart(),
                clockSimStart: this.getClockSimStart(),
                timeOffset: this.getTimeOffset(),
                watchHistory: this.getWatchHistory(),
                cachedInterests: this._get('bygone_cached_interests', null),
                loadCount: this.getLoadCount(),
                dislikes: this.getDislikes(),
                impressions: this.getImpressions(),
                seenIds: this.getSeenIds(),
                clickEvents: this.getClickEvents(),
                feedImpressions: this.getFeedImpressions(),
                searchHistory: this.getSearchHistory(),
                sourceStats: this._get('bygone_source_stats', {}),
                sourceOrder: this.getSourceOrder(),
            }, null, 2);
        }
        static importAll(json) {
            const d = this._parseImportJson(json);
            if (!d._bygone_export) throw new Error('Not a bygone-yt full export');
            const arr = v => Array.isArray(v) ? v : [];
            const obj = v => (v && typeof v === 'object' && !Array.isArray(v)) ? v : {};
            if (this._has(d, 'date'))            this.setDate(d.date || null);
            if (this._has(d, 'active'))          this.setActive(!!d.active);
            if (this._has(d, 'subscriptions'))   this.setSubscriptions(arr(d.subscriptions));
            if (this._has(d, 'searchTerms'))     this.setSearchTerms(arr(d.searchTerms));
            if (this._has(d, 'categories'))      this.setCategories(arr(d.categories));
            if (this._has(d, 'topics'))          this.setTopics(arr(d.topics));
            if (this._has(d, 'blockedChannels')) this.setBlockedChannels(arr(d.blockedChannels));
            if (this._has(d, 'exactDates'))      { this._set('bygone_exact_dates', obj(d.exactDates)); this._exactCache = null; }
            if (this._has(d, 'globalNegatives')) this.setGlobalNegatives(arr(d.globalNegatives));
            if (this._has(d, 'hiddenIds'))       this.setHiddenIds(arr(d.hiddenIds));
            if (this._has(d, 'customLogo'))      d.customLogo ? this.setCustomLogo(d.customLogo) : this.clearCustomLogo();
            if (this._has(d, 'kioskDarkMode'))   this.setKioskDarkMode(!!d.kioskDarkMode);
            if (this._has(d, 'kioskZoom'))       this.setKioskZoom(d.kioskZoom);
            if (this._has(d, 'discovery'))       this.setDiscoveryEnabled(!!d.discovery);
            if (this._has(d, 'similar'))         this.setSimilarEnabled(!!d.similar);
            if (this._has(d, 'learning'))        this.setLearningEnabled(!!d.learning);
            if (this._has(d, 'autoSyncSubs'))    this.setAutoSyncSubs(!!d.autoSyncSubs);
            if (this._has(d, 'syncedSubIds'))    this.setSyncedSubIds(arr(d.syncedSubIds));
            if (this._has(d, 'profiles'))        this.setProfiles(obj(d.profiles));
            if (this._has(d, 'clockActive'))     this.setClockActive(!!d.clockActive);
            if (this._has(d, 'clockRealStart'))  this.setClockRealStart(Number(d.clockRealStart) || 0);
            if (this._has(d, 'clockSimStart'))   this.setClockSimStart(Number(d.clockSimStart) || 0);
            if (this._has(d, 'timeOffset'))      this.setTimeOffset(Number(d.timeOffset) || 0);
            if (this._has(d, 'watchHistory'))    this.setWatchHistory(arr(d.watchHistory));
            if (this._has(d, 'cachedInterests')) {
                if (d.cachedInterests == null) this._del('bygone_cached_interests');
                else this._set('bygone_cached_interests', d.cachedInterests);
            }
            if (this._has(d, 'loadCount'))       this._set('bygone_load_count', Number(d.loadCount) || 0);
            if (this._has(d, 'dislikes'))        this.setDislikes(obj(d.dislikes));
            if (this._has(d, 'impressions'))     this.setImpressions(obj(d.impressions));
            if (this._has(d, 'seenIds'))         this.setSeenIds(arr(d.seenIds));
            if (this._has(d, 'clickEvents'))     this.setClickEvents(arr(d.clickEvents));
            if (this._has(d, 'feedImpressions')) this.setFeedImpressions(obj(d.feedImpressions));
            if (this._has(d, 'searchHistory'))   this.setSearchHistory(arr(d.searchHistory));
            if (this._has(d, 'sourceStats'))     this.setSourceStats(obj(d.sourceStats));
            if (this._has(d, 'sourceOrder'))     this.setSourceOrder(arr(d.sourceOrder));
            if (!this._has(d, 'exactDates')) this._exactCache = null;
            return { version: d._version || null };
        }

        static getCustomLogo()     { return this._get('bygone_custom_logo', null); }
        static setCustomLogo(d)    { this._set('bygone_custom_logo', d); }
        static clearCustomLogo()   { this._del('bygone_custom_logo'); }

        static _pageLocalStorage() {
            try {
                if (typeof unsafeWindow !== 'undefined' && unsafeWindow.localStorage) return unsafeWindow.localStorage;
            } catch {}
            try { return localStorage; } catch { return null; }
        }
        static _lsGet(k, d) {
            const ls = this._pageLocalStorage();
            if (!ls) return d;
            try { const v = ls.getItem(k); return v === null ? d : v; } catch { return d; }
        }
        static _lsSet(k, v) {
            const ls = this._pageLocalStorage();
            if (!ls) return;
            try { ls.setItem(k, String(v)); } catch {}
        }
        static getHideFab()  { return this._get('bygone_hide_fab', false); }
        static setHideFab(v) { this._set('bygone_hide_fab', !!v); }

        static getKioskDarkMode() { return this._lsGet('bygone_kiosk_dark', '0') !== '0'; }
        static setKioskDarkMode(v){ this._lsSet('bygone_kiosk_dark', v ? '1' : '0'); }
        static getKioskZoom() {
            const n = Number(this._lsGet('bygone_kiosk_zoom', '1.35'));
            if (!Number.isFinite(n)) return 1.35;
            return Math.max(0.9, Math.min(1.65, n));
        }
        static setKioskZoom(v) {
            const n = Number(v);
            this._lsSet('bygone_kiosk_zoom', Math.max(0.9, Math.min(1.65, Number.isFinite(n) ? n : 1.35)));
        }

        static isClockActive()     { return this._get('bygone_clock_active', true); }
        static setClockActive(v)   { this._set('bygone_clock_active', v); }
        static getClockRealStart() { return this._get('bygone_clock_real_start', 0); }
        static setClockRealStart(t){ this._set('bygone_clock_real_start', t); }
        static getClockSimStart()  { return this._get('bygone_clock_sim_start', 0); }
        static setClockSimStart(t) { this._set('bygone_clock_sim_start', t); }
        static getTimeOffset()     { return this._get('bygone_time_offset', 0); }
        static setTimeOffset(v)    { this._set('bygone_time_offset', v); }

        static _parseLocalDate(s) {
            if (!s) return new Date();
            const m = String(s).match(/^(\d{4})-(\d{1,2})-(\d{1,2})/);
            return m ? new Date(+m[1], +m[2] - 1, +m[3]) : new Date(s);
        }
        static _formatLocalDate(d) {
            const y = d.getFullYear();
            const m = String(d.getMonth() + 1).padStart(2, '0');
            const dy = String(d.getDate()).padStart(2, '0');
            return `${y}-${m}-${dy}`;
        }

        static _armClockIfNeeded() {
            if (!this.isClockActive()) return;
            if (this.getClockRealStart() && this.getClockSimStart()) return;
            const base = this.getDate();
            if (!base) return;
            this.setClockSimStart(this._parseLocalDate(base).getTime());
            this.setClockRealStart(Date.now());
        }
        static getCurrentDate() {
            if (this.isClockActive()) {
                this._armClockIfNeeded();
                const rs = this.getClockRealStart();
                const ss = this.getClockSimStart();
                if (rs && ss) return this._formatLocalDate(new Date(ss + (Date.now() - rs)));
            }
            return this.getDate();
        }
        static getCurrentDateTime() {
            if (this.isClockActive()) {
                this._armClockIfNeeded();
                const rs = this.getClockRealStart();
                const ss = this.getClockSimStart();
                if (rs && ss) return new Date(ss + (Date.now() - rs));
            }
            const d = this.getDate();
            return d ? this._parseLocalDate(d) : new Date();
        }
        static startClock(dateStr) {
            const base = dateStr || this.getDate();
            if (base) this.setDate(base);
            this.setClockActive(true);
            this.setClockSimStart(this._parseLocalDate(base).getTime());
            this.setClockRealStart(Date.now());
        }
        static stopClock() {
            const cur = this.getCurrentDate();
            this.setClockActive(false);
            this.setDate(cur);
            this.setClockRealStart(0);
            this.setClockSimStart(0);
        }

        static getWatchHistory()   { return this._get('bygone_watch_history', []); }
        static setWatchHistory(h)  { this._set('bygone_watch_history', h); }
        static addWatchEvent(ev) {
            const h = this.getWatchHistory();
            if (h.some(e => e.videoId === ev.videoId && (ev.ts - e.ts) < 300000)) return;
            h.push(ev);
            const cutoff = Date.now() - (60 * 86400000);
            const pruned = h.filter(e => e.ts > cutoff);
            if (pruned.length > 200) pruned.splice(0, pruned.length - 200);
            this.setWatchHistory(pruned);
            this._del('bygone_cached_interests');
        }
        static getCachedInterests() {
            const cached = this._get('bygone_cached_interests', null);
            if (cached) return cached;
            const i = InterestModel.compute();
            this._set('bygone_cached_interests', i);
            return i;
        }
        static clearLearningData() {
            this._del('bygone_watch_history');
            this._del('bygone_cached_interests');
            this._del('bygone_load_count');
        }
        static getLoadCount()      { return this._get('bygone_load_count', 0); }
        static incrementLoadCount(){ const c = this.getLoadCount() + 1; this._set('bygone_load_count', c); return c; }

        static getDislikes()       { return this._get('bygone_dislikes', { channels: {}, keywords: {} }); }
        static setDislikes(d)      { this._set('bygone_dislikes', d); }
        static recordDislike({ channelId, title }) {
            const d = this.getDislikes();
            if (channelId) d.channels[channelId] = (d.channels[channelId] || 0) + 2;
            if (title) {
                const stop = new Set(['the','a','an','in','on','at','to','for','of','and','or','is','it','my','we','i','you','this','that','with','from','by']);
                const words = title.replace(/[^\w\s]/g, '').split(/\s+/)
                    .filter(w => w.length > 2 && !stop.has(w.toLowerCase()));
                for (const w of words.slice(0, 5)) {
                    const k = w.toLowerCase();
                    d.keywords[k] = (d.keywords[k] || 0) + 1;
                }
            }
            this.setDislikes(d);
            this._del('bygone_cached_interests');
        }

        static getImpressions()    { return this._get('bygone_impressions', {}); }
        static setImpressions(i)   { this._set('bygone_impressions', i); }
        static recordImpressions(videoIds) {
            const store = this.getImpressions();
            const fi = this.getFeedImpressions();
            const clicks = this.getClickEvents();
            const now = Date.now();
            const PARK_MS_COLD      = 2 * 86400000;
            const PARK_MS_CLICKED   = 5 * 86400000;
            const THRESHOLD_COLD    = 5;
            const THRESHOLD_CLICKED = 15;
            const clickCounts = {};
            for (const ev of clicks) {
                clickCounts[ev.videoId] = (clickCounts[ev.videoId] || 0) + 1;
            }
            for (const id of videoIds) {
                if (!store[id]) store[id] = { count: 0, hiddenUntil: 0, clicks: 0 };
                const row = store[id];
                if (row.hiddenUntil && row.hiddenUntil <= now) { row.count = 0; row.hiddenUntil = 0; }
                row.count++;
                const userClicks = clickCounts[id] || 0;
                const fiClicked = fi[id] && fi[id].clicked;
                row.clicks = userClicks;
                if (userClicks >= 3 || fiClicked) {
                    if (row.count >= THRESHOLD_CLICKED) {
                        row.hiddenUntil = now + PARK_MS_CLICKED;
                        row.count = 0;
                    }
                } else {
                    if (row.count >= THRESHOLD_COLD) {
                        row.hiddenUntil = now + PARK_MS_COLD;
                        row.count = 0;
                    }
                }
            }
            const keys = Object.keys(store);
            if (keys.length > 5000) {
                const dormant = keys.filter(k => !store[k].hiddenUntil && store[k].count === 0);
                for (const k of dormant.slice(0, keys.length - 4000)) delete store[k];
            }
            this.setImpressions(store);
        }
        static isImpressionHidden(id) {
            const row = this.getImpressions()[id];
            if (!row || !row.hiddenUntil) return false;
            return row.hiddenUntil > Date.now();
        }

        static getSeenIds()        { return this._get('bygone_seen_ids', []); }
        static setSeenIds(ids)     { this._set('bygone_seen_ids', ids); }
        static addSeenIds(newIds) {
            const ids = this.getSeenIds();
            for (const id of newIds) if (!ids.includes(id)) ids.push(id);
            if (ids.length > 300) ids.splice(0, ids.length - 300);
            this.setSeenIds(ids);
        }

        static getClickEvents()    { return this._get('bygone_click_events', []); }
        static setClickEvents(e)   { this._set('bygone_click_events', e); }
        static addClickEvent(ev) {
            const events = this.getClickEvents();
            if (events.some(e => e.videoId === ev.videoId && (ev.ts - e.ts) < 300000)) return;
            events.push(ev);
            const cutoff = Date.now() - (90 * 86400000);
            const pruned = events.filter(e => e.ts > cutoff);
            if (pruned.length > 500) pruned.splice(0, pruned.length - 500);
            this.setClickEvents(pruned);
        }

        static getFeedImpressions()    { return this._get('bygone_feed_impressions', {}); }
        static setFeedImpressions(fi)  { this._set('bygone_feed_impressions', fi); }
        static recordFeedImpressions(videos) {
            const store = this.getFeedImpressions();
            const now = Date.now();
            for (const v of videos) {
                if (!v || !v.id) continue;
                if (!store[v.id]) {
                    store[v.id] = {
                        impressions: 0, clicked: false,
                        channelId: v.channelId || null, channel: v.channel || '',
                        title: v.title || '', source: v.source || '',
                        firstSeen: now, lastSeen: now,
                    };
                }
                store[v.id].impressions++;
                store[v.id].lastSeen = now;
            }
            const keys = Object.keys(store);
            if (keys.length > 3000) {
                const sorted = keys.filter(k => !store[k].clicked)
                    .sort((a, b) => store[a].lastSeen - store[b].lastSeen);
                for (const k of sorted.slice(0, keys.length - 2500)) delete store[k];
            }
            this.setFeedImpressions(store);
        }
        static markFeedClicked(videoId) {
            const store = this.getFeedImpressions();
            if (store[videoId]) { store[videoId].clicked = true; this.setFeedImpressions(store); }
        }

        static getSearchHistory()    { return this._get('bygone_search_history', []); }
        static setSearchHistory(h)   { this._set('bygone_search_history', h); }
        static addSearchQuery(query) {
            if (!query || query.length < 3) return;
            const clean = query.replace(/\s*before:\d{4}-\d{2}-\d{2}/g, '').trim();
            if (!clean) return;
            const h = this.getSearchHistory();
            if (h.some(e => e.query.toLowerCase() === clean.toLowerCase() && (Date.now() - e.ts) < 3600000)) return;
            h.push({ query: clean, ts: Date.now() });
            const cutoff = Date.now() - (180 * 86400000);
            const pruned = h.filter(e => e.ts > cutoff);
            if (pruned.length > 200) pruned.splice(0, pruned.length - 200);
            this.setSearchHistory(pruned);
        }

        static getSourceStats() {
            const stats = this._get('bygone_source_stats', {});
            const now = Date.now();
            const DECAY_INTERVAL = 7 * 86400000;
            let needsWrite = false;
            for (const key of Object.keys(stats)) {
                const s = stats[key];
                if (s.lastUpdated && (now - s.lastUpdated) > DECAY_INTERVAL) {
                    s.impressions = Math.floor(s.impressions * 0.7);
                    s.clicks = Math.floor(s.clicks * 0.7);
                    s.lastUpdated = now;
                    needsWrite = true;
                    if (s.impressions < 5) { delete stats[key]; continue; }
                }
            }
            if (needsWrite) this._set('bygone_source_stats', stats);
            return stats;
        }
        static setSourceStats(s)   { this._set('bygone_source_stats', s); }
        static recordSourceImpression(source) {
            if (!source) return;
            const stats = this.getSourceStats();
            if (!stats[source]) stats[source] = { impressions: 0, clicks: 0, lastUpdated: Date.now() };
            stats[source].impressions++;
            stats[source].lastUpdated = Date.now();
            this.setSourceStats(stats);
        }
        static recordSourceClick(source) {
            if (!source) return;
            const stats = this.getSourceStats();
            if (!stats[source]) stats[source] = { impressions: 0, clicks: 0, lastUpdated: Date.now() };
            stats[source].clicks++;
            stats[source].lastUpdated = Date.now();
            this.setSourceStats(stats);
        }

        static getCacheEntry(key, ttlMs) {
            const e = this._get(`bygone_cache_${key}`, null);
            if (!e) return null;
            if (Date.now() - e.ts > ttlMs) { this._del(`bygone_cache_${key}`); return null; }
            return e.data;
        }
        static setCacheEntry(key, data) { this._set(`bygone_cache_${key}`, { ts: Date.now(), data }); }

        static getSourceOrder() {
            return this._get('bygone_source_order', ['subscriptions', 'searchTerms', 'topics', 'categories']);
        }
        static setSourceOrder(o) { this._set('bygone_source_order', o); }
    }

    class DateHelper {
        static _msMap = {
            year:   365.25 * 86400000,
            month:  30.44  * 86400000,
            week:   7      * 86400000,
            day:             86400000,
            hour:            3600000,
            minute:             60000,
            second:              1000,
        };

        static _stripStreamPrefix(text) {
            return String(text || '').replace(/^(?:Streamed\s+)+/i, '').trim();
        }

        static _streamPrefix(text) {
            return /^(?:Streamed\s+)+/i.test(text || '') ? 'Streamed ' : '';
        }

        static approxPublishDate(relativeText) {
            if (!relativeText) return null;
            const clean = this._stripStreamPrefix(relativeText);
            const m = clean.match(/(\d+)\s*(year|month|week|day|hour|minute|second)/i);
            if (m) return new Date(Date.now() - parseInt(m[1], 10) * (this._msMap[m[2].toLowerCase()] || 0));
            const c = clean.match(/(\d+)\s*(mos?|yrs?|y|wks?|w|hrs?|h|mins?|m|secs?|s|d)\b/i);
            if (!c) return null;
            const u = c[2].toLowerCase();
            const unit = u[0] === 'y' ? 'year'
                : u.slice(0, 2) === 'mo' ? 'month'
                : u[0] === 'w' ? 'week'
                : u === 'd' ? 'day'
                : u[0] === 'h' ? 'hour'
                : (u === 'm' || u.slice(0, 3) === 'min') ? 'minute'
                : 'second';
            return new Date(Date.now() - parseInt(c[1], 10) * (this._msMap[unit] || 0));
        }

        static approxSlackMs(relativeText) {
            const clean = this._stripStreamPrefix(relativeText);
            const m = String(clean).match(/year|month|week|day|hour|minute|second/i);
            return m ? (this._msMap[m[0].toLowerCase()] || 0) : 0;
        }

        static inApproxWindow(relativeText, after, before, opts) {
            const o = opts || {};
            const clean = this._stripStreamPrefix(relativeText);
            const m = String(clean).match(/(\d+)\s*(year|month|week|day|hour|minute|second)/i);
            if (!m) return !o.dropUndated;
            const unitMs = this._msMap[m[2].toLowerCase()] || 0;
            const t = Date.now() - parseInt(m[1], 10) * unitMs;
            if (after && t < new Date(after).getTime() - unitMs) return false;
            if (before && t > new Date(before).getTime() + (o.strictBefore ? 0 : unitMs)) return false;
            return true;
        }

        static relativeToDate(publishDate, referenceDate, videoId) {
            const diffMs = new Date(referenceDate).getTime() - new Date(publishDate).getTime();
            if (diffMs < 0) {
                const h = videoId ? this._hash(videoId) : this._hash(String(publishDate));
                const d = (h % 13) + 1;
                return d === 1 ? '1 day ago' : `${d} days ago`;
            }
            const days = Math.floor(diffMs / 86400000);
            const years = Math.floor(days / 365.25);
            const months = Math.floor(days / 30.44);
            const weeks = Math.floor(days / 7);
            const hours = Math.floor(diffMs / 3600000);
            if (years  >= 1) return years  === 1 ? '1 year ago'  : `${years} years ago`;
            if (months >= 1) return months === 1 ? '1 month ago' : `${months} months ago`;
            if (weeks  >= 1) return weeks  === 1 ? '1 week ago'  : `${weeks} weeks ago`;
            if (days   >= 1) return days   === 1 ? '1 day ago'   : `${days} days ago`;
            if (hours  >= 1) return hours  === 1 ? '1 hour ago'  : `${hours} hours ago`;
            return '1 day ago';
        }

        static parseExactDateText(text) {
            if (!text) return null;
            const t = text.replace(/^(Premiered|Streamed live on|Started streaming on|Uploaded on|Published on)\s+/i, '').trim();
            const d = new Date(t);
            if (isNaN(d.getTime())) return null;
            return d.toISOString().slice(0, 10);
        }

        static recalcRelative(innertubeText, setDateStr, videoId) {
            if (!setDateStr) return innertubeText || '';
            const prefix = this._streamPrefix(innertubeText);
            const exact = videoId ? Store.getExactDate(videoId) : null;
            if (exact) return prefix + this.relativeToDate(new Date(exact), setDateStr, videoId);
            if (!innertubeText) return '';
            const pub = this.approxPublishDate(innertubeText);
            if (!pub) return innertubeText;
            return prefix + this.relativeToDate(pub, setDateStr, videoId);
        }

        static _hash(str) {
            let h = 0;
            for (let i = 0; i < str.length; i++) { h = ((h << 5) - h) + str.charCodeAt(i); h |= 0; }
            return Math.abs(h);
        }

        static relativeToDateIfPast(publishDate, referenceDate) {
            const diffMs = new Date(referenceDate).getTime() - new Date(publishDate).getTime();
            if (diffMs < 0) return null;
            return this.relativeToDate(publishDate, referenceDate);
        }

        static _plausibleRecentFeedAge(innertubeText, setDateStr, videoId) {
            const clean = this._stripStreamPrefix(innertubeText);
            const m = clean.match(/^(\d+)\s*years?\s+ago/i);
            if (!m || !setDateStr) return '';
            const approx = this.approxPublishDate(innertubeText);
            const anchor = new Date(setDateStr).getTime();
            if (!approx || isNaN(anchor)) return '';
            if (Math.abs(anchor - approx.getTime()) > 455 * 86400000) return '';
            const h = this._hash((videoId || '') + '|' + setDateStr);
            const bucket = h % 12;
            if (bucket < 2) {
                const d = (h % 24) + 3;
                return `${d} days ago`;
            }
            if (bucket < 5) {
                const w = (h % 6) + 2;
                return `${w} weeks ago`;
            }
            const mo = (h % 9) + 2;
            return `${mo} months ago`;
        }

        static recalcForFeed(innertubeText, setDateStr, videoId) {
            if (!setDateStr) return innertubeText || '';
            const prefix = this._streamPrefix(innertubeText);
            const exact = videoId ? Store.getExactDate(videoId) : null;
            if (exact) return prefix + this.relativeToDate(new Date(exact), setDateStr, videoId);
            if (!innertubeText) return '';
            const pub = this.approxPublishDate(innertubeText);
            if (!pub) return innertubeText;
            const real = this.relativeToDateIfPast(pub, setDateStr);
            if (real) return prefix + real;
            const plausible = this._plausibleRecentFeedAge(innertubeText, setDateStr, videoId);
            if (plausible) return prefix + plausible;
            return prefix + this.relativeToDate(pub, setDateStr, videoId);
        }

        static recalcForKept(innertubeText, setDateStr, videoId) {
            if (!setDateStr) return innertubeText || '';
            const prefix = this._streamPrefix(innertubeText);
            const exact = videoId ? Store.getExactDate(videoId) : null;
            if (exact) return prefix + this.relativeToDate(new Date(exact), setDateStr, videoId);
            if (!innertubeText) return '';
            const pub = this.approxPublishDate(innertubeText);
            if (!pub) return innertubeText;
            const real = this.relativeToDateIfPast(pub, setDateStr);
            if (real) return prefix + real;
            return innertubeText;
        }

    }

    class InterestModel {
        static _YT_STOP = new Set([
            'official','video','full','new','part','episode','ep',
            'hd','4k','live','stream','clip','trailer','season',
            'ft','feat','vs','vol','remix','edit','reupload',
            'deleted','original','extended','version','subtitles',
        ]);
        static _STOP = new Set([
            'the','a','an','in','on','at','to','for','of','and','or','is','it',
            'my','we','i','you','this','that','with','from','by','be','as','are',
            'was','were','been','has','have','had','do','does','did','but','not',
            'so','if','no','yes',
        ]);

        static compute() {
            const watches = Store.getWatchHistory();
            const dislikes = Store.getDislikes();
            const now = Date.now();
            const channels = {};
            const keywords = {};
            for (const w of watches) {
                const ageDays = (now - w.ts) / 86400000;
                const decay = Math.pow(0.5, ageDays / 7);
                if (w.channelId) {
                    if (!channels[w.channelId]) channels[w.channelId] = { name: w.channel, score: 0 };
                    channels[w.channelId].score += decay;
                }
                if (w.title) {
                    const kws = w.title.replace(/[^\w\s]/g, '').split(/\s+/)
                        .filter(x => x.length > 2 && !this._STOP.has(x.toLowerCase()) && !this._YT_STOP.has(x.toLowerCase()));
                    for (const kw of kws.slice(0, 5)) {
                        const lower = kw.toLowerCase();
                        if (!keywords[lower]) keywords[lower] = { score: 0 };
                        keywords[lower].score += decay;
                    }
                }
            }
            for (const [id, p] of Object.entries(dislikes.channels || {})) if (channels[id]) channels[id].score -= p;
            for (const [kw, p] of Object.entries(dislikes.keywords || {})) if (keywords[kw]) keywords[kw].score -= p;
            try {
                const neg = InterestModel.computeNegativeSignals();
                for (const cc of neg.coldChannels) {
                    if (channels[cc.channelId]) channels[cc.channelId].score -= Math.min(cc.skipScore * 0.5, 3);
                }
                for (const kw of neg.autoNegKeywords) {
                    if (keywords[kw]) keywords[kw].score -= 1;
                }
            } catch (_) {}
            return { channels, keywords };
        }

        static getLearnedChannels(i) {
            return Object.entries(i.channels)
                .filter(([_, c]) => c.score >= 2)
                .sort((a, b) => b[1].score - a[1].score)
                .slice(0, 25)
                .map(([id, c]) => ({ channelId: id, name: c.name, score: c.score }));
        }
        static getLearnedKeywords(i) {
            return Object.entries(i.keywords)
                .filter(([_, k]) => k.score >= 3)
                .sort((a, b) => b[1].score - a[1].score)
                .slice(0, 15)
                .map(([kw, k]) => ({ keyword: kw, score: k.score }));
        }

        static computeNegativeSignals() {
            const fi = Store.getFeedImpressions();
            const channelSkips = {};
            const keywordSkips = {};
            for (const [_, data] of Object.entries(fi)) {
                if (data.impressions < 4) continue;
                const isSkip = !data.clicked;
                if (data.channelId) {
                    if (!channelSkips[data.channelId]) channelSkips[data.channelId] = { name: data.channel, shown: 0, clicked: 0 };
                    channelSkips[data.channelId].shown++;
                    if (!isSkip) channelSkips[data.channelId].clicked++;
                }
                if (isSkip && data.title) {
                    const words = data.title.replace(/[^\w\s]/g, '').split(/\s+/)
                        .filter(w => w.length > 2 && !this._STOP.has(w.toLowerCase()) && !this._YT_STOP.has(w.toLowerCase()));
                    for (const w of words.slice(0, 5)) {
                        const k = w.toLowerCase();
                        if (!keywordSkips[k]) keywordSkips[k] = { shown: 0 };
                        keywordSkips[k].shown++;
                    }
                }
            }
            const coldChannels = Object.entries(channelSkips)
                .filter(([_, c]) => c.shown >= 3 && c.clicked === 0)
                .map(([id, c]) => ({ channelId: id, name: c.name, skipScore: c.shown }));
            const autoNegKeywords = Object.entries(keywordSkips)
                .filter(([_, k]) => k.shown >= 3)
                .sort((a, b) => b[1].shown - a[1].shown)
                .slice(0, 20)
                .map(([kw]) => kw);
            return { coldChannels, autoNegKeywords };
        }

        static inferLanguageHints() {
            const watches = Store.getWatchHistory();
            const clicks = Store.getClickEvents();
            const allTitles = [...watches, ...clicks].map(e => e.title || '').filter(Boolean);
            let latin = 0, total = 0;
            for (const title of allTitles) {
                for (const ch of title) {
                    const cp = ch.codePointAt(0);
                    total++;
                    if (cp >= 0x0041 && cp <= 0x024F) latin++;
                }
            }
            const englishMarkers = /\b(the|and|for|with|this|that|from|have|will|your|about)\b/i;
            let englishScore = 0;
            for (const t of allTitles) if (englishMarkers.test(t)) englishScore++;
            const likelyEnglish = allTitles.length > 5 && (englishScore / allTitles.length) > 0.5;
            const latinDominant = total > 100 && (latin / total) > 0.8;
            return { latinDominant, likelyEnglish };
        }
    }

    class YouTubeAPI {
        constructor() {
            this._lastRequest = 0;
            this._configCache = null;
            this._configCacheTs = 0;
            this._gmDeadUntil = 0;
        }

        _getCookie(name) {
            try {
                const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
                const m = win.document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
                return m ? decodeURIComponent(m[1]) : null;
            } catch { return null; }
        }

        async _getSapisidHash(origin) {
            const sapisid = this._getCookie('SAPISID') || this._getCookie('__Secure-3PAPISID');
            if (!sapisid) return null;
            const ts = Math.floor(Date.now() / 1000);
            try {
                const data = new TextEncoder().encode(`${ts} ${sapisid} ${origin}`);
                const buf = await crypto.subtle.digest('SHA-1', data);
                const hex = Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
                return `SAPISIDHASH ${ts}_${hex}`;
            } catch { return null; }
        }

        _getConfig() {
            if (this._configCache && Date.now() - this._configCacheTs < 30000) return this._configCache;
            let cfg = null;
            try {
                const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
                cfg = win.ytcfg && win.ytcfg.data_;
            } catch {}
            let fullContext = null;
            if (cfg && cfg.INNERTUBE_CONTEXT) {
                try { fullContext = JSON.parse(JSON.stringify(cfg.INNERTUBE_CONTEXT)); } catch {}
            }
            this._configCache = {
                apiKey: (cfg && cfg.INNERTUBE_API_KEY) || 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',
                clientVersion: (cfg && cfg.INNERTUBE_CLIENT_VERSION) || '2.20260301.00.00',
                fullContext,
            };
            this._configCacheTs = Date.now();
            return this._configCache;
        }

        _buildContext(cfg) {
            return cfg.fullContext || { client: { clientName: 'WEB', clientVersion: cfg.clientVersion, hl: 'en', gl: 'US' } };
        }

        _postViaGM(url, body, headers) {
            return new Promise((resolve, reject) => {
                const ep = (url.split('?')[0].match(/youtubei\/v1\/(.+)$/) || [])[1] || url;
                const t0 = Date.now();
                let settled = false;
                let guard = null;
                const fail = (err, detail) => {
                    if (settled) return;
                    settled = true;
                    if (guard) clearTimeout(guard);
                    console.warn('[bygone] innertube ' + ep + ' failed after ' + (Date.now() - t0) + 'ms: ' +
                        err.message + (detail ? ' — ' + String(detail).slice(0, 160) : ''));
                    reject(err);
                };
                const ok = (v) => {
                    if (settled) return;
                    settled = true;
                    if (guard) clearTimeout(guard);
                    resolve(v);
                };
                try {
                    const req = GM_xmlhttpRequest({
                        method: 'POST', url, headers, data: JSON.stringify(body), timeout: 15000,
                        onload(res) {
                            if (res.status >= 200 && res.status < 300) {
                                try { ok(JSON.parse(res.responseText)); }
                                catch { fail(new Error('Invalid JSON'), res.responseText); }
                            } else {
                                const err = new Error(`InnerTube HTTP ${res.status}`);
                                err.status = res.status;
                                fail(err, res.responseText);
                            }
                        },
                        onerror(res) { fail(new Error('Network error'), res && res.error); },
                        ontimeout() { fail(new Error('Timed out')); },
                    });
                    guard = setTimeout(() => {
                        try { if (req && req.abort) req.abort(); } catch (_) {}
                        const err = new Error('GM transport gave no callback (userscript manager messaging dead or request blocked by another extension)');
                        err.transportDead = true;
                        fail(err);
                    }, 17000);
                } catch (e) { e.transportDead = true; fail(e); }
            });
        }

        async _postViaFetch(url, body, headers) {
            const ep = (url.split('?')[0].match(/youtubei\/v1\/(.+)$/) || [])[1] || url;
            const t0 = Date.now();
            const f = (typeof Interceptor !== 'undefined' && Interceptor.origFetch) || fetch;
            const h = {};
            for (const k of Object.keys(headers || {})) {
                if (/^(origin|referer)$/i.test(k)) continue;
                h[k] = headers[k];
            }
            const ctrl = typeof AbortController !== 'undefined' ? new AbortController() : null;
            const timer = ctrl ? setTimeout(() => { try { ctrl.abort(); } catch (_) {} }, 15000) : null;
            try {
                const res = await f(url, {
                    method: 'POST',
                    headers: h,
                    body: JSON.stringify(body),
                    credentials: 'include',
                    signal: ctrl ? ctrl.signal : undefined,
                });
                const text = new TextDecoder().decode(await res.arrayBuffer());
                if (!(res.status >= 200 && res.status < 300)) {
                    const err = new Error(`InnerTube HTTP ${res.status}`);
                    err.status = res.status;
                    throw Object.assign(err, { _snippet: text });
                }
                return JSON.parse(text);
            } catch (e) {
                console.warn('[bygone] innertube ' + ep + ' (page-fetch fallback) failed after ' +
                    (Date.now() - t0) + 'ms: ' + (e && e.message) +
                    (e && e._snippet ? ' — ' + String(e._snippet).slice(0, 160) : ''));
                throw e;
            } finally {
                if (timer) clearTimeout(timer);
            }
        }

        async _send(url, body, headers) {
            if (Date.now() < this._gmDeadUntil) return this._postViaFetch(url, body, headers);
            try {
                return await this._postViaGM(url, body, headers);
            } catch (err) {
                if (err && err.transportDead) {
                    this._gmDeadUntil = Date.now() + 300000;
                    console.warn('[bygone] GM transport dead — using page-fetch fallback for the next 5 minutes');
                    return this._postViaFetch(url, body, headers);
                }
                throw err;
            }
        }

        async _rateLimit() {
            const wait = CONFIG.api.cooldownMs - (Date.now() - this._lastRequest);
            if (wait > 0) await new Promise(r => setTimeout(r, wait));
            this._lastRequest = Date.now();
        }

        async _post(endpoint, body) {
            await this._rateLimit();
            const cfg = this._getConfig();
            const url = `https://www.youtube.com/youtubei/v1/${endpoint}?key=${cfg.apiKey}&prettyPrint=false`;
            const fullBody = { context: this._buildContext(cfg), ...body };
            const headers = {
                'Content-Type': 'application/json',
                'X-YouTube-Client-Name': '1',
                'X-YouTube-Client-Version': cfg.clientVersion,
                'X-Origin': 'https://www.youtube.com',
                'Origin':   'https://www.youtube.com',
                'Referer':  'https://www.youtube.com/',
            };
            const auth = await this._getSapisidHash('https://www.youtube.com');
            if (auth) { headers['Authorization'] = auth; headers['X-Goog-AuthUser'] = '0'; }
            try { return await this._send(url, fullBody, headers); }
            catch (err) {
                if (err.status === 403 || (err.status >= 500 && err.status < 600)) {
                    this._configCache = null;
                    await new Promise(r => setTimeout(r, 1000));
                    const cfg2 = this._getConfig();
                    headers['X-YouTube-Client-Version'] = cfg2.clientVersion;
                    const auth2 = await this._getSapisidHash('https://www.youtube.com');
                    if (auth2) headers['Authorization'] = auth2;
                    fullBody.context = this._buildContext(cfg2);
                    return await this._send(`https://www.youtube.com/youtubei/v1/${endpoint}?key=${cfg2.apiKey}&prettyPrint=false`, fullBody, headers);
                }
                throw err;
            }
        }

        _parseViewCount(t) {
            if (!t) return 0;
            const m = t.replace(/,/g, '').toLowerCase().match(/([\d.]+)\s*([kmb])?/);
            if (!m) return 0;
            const n = parseFloat(m[1]);
            return m[2] === 'b' ? n * 1e9 : m[2] === 'm' ? n * 1e6 : m[2] === 'k' ? n * 1e3 : n;
        }

        _parseSearchResults(data) {
            const out = [];
            const pushVideo = (v) => {
                if (!v || !v.videoId || !/^[A-Za-z0-9_-]{11}$/.test(v.videoId)) return;
                const viewText = v.viewCountText?.simpleText || v.viewCountText?.runs?.[0]?.text
                    || v.shortViewCountText?.simpleText || v.shortViewCountText?.runs?.[0]?.text || '';
                out.push({
                    id: v.videoId,
                    title: v.title?.runs?.[0]?.text || '',
                    channel: v.ownerText?.runs?.[0]?.text || v.longBylineText?.runs?.[0]?.text || '',
                    channelId: v.ownerText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.browseId || '',
                    thumbnail: v.thumbnail?.thumbnails?.slice(-1)?.[0]?.url || '',
                    viewCount: this._parseViewCount(viewText),
                    viewCountFormatted: viewText || '',
                    relativeDate: v.publishedTimeText?.simpleText || '',
                    duration: v.lengthText?.simpleText
                        || v.lengthText?.accessibility?.accessibilityData?.label
                        || (v.thumbnailOverlays || []).map(o => o?.thumbnailOverlayTimeStatusRenderer?.text?.simpleText).filter(Boolean)[0]
                        || '',
                });
            };
            const scanItems = (items) => {
                for (const item of items || []) pushVideo(item.videoRenderer);
            };
            try {
                const sections = data?.contents?.twoColumnSearchResultsRenderer
                    ?.primaryContents?.sectionListRenderer?.contents || [];
                for (const section of sections) scanItems(section?.itemSectionRenderer?.contents);
                for (const c of data?.onResponseReceivedCommands || []) {
                    for (const cont of c?.appendContinuationItemsAction?.continuationItems || []) {
                        scanItems(cont?.itemSectionRenderer?.contents);
                    }
                }
            } catch (e) { console.warn('[bygone] parse error', e.message); }
            return out;
        }

        _parsePlaylistResults(data) {
            const out = [];
            try {
                const tabs = data?.contents?.twoColumnBrowseResultsRenderer?.tabs || [];
                let items = [];
                for (const tab of tabs) {
                    const contents = tab?.tabRenderer?.content?.sectionListRenderer?.contents
                        || tab?.tabRenderer?.content?.richGridRenderer?.contents || [];
                    for (const section of contents) {
                        const sectionItems = section?.itemSectionRenderer?.contents?.[0]
                            ?.playlistVideoListRenderer?.contents || [];
                        items.push(...sectionItems);
                    }
                }
                for (const item of items) {
                    const v = item.playlistVideoRenderer;
                    if (!v || !v.videoId || !/^[A-Za-z0-9_-]{11}$/.test(v.videoId)) continue;
                    const viewText = v.videoInfo?.runs?.[0]?.text || '';
                    out.push({
                        id: v.videoId,
                        title: v.title?.runs?.[0]?.text || v.title?.simpleText || '',
                        channel: v.shortBylineText?.runs?.[0]?.text || '',
                        channelId: v.shortBylineText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.browseId || '',
                        thumbnail: v.thumbnail?.thumbnails?.slice(-1)?.[0]?.url || '',
                        viewCount: this._parseViewCount(viewText),
                        viewCountFormatted: viewText || '',
                        relativeDate: v.videoInfo?.runs?.[2]?.text || '',
                        duration: v.lengthText?.simpleText || '',
                    });
                }
            } catch (e) { console.warn('[bygone] playlist parse error', e.message); }
            return out;
        }

        _parseRelatedResults(data) {
            const out = [];
            try {
                const items = data?.contents?.twoColumnWatchNextResults?.secondaryResults?.secondaryResults?.results || [];
                for (const item of items) {
                    const v = item?.compactVideoRenderer;
                    if (!v || !v.videoId) continue;
                    const viewText = v.viewCountText?.simpleText || v.viewCountText?.runs?.[0]?.text || v.shortViewCountText?.simpleText || '';
                    out.push({
                        id: v.videoId,
                        title: v.title?.simpleText || v.title?.runs?.[0]?.text || '',
                        channel: v.longBylineText?.runs?.[0]?.text || v.shortBylineText?.runs?.[0]?.text || '',
                        channelId: v.longBylineText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.browseId
                            || v.shortBylineText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.browseId || '',
                        thumbnail: v.thumbnail?.thumbnails?.slice(-1)?.[0]?.url || '',
                        viewCount: this._parseViewCount(viewText),
                        viewCountFormatted: viewText || '',
                        relativeDate: v.publishedTimeText?.simpleText || '',
                        duration: v.lengthText?.simpleText || '',
                    });
                }
            } catch (e) { console.warn('[bygone] related parse error', e.message); }
            return out;
        }

        _parseChannelResults(data) {
            try {
                const sections = data?.contents?.twoColumnSearchResultsRenderer
                    ?.primaryContents?.sectionListRenderer?.contents || [];
                for (const section of sections) {
                    for (const item of section?.itemSectionRenderer?.contents || []) {
                        if (item.channelRenderer) {
                            return {
                                id: item.channelRenderer.channelId,
                                name: item.channelRenderer.title?.simpleText
                                    || item.channelRenderer.title?.runs?.[0]?.text || '',
                            };
                        }
                    }
                }
            } catch {}
            return null;
        }

        _buildDateQuery(query, after, before, negatives) {
            let q = query || '';
            if (after)  q += ` after:${(after instanceof Date ? after : new Date(after)).toISOString().split('T')[0]}`;
            if (before) q += ` before:${(before instanceof Date ? before : new Date(before)).toISOString().split('T')[0]}`;
            if (Array.isArray(negatives)) {
                for (const n of negatives) {
                    const t = String(n || '').trim();
                    if (!t) continue;
                    q += /\s/.test(t) ? ` -"${t}"` : ` -${t}`;
                }
            }
            return q.trim();
        }

        _allNegatives(extra) {
            const neg = [...(Array.isArray(extra) ? extra : []), ...Store.getGlobalNegatives()];
            try {
                const lang = InterestModel.inferLanguageHints();
                if (lang.likelyEnglish) neg.push('ITA', 'dublado', 'doblado', 'español', 'en español', 'hindi', 'tamil', 'telugu', 'bhojpuri', 'bollywood', 'русский', 'arabic', 'legendado', 'sottotitoli');
            } catch (_) {}
            return neg;
        }

        async searchVideos(query, { publishedAfter, publishedBefore, maxResults, order = 'relevance', categoryId, negatives, strictMatch, maxPages } = {}) {
            const allNeg = this._allNegatives(negatives);
            let q = this._buildDateQuery(query, publishedAfter, publishedBefore, allNeg);
            if (categoryId && CONFIG.categories[categoryId]) q = `${CONFIG.categories[categoryId]} ${q}`.trim();
            const params = order === 'viewCount' ? 'CAMSAhAB' : order === 'date' ? 'CAISAhAB' : 'EgIQAQ==';
            const want = maxResults || CONFIG.api.maxResults;
            const pageCap = Math.max(1, maxPages || CONFIG.api.maxSearchPages || 1);

            const strictRe = strictMatch
                ? new RegExp(`\\b${strictMatch.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i')
                : null;
            const aMin = publishedAfter ? new Date(publishedAfter) : null;
            const aMax = publishedBefore ? new Date(publishedBefore) : null;
            const inWindow = (v) => DateHelper.inApproxWindow(v.relativeDate, aMin, aMax);

            const collected = [];
            const seen = new Set();
            let token = null;
            for (let page = 0; page < pageCap; page++) {
                let data;
                try { data = await this._post('search', token ? { continuation: token } : { query: q, params }); }
                catch (_) { break; }
                const results = this._parseSearchResults(data);
                for (const v of results) {
                    if (!v || !v.id || seen.has(v.id)) continue;
                    if (strictRe && !strictRe.test(v.title || '')) continue;
                    if (!inWindow(v)) continue;
                    seen.add(v.id);
                    collected.push(v);
                }
                if (collected.length >= want) break;
                token = this._extractSearchContinuation(data);
                if (!token) break;
            }
            return collected.slice(0, want);
        }

        _extractSearchContinuation(data) {
            const fromItems = (items) => {
                for (const it of items || []) {
                    const t = it?.continuationItemRenderer?.continuationEndpoint
                        ?.continuationCommand?.token;
                    if (t) return t;
                }
                return null;
            };
            try {
                const sects = data?.contents?.twoColumnSearchResultsRenderer
                    ?.primaryContents?.sectionListRenderer?.contents || [];
                const t1 = fromItems(sects);
                if (t1) return t1;
                for (const s of sects) {
                    const t = fromItems(s?.itemSectionRenderer?.contents);
                    if (t) return t;
                }
                for (const c of data?.onResponseReceivedCommands || []) {
                    const t = fromItems(c?.appendContinuationItemsAction?.continuationItems);
                    if (t) return t;
                }
            } catch (_) {}
            return null;
        }

        async getChannelVideos(channelName, { publishedAfter, publishedBefore, maxResults, channelId } = {}) {
            if (channelId && channelId.startsWith('UC')) {
                try {
                    const data = await this._post('browse', { browseId: `VL${'UU' + channelId.slice(2)}` });
                    const results = this._parsePlaylistResults(data);
                    const filtered = results.filter(v =>
                        DateHelper.inApproxWindow(v.relativeDate, publishedAfter, publishedBefore));
                    if (filtered.length) return filtered.slice(0, maxResults || CONFIG.api.maxResults);
                } catch (e) { }
            }
            const q = this._buildDateQuery(channelName, publishedAfter, publishedBefore, this._allNegatives());
            const data = await this._post('search', { query: q, params: 'EgIQAQ==' });
            let results = this._parseSearchResults(data);
            if (channelId) {
                results = results.filter(v => v.channelId === channelId);
            } else {
                const lc = channelName.toLowerCase();
                results = results.filter(v => (v.channel || '').toLowerCase() === lc);
            }
            return results.slice(0, maxResults || CONFIG.api.maxResults);
        }

        async getPopularByCategory(categoryId, opts) {
            return this.searchVideos('', { ...opts, categoryId, order: 'relevance' });
        }

        async getRelatedVideos(videoId) {
            try { return this._parseRelatedResults(await this._post('next', { videoId })); }
            catch { return []; }
        }

        async fetchExactDate(videoId) {
            if (!videoId) return null;
            try {
                const data = await this._post('next', { videoId });
                const conts = data?.contents?.twoColumnWatchNextResults
                    ?.results?.results?.contents || [];
                for (const c of conts) {
                    const dt = c?.videoPrimaryInfoRenderer?.dateText;
                    const text = dt?.simpleText || (dt?.runs || []).map(r => r.text).join('');
                    const iso = DateHelper.parseExactDateText(text);
                    if (iso) return iso;
                }
            } catch (_) {}
            return null;
        }

        async resolveChannel(input) {
            const q = input.startsWith('@') ? input : `"${input}"`;
            const data = await this._post('search', { query: q, params: 'EgIQAg==' });
            return this._parseChannelResults(data);
        }

        async subscribeToChannel(channelId) {
            if (!channelId) return false;
            try {
                await this._post('subscription/subscribe', { channelIds: [channelId] });
                return true;
            } catch (e) {
                console.warn('[bygone] subscribe failed for', channelId, '—', e.message);
                return false;
            }
        }
        async unsubscribeFromChannel(channelId) {
            if (!channelId) return false;
            try {
                await this._post('subscription/unsubscribe', { channelIds: [channelId] });
                return true;
            } catch (e) {
                console.warn('[bygone] unsubscribe failed for', channelId, '—', e.message);
                return false;
            }
        }
    }

    class FeedEngine {
        constructor(api) { this.api = api; }

        static _tag(videos, source, detail) {
            for (const v of videos) if (v) { v.source = source; v.sourceDetail = detail; }
            return videos;
        }

        _dateWindow(selectedDate) {
            const d = new Date(selectedDate);
            const days = CONFIG.feed.dateWindowDays;
            const after = new Date(d);  after.setDate(after.getDate() - days);
            const before = new Date(d); before.setDate(before.getDate() + days);
            return { after, before, center: d };
        }

        _interleave(batches) {
            const out = [];
            const longest = Math.max(0, ...batches.map(b => b.length));
            for (let i = 0; i < longest; i++) for (const b of batches) if (i < b.length) out.push(b[i]);
            return out;
        }

        _dedupe(videos) {
            const seen = new Set();
            const blockedNames = new Set(Store.getBlockedChannels().map(b => b.name.toLowerCase()));
            const blockedIds = new Set(Store.getBlockedChannels().map(b => b.id).filter(Boolean));
            const hidden = new Set(Store.getHiddenIds());
            let coldIds = new Set();
            try {
                const neg = InterestModel.computeNegativeSignals();
                coldIds = new Set(neg.coldChannels.filter(c => c.skipScore >= 5).map(c => c.channelId));
            } catch (_) {}
            return videos.filter(v => {
                if (!v || seen.has(v.id)) return false;
                if (v.channel && /\s+-\s+topic$/i.test(v.channel.trim())) return false;
                if (v.channel && blockedNames.has(v.channel.toLowerCase())) return false;
                if (v.channelId && blockedIds.has(v.channelId)) return false;
                if (v.channelId && coldIds.has(v.channelId)) return false;
                if (hidden.has(v.id)) return false;
                seen.add(v.id);
                return true;
            });
        }

        _weightedShuffle(videos, centerDate) {
            const center = new Date(centerDate).getTime();
            const weighted = videos.map(v => {
                let pub = 0;
                let slackDays = 0;
                try {
                    const exact = v.id && Store.getExactDate(v.id);
                    if (exact) pub = new Date(exact).getTime();
                } catch (_) {}
                if (!pub || isNaN(pub)) pub = v.publishedAt ? new Date(v.publishedAt).getTime() : 0;
                if (!pub || isNaN(pub)) {
                    const d = DateHelper.approxPublishDate(v.relativeDate);
                    pub = d ? d.getTime() : center;
                    if (d) slackDays = DateHelper.approxSlackMs(v.relativeDate) / 86400000;
                }
                const daysDiff = Math.max(1, Math.abs(center - pub) / 86400000 - slackDays);
                return { v, sort: Math.random() / Math.pow(daysDiff, 0.6), source: v.source || '' };
            });
            weighted.sort((a, b) => b.sort - a.sort);
            const result = [];
            const deferred = [];
            let lastSrc = '', consecutive = 0;
            for (const w of weighted) {
                if (w.source === lastSrc) { consecutive++; if (consecutive > 2) { deferred.push(w); continue; } }
                else { lastSrc = w.source; consecutive = 1; }
                result.push(w);
            }
            let insertIdx = 1;
            for (const d of deferred) { result.splice(Math.min(insertIdx, result.length), 0, d); insertIdx += 3; }
            return result.map(w => w.v);
        }

        _collectSubscriptions() {
            const subs = Store.getSubscriptions();
            const explicitIds = new Set(subs.map(s => s.id).filter(Boolean));
            const explicitNames = new Set(subs.map(s => s.name.toLowerCase()));
            const result = [...subs];
            if (Store.isLearningEnabled()) {
                const interests = Store.getCachedInterests();
                if (interests) for (const lc of InterestModel.getLearnedChannels(interests)) {
                    if (!explicitIds.has(lc.channelId)) {
                        result.push({ id: lc.channelId, name: lc.name, weight: Math.min(3, Math.round(lc.score)), _learned: true });
                        explicitIds.add(lc.channelId);
                        explicitNames.add(lc.name.toLowerCase());
                    }
                }
            }
            return result;
        }

        _normalizeTerm(raw) {
            if (typeof raw === 'string') return { term: raw, weight: 3 };
            return {
                term: raw.term || '',
                weight: raw.weight || 3,
                negatives: Array.isArray(raw.negatives) ? raw.negatives : [],
                strict: !!raw.strict,
                categoryBias: raw.categoryBias || null,
            };
        }

        _normalizeTopic(raw) {
            if (typeof raw === 'string') return { name: raw, weight: 3 };
            return {
                name: raw.name || '',
                weight: raw.weight || 3,
                negatives: Array.isArray(raw.negatives) ? raw.negatives : [],
                strict: !!raw.strict,
                categoryBias: raw.categoryBias || null,
            };
        }

        _collectSearchTerms() {
            const terms = Store.getSearchTerms().map(t => this._normalizeTerm(t));
            if (Store.isLearningEnabled()) {
                const interests = Store.getCachedInterests();
                if (interests) {
                    const existing = new Set(terms.map(t => t.term.toLowerCase()));
                    for (const lk of InterestModel.getLearnedKeywords(interests)) {
                        if (!existing.has(lk.keyword)) {
                            terms.push({ term: lk.keyword, weight: 2, _learned: true, negatives: [], strict: false, categoryBias: null });
                        }
                    }
                }
            }
            const base = terms.filter(t => t.term && t.term.length > 1);
            const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
            const _WILD = [
                'giant', 'weird', 'homemade', 'forgotten', 'strange', 'amateur',
                'rare', 'lost', 'secret', 'hidden', 'backyard', 'handmade',
                'local', 'unknown', 'original', 'crazy', 'funny', 'real',
                'epic', 'tiny', 'cursed', 'broken', 'ancient', 'haunted',
                'mysterious', 'banned', 'stolen', 'worst', 'ultimate', 'illegal',
            ];
            const dc = { weight: 2, negatives: [], strict: false, categoryBias: null, _deepCut: true };
            if (base.length >= 2) {
                const a = pick(base);
                let b = pick(base), tries = 0;
                while (b.term === a.term && tries++ < 5) b = pick(base);
                if (a.term !== b.term) terms.push({ ...dc, term: a.term + ' ' + b.term });
            }
            if (base.length > 0) {
                terms.push({ ...dc, term: pick(base).term + ' ' + pick(_WILD) });
            }
            terms.push({ ...dc, weight: 1, term: pick(_WILD) });
            const existing = new Set(terms.map(t => t.term.toLowerCase()));
            const subs = Store.getSubscriptions();
            if (subs.length > 0) {
                const pool = subs.filter(s => s.name && !existing.has(s.name.toLowerCase()));
                for (let i = 0; i < Math.min(5, pool.length); i++) {
                    const s = pool.splice(Math.floor(Math.random() * pool.length), 1)[0];
                    terms.push({ ...dc, term: s.name, _chanName: true });
                }
            }
            return terms;
        }

        async _fetchSubs(dw, count, useCache) {
            const subs = this._collectSubscriptions();
            if (!subs.length) return [];
            const key = `subs_${dw.center.toDateString()}`;
            if (useCache) {
                const c = Store.getCacheEntry(key, CONFIG.cache.subscriptions);
                if (c) return c;
            }
            const totalW = subs.reduce((s, x) => s + (x.weight || 3), 0);
            const batches = await Promise.allSettled(subs.map(async sub => {
                if (!sub.id && !sub._learned) {
                    try {
                        const ch = await this.api.resolveChannel(sub.name);
                        if (ch && ch.id) {
                            sub.id = ch.id;
                            sub.name = ch.name || sub.name;
                            const stored = Store.getSubscriptions();
                            const match = stored.find(s => s.name.toLowerCase() === sub.name.toLowerCase() || (s.id && s.id === ch.id));
                            if (match && !match.id) { match.id = ch.id; match.name = ch.name || match.name; Store.setSubscriptions(stored); }
                        }
                    } catch (_) {}
                }
                const w = sub.weight || 3;
                const per = Math.max(3, Math.ceil(count * w / totalW));
                const videos = await this.api.getChannelVideos(sub.name, {
                    publishedAfter: dw.after, publishedBefore: dw.before,
                    maxResults: per, channelId: sub.id,
                });
                const detail = sub._learned ? `Learned: ${sub.name}` : `Subscription: ${sub.name}`;
                return FeedEngine._tag(videos, 'subscriptions', detail);
            }));
            const out = this._interleave(batches.filter(r => r.status === 'fulfilled').map(r => r.value));
            if (useCache && out.length) Store.setCacheEntry(key, out);
            return out;
        }

        async _fetchSearch(dw, count, useCache) {
            const terms = this._collectSearchTerms();
            if (!terms.length) return [];
            const key = `search_${dw.center.toDateString()}`;
            if (useCache) {
                const c = Store.getCacheEntry(key, CONFIG.cache.searchTerms);
                if (c) return c;
            }
            const totalW = terms.reduce((s, x) => s + (x.weight || 3), 0);
            const batches = await Promise.allSettled(terms.map(async t => {
                const w = t.weight || 3;
                const per = Math.max(3, Math.ceil(count * w / totalW));
                const q = `"${t.term}"`;
                const videos = await this.api.searchVideos(q, {
                    publishedAfter: dw.after, publishedBefore: dw.before, maxResults: per,
                    negatives: t.negatives, strictMatch: t.strict ? t.term : null, categoryId: t.categoryBias,
                    order: t._deepCut ? 'date' : 'relevance',
                });
                const label = t._chanName ? `Channel hunt: "${t.term}"` : t._deepCut ? `Deep cut: "${t.term}"` : `Search: "${t.term}"`;
                return FeedEngine._tag(videos, 'searchTerms', label);
            }));
            const out = this._interleave(batches.filter(r => r.status === 'fulfilled').map(r => r.value));
            if (useCache && out.length) Store.setCacheEntry(key, out);
            return out;
        }

        async _fetchCategories(dw, count, useCache) {
            const cats = Store.getCategories();
            if (!cats.length) return [];
            const key = `cats_${cats.join('_')}_${dw.center.toDateString()}`;
            if (useCache) {
                const c = Store.getCacheEntry(key, CONFIG.cache.categories);
                if (c) return c;
            }
            const per = Math.max(5, Math.ceil(count / cats.length));
            const batches = await Promise.allSettled(cats.map(async id => {
                const videos = await this.api.getPopularByCategory(id, {
                    publishedAfter: dw.after, publishedBefore: dw.before, maxResults: per,
                });
                return FeedEngine._tag(videos, 'categories', `Category: ${CONFIG.categories[id] || id}`);
            }));
            const out = this._interleave(batches.filter(r => r.status === 'fulfilled').map(r => r.value));
            if (useCache && out.length) Store.setCacheEntry(key, out);
            return out;
        }

        async _fetchTopics(dw, count, useCache) {
            const topics = Store.getTopics().map(t => this._normalizeTopic(t));
            if (!topics.length) return [];
            const key = `topics_${dw.center.toDateString()}`;
            if (useCache) {
                const c = Store.getCacheEntry(key, CONFIG.cache.topics);
                if (c) return c;
            }
            const totalW = topics.reduce((s, x) => s + (x.weight || 3), 0);
            const batches = await Promise.allSettled(topics.map(async topic => {
                const w = topic.weight || 3;
                const per = Math.max(3, Math.ceil(count * w / totalW));
                const videos = await this.api.searchVideos(topic.name, {
                    publishedAfter: dw.after, publishedBefore: dw.before, maxResults: per,
                    negatives: topic.negatives, strictMatch: topic.strict ? topic.name : null, categoryId: topic.categoryBias,
                });
                return FeedEngine._tag(videos, 'topics', `Topic: "${topic.name}"`);
            }));
            const out = this._interleave(batches.filter(r => r.status === 'fulfilled').map(r => r.value));
            if (useCache && out.length) Store.setCacheEntry(key, out);
            return out;
        }

        _buildDiscoveryQueries() {
            const personal = new Set();
            const generic = new Set();
            const interests = Store.getCachedInterests();
            if (interests) {
                const keywords = Object.entries(interests.keywords)
                    .filter(([_, k]) => k.score >= 3)
                    .sort((a, b) => b[1].score - a[1].score)
                    .slice(0, 8)
                    .map(([kw]) => kw);
                for (let i = 0; i < keywords.length; i++) {
                    personal.add(keywords[i]);
                    if (i + 1 < keywords.length) personal.add(keywords[i] + ' ' + keywords[i + 1]);
                }
            }
            const searchHistory = Store.getSearchHistory();
            for (const entry of searchHistory.slice(-3)) { if (entry.query) personal.add(entry.query); }
            const searchTerms = Store.getSearchTerms();
            for (const raw of searchTerms) {
                const term = typeof raw === 'string' ? raw : raw.term;
                if (term) { generic.add(term); generic.add(term + ' review'); }
            }
            const subs = Store.getSubscriptions();
            for (const sub of subs.slice(0, 5)) { if (sub.name) generic.add(sub.name); }
            if (generic.size < 4) {
                for (const f of ['review', 'tutorial', 'documentary', 'explained', 'analysis']) generic.add(f);
            }
            return { personal: Array.from(personal), generic: Array.from(generic) };
        }

        async _fetchTrending(dw, count, useCache) {
            if (!Store.isDiscoveryEnabled()) return [];
            const key = `trending_${dw.center.toDateString()}`;
            if (useCache) {
                const c = Store.getCacheEntry(key, CONFIG.cache.trending);
                if (c) return c;
            }
            const qsets = this._buildDiscoveryQueries();
            const takeRandom = (arr, n, into) => {
                for (let i = 0; i < n && arr.length; i++) {
                    into.push(arr.splice(Math.floor(Math.random() * arr.length), 1)[0]);
                }
            };
            const picked = [];
            takeRandom(qsets.personal, 2, picked);
            takeRandom(qsets.generic, 6 - picked.length, picked);
            takeRandom(qsets.personal, 6 - picked.length, picked);
            if (!picked.length) picked.push('');
            let autoNeg = [];
            try { autoNeg = InterestModel.computeNegativeSignals().autoNegKeywords.slice(0, 10); } catch (_) {}
            const per = Math.max(5, Math.ceil(count / picked.length));
            const batches = await Promise.allSettled(picked.map(async q => {
                const videos = await this.api.searchVideos(q, {
                    negatives: autoNeg,
                    publishedAfter: dw.after, publishedBefore: dw.before, maxResults: per, order: 'relevance',
                });
                return FeedEngine._tag(videos, 'trending', q ? `Discover: "${q}"` : 'Discover');
            }));
            const out = batches.filter(r => r.status === 'fulfilled').flatMap(r => r.value);
            if (useCache && out.length) Store.setCacheEntry(key, out);
            return out;
        }

        async _fetchSimilar(dw, count, useCache) {
            if (!Store.isSimilarEnabled()) return [];
            const key = `similar_${dw.center.toDateString()}`;
            if (useCache) {
                const c = Store.getCacheEntry(key, CONFIG.cache.similar);
                if (c) return c;
            }
            const seeds = await this._pickSimilarSeeds();
            if (!seeds.length) return [];
            const batches = await Promise.allSettled(seeds.map(async seed => {
                const related = await this.api.getRelatedVideos(seed.videoId);
                const filtered = related.filter(v =>
                    DateHelper.inApproxWindow(v.relativeDate, dw.after, dw.before, { strictBefore: true }));
                return FeedEngine._tag(filtered, 'similar', `Similar to: ${seed.label}`);
            }));
            const out = this._interleave(batches.filter(r => r.status === 'fulfilled').map(r => r.value)).slice(0, count);
            if (useCache && out.length) Store.setCacheEntry(key, out);
            return out;
        }

        async _pickSimilarSeeds() {
            const recent = Store.getWatchHistory().slice().reverse().filter(w => w.videoId).slice(0, 8);
            const seeds = [];
            const usedChannels = new Set();
            for (const w of recent) {
                if (w.channelId && usedChannels.has(w.channelId)) continue;
                seeds.push({ videoId: w.videoId, label: w.title || w.channel || 'recent watch' });
                if (w.channelId) usedChannels.add(w.channelId);
                if (seeds.length >= 3) break;
            }
            if (seeds.length >= 3) return seeds;
            const interests = Store.getCachedInterests();
            if (interests) for (const lc of InterestModel.getLearnedChannels(interests)) {
                if (seeds.length >= 3) break;
                if (usedChannels.has(lc.channelId)) continue;
                try {
                    const v = await this.api.getChannelVideos(lc.name, { maxResults: 1, channelId: lc.channelId });
                    if (v.length) { seeds.push({ videoId: v[0].id, label: lc.name }); usedChannels.add(lc.channelId); }
                } catch {}
            }
            return seeds;
        }

        async _fetchRelatedExpansion(seedVideos, dw, count) {
            const seeds = [];
            const usedCh = new Set();
            for (const v of seedVideos) {
                if (!v || !v.id) continue;
                if (v.channelId && usedCh.has(v.channelId)) continue;
                seeds.push(v);
                if (v.channelId) usedCh.add(v.channelId);
                if (seeds.length >= 8) break;
            }
            if (!seeds.length) return [];
            const batches = await Promise.allSettled(seeds.map(async s => {
                const related = await this.api.getRelatedVideos(s.id);
                const filtered = related.filter(r =>
                    DateHelper.inApproxWindow(r.relativeDate, dw.after, dw.before,
                        { dropUndated: true, strictBefore: true }));
                return FeedEngine._tag(filtered, 'related', `Related to: ${s.title || s.id}`);
            }));
            const out = this._interleave(batches.filter(r => r.status === 'fulfilled').map(r => r.value));
            return out.slice(0, count);
        }

        _effectiveWeights() {
            if (!Store.isLearningEnabled()) return CONFIG.feed.weights;
            const i = Store.getCachedInterests();
            if (!i) return CONFIG.feed.weights;
            const lc = InterestModel.getLearnedChannels(i).length;
            const lk = InterestModel.getLearnedKeywords(i).length;
            const w = { ...CONFIG.feed.weights };
            const subBoost = Math.min(0.10, lc * 0.02);
            const termBoost = Math.min(0.05, lk * 0.01);
            w.subscriptions += subBoost;
            w.searchTerms += termBoost;
            const drain = (subBoost + termBoost) / 2;
            w.trending = Math.max(0.05, w.trending - drain);
            w.similar  = Math.max(0.05, (w.similar || 0) - drain);

            const stats = Store.getSourceStats();
            const sourceKeys = Object.keys(w);
            const ctrs = {};
            let hasEnoughData = false;
            for (const key of sourceKeys) {
                const s = stats[key];
                if (s && s.impressions >= 20) { ctrs[key] = s.clicks / s.impressions; hasEnoughData = true; }
                else ctrs[key] = null;
            }
            if (hasEnoughData) {
                const validCtrs = Object.values(ctrs).filter(v => v !== null);
                const avgCtr = validCtrs.reduce((s, v) => s + v, 0) / validCtrs.length;
                for (const key of sourceKeys) {
                    if (ctrs[key] === null) continue;
                    const adj = Math.max(-0.08, Math.min(0.08, (ctrs[key] - avgCtr) * 2));
                    w[key] = Math.max(0.03, w[key] + adj);
                }
            }
            const total = Object.values(w).reduce((s, v) => s + v, 0);
            for (const key of sourceKeys) w[key] /= total;

            return w;
        }

        _mixSources(sources, weights) {
            const w = weights || CONFIG.feed.weights;
            const total = CONFIG.feed.maxHomepageVideos;
            const take = (arr, n) => [...arr].sort(() => Math.random() - 0.5).slice(0, n);
            const counts = {
                subscriptions: Math.round(total * (w.subscriptions || 0)),
                searchTerms:   Math.round(total * (w.searchTerms   || 0)),
                categories:    Math.round(total * (w.categories    || 0)),
                topics:        Math.round(total * (w.topics        || 0)),
                similar:       Math.round(total * (w.similar       || 0)),
                trending:      Math.round(total * (w.trending      || 0)),
            };
            const mixed = [];
            for (const [k, n] of Object.entries(counts)) mixed.push(...take(sources[k] || [], n));
            if (mixed.length < total) {
                const ids = new Set(mixed.map(v => v.id));
                const extras = Object.values(sources).flat().filter(v => v && !ids.has(v.id));
                mixed.push(...take(extras, total - mixed.length));
            }
            return mixed;
        }

        async _buildWithTimeout(promise) {
            return Promise.race([promise, new Promise((_, rej) => setTimeout(() => rej(new Error('Feed build timed out')), 45000))]);
        }

        _settleWithin(promise, ms, fallback, label) {
            const safe = Promise.resolve(promise).then(
                v => (Array.isArray(v) ? v : fallback),
                (e) => {
                    try { console.warn('[bygone] source rejected:', label || '', (e && e.message) || e); } catch (_) {}
                    return fallback;
                }
            );
            let timer = null;
            const timeout = new Promise(resolve => {
                timer = setTimeout(() => {
                    try { console.warn('[bygone] source timed out after ' + ms + 'ms:', label || 'unlabeled'); } catch (_) {}
                    resolve(fallback);
                }, ms);
            });
            return Promise.race([
                safe.then(v => { if (timer) clearTimeout(timer); return v; }),
                timeout,
            ]);
        }

        async buildHomeFeed(selectedDate, onPartial) { return this._buildWithTimeout(this._build(selectedDate, false, onPartial)); }

        async buildHomeFeedMore(selectedDate, page, excludeIds) {
            const d = new Date(selectedDate);
            d.setDate(d.getDate() - CONFIG.feed.dateWindowDays * 2 * (page - 1));
            const out = await this._build(d.toISOString().split('T')[0], false);
            const excl = excludeIds instanceof Set ? excludeIds : new Set(excludeIds || []);
            return out.filter(v => !excl.has(v.id));
        }

        _enforceDiversity(videos) {
            const MAX_PER_CHANNEL = 3;
            const MAX_PER_SOURCE = Math.ceil(videos.length * 0.35);
            const channelCounts = {};
            const sourceCounts = {};
            const kept = [];
            const deferred = [];
            for (const v of videos) {
                const chKey = v.channelId || v.channel || 'unknown';
                const srcKey = v.source || 'unknown';
                const chCount = channelCounts[chKey] || 0;
                const srcCount = sourceCounts[srcKey] || 0;
                if (chCount >= MAX_PER_CHANNEL || srcCount >= MAX_PER_SOURCE) {
                    deferred.push(v);
                    continue;
                }
                channelCounts[chKey] = chCount + 1;
                sourceCounts[srcKey] = srcCount + 1;
                kept.push(v);
            }
            if (kept.length < 100) for (const v of deferred) { kept.push(v); if (kept.length >= videos.length) break; }
            return kept;
        }

        async _build(selectedDate, useCache, onPartial) {
            const total = CONFIG.feed.maxHomepageVideos;
            const anchor = new Date(selectedDate);
            const smoothMs = 7 * 86400000;
            const subsWindow = this._dateWindow(selectedDate);
            const queryWindow    = { after: new Date(anchor - 90  * 86400000), before: new Date(anchor.getTime() + smoothMs), center: anchor };
            const catWindow      = { after: new Date(anchor - 180 * 86400000), before: new Date(anchor.getTime() + smoothMs), center: anchor };
            const trendingWindow = { after: new Date(anchor - 365 * 86400000), before: new Date(anchor.getTime() + smoothMs), center: anchor };

            const loadNum = Store.incrementLoadCount();
            const explore = loadNum % 10 === 0;
            const weights = explore ? CONFIG.feed.weights : this._effectiveWeights();

            const SOURCE_BUDGET = 22000;
            const emit = (typeof onPartial === 'function') ? onPartial : null;
            const bound = (label, p) => {
                const s = this._settleWithin(p, SOURCE_BUDGET, [], label);
                if (!emit) return s;
                return s.then(vids => { if (vids && vids.length) { try { emit(vids); } catch (_) {} } return vids; });
            };
            const results = await Promise.allSettled([
                bound('subs',     this._fetchSubs      (subsWindow,     Math.round(total * weights.subscriptions * 2), useCache)),
                bound('search',   this._fetchSearch    (queryWindow,    Math.round(total * weights.searchTerms   * 2), useCache)),
                bound('cats',     this._fetchCategories(catWindow,      Math.round(total * weights.categories    * 2), useCache)),
                bound('topics',   this._fetchTopics    (queryWindow,    Math.round(total * weights.topics        * 2), useCache)),
                bound('similar',  this._fetchSimilar   (subsWindow,     Math.round(total * weights.similar       * 2), useCache)),
                bound('trending', this._fetchTrending  (trendingWindow, Math.round(total * weights.trending      * 2), useCache)),
            ]);
            const val = (i) => results[i].status === 'fulfilled' ? results[i].value : [];
            const err = (i) => results[i].status === 'rejected' ? (results[i].reason && results[i].reason.message) || 'rejected' : '';
            console.log('[bygone] sources:',
                'subs=' + val(0).length + (err(0) ? '(err:'+err(0)+')' : ''),
                'search=' + val(1).length + (err(1) ? '(err:'+err(1)+')' : ''),
                'cats=' + val(2).length + (err(2) ? '(err:'+err(2)+')' : ''),
                'topics=' + val(3).length + (err(3) ? '(err:'+err(3)+')' : ''),
                'similar=' + val(4).length + (err(4) ? '(err:'+err(4)+')' : ''),
                'trending=' + val(5).length + (err(5) ? '(err:'+err(5)+')' : ''));
            const mixed = this._mixSources({
                subscriptions: val(0), searchTerms: val(1), categories: val(2),
                topics:        val(3), similar:     val(4), trending:    val(5),
            }, weights);

            let deduped = this._dedupe(mixed);
            if (deduped.length < total * 0.6 && deduped.length > 0) {
                try {
                    const related = await this._settleWithin(
                        this._fetchRelatedExpansion(deduped, trendingWindow, total - deduped.length),
                        10000, [], 'related fan-out');
                    if (related.length) {
                        deduped = this._dedupe([...deduped, ...related]);
                        console.log('[bygone] related fan-out added', related.length, '→ pool', deduped.length);
                    }
                } catch (_) {}
            }
            const diverse = this._enforceDiversity(deduped);
            let visible = diverse.filter(v => !Store.isImpressionHidden(v.id));
            console.log('[bygone] feed build: mixed=' + mixed.length + ' deduped=' + deduped.length + ' visible=' + visible.length);
            if (visible.length < 30 && diverse.length > visible.length) visible = diverse;

            const seen = new Set(Store.getSeenIds());
            const unseen = visible.filter(v => !seen.has(v.id));
            const seenVids = visible.filter(v => seen.has(v.id));
            const ordered = [
                ...this._weightedShuffle(unseen,   anchor),
                ...this._weightedShuffle(seenVids, anchor),
            ];
            const top20 = ordered.slice(0, 20);
            Store.recordImpressions(top20.map(v => v.id));
            try {
                Store.recordFeedImpressions(top20);
                for (const v of top20) Store.recordSourceImpression(v.source || 'unknown');
            } catch (_) {}
            return ordered;
        }
    }

    const CSS = `
        #wbt-fab {
            position: fixed !important;
            bottom: calc(82px + env(safe-area-inset-bottom, 0px)) !important;
            right: calc(16px + env(safe-area-inset-right, 0px)) !important;
            z-index: 2147483646 !important;
            width: var(--bygone-fab-size, 58px) !important; height: var(--bygone-fab-size, 58px) !important;
            border-radius: 50% !important;
            background: #c00 !important; color: #fff !important;
            border: 1px solid #800 !important;
            font: bold var(--bygone-fab-font, 23px) sans-serif !important;
            line-height: var(--bygone-fab-size, 58px) !important;
            cursor: pointer !important;
            box-shadow: 0 2px 8px rgba(0,0,0,.4) !important;
            display: block !important; visibility: visible !important; opacity: 1 !important;
            padding: 0 !important; margin: 0 !important;
            transform: none !important; zoom: 1 !important;
        }
        #wbt-fab:hover { background: #e00 !important; }
        #wbt-panel {
            position: fixed !important;
            bottom: calc(140px + env(safe-area-inset-bottom, 0px)) !important;
            right: 6px !important;
            z-index: 2147483647 !important;
            max-width: calc(100vw - 12px) !important;
            width: min(var(--bygone-panel-width, 430px), calc(100vw - 12px)) !important;
            max-height: calc(100vh - 158px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) !important;
            overflow-y: auto !important;
            background: #f5f5f5 !important; color: #222 !important;
            border: 1px solid #888 !important; border-radius: 4px !important;
            box-shadow: 0 2px 12px rgba(0,0,0,.4) !important;
            font: var(--bygone-control-size, 16px) sans-serif !important;
            visibility: visible !important; opacity: 1 !important;
            transform: none !important; zoom: 1 !important;
        }
        #wbt-panel.wbt-hidden { display: none !important; }
        .wbt-h { background: linear-gradient(#e8e8e8, #d4d4d4); padding: 10px 12px;
            font: bold var(--bygone-control-title-size, 17px) sans-serif; border-bottom: 1px solid #aaa; cursor: move; }
        .wbt-close { float: right; cursor: pointer; color: #666; font-weight: normal; }
        .wbt-close:hover { color: #c00; }
        .wbt-body { padding: 10px 12px; }
        .wbt-sec { margin-bottom: 14px; }
        .wbt-sec h4 { margin: 0 0 8px; font: bold var(--bygone-control-size, 16px) sans-serif; color: #333;
            border-bottom: 1px dotted #aaa; padding-bottom: 3px; }
        .wbt-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 6px 0; }
        .wbt-row input[type="text"], .wbt-row input[type="date"], .wbt-row input[type="number"],
        .wbt-row select { flex: 1 1 150px; min-height: var(--bygone-control-height, 42px); padding: 7px 9px; border: 1px solid #aaa;
            border-radius: 2px; font: var(--bygone-control-size, 16px) sans-serif; min-width: 0; box-sizing: border-box; }
        .wbt-file { flex: 1 1 190px; max-width: 100%; min-height: var(--bygone-control-height, 42px); font: var(--bygone-control-size, 16px) sans-serif; color: #222; }
        .wbt-btn { min-height: var(--bygone-control-height, 42px); padding: 7px 12px; border: 1px solid #888; background: #ddd;
            border-radius: 2px; cursor: pointer; font: var(--bygone-control-size, 16px) sans-serif; white-space: nowrap; box-sizing: border-box; }
        .wbt-btn:hover { background: #e8e8e8; }
        .wbt-btn-primary { background: #c00; color: #fff; border-color: #800; }
        .wbt-btn-primary:hover { background: #e00; }
        .wbt-btn-x { padding: 0 6px; font-weight: bold; color: #c00; }
        .wbt-list { background: #fff; border: 1px solid #aaa; border-radius: 2px;
            min-height: var(--bygone-control-height, 42px); max-height: 180px; overflow-y: auto; }
        .wbt-item { min-height: var(--bygone-control-height, 42px); padding: 7px 9px; border-bottom: 1px dotted #ddd;
            display: flex; align-items: center; gap: 8px; cursor: grab; }
        .wbt-item:last-child { border-bottom: 0; }
        .wbt-item.dragging { opacity: .4; }
        .wbt-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .wbt-item-weight { width: 40px; }
        .wbt-toggle { min-height: var(--bygone-control-height, 42px); display: flex; align-items: center; gap: 8px; margin: 4px 0; cursor: pointer; }
        .wbt-tabs { display: flex; gap: 0; border-bottom: 1px solid #aaa; overflow-x: auto; }
        .wbt-tab { flex: 1 0 auto; text-align: center; padding: 10px 11px; cursor: pointer; border: 1px solid transparent;
            border-bottom: 0; font-size: var(--bygone-control-size, 16px); }
        .wbt-tab.active { background: #f5f5f5; border-color: #aaa; }
        .wbt-tabbody { display: none; }
        .wbt-tabbody.active { display: block; }
        .wbt-mute { color: #666; font-size: var(--bygone-control-small, 14px); line-height: 1.4; }
        .wbt-pill { display: inline-block; background: #ddd; padding: 1px 5px; border-radius: 8px;
            font-size: var(--bygone-control-small, 14px); margin-right: 3px; }
        .wbt-stats td { padding: 1px 6px 1px 0; }
        #wbt-dep-modal {
            position: fixed !important;
            inset: 0 !important;
            z-index: 2147483647 !important;
            background: rgba(0,0,0,.55) !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            visibility: visible !important;
            opacity: 1 !important;
            font: 12px sans-serif !important;
            color: #222 !important;
        }
        #wbt-dep-modal-box {
            width: min(420px, calc(100vw - 28px)) !important;
            background: #f5f5f5 !important;
            border: 1px solid #777 !important;
            box-shadow: 0 4px 22px rgba(0,0,0,.45) !important;
            padding: 12px !important;
            border-radius: 3px !important;
        }
        .wbt-dep-actions {
            display: flex !important;
            flex-wrap: wrap !important;
            gap: 6px !important;
            margin-top: 10px !important;
        }
    `;

    class UI {
        constructor(api, feedEngine) {
            this.api = api;
            this.feedEngine = feedEngine;
            this._dragSrc = null;
            this._feedStatus = '';
            this._feedStatusTimer = null;
            this._activeTab = _checkV3() ? 'feed' : 'setup';
        }

        init() {
            try { GM_addStyle(CSS); } catch {}
            try {
                if (!document.getElementById('wbt-style')) {
                    const s = document.createElement('style');
                    s.id = 'wbt-style';
                    s.textContent = CSS;
                    (document.head || document.documentElement).appendChild(s);
                }
            } catch {}
            if (!document.body) {
                document.addEventListener('DOMContentLoaded', () => this.init(), { once: true });
                return;
            }
            this._mountFab();
            this._mountPanel();
        }

        _style(el, props) {
            for (const k in props) {
                try { el.style.setProperty(k, props[k], 'important'); } catch {}
            }
        }

        _mountFab() {
            if (document.getElementById('wbt-fab')) return;
            const fab = this._el('button', 'wbt-fab', '⏲');
            fab.id = 'wbt-fab';
            fab.title = 'bygone-yt — open panel';
            this._style(fab, {
                position: 'fixed',
                bottom: 'calc(82px + env(safe-area-inset-bottom, 0px))',
                right: 'calc(16px + env(safe-area-inset-right, 0px))',
                'z-index': '2147483646',
                width: '56px', height: '56px',
                'border-radius': '50%',
                background: '#c00', color: '#fff',
                border: '1px solid #800',
                font: 'bold 22px sans-serif',
                'line-height': '56px',
                cursor: 'pointer',
                'box-shadow': '0 2px 8px rgba(0,0,0,.4)',
                display: 'block', visibility: 'visible', opacity: '1',
                transform: 'none', zoom: '1',
                padding: '0', margin: '0',
            });
            fab.onclick = (e) => {
                e.preventDefault();
                e.stopPropagation();
                const panel = document.getElementById('wbt-panel');
                if (panel) {
                    const wasHidden = panel.classList.contains('wbt-hidden');
                    panel.classList.toggle('wbt-hidden');
                    panel.style.setProperty('display', wasHidden ? 'block' : 'none', 'important');
                }
            };
            if (Store.getHideFab()) fab.style.setProperty('display', 'none', 'important');
            (document.body || document.documentElement).appendChild(fab);
            this._wireFabShortcut();
        }

        _wireFabShortcut() {
            if (UI._fabShortcutWired) return;
            UI._fabShortcutWired = true;
            document.addEventListener('keydown', (e) => {
                if (!e.ctrlKey || !e.shiftKey || (e.key !== 'B' && e.key !== 'b')) return;
                e.preventDefault();
                const next = !Store.getHideFab();
                Store.setHideFab(next);
                const fab = document.getElementById('wbt-fab');
                if (fab) fab.style.setProperty('display', next ? 'none' : 'block', 'important');
            }, true);
        }

        _mountPanel() {
            const old = document.getElementById('wbt-panel');
            if (old) old.remove();
            const p = this._el('div');
            p.id = 'wbt-panel';
            p.classList.add('wbt-hidden');
            this._style(p, {
                position: 'fixed',
                bottom: 'calc(140px + env(safe-area-inset-bottom, 0px))',
                right: '6px',
                'z-index': '2147483647',
                width: 'min(var(--bygone-panel-width, 430px), calc(100vw - 12px))',
                'max-width': 'calc(100vw - 12px)',
                'max-height': 'calc(100vh - 158px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px))',
                'overflow-y': 'auto',
                background: '#f5f5f5', color: '#222',
                border: '1px solid #888', 'border-radius': '4px',
                'box-shadow': '0 2px 12px rgba(0,0,0,.4)',
                font: 'var(--bygone-control-size, 16px) sans-serif',
                display: 'none',
                'pointer-events': 'auto',
                transform: 'none', zoom: '1',
                padding: '0', margin: '0',
            });
            this._renderPanel(p);
            (document.body || document.documentElement).appendChild(p);
        }

        _renderPanel(p) {
            p.innerHTML = '';

            const header = this._el('div', 'wbt-h', 'bygone-yt v' + VERSION);
            this._style(header, {
                background: 'linear-gradient(#e8e8e8, #d4d4d4)',
                padding: '10px 12px', 'font-weight': 'bold',
                'border-bottom': '1px solid #aaa', cursor: 'move',
                color: '#222', font: 'bold var(--bygone-control-title-size, 17px) sans-serif',
            });
            const close = this._el('span', 'wbt-close', '✕');
            this._style(close, { float: 'right', cursor: 'pointer', color: '#666', 'font-weight': 'normal' });
            close.onclick = () => {
                p.classList.add('wbt-hidden');
                p.style.setProperty('display', 'none', 'important');
            };
            header.appendChild(close);
            this._enableDrag(p, header);
            p.appendChild(header);

            const tabs = this._el('div', 'wbt-tabs');
            this._style(tabs, { display: 'flex', gap: '0', 'border-bottom': '1px solid #aaa', background: '#eee', 'overflow-x': 'auto' });
            const body = this._el('div', 'wbt-body');
            this._style(body, { padding: '10px 12px' });

            const sections = [
                ['feed',     'Feed',     () => this._renderFeed()],
                ['sources',  'Sources',  () => this._renderSources()],
                ['profiles', 'Profiles', () => this._renderProfiles()],
                ['look',     'Look',     () => this._renderLook()],
                ['stats',    'Stats',    () => this._renderStats()],
                ['setup',    'Setup',    () => this._renderSetup()],
            ];
            for (const [id, label, render] of sections) {
                const tab = this._el('div', 'wbt-tab', label);
                this._style(tab, {
                    flex: '1 0 auto', padding: '10px 11px', cursor: 'pointer',
                    border: '1px solid transparent', 'border-bottom': '0',
                    'font-size': 'var(--bygone-control-size, 16px)', 'text-align': 'center',
                    background: id === this._activeTab ? '#f5f5f5' : 'transparent',
                    'border-top-color': id === this._activeTab ? '#aaa' : 'transparent',
                    'border-left-color': id === this._activeTab ? '#aaa' : 'transparent',
                    'border-right-color': id === this._activeTab ? '#aaa' : 'transparent',
                });
                if (id === this._activeTab) tab.classList.add('active');
                tab.onclick = () => {
                    this._activeTab = id;
                    this._renderPanel(p);
                };
                tabs.appendChild(tab);
            }
            const section = sections.find(s => s[0] === this._activeTab);
            const content = section ? section[2]() : this._renderFeed();
            body.appendChild(content);
            p.appendChild(tabs);
            p.appendChild(body);
        }

        _styleBtn(b, primary) {
            this._style(b, {
                'min-height': 'var(--bygone-control-height, 42px)', padding: '7px 12px',
                border: '1px solid ' + (primary ? '#800' : '#888'),
                background: primary ? '#c00' : '#ddd',
                color: primary ? '#fff' : '#222',
                'border-radius': '2px', cursor: 'pointer',
                font: 'var(--bygone-control-size, 16px) sans-serif', 'white-space': 'nowrap',
                'box-sizing': 'border-box',
            });
        }
        _styleInput(i) {
            this._style(i, {
                flex: '1 1 150px', 'min-height': 'var(--bygone-control-height, 42px)', padding: '7px 9px',
                border: '1px solid #aaa', 'border-radius': '2px',
                font: 'var(--bygone-control-size, 16px) sans-serif', 'min-width': '0',
                background: '#fff', color: '#222',
                'box-sizing': 'border-box',
            });
        }
        _styleRow(r) {
            this._style(r, { display: 'flex', gap: '8px', 'align-items': 'center', 'flex-wrap': 'wrap', margin: '6px 0' });
        }
        _styleSec(s) {
            this._style(s, { 'margin-bottom': '14px' });
        }
        _styleH4(h) {
            this._style(h, {
                margin: '0 0 8px', 'font-size': 'var(--bygone-control-size, 16px)', color: '#333',
                'border-bottom': '1px dotted #aaa', 'padding-bottom': '3px',
                font: 'bold var(--bygone-control-size, 16px) sans-serif',
            });
        }
        _styleList(l) {
            this._style(l, {
                background: '#fff', border: '1px solid #aaa',
                'border-radius': '2px', 'min-height': 'var(--bygone-control-height, 42px)',
                'max-height': '180px', 'overflow-y': 'auto',
            });
        }
        _styleItem(it) {
            this._style(it, {
                'min-height': 'var(--bygone-control-height, 42px)', padding: '7px 9px', 'border-bottom': '1px dotted #ddd',
                display: 'flex', 'align-items': 'center', gap: '6px', cursor: 'grab',
            });
        }
        _styleMute(m) {
            this._style(m, { color: '#666', 'font-size': 'var(--bygone-control-small, 14px)', 'line-height': '1.4' });
        }
        _styleToggle(l) {
            this._style(l, { 'min-height': 'var(--bygone-control-height, 42px)', display: 'flex', 'align-items': 'center', gap: '8px', margin: '4px 0', cursor: 'pointer' });
        }

        _renderFeed() {
            const wrap = this._el('div');
            wrap.appendChild(this._toggle('Active', Store.isActive(), v => {
                Store.setActive(v);
                if (v) {
                    this._reloadFeed();
                } else {
                    try { Interceptor.clearPool(); } catch (_) {}
                    try { Interceptor.setPaused(true); } catch (_) {}
                    this._setFeedStatus('Paused — YouTube is showing its own videos. Reload the page for a clean reset.', 8000);
                }
            }));

            const dateSec = this._el('div', 'wbt-sec');
            dateSec.appendChild(this._el('h4', null, 'Date'));
            const dateRow = this._el('div', 'wbt-row');
            const date = Store.getDate() || '';
            const dateInput = this._el('input');
            dateInput.type = 'date';
            dateInput.value = date;
            const applyDate = (val) => {
                if (!/^\d{4}-\d{2}-\d{2}$/.test(val) || isNaN(new Date(val).getTime())) return;
                if (Store.isClockActive()) Store.startClock(val);
                else Store.setDate(val);
                if (dateInput.value !== val) dateInput.value = val;
                if (dateText.value !== val) dateText.value = val;
                this._clearFeedCaches();
                this._reloadFeed();
            };
            dateInput.onchange = () => applyDate(dateInput.value);
            dateRow.appendChild(dateInput);
            const dateText = this._el('input');
            dateText.type = 'text';
            dateText.placeholder = 'YYYY-MM-DD';
            dateText.value = date;
            dateText.setAttribute('inputmode', 'numeric');
            dateText.setAttribute('autocomplete', 'off');
            dateText.maxLength = 10;
            this._style(dateText, { 'max-width': '120px' });
            dateText.onchange = () => applyDate(dateText.value.trim());
            dateText.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') { e.preventDefault(); applyDate(dateText.value.trim()); }
            });
            dateRow.appendChild(dateText);
            dateSec.appendChild(dateRow);

            const presetRow = this._el('div', 'wbt-row');
            for (const y of [2008, 2011, 2014, 2017]) {
                const b = this._el('button', 'wbt-btn', String(y));
                b.title = 'Jump to ' + y;
                b.onclick = () => {
                    const now = new Date();
                    let day = now.getDate();
                    const month = now.getMonth();
                    const isLeap = (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0;
                    if (month === 1 && day === 29 && !isLeap) day = 28;
                    applyDate(Store._formatLocalDate(new Date(y, month, day)));
                };
                presetRow.appendChild(b);
            }
            dateSec.appendChild(presetRow);

            const clockRow = this._el('div', 'wbt-row');
            const clockBtn = this._el('button', 'wbt-btn', Store.isClockActive() ? 'Stop clock' : 'Start rolling clock');
            clockBtn.onclick = () => {
                if (Store.isClockActive()) Store.stopClock();
                else if (dateInput.value) Store.startClock(dateInput.value);
                this._renderPanel(document.getElementById('wbt-panel'));
                this._reloadFeed();
            };
            clockRow.appendChild(clockBtn);
            dateSec.appendChild(clockRow);
            if (Store.isClockActive()) {
                const now = Store.getCurrentDate();
                dateSec.appendChild(this._el('div', 'wbt-mute', 'Sim time: ' + now));
            }
            wrap.appendChild(dateSec);

            const togSec = this._el('div', 'wbt-sec');
            togSec.appendChild(this._el('h4', null, 'Sources'));
            togSec.appendChild(this._toggle('"Similar" (CF) source', Store.isSimilarEnabled(), v => Store.setSimilarEnabled(v)));
            togSec.appendChild(this._toggle('Discovery', Store.isDiscoveryEnabled(), v => Store.setDiscoveryEnabled(v)));
            togSec.appendChild(this._toggle('Watch-history learning', Store.isLearningEnabled(), v => Store.setLearningEnabled(v)));
            togSec.appendChild(this._toggle('Auto-subscribe on YouTube to bygone subs', Store.isAutoSyncSubs(), v => {
                Store.setAutoSyncSubs(v);
                if (v) App._scheduleSubSync(500);
            }));
            wrap.appendChild(togSec);

            const actions = this._el('div', 'wbt-sec');
            const row = this._el('div', 'wbt-row');
            const reload = this._el('button', 'wbt-btn wbt-btn-primary', 'Reload feed');
            reload.onclick = () => this._reloadFeed(reload);
            const clear = this._el('button', 'wbt-btn', 'Clear cache');
            clear.onclick = async () => {
                const n = this._clearFeedCaches();
                this._setFeedStatus('Cleared ' + n + ' cached feed ' + (n === 1 ? 'entry' : 'entries') + ' and reset the pool. Reloading...');
                await this._reloadFeed(clear, 'Cache cleared. ');
            };
            row.appendChild(reload); row.appendChild(clear);
            actions.appendChild(row);
            const status = this._el('div', 'wbt-mute', this._feedStatus || '');
            status.id = 'wbt-feed-status';
            this._style(status, { 'min-height': '14px', 'margin-top': '4px' });
            actions.appendChild(status);
            wrap.appendChild(actions);

            return wrap;
        }

        _renderSources() {
            const wrap = this._el('div');

            const subSec = this._listSection('Subscriptions',
                Store.getSubscriptions(),
                (s) => s.name + (s.weight ? ` (w${s.weight})` : ''),
                'Channel name…',
                async (name) => {
                    if (!name) return;
                    const ch = await this.api.resolveChannel(name).catch(() => null);
                    const subs = Store.getSubscriptions();
                    subs.push({ id: ch ? ch.id : null, name: ch ? ch.name : name, weight: 3 });
                    Store.setSubscriptions(subs);
                    App._scheduleSubSync(800);
                },
                (newOrder) => Store.setSubscriptions(newOrder));
            wrap.appendChild(subSec);

            wrap.appendChild(this._listSection('Search terms',
                Store.getSearchTerms(),
                (t) => (typeof t === 'string' ? t : t.term) + (t.weight ? ` (w${t.weight})` : ''),
                'Search query…',
                (q) => { if (!q) return; const t = Store.getSearchTerms(); t.push({ term: q, weight: 3 }); Store.setSearchTerms(t); },
                (newOrder) => Store.setSearchTerms(newOrder)));

            wrap.appendChild(this._listSection('Custom topics',
                Store.getTopics(),
                (t) => (typeof t === 'string' ? t : t.name) + (t.weight ? ` (w${t.weight})` : ''),
                'Topic name…',
                (n) => { if (!n) return; const t = Store.getTopics(); t.push({ name: n, weight: 3 }); Store.setTopics(t); },
                (newOrder) => Store.setTopics(newOrder)));

            const catSec = this._el('div', 'wbt-sec');
            catSec.appendChild(this._el('h4', null, 'Categories'));
            const selected = new Set(Store.getCategories());
            for (const [id, name] of Object.entries(CONFIG.categories)) {
                const row = this._el('label', 'wbt-toggle');
                const cb = this._el('input');
                cb.type = 'checkbox';
                cb.checked = selected.has(Number(id));
                cb.onchange = () => {
                    if (cb.checked) selected.add(Number(id));
                    else selected.delete(Number(id));
                    Store.setCategories(Array.from(selected));
                };
                row.appendChild(cb);
                row.appendChild(document.createTextNode(' ' + name));
                catSec.appendChild(row);
            }
            wrap.appendChild(catSec);

            wrap.appendChild(this._listSection('Blocked channels',
                Store.getBlockedChannels(),
                (b) => b.name,
                'Channel name to block…',
                (n) => { if (!n) return; const b = Store.getBlockedChannels(); b.push({ name: n, id: null }); Store.setBlockedChannels(b); },
                (newOrder) => Store.setBlockedChannels(newOrder)));

            wrap.appendChild(this._listSection('Global negative keywords',
                Store.getGlobalNegatives().map(n => ({ name: n })),
                (n) => n.name,
                'Negative keyword…',
                (n) => { if (!n) return; const list = Store.getGlobalNegatives(); list.push(n); Store.setGlobalNegatives(list); },
                (newOrder) => Store.setGlobalNegatives(newOrder.map(n => n.name))));

            return wrap;
        }

        _listSection(title, items, formatItem, placeholder, onAdd, onReorder) {
            const sec = this._el('div', 'wbt-sec');
            sec.appendChild(this._el('h4', null, title));
            const list = this._el('div', 'wbt-list');
            items.forEach((item, idx) => {
                const row = this._el('div', 'wbt-item');
                row.draggable = true;
                row.dataset.idx = String(idx);
                row.ondragstart = (e) => { this._dragSrc = idx; row.classList.add('dragging'); try { e.dataTransfer.effectAllowed = 'move'; } catch {} };
                row.ondragend = () => row.classList.remove('dragging');
                row.ondragover = (e) => { e.preventDefault(); };
                row.ondrop = (e) => {
                    e.preventDefault();
                    const src = this._dragSrc; this._dragSrc = null;
                    if (src === null || src === idx) return;
                    const reordered = items.slice();
                    const [moved] = reordered.splice(src, 1);
                    reordered.splice(idx, 0, moved);
                    onReorder(reordered);
                    this._renderPanel(document.getElementById('wbt-panel'));
                };
                row.appendChild(this._el('span', 'wbt-item-name', formatItem(item)));
                const rm = this._el('button', 'wbt-btn wbt-btn-x', '×');
                rm.onclick = () => {
                    const next = items.slice();
                    next.splice(idx, 1);
                    onReorder(next);
                    this._renderPanel(document.getElementById('wbt-panel'));
                };
                row.appendChild(rm);
                list.appendChild(row);
            });
            sec.appendChild(list);

            const addRow = this._el('div', 'wbt-row');
            const input = this._el('input');
            input.type = 'text';
            input.placeholder = placeholder;
            const addBtn = this._el('button', 'wbt-btn', '+');
            const doAdd = async () => {
                const val = input.value.trim();
                input.value = '';
                await onAdd(val);
                this._renderPanel(document.getElementById('wbt-panel'));
            };
            addBtn.onclick = doAdd;
            input.onkeydown = (e) => { if (e.key === 'Enter') doAdd(); };
            addRow.appendChild(input);
            addRow.appendChild(addBtn);
            sec.appendChild(addRow);

            return sec;
        }

        _renderProfiles() {
            const wrap = this._el('div');
            wrap.appendChild(this._el('h4', null, 'Profiles'));
            const profiles = Store.getProfiles();
            const names = Object.keys(profiles);

            if (!names.length) wrap.appendChild(this._el('div', 'wbt-mute', 'No saved profiles yet.'));
            for (const name of names) {
                const row = this._el('div', 'wbt-item');
                row.appendChild(this._el('span', 'wbt-item-name', name));
                const load = this._el('button', 'wbt-btn', 'Load');
                load.onclick = () => { Store.loadProfile(name); this._renderPanel(document.getElementById('wbt-panel')); this._reloadFeed(); App._scheduleSubSync(800); };
                const exp  = this._el('button', 'wbt-btn', 'Export');
                exp.onclick = () => {
                    const blob = new Blob([Store.exportProfile(name)], { type: 'application/json' });
                    const url = URL.createObjectURL(blob);
                    const a = this._el('a');
                    a.href = url; a.download = `bygone-profile-${name}.json`;
                    a.click();
                    setTimeout(() => URL.revokeObjectURL(url), 1000);
                };
                const del  = this._el('button', 'wbt-btn wbt-btn-x', '×');
                del.onclick = () => { if (confirm(`Delete profile "${name}"?`)) { Store.deleteProfile(name); this._renderPanel(document.getElementById('wbt-panel')); } };
                row.appendChild(load); row.appendChild(exp); row.appendChild(del);
                wrap.appendChild(row);
            }

            const addRow = this._el('div', 'wbt-row');
            const input = this._el('input');
            input.type = 'text';
            input.placeholder = 'New profile name…';
            const saveBtn = this._el('button', 'wbt-btn', 'Save current as…');
            saveBtn.onclick = () => {
                const n = input.value.trim();
                if (!n) return;
                Store.saveProfile(n);
                input.value = '';
                this._renderPanel(document.getElementById('wbt-panel'));
            };
            const blankBtn = this._el('button', 'wbt-btn', 'New blank');
            blankBtn.onclick = () => {
                const n = input.value.trim();
                if (!n) { input.placeholder = 'enter a name first…'; input.focus(); return; }
                if (Store.getProfiles()[n] && !confirm(`Overwrite "${n}" with a blank profile?`)) return;
                Store.createBlankProfile(n);
                input.value = '';
                this._renderPanel(document.getElementById('wbt-panel'));
            };
            addRow.appendChild(input); addRow.appendChild(saveBtn); addRow.appendChild(blankBtn);
            wrap.appendChild(addRow);

            const impRow = this._el('div', 'wbt-row');
            const imp = this._el('input', 'wbt-file');
            imp.type = 'file';
            imp.accept = '.json,application/json,text/json,text/plain';
            imp.onchange = () => {
                const f = imp.files && imp.files[0];
                if (!f) return;
                const r = new FileReader();
                r.onload = () => {
                    try { Store.importProfile(r.result); alert('Profile imported.'); this._renderPanel(document.getElementById('wbt-panel')); }
                    catch (e) { alert('Import failed: ' + e.message); }
                    finally { imp.value = ''; }
                };
                r.readAsText(f);
            };
            impRow.appendChild(imp);
            wrap.appendChild(impRow);

            wrap.appendChild(this._el('h4', null, 'Full Backup'));
            const expAllRow = this._el('div', 'wbt-row');
            const expAllBtn = this._el('button', 'wbt-btn wbt-btn-primary', 'Export ALL data');
            expAllBtn.onclick = () => {
                const blob = new Blob([Store.exportAll()], { type: 'application/json' });
                const url = URL.createObjectURL(blob);
                const a = this._el('a');
                a.href = url; a.download = `bygone-yt-full-backup.json`;
                a.click();
                setTimeout(() => URL.revokeObjectURL(url), 1000);
            };
            expAllRow.appendChild(expAllBtn);
            wrap.appendChild(expAllRow);

            const backupStatus = this._el('div', 'wbt-mute', this._backupStatus || '');
            backupStatus.id = 'wbt-backup-status';
            const setBackupStatus = (text, ttlMs) => {
                this._backupStatus = text || '';
                const el = document.getElementById('wbt-backup-status');
                if (el) el.textContent = this._backupStatus;
                if (this._backupStatusTimer) clearTimeout(this._backupStatusTimer);
                if (ttlMs) {
                    this._backupStatusTimer = setTimeout(() => {
                        this._backupStatus = '';
                        const cur = document.getElementById('wbt-backup-status');
                        if (cur) cur.textContent = '';
                    }, ttlMs);
                }
            };
            const runImportAll = async (text) => {
                try {
                    Store.importAll(text);
                } catch (e) {
                    setBackupStatus('Import failed: ' + (e && e.message ? e.message : e));
                    return;
                }
                const cleared = this._clearFeedCaches();
                setBackupStatus('Full backup restored. Cleared ' + cleared + ' old feed cache ' + (cleared === 1 ? 'entry' : 'entries') + ' — reloading feed...', 15000);
                this._broadcastKioskLookPrefs();
                this._renderPanel(document.getElementById('wbt-panel'));
                App._scheduleSubSync(800);
                await this._reloadFeed(null, 'Full backup restored. ');
            };

            const impAllRow = this._el('div', 'wbt-row');
            const impAll = this._el('input', 'wbt-file');
            impAll.type = 'file';
            impAll.accept = '.json,application/json,text/json,text/plain';
            impAll.onchange = () => {
                const f = impAll.files && impAll.files[0];
                if (!f) return;
                const r = new FileReader();
                r.onload = () => { runImportAll(r.result); impAll.value = ''; };
                r.onerror = () => { setBackupStatus('Import failed: could not read the file.'); impAll.value = ''; };
                r.readAsText(f);
            };
            impAllRow.appendChild(impAll);
            wrap.appendChild(impAllRow);

            const pasteBox = this._el('textarea');
            pasteBox.placeholder = 'Kiosk/mobile: paste the backup JSON here instead';
            pasteBox.setAttribute('autocomplete', 'off');
            pasteBox.setAttribute('spellcheck', 'false');
            this._style(pasteBox, { width: '100%', 'min-height': '70px', 'box-sizing': 'border-box' });
            const pasteRow = this._el('div', 'wbt-row');
            pasteRow.appendChild(pasteBox);
            wrap.appendChild(pasteRow);
            const pasteBtnRow = this._el('div', 'wbt-row');
            const pasteBtn = this._el('button', 'wbt-btn', 'Import pasted JSON');
            pasteBtn.onclick = () => {
                const text = (pasteBox.value || '').trim();
                if (!text) { setBackupStatus('Paste the backup JSON first.', 8000); return; }
                runImportAll(text);
            };
            pasteBtnRow.appendChild(pasteBtn);
            wrap.appendChild(pasteBtnRow);
            wrap.appendChild(backupStatus);

            return wrap;
        }

        _renderLook() {
            const wrap = this._el('div');
            wrap.appendChild(this._el('h4', null, 'APK page look'));

            const dark = this._el('input');
            dark.type = 'checkbox';
            dark.checked = Store.getKioskDarkMode();
            const darkRow = this._el('label', 'wbt-toggle');
            darkRow.appendChild(dark);
            darkRow.appendChild(document.createTextNode('Dark mode'));
            dark.onchange = () => {
                Store.setKioskDarkMode(dark.checked);
                this._broadcastKioskLookPrefs();
            };
            wrap.appendChild(darkRow);

            const hideFab = this._el('input');
            hideFab.type = 'checkbox';
            hideFab.checked = Store.getHideFab();
            const hideFabRow = this._el('label', 'wbt-toggle');
            hideFabRow.appendChild(hideFab);
            hideFabRow.appendChild(document.createTextNode('Hide the floating ⏲ button (Ctrl+Shift+B toggles it back; the kiosk bottom nav still opens this panel)'));
            hideFab.onchange = () => {
                Store.setHideFab(hideFab.checked);
                const fab = document.getElementById('wbt-fab');
                if (fab) fab.style.setProperty('display', hideFab.checked ? 'none' : 'block', 'important');
            };
            wrap.appendChild(hideFabRow);

            const zoomRow = this._el('div', 'wbt-row');
            const zoomLabel = this._el('span', null, 'UI size');
            this._style(zoomLabel, { width: '68px', 'font-size': 'var(--bygone-control-small, 14px)', color: '#333' });
            const zoom = this._el('input');
            zoom.type = 'range';
            zoom.min = '0.9';
            zoom.max = '1.65';
            zoom.step = '0.05';
            zoom.value = String(Store.getKioskZoom());
            this._style(zoom, { flex: '1' });
            const zoomValue = this._el('span', null, Math.round(Store.getKioskZoom() * 100) + '%');
            this._style(zoomValue, { width: '48px', 'font-size': 'var(--bygone-control-small, 14px)', color: '#333', 'text-align': 'right' });
            const resetZoom = this._el('button', 'wbt-btn', 'Reset');
            const applyZoom = () => {
                Store.setKioskZoom(zoom.value);
                zoomValue.textContent = Math.round(Store.getKioskZoom() * 100) + '%';
                this._broadcastKioskLookPrefs();
            };
            zoom.oninput = applyZoom;
            resetZoom.onclick = () => {
                zoom.value = '1.35';
                applyZoom();
            };
            zoomRow.appendChild(zoomLabel);
            zoomRow.appendChild(zoom);
            zoomRow.appendChild(zoomValue);
            zoomRow.appendChild(resetZoom);
            wrap.appendChild(zoomRow);

            const hint = this._el('div', 'wbt-mute', 'These controls are read by the APK page layer. UI size enlarges cards, thumbnails, titles, and touch targets without moving the floating button.');
            wrap.appendChild(hint);

            wrap.appendChild(this._el('h4', null, 'Custom logo'));

            const cur = Store.getCustomLogo();
            if (cur) {
                const img = this._el('img');
                img.src = cur;
                img.style.maxWidth = '100%';
                img.style.maxHeight = '60px';
                wrap.appendChild(img);
            }
            const row = this._el('div', 'wbt-row');
            const file = this._el('input', 'wbt-file');
            file.type = 'file';
            file.accept = 'image/*';
            file.onchange = () => {
                const f = file.files && file.files[0];
                if (!f) return;
                const r = new FileReader();
                r.onload = () => {
                    Store.setCustomLogo(r.result);
                    this._renderPanel(document.getElementById('wbt-panel'));
                    this._applyCustomLogo();
                };
                r.readAsDataURL(f);
            };
            const clear = this._el('button', 'wbt-btn', 'Clear');
            clear.onclick = () => { Store.clearCustomLogo(); this._renderPanel(document.getElementById('wbt-panel')); };
            row.appendChild(file); row.appendChild(clear);
            wrap.appendChild(row);

            return wrap;
        }

        _renderStats() {
            const wrap = this._el('div');
            wrap.appendChild(this._el('h4', null, 'Pool'));
            const pool = this._el('table', 'wbt-stats');
            const row = (k, v) => { const tr = this._el('tr'); tr.appendChild(this._el('td', null, k)); tr.appendChild(this._el('td', null, String(v))); pool.appendChild(tr); };
            row('Pool size',   Interceptor.poolSize());
            row('Used',        Interceptor.usedCount());
            row('Active',      Interceptor.isActive());
            wrap.appendChild(pool);

            wrap.appendChild(this._el('h4', null, 'Learning'));
            const interests = Store.getCachedInterests();
            const lc = interests ? InterestModel.getLearnedChannels(interests) : [];
            const lk = interests ? InterestModel.getLearnedKeywords(interests) : [];
            if (!lc.length && !lk.length) {
                wrap.appendChild(this._el('div', 'wbt-mute', 'No learning data yet — watch some videos to build a profile.'));
            } else {
                wrap.appendChild(this._el('div', 'wbt-mute', 'Top channels:'));
                for (const c of lc.slice(0, 6)) wrap.appendChild(this._el('div', null, `• ${c.name} (${c.score.toFixed(1)})`));
                wrap.appendChild(this._el('div', 'wbt-mute', 'Top keywords:'));
                for (const k of lk.slice(0, 6)) wrap.appendChild(this._el('div', null, `• ${k.keyword}`));
            }

            const clearBtn = this._el('button', 'wbt-btn', 'Clear learning data');
            clearBtn.onclick = () => { if (confirm('Clear all watch history + learning?')) { Store.clearLearningData(); this._renderPanel(document.getElementById('wbt-panel')); } };
            wrap.appendChild(clearBtn);

            return wrap;
        }

        _renderSetup() {
            const wrap = this._el('div');
            wrap.appendChild(this._el('h4', null, 'Required Extensions'));

            const v3Ok = _checkV3();

            const v3Row = this._el('div', 'wbt-row');
            const v3Status = this._el('span', null, v3Ok ? 'V3 detected' : 'V3 NOT detected');
            this._style(v3Status, { color: v3Ok ? '#080' : '#c00', 'font-weight': 'bold', 'font-size': 'var(--bygone-control-small, 14px)' });
            v3Row.appendChild(v3Status);
            wrap.appendChild(v3Row);

            if (!v3Ok) {
                const warn = this._el('div');
                this._style(warn, {
                    background: '#fff3cd', border: '1px solid #e0c36a',
                    'border-radius': '4px', padding: '8px 10px', margin: '8px 0',
                    color: '#664d03', 'font-size': 'var(--bygone-control-small, 14px)', 'line-height': '1.5',
                });
                warn.innerHTML = '<b>bygone-yt requires V3 and StarTube to work.</b><br>' +
                    'V3 ("Get Old YouTube Layout") provides the 2013 YouTube layout.<br>' +
                    'StarTube is the companion userscript that V3 depends on.<br><br>' +
                    'Without these, bygone-yt cannot function — the page will not render correctly ' +
                    'and you may experience refresh loops or broken layouts.<br><br>' +
                    '<b>Install both V3 and StarTube first, then reload the page.</b>';
                wrap.appendChild(warn);
            } else {
                const ok = this._el('div', 'wbt-mute', 'V3 is installed and active. bygone-yt is ready to use.');
                wrap.appendChild(ok);
            }

            const kioskRev = document.documentElement.getAttribute('data-bygone-kiosk-rev');
            const kioskRow = this._el('div', 'wbt-row');
            kioskRow.appendChild(this._el('span', 'wbt-mute',
                'Kiosk page script: ' + (kioskRev ? 'rev ' + kioskRev : 'ABSENT (not kiosk, or stale extension)')));
            wrap.appendChild(kioskRow);

            const dbgBtn = this._el('button', 'wbt-btn', 'Copy debug info');
            const dbgOut = this._el('textarea');
            this._style(dbgOut, {
                display: 'none', width: '100%', height: '130px', margin: '6px 0',
                'font-size': '10px', 'line-height': '1.2', 'box-sizing': 'border-box',
            });
            dbgBtn.onclick = () => {
                const report = this._buildDebugReport();
                dbgOut.value = report;
                dbgOut.style.display = 'block';
                try { dbgOut.focus(); dbgOut.select(); } catch (_) {}
                try { navigator.clipboard && navigator.clipboard.writeText(report); } catch (_) {}
                try { document.execCommand && document.execCommand('copy'); } catch (_) {}
            };
            wrap.appendChild(dbgBtn);
            wrap.appendChild(dbgOut);

            const thumbBtn = this._el('button', 'wbt-btn', 'Copy thumb debug');
            const thumbOut = this._el('textarea');
            this._style(thumbOut, {
                display: 'none', width: '100%', height: '200px', margin: '6px 0',
                'font-size': '9px', 'line-height': '1.15', 'box-sizing': 'border-box',
                'white-space': 'pre', 'font-family': 'monospace',
            });
            thumbBtn.onclick = () => {
                const report = this._buildThumbReport();
                thumbOut.value = report;
                thumbOut.style.display = 'block';
                try { thumbOut.focus(); thumbOut.select(); } catch (_) {}
                try { navigator.clipboard && navigator.clipboard.writeText(report); } catch (_) {}
                try { document.execCommand && document.execCommand('copy'); } catch (_) {}
            };
            wrap.appendChild(thumbBtn);
            wrap.appendChild(thumbOut);

            const dumpBtn = this._el('button', 'wbt-btn', 'Copy FULL page dump');
            const dumpOut = this._el('textarea');
            this._style(dumpOut, {
                display: 'none', width: '100%', height: '250px', margin: '6px 0',
                'font-size': '8px', 'line-height': '1.1', 'box-sizing': 'border-box',
                'white-space': 'pre', 'font-family': 'monospace',
            });
            dumpBtn.onclick = () => {
                const report = this._buildFullPageDump();
                dumpOut.value = report;
                dumpOut.style.display = 'block';
                try { dumpOut.focus(); dumpOut.select(); } catch (_) {}
                try { navigator.clipboard && navigator.clipboard.writeText(report); } catch (_) {}
                try { document.execCommand && document.execCommand('copy'); } catch (_) {}
            };
            wrap.appendChild(dumpBtn);
            wrap.appendChild(dumpOut);

            wrap.appendChild(this._el('h4', null, 'About'));
            const about = this._el('div', 'wbt-mute');
            about.textContent = 'bygone-yt v' + VERSION + ' — YouTube time machine for V3/StarTube. ' +
                'Set a date and browse YouTube as it was back then.';
            wrap.appendChild(about);

            return wrap;
        }

        _buildDebugReport() {
            const lines = [];
            try { lines.push('bygone v' + VERSION); } catch (_) {}
            lines.push('kiosk-rev: ' + (document.documentElement.getAttribute('data-bygone-kiosk-rev') || 'ABSENT'));
            lines.push('ua: ' + navigator.userAgent);
            lines.push('viewport: ' + window.innerWidth + 'x' + window.innerHeight +
                ' path: ' + location.pathname);
            try { lines.push('pool: ' + Interceptor.poolSize() + ' active: ' + Interceptor.isActive()); } catch (e) { lines.push('pool err: ' + e.message); }
            try { if (typeof __bygoneDiag === 'function') lines.push('diag: ' + __bygoneDiag()); } catch (_) {}
            try { lines.push('flags: bygone_debug=' + localStorage.getItem('bygone_debug') + ' bygone_no_poke=' + localStorage.getItem('bygone_no_poke')); } catch (_) {}
            try { if (typeof __bygoneNav === 'function') lines.push('nav-trace:\n' + __bygoneNav()); } catch (_) {}
            try {
                const cards = Interceptor.findCards(document);
                let dumped = 0;
                for (const c of cards) {
                    const t = (c.textContent || '');
                    const views = (t.match(/\b\d[\d,.]*\s*[KkMmBb]?\s*views?\b/g) || []).length;
                    const dates = (t.match(/\b\d+\s*(?:years?|months?|weeks?|days?|hours?|y|mos?|wks?|w|d|hrs?|h)\.?\s+ago\b/gi) || []).length;
                    const watching = (t.match(/\bwatching\b/gi) || []).length;
                    if (views >= 2 || dates >= 2 || watching) {
                        dumped++;
                        lines.push('--- doubled card ' + dumped + ' (views=' + views + ' dates=' + dates + ' watching=' + watching + ') ---');
                        lines.push((c.outerHTML || '').replace(/\s+/g, ' ').slice(0, 1800));
                        if (dumped >= 2) break;
                    }
                }
                if (!dumped) lines.push('cards: ' + cards.length + ' — no doubled-meta cards on this page');
            } catch (e) { lines.push('card dump err: ' + e.message); }
            return lines.join('\n');
        }

        _buildThumbReport() {
            var lines = [];
            try {
                var imgs = document.querySelectorAll('img[data-bygone-thumb]');
                var vh = window.innerHeight;
                var vw = window.innerWidth;
                lines.push('bygone v' + VERSION + ' thumb-dump');
                lines.push('viewport: ' + vw + 'x' + vh + ' path: ' + location.pathname);
                lines.push('tagged imgs: ' + imgs.length);
                lines.push('');

                var ok = 0, broken = 0, offscreen = 0;
                for (var idx = 0; idx < imgs.length; idx++) {
                    var img = imgs[idx];
                    var r = img.getBoundingClientRect();
                    var vis = r.bottom > 0 && r.top < vh;
                    if (!vis) offscreen++;
                    var ratio = r.width > 0 ? r.height / r.width : 0;
                    var good = r.height >= 40 && ratio > 0.4;
                    if (good) {
                        ok++;
                        if (ok <= 8) {
                            var okCls = (img.className || '').toString().split(' ').slice(0, 3).join('.');
                            var okP = img.parentElement;
                            var okPCls = okP ? (okP.className || '').toString().split(' ').slice(0, 3).join('.') : '';
                            var okA = img.closest && img.closest('a[href]');
                            lines.push('[OK ' + idx + (vis ? '' : ' offscr') + '] ' + Math.round(r.width) + 'x' + Math.round(r.height) +
                                ' img=' + (okCls || '-') + ' parent=' + (okPCls || '-') +
                                ' a=' + (okA ? (okA.getAttribute('href') || '').slice(0, 40) : 'none') +
                                ' src=' + ((img.currentSrc || img.src || '').slice(-44)));
                        }
                        continue;
                    }
                    broken++;
                    if (broken > 8) continue;

                    lines.push('[BROKEN ' + idx + (vis ? '' : ' offscr') + '] img: ' + Math.round(r.width) + 'x' + Math.round(r.height) + ' screenY=' + Math.round(r.top) +
                        ' src=' + ((img.currentSrc || img.src || '').slice(-44)));
                    var chain = [];
                    for (var e = img, j = 0; e && j < 8; e = e.parentElement, j++) {
                        try {
                            var cr = e.getBoundingClientRect();
                            var cs = window.getComputedStyle(e);
                            var tag = e.tagName || '?';
                            var cl = (e.className || '').toString().split(' ').slice(0, 3).join('.');
                            chain.push('  ' + j + ': ' + tag + (cl ? '.' + cl : '') +
                                ' pos=' + cs.position + ' top=' + cs.top +
                                ' ' + Math.round(cr.width) + 'x' + Math.round(cr.height) +
                                ' overflow=' + cs.overflow +
                                ' display=' + cs.display);
                        } catch (_) { chain.push('  ' + j + ': ERR'); }
                    }
                    lines.push(chain.join('\n'));
                    lines.push('');
                }
                lines.push('summary: ok=' + ok + ' broken=' + broken + ' offscreen=' + offscreen + ' total=' + imgs.length);
            } catch (e) { lines.push('thumb report err: ' + e.message); }
            return lines.join('\n');
        }

        _buildFullPageDump() {
            var L = [];
            try {
                L.push('=== BYGONE FULL PAGE DUMP v' + VERSION + ' ===');
                L.push('url: ' + location.href);
                L.push('viewport: ' + window.innerWidth + 'x' + window.innerHeight);
                L.push('time: ' + new Date().toISOString());
                L.push('');

                L.push('=== STYLE ELEMENTS ===');
                var styles = document.querySelectorAll('style');
                for (var si = 0; si < styles.length; si++) {
                    var s = styles[si];
                    var id = s.id || '(no-id)';
                    var len = (s.textContent || '').length;
                    var rules = 0;
                    try { rules = s.sheet && s.sheet.cssRules ? s.sheet.cssRules.length : '?'; } catch (_) { rules = 'blocked'; }
                    L.push('style#' + id + ' rules=' + rules + ' len=' + len + ' media=' + (s.media || '') + ' disabled=' + s.disabled);
                    if (id.indexOf('bygone') >= 0 || id.indexOf('v3') >= 0 || id.indexOf('vorapis') >= 0) {
                        L.push('  content: ' + (s.textContent || '').slice(0, 2000));
                    }
                }
                L.push('');

                L.push('=== LINK STYLESHEETS ===');
                var links = document.querySelectorAll('link[rel="stylesheet"]');
                for (var li = 0; li < links.length; li++) {
                    L.push('link: ' + (links[li].href || '').slice(0, 200));
                }
                L.push('');

                L.push('=== PLAYER ===');
                var player = document.querySelector('#movie_player, #player, ytd-player, .html5-video-player');
                if (player) {
                    var pr = player.getBoundingClientRect();
                    var pcs = window.getComputedStyle(player);
                    L.push('player: ' + player.tagName + '#' + (player.id || '') + ' ' + Math.round(pr.width) + 'x' + Math.round(pr.height) + ' vis=' + pcs.visibility + ' display=' + pcs.display + ' opacity=' + pcs.opacity);
                    var vid = player.querySelector('video');
                    if (vid) {
                        var vr = vid.getBoundingClientRect();
                        L.push('video: ' + Math.round(vr.width) + 'x' + Math.round(vr.height) + ' paused=' + vid.paused + ' src=' + (vid.src || '').slice(0, 100) + ' readyState=' + vid.readyState);
                    }
                    L.push('player classes: ' + (player.className || '').toString().slice(0, 300));
                    L.push('player inline style: ' + (player.getAttribute('style') || 'none').slice(0, 500));
                } else {
                    L.push('player: NOT FOUND');
                }
                L.push('');

                L.push('=== SIDEBAR ===');
                var sidebar = document.querySelector('#watch7-sidebar, #related, ytd-watch-next-secondary-results-renderer, .watch-sidebar');
                if (sidebar) {
                    var sr = sidebar.getBoundingClientRect();
                    var scs = window.getComputedStyle(sidebar);
                    L.push('sidebar: ' + sidebar.tagName + '#' + (sidebar.id || '') + '.' + (sidebar.className || '').toString().split(' ')[0] + ' ' + Math.round(sr.width) + 'x' + Math.round(sr.height) + ' display=' + scs.display + ' vis=' + scs.visibility);
                    var sideCards = sidebar.querySelectorAll('.video-list-item, ytd-compact-video-renderer, .related-list-item');
                    L.push('sidebar cards: ' + sideCards.length);
                } else {
                    L.push('sidebar: NOT FOUND');
                }
                L.push('');

                L.push('=== HOME FEED ===');
                var shelves = document.querySelectorAll('.shelf-wrapper, ytd-rich-shelf-renderer, .branded-page-v2-body');
                L.push('shelves: ' + shelves.length);
                var allCards = document.querySelectorAll('[data-bygone-swept], [data-bygone-ok], .yt-lockup, ytd-rich-item-renderer');
                L.push('total cards (swept/lockup): ' + allCards.length);
                L.push('');

                L.push('=== VISIBLE CARDS ===');
                var vh = window.innerHeight;
                var cardSel = '.context-data-item, .yt-lockup, ytd-rich-item-renderer, .video-list-item';
                var allC = document.querySelectorAll(cardSel);
                var visCount = 0;
                for (var ci = 0; ci < allC.length && visCount < 30; ci++) {
                    var c = allC[ci];
                    var cr2 = c.getBoundingClientRect();
                    if (cr2.bottom < 0 || cr2.top > vh) continue;
                    visCount++;
                    var ccs = window.getComputedStyle(c);
                    var thumbEl = c.querySelector('.video-thumb');
                    var thumbStr = 'no-.video-thumb';
                    if (thumbEl) {
                        var tr = thumbEl.getBoundingClientRect();
                        var tcs = window.getComputedStyle(thumbEl);
                        thumbStr = '.video-thumb ' + Math.round(tr.width) + 'x' + Math.round(tr.height) + ' pos=' + tcs.position + ' overflow=' + tcs.overflow;
                    }
                    var imgEl = c.querySelector('img[data-bygone-thumb]');
                    var imgStr = 'no-bygone-img';
                    if (imgEl) {
                        var ir = imgEl.getBoundingClientRect();
                        var ics = window.getComputedStyle(imgEl);
                        imgStr = 'img ' + Math.round(ir.width) + 'x' + Math.round(ir.height) + ' pos=' + ics.position + ' aspect=' + ics.aspectRatio + ' objfit=' + ics.objectFit + ' parent=' + (imgEl.parentElement ? imgEl.parentElement.className || '' : '?').toString().split(' ')[0];
                    }
                    var clipEl = c.querySelector('.yt-thumb-clip');
                    var clipStr = 'no-clip';
                    if (clipEl) {
                        var clcs = window.getComputedStyle(clipEl);
                        clipStr = '.yt-thumb-clip pos=' + clcs.position + ' top=' + clcs.top + ' display=' + clcs.display + ' ' + Math.round(clipEl.getBoundingClientRect().width) + 'x' + Math.round(clipEl.getBoundingClientRect().height);
                    }
                    L.push('card' + visCount + ': ' + c.tagName + '.' + (c.className || '').toString().split(' ')[0] + ' ' + Math.round(cr2.width) + 'x' + Math.round(cr2.height));
                    L.push('  ' + thumbStr);
                    L.push('  ' + imgStr);
                    L.push('  ' + clipStr);
                }
                L.push('visible cards dumped: ' + visCount);
                L.push('');

                L.push('=== COMMENTS ===');
                try {
                    var cRoot = document.querySelector(
                        'ytd-comments, #watch-discussion, #watch7-discussion, ' +
                        '#comment-section-renderer, .comment-section, .comments'
                    );
                    if (!cRoot) {
                        L.push('comment root: NOT FOUND');
                    } else {
                        var crr = cRoot.getBoundingClientRect();
                        L.push('root: ' + cRoot.tagName + '#' + (cRoot.id || '') + ' ' + Math.round(crr.width) + 'x' + Math.round(crr.height));
                        var tSel = 'div.comment[data-id], ytd-comment-thread-renderer, ytd-comment-view-model, .comment-thread-renderer, .comment-item, .post';
                        var cParents = [];
                        cRoot.querySelectorAll(tSel).forEach(function (t) {
                            if (t.parentElement && cParents.indexOf(t.parentElement) === -1) cParents.push(t.parentElement);
                        });
                        cParents.sort(function (a, b) { return b.children.length - a.children.length; });
                        L.push('thread parents: ' + cParents.length);
                        for (var cpi = 0; cpi < Math.min(cParents.length, 3); cpi++) {
                            var cp = cParents[cpi];
                            L.push('parent' + cpi + ': ' + cp.tagName + '#' + (cp.id || '') + '.' + (cp.className || '').toString().split(' ').slice(0, 2).join('.'));
                            var kids = cp.children;
                            var printed = 0;
                            for (var kk = 0; kk < kids.length && printed < 40; kk++) {
                                var kid = kids[kk];
                                var kr = kid.getBoundingClientRect();
                                var kcs = window.getComputedStyle(kid);
                                var isThread = kid.matches && kid.matches(tSel);
                                var kidText = (kid.textContent || '').replace(/\s+/g, ' ').trim();
                                printed++;
                                L.push('  [' + kk + '] ' + kid.tagName + '.' + (kid.className || '').toString().split(' ').slice(0, 3).join('.') +
                                    (kid.id ? '#' + kid.id : '') +
                                    ' ' + Math.round(kr.width) + 'x' + Math.round(kr.height) +
                                    ' mt=' + kcs.marginTop + ' mb=' + kcs.marginBottom +
                                    ' pt=' + kcs.paddingTop + ' pb=' + kcs.paddingBottom +
                                    ' bt=' + kcs.borderTopWidth + ' disp=' + kcs.display +
                                    (isThread ? ' THREAD' : '') +
                                    (kid.getAttribute('data-bygone-comment-gap') ? ' GAP' : '') +
                                    (kid.getAttribute('data-bygone-comment-hidden') ? ' HIDDEN' : '') +
                                    (kid.getAttribute('data-bygone-comment-status') ? ' st=' + kid.getAttribute('data-bygone-comment-status') : '') +
                                    ' "' + kidText.slice(0, 42) + '"');
                            }
                            if (kids.length > printed) L.push('  ... +' + (kids.length - printed) + ' more children');
                        }
                    }
                } catch (ce) { L.push('comments dump err: ' + ce.message); }
                L.push('');

                L.push('=== KEY ELEMENT STYLES ===');
                var keys = ['body', '#page', '#content', '#page-manager', 'ytd-app', '#watch7-content', '#watch-appbar-playlist'];
                for (var ki = 0; ki < keys.length; ki++) {
                    var el = document.querySelector(keys[ki]);
                    if (!el) continue;
                    var elr = el.getBoundingClientRect();
                    var elcs = window.getComputedStyle(el);
                    L.push(keys[ki] + ': ' + Math.round(elr.width) + 'x' + Math.round(elr.height) + ' display=' + elcs.display + ' overflow=' + elcs.overflow + ' bg=' + elcs.backgroundColor);
                    var inl = el.getAttribute('style');
                    if (inl) L.push('  inline: ' + inl.slice(0, 300));
                }
                L.push('');

                L.push('=== MISC ===');
                try { L.push('pool: ' + Interceptor.poolSize() + ' active: ' + Interceptor.isActive()); } catch (e) { L.push('pool: ' + e.message); }
                try { if (typeof __bygoneDiag === 'function') L.push('diag: ' + __bygoneDiag()); } catch (_) {}
                try { if (typeof __bygoneNav === 'function') L.push('nav: ' + __bygoneNav()); } catch (_) {}
                L.push('bygone-hide-css: ' + (document.getElementById('bygone-hide-css') ? 'PRESENT' : 'ABSENT'));

            } catch (e) { L.push('DUMP ERROR: ' + e.message + '\n' + e.stack); }
            return L.join('\n');
        }

        static _STYLE_MAP = {
            'b14-sec': {
                background: 'linear-gradient(#414141,#373737)', color: '#a6a6a6',
                font: 'bold 13px/1.1 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif',
                padding: '7px 12px', 'text-shadow': '0 1px 0 rgba(0,0,0,.7)',
                'border-top': '1px solid #4d4d4d', 'border-bottom': '1px solid #1f1f1f',
            },
            'b14-row': {
                display: 'flex', 'align-items': 'center', gap: '14px', padding: '12px 14px',
                color: '#d8d8d8', font: 'bold 15px/1.2 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif',
                'border-bottom': '1px solid #242424', cursor: 'pointer', background: 'transparent',
            },
            'b14-active': { background: '#1b1b1b', color: '#fff', 'box-shadow': 'inset 5px 0 0 #cc181e' },
            'b14-ic': {
                flex: '0 0 30px', width: '30px', height: '30px', 'line-height': '30px',
                'text-align': 'center', 'font-size': '19px', color: '#bdbdbd', overflow: 'hidden',
            },
            'b14-tile': {
                background: '#4a4a4a', color: '#fff',
                font: 'bold 16px/30px "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif',
                border: '1px solid #1c1c1c', 'box-sizing': 'border-box',
            },
            'b14-label': {
                flex: '1 1 auto', 'min-width': '0', overflow: 'hidden',
                'text-overflow': 'ellipsis', 'white-space': 'nowrap',
            },
            'b14-sg': {
                display: 'flex', 'align-items': 'center', 'min-height': '46px',
                padding: '0 0 0 14px', 'border-bottom': '1px solid #e3e3e3', background: '#fff',
            },
            'b14-sg-q': {
                flex: '1 1 auto', 'min-width': '0', color: '#333',
                font: '16px/1.3 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif',
                'text-align': 'left', overflow: 'hidden', 'text-overflow': 'ellipsis', 'white-space': 'nowrap',
            },
            'b14-sg-fill': {
                flex: '0 0 48px', width: '48px', height: '46px', border: '0', margin: '0', padding: '0',
                background: 'transparent', color: '#9b9b9b', 'font-size': '20px',
                'line-height': '46px', 'text-align': 'center',
            },
            'b14-wtabs': {
                display: 'flex', width: '100%', margin: '0 0 10px', padding: '0',
                background: '#f1f1f1', 'border-bottom': '1px solid #d0d0d0', 'box-sizing': 'border-box',
            },
            'b14-wtab': {
                flex: '1 1 50%', 'min-height': '44px', border: '0', margin: '0', padding: '10px 6px',
                background: 'transparent', color: '#666',
                font: 'bold 15px/1.2 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif',
                'text-align': 'center', cursor: 'pointer', 'box-sizing': 'border-box',
                'text-transform': 'uppercase', 'letter-spacing': '.4px',
            },
            'wbt-sec':   { 'margin-bottom': '14px' },
            'wbt-row':   { display: 'flex', gap: '8px', 'align-items': 'center', 'flex-wrap': 'wrap', margin: '6px 0' },
            'wbt-btn':   {
                'min-height': 'var(--bygone-control-height, 42px)', padding: '7px 12px', border: '1px solid #888', background: '#ddd',
                color: '#222', 'border-radius': '2px', cursor: 'pointer',
                font: 'var(--bygone-control-size, 16px) sans-serif', 'white-space': 'nowrap', 'box-sizing': 'border-box',
            },
            'wbt-btn-primary': {
                'min-height': 'var(--bygone-control-height, 42px)', padding: '7px 12px', border: '1px solid #800', background: '#c00',
                color: '#fff', 'border-radius': '2px', cursor: 'pointer',
                font: 'var(--bygone-control-size, 16px) sans-serif', 'white-space': 'nowrap', 'box-sizing': 'border-box',
            },
            'wbt-btn-x': { 'min-height': 'var(--bygone-control-height, 42px)', padding: '0 8px', 'font-weight': 'bold', color: '#c00', border: '1px solid #888', background: '#ddd', cursor: 'pointer', 'border-radius': '2px', font: 'var(--bygone-control-size, 16px) sans-serif' },
            'wbt-list':  {
                background: '#fff', border: '1px solid #aaa',
                'border-radius': '2px', 'min-height': 'var(--bygone-control-height, 42px)',
                'max-height': '180px', 'overflow-y': 'auto',
            },
            'wbt-item':  {
                'min-height': 'var(--bygone-control-height, 42px)', padding: '7px 9px', 'border-bottom': '1px dotted #ddd',
                display: 'flex', 'align-items': 'center', gap: '8px', cursor: 'grab',
            },
            'wbt-item-name': { flex: '1', overflow: 'hidden', 'text-overflow': 'ellipsis', 'white-space': 'nowrap' },
            'wbt-toggle': { 'min-height': 'var(--bygone-control-height, 42px)', display: 'flex', 'align-items': 'center', gap: '8px', margin: '4px 0', cursor: 'pointer' },
            'wbt-mute':  { color: '#666', 'font-size': 'var(--bygone-control-small, 14px)', 'line-height': '1.4' },
            'wbt-file':  { flex: '1 1 190px', 'max-width': '100%', 'min-height': 'var(--bygone-control-height, 42px)', font: 'var(--bygone-control-size, 16px) sans-serif', color: '#222' },
            'wbt-stats': { 'border-collapse': 'collapse' },
        };

        _el(tag, cls, text) {
            const el = document.createElement(tag);
            if (cls) {
                el.className = cls;
                for (const c of cls.split(/\s+/)) {
                    const sty = UI._STYLE_MAP[c];
                    if (sty) for (const k in sty) {
                        try { el.style.setProperty(k, sty[k], 'important'); } catch {}
                    }
                }
            }
            if (text !== undefined && text !== null) el.textContent = text;
            if (tag === 'h4') {
                try {
                    el.style.setProperty('margin', '0 0 8px', 'important');
                    el.style.setProperty('font', 'bold var(--bygone-control-size, 16px) sans-serif', 'important');
                    el.style.setProperty('color', '#333', 'important');
                    el.style.setProperty('border-bottom', '1px dotted #aaa', 'important');
                    el.style.setProperty('padding-bottom', '3px', 'important');
                } catch {}
            }
            if (tag === 'input' || tag === 'select') {
                queueMicrotask(() => {
                    if (el.type === 'checkbox' || el.type === 'radio' || el.type === 'file') return;
                    try {
                        el.style.setProperty('flex', '1 1 150px', 'important');
                        el.style.setProperty('min-height', 'var(--bygone-control-height, 42px)', 'important');
                        el.style.setProperty('padding', '7px 9px', 'important');
                        el.style.setProperty('border', '1px solid #aaa', 'important');
                        el.style.setProperty('border-radius', '2px', 'important');
                        el.style.setProperty('font', 'var(--bygone-control-size, 16px) sans-serif', 'important');
                        el.style.setProperty('min-width', '0', 'important');
                        el.style.setProperty('box-sizing', 'border-box', 'important');
                        el.style.setProperty('background', '#fff', 'important');
                        el.style.setProperty('color', '#222', 'important');
                    } catch {}
                });
            }
            if (tag === 'button' && (!cls || !/wbt-btn/.test(cls))) {
                try {
                    el.style.setProperty('min-height', 'var(--bygone-control-height, 42px)', 'important');
                    el.style.setProperty('padding', '7px 12px', 'important');
                    el.style.setProperty('border', '1px solid #888', 'important');
                    el.style.setProperty('background', '#ddd', 'important');
                    el.style.setProperty('color', '#222', 'important');
                    el.style.setProperty('border-radius', '2px', 'important');
                    el.style.setProperty('cursor', 'pointer', 'important');
                    el.style.setProperty('font', 'var(--bygone-control-size, 16px) sans-serif', 'important');
                } catch {}
            }
            return el;
        }

        _toggle(label, value, onChange) {
            const lab = this._el('label', 'wbt-toggle');
            const cb = this._el('input');
            cb.type = 'checkbox';
            cb.checked = !!value;
            cb.onchange = () => onChange(cb.checked);
            lab.appendChild(cb);
            lab.appendChild(document.createTextNode(' ' + label));
            return lab;
        }

        _enableDrag(panel, handle) {
            handle.addEventListener('mousedown', (e) => {
                if (e.target.tagName === 'SPAN' || e.target.tagName === 'BUTTON') return;
                const r = panel.getBoundingClientRect();
                this._dragState = { panel, ox: e.clientX - r.left, oy: e.clientY - r.top };
                e.preventDefault();
            });
            if (this._dragDocBound) return;
            this._dragDocBound = true;
            document.addEventListener('mousemove', (e) => {
                const d = this._dragState;
                if (!d) return;
                d.panel.style.left = (e.clientX - d.ox) + 'px';
                d.panel.style.top  = (e.clientY - d.oy) + 'px';
                d.panel.style.right = 'auto';
                d.panel.style.bottom = 'auto';
            });
            document.addEventListener('mouseup', () => { this._dragState = null; });
        }

        _setFeedStatus(text, ttlMs) {
            this._feedStatus = text || '';
            const el = document.getElementById('wbt-feed-status');
            if (el) el.textContent = this._feedStatus;
            if (this._feedStatusTimer) clearTimeout(this._feedStatusTimer);
            if (ttlMs) {
                this._feedStatusTimer = setTimeout(() => {
                    this._feedStatus = '';
                    const cur = document.getElementById('wbt-feed-status');
                    if (cur) cur.textContent = '';
                }, ttlMs);
            }
        }

        _clearFeedCaches() {
            let n = 0;
            try {
                for (const k of GM_listValues()) {
                    if (!k.startsWith('bygone_cache_')) continue;
                    GM_deleteValue(k);
                    n++;
                }
            } catch (_) {}
            try { Interceptor.clearPool(); } catch (_) {}
            return n;
        }

        async _reloadFeed(button, successPrefix) {
            const label = button && button.textContent;
            if (button) {
                button.disabled = true;
                button.textContent = 'Reloading...';
            }
            this._setFeedStatus((successPrefix || '') + 'Reloading feed...');
            try {
                const result = await App.primeInterceptor();
                if (result && result.ok) {
                    try { Interceptor.forceResweep(); } catch (_) {}
                    this._setFeedStatus((successPrefix || '') + 'Loaded ' + result.count + ' era videos.', 5000);
                } else {
                    const msg = result && result.message ? result.message : 'No era videos loaded.';
                    this._setFeedStatus((successPrefix || '') + msg, 8000);
                }
                return result;
            } catch (e) {
                console.warn('[bygone] reload failed:', e);
                this._setFeedStatus('Reload failed: ' + (e && e.message ? e.message : e), 8000);
                return { ok: false, count: 0, error: e };
            } finally {
                if (button) {
                    button.disabled = false;
                    button.textContent = label;
                }
            }
        }

        _applyCustomLogo() {
            const url = Store.getCustomLogo();
            if (!url) return;
            const apply = () => {
                document.querySelectorAll('#logo img, #logo-icon img, .logo-icon img, a#logo img, .v3-logo img, #masthead-logo-link img')
                    .forEach(img => { img.src = url; });
            };
            apply();
            setTimeout(apply, 800);
            setTimeout(apply, 2500);
        }

        _ensureKioskLookStyle() {
            const css = [
                'html[data-bygone-kiosk-dark="1"],html[data-bygone-kiosk-dark="1"] body{background:#0f0f0f!important;color:#e8eaed!important;}',
                'html[data-bygone-kiosk-dark="1"] #page,html[data-bygone-kiosk-dark="1"] #content,html[data-bygone-kiosk-dark="1"] #body-container,html[data-bygone-kiosk-dark="1"] #masthead,html[data-bygone-kiosk-dark="1"] #watch7-container,html[data-bygone-kiosk-dark="1"] #watch7-main-container,html[data-bygone-kiosk-dark="1"] #watch7-sidebar,html[data-bygone-kiosk-dark="1"] #guide,html[data-bygone-kiosk-dark="1"] .yt-card,html[data-bygone-kiosk-dark="1"] .feed-item-container,html[data-bygone-kiosk-dark="1"] .yt-lockup,html[data-bygone-kiosk-dark="1"] .comment,html[data-bygone-kiosk-dark="1"] .post{background:#0f0f0f!important;color:#e8eaed!important;border-color:#303134!important;}',
                'html[data-bygone-kiosk-dark="1"] .metadata,html[data-bygone-kiosk-dark="1"] .yt-lockup-meta,html[data-bygone-kiosk-dark="1"] .yt-lockup-byline{color:#aeb3b8!important;}',
                'html[data-bygone-kiosk-dark="1"] a,html[data-bygone-kiosk-dark="1"] a:visited,html[data-bygone-kiosk-dark="1"] a:hover,html[data-bygone-kiosk-dark="1"] a:active{color:#e8eaed!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) a,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) a:visited,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) a:hover,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) a:active{color:#0f0f0f!important;}',
                'html,body{touch-action:pan-y!important;overscroll-behavior:none!important;overscroll-behavior-x:none!important;overscroll-behavior-y:none!important;}',
                'html[data-bygone-kiosk-zoom="1"] body *{touch-action:pan-y!important;}',
                'html[data-bygone-kiosk-zoom="1"]{--bygone-kiosk-zoom:1.35;--bygone-feed-columns:1;--bygone-feed-gap:6px;--bygone-feed-pad:0px;--bygone-feed-max:100vw;--bygone-watch-pad:0px;--bygone-watch-width:100vw;--bygone-home-top-gap:10px;--bygone-body-size:16px;--bygone-title-size:21px;--bygone-meta-size:15px;--bygone-control-size:16px;--bygone-control-small:14px;--bygone-control-title-size:17px;--bygone-control-height:42px;--bygone-panel-width:430px;--bygone-fab-size:58px;--bygone-fab-font:23px;--bygone-card-thumb:100%;--bygone-side-thumb:min(42vw,160px);width:100%!important;max-width:100vw!important;min-width:0!important;overflow-x:hidden!important;overscroll-behavior:none!important;-webkit-text-size-adjust:100%!important;text-size-adjust:100%!important;}',
                '@media (min-width:600px){html[data-bygone-kiosk-zoom="1"]{--bygone-feed-columns:2;--bygone-feed-gap:8px;--bygone-feed-pad:4px;--bygone-feed-max:100vw;--bygone-watch-width:100vw;}}',
                'html[data-bygone-kiosk-zoom="1"],html[data-bygone-kiosk-zoom="1"] body{width:100%!important;max-width:100vw!important;min-width:0!important;overflow-x:hidden!important;}',
                '@supports (overflow:clip){html[data-bygone-kiosk-zoom="1"],html[data-bygone-kiosk-zoom="1"] body{overflow-x:clip!important;}}',
                'html[data-bygone-kiosk-zoom="1"] body{font-size:var(--bygone-body-size)!important;line-height:1.35!important;transform:none!important;zoom:1!important;margin:0!important;padding-bottom:calc(88px + env(safe-area-inset-bottom,0px))!important;overscroll-behavior:none!important;}',
                'html[data-bygone-kiosk-zoom="1"] #wbt-fab{position:fixed!important;right:calc(14px + env(safe-area-inset-right,0px))!important;bottom:calc(78px + env(safe-area-inset-bottom,0px))!important;width:var(--bygone-fab-size)!important;height:var(--bygone-fab-size)!important;font-size:var(--bygone-fab-font)!important;line-height:var(--bygone-fab-size)!important;transform:none!important;zoom:1!important;}',
                'html[data-bygone-kiosk-zoom="1"] #wbt-panel{position:fixed!important;right:6px!important;bottom:calc(140px + env(safe-area-inset-bottom,0px))!important;width:min(var(--bygone-panel-width),calc(100vw - 12px))!important;max-width:calc(100vw - 12px)!important;max-height:calc(100vh - 158px - env(safe-area-inset-top,0px) - env(safe-area-inset-bottom,0px))!important;font-size:var(--bygone-control-size)!important;line-height:1.35!important;transform:none!important;zoom:1!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-zoom="1"] #wbt-panel,html[data-bygone-kiosk-zoom="1"] #wbt-panel *{font-size:var(--bygone-control-size)!important;line-height:1.35!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-zoom="1"] #wbt-panel .wbt-h{font-size:var(--bygone-control-title-size)!important;}',
                'html[data-bygone-kiosk-zoom="1"] #wbt-panel .wbt-mute,html[data-bygone-kiosk-zoom="1"] #wbt-panel .wbt-pill{font-size:var(--bygone-control-small)!important;}',
                'html[data-bygone-kiosk-zoom="1"] #wbt-panel button,html[data-bygone-kiosk-zoom="1"] #wbt-panel input,html[data-bygone-kiosk-zoom="1"] #wbt-panel select{font-size:var(--bygone-control-size)!important;min-height:var(--bygone-control-height)!important;}',
                'html[data-bygone-kiosk-zoom="1"] #masthead-positioner,html[data-bygone-kiosk-zoom="1"] #yt-masthead-container,html[data-bygone-kiosk-zoom="1"] #masthead,html[data-bygone-kiosk-zoom="1"] #masthead-container{left:0!important;right:auto!important;width:100vw!important;max-width:100vw!important;min-width:0!important;margin-left:0!important;margin-right:0!important;box-sizing:border-box!important;overflow:hidden!important;transform:none!important;}',
                'html[data-bygone-kiosk-zoom="1"] #yt-masthead-container,html[data-bygone-kiosk-zoom="1"] #masthead-container,html[data-bygone-kiosk-zoom="1"] #masthead{display:flex!important;align-items:center!important;gap:6px!important;padding:4px 6px!important;}',
                'html[data-bygone-kiosk-zoom="1"] #masthead-search,html[data-bygone-kiosk-zoom="1"] #masthead-search-form,html[data-bygone-kiosk-zoom="1"] #search-form:not(#bygone-kiosk-search-bar),html[data-bygone-kiosk-zoom="1"] form[action="/results"]:not(#bygone-kiosk-search-bar),html[data-bygone-kiosk-zoom="1"] form[action$="/results"]:not(#bygone-kiosk-search-bar){display:none!important;}',
                '#bygone-kiosk-search-bar{display:flex!important;align-items:center!important;flex:1 1 auto!important;min-width:0!important;height:42px!important;margin:0!important;padding:0!important;box-sizing:border-box!important;}',
                '#bygone-kiosk-search-bar input{display:block!important;flex:1 1 auto!important;min-width:0!important;width:100%!important;height:40px!important;margin:0!important;padding:0 10px!important;border:1px solid #858585!important;border-right:0!important;border-radius:2px 0 0 2px!important;background:#fff!important;color:#111!important;font:18px/40px Arial,sans-serif!important;box-sizing:border-box!important;}',
                '#bygone-kiosk-search-bar button{display:flex!important;align-items:center!important;justify-content:center!important;flex:0 0 46px!important;width:46px!important;height:40px!important;margin:0!important;padding:0!important;border:1px solid #858585!important;border-radius:0 2px 2px 0!important;background:#d8d8d8!important;color:#222!important;font:bold 15px/40px Arial,sans-serif!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-zoom="1"] #masthead-upload-button-group,html[data-bygone-kiosk-zoom="1"] #masthead-user,html[data-bygone-kiosk-zoom="1"] #yt-masthead-user,html[data-bygone-kiosk-zoom="1"] #masthead-signin,html[data-bygone-kiosk-zoom="1"] #yt-masthead-signin{display:none!important;}',
                'html[data-bygone-kiosk-zoom="1"] #guide,html[data-bygone-kiosk-zoom="1"] #guide-container{display:none!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #appbar-content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .appbar-content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #appbar-content-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .appbar-content-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #browse-items-primary,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .branded-page-v2-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .branded-page-v2-col-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .branded-page-v2-primary-col,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .branded-page-v2-secondary-col,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-shelf-grid{width:100%!important;max-width:100vw!important;min-width:0!important;margin-left:0!important;margin-right:0!important;padding-left:0!important;left:0!important;right:auto!important;transform:none!important;float:none!important;box-sizing:border-box!important;}',
                '#bygone-kiosk-bottom-nav{position:fixed!important;left:0!important;right:0!important;top:auto!important;bottom:0!important;width:100vw!important;max-width:100vw!important;min-width:0!important;height:calc(54px + env(safe-area-inset-bottom,0px))!important;max-height:calc(54px + env(safe-area-inset-bottom,0px))!important;padding:0 0 env(safe-area-inset-bottom,0px)!important;z-index:2147483645!important;display:flex!important;background:#b8b8b8!important;background:linear-gradient(#dedede,#b8b8b8)!important;border-top:1px solid #777!important;box-shadow:0 -1px 2px rgba(0,0,0,.35)!important;transform:none!important;zoom:1!important;box-sizing:border-box!important;overflow:hidden!important;pointer-events:none!important;}',
                '#bygone-kiosk-bottom-nav button{flex:1 1 20%!important;width:auto!important;height:54px!important;max-height:54px!important;border:0!important;border-left:1px solid #8f8f8f!important;border-right:1px solid #d8d8d8!important;background:#c8c8c8!important;background:linear-gradient(#eeeeee,#bebebe)!important;color:#222!important;text-shadow:0 1px 0 rgba(255,255,255,.65)!important;font:bold 12px/1.05 Arial,sans-serif!important;min-width:0!important;max-width:none!important;margin:0!important;padding:3px 1px 2px!important;display:flex!important;align-items:center!important;justify-content:center!important;box-sizing:border-box!important;overflow:hidden!important;white-space:normal!important;text-align:center!important;pointer-events:auto!important;}',
                '#bygone-kiosk-bottom-nav button:first-child{border-left:0!important;}',
                '#bygone-kiosk-bottom-nav .bygone-nav-icon{display:none!important;}',
                '#bygone-kiosk-bottom-nav .bygone-nav-label{display:block!important;width:100%!important;max-width:100%!important;min-width:0!important;font:bold 12px/1.05 Arial,sans-serif!important;white-space:normal!important;overflow:hidden!important;text-overflow:clip!important;text-align:center!important;pointer-events:none!important;}',
                'html[data-bygone-kiosk-home-guard="1"] [data-bygone-ok="1"],html[data-bygone-kiosk-home-guard="1"] [data-bygone-swept],html[data-bygone-kiosk-home-guard="1"] [data-bygone-keep="1"],html[data-bygone-kiosk-home-guard="1"] [data-bygone-ok="1"] .yt-lockup,html[data-bygone-kiosk-home-guard="1"] [data-bygone-swept] .yt-lockup,html[data-bygone-kiosk-home-guard="1"] [data-bygone-ok="1"] .context-data-item.yt-lockup,html[data-bygone-kiosk-home-guard="1"] [data-bygone-swept] .context-data-item.yt-lockup,html[data-bygone-kiosk-home-guard="1"] [data-bygone-ok="1"] .lohp-media-object-content,html[data-bygone-kiosk-home-guard="1"] [data-bygone-swept] .lohp-media-object-content,html[data-bygone-kiosk-home-guard="1"] [data-bygone-ok="1"] .lohp-video-link,html[data-bygone-kiosk-home-guard="1"] [data-bygone-swept] .lohp-video-link{visibility:visible!important;}',
                'html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] ytd-rich-item-renderer:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] ytd-grid-video-renderer:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] ytd-video-renderer:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] ytd-compact-video-renderer:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] yt-lockup-view-model:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] .yt-lockup-view-model:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] .lohp-large-shelf-container:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])),html[data-bygone-kiosk-zoom="1"][data-bygone-kiosk-home-settled="1"] .lohp-medium-shelf:not([data-bygone-ok="1"]):not([data-bygone-swept]):not(:has([data-bygone-ok="1"],[data-bygone-swept])){display:none!important;}',
                '#bygone-probe-btn,#bygone-err-btn,#bygone-probe-box{display:none!important;visibility:hidden!important;pointer-events:none!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #content{padding-top:var(--bygone-home-top-gap)!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #page,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #body-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-card,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .feed-item-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .feed-item-main,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .feed-item-main-content{width:100%!important;max-width:var(--bygone-feed-max)!important;min-width:0!important;max-height:none!important;height:auto!important;box-sizing:border-box!important;margin-left:auto!important;margin-right:auto!important;padding-left:var(--bygone-feed-pad)!important;padding-right:var(--bygone-feed-pad)!important;overflow:visible!important;overflow-x:clip!important;touch-action:pan-y!important;-webkit-overflow-scrolling:auto!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #page,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #body-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #content-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #main,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) #feed,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .feed-list{width:100vw!important;max-width:100vw!important;min-width:0!important;margin-left:0!important;margin-right:0!important;padding-left:var(--bygone-feed-pad)!important;padding-right:var(--bygone-feed-pad)!important;left:0!important;right:auto!important;transform:none!important;box-sizing:border-box!important;overflow-x:hidden!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .shelf-wrapper,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .multirow-shelf,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-expander,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-shelfslider-body{display:block!important;width:100%!important;max-width:none!important;max-height:none!important;height:auto!important;overflow:visible!important;overflow-y:visible!important;touch-action:pan-y!important;-webkit-overflow-scrolling:auto!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .shelf-content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-shelfslider-list,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-shelf-grid,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .channels-browse-content-grid,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-medium-shelves-container{display:grid!important;grid-template-columns:repeat(var(--bygone-feed-columns),minmax(0,1fr))!important;gap:var(--bygone-feed-gap)!important;width:100%!important;max-width:none!important;max-height:none!important;height:auto!important;overflow:visible!important;overflow-y:visible!important;padding:0!important;margin:0!important;touch-action:pan-y!important;-webkit-overflow-scrolling:auto!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-shelfslider-prev,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-shelfslider-next,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-slider-prev,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-slider-next{display:none!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-uix-shelfslider-item,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .context-data-item.yt-lockup,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-medium-shelf,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-large-shelf-container{display:block!important;width:100%!important;max-width:none!important;max-height:none!important;height:auto!important;min-width:0!important;margin:0!important;padding:6px 0 14px!important;box-sizing:border-box!important;border-bottom:1px solid rgba(128,128,128,.28)!important;float:none!important;clear:both!important;overflow:visible!important;overflow-y:visible!important;touch-action:pan-y!important;-webkit-overflow-scrolling:auto!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) li.yt-uix-shelfslider-item > .yt-lockup{padding:0!important;border:0!important;min-height:0!important;background:transparent!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) a[href*="/watch"],html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup a,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-video-link{touch-action:pan-y!important;-webkit-user-drag:none!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-title,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-title a,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-video-link{font-size:var(--bygone-title-size)!important;line-height:1.18!important;font-weight:700!important;white-space:normal!important;overflow-wrap:anywhere!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-title .yt-ui-ellipsis,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-title .yt-ui-ellipsis-wrapper,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-video-link .yt-ui-ellipsis,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-video-link .yt-ui-ellipsis-wrapper{max-height:none!important;white-space:normal!important;overflow:visible!important;text-overflow:clip!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-meta,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-meta *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-byline,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-byline *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-video-metadata,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-video-metadata *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .metadata,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .metadata *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .bygone-meta,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .bygone-meta *{font-size:var(--bygone-meta-size)!important;line-height:1.35!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .ux-thumb-wrap,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .video-thumb,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-thumbnail,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-media-object{display:block!important;width:100%!important;max-width:none!important;min-width:0!important;aspect-ratio:16/9!important;height:auto!important;margin:0 0 8px!important;float:none!important;overflow:hidden!important;background:transparent!important;touch-action:pan-y!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb-clip,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb-clip-inner,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb-square,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb-default,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb-simple,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb-fluid{display:block!important;width:100%!important;max-width:none!important;height:100%!important;max-height:none!important;min-height:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-media-object-content{display:block!important;min-width:0!important;width:100%!important;max-width:none!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-thumb img,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .ux-thumb-wrap img,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .video-thumb img,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .yt-lockup-thumbnail img,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) .lohp-media-object img{display:block!important;width:100%!important;max-width:none!important;height:100%!important;max-height:none!important;object-fit:cover!important;object-position:center center!important;background:transparent!important;margin:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;transform:none!important;vertical-align:top!important;pointer-events:none!important;-webkit-user-drag:none!important;touch-action:pan-y!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-watch="1"]) img.bygone-thumb{display:block!important;width:100%!important;max-width:none!important;aspect-ratio:16/9!important;height:auto!important;max-height:none!important;object-fit:cover!important;object-position:center center!important;background:transparent!important;margin:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;transform:none!important;vertical-align:top!important;pointer-events:none!important;-webkit-user-drag:none!important;touch-action:pan-y!important;}',
                'html[data-bygone-kiosk-watch="1"],html[data-bygone-kiosk-watch="1"] body{width:100%!important;max-width:100vw!important;min-width:0!important;overflow-x:hidden!important;overscroll-behavior:none!important;}',
                'html[data-bygone-kiosk-watch="1"] #page,html[data-bygone-kiosk-watch="1"] #content,html[data-bygone-kiosk-watch="1"] #body-container,html[data-bygone-kiosk-watch="1"] #watch7-container,html[data-bygone-kiosk-watch="1"] #watch7-main-container,html[data-bygone-kiosk-watch="1"] #watch7-content,html[data-bygone-kiosk-watch="1"] .watch-main-col{width:var(--bygone-watch-width,100vw)!important;max-width:100vw!important;min-width:0!important;margin-left:0!important;margin-right:0!important;padding-left:0!important;padding-right:0!important;left:0!important;right:auto!important;transform:none!important;box-sizing:border-box!important;overflow-x:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #player,html[data-bygone-kiosk-watch="1"] #player-api,html[data-bygone-kiosk-watch="1"] #watch7-player,html[data-bygone-kiosk-watch="1"] #watch-player,html[data-bygone-kiosk-watch="1"] .player-width,html[data-bygone-kiosk-watch="1"] .html5-video-player{width:var(--bygone-watch-width,100vw)!important;max-width:100vw!important;min-width:0!important;margin:0 0 10px!important;left:0!important;right:auto!important;transform:none!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar,html[data-bygone-kiosk-watch="1"] .watch-sidebar,html[data-bygone-kiosk-watch="1"] #secondary,html[data-bygone-kiosk-watch="1"] #secondary-inner{width:var(--bygone-watch-width,100vw)!important;max-width:100vw!important;margin:12px 0 0!important;padding:0 4px calc(84px + env(safe-area-inset-bottom,0px))!important;left:0!important;right:auto!important;transform:none!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] .html5-video-container,html[data-bygone-kiosk-watch="1"] .html5-video-player video,html[data-bygone-kiosk-watch="1"] video.html5-main-video{left:0!important;top:0!important;width:100%!important;height:100%!important;max-width:100%!important;max-height:100%!important;object-fit:contain!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar-contents,html[data-bygone-kiosk-watch="1"] #watch7-sidebar-modules,html[data-bygone-kiosk-watch="1"] .watch-sidebar-body,html[data-bygone-kiosk-watch="1"] #related{display:block!important;width:100%!important;max-width:100%!important;margin:0!important;padding:0!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar ol,html[data-bygone-kiosk-watch="1"] #watch7-sidebar ul,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list,html[data-bygone-kiosk-watch="1"] .watch-sidebar-body ol,html[data-bygone-kiosk-watch="1"] .watch-sidebar-body ul{display:block!important;width:100%!important;max-width:100%!important;margin:0!important;padding:0!important;list-style:none!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar li,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list-item,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .related-list-item,html[data-bygone-kiosk-watch="1"] #watch7-sidebar ytd-compact-video-renderer,html[data-bygone-kiosk-watch="1"] .watch-sidebar .video-list-item{display:block!important;width:100%!important;max-width:100%!important;min-width:0!important;min-height:0!important;margin:0!important;padding:10px 0!important;box-sizing:border-box!important;border-bottom:1px solid rgba(128,128,128,.32)!important;float:none!important;clear:both!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar .content-link,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .context-data-item.yt-lockup,html[data-bygone-kiosk-watch="1"] .watch-sidebar .content-link,html[data-bygone-kiosk-watch="1"] .watch-sidebar .yt-lockup{display:grid!important;grid-template-columns:minmax(112px,42%) minmax(0,1fr)!important;column-gap:10px!important;align-items:start!important;width:100%!important;max-width:100%!important;margin:0!important;padding:0!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list-item .video-thumb,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list-item .yt-lockup-thumbnail,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list-item .yt-thumb,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-thumb,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-thumbnail,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-thumb,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .ux-thumb-wrap,html[data-bygone-kiosk-watch="1"] .watch-sidebar .video-thumb,html[data-bygone-kiosk-watch="1"] .watch-sidebar .yt-lockup-thumbnail{grid-column:1!important;display:block!important;width:100%!important;max-width:none!important;min-width:0!important;margin:0!important;float:none!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar .content-wrapper,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-content,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .related-list-item-content,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .content,html[data-bygone-kiosk-watch="1"] .watch-sidebar .content-wrapper,html[data-bygone-kiosk-watch="1"] .watch-sidebar .yt-lockup-content{grid-column:2!important;display:block!important;min-width:0!important;width:auto!important;max-width:100%!important;margin:0!important;padding:0!important;box-sizing:border-box!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar .title,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-title,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-title a,html[data-bygone-kiosk-watch="1"] .watch-sidebar .title{font-size:var(--bygone-meta-size)!important;line-height:1.25!important;white-space:normal!important;overflow-wrap:anywhere!important;word-break:normal!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch7-sidebar .metadata,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .metadata *,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-meta,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-meta *,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-byline,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-byline *,html[data-bygone-kiosk-watch="1"] .watch-sidebar .metadata,html[data-bygone-kiosk-watch="1"] .watch-sidebar .metadata *{font-size:var(--bygone-control-small)!important;line-height:1.3!important;white-space:normal!important;overflow-wrap:anywhere!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch-discussion,html[data-bygone-kiosk-watch="1"] #watch7-discussion,html[data-bygone-kiosk-watch="1"] #comment-section-renderer,html[data-bygone-kiosk-watch="1"] .comment-section,html[data-bygone-kiosk-watch="1"] .comments{display:block!important;width:100%!important;max-width:100%!important;min-width:0!important;margin:0!important;padding:0 8px!important;box-sizing:border-box!important;overflow:hidden!important;overflow-wrap:anywhere!important;}',
                'html[data-bygone-kiosk-watch="1"] div.comment[data-id],html[data-bygone-kiosk-watch="1"] .comment-thread-renderer,html[data-bygone-kiosk-watch="1"] .comment-item,html[data-bygone-kiosk-watch="1"] #watch-discussion .post{display:block!important;width:100%!important;max-width:100%!important;min-width:0!important;margin:0!important;box-sizing:border-box!important;float:none!important;overflow:hidden!important;overflow-wrap:anywhere!important;font-size:var(--bygone-body-size)!important;line-height:1.4!important;}',
                'html[data-bygone-kiosk-watch="1"] div.comment[data-id] .metadata,html[data-bygone-kiosk-watch="1"] div.comment[data-id] .comment-header,html[data-bygone-kiosk-watch="1"] div.comment[data-id] .comment-footer,html[data-bygone-kiosk-watch="1"] div.comment[data-id] .detail_link{font-size:var(--bygone-meta-size)!important;}',
                'html[data-bygone-kiosk-watch="1"] #watch-discussion .load-more-button,html[data-bygone-kiosk-watch="1"] #watch-discussion .yt-uix-load-more{display:block!important;width:100%!important;min-height:44px!important;font-size:var(--bygone-control-size)!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-watch="1"] .yt-thumb,html[data-bygone-kiosk-watch="1"] .ux-thumb-wrap,html[data-bygone-kiosk-watch="1"] .video-thumb,html[data-bygone-kiosk-watch="1"] .yt-lockup-thumbnail{display:block!important;width:100%!important;max-width:100%!important;min-width:0!important;aspect-ratio:16/9!important;height:auto!important;margin:0!important;float:none!important;overflow:hidden!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-watch="1"] .yt-thumb-clip,html[data-bygone-kiosk-watch="1"] .yt-thumb-clip-inner,html[data-bygone-kiosk-watch="1"] .yt-thumb-square,html[data-bygone-kiosk-watch="1"] .yt-thumb-default,html[data-bygone-kiosk-watch="1"] .yt-thumb-simple,html[data-bygone-kiosk-watch="1"] .yt-thumb-fluid{display:block!important;width:100%!important;max-width:none!important;height:100%!important;max-height:none!important;min-height:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;overflow:hidden!important;}',
                'html[data-bygone-kiosk-watch="1"] .yt-thumb img,html[data-bygone-kiosk-watch="1"] .ux-thumb-wrap img,html[data-bygone-kiosk-watch="1"] .video-thumb img,html[data-bygone-kiosk-watch="1"] .yt-lockup-thumbnail img{display:block!important;width:100%!important;max-width:none!important;height:100%!important;max-height:none!important;object-fit:cover!important;object-position:center center!important;margin:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;transform:none!important;vertical-align:top!important;}',
                'html[data-bygone-kiosk-watch="1"] img.bygone-thumb{display:block!important;width:100%!important;max-width:none!important;aspect-ratio:16/9!important;height:auto!important;max-height:none!important;object-fit:cover!important;object-position:center center!important;margin:0!important;position:static!important;transform:none!important;vertical-align:top!important;}',
                'html[data-bygone-kiosk-zoom="1"] #gb,html[data-bygone-kiosk-zoom="1"] #gbw,html[data-bygone-kiosk-zoom="1"] #gbz,html[data-bygone-kiosk-zoom="1"] #gbx3,html[data-bygone-kiosk-zoom="1"] #footer-container,html[data-bygone-kiosk-zoom="1"] #footer,html[data-bygone-kiosk-zoom="1"] #guide-main,html[data-bygone-kiosk-zoom="1"] .guide-module,html[data-bygone-kiosk-zoom="1"] #appbar-guide-menu{display:none!important;}',
                'html[data-bygone-kiosk-zoom="1"] body #yt-masthead-container,html[data-bygone-kiosk-zoom="1"] body #masthead-positioner,html[data-bygone-kiosk-zoom="1"] body #masthead,html[data-bygone-kiosk-zoom="1"] body #page,html[data-bygone-kiosk-zoom="1"] body #content,html[data-bygone-kiosk-zoom="1"] body #body-container,html[data-bygone-kiosk-zoom="1"] body #appbar-content,html[data-bygone-kiosk-zoom="1"] body .yt-grid-box{width:100vw!important;max-width:100vw!important;min-width:0!important;margin-left:0!important;margin-right:0!important;left:0!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-watch="1"] body #watch7-main,html[data-bygone-kiosk-watch="1"] body #watch7-main-container,html[data-bygone-kiosk-watch="1"] body #watch7-video,html[data-bygone-kiosk-watch="1"] body #watch7-content,html[data-bygone-kiosk-watch="1"] body #player-api,html[data-bygone-kiosk-watch="1"] body .player-width{width:var(--bygone-watch-width,100vw)!important;max-width:100vw!important;min-width:0!important;margin:0!important;padding-left:0!important;padding-right:0!important;float:none!important;left:0!important;box-sizing:border-box!important;}',
                'html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="next"] #watch-discussion,html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="next"] #watch7-discussion,html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="next"] #comment-section-renderer,html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="next"] .comment-section,html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="next"] .comments{display:none!important;}',
                'html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="comments"] #watch7-sidebar,html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="comments"] .watch-sidebar,html[data-bygone-kiosk-watch="1"][data-bygone-watch-tab="comments"] #secondary{display:none!important;}',
                '@media (min-width:600px){html[data-bygone-kiosk-watch="1"] #watch7-sidebar ol,html[data-bygone-kiosk-watch="1"] #watch7-sidebar ul,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list,html[data-bygone-kiosk-watch="1"] .watch-sidebar-body ol,html[data-bygone-kiosk-watch="1"] .watch-sidebar-body ul{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:12px!important;}html[data-bygone-kiosk-watch="1"] #watch7-sidebar li,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-list-item,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .related-list-item,html[data-bygone-kiosk-watch="1"] .watch-sidebar .video-list-item{border-bottom:0!important;padding:0 0 10px!important;}html[data-bygone-kiosk-watch="1"] #watch7-sidebar .content-link,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .context-data-item.yt-lockup,html[data-bygone-kiosk-watch="1"] .watch-sidebar .content-link,html[data-bygone-kiosk-watch="1"] .watch-sidebar .yt-lockup{display:block!important;}html[data-bygone-kiosk-watch="1"] #watch7-sidebar .video-thumb,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-thumb,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-thumbnail,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .ux-thumb-wrap,html[data-bygone-kiosk-watch="1"] .watch-sidebar .video-thumb,html[data-bygone-kiosk-watch="1"] .watch-sidebar .yt-lockup-thumbnail{width:100%!important;max-width:none!important;}html[data-bygone-kiosk-watch="1"] #watch7-sidebar .content-wrapper,html[data-bygone-kiosk-watch="1"] #watch7-sidebar .yt-lockup-content,html[data-bygone-kiosk-watch="1"] .watch-sidebar .yt-lockup-content{display:block!important;width:100%!important;margin-top:6px!important;}}',
                'html[data-bygone-kiosk-zoom="1"] #masthead-positioner,html[data-bygone-kiosk-zoom="1"] #yt-masthead-container,html[data-bygone-kiosk-zoom="1"] #masthead,html[data-bygone-kiosk-zoom="1"] #masthead-container{background:#1d1d1d!important;border-bottom:1px solid #000!important;box-shadow:0 1px 2px rgba(0,0,0,.4)!important;}',
                'html body #bygone-2014-menu{flex:0 0 44px!important;width:44px!important;height:44px!important;margin:0!important;padding:0!important;border:0!important;background:transparent!important;color:#fff!important;font-size:22px!important;line-height:44px!important;text-align:center!important;}',
                '#bygone-kiosk-search-bar input{border:1px solid #555!important;border-right:1px solid #555!important;border-radius:3px!important;background:#fff!important;color:#222!important;}',
                '#bygone-kiosk-search-bar button{margin-left:6px!important;border:1px solid #161616!important;border-radius:3px!important;background:#3c3c3c!important;background:linear-gradient(#454545,#323232)!important;color:#e8e8e8!important;text-shadow:0 -1px 0 rgba(0,0,0,.5)!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]),html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) body{background:#e9e9e9!important;color:#1a1a1a!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) #page,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) #content,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) #body-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .feed-item-container{background:#e9e9e9!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .yt-uix-shelfslider-item,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .yt-lockup,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .context-data-item.yt-lockup,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .lohp-medium-shelf,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .lohp-large-shelf-container,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) .video-list-item{background:#fff!important;border:1px solid #d6d6d6!important;border-radius:2px!important;box-shadow:0 1px 1px rgba(0,0,0,.08)!important;margin:0 0 8px!important;padding:8px 8px 10px!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]):not([data-bygone-kiosk-watch="1"]) li.yt-uix-shelfslider-item > .yt-lockup{border:0!important;box-shadow:none!important;margin:0!important;padding:0!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .yt-lockup-title,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .yt-lockup-title a,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .lohp-video-link,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) #video-title{color:#1a1a1a!important;}',
                'html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .yt-lockup-meta,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .yt-lockup-meta *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .yt-lockup-byline,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .yt-lockup-byline *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .lohp-video-metadata,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .lohp-video-metadata *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .metadata,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .metadata *,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .bygone-meta,html[data-bygone-kiosk-zoom="1"]:not([data-bygone-kiosk-dark="1"]) .bygone-meta *{color:#757575!important;}',
                'html body #bygone-kiosk-bottom-nav{background:#262626!important;background:linear-gradient(#303030,#1e1e1e)!important;border-top:1px solid #000!important;box-shadow:0 -1px 2px rgba(0,0,0,.5)!important;}',
                'html body #bygone-kiosk-bottom-nav button{background:transparent!important;border-left:1px solid #151515!important;border-right:1px solid #3a3a3a!important;color:#cfcfcf!important;text-shadow:0 -1px 0 rgba(0,0,0,.6)!important;}',
                'html body #bygone-kiosk-bottom-nav button:first-child{border-left:0!important;}',
                'html body #bygone-kiosk-bottom-nav button:last-child{border-right:0!important;}',
                'html body #bygone-kiosk-bottom-nav button:active{background:#121212!important;}',
                'html body #bygone-kiosk-bottom-nav .bygone-nav-label{color:inherit!important;text-shadow:inherit!important;}',
                '#bygone-2014-scrim{position:fixed!important;top:0!important;left:0!important;right:0!important;bottom:0!important;background:rgba(0,0,0,.55)!important;z-index:2147483645!important;opacity:0!important;pointer-events:none!important;transition:opacity .2s!important;}',
                '#bygone-2014-scrim[data-open="1"]{opacity:1!important;pointer-events:auto!important;}',
                '#bygone-2014-drawer{position:fixed!important;top:0!important;bottom:0!important;left:0!important;width:min(80vw,300px)!important;background:#2c2c2c!important;z-index:2147483646!important;transform:translateX(-103%)!important;transition:transform .22s ease!important;overflow-y:auto!important;overflow-x:hidden!important;box-shadow:2px 0 8px rgba(0,0,0,.5)!important;font-family:"Helvetica Neue",Roboto,Helvetica,Arial,sans-serif!important;padding:0 0 env(safe-area-inset-bottom,0px)!important;box-sizing:border-box!important;touch-action:pan-y!important;}',
                '#bygone-2014-drawer[data-open="1"]{transform:translateX(0)!important;}',
                '#bygone-2014-drawer .b14-sec{background:linear-gradient(#414141,#373737)!important;color:#a6a6a6!important;font:bold 13px/1.1 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif!important;padding:7px 12px!important;text-shadow:0 1px 0 rgba(0,0,0,.7)!important;border-top:1px solid #4d4d4d!important;border-bottom:1px solid #1f1f1f!important;}',
                '#bygone-2014-drawer .b14-row{display:flex!important;align-items:center!important;gap:14px!important;padding:12px 14px!important;color:#d8d8d8!important;font:bold 15px/1.2 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif!important;border-bottom:1px solid #242424!important;cursor:pointer!important;}',
                '#bygone-2014-drawer .b14-row:active{background:#1b1b1b!important;}',
                '#bygone-2014-drawer .b14-active{background:#1b1b1b!important;color:#fff!important;box-shadow:inset 5px 0 0 #cc181e!important;}',
                '#bygone-2014-drawer .b14-ic{flex:0 0 30px!important;width:30px!important;height:30px!important;line-height:30px!important;text-align:center!important;font-size:19px!important;color:#bdbdbd!important;overflow:hidden!important;}',
                '#bygone-2014-drawer .b14-tile{background:#4a4a4a!important;color:#fff!important;font:bold 16px/30px "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif!important;border:1px solid #1c1c1c!important;box-sizing:border-box!important;}',
                '#bygone-2014-drawer .b14-label{flex:1 1 auto!important;min-width:0!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;}',
                '#bygone-2014-suggest{position:fixed!important;left:0!important;right:0!important;background:#fff!important;z-index:2147483644!important;display:none!important;box-shadow:0 3px 8px rgba(0,0,0,.35)!important;max-height:60vh!important;overflow-y:auto!important;border-bottom:1px solid #c9c9c9!important;}',
                '#bygone-2014-suggest[data-open="1"]{display:block!important;}',
                '#bygone-2014-suggest .b14-sg{display:flex!important;align-items:center!important;min-height:46px!important;padding:0 0 0 14px!important;border-bottom:1px solid #e3e3e3!important;background:#fff!important;}',
                '#bygone-2014-suggest .b14-sg:active{background:#f0f0f0!important;}',
                '#bygone-2014-suggest .b14-sg-q{flex:1 1 auto!important;min-width:0!important;color:#333!important;font:16px/1.3 "Helvetica Neue",Roboto,Helvetica,Arial,sans-serif!important;text-align:left!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;}',
                '#bygone-2014-suggest .b14-sg-fill{flex:0 0 48px!important;width:48px!important;height:46px!important;border:0!important;margin:0!important;padding:0!important;background:transparent!important;color:#9b9b9b!important;font-size:20px!important;line-height:46px!important;text-align:center!important;}',
            ].join('\n');
            try {
                if (typeof CSSStyleSheet !== 'undefined' && document.adoptedStyleSheets !== undefined) {
                    if (!this._kioskSheet) {
                        this._kioskSheet = new CSSStyleSheet();
                        this._kioskSheetCss = null;
                    }
                    if (this._kioskSheetCss !== css) {
                        this._kioskSheet.replaceSync(css);
                        this._kioskSheetCss = css;
                    }
                    if (document.adoptedStyleSheets.indexOf(this._kioskSheet) === -1) {
                        document.adoptedStyleSheets = document.adoptedStyleSheets.concat([this._kioskSheet]);
                    }
                    return;
                }
            } catch (_) {}
            const host = document.head || document.documentElement;
            if (!host) return;
            let style = document.getElementById('bygone-userscript-kiosk-style');
            if (style) {
                if (style.parentNode && style !== style.parentNode.lastElementChild) {
                    try { style.parentNode.appendChild(style); } catch (_) {}
                }
                if (style.textContent !== css) style.textContent = css;
                return;
            }
            style = document.createElement('style');
            style.id = 'bygone-userscript-kiosk-style';
            style.textContent = css;
            host.appendChild(style);
        }

        _clampKioskViewportSlack() {
            try {
                const root = document.documentElement;
                const body = document.body;
                const scroller = document.scrollingElement || root;
                if (root) root.scrollLeft = 0;
                if (body) body.scrollLeft = 0;
                if (scroller) scroller.scrollLeft = 0;
            } catch {}
        }

        _ensureKioskViewportLock() {
            try {
                const head = document.head || document.querySelector('head');
                if (!head) return;
                let meta = document.querySelector('meta[name="viewport"]');
                if (!meta) {
                    meta = document.createElement('meta');
                    meta.setAttribute('name', 'viewport');
                    head.appendChild(meta);
                }
                const want = 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover';
                if (meta.getAttribute('content') !== want) meta.setAttribute('content', want);
            } catch {}
        }

        _ensureKioskSearchBar() {
            try {
                const host = document.querySelector('#masthead, #yt-masthead-container, #masthead-container') || document.body;
                if (!host) return;
                let form = document.getElementById('bygone-kiosk-search-bar');
                if (!form) {
                    form = document.createElement('form');
                    form.id = 'bygone-kiosk-search-bar';
                    form.action = 'https://www.youtube.com/results';
                    form.method = 'GET';
                    form.setAttribute('role', 'search');
                    const input = document.createElement('input');
                    input.type = 'search';
                    input.name = 'search_query';
                    input.autocomplete = 'off';
                    input.placeholder = 'Search';
                    input.setAttribute('aria-label', 'Search');
                    const button = document.createElement('button');
                    button.type = 'submit';
                    button.setAttribute('aria-label', 'Search');
                    button.textContent = 'Go';
                    form.appendChild(input);
                    form.appendChild(button);
                    form.addEventListener('submit', (event) => {
                        event.preventDefault();
                        event.stopPropagation();
                        const q = (input.value || '').trim();
                        if (!q) {
                            try { input.focus(); } catch {}
                            return;
                        }
                        location.href = 'https://www.youtube.com/results?search_query=' + encodeURIComponent(q);
                    }, false);
                }
                form.hidden = false;
                form.removeAttribute('aria-hidden');
                if (form.parentNode !== host) host.appendChild(form);
            } catch {}
        }

        _restyleKioskBottomNav() {
            try {
                const nav = document.getElementById('bygone-kiosk-bottom-nav');
                if (!nav) return;
                nav.style.setProperty('display', 'flex', 'important');
                nav.style.setProperty('position', 'fixed', 'important');
                nav.style.setProperty('left', '0', 'important');
                nav.style.setProperty('right', '0', 'important');
                nav.style.setProperty('top', 'auto', 'important');
                nav.style.setProperty('bottom', '0', 'important');
                nav.style.setProperty('width', '100vw', 'important');
                nav.style.setProperty('max-width', '100vw', 'important');
                nav.style.setProperty('height', 'calc(54px + env(safe-area-inset-bottom,0px))', 'important');
                nav.style.setProperty('max-height', 'calc(54px + env(safe-area-inset-bottom,0px))', 'important');
                nav.style.setProperty('overflow', 'hidden', 'important');
                nav.style.setProperty('z-index', '2147483645', 'important');
            } catch {}
        }

        _updateKioskHomeSettled() {
            try {
                const root = document.documentElement;
                if (!root) return;
                const key = location.pathname + location.search;
                if (key !== this._kioskNavKey) {
                    this._kioskNavKey = key;
                    this._kioskNavAt = Date.now();
                }
                const isHome = location.pathname === '/' || location.pathname === '' ||
                    location.pathname === '/feed/recommended';
                if (isHome && Date.now() - (this._kioskNavAt || 0) > 5000) {
                    root.setAttribute('data-bygone-kiosk-home-settled', '1');
                } else {
                    root.removeAttribute('data-bygone-kiosk-home-settled');
                }
            } catch {}
        }

        _ensureWatchTabs() {
            try {
                const root = document.documentElement;
                if (!root.getAttribute('data-bygone-watch-tab')) {
                    root.setAttribute('data-bygone-watch-tab', 'next');
                }
                const discussion = document.querySelector('#watch-discussion, #watch7-discussion, #comment-section-renderer, .comment-section');
                const sidebar = document.querySelector('#watch7-sidebar, .watch-sidebar, #secondary');
                let anchor = sidebar || discussion;
                if (sidebar && discussion) {
                    anchor = (discussion.compareDocumentPosition(sidebar) & Node.DOCUMENT_POSITION_PRECEDING)
                        ? sidebar : discussion;
                }
                if (!anchor || !anchor.parentNode) return;
                let tabs = document.getElementById('bygone-watch-tabs');
                if (!tabs) {
                    tabs = this._el('div', 'b14-wtabs');
                    tabs.id = 'bygone-watch-tabs';
                    for (const [key, label] of [['next', 'Up next'], ['comments', 'Comments']]) {
                        const b = this._el('button', 'b14-wtab', label);
                        b.type = 'button';
                        b.setAttribute('data-tab', key);
                        b.addEventListener('click', (e) => {
                            e.preventDefault();
                            e.stopPropagation();
                            document.documentElement.setAttribute('data-bygone-watch-tab', key);
                            this._paintWatchTabs();
                        }, true);
                        tabs.appendChild(b);
                    }
                }
                if (tabs.parentNode !== anchor.parentNode || tabs.nextElementSibling !== anchor) {
                    anchor.parentNode.insertBefore(tabs, anchor);
                }
                this._paintWatchTabs();
            } catch {}
        }

        _paintWatchTabs() {
            try {
                const active = document.documentElement.getAttribute('data-bygone-watch-tab') || 'next';
                document.querySelectorAll('#bygone-watch-tabs .b14-wtab, #bygone-watch-tabs button').forEach((b) => {
                    const on = b.getAttribute('data-tab') === active;
                    b.style.setProperty('background', on ? '#fff' : 'transparent', 'important');
                    b.style.setProperty('color', on ? '#1a1a1a' : '#666', 'important');
                    b.style.setProperty('box-shadow', on ? 'inset 0 -3px 0 #cc181e' : 'none', 'important');
                });
            } catch {}
        }

        _ensureKiosk2014Chrome() {
            try {
                const body = document.body;
                if (!body) return;
                const host = document.querySelector('#masthead, #yt-masthead-container, #masthead-container');
                const pin = (el, styles) => {
                    for (const k in styles) {
                        try { el.style.setProperty(k, styles[k], 'important'); } catch {}
                    }
                };
                let menuBtn = document.getElementById('bygone-2014-menu');
                if (!menuBtn) {
                    menuBtn = document.createElement('button');
                    menuBtn.id = 'bygone-2014-menu';
                    menuBtn.type = 'button';
                    menuBtn.setAttribute('aria-label', 'Guide');
                    menuBtn.textContent = '☰';
                    menuBtn.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        this._toggle2014Drawer();
                    }, true);
                }
                pin(menuBtn, {
                    flex: '0 0 44px', width: '44px', height: '44px', margin: '0', padding: '0',
                    border: '0', background: 'transparent', color: '#fff',
                    'font-size': '22px', 'line-height': '44px', 'text-align': 'center',
                });
                if (host && menuBtn.parentNode !== host) host.insertBefore(menuBtn, host.firstChild);
                let scrim = document.getElementById('bygone-2014-scrim');
                if (!scrim) {
                    scrim = document.createElement('div');
                    scrim.id = 'bygone-2014-scrim';
                    scrim.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        this._toggle2014Drawer(false);
                    }, true);
                }
                pin(scrim, {
                    position: 'fixed', top: '0', left: '0', right: '0', bottom: '0',
                    background: 'rgba(0,0,0,.55)', 'z-index': '2147483645', transition: 'opacity .2s',
                });
                if (scrim.getAttribute('data-open') !== '1') {
                    pin(scrim, { opacity: '0', 'pointer-events': 'none' });
                }
                if (scrim.parentNode !== body) body.appendChild(scrim);
                let drawer = document.getElementById('bygone-2014-drawer');
                if (!drawer) {
                    drawer = document.createElement('div');
                    drawer.id = 'bygone-2014-drawer';
                }
                pin(drawer, {
                    position: 'fixed', top: '0', bottom: '0', left: '0',
                    width: 'min(80vw,300px)', background: '#2c2c2c', 'z-index': '2147483646',
                    'overflow-y': 'auto', 'overflow-x': 'hidden',
                    'box-shadow': '2px 0 8px rgba(0,0,0,.5)',
                    'font-family': '"Helvetica Neue",Roboto,Helvetica,Arial,sans-serif',
                    padding: '0 0 env(safe-area-inset-bottom,0px)', 'box-sizing': 'border-box',
                    transition: 'transform .22s ease', 'touch-action': 'pan-y',
                });
                if (drawer.getAttribute('data-open') !== '1') {
                    pin(drawer, { transform: 'translateX(-103%)' });
                }
                if (drawer.parentNode !== body) body.appendChild(drawer);
                this._ensure2014Suggest();
            } catch {}
        }

        _toggle2014Drawer(force) {
            const drawer = document.getElementById('bygone-2014-drawer');
            const scrim = document.getElementById('bygone-2014-scrim');
            if (!drawer || !scrim) return;
            const open = force !== undefined ? !!force : drawer.getAttribute('data-open') !== '1';
            if (open) this._build2014Drawer(drawer);
            drawer.setAttribute('data-open', open ? '1' : '0');
            scrim.setAttribute('data-open', open ? '1' : '0');
            try {
                drawer.style.setProperty('transform', open ? 'translateX(0)' : 'translateX(-103%)', 'important');
                scrim.style.setProperty('opacity', open ? '1' : '0', 'important');
                scrim.style.setProperty('pointer-events', open ? 'auto' : 'none', 'important');
            } catch {}
        }

        _build2014Drawer(drawer) {
            drawer.textContent = '';
            const path = location.pathname;
            const section = (label) => drawer.appendChild(this._el('div', 'b14-sec', label));
            const row = (iconText, label, onTap, opts = {}) => {
                const r = this._el('div', 'b14-row' + (opts.active ? ' b14-active' : ''));
                r.appendChild(this._el('span', 'b14-ic' + (opts.tile ? ' b14-tile' : ''), iconText));
                r.appendChild(this._el('span', 'b14-label', label));
                r.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    this._toggle2014Drawer(false);
                    onTap();
                }, true);
                drawer.appendChild(r);
            };
            const openPanel = () => {
                const fab = document.getElementById('wbt-fab');
                if (fab) { try { fab.click(); } catch {} }
            };
            section('Account');
            row('⚙︎', 'Settings', openPanel);
            row('+', 'Add Channels', openPanel);
            section('Channels');
            row('⌂', 'Home Feed', () => { location.href = 'https://www.youtube.com/'; },
                { active: path === '/' || path === '' });
            let subs = [];
            try { subs = (Store.getSubscriptions() || []).slice(0, 14); } catch {}
            for (const sub of subs) {
                const name = sub && sub.name;
                if (!name) continue;
                row(name.charAt(0).toUpperCase(), name, () => {
                    location.href = sub.id
                        ? 'https://www.youtube.com/channel/' + sub.id + '/videos'
                        : 'https://www.youtube.com/results?search_query=' + encodeURIComponent(name);
                }, { tile: true, active: !!sub.id && path.indexOf('/channel/' + sub.id) === 0 });
            }
            section('From YouTube');
            row('★', 'Popular', () => { location.href = 'https://www.youtube.com/feed/trending'; },
                { active: path.indexOf('/feed/trending') === 0 });
        }

        _ensure2014Suggest() {
            const form = document.getElementById('bygone-kiosk-search-bar');
            if (!form) return;
            const input = form.querySelector('input[name="search_query"]');
            if (!input) return;
            let list = document.getElementById('bygone-2014-suggest');
            if (!list) {
                list = document.createElement('div');
                list.id = 'bygone-2014-suggest';
                list.addEventListener('mousedown', (e) => e.preventDefault(), true);
            }
            for (const [k, v] of Object.entries({
                position: 'fixed', left: '0', right: '0', background: '#fff',
                'z-index': '2147483644', 'box-shadow': '0 3px 8px rgba(0,0,0,.35)',
                'max-height': '60vh', 'overflow-y': 'auto', 'border-bottom': '1px solid #c9c9c9',
            })) {
                try { list.style.setProperty(k, v, 'important'); } catch {}
            }
            if (list.getAttribute('data-open') !== '1') {
                try { list.style.setProperty('display', 'none', 'important'); } catch {}
            }
            if (list.parentNode !== document.body) document.body.appendChild(list);
            if (input.getAttribute('data-b14-wired') === '1') return;
            input.setAttribute('data-b14-wired', '1');
            const hide = () => {
                list.setAttribute('data-open', '0');
                try { list.style.setProperty('display', 'none', 'important'); } catch {}
            };
            const submitWith = (text) => {
                input.value = text;
                hide();
                if (form.requestSubmit) form.requestSubmit();
                else form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
            };
            const render = () => {
                const q = (input.value || '').trim().toLowerCase();
                let hist = [];
                try { hist = Store.getSearchHistory() || []; } catch {}
                const seen = new Set();
                const items = [];
                for (let i = hist.length - 1; i >= 0 && items.length < 6; i--) {
                    const text = hist[i] && hist[i].query;
                    if (!text) continue;
                    const lower = text.toLowerCase();
                    if (seen.has(lower)) continue;
                    if (q && (lower.indexOf(q) === -1 || lower === q)) continue;
                    seen.add(lower);
                    items.push(text);
                }
                list.textContent = '';
                if (!items.length) { hide(); return; }
                for (const text of items) {
                    const r = this._el('div', 'b14-sg');
                    r.appendChild(this._el('span', 'b14-sg-q', text));
                    const fill = this._el('button', 'b14-sg-fill', '↖');
                    fill.type = 'button';
                    fill.setAttribute('aria-label', 'Fill search with ' + text);
                    fill.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        input.value = text;
                        try { input.focus(); } catch {}
                        render();
                    }, true);
                    r.appendChild(fill);
                    r.addEventListener('click', (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        submitWith(text);
                    }, true);
                    list.appendChild(r);
                }
                const rect = form.getBoundingClientRect();
                list.style.setProperty('top', Math.max(0, Math.round(rect.bottom + 4)) + 'px', 'important');
                list.setAttribute('data-open', '1');
                try { list.style.setProperty('display', 'block', 'important'); } catch {}
            };
            input.addEventListener('focus', render);
            input.addEventListener('input', render);
            input.addEventListener('blur', () => setTimeout(hide, 250));
            form.addEventListener('submit', hide, true);
        }

        _applyKioskLookPrefs() {
            const root = document.documentElement;
            if (!root) return;
            this._ensureKioskLookStyle();
            const sizeVars = [
                '--bygone-kiosk-zoom',
                '--bygone-body-size',
                '--bygone-title-size',
                '--bygone-meta-size',
                '--bygone-control-size',
                '--bygone-control-small',
                '--bygone-control-title-size',
                '--bygone-control-height',
                '--bygone-panel-width',
                '--bygone-fab-size',
                '--bygone-fab-font',
                '--bygone-home-top-gap',
            ];
            const feedVars = [
                '--bygone-feed-columns',
                '--bygone-feed-gap',
                '--bygone-feed-pad',
                '--bygone-feed-max',
                '--bygone-watch-pad',
                '--bygone-watch-width',
            ];
            if (!_isKioskOrMobileLayout()) {
                root.removeAttribute('data-bygone-kiosk-dark');
                root.removeAttribute('data-bygone-kiosk-zoom');
                root.removeAttribute('data-bygone-kiosk-watch');
                root.removeAttribute('data-bygone-kiosk-columns');
                root.removeAttribute('data-bygone-kiosk-home-settled');
                sizeVars.concat(feedVars).forEach(v => root.style.removeProperty(v));
                return;
            }
            try {
                if (Store._lsGet('bygone_kiosk_2014_light_v1', '0') !== '1') {
                    Store.setKioskDarkMode(false);
                    Store._lsSet('bygone_kiosk_2014_light_v1', '1');
                }
            } catch {}
            if (Store.getKioskDarkMode()) root.setAttribute('data-bygone-kiosk-dark', '1');
            else root.removeAttribute('data-bygone-kiosk-dark');
            root.setAttribute('data-bygone-kiosk-zoom', '1');
            this._ensureKioskViewportLock();
            this._ensureKioskSearchBar();
            this._restyleKioskBottomNav();
            this._updateKioskHomeSettled();
            this._ensureKiosk2014Chrome();
            if (location.pathname.indexOf('/watch') === 0) {
                root.setAttribute('data-bygone-kiosk-watch', '1');
                for (const id of ['player', 'watch7-main-container', 'watch7-main', 'watch7-content', 'watch7-container', 'watch7-video']) {
                    const el = document.getElementById(id);
                    if (!el) continue;
                    try {
                        el.style.setProperty('padding-left', '0', 'important');
                        el.style.setProperty('padding-right', '0', 'important');
                        el.style.setProperty('margin-left', '0', 'important');
                        el.style.setProperty('margin-right', '0', 'important');
                        el.style.setProperty('float', 'none', 'important');
                        el.style.setProperty('max-width', '100vw', 'important');
                    } catch (_) {}
                }
                try {
                    if (!document.fullscreenElement) {
                        const visW = _kioskVisibleWidth() || window.innerWidth;
                        const playerHeight = Math.round(Math.min(
                            visW * 9 / 16,
                            window.innerHeight - 112
                        ));
                        if (playerHeight > 150) {
                            document.querySelectorAll('#movie_player, #player-api, [id^="player-api"]').forEach(box => {
                                box.style.setProperty('height', playerHeight + 'px', 'important');
                            });
                            const wrap = document.getElementById('player');
                            if (wrap) wrap.style.setProperty('height', 'auto', 'important');
                        }
                    }
                } catch (_) {}
                const sidebar = document.getElementById('watch7-sidebar');
                if (sidebar) {
                    try {
                        sidebar.style.setProperty('margin-left', '0', 'important');
                        sidebar.style.setProperty('margin-right', '0', 'important');
                        sidebar.style.setProperty('float', 'none', 'important');
                    } catch (_) {}
                }
                this._ensureWatchTabs();
            } else {
                root.removeAttribute('data-bygone-kiosk-watch');
                root.removeAttribute('data-bygone-watch-tab');
            }
            const z = Store.getKioskZoom();
            const px = n => Math.round(n) + 'px';
            const clamp = (n, min, max) => Math.max(min, Math.min(max, n));
            const visibleWidth = _kioskVisibleWidth() || _kioskEffectiveWidth() || 390;
            const layoutWidth = Math.max(
                Number(window.innerWidth) || 0,
                Number(document.documentElement && document.documentElement.clientWidth) || 0,
                Number(window.visualViewport && window.visualViewport.width) || 0
            );
            const columnWidth = visibleWidth || layoutWidth;
            const feedColumns = columnWidth >= 600 ? 2 : 1;
            const widthT = clamp((columnWidth - 340) / 440, 0, 1);
            const userScale = clamp(0.95 + (z - 1.15) * 0.14, 0.92, 1.08);
            const titleBase = feedColumns === 2
                ? clamp(18 + widthT * 3, 18, 21)
                : clamp(20 + widthT * 3, 20, 23);
            const metaBase = feedColumns === 2
                ? clamp(15 + widthT, 15, 16)
                : clamp(16 + widthT * 1.5, 16, 18);
            const bodyBase = clamp(16 + widthT * 1.5, 16, 18);
            const controlBase = clamp(16 + widthT * 1.5, 16, 18);
            root.setAttribute('data-bygone-kiosk-columns', String(feedColumns));
            root.style.setProperty('--bygone-kiosk-zoom', String(z));
            root.style.setProperty('--bygone-feed-columns', String(feedColumns));
            root.style.setProperty('--bygone-feed-gap', feedColumns === 2 ? px(clamp(7 + widthT, 7, 8)) : px(clamp(4 + widthT * 2, 4, 6)));
            root.style.setProperty('--bygone-feed-pad', feedColumns === 2 ? px(clamp(2 + widthT * 2, 2, 4)) : '0px');
            root.style.setProperty('--bygone-feed-max', '100vw');
            root.style.setProperty('--bygone-watch-pad', '0px');
            root.style.setProperty('--bygone-watch-width', px(visibleWidth));
            root.style.setProperty('--bygone-body-size', px(bodyBase * userScale));
            root.style.setProperty('--bygone-title-size', px(titleBase * userScale));
            root.style.setProperty('--bygone-meta-size', px(metaBase * userScale));
            root.style.setProperty('--bygone-control-size', px(controlBase * userScale));
            root.style.setProperty('--bygone-control-small', px(clamp(controlBase - 2, 14, 16) * userScale));
            root.style.setProperty('--bygone-control-title-size', px(clamp(controlBase + 1, 17, 19) * userScale));
            root.style.setProperty('--bygone-control-height', px(clamp(40 + widthT * 6, 40, 46) * userScale));
            root.style.setProperty('--bygone-panel-width', px(clamp(columnWidth - 12, 320, 430)));
            root.style.setProperty('--bygone-fab-size', px(clamp(54 + widthT * 6, 54, 60)));
            root.style.setProperty('--bygone-fab-font', px(clamp(21 + widthT * 3, 21, 24)));
            root.style.setProperty('--bygone-home-top-gap', px(clamp(8 + widthT * 6, 8, 14)));
            this._clampKioskViewportSlack();
        }

        _broadcastKioskLookPrefs() {
            this._applyKioskLookPrefs();
            try {
                const target = (typeof unsafeWindow !== 'undefined' && unsafeWindow) || window;
                const Ctor = target.CustomEvent || CustomEvent;
                target.dispatchEvent(new Ctor('bygone-kiosk-look-changed', {
                    detail: { dark: Store.getKioskDarkMode(), zoom: Store.getKioskZoom() }
                }));
            } catch {}
        }
    }

    class App {
        static async init() {
            const offset = Store.getTimeOffset();
            if (Math.abs(offset) > 86400000) Store.setTimeOffset(0);

            const lastVersion = Store._get('bygone_last_version', 0);
            if (lastVersion < VERSION) {
                try { for (const k of GM_listValues()) if (k.startsWith('bygone_cache_')) GM_deleteValue(k); } catch {}
                try { Store.setImpressions({}); } catch {}
                try { Store.setSeenIds([]); } catch {}
                try { Interceptor.clearPool(); } catch {}
                try {
                    const oldZoom = Number(Store._lsGet('bygone_kiosk_zoom', '1.35'));
                    if (!Number.isFinite(oldZoom) || oldZoom > 1.65) Store.setKioskZoom(1.35);
                } catch {}
                Store._set('bygone_last_version', VERSION);
            }

            await App._waitForBody();

            const api = new YouTubeAPI();
            const feedEngine = new FeedEngine(api);
            App._api = api;
            App._feedEngine = feedEngine;
            App._ui = new UI(api, feedEngine);

            const netDiag = () => api._post('search', { query: 'minecraft before:2014-05-23' }).then(
                j => {
                    const s = JSON.stringify(j);
                    console.log('[bygone] NET-DIAG GM path OK — bytes:', s.length,
                        'videoRenderer:', (s.match(/"videoRenderer"/g) || []).length);
                    return 'ok';
                },
                e => { console.warn('[bygone] NET-DIAG GM path FAILED:', (e && e.message) || e); return 'fail'; });
            try { window.__bygoneNetDiag = netDiag; } catch (_) {}
            try { if (typeof unsafeWindow !== 'undefined' && unsafeWindow) unsafeWindow.__bygoneNetDiag = netDiag; } catch (_) {}

            const storedDate = Store.getDate();
            const defaultMigrated = Store._get('bygone_default_date_migrated', false);
            if (!storedDate || (!defaultMigrated && Store.shouldUpgradeLegacyDefaultDate(storedDate))) {
                const defaultDate = Store.defaultEraDate();
                if (Store.isClockActive()) Store.startClock(defaultDate);
                else Store.setDate(defaultDate);
            }
            if (!defaultMigrated) Store._set('bygone_default_date_migrated', true);

            try { App._ui.init(); } catch (e) { console.error('[bygone] UI mount failed:', e); }
            setTimeout(() => App._maybeShowDependencyPrompt(), 800);
            setInterval(() => {
                if (!document.getElementById('wbt-panel') && !document.getElementById('wbt-fab')) {
                    try { App._ui.init(); } catch {}
                }
            }, 5000);

            App.primeInterceptor().catch(e => console.error('[bygone] prime failed:', e));

            const applyLogo = () => { try { App._ui._applyCustomLogo(); } catch {} };
            applyLogo();
            window.addEventListener('yt-navigate-finish', applyLogo);
            window.addEventListener('popstate', applyLogo);

            const applyLook = () => { try { App._ui._applyKioskLookPrefs(); } catch {} };
            applyLook();
            window.addEventListener('yt-navigate-finish', applyLook);
            window.addEventListener('popstate', applyLook);
            let applyLookResizeTimer = null;
            const applyLookSoon = () => {
                if (applyLookResizeTimer) clearTimeout(applyLookResizeTimer);
                applyLookResizeTimer = setTimeout(applyLook, 120);
            };
            window.addEventListener('resize', applyLookSoon);
            window.addEventListener('orientationchange', applyLookSoon);
            try {
                if (window.visualViewport) {
                    window.visualViewport.addEventListener('resize', applyLookSoon);
                    window.visualViewport.addEventListener('scroll', applyLookSoon);
                }
            } catch {}
            try {
                if (window.ResizeObserver) {
                    const ro = new ResizeObserver(applyLookSoon);
                    ro.observe(document.documentElement);
                    if (document.body) ro.observe(document.body);
                }
            } catch {}

            setInterval(applyLook, 1000);
            App._wireWatchTracking();

            App._installSubscribeHijack();
            App._scheduleSubSync(2000);

            App._installSearchHijack();

            App._startKeptDateEnrichment();

            setTimeout(() => {
                App._checkGreasyForkVersion().catch(e => console.warn('[bygone] update check failed:', e));
            }, 3500);

            window.addEventListener('yt-navigate-finish', () => {
                if (Interceptor.isChannelPage()) {
                    setTimeout(() => App._handleChannelPage().catch(e => console.warn('[bygone] channel page error:', e)), 800);
                } else {
                    App._channelPageActive = null;
                }
            });
            if (Interceptor.isChannelPage()) {
                setTimeout(() => App._handleChannelPage().catch(e => console.warn('[bygone] channel page error:', e)), 1500);
            }

            console.log(`[bygone] v2 (${VERSION}) ready. Date: ${Store.getCurrentDate()}`);
        }

        static _depsReady() {
            return { v3: _checkV3(), starTube: _checkStarTube() };
        }

        static _maybeShowDependencyPrompt() {
            try {
                if (Store.hasSeenDependencyPrompt()) return;
                const deps = App._depsReady();
                if (deps.v3 && deps.starTube) return;
                Store.markDependencyPromptSeen();
                App._renderDependencyPrompt(deps);
            } catch (e) {
                console.warn('[bygone] dependency prompt failed:', e);
            }
        }

        static _renderDependencyPrompt(deps) {
            if (!document.body || document.getElementById('wbt-dep-modal')) return;
            const modal = document.createElement('div');
            modal.id = 'wbt-dep-modal';

            const box = document.createElement('div');
            box.id = 'wbt-dep-modal-box';

            const title = document.createElement('div');
            title.textContent = 'bygone-yt needs V3 and StarTube';
            title.style.cssText = 'font:bold 14px sans-serif;margin-bottom:8px;color:#222;';
            box.appendChild(title);

            const missing = [];
            if (!deps.v3) missing.push('V3 / VORAPIS');
            if (!deps.starTube) missing.push('StarTube');
            const body = document.createElement('div');
            body.style.cssText = 'line-height:1.45;color:#333;margin-bottom:8px;';
            body.textContent = 'Missing: ' + missing.join(', ') + '. Install the missing scripts, then reload YouTube.';
            box.appendChild(body);

            const note = document.createElement('div');
            note.textContent = 'This message only appears once. The Setup tab will still show dependency status later.';
            note.style.cssText = 'font-size:11px;color:#666;margin-bottom:10px;';
            box.appendChild(note);

            const actions = document.createElement('div');
            actions.className = 'wbt-dep-actions';

            const mkBtn = (label, primary, onClick) => {
                const b = document.createElement('button');
                b.textContent = label;
                b.className = primary ? 'wbt-btn wbt-btn-primary' : 'wbt-btn';
                b.style.cssText = 'padding:4px 9px;border:1px solid ' + (primary ? '#800' : '#888') +
                    ';background:' + (primary ? '#c00' : '#ddd') +
                    ';color:' + (primary ? '#fff' : '#222') +
                    ';border-radius:2px;cursor:pointer;font:12px sans-serif;';
                b.addEventListener('click', onClick);
                return b;
            };
            const close = () => { try { modal.remove(); } catch (_) {} };

            if (!deps.v3) {
                actions.appendChild(mkBtn('Install V3', true, () => {
                    window.open(CONFIG.installUrls.v3, '_blank', 'noopener,noreferrer');
                    close();
                }));
            }
            if (!deps.starTube) {
                actions.appendChild(mkBtn('Install StarTube', true, () => {
                    window.open(CONFIG.installUrls.starTube, '_blank', 'noopener,noreferrer');
                    close();
                }));
            }
            actions.appendChild(mkBtn('Open setup', false, () => {
                close();
                try {
                    if (App._ui) App._ui._activeTab = 'setup';
                    App._ui.init();
                    const panel = document.getElementById('wbt-panel');
                    if (panel) {
                        panel.classList.remove('wbt-hidden');
                        panel.style.setProperty('display', 'block', 'important');
                    }
                } catch (_) {}
            }));
            actions.appendChild(mkBtn('Close', false, close));

            box.appendChild(actions);
            modal.appendChild(box);
            document.body.appendChild(modal);
        }

        static _installSearchHijack() {
            const TAG_RE = /\s*before:\d{4}-\d{2}-\d{2}/g;
            const cleanOf = (s) => (s || '').replace(TAG_RE, '').trim();
            const hasTag = (s) => /before:\d{4}-\d{2}-\d{2}/.test(s || '');

            const findSearchInput = () => {
                return document.querySelector(
                    'input#search, input[name="search_query"], input#masthead-search-term'
                );
            };

            const scrubVisibleInput = () => {
                const inp = findSearchInput();
                if (!inp) return;
                if (hasTag(inp.value)) inp.value = cleanOf(inp.value);
            };

            const applyUrlFixup = () => {
                if (!Store.isActive()) return;
                const p = location.pathname;
                if (p !== '/results' && p !== '/results/') return;
                const dateStr = Store.getCurrentDate();
                if (!dateStr) return;
                const params = new URLSearchParams(location.search);
                const query = params.get('search_query') || '';
                if (!query) return;
                if (hasTag(query)) { scrubVisibleInput(); return; }
                params.set('search_query', `${query} before:${dateStr}`.trim());
                window.location.replace(`/results?${params.toString()}`);
            };

            document.addEventListener('submit', (e) => {
                if (!Store.isActive()) return;
                const form = e.target;
                if (!form || form.tagName !== 'FORM') return;
                const input = form.querySelector(
                    'input[name="search_query"], input#search, input#masthead-search-term'
                );
                if (!input || !input.value.trim()) return;
                if (hasTag(input.value)) return;
                const dateStr = Store.getCurrentDate();
                if (!dateStr) return;
                const original = input.value;
                try { Store.addSearchQuery(original); } catch (_) {}
                input.value = `${original.trim()} before:${dateStr}`;
                setTimeout(() => {
                    const live = findSearchInput();
                    if (live) live.value = original;
                }, 0);
            }, true);

            document.addEventListener('keydown', (e) => {
                if (e.key !== 'Enter' || e.isComposing) return;
                if (!Store.isActive()) return;
                const t = e.target;
                if (!t || !t.matches) return;
                if (!t.matches('input[name="search_query"], input#search, input#masthead-search-term')) return;
                if (!t.value.trim() || hasTag(t.value)) return;
                const dateStr = Store.getCurrentDate();
                if (!dateStr) return;
                const original = t.value;
                try { Store.addSearchQuery(original); } catch (_) {}
                t.value = `${original.trim()} before:${dateStr}`;
                setTimeout(() => {
                    const live = findSearchInput();
                    if (live) live.value = original;
                }, 0);
            }, true);

            applyUrlFixup();
            window.addEventListener('yt-navigate-finish', () => {
                applyUrlFixup();
                setTimeout(scrubVisibleInput, 100);
                setTimeout(scrubVisibleInput, 500);
            });
            window.addEventListener('popstate', () => {
                applyUrlFixup();
                setTimeout(scrubVisibleInput, 100);
            });
            setInterval(() => {
                const p = location.pathname;
                if (p === '/results' || p === '/results/') scrubVisibleInput();
            }, 1000);
        }

        static _installSubscribeHijack() {
            const isSubButton = (el) => {
                for (let i = 0; i < 8 && el && el !== document.body; i++) {
                    const cls = (el.className && el.className.toString && el.className.toString()) || '';
                    if (/yt-uix-button-subscribe-branded|yt-uix-subscription-button|subscribe-button-renderer|ytd-subscribe-button/i.test(cls)) return el;
                    const aria = el.getAttribute && (el.getAttribute('aria-label') || '');
                    if (/^subscribe/i.test(aria) || /^subscribed/i.test(aria)) return el;
                    const txt = (el.textContent || '').trim().toLowerCase();
                    if (txt === 'subscribe' || txt === 'subscribed') return el;
                    el = el.parentElement;
                }
                return null;
            };

            document.addEventListener('click', async (e) => {
                if (!isSubButton(e.target)) return;
                let wasSubscribed = false;
                try {
                    let el = e.target;
                    for (let i = 0; i < 8 && el; i++) {
                        const txt = (el.textContent || '').trim().toLowerCase();
                        if (txt === 'subscribed') { wasSubscribed = true; break; }
                        if (txt === 'subscribe') { wasSubscribed = false; break; }
                        el = el.parentElement;
                    }
                } catch {}

                setTimeout(async () => {
                    try {
                        const info = await App._extractChannelInfo();
                        if (!info || !info.id) return;
                        const subs = Store.getSubscriptions();
                        const i = subs.findIndex(s => s.id === info.id);
                        if (wasSubscribed) {
                            if (i >= 0) {
                                subs.splice(i, 1);
                                Store.setSubscriptions(subs);
                                console.log('[bygone] removed subscription:', info.name);
                            }
                        } else {
                            if (i < 0) {
                                subs.push({ id: info.id, name: info.name, weight: 3 });
                                Store.setSubscriptions(subs);
                                Store.markSubSynced(info.id);
                                console.log('[bygone] added subscription:', info.name);
                            }
                        }
                    } catch (err) {
                        console.warn('[bygone] sub hijack error:', err);
                    }
                }, 200);
            }, true);
        }

        static async _extractChannelInfo() {
            const path = location.pathname;
            let m = path.match(/^\/channel\/(UC[A-Za-z0-9_-]+)/);
            if (m) {
                const id = m[1];
                const name = App._scrapeChannelName() || id;
                return { id, name };
            }
            const link = document.querySelector('a[href^="/channel/UC"]');
            if (link) {
                const href = link.getAttribute('href') || '';
                const m2 = href.match(/^\/channel\/(UC[A-Za-z0-9_-]+)/);
                if (m2) {
                    const id = m2[1];
                    const name = (link.textContent || '').trim() || App._scrapeChannelName() || id;
                    return { id, name };
                }
            }
            const name = App._scrapeChannelName();
            if (!name) return null;
            try {
                const ch = await App._api.resolveChannel(name);
                if (ch && ch.id) return { id: ch.id, name: ch.name || name };
            } catch {}
            return null;
        }

        static _scrapeChannelName() {
            const sels = [
                '.qualified-channel-title-text',
                '.channel-header-profile-image-container .channel-title',
                '#channel-header-container .channel-name',
                '#channel-name',
                'ytd-channel-name',
                '.ytd-channel-name',
                '.attribution .g-hovercard',
                '.attribution .yt-user-name',
                '.attribution',
            ];
            for (const sel of sels) {
                const el = document.querySelector(sel);
                if (el && el.textContent && el.textContent.trim()) {
                    return el.textContent.trim().replace(/^by\s+/i, '');
                }
            }
            return null;
        }

        static async _syncSubsToYouTube() {
            if (!Store.isAutoSyncSubs()) return;
            const subs = Store.getSubscriptions();
            const synced = new Set(Store.getSyncedSubIds());
            const pending = subs.filter(s => s && s.id && !synced.has(s.id));
            if (!pending.length) return;
            console.log(`[bygone] syncing ${pending.length} subscription(s) to YouTube…`);
            for (const sub of pending) {
                try {
                    const ok = await App._api.subscribeToChannel(sub.id);
                    if (ok) {
                        Store.markSubSynced(sub.id);
                        console.log('[bygone] subscribed on YouTube:', sub.name);
                    }
                } catch (e) {
                    console.warn('[bygone] sync error for', sub.name, e.message);
                }
            }
        }

        static _scheduleSubSync(delay) {
            if (App._syncTimer) clearTimeout(App._syncTimer);
            App._syncTimer = setTimeout(() => {
                App._syncTimer = null;
                App._syncSubsToYouTube().catch(e => console.warn('[bygone] sync failed:', e));
            }, delay || 1500);
        }

        static async primeInterceptor() {
            try {
                if (!Store.isActive()) {
                    Interceptor.setPaused(true);
                    return { ok: false, count: 0, message: 'bygone is paused — turn Active on to rebuild the feed.' };
                }
                Interceptor.setPaused(false);
                const date = Store.getCurrentDate();
                if (!date) return { ok: false, count: 0, message: 'No date is set.' };
                let earlyPrimed = false;
                const onPartial = (vids) => {
                    try {
                        if (!vids || !vids.length) return;
                        if (Interceptor.isActive()) {
                            Interceptor.appendVideos(vids);
                        } else if (Interceptor.setVideos(vids)) {
                            earlyPrimed = true;
                            console.log('[bygone] early-primed', Interceptor.poolSize(), 'videos (partial) — pool live');
                        }
                    } catch (_) {}
                };
                const videos = await App._feedEngine.buildHomeFeed(date, onPartial);
                let accepted = 0;
                if (videos && videos.length) {
                    if (earlyPrimed) {
                        const added = Interceptor.appendVideos(videos);
                        accepted = Interceptor.poolSize();
                        console.log('[bygone] primed with', accepted, 'videos (appended', added, 'new)');
                    } else {
                        accepted = Interceptor.setVideos(videos);
                        if (accepted) console.log('[bygone] primed with', accepted, 'videos');
                    }
                    if (accepted) App._enrichExactDates(videos, date);
                } else if (earlyPrimed) {
                    accepted = Interceptor.poolSize();
                }
                Interceptor.setLazyFetcher(async (page) => {
                    const cur = Store.getCurrentDate();
                    if (!cur) return [];
                    const more = await App._feedEngine.buildHomeFeedMore(cur, page, Interceptor.getPoolIds());
                    App._enrichExactDates(more, cur);
                    return more;
                });
                if (!accepted) {
                    return { ok: false, count: 0, message: 'No era videos loaded. Check sources or try Clear cache.' };
                }
                return { ok: true, count: accepted };
            } catch (e) {
                console.error('[bygone] prime failed', e);
                return { ok: false, count: 0, error: e, message: 'Reload failed: ' + (e && e.message ? e.message : e) };
            }
        }

        static _enrichRunning = false;
        static async _enrichExactDates(videos, setDateStr) {
            if (App._enrichRunning) return;
            videos = videos || [];
            const _p = location.pathname;
            if (_p !== '/' && _p !== '' && _p !== '/feed/trending') return;
            const anchor = new Date(setDateStr).getTime();
            if (isNaN(anchor)) return;
            const AMBIG_MS = 400 * 86400000;
            const seen = new Set();
            const need = [];
            const later = [];
            const consider = (id, relativeDate) => {
                if (!id || seen.has(id)) return;
                seen.add(id);
                try { if (Store.getExactDate(id)) return; } catch (_) { return; }
                const approx = DateHelper.approxPublishDate(relativeDate || '');
                const ambig = AMBIG_MS + DateHelper.approxSlackMs(relativeDate || '');
                if (approx && Math.abs(anchor - approx.getTime()) > ambig) later.push(id);
                else need.push(id);
            };
            for (const v of videos) consider(v && v.id, v && v.relativeDate);
            try {
                for (const v of Interceptor.getPool()) consider(v && v.id, v && v.relativeDate);
            } catch (_) {}
            try {
                for (const id of Interceptor.getKeptNaturalIds()) consider(id, '');
            } catch (_) {}
            need.push(...later);
            if (need.length > 80) need.length = 80;
            if (!need.length) return;
            App._enrichRunning = true;
            try {
                const CHUNK = 10;
                for (let i = 0; i < need.length; i += CHUNK) {
                    const slice = need.slice(i, i + CHUNK);
                    const map = {};
                    await Promise.all(slice.map(async id => {
                        const iso = await App._api.fetchExactDate(id);
                        if (iso) map[id] = iso;
                    }));
                    if (Object.keys(map).length) {
                        Store.addExactDates(map);
                        const future = Object.keys(map).filter(id => new Date(map[id]) > new Date(setDateStr));
                        if (future.length) {
                            const n = Interceptor.removeVideos(future);
                            if (n) console.log('[bygone] evicted', n, 'post-era videos from pool');
                        }
                        try { Interceptor.refreshAllDates(); } catch (_) {}
                    }
                    if (Store.getCurrentDate() !== setDateStr) break;
                    if (i + CHUNK < need.length) await new Promise(r => setTimeout(r, 1200));
                }
                console.log('[bygone] exact-date enrichment done for', need.length, 'videos');
            } catch (_) {
            } finally {
                App._enrichRunning = false;
            }
        }

        static _startKeptDateEnrichment() {
            setInterval(() => {
                try {
                    const cur = Store.getCurrentDate();
                    if (!cur) return;
                    App._enrichExactDates([], cur);
                } catch (_) {}
            }, 30000);
        }

        static _channelPageActive = null;

        static async _handleChannelPage() {
            if (!Interceptor.isChannelPage()) return;
            const date = Store.getCurrentDate();
            if (!date) return;

            const info = await App._extractChannelInfo();
            if (!info || !info.id) {
                console.warn('[bygone] channel page: could not extract channelId');
                return;
            }

            if (App._channelPageActive === info.id) return;
            App._channelPageActive = info.id;

            console.log('[bygone] channel page: fetching videos for', info.id, info.name);

            try {
                const videos = await App._api.getChannelVideos(info.name, {
                    channelId: info.id,
                    publishedBefore: date,
                    maxResults: 50,
                });

                if (!videos || !videos.length) {
                    console.log('[bygone] channel page: no videos found before', date);
                    return;
                }

                videos.sort((a, b) => {
                    const da = DateHelper.approxPublishDate(a.relativeDate);
                    const db = DateHelper.approxPublishDate(b.relativeDate);
                    if (!da && !db) return 0;
                    if (!da) return 1;
                    if (!db) return -1;
                    return db.getTime() - da.getTime();
                });

                for (const v of videos) {
                    if (v.relativeDate) {
                        try {
                            v.relativeDate = DateHelper.recalcForFeed(v.relativeDate, date, v.id) || v.relativeDate;
                        } catch (_) {}
                    }
                }

                console.log('[bygone] channel page: fetched', videos.length, 'videos for', info.id);

                const tryRewrite = () => {
                    const cards = Interceptor.findCards(document);
                    if (!cards.length) return false;
                    const channelCards = cards.filter(c => {
                        const a = c.querySelector('a[href*="/watch"]');
                        return !!a;
                    });
                    const inner = [];
                    let wrote = 0;
                    for (let i = 0; i < channelCards.length; i++) {
                        if (i < videos.length) {
                            try {
                                Interceptor.rewriteCard(channelCards[i], videos[i], inner);
                                channelCards[i].setAttribute('data-bygone-ok', '1');
                                wrote++;
                            } catch (_) {}
                        } else {
                            try { channelCards[i].style.setProperty('display', 'none', 'important'); } catch (_) {}
                        }
                    }
                    return wrote > 0;
                };

                if (!tryRewrite()) {
                    setTimeout(tryRewrite, 500);
                    setTimeout(tryRewrite, 1500);
                    setTimeout(tryRewrite, 3000);
                }
            } catch (e) {
                console.error('[bygone] channel page fetch failed:', e);
            }
        }

        static _cacheBustUrl(url) {
            const sep = url.indexOf('?') === -1 ? '?' : '&';
            return url + sep + 'bygone_update_check=' + VERSION + '_' + Date.now();
        }

        static _requestText(url, timeoutMs) {
            return new Promise((resolve, reject) => {
                try {
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: App._cacheBustUrl(url),
                        timeout: timeoutMs || 10000,
                        headers: { 'Accept': 'text/plain,text/html,*/*' },
                        onload(res) {
                            if (res.status >= 200 && res.status < 300) resolve(res.responseText || '');
                            else reject(new Error('HTTP ' + res.status));
                        },
                        onerror() { reject(new Error('Network error')); },
                        ontimeout() { reject(new Error('Timed out')); },
                    });
                } catch (e) {
                    reject(e);
                }
            });
        }

        static _parseUserscriptVersion(text) {
            const m = String(text || '').match(/^\s*\/\/\s*@version\s+(.+?)\s*$/m);
            return m ? m[1].trim() : '';
        }

        static _compareVersions(a, b) {
            const pa = String(a || '').match(/\d+/g);
            const pb = String(b || '').match(/\d+/g);
            if (!pa || !pb) return String(a || '').localeCompare(String(b || ''), undefined, { numeric: true, sensitivity: 'base' });
            const len = Math.max(pa.length, pb.length);
            for (let i = 0; i < len; i++) {
                const na = Number(pa[i] || 0);
                const nb = Number(pb[i] || 0);
                if (na !== nb) return na < nb ? -1 : 1;
            }
            return 0;
        }

        static _greasyForkVersionUrls() {
            const urls = [];
            const add = (url) => {
                if (!url || !/greasyfork\.org/i.test(url)) return;
                if (urls.indexOf(url) === -1) urls.push(url);
            };
            add(CONFIG.update.metaUrl);
            add(CONFIG.update.userUrl);
            try {
                const info = (typeof GM_info !== 'undefined' && GM_info) ? GM_info : null;
                const script = info && info.script ? info.script : {};
                add(script.updateURL || script.updateUrl);
                add(script.downloadURL || script.downloadUrl);
            } catch (_) {}
            return urls;
        }

        static async _fetchLatestGreasyForkVersion() {
            for (const url of App._greasyForkVersionUrls()) {
                try {
                    const text = await App._requestText(url, 10000);
                    const version = App._parseUserscriptVersion(text);
                    if (version) return { version, url };
                } catch (e) {
                    console.warn('[bygone] update check source failed:', url, e && e.message ? e.message : e);
                }
            }
            return null;
        }

        static async _checkGreasyForkVersion(force) {
            const now = Date.now();
            const interval = CONFIG.update.checkIntervalMs || 21600000;
            const lastCheck = Number(Store._get('bygone_update_last_check', 0)) || 0;
            if (!force && now - lastCheck < interval) return;
            Store._set('bygone_update_last_check', now);

            const latest = await App._fetchLatestGreasyForkVersion();
            if (!latest || !latest.version) return;
            Store._set('bygone_update_latest_version', latest.version);
            if (App._compareVersions(VERSION, latest.version) >= 0) return;

            const repeatMs = CONFIG.update.alertRepeatMs || 86400000;
            const lastAlertVersion = Store._get('bygone_update_last_alert_version', '');
            const lastAlertAt = Number(Store._get('bygone_update_last_alert_at', 0)) || 0;
            if (!force && lastAlertVersion === latest.version && now - lastAlertAt < repeatMs) return;

            Store._set('bygone_update_last_alert_version', latest.version);
            Store._set('bygone_update_last_alert_at', now);
            alert(
                'out of date; please update!\n\n' +
                'Installed: v' + VERSION + '\n' +
                'Latest: v' + latest.version + '\n\n' +
                CONFIG.update.scriptPage
            );
        }

        static _waitForBody() {
            return new Promise(resolve => {
                let waited = 0;
                const check = () => {
                    if (document.body) return resolve();
                    waited += 200;
                    if (waited >= 10000) return resolve();
                    setTimeout(check, 200);
                };
                if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', check, { once: true });
                else check();
            });
        }

        static _wireWatchTracking() {
            let timer = null;
            const tick = () => {
                if (timer) { clearTimeout(timer); timer = null; }
                if (!location.pathname.startsWith('/watch')) return;
                const m = location.search.match(/[?&]v=([A-Za-z0-9_-]+)/);
                if (!m) return;
                const videoId = m[1];
                timer = setTimeout(() => {
                    if (!location.pathname.startsWith('/watch')) return;
                    if (location.search.indexOf(videoId) === -1) return;
                    const titleEl = document.querySelector('.watch-title, #eow-title, h1.title, .watch-page-title') || document.querySelector('title');
                    const chanEl = document.querySelector('.yt-user-name, .watch-user-name, .attribution .g-hovercard, .attribution');
                    let channelId = null;
                    const chanLink = document.querySelector(
                        'a[href*="/channel/UC"], .yt-user-name[href*="/channel/"], .attribution a[href*="/channel/"]'
                    );
                    if (chanLink) {
                        const cm = (chanLink.getAttribute('href') || '').match(/\/channel\/(UC[A-Za-z0-9_-]+)/);
                        if (cm) channelId = cm[1];
                    }
                    if (!channelId) {
                        const pv = Interceptor.getPoolVideo(videoId);
                        if (pv && pv.channelId) channelId = pv.channelId;
                    }
                    Store.addWatchEvent({
                        videoId,
                        title: titleEl ? titleEl.textContent.trim().slice(0, 200) : '',
                        channel: chanEl ? chanEl.textContent.trim().slice(0, 80) : '',
                        channelId,
                        ts: Date.now(),
                    });
                }, 15000);
            };
            window.addEventListener('yt-navigate-finish', tick);
            window.addEventListener('popstate', tick);
            tick();
        }
    }

    App.init();

})();