YouTube List View

Forces YouTube Subscriptions feed into a classic List View with optional video descriptions. Press Alt+L to open settings.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

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

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

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

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

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

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

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         YouTube List View
// @namespace    http://tampermonkey.net/
// @version      5.2
// @description  Forces YouTube Subscriptions feed into a classic List View with optional video descriptions. Press Alt+L to open settings.
// @author       dr.bobo0
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?domain=youtube.com
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @run-at       document-idle
// ==/UserScript==
 
(function () {
    'use strict';
 
    // ══════════════════════════════════════════════════════════════════
    // CONSTANTS & CONFIG
    // ══════════════════════════════════════════════════════════════════
    const SHIFT_DELAY = 600;
 
    const GRID_RECTS = [
        { x: 2,   y: 4,  width: 5, height: 7, rx: 1 },
        { x: 2,   y: 13, width: 5, height: 7, rx: 1 },
        { x: 9.5, y: 4,  width: 5, height: 7, rx: 1 },
        { x: 9.5, y: 13, width: 5, height: 7, rx: 1 },
        { x: 17,  y: 4,  width: 5, height: 7, rx: 1 },
        { x: 17,  y: 13, width: 5, height: 7, rx: 1 },
    ];
    const LIST_RECTS = [
        { x: 2, y: 4,  width: 5,  height: 4, rx: 1 },
        { x: 9, y: 4,  width: 13, height: 4, rx: 1 },
        { x: 2, y: 10, width: 5,  height: 4, rx: 1 },
        { x: 9, y: 10, width: 13, height: 4, rx: 1 },
        { x: 2, y: 16, width: 5,  height: 4, rx: 1 },
        { x: 9, y: 16, width: 13, height: 4, rx: 1 },
    ];
 
    const SLIDER_CONFIGS = [
        { key: 'listContainerWidth', label: 'Container Width',  min: 51,  max: 100, unit: '%',  cssVar: '--list-container-width', icon: '⇔' },
        { key: 'thumbnailWidth',     label: 'Thumbnail Width',  min: 150, max: 400, unit: 'px', cssVar: '--thumbnail-width',      icon: '⊡' },
        { key: 'titleFontSize',      label: 'Title Size',       min: 10,  max: 40,  unit: 'pt', cssVar: '--title-font-size',      icon: 'T' },
        { key: 'metaFontSize',       label: 'Meta Size',        min: 8,   max: 24,  unit: 'pt', cssVar: '--meta-font-size',       icon: 't' },
        { key: 'notifyWidth',        label: 'Notify Button',    min: 100, max: 700, unit: 'px', cssVar: '--notify-width',         icon: '🔔' },
    ];
 
    // Toggles rendered in the panel
    const TOGGLE_CONFIGS = [
        { key: 'changeShortsScroll', label: 'Shorts: scroll back on collapse',   icon: '↑' },
        { key: 'hideShorts',         label: 'Hide Shorts section',               icon: '🚫' },
        { key: 'hideMostRelevant',   label: 'Hide "Most Relevant" section',      icon: '🚫' },
        { key: 'hideDividers',       label: 'Hide row dividers',                 icon: '―' },
        { key: 'showDescriptions',   label: 'Show video descriptions',           icon: '≡', warn: 'Fetches each video page — uses extra bandwidth. Cached for 1 hour.' },
        { key: 'panelTransparent',   label: 'Frosted glass panel',               icon: '◫' },
    ];
 
    const DEFAULT_SETTINGS = {
        listContainerWidth: 90,
        thumbnailWidth:     260,
        titleFontSize:      13,
        metaFontSize:       10,
        notifyWidth:        150,
        viewModeSubs:       'list',
        changeShortsScroll: false,
        hideShorts:         false,
        hideMostRelevant:   false,
        hideDividers:       false,
        showDescriptions:   false,
        panelTransparent:   false,
        panelLight:         false,
    };
 
    // Description cache config
    const DESC_CACHE_KEY    = 'ytlv_desc_cache_v1';
    const DESC_CACHE_TTL_MS = 60 * 60 * 1000;
    const DESC_MAX_ENTRIES  = 800;
    const DESC_SAVE_DELAY   = 300;
 
    // Shimmer
    const SHIMMER_VAR = '--ytlv-shimmer-x';
    const SHIMMER_MS  = 2000;
 
    // ══════════════════════════════════════════════════════════════════
    // DOM HELPERS
    // ══════════════════════════════════════════════════════════════════
    function createSVG(rects) {
        const NS  = 'http://www.w3.org/2000/svg';
        const svg = document.createElementNS(NS, 'svg');
        svg.setAttribute('viewBox', '0 0 24 24');
        svg.setAttribute('width',   '24');
        svg.setAttribute('height',  '24');
        for (const attrs of rects) {
            const rect = document.createElementNS(NS, 'rect');
            for (const [k, v] of Object.entries(attrs)) rect.setAttribute(k, v);
            svg.appendChild(rect);
        }
        return svg;
    }
 
    function makeSVGIcon(pathD, size = 20) {
        const NS  = 'http://www.w3.org/2000/svg';
        const svg = document.createElementNS(NS, 'svg');
        svg.setAttribute('viewBox', '0 0 24 24');
        svg.setAttribute('width',  String(size));
        svg.setAttribute('height', String(size));
        const path = document.createElementNS(NS, 'path');
        path.setAttribute('d', pathD);
        svg.appendChild(path);
        return svg;
    }
 
    function el(tag, attrs = {}, children = []) {
        const e = document.createElement(tag);
        for (const [k, v] of Object.entries(attrs)) {
            if      (k === 'style' && typeof v === 'object') Object.assign(e.style, v);
            else if (k === 'className')   e.className   = v;
            else if (k === 'textContent') e.textContent = v;
            else if (k === 'htmlFor')     e.htmlFor     = v;
            else e.setAttribute(k, v);
        }
        for (const child of children) {
            if (typeof child === 'string') e.appendChild(document.createTextNode(child));
            else if (child) e.appendChild(child);
        }
        return e;
    }
 
    // ══════════════════════════════════════════════════════════════════
    // PAGE HELPERS  (subscriptions only)
    // ══════════════════════════════════════════════════════════════════
    function isSubs()       { return location.pathname === '/feed/subscriptions'; }
    function isTargetPage() { return isSubs(); }
 
    // ══════════════════════════════════════════════════════════════════
    // SETTINGS STORAGE
    // ══════════════════════════════════════════════════════════════════
    function getSetting(key) {
        const val = GM_getValue(key, DEFAULT_SETTINGS[key]);
        if (typeof DEFAULT_SETTINGS[key] === 'boolean') return val === true || val === 'true';
        if (typeof DEFAULT_SETTINGS[key] === 'number')  return Number(val);
        return val;
    }
    function setSetting(key, value) { GM_setValue(key, value); }
    function getAllSettings() {
        const s = {};
        for (const key of Object.keys(DEFAULT_SETTINGS)) s[key] = getSetting(key);
        return s;
    }
 
    let settings = getAllSettings();
 
    // ══════════════════════════════════════════════════════════════════
    // DESCRIPTION CACHE
    // ══════════════════════════════════════════════════════════════════
    const _descState = {
        memCache:    new Map(),
        persist:     null,
        dirty:       false,
        saveTimer:   0,
        inFlight:    new Map(),  // vid → true (dedup only)
        loopTimer:   0,
        shimRaf:     0,
        shimRunning: false,
        shimT0:      0,
    };
 
    function descStoreLoad() {
        if (_descState.persist) return;
        let obj = {};
        try {
            const raw = localStorage.getItem(DESC_CACHE_KEY) || '';
            if (raw) {
                const parsed = JSON.parse(raw);
                if (parsed && typeof parsed === 'object') obj = parsed;
            }
        } catch { obj = {}; }
        _descState.persist = obj;
        descStorePrune();
    }
 
    function descStoreSave() {
        if (_descState.saveTimer) return;
        _descState.saveTimer = setTimeout(() => {
            _descState.saveTimer = 0;
            if (!_descState.dirty) return;
            _descState.dirty = false;
            try { localStorage.setItem(DESC_CACHE_KEY, JSON.stringify(_descState.persist || {})); } catch { }
        }, DESC_SAVE_DELAY);
    }
 
    function descStorePrune() {
        descStoreLoad();
        const now = Date.now();
        const obj = _descState.persist || {};
        const entries = [];
        for (const k of Object.keys(obj)) {
            const t = Number(obj[k]?.t || 0);
            if (!t || now - t >= DESC_CACHE_TTL_MS) { delete obj[k]; _descState.dirty = true; continue; }
            entries.push([k, t]);
        }
        if (entries.length > DESC_MAX_ENTRIES) {
            entries.sort((a, b) => a[1] - b[1]);
            for (let i = 0; i < entries.length - DESC_MAX_ENTRIES; i++) {
                delete obj[entries[i][0]]; _descState.dirty = true;
            }
        }
        if (_descState.dirty) descStoreSave();
    }
 
    function descGet(vid) {
        if (!vid) return null;
        descStoreLoad();
        if (_descState.memCache.has(vid)) return _descState.memCache.get(vid);
        const e = _descState.persist[vid];
        if (!e) return null;
        if (Date.now() - Number(e.t || 0) >= DESC_CACHE_TTL_MS) {
            delete _descState.persist[vid]; _descState.dirty = true; descStoreSave(); return null;
        }
        _descState.memCache.set(vid, e.d);
        return e.d;
    }
 
    function descSet(vid, text) {
        if (!vid) return;
        descStoreLoad();
        _descState.memCache.set(vid, text);
        _descState.persist[vid] = { t: Date.now(), d: String(text || '') };
        _descState.dirty = true;
        descStorePrune();
        descStoreSave();
    }
 
    // ══════════════════════════════════════════════════════════════════
    // DESCRIPTION FETCHING
    // ══════════════════════════════════════════════════════════════════
    function decodeHtmlEntities(str) {
        return (str || '').replace(/&amp;/g, '&').replace(/&lt;/g, '<')
            .replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'");
    }
 
    function extractVideoId(href) {
        const h = String(href || '');
        if (h.includes('/shorts/')) {
            const m = h.match(/\/shorts\/([^?&#/]+)/);
            return m ? m[1] : '';
        }
        try { return new URL(h, location.origin).searchParams.get('v') || ''; } catch { return ''; }
    }
 
    function applyDescToDom(vid, text) {
        document.querySelectorAll(`.custom-description[data-vid="${CSS.escape(vid)}"]`).forEach(el => {
            el.classList.remove('desc-skeleton');
            el.textContent = text || '';
            el.style.display = text ? '' : 'none';
        });
    }
 
    // V4-style: just grab the <meta> tag — no JSON parsing, no post-processing
    function fetchDescription(item) {
        if (!settings.showDescriptions || !listViewEnabled) return;
 
        const linkEl = item.querySelector('a#video-title-link, a.yt-lockup-metadata-view-model__title');
        if (!linkEl) return;
        const metaContainer = item.querySelector('yt-content-metadata-view-model');
        if (!metaContainer) return;
 
        const vid = extractVideoId(linkEl.href);
        if (!vid) return;
 
        // Already resolved for this vid
        const descEl = metaContainer.querySelector('.custom-description');
        if (descEl?.dataset.vid === vid && !descEl.classList.contains('desc-skeleton')) return;
 
        // Serve from cache instantly — no fetch needed
        const cached = descGet(vid);
        if (cached != null) {
            applyDescToDom(vid, cached);
            return;
        }
 
        // Already in flight
        if (_descState.inFlight.has(vid)) return;
 
        _descState.inFlight.set(vid, true);
        fetch(linkEl.href)
            .then(r => r.text())
            .then(html => {
                const m = html.match(/<meta name="description" content="([^"]*)"/);
                const text = (m && m[1] && m[1] !== 'null') ? decodeHtmlEntities(m[1]) : '';
                descSet(vid, text);
                applyDescToDom(vid, text);
            })
            .catch(() => { descSet(vid, ''); applyDescToDom(vid, ''); })
            .finally(() => { _descState.inFlight.delete(vid); });
    }
 
    function ensureDescLoop() {
        if (_descState.loopTimer) clearInterval(_descState.loopTimer);
        _descState.loopTimer = setInterval(() => {
            if (!settings.showDescriptions) { stopShimmer(); return; }
            descStorePrune();
            if (document.querySelector('.custom-description.desc-skeleton')) startShimmer();
            else stopShimmer();
        }, 400);
    }
 
    // ══════════════════════════════════════════════════════════════════
    // SHIMMER ANIMATION
    // ══════════════════════════════════════════════════════════════════
    function startShimmer() {
        if (_descState.shimRunning) return;
        _descState.shimRunning = true;
        _descState.shimT0 = performance.now();
        const tick = t => {
            if (!_descState.shimRunning) return;
            if (!document.querySelector('.custom-description.desc-skeleton')) { stopShimmer(); return; }
            const phase = (t - _descState.shimT0) % SHIMMER_MS / SHIMMER_MS;
            document.documentElement.style.setProperty(SHIMMER_VAR, `${200 - phase * 400}%`);
            _descState.shimRaf = requestAnimationFrame(tick);
        };
        _descState.shimRaf = requestAnimationFrame(tick);
    }
 
    function stopShimmer() {
        _descState.shimRunning = false;
        if (_descState.shimRaf) { cancelAnimationFrame(_descState.shimRaf); _descState.shimRaf = 0; }
        document.documentElement.style.removeProperty(SHIMMER_VAR);
    }
 
    // ══════════════════════════════════════════════════════════════════
    // CSS
    // ══════════════════════════════════════════════════════════════════
    const FEED      = 'ytd-browse[page-subtype="subscriptions"]';
    const FEED_ITEM = `html.list-view-active ${FEED} ytd-rich-grid-renderer > #contents > ytd-rich-item-renderer`;
 
    GM_addStyle(`
        :root {
            --list-container-width: 90%;
            --thumbnail-width: 260px;
            --header-height: 40px;
            --channel-info-padding-bottom: 10px;
            --notify-width: 150px;
            --title-font-size: 13pt;
            --meta-font-size: 10pt;
 
            /* Panel design tokens — dark (default) */
            --ytlv-bg:            #0f0f0f;
            --ytlv-bg-elevated:   #212121;
            --ytlv-bg-hover:      #3f3f3f;
            --ytlv-surface:       #1f1f1f;
            --ytlv-border:        rgba(255,255,255,0.1);
            --ytlv-text-primary:  #f1f1f1;
            --ytlv-text-secondary:#aaaaaa;
            --ytlv-text-muted:    #717171;
            --ytlv-accent:        #ff0000;
            --ytlv-blue:          #3ea6ff;
            --ytlv-radius-sm:     4px;
            --ytlv-radius-md:     8px;
            --ytlv-radius-lg:     12px;
            --ytlv-radius-full:   100px;
            --ytlv-shadow:        0 4px 20px rgba(0,0,0,0.5), 0 1px 4px rgba(0,0,0,0.3);
            --ytlv-chip-hover-bg:       rgba(255,255,255,0.1);
            --ytlv-chip-active-bg:      rgba(255,255,255,0.15);
            --ytlv-chip-active-border:  rgba(255,255,255,0.35);
            --ytlv-switch-off:          rgba(255,255,255,0.2);
            --ytlv-input-bg:            rgba(255,255,255,0.06);
            --ytlv-input-border:        rgba(255,255,255,0.12);
            --ytlv-input-border-focus:  rgba(255,255,255,0.35);
            --ytlv-input-bg-focus:      rgba(255,255,255,0.1);
            --ytlv-toggle-row-hover:    rgba(255,255,255,0.04);
            --ytlv-scrollbar-thumb:     rgba(255,255,255,0.12);
            --ytlv-shortcut-bg:         rgba(255,255,255,0.06);
            --ytlv-shortcut-border:     rgba(255,255,255,0.1);
            --ytlv-reset-border:        rgba(255,255,255,0.12);
            --ytlv-reset-hover-bg:      rgba(255,255,255,0.08);
            --ytlv-reset-hover-border:  rgba(255,255,255,0.3);
            --ytlv-reset-active-bg:     rgba(255,255,255,0.14);
            --ytlv-slider-track-bg:     rgba(255,255,255,0.15);
            --ytlv-thumb-border:        #0f0f0f;
            --ytlv-thumb-shadow:        rgba(255,255,255,0.3);
        }
 
        /* ── Light theme overrides for panel ── */
        #yt-lv-panel.panel-light {
            --ytlv-bg:            #ffffff;
            --ytlv-bg-elevated:   #f2f2f2;
            --ytlv-surface:       #f9f9f9;
            --ytlv-border:        rgba(0,0,0,0.1);
            --ytlv-text-primary:  #0f0f0f;
            --ytlv-text-secondary:#606060;
            --ytlv-text-muted:    #909090;
            --ytlv-blue:          #065fd4;
            --ytlv-shadow:        0 4px 20px rgba(0,0,0,0.15), 0 1px 4px rgba(0,0,0,0.08);
            --ytlv-chip-hover-bg:       rgba(0,0,0,0.07);
            --ytlv-chip-active-bg:      rgba(0,0,0,0.1);
            --ytlv-chip-active-border:  rgba(0,0,0,0.3);
            --ytlv-switch-off:          rgba(0,0,0,0.18);
            --ytlv-input-bg:            rgba(0,0,0,0.04);
            --ytlv-input-border:        rgba(0,0,0,0.12);
            --ytlv-input-border-focus:  rgba(0,0,0,0.3);
            --ytlv-input-bg-focus:      rgba(0,0,0,0.07);
            --ytlv-toggle-row-hover:    rgba(0,0,0,0.04);
            --ytlv-scrollbar-thumb:     rgba(0,0,0,0.15);
            --ytlv-shortcut-bg:         rgba(0,0,0,0.05);
            --ytlv-shortcut-border:     rgba(0,0,0,0.12);
            --ytlv-reset-border:        rgba(0,0,0,0.15);
            --ytlv-reset-hover-bg:      rgba(0,0,0,0.06);
            --ytlv-reset-hover-border:  rgba(0,0,0,0.3);
            --ytlv-reset-active-bg:     rgba(0,0,0,0.1);
            --ytlv-slider-track-bg:     rgba(0,0,0,0.15);
            --ytlv-thumb-border:        #ffffff;
            --ytlv-thumb-shadow:        rgba(0,0,0,0.25);
            scrollbar-color: rgba(0,0,0,0.15) transparent;
        }
        #yt-lv-panel.panel-light::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); }
 
        /* ── Hide Shorts ── */
        html.hide-shorts ${FEED} ytd-rich-section-renderer:has(ytd-rich-shelf-renderer[is-shorts]),
        html.hide-shorts ${FEED} ytd-rich-shelf-renderer[is-shorts] {
            display: none !important;
        }
 
        /* ── Toggle Buttons — YouTube glass-chip style ── */
        #view-toggle-container {
            display: flex; align-items: center; gap: 6px; padding-left: 8px; z-index: 2018;
        }
        .view-toggle-btn {
            display: flex;
            align-items: center;
            gap: 6px;
            padding: 0 12px 0 10px;
            height: 32px;
            background: rgba(255,255,255,0.1);
            border: none;
            outline: none;
            border-radius: 100px;
            cursor: pointer;
            color: var(--yt-spec-text-primary, #f1f1f1);
            font-family: "Roboto", "Arial", sans-serif;
            font-size: 13px;
            font-weight: 500;
            white-space: nowrap;
            transition: background 0.15s, color 0.15s;
        }
        .view-toggle-btn:focus-visible {
            outline: 2px solid var(--yt-spec-call-to-action, #3ea6ff);
            outline-offset: 2px;
        }
        .view-toggle-btn:hover  { background: rgba(255,255,255,0.18); }
        .view-toggle-btn.active {
            background: var(--yt-spec-text-primary, #f1f1f1);
            color: var(--yt-spec-base-background, #0f0f0f);
        }
        .view-toggle-btn svg { width: 16px; height: 16px; fill: currentColor; flex-shrink: 0; }
        .view-toggle-btn .vt-label { font-size: 13px; font-weight: 500; line-height: 1; }
        html:not([dark]) .view-toggle-btn            { background: rgba(0,0,0,0.05); color: var(--yt-spec-text-primary, #0f0f0f); }
        html:not([dark]) .view-toggle-btn:hover      { background: rgba(0,0,0,0.1); }
        html:not([dark]) .view-toggle-btn.active     { background: var(--yt-spec-text-primary, #0f0f0f); color: #fff; }
 
        /* ── Grid Override ── */
        html.list-view-active ${FEED} ytd-rich-grid-renderer {
            --ytd-rich-grid-items-per-row: 1 !important;
            --ytd-rich-grid-posts-per-row: 1 !important;
            width: 100% !important; max-width: 100% !important; margin: 0 !important;
        }
        html.list-view-active ${FEED} #contents {
            width: 100% !important; max-width: 100% !important;
        }
 
        /* ── Item Container ── */
        ${FEED_ITEM} {
            width: 100% !important; max-width: var(--list-container-width) !important;
            padding-bottom: 16px !important; margin: 0 auto 16px auto !important;
            border-bottom: 1px solid #3F3F3F !important;
        }
        ${FEED_ITEM}:last-child { border-bottom: none !important; }
 
        /* ── Lockup Row Layout ── */
        ${FEED_ITEM} .yt-lockup-view-model {
            display: flex !important; flex-direction: row !important;
            align-items: flex-start !important; gap: 16px !important;
            width: 100% !important; justify-content: flex-start !important;
            position: relative !important;
            padding-top: calc(var(--header-height) + var(--channel-info-padding-bottom)) !important;
            isolation: isolate;
        }
 
        /* ── Thumbnail ── */
        html.list-view-active ${FEED} .yt-lockup-view-model__content-image {
            width: var(--thumbnail-width) !important; min-width: var(--thumbnail-width) !important;
            max-width: var(--thumbnail-width) !important; flex-shrink: 0 !important;
            display: block !important; margin: 0 !important;
            border-radius: 12px !important; overflow: hidden !important;
            position: relative !important; z-index: auto !important;
        }
 
        /* ── Metadata Reset ── */
        html.list-view-active ${FEED} :is(
            .yt-lockup-view-model__metadata,
            yt-lockup-metadata-view-model,
            .yt-lockup-metadata-view-model,
            .yt-lockup-metadata-view-model__text-container,
            yt-content-metadata-view-model
        ) { position: static !important; transform: none !important; contain: none !important; }
 
        /* ── Title ── */
        html.list-view-active ${FEED} .yt-lockup-metadata-view-model__title {
            font-size: var(--title-font-size) !important; line-height: 1.3 !important;
            margin-bottom: 6px !important; max-width: 90% !important; display: block !important;
        }
 
        /* ── Avatar ── */
        html.list-view-active ${FEED} .yt-lockup-metadata-view-model__avatar {
            position: absolute !important; top: 0 !important; left: 0 !important;
            width: 32px !important; height: 32px !important;
            z-index: auto !important; margin: 0 !important; border-radius: 50% !important;
        }
        html.list-view-active ${FEED} .custom-avatar-link {
            display: block !important; width: 100% !important; height: 100% !important;
            border-radius: 50% !important; cursor: pointer !important;
        }
        html.list-view-active ${FEED} .yt-lockup-metadata-view-model__avatar img {
            width: 100% !important; height: 100% !important;
            display: block !important; border-radius: 50% !important;
        }
 
        /* ── Cloned Channel Name ── */
        ${FEED} .cloned-channel-name { display: none !important; }
        html.list-view-active ${FEED} .cloned-channel-name {
            position: absolute !important; top: 0 !important; left: 42px !important;
            height: 32px !important; z-index: auto !important; background: transparent !important;
            padding: 0 !important; display: flex !important; align-items: center !important;
            pointer-events: auto !important;
        }
        html.list-view-active ${FEED} .cloned-channel-name :is(a, span) {
            color: var(--yt-spec-text-primary) !important; font-weight: 500 !important;
            font-size: var(--title-font-size) !important; text-shadow: none !important;
            text-decoration: none !important; line-height: 1 !important;
        }
        html.list-view-active ${FEED} .cloned-channel-name span[role="separator"] {
            display: none !important;
        }
 
        /* ── Content Metadata Rows ── */
        html.list-view-active ${FEED} yt-content-metadata-view-model {
            display: block !important; width: 100% !important;
        }
        html.list-view-active ${FEED} yt-content-metadata-view-model
            .yt-content-metadata-view-model__metadata-row:not(.cloned-channel-name) {
            display: inline-flex !important; align-items: baseline !important;
            margin: 0 !important; padding: 0 !important;
            font-size: var(--meta-font-size) !important; color: #aaa !important;
            white-space: nowrap !important;
        }
        html.list-view-active ${FEED} yt-content-metadata-view-model
            .yt-content-metadata-view-model__metadata-row:not(.cloned-channel-name) * {
            font-size: var(--meta-font-size) !important; line-height: 1.4 !important;
        }
        html.list-view-active ${FEED} yt-content-metadata-view-model
            .yt-content-metadata-view-model__metadata-row:not(.cloned-channel-name):first-of-type {
            margin-right: 8px !important;
        }
        html.list-view-active ${FEED} yt-content-metadata-view-model
            .yt-content-metadata-view-model__metadata-row:not(.cloned-channel-name) a {
            color: #aaa !important; font-weight: 400 !important; text-decoration: none !important;
        }
        html.list-view-active ${FEED} yt-content-metadata-view-model
            .yt-content-metadata-view-model__metadata-row:not(.cloned-channel-name) a:hover {
            color: #fff !important;
        }
        html.list-view-active ${FEED} yt-content-metadata-view-model
            .yt-content-metadata-view-model__metadata-row:not(.cloned-channel-name) span[role="separator"] {
            display: inline-block !important; margin: 0 4px !important;
        }
 
        /* ── Menu Button ── */
        html.list-view-active ${FEED} .yt-lockup-metadata-view-model__menu-button {
            position: absolute !important;
            top: calc(var(--header-height) + var(--channel-info-padding-bottom)) !important;
            right: 0 !important;
        }
 
        /* ── Sections & Shelves ── */
        html.list-view-active ${FEED} ytd-rich-section-renderer > #content {
            max-width: var(--list-container-width) !important; margin: 0 auto !important;
        }
        html.list-view-active ${FEED} ytd-rich-section-renderer,
        html.list-view-active ${FEED} ytd-shelf-renderer,
        html.list-view-active ${FEED} ytd-shelf-renderer h2 {
            margin: 0 !important; padding: 0 !important;
        }
 
        /* ── Notify Button ── */
        html.list-view-active :is(lockup-attachments-view-model, .ytLockupAttachmentsViewModelHost) {
            width: var(--notify-width) !important; max-width: 100% !important;
        }
 
        /* ── Dismissed / Replaced Items ── */
        ${FEED_ITEM}:has(.ytDismissibleItemReplacedContent) .yt-lockup-view-model {
            display: block !important; padding-top: 0 !important; height: auto !important;
        }
        html.list-view-active ytd-rich-item-renderer:has(.ytDismissibleItemReplacedContent)
            :is(.ytDismissibleItemAspectRatio16By9, .ytDismissibleItemReplacedContent) {
            padding: 0 !important; aspect-ratio: auto !important;
            height: auto !important; min-height: 0 !important;
        }
        html.list-view-active ytd-rich-item-renderer:has(.ytDismissibleItemReplacedContent)
            .ytDismissibleItemAspectRatio16By9::before {
            display: none !important; padding-bottom: 0 !important;
        }
        html.list-view-active ytd-rich-item-renderer:has(.ytDismissibleItemReplacedContent)
            .ytDismissibleItemAspectRatioContainer {
            position: static !important; padding: 24px !important;
            display: flex !important; justify-content: center !important;
            align-items: center !important; height: auto !important;
        }
        html.list-view-active ytd-rich-item-renderer:has(.ytDismissibleItemReplacedContent)
            notification-multi-action-renderer {
            position: static !important; height: auto !important;
            width: auto !important; margin: 0 auto !important;
        }
 
        /* ── Hide Dividers ── */
        html.list-view-active.hide-dividers ${FEED}
            ytd-rich-grid-renderer > #contents > ytd-rich-item-renderer {
            border-bottom: none !important;
        }
 
        /* ── Video Descriptions ── */
        .custom-description {
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            overflow: hidden;
            font-size: var(--meta-font-size);
            line-height: 1.5;
            color: #9a9a9a;
            margin-top: 8px;
            width: 100%;
            max-width: 95%;
            white-space: normal;
        }
        html:not(.show-descriptions) .custom-description { display: none !important; }
        html:not(.list-view-active) .custom-description  { display: none !important; }
 
        /* Shimmer skeleton state */
        .custom-description.desc-skeleton {
            display: block !important;
            -webkit-line-clamp: unset !important;
            overflow: hidden !important;
            color: transparent !important;
            pointer-events: none !important;
        }
        .custom-description.desc-skeleton::before,
        .custom-description.desc-skeleton::after {
            content: '';
            display: block;
            border-radius: 6px;
            height: 11px;
            background-color: var(--ytlv-skel-base, rgba(255,255,255,.10));
            background-image: linear-gradient(
                90deg,
                var(--ytlv-skel-base, rgba(255,255,255,.10)) 0%,
                var(--yt-spec-10-percent-layer, rgba(255,255,255,.22)) 50%,
                var(--ytlv-skel-base, rgba(255,255,255,.10)) 100%
            );
            background-size: 220% 100%;
            background-position: var(${SHIMMER_VAR}, 200%) 0;
            will-change: background-position;
        }
        .custom-description.desc-skeleton::before { width: 78%; margin-bottom: 6px; }
        .custom-description.desc-skeleton::after  { width: 55%; }
 
        html[dark]       { --ytlv-skel-base: rgba(255,255,255,.10); }
        html:not([dark]) { --ytlv-skel-base: rgba(0,0,0,.10); }
 
        /* ══════════════════════════════════════════════════════════
           SETTINGS PANEL
        ══════════════════════════════════════════════════════════ */
 
        #yt-lv-panel-overlay {
            position: fixed; inset: 0; z-index: 2147483645;
            background: transparent; display: none; pointer-events: none;
        }
        #yt-lv-panel-overlay.open { display: block; pointer-events: auto; }
 
        /* Panel shell */
        #yt-lv-panel {
            position: fixed;
            top: 56px;
            right: 16px;
            width: 360px;
            max-height: calc(100vh - 72px);
            overflow-y: auto;
            overflow-x: hidden;
            font-family: "Roboto", "Arial", sans-serif;
            font-size: 14px;
            background: var(--ytlv-bg, #0f0f0f);
            color: var(--ytlv-text-primary, #f1f1f1);
            border-radius: var(--ytlv-radius-lg, 12px);
            border: 1px solid var(--ytlv-border, rgba(255,255,255,0.1));
            box-shadow: var(--ytlv-shadow);
            z-index: 2147483647;
            box-sizing: border-box;
            display: none;
            scrollbar-width: thin;
            scrollbar-color: var(--ytlv-scrollbar-thumb, rgba(255,255,255,0.12)) transparent;
            transform-origin: top right;
            transition: background 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
        }
        #yt-lv-panel::-webkit-scrollbar       { width: 6px; }
        #yt-lv-panel::-webkit-scrollbar-thumb { background: var(--ytlv-scrollbar-thumb, rgba(255,255,255,0.12)); border-radius: 3px; }
        #yt-lv-panel::-webkit-scrollbar-track { background: transparent; }
 
        #yt-lv-panel.open {
            display: block;
            animation: ytlv-panel-in 0.2s cubic-bezier(0.4, 0, 0.2, 1) both;
        }
 
        #yt-lv-panel.panel-transparent {
            background: rgba(15,15,15,0.88);
            backdrop-filter: blur(20px) saturate(1.4);
            -webkit-backdrop-filter: blur(20px) saturate(1.4);
        }
        #yt-lv-panel.panel-light.panel-transparent {
            background: rgba(255,255,255,0.88);
        }
 
        @keyframes ytlv-panel-in {
            from { opacity: 0; transform: scale(0.96) translateY(-6px); }
            to   { opacity: 1; transform: scale(1)    translateY(0);    }
        }
 
        /* Header */
        #yt-lv-panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 14px 16px 12px;
            border-bottom: 1px solid var(--ytlv-border, rgba(255,255,255,0.1));
            cursor: move;
            user-select: none;
            position: sticky;
            top: 0;
            background: var(--ytlv-bg, #0f0f0f);
            z-index: 2;
            border-radius: var(--ytlv-radius-lg) var(--ytlv-radius-lg) 0 0;
            transition: background 0.2s, border-color 0.2s;
        }
        #yt-lv-panel.panel-transparent #yt-lv-panel-header {
            background: rgba(15,15,15,0.82);
            backdrop-filter: blur(20px) saturate(1.4);
            -webkit-backdrop-filter: blur(20px) saturate(1.4);
        }
        #yt-lv-panel.panel-light.panel-transparent #yt-lv-panel-header {
            background: rgba(255,255,255,0.82);
            backdrop-filter: blur(20px) saturate(1.4);
            -webkit-backdrop-filter: blur(20px) saturate(1.4);
        }
        #yt-lv-panel-header-icon {
            width: 20px; height: 20px; flex-shrink: 0;
            fill: var(--ytlv-text-primary, #f1f1f1);
        }
        #yt-lv-panel-title {
            flex: 1;
            font-size: 14px;
            font-weight: 500;
            color: var(--ytlv-text-primary, #f1f1f1);
            letter-spacing: 0.01em;
        }
        #yt-lv-panel-shortcut {
            font-size: 11px;
            color: var(--ytlv-text-muted, #717171);
            background: var(--ytlv-shortcut-bg, rgba(255,255,255,0.06));
            border: 1px solid var(--ytlv-shortcut-border, rgba(255,255,255,0.1));
            border-radius: var(--ytlv-radius-sm, 4px);
            padding: 2px 6px;
            font-family: monospace;
            letter-spacing: 0.05em;
        }
 
        /* Theme toggle button */
        #yt-lv-theme-btn {
            width: 30px; height: 30px;
            display: flex; align-items: center; justify-content: center;
            background: none; border: none; cursor: pointer;
            color: var(--ytlv-text-muted, #717171);
            border-radius: 50%;
            flex-shrink: 0;
            transition: background 0.15s, color 0.15s;
            padding: 0; position: relative;
        }
        #yt-lv-theme-btn:hover {
            background: var(--ytlv-chip-hover-bg, rgba(255,255,255,0.1));
            color: var(--ytlv-text-primary, #f1f1f1);
        }
        #yt-lv-theme-btn svg {
            width: 18px; height: 18px; fill: currentColor; pointer-events: none;
            transition: transform 0.3s cubic-bezier(0.4,0,0.2,1), opacity 0.2s;
            position: absolute;
        }
        /* Dark (default): sun visible */
        #yt-lv-panel:not(.panel-light) #yt-lv-theme-btn .icon-sun  { opacity: 1; transform: rotate(0deg)   scale(1);   }
        #yt-lv-panel:not(.panel-light) #yt-lv-theme-btn .icon-moon { opacity: 0; transform: rotate(90deg)  scale(0.5); }
        /* Light: moon visible */
        #yt-lv-panel.panel-light #yt-lv-theme-btn .icon-sun  { opacity: 0; transform: rotate(-90deg) scale(0.5); }
        #yt-lv-panel.panel-light #yt-lv-theme-btn .icon-moon { opacity: 1; transform: rotate(0deg)   scale(1);   }
 
        #yt-lv-panel-close {
            width: 36px; height: 36px;
            display: flex; align-items: center; justify-content: center;
            background: none; border: none; cursor: pointer;
            color: var(--ytlv-text-muted, #717171);
            border-radius: 50%;
            transition: background 0.15s, color 0.15s;
            flex-shrink: 0;
        }
        #yt-lv-panel-close:hover {
            background: var(--ytlv-chip-hover-bg, rgba(255,255,255,0.1));
            color: var(--ytlv-text-primary, #f1f1f1);
        }
        #yt-lv-panel-close svg { width: 18px; height: 18px; fill: currentColor; pointer-events: none; }
 
        /* Panel body */
        #yt-lv-panel-body { padding: 12px 0 8px; }
 
        .ytlv-section-label {
            font-size: 11px;
            font-weight: 500;
            color: var(--ytlv-text-muted, #717171);
            text-transform: uppercase;
            letter-spacing: 0.08em;
            padding: 0 16px;
            margin: 4px 0 8px;
        }
 
        .ytlv-divider {
            height: 1px;
            background: var(--ytlv-border, rgba(255,255,255,0.1));
            margin: 10px 0;
        }
 
        /* View mode chips */
        #ytlv-view-chips { display: flex; gap: 8px; padding: 0 16px; margin-bottom: 4px; }
        .ytlv-chip {
            display: flex;
            align-items: center;
            gap: 6px;
            padding: 6px 14px 6px 10px;
            border-radius: var(--ytlv-radius-full, 100px);
            border: 1px solid var(--ytlv-border, rgba(255,255,255,0.15));
            background: transparent;
            color: var(--ytlv-text-secondary, #aaa);
            font-size: 13px;
            font-weight: 400;
            cursor: pointer;
            transition: all 0.15s;
            user-select: none;
        }
        .ytlv-chip:hover {
            background: var(--ytlv-chip-hover-bg, rgba(255,255,255,0.1));
            color: var(--ytlv-text-primary, #f1f1f1);
            border-color: var(--ytlv-chip-active-border, rgba(255,255,255,0.25));
        }
        .ytlv-chip.active {
            background: var(--ytlv-chip-active-bg, rgba(255,255,255,0.15));
            color: var(--ytlv-text-primary, #f1f1f1);
            border-color: var(--ytlv-chip-active-border, rgba(255,255,255,0.35));
            font-weight: 500;
        }
        .ytlv-chip svg { width: 16px; height: 16px; fill: currentColor; flex-shrink: 0; }
 
        /* Slider rows */
        .ytlv-slider-row   { padding: 6px 16px; display: flex; flex-direction: column; gap: 5px; }
        .ytlv-slider-label { font-size: 13px; color: var(--ytlv-text-secondary, #aaa); }
        .ytlv-slider-track { display: flex; align-items: center; gap: 8px; }
 
        .ytlv-slider-track input[type="range"] {
            flex: 1; height: 3px;
            appearance: none; -webkit-appearance: none;
            background: var(--ytlv-slider-track-bg, rgba(255,255,255,0.15));
            border-radius: 2px; outline: none; cursor: pointer;
            accent-color: var(--ytlv-text-primary, #f1f1f1);
        }
        .ytlv-slider-track input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 14px; height: 14px; border-radius: 50%;
            background: var(--ytlv-text-primary, #f1f1f1);
            border: 2px solid var(--ytlv-thumb-border, #0f0f0f);
            box-shadow: 0 0 0 1px var(--ytlv-thumb-shadow, rgba(255,255,255,0.3));
            transition: transform 0.1s;
        }
        .ytlv-slider-track input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .ytlv-slider-track input[type="range"]::-moz-range-thumb {
            width: 14px; height: 14px; border-radius: 50%;
            background: var(--ytlv-text-primary, #f1f1f1);
            border: 2px solid var(--ytlv-thumb-border, #0f0f0f);
        }
        .ytlv-num-input {
            width: 54px;
            background: var(--ytlv-input-bg, rgba(255,255,255,0.06));
            border: 1px solid var(--ytlv-input-border, rgba(255,255,255,0.12));
            border-radius: var(--ytlv-radius-sm, 4px);
            color: var(--ytlv-text-primary, #f1f1f1);
            font-size: 12px; padding: 4px 6px; text-align: right;
            font-variant-numeric: tabular-nums;
            transition: border-color 0.15s, background 0.15s;
        }
        .ytlv-num-input:focus {
            outline: none;
            border-color: var(--ytlv-input-border-focus, rgba(255,255,255,0.35));
            background: var(--ytlv-input-bg-focus, rgba(255,255,255,0.1));
        }
 
        /* Toggle rows */
        .ytlv-toggle-row {
            display: flex; align-items: center; justify-content: space-between;
            padding: 9px 16px;
            transition: background 0.12s; cursor: pointer; gap: 12px;
        }
        .ytlv-toggle-row:hover { background: var(--ytlv-toggle-row-hover, rgba(255,255,255,0.04)); }
        .ytlv-toggle-label { font-size: 13px; color: var(--ytlv-text-secondary, #aaa); flex: 1; cursor: pointer; }
        .ytlv-toggle-warn  { font-size: 11px; color: var(--ytlv-text-muted, #717171); padding: 0 16px 6px; line-height: 1.4; }
 
        /* YouTube-style toggle switch */
        .ytlv-switch { position: relative; width: 36px; height: 20px; flex-shrink: 0; }
        .ytlv-switch input { opacity: 0; width: 0; height: 0; position: absolute; }
        .ytlv-switch-track {
            position: absolute; inset: 0;
            background: var(--ytlv-switch-off, rgba(255,255,255,0.2));
            border-radius: 10px; transition: background 0.2s; cursor: pointer;
        }
        .ytlv-switch input:checked + .ytlv-switch-track { background: var(--ytlv-blue, #3ea6ff); }
        .ytlv-switch-thumb {
            position: absolute; top: 2px; left: 2px;
            width: 16px; height: 16px; border-radius: 50%; background: #fff;
            transition: transform 0.2s cubic-bezier(0.4,0,0.2,1), box-shadow 0.15s;
            pointer-events: none; box-shadow: 0 1px 3px rgba(0,0,0,0.4);
        }
        .ytlv-switch input:checked ~ .ytlv-switch-thumb { transform: translateX(16px); }
 
        /* Footer */
        #yt-lv-panel-footer { padding: 8px 16px 14px; display: flex; flex-direction: column; gap: 6px; }
        #yt-lv-cache-stats  { font-size: 11px; color: var(--ytlv-text-muted, #717171); text-align: center; }
        .ytlv-reset-btn {
            width: 100%; padding: 9px 16px;
            background: transparent;
            border: 1px solid var(--ytlv-reset-border, rgba(255,255,255,0.12));
            color: var(--ytlv-text-secondary, #aaa);
            border-radius: var(--ytlv-radius-full, 100px);
            cursor: pointer;
            font-size: 13px; font-family: "Roboto","Arial",sans-serif; font-weight: 500;
            letter-spacing: 0.01em; transition: all 0.15s;
        }
        .ytlv-reset-btn:hover {
            background: var(--ytlv-reset-hover-bg, rgba(255,255,255,0.08));
            border-color: var(--ytlv-reset-hover-border, rgba(255,255,255,0.3));
            color: var(--ytlv-text-primary, #f1f1f1);
        }
        .ytlv-reset-btn:active { background: var(--ytlv-reset-active-bg, rgba(255,255,255,0.14)); }
    `);
 
    // ══════════════════════════════════════════════════════════════════
    // STATE
    // ══════════════════════════════════════════════════════════════════
    let listViewEnabled  = true;
    let layoutFixDone    = false;
    let lastUrl          = location.href;
    let rafPending       = false;
    let watchLaterDone   = false;
    let isSliderDragging = false;
    let _sliderRaf       = 0;
    const _pendingCSS    = {};
 
    // WeakSets — skip already-processed items on repeat calls
    let _processedHeaders = new WeakSet();
    let _processedAvatars = new WeakSet();
 
    // Targeted MutationObserver (narrower than body)
    let _feedMo       = null;
    let _feedMoTarget = null;
 
    // ══════════════════════════════════════════════════════════════════
    // VIEW MODE CONTROL
    // ══════════════════════════════════════════════════════════════════
    function setListView(enabled) {
        listViewEnabled = enabled;
        document.documentElement.classList.toggle('list-view-active', enabled);
        updateToggleUI();
        if (!enabled) stopShimmer();
        if (enabled && isTargetPage()) {
            injectLayoutFix();
            scheduleUpdate();
        }
    }
 
    function applySettings(s) {
        settings = { ...DEFAULT_SETTINGS, ...s };
        const root = document.documentElement;
        for (const { key, unit, cssVar } of SLIDER_CONFIGS) {
            root.style.setProperty(cssVar, settings[key] + unit);
        }
        root.classList.toggle('hide-dividers',     !!settings.hideDividers);
        root.classList.toggle('hide-shorts',       !!settings.hideShorts);
        root.classList.toggle('show-descriptions', !!settings.showDescriptions);
        applyPanelTransparency(!!settings.panelTransparent);
        applyPanelLight(!!settings.panelLight);
        setListView(settings.viewModeSubs !== 'grid');
        updateShortsScroll();
        processMostRelevant();
    }
 
    function applyPanelTransparency(enabled) {
        document.getElementById('yt-lv-panel')?.classList.toggle('panel-transparent', enabled);
    }
 
    function applyPanelLight(enabled) {
        document.getElementById('yt-lv-panel')?.classList.toggle('panel-light', enabled);
    }
 
    function scheduleUpdate() {
        if (rafPending) return;
        rafPending = true;
        requestAnimationFrame(() => { rafPending = false; handleDomChanges(); });
    }
 
    // ══════════════════════════════════════════════════════════════════
    // SMOOTH SLIDER HELPERS
    // ══════════════════════════════════════════════════════════════════
    function flushPendingCSS() {
        if (_sliderRaf) { cancelAnimationFrame(_sliderRaf); _sliderRaf = 0; }
        const root = document.documentElement;
        for (const [prop, val] of Object.entries(_pendingCSS)) root.style.setProperty(prop, val);
        for (const k in _pendingCSS) delete _pendingCSS[k];
    }
 
    function liveApply(key, value) {
        settings[key] = value;
        const cfg = SLIDER_CONFIGS.find(c => c.key === key);
        if (!cfg) return;
        _pendingCSS[cfg.cssVar] = value + cfg.unit;
        if (!_sliderRaf) {
            _sliderRaf = requestAnimationFrame(() => {
                const root = document.documentElement;
                for (const [prop, val] of Object.entries(_pendingCSS)) root.style.setProperty(prop, val);
                for (const k in _pendingCSS) delete _pendingCSS[k];
                _sliderRaf = 0;
            });
        }
    }
 
    document.addEventListener('pointerup', () => { isSliderDragging = false; }, true);
 
    // ══════════════════════════════════════════════════════════════════
    // SVG ICON PATHS
    // ══════════════════════════════════════════════════════════════════
    const ICON_SETTINGS = 'M19.14 12.94c.04-.3.06-.61.06-.94s-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z';
    const ICON_CLOSE    = 'M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z';
    const ICON_SUN      = 'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58a.996.996 0 00-1.41 0 .996.996 0 000 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37a.996.996 0 00-1.41 0 .996.996 0 000 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 000-1.41l-1.06-1.06zm1.06-12.37l-1.06 1.06a.996.996 0 000 1.41c.39.39 1.03.39 1.41 0l1.06-1.06a.996.996 0 000-1.41-.996.996 0 00-1.41 0zM7.05 18.36l-1.06 1.06a.996.996 0 000 1.41c.39.39 1.03.39 1.41 0l1.06-1.06a.996.996 0 000-1.41-.99.99 0 00-1.41 0z';
    const ICON_MOON     = 'M12 3a9 9 0 109 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 01-4.4 2.26 5.403 5.403 0 01-3.14-9.8c-.44-.06-.9-.1-1.36-.1z';
 
    // ══════════════════════════════════════════════════════════════════
    // SETTINGS PANEL
    // ══════════════════════════════════════════════════════════════════
    function buildPanel() {
        if (document.getElementById('yt-lv-panel')) return;
 
        const overlay = el('div', { id: 'yt-lv-panel-overlay' });
        overlay.addEventListener('click', closePanel);
 
        const panel = el('div', { id: 'yt-lv-panel' });
        panel.addEventListener('click', e => e.stopPropagation());
 
        // ── Header ──
        const settingsIcon = makeSVGIcon(ICON_SETTINGS, 20);
        settingsIcon.id = 'yt-lv-panel-header-icon';
 
        const closeIcon = makeSVGIcon(ICON_CLOSE, 18);
        const closeBtn  = el('button', { id: 'yt-lv-panel-close', title: 'Close (Esc)' }, [closeIcon]);
        closeBtn.addEventListener('click', closePanel);
 
        const sunIcon  = makeSVGIcon(ICON_SUN,  18); sunIcon.classList.add('icon-sun');
        const moonIcon = makeSVGIcon(ICON_MOON, 18); moonIcon.classList.add('icon-moon');
        const themeBtn = el('button', { id: 'yt-lv-theme-btn', title: 'Toggle light/dark panel' }, [sunIcon, moonIcon]);
        themeBtn.addEventListener('click', () => {
            const p = document.getElementById('yt-lv-panel');
            const isLight = p.classList.toggle('panel-light');
            settings.panelLight = isLight;
            setSetting('panelLight', isLight);
        });
 
        const header = el('div', { id: 'yt-lv-panel-header' }, [
            settingsIcon,
            el('span', { id: 'yt-lv-panel-title',    textContent: 'List View' }),
            el('span', { id: 'yt-lv-panel-shortcut', textContent: 'Alt+L' }),
            themeBtn,
            closeBtn,
        ]);
        panel.appendChild(header);
 
        const body = el('div', { id: 'yt-lv-panel-body' });
 
        // ── View Mode Chips ──
        body.appendChild(el('div', { className: 'ytlv-section-label', textContent: 'View mode' }));
 
        const gridChip = el('div', { id: 'lv-icon-grid', className: 'ytlv-chip', title: 'Grid View' });
        const gridSvg  = createSVG(GRID_RECTS);
        gridSvg.setAttribute('width', '16'); gridSvg.setAttribute('height', '16');
        gridChip.append(gridSvg, document.createTextNode('Grid'));
        gridChip.addEventListener('click', () => {
            settings.viewModeSubs = 'grid'; setSetting('viewModeSubs', 'grid');
            setListView(false); updatePanelChips();
        });
 
        const listChip = el('div', { id: 'lv-icon-list', className: 'ytlv-chip', title: 'List View' });
        const listSvg  = createSVG(LIST_RECTS);
        listSvg.setAttribute('width', '16'); listSvg.setAttribute('height', '16');
        listChip.append(listSvg, document.createTextNode('List'));
        listChip.addEventListener('click', () => {
            settings.viewModeSubs = 'list'; setSetting('viewModeSubs', 'list');
            setListView(true); updatePanelChips();
        });
 
        body.appendChild(el('div', { id: 'ytlv-view-chips' }, [gridChip, listChip]));
        body.appendChild(el('div', { className: 'ytlv-divider' }));
 
        // ── Sliders ──
        body.appendChild(el('div', { className: 'ytlv-section-label', textContent: 'Layout' }));
 
        for (const { key, label, min, max } of SLIDER_CONFIGS) {
            const slider   = el('input', { type: 'range',  id: `lv-${key}-slider`, min, max, step: '1' });
            const numInput = el('input', { type: 'number', id: `lv-${key}`,        min, max, step: '1', className: 'ytlv-num-input' });
 
            slider.addEventListener('pointerdown', () => { isSliderDragging = true; });
            slider.addEventListener('input',  () => { numInput.value = slider.value; liveApply(key, +slider.value); });
            slider.addEventListener('change', () => { flushPendingCSS(); isSliderDragging = false; setSetting(key, +slider.value); });
            numInput.addEventListener('input', () => {
                const v = +numInput.value;
                if (v >= min && v <= max) { slider.value = v; liveApply(key, v); }
            });
            numInput.addEventListener('change', () => {
                const v = Math.min(max, Math.max(min, +numInput.value));
                numInput.value = v; slider.value = v;
                flushPendingCSS(); setSetting(key, v); liveApply(key, v);
            });
 
            body.appendChild(el('div', { className: 'ytlv-slider-row' }, [
                el('span', { className: 'ytlv-slider-label', textContent: label }),
                el('div',  { className: 'ytlv-slider-track' }, [slider, numInput]),
            ]));
        }
 
        body.appendChild(el('div', { className: 'ytlv-divider' }));
 
        // ── Toggles ──
        body.appendChild(el('div', { className: 'ytlv-section-label', textContent: 'Options' }));
 
        for (const { key, label, warn } of TOGGLE_CONFIGS) {
            const cbInput = el('input', { type: 'checkbox', id: `lv-${key}` });
            const track   = el('span', { className: 'ytlv-switch-track' });
            const thumb   = el('span', { className: 'ytlv-switch-thumb' });
            const sw      = el('label', { className: 'ytlv-switch', htmlFor: `lv-${key}` }, [cbInput, track, thumb]);
 
            cbInput.addEventListener('change', () => {
                setSetting(key, cbInput.checked);
                settings[key] = cbInput.checked;
                if (key === 'showDescriptions') {
                    document.documentElement.classList.toggle('show-descriptions', cbInput.checked);
                    if (cbInput.checked) { processItems(); ensureDescLoop(); }
                    else { clearDescriptions(); stopShimmer(); }
                    updateCacheStats();
                } else if (key === 'hideShorts') {
                    document.documentElement.classList.toggle('hide-shorts', cbInput.checked);
                } else if (key === 'panelTransparent') {
                    applyPanelTransparency(cbInput.checked);
                } else {
                    applySettings(getAllSettings());
                }
            });
 
            body.appendChild(el('div', { className: 'ytlv-toggle-row' }, [
                el('label', { className: 'ytlv-toggle-label', htmlFor: `lv-${key}`, textContent: label }),
                sw,
            ]));
            if (warn) {
                body.appendChild(el('div', { className: 'ytlv-toggle-warn', textContent: warn }));
            }
        }
 
        // ── Footer ──
        const statsLine = el('div', { id: 'yt-lv-cache-stats' });
        const resetBtn  = el('button', { className: 'ytlv-reset-btn', textContent: 'Reset to defaults' });
        resetBtn.addEventListener('click', () => {
            for (const [k, v] of Object.entries(DEFAULT_SETTINGS)) setSetting(k, v);
            clearDescriptions();
            applySettings(getAllSettings());
            loadPanelValues();
            updateCacheStats();
        });
 
        const footer = el('div', { id: 'yt-lv-panel-footer' }, [statsLine, resetBtn]);
        panel.append(body, el('div', { className: 'ytlv-divider' }), footer);
 
        document.documentElement.append(overlay, panel);
        makeDraggable(panel, header);
        applyPanelTransparency(!!settings.panelTransparent);
        applyPanelLight(!!settings.panelLight);
    }
 
    function updateCacheStats() {
        const statsEl = document.getElementById('yt-lv-cache-stats');
        if (!statsEl) return;
        descStoreLoad();
        const count = Object.keys(_descState.persist || {}).length;
        statsEl.textContent = count > 0 ? `${count} descriptions cached` : '';
    }
 
    function openPanel() {
        buildPanel(); loadPanelValues(); updateCacheStats();
        document.getElementById('yt-lv-panel-overlay').classList.add('open');
        document.getElementById('yt-lv-panel').classList.add('open');
    }
    function closePanel() {
        document.getElementById('yt-lv-panel-overlay')?.classList.remove('open');
        document.getElementById('yt-lv-panel')?.classList.remove('open');
    }
    function togglePanel() {
        document.getElementById('yt-lv-panel')?.classList.contains('open') ? closePanel() : openPanel();
    }
 
    function loadPanelValues() {
        const s = getAllSettings();
        for (const { key } of SLIDER_CONFIGS) {
            const slider = document.getElementById(`lv-${key}-slider`);
            const number = document.getElementById(`lv-${key}`);
            if (slider) slider.value = s[key];
            if (number) number.value = s[key];
        }
        for (const { key } of TOGGLE_CONFIGS) {
            const cb = document.getElementById(`lv-${key}`);
            if (cb) cb.checked = s[key];
        }
        updatePanelChips();
    }
 
    function updatePanelChips() {
        const isGrid = settings.viewModeSubs === 'grid';
        document.getElementById('lv-icon-grid')?.classList.toggle('active',  isGrid);
        document.getElementById('lv-icon-list')?.classList.toggle('active', !isGrid);
    }
 
    function makeDraggable(panel, handle) {
        handle.addEventListener('mousedown', e => {
            if (e.target.closest('button')) return;
            e.preventDefault();
            const rect             = panel.getBoundingClientRect();
            const [sx, sy, sl, st] = [e.clientX, e.clientY, rect.left, rect.top];
            const onMove = ev => {
                panel.style.left  = (sl + ev.clientX - sx) + 'px';
                panel.style.top   = (st + ev.clientY - sy) + 'px';
                panel.style.right = 'auto';
            };
            const onUp = () => {
                document.removeEventListener('mousemove', onMove);
                document.removeEventListener('mouseup',   onUp);
            };
            document.addEventListener('mousemove', onMove);
            document.addEventListener('mouseup',   onUp);
        });
    }
 
    GM_registerMenuCommand('⚙️ Open Settings Panel (Alt+L)', openPanel);
 
    // ══════════════════════════════════════════════════════════════════
    // KEYBOARD SHORTCUT
    // ══════════════════════════════════════════════════════════════════
    document.addEventListener('keydown', e => {
        const tag = e.target.tagName;
        if (tag === 'INPUT' || tag === 'TEXTAREA' || e.target.isContentEditable) return;
        if (e.altKey && !e.ctrlKey && !e.shiftKey && e.key.toLowerCase() === 'l') {
            e.preventDefault(); e.stopPropagation(); togglePanel();
        }
        if (e.key === 'Escape') closePanel();
    }, true);
 
    // ══════════════════════════════════════════════════════════════════
    // TOGGLE BUTTONS
    // ══════════════════════════════════════════════════════════════════
    function injectToggleButtons() {
        if (!isSubs()) return;
 
        let container = document.getElementById('view-toggle-container');
        if (!container) {
            container = el('div', { id: 'view-toggle-container' });
            const makeBtn = (id, title, rects, mode, labelText) => {
                const svg = createSVG(rects);
                svg.setAttribute('width', '16'); svg.setAttribute('height', '16');
                const label = el('span', { className: 'vt-label', textContent: labelText });
                const btn = el('button', { className: 'view-toggle-btn', id, title }, [svg, label]);
                btn.onclick = e => {
                    e.stopPropagation();
                    settings.viewModeSubs = mode;
                    setSetting('viewModeSubs', mode);
                    setListView(mode === 'list');
                    updatePanelChips();
                };
                return btn;
            };
            container.append(
                makeBtn('toggle-grid-btn', 'Grid View', GRID_RECTS, 'grid', 'Grid'),
                makeBtn('toggle-list-btn', 'List View', LIST_RECTS, 'list', 'List'),
            );
        }
 
        const subBtn = document.querySelector('ytd-shelf-renderer #subscribe-button');
        const target = subBtn?.parentElement;
        if (target && container.parentElement !== target) {
            target.appendChild(container);
            updateToggleUI();
        }
    }
 
    function updateToggleUI() {
        document.getElementById('toggle-list-btn')?.classList.toggle('active',  listViewEnabled);
        document.getElementById('toggle-grid-btn')?.classList.toggle('active', !listViewEnabled);
    }
 
    // ══════════════════════════════════════════════════════════════════
    // ITEM PROCESSING
    // ══════════════════════════════════════════════════════════════════
function processItemHeader(item) {
    if (!_processedHeaders.has(item)) {
        const lockup = item.querySelector('.yt-lockup-view-model');
        const meta   = item.querySelector('yt-content-metadata-view-model');
        const META_ROW = ':is(.yt-content-metadata-view-model__metadata-row, .ytContentMetadataViewModelMetadataRow)';
        const row    = meta?.querySelector(META_ROW);
        if (lockup && row) {
            const clone = row.cloneNode(true);
            clone.classList.add('cloned-channel-name');
            clone.querySelectorAll(':is(.yt-content-metadata-view-model__delimiter, .ytContentMetadataViewModelDelimiter)').forEach(n => n.remove());
            clone.querySelectorAll(':is(.yt-content-metadata-view-model__leading-icon, .ytContentMetadataViewModelLeadingIcon)').forEach(n => n.remove());
            clone.querySelectorAll(':is(.yt-content-metadata-view-model__metadata-text, .ytContentMetadataViewModelMetadataText)').forEach(span => {
                if (!span.querySelector('a')) span.remove();
            });
            lockup.appendChild(clone);
            _processedHeaders.add(item);
        }
    }
    if (!_processedAvatars.has(item)) {
        const avatar = item.querySelector('.yt-lockup-metadata-view-model__avatar');
        if (avatar && !avatar.querySelector('.custom-avatar-link')) {
            const link = item.querySelector('.cloned-channel-name a, yt-content-metadata-view-model a');
            if (link) {
                const anchor = el('a', { href: link.href, className: 'custom-avatar-link' });
                while (avatar.firstChild) anchor.appendChild(avatar.firstChild);
                avatar.appendChild(anchor);
                _processedAvatars.add(item);
            }
        }
    }
}
 
    function ensureDescriptionEl(item) {
        if (!settings.showDescriptions || !listViewEnabled) return;
        const metaContainer = item.querySelector('yt-content-metadata-view-model');
        if (!metaContainer) return;
        const linkEl = item.querySelector('a#video-title-link, a.yt-lockup-metadata-view-model__title');
        if (!linkEl) return;
        const vid = extractVideoId(linkEl.href);
        if (!vid) return;
 
        // Ensure the DOM element exists with a skeleton placeholder
        let descEl = metaContainer.querySelector('.custom-description');
        if (!descEl) {
            descEl = el('div', { className: 'custom-description' });
            metaContainer.appendChild(descEl);
        }
        if (descEl.dataset.vid !== vid) {
            descEl.dataset.vid = vid;
            descEl.textContent = '';
            descEl.style.display = '';
            descEl.classList.add('desc-skeleton');
        }
 
        // Kick off the fetch (no-ops if cached or already in flight)
        fetchDescription(item);
    }
 
    function processItems() {
        for (const item of document.querySelectorAll('ytd-rich-item-renderer')) {
            if (item.querySelector('ytd-ad-slot-renderer')) { item.remove(); continue; }
            processItemHeader(item);
            ensureDescriptionEl(item);
        }
    }
 
    function clearDescriptions() {
        for (const div of document.querySelectorAll('.custom-description')) {
            div.remove();
        }
    }
 
    // ══════════════════════════════════════════════════════════════════
    // WATCH LATER SIDEBAR LINK
    // ══════════════════════════════════════════════════════════════════
    function injectWatchLater() {
        if (watchLaterDone || !listViewEnabled) return;
        if (document.querySelector('a[href="/playlist?list=WL"]')) { watchLaterDone = true; return; }
 
        const ref = ['a[href="/feed/playlists"]', 'a[href="/feed/history"]']
            .map(s => document.querySelector(s)?.closest('ytd-guide-entry-renderer'))
            .find(Boolean);
        if (!ref?.parentElement) return;
 
        const NS  = 'http://www.w3.org/2000/svg';
        const svg = document.createElementNS(NS, 'svg');
        for (const [k, v] of Object.entries({ xmlns: NS, height: '24', viewBox: '0 0 24 24', width: '24', focusable: 'false', 'aria-hidden': 'true' })) svg.setAttribute(k, v);
        svg.style.cssText = 'pointer-events:none;display:inherit;width:100%;height:100%;';
        const path = document.createElementNS(NS, 'path');
        path.setAttribute('d', 'M12 1C5.925 1 1 5.925 1 12s4.925 11 11 11 11-4.925 11-11S18.075 1 12 1Zm0 2a9 9 0 110 18.001A9 9 0 0112 3Zm0 3a1 1 0 00-1 1v5.565l.485.292 3.33 2a1 1 0 001.03-1.714L13 11.435V7a1 1 0 00-1-1Z');
        svg.appendChild(path);
 
        const entry = el('ytd-guide-entry-renderer', {
            className: 'style-scope ytd-guide-collapsible-section-entry-renderer', 'line-end-style': 'none',
        }, [
            el('a', { id: 'endpoint', className: 'yt-simple-endpoint style-scope ytd-guide-entry-renderer', tabindex: '-1', role: 'link', href: '/playlist?list=WL', title: 'Watch later' }, [
                el('tp-yt-paper-item', { role: 'link', className: 'style-scope ytd-guide-entry-renderer', 'style-target': 'host', tabindex: '0', 'aria-disabled': 'false' }, [
                    el('yt-icon', { className: 'guide-icon style-scope ytd-guide-entry-renderer' }, [
                        el('span', { className: 'yt-icon-shape style-scope yt-icon ytSpecIconShapeHost' }, [
                            el('div', { style: { width: '100%', height: '100%', display: 'block', fill: 'currentcolor' } }, [svg]),
                        ]),
                    ]),
                    el('yt-formatted-string', { className: 'title style-scope ytd-guide-entry-renderer', textContent: 'Watch later' }),
                ]),
            ]),
        ]);
 
        ref.after(entry);
        watchLaterDone = true;
    }
 
    // ══════════════════════════════════════════════════════════════════
    // LAYOUT FIX
    // ══════════════════════════════════════════════════════════════════
    function injectLayoutFix() {
        if (layoutFixDone || !listViewEnabled) return;
        const primary = document.querySelector('ytd-two-column-browse-results-renderer #primary');
        if (!primary) return;
        layoutFixDone = true;
 
        const dummy       = el('div', { style: { width: '1px', height: '100vh', flexShrink: '0', background: 'transparent', transition: 'width 0.2s ease-out' } });
        const origDisplay = primary.style.display;
        primary.style.display = 'flex'; primary.style.flexDirection = 'row';
        primary.prepend(dummy);
        setTimeout(() => {
            dummy.style.width = '0px';
            setTimeout(() => { dummy.remove(); primary.style.display = origDisplay; dispatchEvent(new Event('resize')); }, 200);
        }, SHIFT_DELAY);
    }
 
    // ══════════════════════════════════════════════════════════════════
    // FEATURE TOGGLES
    // ══════════════════════════════════════════════════════════════════
    function processMostRelevant() {
        if (!settings.hideMostRelevant) {
            for (const s of document.querySelectorAll('ytd-rich-section-renderer[data-hidden-by-ext="true"]')) {
                s.style.display = ''; s.removeAttribute('data-hidden-by-ext');
            }
            return;
        }
        for (const s of document.querySelectorAll('ytd-rich-section-renderer:not([data-hidden-by-ext="true"])')) {
            if (s.querySelector('span#title')?.textContent?.trim().toLowerCase() === 'most relevant') {
                s.style.display = 'none'; s.setAttribute('data-hidden-by-ext', 'true');
            }
        }
    }
 
    function handleShortsScroll(e) {
        const btnRenderer = e.target.closest('.expand-collapse-button');
        if (!btnRenderer) return;
        const isLess =
            (btnRenderer.querySelector('button')?.getAttribute('aria-label') || '').toLowerCase() === 'show less' ||
            (btnRenderer.querySelector('.yt-core-attributed-string')?.textContent?.trim() || '').toLowerCase() === 'show less';
        if (!isLess) return;
        const shelf = btnRenderer.closest('ytd-rich-shelf-renderer');
        if (shelf?.getBoundingClientRect().top < 56) {
            setTimeout(() => scrollTo({ top: shelf.getBoundingClientRect().top + scrollY - 72, behavior: 'smooth' }), 500);
        }
    }
 
    function updateShortsScroll() {
        document.removeEventListener('click', handleShortsScroll);
        if (settings.changeShortsScroll) document.addEventListener('click', handleShortsScroll);
    }
 
    function ensurePageSubtype() {
        const browse = document.querySelector('ytd-browse');
        if (browse && browse.getAttribute('page-subtype') !== 'subscriptions') {
            browse.setAttribute('page-subtype', 'subscriptions');
        }
    }
 
    // ══════════════════════════════════════════════════════════════════
    // NAV RESET
    // ══════════════════════════════════════════════════════════════════
    function resetNavState() {
        _processedHeaders = new WeakSet();
        _processedAvatars = new WeakSet();
        _descState.inFlight.clear();
        _descState.memCache.clear();
        layoutFixDone  = false;
        watchLaterDone = false;
        // Re-attach observer to new feed DOM after navigation
        _feedMoTarget = null;
    }
 
    // ══════════════════════════════════════════════════════════════════
    // MAIN DOM HANDLER
    // ══════════════════════════════════════════════════════════════════
    function handleDomChanges() {
        if (location.href !== lastUrl) {
            lastUrl = location.href; resetNavState();
        }
        injectToggleButtons();
        if (!isTargetPage()) return;
        ensurePageSubtype();
        attachFeedObserver();
        if (listViewEnabled) {
            processItems();
            if (!watchLaterDone) injectWatchLater();
            if (!layoutFixDone && document.querySelector('ytd-rich-item-renderer')) injectLayoutFix();
        }
        processMostRelevant();
    }
 
    // ══════════════════════════════════════════════════════════════════
    // OBSERVERS & INIT
    // ══════════════════════════════════════════════════════════════════
 
    // Broad observer on body — only used as a fallback for navigation detection
    // and to trigger the targeted observer attachment.
    new MutationObserver(() => {
        if (!isSliderDragging) scheduleUpdate();
    }).observe(document.body, { childList: true, subtree: true });
 
    // Targeted observer: watches only the feed contents container.
    // Much cheaper than observing all of document.body.
    function attachFeedObserver() {
        if (!isTargetPage()) return;
        const target =
            document.querySelector('ytd-rich-grid-renderer #contents') ||
            document.querySelector('ytd-rich-grid-renderer');
        if (!target || target === _feedMoTarget) return;
        _feedMo?.disconnect();
        _feedMoTarget = target;
        _feedMo = new MutationObserver(muts => {
            if (isSliderDragging) return;
            for (const m of muts)
                for (const node of m.addedNodes)
                    if (node?.nodeType === 1 && node.tagName === 'YTD-RICH-ITEM-RENDERER')
                        scheduleUpdate();
        });
        _feedMo.observe(target, { childList: true });
    }
 
    document.addEventListener('yt-navigate-finish', () => {
        lastUrl = location.href;
        resetNavState();
        applySettings(settings);
        handleDomChanges();
        attachFeedObserver();
    });
 
    window.addEventListener('popstate', () => {
        resetNavState();
        handleDomChanges();
    }, { passive: true });
 
    // Boot
    descStoreLoad();
    applySettings(getAllSettings());
    ensureDescLoop();
    setTimeout(() => attachFeedObserver(), 300);
})();