/* YouTube-page-only additions. The video shelves below reuse .vod-card /
   .watchlist-toggle from vods.css, so both video pages stay visually
   consistent without duplicating that CSS.

   This file also loads on /vods/ (purely to share .yt-section-title for
   its "Vom YouTube VOD Kanal" heading), so every other rule in here is
   deliberately scoped under an ID this page's own JS generates (#yt-*), a
   yt- prefixed class vods.js never generates, or the body.yt-page marker
   set on this page's own <body> (youtube/index.html only) -- that last one
   matters here because a few rules below intentionally reach out to shared
   chrome (.site-header, .page-body) that vods.js never touches directly.
   That keeps all of this page's polish from leaking onto the VODs page. */

/* ==========================================================================
   Full-bleed hero
   Gronkh.tv structural reference: the latest upload fills the page's full
   width right from y=0 as a tall, background-like banner, with the site nav
   floating transparently on top of it instead of sitting in a solid bar
   above a bounded card. Translated into this site's own paper-craft
   language: no purple/glass, just the existing dark-scrim-over-media
   convention already used for the watchlist star/play button/modal close
   (see the "Already done" note on video modal close buttons in CLAUDE.md).
   ========================================================================== */

/* The nav itself is shared chrome (js/layout.js, css/style.css) -- neither
   file is touched here. Instead this reaches out to it by ancestor scope
   (body.yt-page, set on this page's own <body> only) and wins on
   specificity/source-order alone, no !important needed for the
   background/shadow swap. Text-color overrides below DO need !important
   because style.css's own dark-mode branch sets those with !important. */
body.yt-page .site-header { transition: background-color 0.25s ease, box-shadow 0.25s ease; }
body.yt-page:not(.yt-scrolled) .site-header {
  background-color: transparent;
  background-image: none;
  box-shadow: none;
}
body.yt-page:not(.yt-scrolled) .site-logo,
body.yt-page:not(.yt-scrolled) .cart-button,
body.yt-page:not(.yt-scrolled) .theme-toggle,
body.yt-page:not(.yt-scrolled) .nav-toggle {
  color: #fff !important;
}
/* .site-nav a's white-on-transparent treatment only makes sense for the
   desktop floating-bar nav sitting directly over the hero. Below 700px the
   nav becomes a dropdown PANEL with its own solid --paper-accent background
   (style.css's mobile media query) -- forcing white text there produced
   white-on-cream in light theme, nearly unreadable. Scoped to match
   style.css's own mobile breakpoint exactly. */
@media (min-width: 701px) {
  body.yt-page:not(.yt-scrolled) .site-nav a { color: #fff !important; }
  body.yt-page:not(.yt-scrolled) .site-nav a:hover { background: rgba(255, 255, 255, 0.15); }
}
body.yt-page:not(.yt-scrolled) .nav-toggle span,
body.yt-page:not(.yt-scrolled) .nav-toggle span::before,
body.yt-page:not(.yt-scrolled) .nav-toggle span::after {
  background: #fff;
}
body.yt-page:not(.yt-scrolled) .cart-button { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.4); }
body.yt-page:not(.yt-scrolled) .theme-toggle { border-color: rgba(255, 255, 255, 0.4); }

/* .page-body's shared padding-top exists purely to clear the fixed header
   for pages where content starts right underneath it. Here the hero (not
   .page-body) is the element adjacent to the header, and the hero already
   accounts for its own height -- so the normal header-clearing offset would
   just be a large, unwanted empty gap between the hero and the library
   section below it. */
body.yt-page .page-body { padding-top: 34px; }

/* plain vh is sized against the largest-possible mobile viewport (as if the
   address bar were hidden), not what's actually visible -- causes the hero
   to run taller than the real screen and clip/overflow on phones. dvh
   tracks the real visible viewport; kept as a second declaration so
   browsers without dvh support silently keep the vh fallback above. */
.yt-hero-full {
  position: relative;
  width: 100%;
  height: 86vh;
  height: 86dvh;
  min-height: 460px;
  max-height: 820px;
  overflow: hidden;
  background: var(--blue-mat-dark);
}
.yt-hero-media { position: absolute; inset: 0; z-index: 0; }
.yt-hero-media img {
  width: 100%; height: 100%; object-fit: cover; display: block; cursor: pointer;
  transition: transform 0.7s ease;
}
.yt-hero-full:hover .yt-hero-media img { transform: scale(1.035); }
.yt-hero-skeleton { width: 100%; height: 100%; border-radius: 0; }
/* Loading placeholders for #yt-hero-content, pre-seeded in the HTML and
   fully replaced by js/youtube.js once the feed loads. The shared
   .skeleton-line rule (style.css) centers itself with a fixed height for a
   generic loading list -- that's wrong here (this content block is
   bottom-left-anchored, not centered, and the three lines stand in for
   differently-sized badge/title/meta rows), so each gets its own size. */
.yt-hero-skel { margin: 0 0 12px; }
.yt-hero-skel--badge { width: 150px; height: 26px; border-radius: 999px; }
.yt-hero-skel--title { width: min(70%, 480px); height: 36px; }
.yt-hero-skel--meta { width: 220px; margin-bottom: 0; }

/* Fixed dark rgba (not theme tokens): this sits over an arbitrary, unknown
   video thumbnail in both themes, so it needs to guarantee legible white
   text regardless of how bright the frame underneath is -- same reasoning
   as the modal close button and watchlist star's fixed dark circles below. */
.yt-hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(6, 9, 15, 0.65) 0%, rgba(6, 9, 15, 0) 22%, rgba(6, 9, 15, 0.1) 46%, rgba(6, 9, 15, 0.86) 82%, rgba(6, 9, 15, 0.97) 100%);
}

.yt-hero-content {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: 0 clamp(20px, 5vw, 64px) clamp(30px, 5.5vw, 58px);
  max-width: 880px;
  color: #fff;
}
.yt-hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  padding: 6px 14px;
  border-radius: 999px;
  font-weight: 800;
  font-size: 0.82rem;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  background: var(--accent-red);
  color: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
.yt-hero-badge svg { flex-shrink: 0; }

.yt-hero-title {
  margin: 0;
  color: #fff;
  font-family: "Bebas Neue", "Futura", sans-serif;
  font-size: clamp(1.8rem, 4.4vw, 3.1rem);
  line-height: 1.1;
  letter-spacing: 0.3px;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.yt-hero-stats { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; margin-top: 12px; }
.yt-hero-stats .stat {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.9rem; font-weight: 600; color: #fff;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.yt-hero-stats .stat svg { flex-shrink: 0; opacity: 0.95; }

.yt-hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 22px; }
.yt-hero-actions > * { flex-shrink: 0; }
.yt-hero-play-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 12px 22px; border: none; border-radius: 4px;
  background: #fff; color: #16171b !important; font-weight: 800; font-size: 0.95rem;
  text-decoration: none;
  transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.yt-hero-play-btn:hover { transform: scale(1.05); }
/* Subscribe CTA -- previously the old channel-intro card's own button, now
   relocated into the hero's action row (see js/youtube.js renderFeatured).
   Its own base rule (not just the hero-scoped padding override below) since
   nothing else in the shared stylesheets defines .btn-youtube. */
.btn-youtube {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 12px 22px; background: var(--accent-red); color: #fff !important;
  border: none; font-weight: bold; border-radius: 4px; text-decoration: none;
  transition: transform .2s cubic-bezier(.175,.885,.32,1.275);
}
.btn-youtube:hover { transform: scale(1.05); }
.btn-youtube svg { width: 20px; height: 20px; flex-shrink: 0; }
.yt-hero-actions .btn-youtube { padding: 12px 20px; }
/* .watchlist-toggle's base rule (vods.css) absolutely-positions it into a
   card's top-right corner -- .yt-hero-watch (js/youtube.js) overrides that
   back to a normal inline flex item here in the hero's action row instead. */
.yt-hero-watch {
  position: static;
  width: 44px; height: 44px;
  margin-left: auto;
}

.yt-hero-empty { text-align: center; color: #fff; max-width: 420px; }
.yt-hero-empty .yt-empty-icon { color: rgba(255, 255, 255, 0.55); margin-bottom: 10px; }
.yt-hero-empty h2 { margin: 0 0 6px; font-size: 1.4rem; }
.yt-hero-empty p { margin: 0 0 16px; color: rgba(255, 255, 255, 0.8); }

@media (max-width: 700px) {
  .yt-hero-full { height: 74vh; height: 74dvh; min-height: 420px; max-height: 640px; }
  .yt-hero-content { padding-bottom: 26px; }
  .yt-hero-watch { margin-left: 0; }
}

/* ==========================================================================
   Library section (everything below the hero)
   ========================================================================== */

.yt-library {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 22px;
  box-sizing: border-box;
}
/* Light theme brightness fix: the site's cutting-mat background stays dark
   navy in both themes by design (see CLAUDE.md), so this page gives its own
   main content zone an actual light "paper sheet" surface in light mode --
   scoped to this page-exclusive wrapper, so it can't leak onto any other
   page even though this stylesheet also loads on /vods/. Dark mode is left
   completely untouched (no background/padding here at all) so it renders
   exactly as before. */
:root:not([data-theme="dark"]) .yt-library {
  background-color: var(--paper);
  box-shadow: var(--shadow-soft);
  padding: 40px clamp(16px, 4vw, 56px) 52px;
  margin-top: 8px;
}

.yt-library .scissor-line { margin: 0 auto 34px; }

/* Base rule for text sitting directly on the mat (not inside a paper
   section) -- fixed white, not a theme token, because the mat stays dark
   navy in both themes by design (see CLAUDE.md). Was accidentally dropped
   in the gronkh.tv restructure despite the comment below still describing
   it as present; VODs' "Die neusten Streams"/"Aus dem Archiv"/"Vom YouTube
   VOD Kanal" headings depend on this exact class for their color. */
.yt-section-title {
  text-align: center; color: #fff; margin: 54px 0 24px; font-family: "Bebas Neue", sans-serif;
  font-size: 1.7rem; letter-spacing: 1px; text-transform: uppercase;
}

.yt-library-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px 20px;
  width: 100%;
  margin: 0 0 22px;
}
.yt-library-head .yt-section-title { margin: 0; text-align: left; }
/* Only ever matches inside .yt-library, which only exists on this page --
   the VODs page reuses the bare .yt-section-title rule (white, centered)
   completely untouched. Token-based (not a hardcoded color) because it's
   correct in both themes automatically once nested in .yt-library: mat-dark
   (white text reads fine) in dark mode, the new paper sheet above (dark
   text reads fine) in light mode. */
.yt-library .yt-section-title { color: var(--text-dark); }
.yt-library-head .filter-bar { width: auto; max-width: none; margin: 0; padding-bottom: 0; justify-content: flex-end; }

@media (max-width: 700px) {
  .yt-library-head { justify-content: center; }
  .yt-library-head .yt-section-title { text-align: center; width: 100%; }
  .yt-library-head .filter-bar { width: 100%; justify-content: center; }
}

/* ---------- Filter bar: small icons inside the shop-style pills ---------- */
#yt-filter-bar .filter-pill { display: inline-flex; align-items: center; gap: 7px; }
#yt-filter-bar .filter-pill svg { flex-shrink: 0; }

.yt-pill-skeleton {
  display: inline-block; width: 118px; height: 41px; border-radius: 4px;
  background: linear-gradient(90deg, rgba(255,255,255,.35) 25%, rgba(255,255,255,.6) 37%, rgba(255,255,255,.35) 63%);
  background-size: 400px 100%;
  animation: shimmer 1.4s infinite linear;
}

/* Light-theme skeleton/empty-state legibility: the shared .skeleton-card/
   .skeleton-line/.empty-state rules (style.css) use a pale shimmer and white
   text tuned for the dark mat they normally sit on. Inside .yt-library's new
   light paper sheet (light theme only -- see above) that would read as
   pale-on-pale, so this overrides both, scoped to stay off every other page
   that also uses those shared classes. */
:root:not([data-theme="dark"]) .yt-library .skeleton-card,
:root:not([data-theme="dark"]) .yt-library .skeleton-line,
:root:not([data-theme="dark"]) .yt-pill-skeleton {
  background: linear-gradient(90deg, rgba(0,0,0,.07) 25%, rgba(0,0,0,.15) 37%, rgba(0,0,0,.07) 63%);
  background-size: 400px 100%;
}
.yt-library .empty-state, .yt-library .error-state { color: var(--text-dark); }
.yt-empty-icon { color: var(--text-muted); opacity: 0.6; }

/* ---------- Empty-state CTA ----------
   A dead-end "nothing here yet" used to just be text -- this gives it
   somewhere to actually go instead. */
.yt-empty-cta {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 16px;
  padding: 10px 20px; border-radius: 999px; font-weight: 800; font-size: 0.85rem;
  text-decoration: none; color: #fff !important; background: var(--accent-red);
  transition: transform 0.2s cubic-bezier(.175,.885,.32,1.275);
}
.yt-empty-cta:hover { transform: scale(1.05); }

/* ---------- Sort bar ----------
   A compact segmented control instead of a second row of big torn pills
   identical to the Videos/Shorts filter above it -- this is a lighter-
   weight, secondary control, not another primary navigation choice.
   Data-gated in js/youtube.js (renderSortBar) at >=4 items with real
   view-count variance -- the same threshold vods.js uses for its Twitch
   archive sort. */
#yt-spotlight:empty, #yt-sort-bar:empty { display: none; margin: 0; }
#yt-sort-bar.vod-section-head {
  width: 100%;
  margin: -6px 0 24px;
  justify-content: center;
  gap: 12px;
}
@media (min-width: 701px) {
  #yt-sort-bar.vod-section-head { justify-content: flex-end; }
}
.yt-sort-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.82rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--text-dark);
}
.yt-sort-label svg { flex-shrink: 0; opacity: 0.85; }
.yt-sort-toggle {
  display: inline-flex;
  align-items: center;
  padding: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
}
:root:not([data-theme="dark"]) .yt-library .yt-sort-toggle {
  background: rgba(0, 0, 0, 0.05);
  border-color: rgba(0, 0, 0, 0.1);
}
.yt-sort-btn {
  border: none;
  background: none;
  padding: 7px 16px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--text-dark);
  opacity: 0.7;
  transition: background 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}
.yt-sort-btn:hover { opacity: 1; }
.yt-sort-btn.is-active { background: var(--accent-red); color: #fff !important; opacity: 1; }

/* ==========================================================================
   Horizontal shelves (main "Mehr von Jamon" row)
   Gronkh.tv structural reference: rows of cards you scroll sideways through
   rather than a uniform wrapping grid -- fits today's small video count
   just as well as it will once the channel's full history loads (the row
   simply starts needing to scroll). #yt-grid keeps the "load more"
   pagination contract exactly as before (js/youtube.js); this only changes
   how the currently-visible cards are laid out.
   ========================================================================== */
.yt-shelf-wrap { position: relative; width: 100%; }
.yt-shelf {
  display: flex;
  flex-wrap: nowrap;
  gap: 20px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  width: 100%;
  padding: 18px 6px 30px;
  scrollbar-width: thin;
  scrollbar-color: rgba(120, 120, 130, 0.4) transparent;
}
.yt-shelf::-webkit-scrollbar { height: 8px; }
.yt-shelf::-webkit-scrollbar-track { background: transparent; }
.yt-shelf::-webkit-scrollbar-thumb { background: rgba(120, 120, 130, 0.4); border-radius: 4px; }
.yt-shelf > .vod-card,
.yt-shelf > .skeleton-card {
  flex: 0 0 272px;
  scroll-snap-align: start;
  margin-top: 0;
}
.yt-shelf > .empty-state { flex: 1 1 100%; width: 100%; }

/* #yt-grid: a normal wrapping grid + "load more" button underneath, not a
   horizontal shelf -- reported as the actual wanted behavior once the
   channel's full ~200-video catalog was loaded (sideways-scrolling through
   that many cards to browse the whole channel was the complaint). The
   "Aus dem Archiv" spotlight above it stays a .yt-shelf on purpose: a
   handful of curated picks is fine to browse sideways, it's discovery, not
   the primary way to page through the catalog. */
.yt-main-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 24px;
  width: 100%;
  padding: 18px 6px 10px;
}
.yt-main-grid.yt-grid--shorts { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
.yt-main-grid > .empty-state { grid-column: 1 / -1; }

.yt-shelf-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 42px; height: 42px;
  border-radius: 50%;
  border: none;
  background: rgba(10, 10, 14, 0.6);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
  transition: background 0.2s ease, opacity 0.2s ease;
}
.yt-shelf-nav:hover { background: rgba(10, 10, 14, 0.82); }
.yt-shelf-nav--prev { left: -4px; }
.yt-shelf-nav--next { right: -4px; }
.yt-shelf-nav.is-hidden { display: none; }
@media (max-width: 700px) {
  /* Touch devices already get native swipe scrolling on .yt-shelf; the
     overlay buttons mostly just cover cards on narrow screens. */
  .yt-shelf-nav { display: none; }
}

/* #yt-spotlight (the "Aus dem Archiv" row, still a .yt-shelf) and #yt-grid
   (now a plain .yt-main-grid) share the exact same card markup/classes, so
   the thumbnail-hover and play-button rules below apply to both containers
   by id rather than being duplicated per layout. */
#yt-grid .vod-thumb, #yt-spotlight .vod-thumb { overflow: hidden; }
#yt-grid .vod-thumb img, #yt-spotlight .vod-thumb img { transition: transform 0.5s ease; }
#yt-grid .vod-card:hover .vod-thumb img, #yt-spotlight .vod-card:hover .vod-thumb img { transform: scale(1.06); }

/* Custom play-button affordance: cards open the on-brand video modal
   below instead of navigating away, so this signals "plays here". Own
   yt-prefixed classes (not scoped to #yt-grid) -- safe anywhere per this
   file's header comment, since vods.js never generates them. */
.yt-play-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.yt-play-circle {
  width: 52px; height: 52px; border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.25s cubic-bezier(.175,.885,.32,1.275), background 0.2s ease;
}
.yt-play-circle svg { margin-left: 2px; }
.vod-card:hover .yt-play-circle { transform: scale(1.15); background: var(--accent-red); }

/* Title color shift on hover/focus -- a small extra bit of "this is
   interactive" feedback beyond the existing lift/zoom, scoped to this
   page's own two shelves so it doesn't reach vods.js's cards. */
#yt-grid .vod-card h3, #yt-spotlight .vod-card h3 { transition: color 0.2s ease; }
#yt-grid .vod-card:hover h3, #yt-spotlight .vod-card:hover h3,
#yt-grid .vod-card:focus-visible h3, #yt-spotlight .vod-card:focus-visible h3 { color: var(--accent-red); }

#yt-grid .yt-card-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 10px;
  margin-top: auto;
}
#yt-grid .yt-card-meta .vod-date { margin-top: 0; }
#yt-grid .yt-card-views {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.76rem;
  color: var(--text-muted);
  white-space: nowrap;
}
#yt-grid .yt-card-views svg { flex-shrink: 0; opacity: .8; }

.yt-short-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 9px 4px 6px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .yt-shelf { scroll-behavior: auto; }
}

/* ---------- Load more ----------
   Revealed by youtube.js/renderLoadMore whenever the active tab (Videos or
   Shorts) has more cards than are currently shown — keeps a long-running
   channel's full history (hundreds of entries once scripts/fetch-main-
   feed.mjs pulls from the YouTube Data API instead of the old ~15-video RSS
   cap) from being dumped into the shelf in one go. */
.yt-load-more-row { width: 100%; display: flex; justify-content: center; margin: 4px 0 4px; }
.yt-load-more-btn { display: inline-flex; align-items: center; gap: 8px; }
.yt-load-more-btn svg { flex-shrink: 0; transition: transform 0.2s ease; }
.yt-load-more-btn:hover svg { transform: translateY(2px); }

/* ---------- Shorts mode: narrower, taller (9:16) cards instead of the
   16:9 video ones. Bare .yt-grid--shorts (not scoped to .yt-main-grid) on
   purpose -- the spotlight shelf never gets this class (it's Videos-tab
   only, see computeSpotlight), so there's nothing else it could match. ---------- */
.yt-grid--shorts .vod-thumb img { aspect-ratio: 9 / 16; object-fit: cover; }
.yt-grid--shorts .vod-card h3 { font-size: 0.92rem; }
.yt-grid--shorts .vod-card:hover { transform: rotate(0deg) scale(1.045) translateY(-6px) !important; }
.yt-grid--shorts .watchlist-toggle { width: 30px; height: 30px; }
.yt-grid--shorts .watchlist-toggle svg { width: 15px; height: 15px; }
/* Shorts cards stay clean and minimal at their narrow width; view counts
   only show on the wider regular-video cards. */
.yt-grid--shorts .yt-card-views { display: none; }

@media (max-width: 560px) {
  .yt-main-grid.yt-grid--shorts { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .yt-shelf > .vod-card, .yt-shelf > .skeleton-card { flex-basis: 240px; }
  #yt-grid .yt-short-badge { font-size: 0.62rem; padding: 3px 7px 3px 5px; }
}

/* ---------- "Aus dem Archiv" discovery row ----------
   A random sample from the Videos tab's archive, surfaced above the sort
   bar and main shelf -- the same "discovery angle on top of the plain
   chronological list" idea as vods.css's .twitch-spotlight-*, but presented
   as its own horizontal row using the exact same card language as the shelf
   below it (see computeSpotlight/renderSpotlight in js/youtube.js), not a
   single wide spotlight card. Data-gated in js/youtube.js: unlike the
   Twitch VOD archive, which vods.js gates at just 3 items because that list
   is permanently capped at 12 by its own fetch script, main-videos.json
   holds the channel's *entire* upload history with no such cap -- once the
   YouTube Data API key is configured it can grow to hundreds of videos, so
   a low gate here would just always pass and never actually confirm there's
   a real pool to discover from. Today's real count (see main-videos.json)
   is only 4 non-Short videos, comfortably below that gate, so this
   deliberately renders nothing yet rather than re-surfacing the same 4
   cards already fully visible one scroll away. */
.yt-spotlight-label {
  font-family: "Bebas Neue", sans-serif;
  font-size: 0.9rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--accent-red);
  margin: 0 0 6px 4px;
}
/* Needs an explicit width: its parent .yt-library is a centered flex column,
   so without this it would shrink-wrap to the row's own content instead of
   100% resolving against the real (up to 1200px) row width. */
#yt-spotlight { width: 100%; }

