Greasy Fork

Greasy Fork is available in English.

YouTube Layout Plus

Home: collapse guide, 5 videos per row, hide Shorts. Watch: hide recommendations sidebar and center the player/content, while preserving live chat on streams/replays. Adds a topbar theme switcher that triggers YouTube's official Appearance modes via direct yt-action dispatch.

当前为 2026-04-23 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         YouTube Layout Plus
// @namespace    https://qazwsx123.uk/
// @version      0.2.17
// @description  Home: collapse guide, 5 videos per row, hide Shorts. Watch: hide recommendations sidebar and center the player/content, while preserving live chat on streams/replays. Adds a topbar theme switcher that triggers YouTube's official Appearance modes via direct yt-action dispatch.
// @author       Codex
// @match        https://www.youtube.com/*
// @run-at       document-idle
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  const STYLE_ID = 'tm-youtube-layout-plus-style';
  const THEME_SWITCHER_ID = 'tm-youtube-layout-plus-theme-switcher';
  const HOME_GRID_SWITCHER_ID = 'tm-youtube-layout-plus-home-grid-switcher';
  const THEME_STATUS_ID = 'tm-youtube-layout-plus-theme-status';
  const REPLAY_HIDE_CLASS = 'tm-youtube-layout-plus-hide-replay-prompt';
  const THEME_MODE_STORAGE_KEY = 'tm-youtube-layout-plus-theme-mode';
  const HOME_GRID_COLUMNS_STORAGE_KEY = 'tm-youtube-layout-plus-home-grid-columns';
  const THEME_MODES = [
    { mode: 'auto', label: 'Auto', actionName: 'yt-signal-action-toggle-dark-theme-device' },
    { mode: 'light', label: 'Light', actionName: 'yt-signal-action-toggle-dark-theme-off' },
    { mode: 'dark', label: 'Dark', actionName: 'yt-signal-action-toggle-dark-theme-on' },
  ];
  const HOME_GRID_COLUMN_OPTIONS = [4, 5];
  const LAYOUT_MODE_CLASSES = [
    'tm-youtube-layout-plus-home',
    'tm-youtube-layout-plus-watch',
    'tm-youtube-layout-plus-watch-chat',
    'tm-youtube-layout-plus-watch-plain',
  ];
  const OBSERVER_APPLY_DEBOUNCE_MS = 150;
  const ROUTE_POLL_INTERVAL_MS = 3000;
  // YouTube's PREF cookie f6 is a hex bitfield.
  // 0x80 = "theme preference set" (device theme if no further bits).
  // 0x400 = dark. 0x80000 = light.
  const PREF_F6_PREF_BIT = 0x80;
  const PREF_F6_DARK_BIT = 0x400;
  const PREF_F6_LIGHT_BIT = 0x80000;

  let currentUrl = location.href;
  let applyFrame = 0;
  let applyDelayTimer = null;
  let bodyObserver = null;
  let routeTimer = null;
  let resizeTimer = null;
  let resizeFrame = 0;
  let watchLayoutRetryTimer = null;
  let watchLayoutRetryStep = 0;
  let watchChatStateTimer = null;
  let lastWatchChatExpanded = null;
  let playerSyncTimer = null;
  let lastPlayerSyncKey = '';
  let lastAutoCollapsedHomeUrl = '';
  let lastAutoCollapsedWatchChatKey = '';
  let currentThemeMode = loadStoredThemeMode();
  let currentHomeGridColumns = loadStoredHomeGridColumns();
  let themeSwitchInFlight = false;
  let pendingThemeMode = null;
  let themeStatusHideTimer = null;
  let lastRenderedThemeMode = null;
  let lastRenderedThemeDisabled = null;
  let lastRenderedHomeGridColumns = null;
  let lastPersistedThemeMode = currentThemeMode;
  const WATCH_LAYOUT_RETRY_DELAYS = [0, 40, 120, 260, 520, 900, 1400, 2200, 3200, 4500];

  function isHomePage() {
    return location.pathname === '/';
  }

  function isWatchPage() {
    return location.pathname === '/watch';
  }

  function getWatchPageKey() {
    if (!isWatchPage()) return location.pathname;

    const params = new URLSearchParams(location.search);
    const videoId = params.get('v');
    return videoId ? `/watch?v=${videoId}` : location.pathname;
  }

  function getWatchTeaserText() {
    const teaserCarousel = document.querySelector('ytd-watch-metadata #teaser-carousel');
    return (teaserCarousel?.innerText || teaserCarousel?.textContent || '').trim();
  }

  function hasLiveWatchPrompt(teaserText = getWatchTeaserText()) {
    return /join the conversation to interact with the creator and others watching this live stream/i.test(teaserText)
      || (/watching now/i.test(document.body.innerText) && /started streaming/i.test(document.body.innerText));
  }

  function hasReplayWatchPrompt(teaserText = getWatchTeaserText()) {
    return /live chat replay/i.test(teaserText)
      || /see what others said about this video while it was live/i.test(teaserText);
  }

  function hasWatchSidebarChat(watchFlexy) {
    if (!watchFlexy) return false;

    if (
      watchFlexy.hasAttribute('is-live')
      || watchFlexy.hasAttribute('is-live-content')
      || watchFlexy.hasAttribute('live-chat-collapsed')
    ) {
      return true;
    }

    const liveBadge = watchFlexy.querySelector(
      'ytd-badge-supported-renderer[system-icons][icon="LIVE"], ' +
      'ytd-thumbnail-overlay-time-status-renderer[overlay-style="LIVE"], ' +
      'yt-icon[icon="yt-icons:live"]'
    );
    if (liveBadge && isVisibleElement(liveBadge)) {
      return true;
    }

    const teaserText = getWatchTeaserText();
    if (hasLiveWatchPrompt(teaserText)) {
      return true;
    }

    const chatFrame = watchFlexy.querySelector(
      'ytd-live-chat-frame#chat, #chat ytd-live-chat-frame, #chat-container ytd-live-chat-frame'
    );
    const chatHost = chatFrame?.closest('#chat') || watchFlexy.querySelector('#chat, #chat-container');
    const hasStampedChat = watchFlexy.hasAttribute('should-stamp-chat') || !!chatFrame || !!chatHost;
    if (hasReplayWatchPrompt(teaserText) && hasStampedChat) {
      return true;
    }

    if (!chatFrame) return false;
    if (chatFrame.hasAttribute('hidden')) return false;
    if (chatFrame.hasAttribute('collapsed')) {
      return hasStampedChat;
    }

    return isVisibleElement(chatFrame) || isVisibleElement(chatHost);
  }

  function ensureStyle() {
    if (document.getElementById(STYLE_ID)) return;

    const style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent = `
      html.tm-youtube-layout-plus-home {
        --tm-guide-collapsed-width: 72px;
        --tm-chip-overlay-shift: 18px;
        --tm-chip-strip-bg:
          radial-gradient(circle at 18% 0%, rgba(255, 255, 255, 0.42) 0%, rgba(255, 255, 255, 0) 34%),
          radial-gradient(circle at 82% 6%, rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0) 28%),
          linear-gradient(180deg, rgba(214, 223, 233, 0.32) 0%, rgba(191, 201, 212, 0.22) 100%);
        --tm-chip-active-bg:
          radial-gradient(circle at 20% 0%, rgba(255, 255, 255, 0.52) 0%, rgba(255, 255, 255, 0) 42%),
          linear-gradient(180deg, rgba(250, 252, 255, 0.52) 0%, rgba(229, 236, 243, 0.28) 100%);
        --tm-chip-text: #3b424b;
        --tm-chip-text-active: #1f2328;
        --tm-chip-separator: rgba(70, 77, 88, 0.18);
        --tm-chip-strip-border: rgba(255, 255, 255, 0.24);
        --tm-chip-strip-top-line: rgba(156, 164, 175, 0.32);
        --tm-chip-strip-shadow-top: rgba(255, 255, 255, 0.24);
        --tm-chip-strip-shadow-bottom: rgba(43, 50, 59, 0.12);
        --tm-chip-hover-bg: rgba(255, 255, 255, 0.12);
        --tm-chip-active-border: rgba(148, 157, 169, 0.22);
        --tm-chip-active-top-stroke: rgba(148, 157, 169, 0.2);
        --tm-chip-active-shadow-top: rgba(255, 255, 255, 0.4);
        --tm-chip-active-shadow-bottom: rgba(148, 157, 169, 0.24);
        --tm-chip-active-shadow-mid: rgba(60, 64, 67, 0.1);
        --tm-chip-active-shadow-ring: rgba(118, 126, 137, 0.1);
        --tm-chip-arrow-bg:
          radial-gradient(circle at 20% 0%, rgba(255, 255, 255, 0.28) 0%, rgba(255, 255, 255, 0) 38%),
          linear-gradient(180deg, rgba(248, 251, 255, 0.28) 0%, rgba(228, 235, 242, 0.18) 100%);
        --tm-chip-arrow-shadow-top: rgba(255, 255, 255, 0.18);
        --tm-chip-arrow-shadow-mid: rgba(60, 64, 67, 0.08);
        --tm-chip-glass-blur: 34px;
      }

      html[dark].tm-youtube-layout-plus-home {
        --tm-chip-strip-bg:
          radial-gradient(circle at 18% 0%, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0) 34%),
          linear-gradient(180deg, rgba(46, 51, 58, 0.52) 0%, rgba(28, 31, 37, 0.38) 100%);
        --tm-chip-active-bg:
          radial-gradient(circle at 20% 0%, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0) 40%),
          linear-gradient(180deg, rgba(86, 92, 100, 0.38) 0%, rgba(61, 66, 73, 0.26) 100%);
        --tm-chip-text: rgba(231, 234, 237, 0.9);
        --tm-chip-text-active: #ffffff;
        --tm-chip-separator: rgba(255, 255, 255, 0.1);
        --tm-chip-strip-border: rgba(255, 255, 255, 0.1);
        --tm-chip-strip-top-line: rgba(255, 255, 255, 0.12);
        --tm-chip-strip-shadow-top: rgba(255, 255, 255, 0.08);
        --tm-chip-strip-shadow-bottom: rgba(0, 0, 0, 0.28);
        --tm-chip-hover-bg: rgba(255, 255, 255, 0.08);
        --tm-chip-active-border: rgba(255, 255, 255, 0.12);
        --tm-chip-active-top-stroke: rgba(255, 255, 255, 0.08);
        --tm-chip-active-shadow-top: rgba(255, 255, 255, 0.06);
        --tm-chip-active-shadow-bottom: rgba(255, 255, 255, 0.04);
        --tm-chip-active-shadow-mid: rgba(0, 0, 0, 0.18);
        --tm-chip-active-shadow-ring: rgba(255, 255, 255, 0.06);
        --tm-chip-arrow-bg:
          radial-gradient(circle at 20% 0%, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0) 38%),
          linear-gradient(180deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.06) 100%);
        --tm-chip-arrow-shadow-top: rgba(255, 255, 255, 0.06);
        --tm-chip-arrow-shadow-mid: rgba(0, 0, 0, 0.2);
        --tm-chip-glass-blur: 28px;
      }

      .${REPLAY_HIDE_CLASS} {
        display: none !important;
      }

      #${THEME_SWITCHER_ID} {
        position: relative;
        display: flex;
        align-items: center;
        gap: 0;
        margin-left: 12px;
        padding: 4px 6px;
        border: 1px solid var(--yt-spec-10-percent-layer, rgba(0, 0, 0, 0.12));
        border-radius: 20px;
        background: var(--yt-spec-badge-chip-background, rgba(0, 0, 0, 0.05));
      }

      #${THEME_STATUS_ID} {
        position: fixed;
        top: 72px;
        right: 24px;
        z-index: 2200;
        max-width: 320px;
        padding: 10px 14px;
        border: 1px solid rgba(190, 60, 60, 0.28);
        border-radius: 14px;
        background: rgba(126, 28, 28, 0.92);
        color: #fff;
        font: 500 13px/1.4 Roboto, Arial, sans-serif;
        box-shadow: 0 10px 24px rgba(0, 0, 0, 0.24);
        opacity: 0;
        transform: translateY(-6px);
        pointer-events: none;
        transition: opacity 160ms ease, transform 160ms ease;
      }

      #${THEME_STATUS_ID}[data-visible="true"] {
        opacity: 1;
        transform: translateY(0);
      }

      #${THEME_SWITCHER_ID} .tm-theme-switch-track {
        display: inline-flex;
        align-items: center;
        gap: 4px;
      }

      #${THEME_SWITCHER_ID} .tm-theme-switch-option {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 52px;
        height: 28px;
        padding: 0 10px;
        border: 0;
        border-radius: 14px;
        background: transparent;
        color: var(--yt-spec-text-primary, #0f0f0f);
        cursor: pointer;
        font: 600 12px/1 Roboto, Arial, sans-serif;
        transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
      }

      #${THEME_SWITCHER_ID} .tm-theme-switch-option:hover {
        background: var(--yt-spec-badge-chip-background-hover, rgba(0, 0, 0, 0.08));
      }

      #${THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"] {
        background: var(--yt-spec-brand-background-solid, rgba(15, 15, 15, 0.92));
        color: var(--yt-spec-static-brand-white, #fff);
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
      }

      html[dark] #${THEME_SWITCHER_ID} {
        border-color: rgba(255, 255, 255, 0.14);
        background: rgba(255, 255, 255, 0.04);
      }

      html[dark] #${THEME_SWITCHER_ID} .tm-theme-switch-option {
        color: rgba(255, 255, 255, 0.92);
      }

      html[dark] #${THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"] {
        background: rgba(255, 255, 255, 0.14);
        color: #fff;
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
      }

      #${HOME_GRID_SWITCHER_ID} {
        position: relative;
        display: inline-flex;
        align-items: center;
        gap: 8px;
        margin-left: 8px;
        padding: 4px 8px;
        border: 1px solid var(--yt-spec-10-percent-layer, rgba(0, 0, 0, 0.12));
        border-radius: 999px;
        background: var(--yt-spec-badge-chip-background, rgba(0, 0, 0, 0.05));
      }

      #${HOME_GRID_SWITCHER_ID} .tm-home-grid-option {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 28px;
        height: 28px;
        border: 1px solid var(--yt-spec-10-percent-layer, rgba(0, 0, 0, 0.18));
        border-radius: 999px;
        background: transparent;
        color: var(--yt-spec-text-primary, #0f0f0f);
        cursor: pointer;
        font: 700 12px/1 Roboto, Arial, sans-serif;
        transition: background 140ms ease, color 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
      }

      #${HOME_GRID_SWITCHER_ID} .tm-home-grid-option:hover {
        background: var(--yt-spec-badge-chip-background-hover, rgba(0, 0, 0, 0.08));
      }

      #${HOME_GRID_SWITCHER_ID} .tm-home-grid-option[data-active="true"] {
        border-color: transparent;
        background: var(--yt-spec-brand-background-solid, rgba(15, 15, 15, 0.92));
        color: var(--yt-spec-static-brand-white, #fff);
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
      }

      html[dark] #${HOME_GRID_SWITCHER_ID} {
        border-color: rgba(255, 255, 255, 0.14);
        background: rgba(255, 255, 255, 0.04);
      }

      html[dark] #${HOME_GRID_SWITCHER_ID} .tm-home-grid-option {
        border-color: rgba(255, 255, 255, 0.18);
        color: rgba(255, 255, 255, 0.92);
      }

      html[dark] #${HOME_GRID_SWITCHER_ID} .tm-home-grid-option[data-active="true"] {
        background: rgba(255, 255, 255, 0.14);
        color: #fff;
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
      }

      html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-feed-filter-chip-bar-renderer,
      html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) #chips-wrapper {
        left: var(--tm-guide-collapsed-width) !important;
        width: calc(100vw - var(--tm-guide-collapsed-width)) !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer {
        padding: 0 14px !important;
        background: transparent !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-wrapper,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips {
        align-items: center !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-wrapper {
        transform: translateY(var(--tm-chip-overlay-shift)) !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content {
        position: relative !important;
        overflow: hidden !important;
        isolation: isolate !important;
        padding: 5px 8px !important;
        margin-top: 0 !important;
        border: 1px solid var(--tm-chip-strip-border) !important;
        border-radius: 22px !important;
        background: var(--tm-chip-strip-bg) !important;
        backdrop-filter: blur(var(--tm-chip-glass-blur)) saturate(220%) contrast(1.05) brightness(1.08) !important;
        -webkit-backdrop-filter: blur(var(--tm-chip-glass-blur)) saturate(220%) contrast(1.05) brightness(1.08) !important;
        box-shadow:
          inset 0 1px 0 var(--tm-chip-strip-top-line),
          inset 0 1px 0 var(--tm-chip-strip-shadow-top),
          0 2px 0 rgba(34, 40, 49, 0.11),
          0 3px 2px rgba(34, 40, 49, 0.06),
          0 5px 7px rgba(34, 40, 49, 0.03) !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content::before {
        content: '' !important;
        position: absolute !important;
        inset: 0 !important;
        border-radius: inherit !important;
        background:
          linear-gradient(180deg, rgba(255, 255, 255, 0.26) 0%, rgba(255, 255, 255, 0.08) 36%, rgba(255, 255, 255, 0.02) 100%) !important;
        pointer-events: none !important;
        z-index: 0 !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content::after {
        content: '' !important;
        position: absolute !important;
        inset: 0 !important;
        border-radius: inherit !important;
        background:
          radial-gradient(circle at 50% 100%, rgba(180, 198, 220, 0.12) 0%, rgba(180, 198, 220, 0) 58%) !important;
        pointer-events: none !important;
        z-index: 0 !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer {
        position: relative !important;
        z-index: 1 !important;
        margin: 0 !important;
        padding: 0 2px !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer + yt-chip-cloud-chip-renderer::before {
        content: '' !important;
        position: absolute !important;
        left: -1px !important;
        top: 9px !important;
        bottom: 9px !important;
        width: 1px !important;
        border-radius: 999px !important;
        background: var(--tm-chip-separator) !important;
        pointer-events: none !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer button.ytChipShapeButtonReset {
        border-radius: 18px !important;
        overflow: visible !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip {
        position: relative !important;
        min-height: 38px !important;
        padding: 0 22px !important;
        border: 0 !important;
        border-radius: 18px !important;
        background: transparent !important;
        box-shadow: none !important;
        color: var(--tm-chip-text) !important;
        font-weight: 600 !important;
        letter-spacing: -0.01em !important;
        transition:
          background 140ms ease,
          box-shadow 140ms ease,
          color 140ms ease,
          transform 140ms ease,
          backdrop-filter 140ms ease !important;
        backdrop-filter: blur(calc(var(--tm-chip-glass-blur) * 0.7)) saturate(170%) brightness(1.04) !important;
        -webkit-backdrop-filter: blur(calc(var(--tm-chip-glass-blur) * 0.7)) saturate(170%) brightness(1.04) !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip > div {
        font-size: 15px !important;
        line-height: 36px !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer:hover .ytChipShapeChip,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer button:focus-visible .ytChipShapeChip {
        background: var(--tm-chip-hover-bg) !important;
        color: var(--tm-chip-text-active) !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected] .ytChipShapeChip,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip.ytChipShapeActive {
        background: var(--tm-chip-active-bg) !important;
        border: 1px solid var(--tm-chip-active-border) !important;
        box-shadow: none !important;
        color: var(--tm-chip-text-active) !important;
        transform: none !important;
        z-index: 1 !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected]::before,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected] + yt-chip-cloud-chip-renderer::before {
        opacity: 0 !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer yt-touch-feedback-shape,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .yt-spec-touch-feedback-shape__stroke,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .yt-spec-touch-feedback-shape__fill {
        border-radius: 18px !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #right-arrow.ytd-feed-filter-chip-bar-renderer,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #left-arrow.ytd-feed-filter-chip-bar-renderer {
        margin-top: 0 !important;
        transform: none !important;
      }

      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #right-arrow button,
      html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #left-arrow button {
        border: 0 !important;
        border-radius: 18px !important;
        background: var(--tm-chip-arrow-bg) !important;
        transform: none !important;
        backdrop-filter: blur(calc(var(--tm-chip-glass-blur) * 0.72)) saturate(175%) brightness(1.04) !important;
        -webkit-backdrop-filter: blur(calc(var(--tm-chip-glass-blur) * 0.72)) saturate(175%) brightness(1.04) !important;
        box-shadow:
          inset 0 1px 0 var(--tm-chip-arrow-shadow-top),
          0 4px 12px var(--tm-chip-arrow-shadow-mid) !important;
      }

      html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-page-manager {
        margin-left: var(--tm-guide-collapsed-width) !important;
        width: calc(100% - var(--tm-guide-collapsed-width)) !important;
      }

      html.tm-youtube-layout-plus-home ytd-browse {
        overflow: visible !important;
      }

      html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-two-column-browse-results-renderer,
      html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-rich-grid-renderer,
      html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) #contents.ytd-rich-grid-renderer {
        margin-left: 0 !important;
        width: auto !important;
      }

      html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer {
        margin-top: 0 !important;
        padding-top: calc(var(--tm-chip-overlay-shift) + 8px) !important;
        padding-left: 14px !important;
        padding-right: 12px !important;
        box-sizing: border-box !important;
      }

      html.tm-youtube-layout-plus-home ytd-rich-grid-renderer {
        --ytd-rich-grid-items-per-row: var(--tm-home-grid-items-per-row, 5) !important;
        --ytd-rich-grid-posts-per-row: var(--tm-home-grid-items-per-row, 5) !important;
      }

      html.tm-youtube-layout-plus-home ytd-rich-item-renderer,
      html.tm-youtube-layout-plus-home ytd-rich-grid-row,
      html.tm-youtube-layout-plus-home ytd-rich-grid-media,
      html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > * {
        max-width: none !important;
      }

      html.tm-youtube-layout-plus-home ytd-rich-item-renderer {
        position: relative !important;
        z-index: 0 !important;
        margin-left: 0 !important;
        margin-right: 10px !important;
        transform-origin: center top !important;
        transition:
          transform 160ms ease,
          box-shadow 160ms ease,
          z-index 160ms ease !important;
        will-change: transform !important;
      }

      html.tm-youtube-layout-plus-home ytd-rich-item-renderer:hover,
      html.tm-youtube-layout-plus-home ytd-rich-item-renderer:focus-within {
        transform: scale(1.1) !important;
        z-index: 4 !important;
      }

      html.tm-youtube-layout-plus-home ytd-rich-section-renderer,
      html.tm-youtube-layout-plus-home ytd-rich-shelf-renderer,
      html.tm-youtube-layout-plus-home ytd-reel-shelf-renderer {
        display: none !important;
      }

      html.tm-youtube-layout-plus-watch,
      html.tm-youtube-layout-plus-watch body,
      html.tm-youtube-layout-plus-watch ytd-app,
      html.tm-youtube-layout-plus-watch ytd-watch-flexy,
      html.tm-youtube-layout-plus-watch ytd-watch-flexy #columns,
      html.tm-youtube-layout-plus-watch ytd-watch-flexy #primary,
      html.tm-youtube-layout-plus-watch ytd-watch-flexy #primary-inner,
      html.tm-youtube-layout-plus-watch ytd-watch-flexy #below {
        overflow-x: hidden !important;
        overscroll-behavior-x: none !important;
        max-width: 100% !important;
      }

      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy #secondary,
      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy #related,
      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy #secondary-inner,
      html.tm-youtube-layout-plus-watch-plain ytd-watch-next-secondary-results-renderer,
      html.tm-youtube-layout-plus-watch-chat ytd-watch-flexy #related,
      html.tm-youtube-layout-plus-watch-chat ytd-watch-next-secondary-results-renderer {
        display: none !important;
      }

      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy[is-two-columns_] #primary {
        max-width: none !important;
        width: min(1400px, calc(100vw - 48px)) !important;
        margin: 0 auto !important;
      }

      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy[is-two-columns_] #columns {
        display: block !important;
        width: 100% !important;
        max-width: 100% !important;
      }

      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy[is-two-columns_] #primary-inner,
      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy[is-two-columns_] #above-the-fold,
      html.tm-youtube-layout-plus-watch-plain ytd-watch-flexy[is-two-columns_] #below {
        max-width: none !important;
      }

      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy #secondary,
      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy #secondary-inner {
        display: none !important;
      }

      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy[is-two-columns_] #primary {
        max-width: none !important;
        width: min(1400px, calc(100vw - 48px)) !important;
        margin: 0 auto !important;
      }

      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy[is-two-columns_] #columns {
        display: block !important;
        width: 100% !important;
        max-width: 100% !important;
      }

      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy[is-two-columns_] #primary-inner,
      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy[is-two-columns_] #above-the-fold,
      html.tm-youtube-layout-plus-watch-chat-collapsed ytd-watch-flexy[is-two-columns_] #below {
        max-width: none !important;
      }
    `;

    document.head.appendChild(style);
  }

  function collapseGuide() {
    const app = document.querySelector('ytd-app');
    if (app) {
      app.removeAttribute('guide-persistent-and-visible');
      app.setAttribute('mini-guide-visible', '');
    }

    const drawer = document.querySelector('tp-yt-app-drawer#guide');
    if (drawer) {
      drawer.removeAttribute('opened');
      drawer.style.width = '';
      drawer.style.minWidth = '';
      drawer.style.visibility = '';
    }

    const guideRenderer = document.querySelector('ytd-guide-renderer');
    if (guideRenderer) {
      guideRenderer.style.display = '';
      guideRenderer.style.width = '';
      guideRenderer.style.minWidth = '';
    }
  }

  function setLayoutModeClasses(targetClasses) {
    const target = new Set(targetClasses);
    const root = document.documentElement;
    for (const cls of LAYOUT_MODE_CLASSES) {
      const shouldHave = target.has(cls);
      const hasIt = root.classList.contains(cls);
      if (shouldHave && !hasIt) root.classList.add(cls);
      else if (!shouldHave && hasIt) root.classList.remove(cls);
    }
  }

  function applyHomeLayout() {
    const richGrid = document.querySelector('ytd-rich-grid-renderer');
    if (!richGrid) {
      setLayoutModeClasses([]);
      return;
    }

    setLayoutModeClasses(['tm-youtube-layout-plus-home']);
    applyHomeGridColumns();

    if (lastAutoCollapsedHomeUrl !== location.href) {
      collapseGuide();
      lastAutoCollapsedHomeUrl = location.href;
    }
  }

  function applyWatchLayout() {
    const watchFlexy = document.querySelector('ytd-watch-flexy');
    if (!watchFlexy) {
      setLayoutModeClasses([]);
      return;
    }

    if (hasWatchSidebarChat(watchFlexy)) {
      setLayoutModeClasses([
        'tm-youtube-layout-plus-watch',
        'tm-youtube-layout-plus-watch-chat',
      ]);
      updateWatchChatPanelState(watchFlexy);
      autoCollapseLiveChatPanel(watchFlexy);
      syncWatchPlayerSize();
      schedulePlayerSync(120);
      return;
    }

    setLayoutModeClasses([
      'tm-youtube-layout-plus-watch',
      'tm-youtube-layout-plus-watch-plain',
    ]);
    hideWatchReplayPrompt();
    syncWatchPlayerSize();
    schedulePlayerSync(120);
  }

  function clearHiddenReplayPrompts() {
    for (const el of document.querySelectorAll('.' + REPLAY_HIDE_CLASS)) {
      el.classList.remove(REPLAY_HIDE_CLASS);
    }
  }

  function hideWatchReplayPrompt() {
    const teaserCarousel = document.querySelector('ytd-watch-metadata #teaser-carousel');
    if (!teaserCarousel) return;

    const teaserText = getWatchTeaserText();
    if (hasLiveWatchPrompt(teaserText)) {
      teaserCarousel.classList.remove(REPLAY_HIDE_CLASS);
      return;
    }

    const watchFlexy = document.querySelector('ytd-watch-flexy');
    if (watchFlexy && hasReplayWatchPrompt(teaserText) && hasWatchSidebarChat(watchFlexy)) {
      teaserCarousel.classList.remove(REPLAY_HIDE_CLASS);
      return;
    }

    const replayPrompt = Array.from(
      teaserCarousel.querySelectorAll('yt-video-metadata-carousel-view-model')
    ).find((card) => {
      const text = (card.innerText || card.textContent || '').trim();
      return /live chat replay/i.test(text)
        || /see what others said about this video while it was live/i.test(text);
    });

    if (!replayPrompt) {
      teaserCarousel.classList.remove(REPLAY_HIDE_CLASS);
      return;
    }

    teaserCarousel.classList.add(REPLAY_HIDE_CLASS);
  }

  function updateWatchChatPanelState(watchFlexy) {
    const chatFrame = watchFlexy.querySelector('ytd-live-chat-frame#chat');
    const openPanelButton = findOpenPanelButton();

    const chatVisible = !!chatFrame && isVisibleElement(chatFrame);
    const panelExpanded = chatVisible || !!(openPanelButton && openPanelButton.disabled);

    document.documentElement.classList.toggle('tm-youtube-layout-plus-watch-chat-open', panelExpanded);
    document.documentElement.classList.toggle('tm-youtube-layout-plus-watch-chat-collapsed', !panelExpanded);

    if (lastWatchChatExpanded !== panelExpanded) {
      lastWatchChatExpanded = panelExpanded;

      window.requestAnimationFrame(() => {
        syncWatchPlayerSize();
        schedulePlayerSync(120);
      });
    }
  }

  function stopWatchChatStateSync() {
    if (!watchChatStateTimer) return;
    window.clearInterval(watchChatStateTimer);
    watchChatStateTimer = null;
  }

  function startWatchChatStateSync() {
    stopWatchChatStateSync();

    if (!isWatchPage()) return;

    watchChatStateTimer = window.setInterval(() => {
      if (!isWatchPage()) {
        stopWatchChatStateSync();
        return;
      }

      const watchFlexy = document.querySelector('ytd-watch-flexy');
      if (!watchFlexy) {
        return;
      }

      const hasSidebarChat = hasWatchSidebarChat(watchFlexy);
      const hasWatchChatClass = document.documentElement.classList.contains('tm-youtube-layout-plus-watch-chat');

      if (hasSidebarChat && !hasWatchChatClass) {
        scheduleApply();
        return;
      }

      if (!hasSidebarChat || !hasWatchChatClass) {
        return;
      }

      updateWatchChatPanelState(watchFlexy);
    }, 500);
  }

  function findOpenPanelButton() {
    return Array.from(document.querySelectorAll('button, yt-button-shape button, tp-yt-paper-button')).find(
      (button) => /open panel/i.test((button.innerText || button.textContent || '').trim())
    ) || null;
  }

  function safeGetIframeDocument(frame) {
    try {
      return frame?.contentDocument || null;
    } catch {
      return null;
    }
  }

  function autoCollapseLiveChatPanel(watchFlexy) {
    const watchPageKey = getWatchPageKey();
    if (lastAutoCollapsedWatchChatKey === watchPageKey) return;

    const chatFrameHost = watchFlexy.querySelector('ytd-live-chat-frame#chat');
    const openPanelButton = findOpenPanelButton();
    if (openPanelButton && !openPanelButton.disabled) {
      lastAutoCollapsedWatchChatKey = watchPageKey;
      return;
    }

    if (chatFrameHost?.hasAttribute('collapsed')) {
      lastAutoCollapsedWatchChatKey = watchPageKey;
      return;
    }

    const hostToggleButton = chatFrameHost?.querySelector(
      '#show-hide-button button, #show-hide-button yt-button-shape button, #show-hide-button tp-yt-paper-button'
    );
    if (hostToggleButton) {
      hostToggleButton.click();
      lastAutoCollapsedWatchChatKey = watchPageKey;
      window.setTimeout(scheduleApply, 80);
      return;
    }

    const chatFrame = watchFlexy.querySelector(
      'ytd-live-chat-frame#chat #chatframe, ytd-live-chat-frame#chat iframe, #chatframe'
    );
    const chatDoc = safeGetIframeDocument(chatFrame);
    if (!chatDoc) return;

    const closeButton = Array.from(chatDoc.querySelectorAll('button')).find(
      (button) => /close/i.test(button.getAttribute('aria-label') || '')
    );
    if (!closeButton) return;

    closeButton.click();
    lastAutoCollapsedWatchChatKey = watchPageKey;
    window.setTimeout(scheduleApply, 80);
  }

  function syncWatchPlayerSize() {
    if (!isWatchPage()) return;

    const playerContainer = document.getElementById('player');
    const moviePlayer = document.getElementById('movie_player');
    if (!playerContainer || !moviePlayer) return;

    const rect = playerContainer.getBoundingClientRect();
    const width = Math.round(rect.width);
    const height = Math.round(rect.height);
    if (!width || !height) return;

    const syncKey = `${location.href}|${width}x${height}`;
    if (lastPlayerSyncKey === syncKey) return;

    try {
      if (typeof moviePlayer.setInternalSize === 'function') {
        moviePlayer.setInternalSize(width, height);
      }
      if (typeof moviePlayer.setSize === 'function') {
        moviePlayer.setSize(width, height);
      }
    } catch (error) {
      console.debug('YouTube Layout Plus player sync failed:', error);
    }

    lastPlayerSyncKey = syncKey;
  }

  function schedulePlayerSync(delay = 0) {
    if (playerSyncTimer) {
      window.clearTimeout(playerSyncTimer);
      playerSyncTimer = null;
    }

    playerSyncTimer = window.setTimeout(() => {
      playerSyncTimer = null;
      syncWatchPlayerSize();
    }, delay);
  }

  function loadStoredThemeMode() {
    try {
      const mode = window.localStorage.getItem(THEME_MODE_STORAGE_KEY);
      return THEME_MODES.some((item) => item.mode === mode) ? mode : null;
    } catch {
      return null;
    }
  }

  function normalizeHomeGridColumns(value) {
    const columns = Number(value);
    return HOME_GRID_COLUMN_OPTIONS.includes(columns) ? columns : 5;
  }

  function loadStoredHomeGridColumns() {
    try {
      return normalizeHomeGridColumns(window.localStorage.getItem(HOME_GRID_COLUMNS_STORAGE_KEY));
    } catch {
      return 5;
    }
  }

  function persistThemeMode(mode) {
    if (lastPersistedThemeMode === mode) return;
    try {
      if (THEME_MODES.some((item) => item.mode === mode)) {
        window.localStorage.setItem(THEME_MODE_STORAGE_KEY, mode);
      } else {
        window.localStorage.removeItem(THEME_MODE_STORAGE_KEY);
      }
      lastPersistedThemeMode = mode;
    } catch {
      // Ignore storage failures.
    }
  }

  function persistHomeGridColumns(columns) {
    try {
      window.localStorage.setItem(
        HOME_GRID_COLUMNS_STORAGE_KEY,
        String(normalizeHomeGridColumns(columns))
      );
    } catch {
      // Ignore storage failures.
    }
  }

  function applyHomeGridColumns() {
    document.documentElement.style.setProperty(
      '--tm-home-grid-items-per-row',
      String(normalizeHomeGridColumns(currentHomeGridColumns))
    );
  }

  function delay(ms) {
    return new Promise((resolve) => {
      window.setTimeout(resolve, ms);
    });
  }

  function getThemeActionName(mode) {
    return THEME_MODES.find((item) => item.mode === mode)?.actionName || null;
  }

  function getThemeModeFromPrefCookie() {
    const prefEntries = document.cookie
      .split('; ')
      .filter((entry) => entry.startsWith('PREF='));
    const lastEntry = prefEntries[prefEntries.length - 1];
    if (!lastEntry) return null;

    try {
      const pref = decodeURIComponent(lastEntry.slice(5));
      const f6Match = pref.match(/(?:^|&)f6=([0-9a-fA-F]+)/);
      if (!f6Match) return null;

      const f6 = parseInt(f6Match[1], 16);
      if (!Number.isFinite(f6)) return null;

      // Bit-decode. Light wins over dark (matches YouTube's reducer behavior
      // where an explicit light bit overrides a residual dark bit).
      if ((f6 & PREF_F6_LIGHT_BIT) !== 0) return 'light';
      if ((f6 & PREF_F6_DARK_BIT) !== 0) return 'dark';
      if ((f6 & PREF_F6_PREF_BIT) !== 0) return 'auto';
      return null;
    } catch {
      return null;
    }
  }

  function inferThemeModeFromDocument() {
    return document.documentElement.hasAttribute('dark') ? 'dark' : 'light';
  }

  function getObservedThemeMode() {
    return getThemeModeFromPrefCookie() || inferThemeModeFromDocument();
  }

  function showThemeStatusMessage(message) {
    let status = document.getElementById(THEME_STATUS_ID);
    if (!status) {
      status = document.createElement('div');
      status.id = THEME_STATUS_ID;
      status.dataset.visible = 'false';
      document.body.appendChild(status);
    }

    status.textContent = message;
    status.dataset.visible = 'true';
    if (themeStatusHideTimer) window.clearTimeout(themeStatusHideTimer);
    themeStatusHideTimer = window.setTimeout(() => {
      status.dataset.visible = 'false';
      themeStatusHideTimer = null;
    }, 2600);
  }

  function hideThemeStatusMessage() {
    const status = document.getElementById(THEME_STATUS_ID);
    if (status) status.dataset.visible = 'false';
    if (themeStatusHideTimer) {
      window.clearTimeout(themeStatusHideTimer);
      themeStatusHideTimer = null;
    }
  }

  function isVisibleElement(element) {
    if (!element) return false;
    if (element.hidden) return false;

    const style = window.getComputedStyle(element);
    if (style.display === 'none' || style.visibility === 'hidden') return false;

    const rect = element.getBoundingClientRect();
    return rect.width > 0 && rect.height > 0;
  }

  function dispatchThemeSignal(mode) {
    const actionName = getThemeActionName(mode);
    if (!actionName) return false;

    const target = document.querySelector('ytd-app') || document.documentElement;
    try {
      target.dispatchEvent(new CustomEvent('yt-action', {
        detail: {
          actionName,
          args: [],
          optionalAction: false,
          returnValue: [],
        },
        bubbles: true,
        cancelable: false,
        composed: true,
      }));
      return true;
    } catch (error) {
      console.debug('YouTube Layout Plus theme dispatch failed:', error);
      return false;
    }
  }

  function updateThemeSwitcherUI({ force = false } = {}) {
    const switcher = document.getElementById(THEME_SWITCHER_ID);
    if (!switcher) return;

    if (!pendingThemeMode) {
      const observedMode = getObservedThemeMode();
      if (observedMode && observedMode !== currentThemeMode) {
        currentThemeMode = observedMode;
        persistThemeMode(observedMode);
      }
    } else if (!currentThemeMode) {
      currentThemeMode = loadStoredThemeMode() || inferThemeModeFromDocument();
    }

    const visibleMode = pendingThemeMode || currentThemeMode;
    const disabled = themeSwitchInFlight;

    if (!force
      && lastRenderedThemeMode === visibleMode
      && lastRenderedThemeDisabled === disabled) {
      return;
    }

    lastRenderedThemeMode = visibleMode;
    lastRenderedThemeDisabled = disabled;

    const optionButtons = switcher.querySelectorAll('.tm-theme-switch-option[data-mode]');
    for (const button of optionButtons) {
      const isActive = button.dataset.mode === visibleMode;
      button.dataset.active = String(isActive);
      button.setAttribute('aria-pressed', String(isActive));
      button.disabled = disabled;
    }
  }

  async function verifyThemeMode(mode, { attempts = 10, intervalMs = 120 } = {}) {
    // For Auto we can't rely on `<html dark>` alone because it reflects the
    // current system preference, not the "Auto" mode itself. We only trust the
    // cookie for Auto. For Light/Dark, cookie + attribute must both agree.
    const expectedDarkAttr = mode === 'dark';
    let lastResult = null;

    for (let attempt = 0; attempt < attempts; attempt += 1) {
      const cookieMode = getThemeModeFromPrefCookie();
      const hasDark = document.documentElement.hasAttribute('dark');
      const actualMode = cookieMode || inferThemeModeFromDocument();
      const cookieConsistent = cookieMode ? cookieMode === mode : true;
      const darkConsistent = mode === 'auto' ? true : hasDark === expectedDarkAttr;

      lastResult = {
        ok: cookieConsistent && darkConsistent,
        actualMode,
        cookieMode,
        hasDark,
      };

      if (lastResult.ok) {
        return lastResult;
      }

      await delay(intervalMs);
    }

    return lastResult || {
      ok: false,
      actualMode: getObservedThemeMode(),
      cookieMode: getThemeModeFromPrefCookie(),
      hasDark: document.documentElement.hasAttribute('dark'),
    };
  }

  async function setThemeMode(mode) {
    if (themeSwitchInFlight) return;
    if (!THEME_MODES.some((item) => item.mode === mode)) return;

    const previousMode = currentThemeMode
      || loadStoredThemeMode()
      || getThemeModeFromPrefCookie()
      || inferThemeModeFromDocument();

    const expectedDarkAttr = mode === 'dark'
      || (mode === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
    if (previousMode === mode
      && document.documentElement.hasAttribute('dark') === expectedDarkAttr) {
      currentThemeMode = mode;
      persistThemeMode(mode);
      pendingThemeMode = null;
      updateThemeSwitcherUI();
      return;
    }

    themeSwitchInFlight = true;
    pendingThemeMode = mode;

    try {
      updateThemeSwitcherUI();

      if (!dispatchThemeSignal(mode)) {
        currentThemeMode = previousMode;
        persistThemeMode(previousMode);
        showThemeStatusMessage(`Theme switch failed: unable to dispatch ${mode}.`);
        return;
      }

      currentThemeMode = mode;
      persistThemeMode(mode);
      updateThemeSwitcherUI();

      let verification = await verifyThemeMode(mode);
      if (!verification.ok) {
        // Silent single retry — cookie write can lag on the first dispatch.
        dispatchThemeSignal(mode);
        verification = await verifyThemeMode(mode, { attempts: 14, intervalMs: 140 });
      }

      if (!verification.ok) {
        currentThemeMode = verification.actualMode || previousMode;
        persistThemeMode(currentThemeMode);
        showThemeStatusMessage(
          `Theme switch failed: expected ${mode}, actual ${currentThemeMode || 'unknown'}.`
        );
        return;
      }

      currentThemeMode = verification.actualMode || mode;
      persistThemeMode(currentThemeMode);
      hideThemeStatusMessage();
    } finally {
      themeSwitchInFlight = false;
      pendingThemeMode = null;
      currentThemeMode = currentThemeMode
        || loadStoredThemeMode()
        || getThemeModeFromPrefCookie()
        || previousMode;
      updateThemeSwitcherUI();
    }
  }

  function ensureThemeSwitcher() {
    const logoRenderer = document.querySelector('ytd-topbar-logo-renderer');
    if (!logoRenderer) return;

    let switcher = document.getElementById(THEME_SWITCHER_ID);
    let justCreated = false;

    if (!switcher) {
      const track = document.createElement('div');
      track.className = 'tm-theme-switch-track';
      track.setAttribute('role', 'group');
      track.setAttribute('aria-label', 'Theme switcher');

      switcher = document.createElement('div');
      switcher.id = THEME_SWITCHER_ID;

      for (const item of THEME_MODES) {
        const optionButton = document.createElement('button');
        optionButton.type = 'button';
        optionButton.className = 'tm-theme-switch-option';
        optionButton.dataset.mode = item.mode;
        optionButton.dataset.active = 'false';
        optionButton.textContent = item.label;
        optionButton.setAttribute('aria-pressed', 'false');
        optionButton.addEventListener('click', async (event) => {
          event.preventDefault();
          event.stopPropagation();
          await setThemeMode(item.mode);
        });
        track.appendChild(optionButton);
      }

      switcher.append(track);

      logoRenderer.insertAdjacentElement('afterend', switcher);
      justCreated = true;
    } else if (switcher.previousElementSibling !== logoRenderer) {
      logoRenderer.insertAdjacentElement('afterend', switcher);
    }

    updateThemeSwitcherUI({ force: justCreated });
  }

  function updateHomeGridSwitcherUI({ force = false } = {}) {
    const switcher = document.getElementById(HOME_GRID_SWITCHER_ID);
    if (!switcher) return;

    const activeColumns = normalizeHomeGridColumns(currentHomeGridColumns);
    if (!force && lastRenderedHomeGridColumns === activeColumns) return;
    lastRenderedHomeGridColumns = activeColumns;

    for (const button of switcher.querySelectorAll('.tm-home-grid-option[data-columns]')) {
      const isActive = Number(button.dataset.columns) === activeColumns;
      button.dataset.active = String(isActive);
      button.setAttribute('aria-pressed', String(isActive));
    }
  }

  function setHomeGridColumns(columns) {
    const normalized = normalizeHomeGridColumns(columns);
    if (normalized === currentHomeGridColumns) return;

    currentHomeGridColumns = normalized;
    persistHomeGridColumns(currentHomeGridColumns);
    applyHomeGridColumns();
    updateHomeGridSwitcherUI();

    if (isHomePage()) {
      scheduleApply();
      // Nudge YouTube's grid renderer to re-measure — it only recomputes
      // items-per-row on mount or resize events.
      window.setTimeout(() => {
        window.dispatchEvent(new Event('resize'));
      }, 60);
    }
  }

  function ensureHomeGridSwitcher() {
    const anchor = document.getElementById(THEME_SWITCHER_ID)
      || document.querySelector('ytd-topbar-logo-renderer');
    if (!anchor) return;

    let switcher = document.getElementById(HOME_GRID_SWITCHER_ID);
    let justCreated = false;

    if (!switcher) {
      switcher = document.createElement('div');
      switcher.id = HOME_GRID_SWITCHER_ID;
      switcher.setAttribute('role', 'group');
      switcher.setAttribute('aria-label', 'Home grid columns');

      for (const columns of HOME_GRID_COLUMN_OPTIONS) {
        const optionButton = document.createElement('button');
        optionButton.type = 'button';
        optionButton.className = 'tm-home-grid-option';
        optionButton.dataset.columns = String(columns);
        optionButton.dataset.active = 'false';
        optionButton.textContent = String(columns);
        optionButton.setAttribute('aria-pressed', 'false');
        optionButton.addEventListener('click', (event) => {
          event.preventDefault();
          event.stopPropagation();
          setHomeGridColumns(columns);
        });
        switcher.appendChild(optionButton);
      }

      anchor.insertAdjacentElement('afterend', switcher);
      justCreated = true;
    } else if (switcher.previousElementSibling !== anchor) {
      anchor.insertAdjacentElement('afterend', switcher);
    }

    updateHomeGridSwitcherUI({ force: justCreated });
  }

  function applyLayout() {
    ensureStyle();
    applyHomeGridColumns();

    try {
      ensureThemeSwitcher();
      ensureHomeGridSwitcher();
    } catch (error) {
      console.error('YouTube Layout Plus switcher insertion failed:', error);
    }

    if (isHomePage()) {
      applyHomeLayout();
      return;
    }

    if (isWatchPage()) {
      applyWatchLayout();
      return;
    }

    // Other YouTube routes: clear layout-specific classes so stray styles
    // don't linger from the previous page.
    setLayoutModeClasses([]);
  }

  function queueApply() {
    if (applyFrame) return;

    applyFrame = window.requestAnimationFrame(() => {
      applyFrame = 0;
      applyLayout();
    });
  }

  function scheduleApply(delay = 0) {
    if (delay > 0) {
      window.clearTimeout(applyDelayTimer);
      applyDelayTimer = window.setTimeout(() => {
        applyDelayTimer = null;
        queueApply();
      }, delay);
      return;
    }

    if (applyDelayTimer) {
      window.clearTimeout(applyDelayTimer);
      applyDelayTimer = null;
    }

    queueApply();
  }

  function stopWatchLayoutRetry() {
    if (!watchLayoutRetryTimer) return;
    window.clearTimeout(watchLayoutRetryTimer);
    watchLayoutRetryTimer = null;
  }

  function startWatchLayoutRetry() {
    stopWatchLayoutRetry();

    if (!isWatchPage()) return;

    watchLayoutRetryStep = 0;

    const run = () => {
      if (!isWatchPage()) {
        stopWatchLayoutRetry();
        return;
      }

      scheduleApply();

      if (watchLayoutRetryStep >= WATCH_LAYOUT_RETRY_DELAYS.length - 1) {
        stopWatchLayoutRetry();
        return;
      }

      watchLayoutRetryStep += 1;
      watchLayoutRetryTimer = window.setTimeout(run, WATCH_LAYOUT_RETRY_DELAYS[watchLayoutRetryStep]);
    };

    run();
  }

  function handleRouteChange(force = false) {
    const nextUrl = location.href;
    if (!force && nextUrl === currentUrl) return;

    currentUrl = nextUrl;

    // Reset inline-hidden replay prompts so a reused DOM node doesn't stay
    // hidden on the next video.
    clearHiddenReplayPrompts();

    if (!isHomePage()) {
      lastAutoCollapsedHomeUrl = '';
    }

    if (!isWatchPage()) {
      lastAutoCollapsedWatchChatKey = '';
      stopWatchLayoutRetry();
      stopWatchChatStateSync();
      lastWatchChatExpanded = null;
      lastPlayerSyncKey = '';
      if (playerSyncTimer) {
        window.clearTimeout(playerSyncTimer);
        playerSyncTimer = null;
      }
    } else {
      lastWatchChatExpanded = null;
      lastPlayerSyncKey = '';
      startWatchLayoutRetry();
      startWatchChatStateSync();
    }

    scheduleApply();
  }

  function startObservers() {
    if (bodyObserver) return;

    bodyObserver = new MutationObserver((mutations) => {
      if (isWatchPage()) {
        return;
      }

      const hasRelevantMutation = mutations.some((mutation) => {
        const target = mutation.target instanceof Element
          ? mutation.target
          : mutation.target?.parentElement;
        if (!target) return false;

        if (target.closest('#movie_player, .html5-video-player, #chatframe')) {
          return false;
        }

        return true;
      });

      if (hasRelevantMutation) {
        // Debounce to coalesce bursts of thumbnail / chip-bar mutations into
        // a single apply instead of one per rAF.
        scheduleApply(OBSERVER_APPLY_DEBOUNCE_MS);
      }
    });

    bodyObserver.observe(document.body, {
      childList: true,
      subtree: true,
    });
  }

  function startNavigationListeners() {
    document.addEventListener('yt-navigate-finish', handleRouteChange, true);
    window.addEventListener('popstate', handleRouteChange, true);
  }

  function startWindowListeners() {
    window.addEventListener('resize', () => {
      if (resizeTimer) {
        window.clearTimeout(resizeTimer);
      }

      if (resizeFrame) {
        window.cancelAnimationFrame(resizeFrame);
      }

      resizeFrame = window.requestAnimationFrame(() => {
        resizeFrame = 0;

        if (!isWatchPage()) return;

        lastPlayerSyncKey = '';
        syncWatchPlayerSize();
      });

      resizeTimer = window.setTimeout(() => {
        resizeTimer = null;

        if (!isWatchPage()) {
          scheduleApply();
          return;
        }

        lastPlayerSyncKey = '';
        scheduleApply();
        schedulePlayerSync(120);
      }, 30);
    }, true);
  }

  function startInteractionListeners() {
    document.addEventListener('click', (event) => {
      const trigger = event.target instanceof Element
        ? event.target.closest('button, yt-button-shape button, tp-yt-paper-button')
        : null;
      if (!trigger) return;

      const text = (trigger.innerText || trigger.textContent || '').trim();
      if (/open panel/i.test(text) && isWatchPage()) {
        lastAutoCollapsedWatchChatKey = getWatchPageKey();
        scheduleApply(80);
      }
    }, true);
  }

  function watchRoute() {
    if (routeTimer) return;

    routeTimer = window.setInterval(() => {
      if (location.href === currentUrl) return;
      handleRouteChange();
    }, ROUTE_POLL_INTERVAL_MS);
  }

  function init() {
    ensureStyle();
    handleRouteChange(true);
    startObservers();
    startNavigationListeners();
    startWindowListeners();
    startInteractionListeners();
    watchRoute();
  }

  init();
})();