/* MVP Dashboard Clone V0.7.0
   Page-specific layout only. Every color, radius, spacing, blur, motion duration and
   component shape comes from assets/momentum.css (loaded before this file) - this sheet
   composes those tokens/components into the mvp-dashboard page shell (the four zones +
   drawer + footer) and adds nothing that duplicates a momentum.css component. See
   docs/DESIGN-SYSTEM.md for the harvest.

   Design law inherited from momentum.css: no italics, no em dashes, no pill radii (max
   14px panel radius; 50% only on round dots/rings/blobs), dark theme only, mobile first,
   --mom-gold is body gold, --mom-gold-ops is header-chrome gold, no cyan anywhere. */

/* Real measured height of .mom-footer, used by momentum.css to bound the drawer/backdrop
   above the footer rather than the OPS console's hardcoded 38px world-clock-only strip.
   Page-specific value, so it lives here rather than in momentum.css's own token section.
   V1.1.0 (JOB 1): .mom-footer is now the world-clock ribbon only (the link grid moved up
   into #quick-links-panel, the brand/version row is deleted - see momentum.css section 12),
   so this dropped from 104px to a real measured ~55px at 1680px, the same reference width
   the rest of this file's "Real measured..." comments use. At 390px the 7-city ribbon wraps
   to more rows (up to ~162px measured) - this single value does not chase that, same
   approximation the old 104px already made against an even taller, more variable footer. */
:root {
  --mom-footer-h: 60px;
  /* V1.4.0 (FIX 2): the explicit height of .shell-row--main, named here so the desktop rule
     and the 1180px stacked rule below can never drift apart. Raised from 600px to 760px for
     one measured reason: the right-hand column now carries THREE panels (05 LIVE at 483px of
     real content, PROGRESS at 76px, 06 REPLAYS with a 132px floor) plus two 22px gaps, which
     needs 735px. At 600px the rotation rows were squeezed out of 05 LIVE entirely. The extra
     height also goes to 02 ALERTS and 03 LATEST RELEASES, which is where Anric wanted more
     room to begin with. The orb keeps its own size and simply centres in the taller column;
     its internal proportions are relative to .gear-cluster-zone, not to this value. */
  --mvp-row-h: 760px;
}

* {
  box-sizing: border-box;
}

/* V1.5.0 (FIX 2, second half of the root cause). #mn-bar declares position:sticky/top:0, but
 it was NOT actually sticking: overflow-x:hidden here makes the other axis compute to auto
 (CSS Overflow 3: a "visible" value becomes "auto" when the other axis is neither visible nor
 clip), which turns the root element into a scroll container and silently disables sticky
 positioning for its descendants. Measured before this change at 1280px: scroll the page to
 y=600 and #mn-bar's top reads -570, i.e. the header scrolled away with the document. That is
 the literal mechanism behind Anric's "Unless you scroll the whole page because the header
 covers the top" - the only way he could reach the drawer's close control was to scroll the
 header off the page.
 overflow-x:clip clips the same horizontal overflow but does NOT create a scroll container,
 so overflow-y stays visible and sticky works again. Verified after: at both 1280 and 390 the
 bar's top reads 0 at scroll y=800, and documentElement.scrollWidth still equals innerWidth at
 390 (no horizontal scroll). The hidden declaration is kept first as a fallback for anything
 that does not support clip; there it behaves exactly as it did before this build. */
html,
body {
  margin: 0;
  padding: 0;
  max-width: 100%;
  overflow-x: hidden;
  overflow-x: clip;
}

body {
  background: var(--mom-bg-page);
  color: var(--mom-text-body);
  font-family: var(--mom-font-body-member);
  font-size: var(--mom-text-md);
  line-height: 1.45;
  font-style: normal;
  /* This page never renders a light surface, so tell the UA to pick its default form
     controls and scrollbars from the dark end of its palette rather than the light default
     WebKit otherwise assumes. */
  color-scheme: dark;
}

a {
  color: var(--mom-blue);
}
a:focus-visible,
button:focus-visible,
input:focus-visible,
[tabindex]:focus-visible {
  outline: 1px solid var(--mom-gold);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---- Preview banner: unmissable, red, sits above the HUD ---- */
.preview-banner {
  position: relative;
  background: var(--mom-red);
  color: #fff;
  padding: 7px 16px;
  text-align: center;
  font-family: var(--mom-font-mono);
  font-size: 11px;
  letter-spacing: 0.3px;
}
.preview-banner a {
  color: #fff;
  text-decoration: underline;
}
.preview-banner-tag {
  display: inline-block;
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: 10px;
  letter-spacing: 2px;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--mom-radius-xs);
  padding: 2px 7px;
  margin-right: 8px;
}

/* ---- CORS-degradation banner (V1.0.0, header port): same shape as .preview-banner above,
   distinct color (--mom-orange, an existing warning-adjacent token, not a new color) so it
   reads as a live-data warning rather than the static "this is a preview build" notice.
   Hidden by default in index.html; revealed by window.mvpShowCorsBanner() only when a real
   fetch to mvp-access-gate-worker or mvp-profile-worker actually fails. ---- */
.preview-banner--warn {
  background: var(--mom-orange);
}

/* ---- HUD status strip micro pieces (layout only, styling lives in momentum.css) ---- */
#hud-search-affordance {
  background: transparent;
  cursor: pointer;
}
#hud-search-affordance:hover {
  border-color: var(--mom-gold-ops);
  color: var(--mom-gold-ops);
}

/* ---- Main shell ----
   V0.6.0 job 3: max-width removed so the grid can span the full viewport (previously
   capped at 1360px, which left the orb - now the row's dominant element - squeezed into a
   fixed-width center column regardless of how wide the browser actually was). Horizontal
   padding stays as a gutter; nothing else about the shell's vertical rhythm changes. */
main {
  margin: 0 auto;
  padding: var(--mom-space-6) var(--mom-space-6) var(--mom-space-10);
  display: flex;
  flex-direction: column;
  gap: var(--mom-space-6);
}

/* ---- Search row (now a standalone strip above the four zones) ---- */
.search-row {
  position: relative;
}

.search-wrap {
  position: relative;
}

#search-input {
  width: 100%;
  background: var(--mom-bg-inset);
  border: 1px solid var(--mom-border-soft);
  color: var(--mom-text);
  padding: 10px 12px;
  font-size: var(--mom-text-base);
  font-family: var(--mom-font-body-member);
  border-radius: var(--mom-radius-sm);
}
#search-input:focus-visible {
  border-color: var(--mom-gold);
}
#search-input::placeholder {
  color: var(--mom-text-muted);
}

.search-results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 20;
  display: none;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--mom-bg-modal);
  border: 1px solid var(--mom-border-strong);
  border-radius: var(--mom-radius-md);
  box-shadow: var(--mom-shadow-modal);
  backdrop-filter: blur(var(--mom-blur-md));
  -webkit-backdrop-filter: blur(var(--mom-blur-md));
}
.search-results.open {
  display: block;
}

/* V1.6.0 (snag 1, direct from Anric: "the window with results is so small and narrow that
 you can't actually really read the results"). Root cause, measured, not guessed: when the
 header's copy of this dropdown is open, positionPalette() in app.js (out of scope this pass,
 see docs/SNAG-LIST.md) sizes and places #search-results by copying the SEARCH INPUT's own
 box - left, width, top from .search-wrap's getBoundingClientRect() - so the dropdown is
 exactly as wide as the compact header search field, never wider. Measured at 1280px before
 this fix: panel width 173px, .sr-name clientWidth 54px against a 12px font, an 8-9 character
 window before ellipsis truncation on result names up to 38 characters long (e.g.
 "RaisingCapital.Live (1-Day Intensive)" read as roughly "RaisingCap..."). The input itself is
 deliberately narrow at every breakpoint (150-300px, see #mn-bar .search-wrap in index.html)
 to fit the header row; the RESULTS panel does not need to match that width to be usable, and
 CSS can override the JS-set inline styles without touching app.js: min-width/max-width are
 applied by the browser after the cascade regardless of an inline pixel `width`, and a
 stylesheet `!important` beats a plain (non-important) inline style for left/right/width.
 Anchoring from the header's own right inset (16px, less than the smallest breakpoint's own
 #mn-bar padding of 12px, so it never crowds the frame) rather than from the narrow input's
 left edge means one rule works at every width instead of a matching breakpoint ladder.
 Measured after: panel width 369px at 1280px (up from 173px), full result names visible with
 no truncation on the sampled list; 343px at 375px (clamped by calc(100vw - 32px)), only the
 single longest sampled name (38 characters) still truncates there. */
#search-results.open {
  left: auto !important;
  right: 16px !important;
  width: auto !important;
  min-width: 320px;
  max-width: min(440px, calc(100vw - 32px));
}

/* V1.5.0 (FIX 2): the head row gains a real, visibly reachable close control. Escape and
 click-outside both already closed this dropdown, but neither is visible, and Anric's report
 was specifically about not being able to see a way out. The head is the first thing painted
 and the dropdown hangs BELOW the header it lives inside, so this control can never be
 covered by header chrome the way the drawer's × was. */
.sr-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 12px;
  font-family: var(--mom-font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mom-text-muted);
  border-bottom: 1px solid var(--mom-border-faint);
}
.sr-head-text {
  flex: 1 1 auto;
  min-width: 0;
}
.sr-close {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--mom-red-dim);
  border: 1px solid rgba(220, 20, 60, 0.4);
  color: var(--mom-red);
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--mom-radius-xs); /* never pill */
}
.sr-close:hover,
.sr-close:focus-visible {
  background: rgba(220, 20, 60, 0.25);
  color: #fff;
}
.sr-empty {
  padding: 14px 12px;
  font-family: var(--mom-font-mono);
  font-size: 12px;
  color: var(--mom-text-muted);
}
.sr-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--mom-border-faint);
  cursor: pointer;
}
.sr-item:last-child {
  border-bottom: 0;
}
.sr-item:hover,
.sr-item.active {
  background: var(--mom-gold-dim);
}
.sr-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  background: var(--mom-bg-inset);
  border: 1px solid var(--mom-border-ops);
  border-radius: var(--mom-radius-xs);
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: 9px;
  color: var(--mom-gold-ops);
}
.sr-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--mom-text-base); /* V1.6.0 (snag 1): 13px, up from a hardcoded 12px, to
    match the body tier used for every other "thing being read" row (.release-row-body,
    .note-sec-body) - this is the result NAME, not metadata, so it gets the same tier they
    get, not the smaller one. The width fix above (#search-results.open) is what actually
    stops truncation; this only brings the one remaining off-tier size back in line. */
  color: var(--mom-text);
}
.sr-cat {
  flex-shrink: 0;
  font-family: var(--mom-font-mono);
  font-size: 10px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--mom-blue);
}

/* Concept-aware search (Layer 2, Magnum curriculum index): a routing cluster painted above
   the ordinary sr-head/sr-item rows by paletteConceptHTML in app.js (conceptClusterHTML() /
   taskClusterHTML()). Same panel, same squared corners, same gold-on-black vocabulary as the
   rest of #search-results - this is not a second dropdown, it is a labelled zone at the top
   of the one dropdown that already exists. */
.sr-concepts {
  border-bottom: 1px solid var(--mom-border-strong);
  background: var(--mom-bg-inset);
}
.sr-concepts-label {
  padding: 6px 12px 4px;
  font-family: var(--mom-font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mom-gold-ops);
}
.sr-concept {
  padding: 2px 12px 10px;
  border-bottom: 1px solid var(--mom-border-faint);
}
.sr-concept:last-child {
  border-bottom: 0;
}
.sr-concept-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 4px 0 6px;
}
.sr-concept-name {
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: var(--mom-text-base);
  color: var(--mom-gold);
}
.sr-concept-prereq {
  flex-shrink: 0;
  padding: 2px 6px;
  font-family: var(--mom-font-mono);
  font-size: 9px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--mom-red);
  background: var(--mom-red-dim);
  border: 1px solid rgba(220, 20, 60, 0.4);
  border-radius: var(--mom-radius-xs); /* never pill */
}
.sr-concept-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 3px 0;
  text-decoration: none;
}
a.sr-concept-line:hover .sr-concept-line-value,
a.sr-concept-line:focus-visible .sr-concept-line-value {
  color: var(--mom-gold);
  text-decoration: underline;
}
.sr-concept-line-label {
  flex-shrink: 0;
  width: 68px;
  font-family: var(--mom-font-mono);
  font-size: 9px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--mom-text-muted);
}
.sr-concept-line-value {
  min-width: 0;
  font-size: 12px;
  color: var(--mom-text);
}
.sr-concept-line--flat .sr-concept-line-value {
  color: var(--mom-text-muted);
}

/* ---- The four zones: portal rail | welcome+release | orb | live+replays ----
   V0.5.0. An explicit row height governs this row rather than its content, per the brief:
   "the row height must be governed by ... an explicit row height, not by content." Each
   column stretches to that height and any panel body that can overflow (the note, the
   release feed, the replays list) scrolls internally (flex: 1 1 0; min-height: 0;
   overflow-y: auto - never a fixed max-height, which is what clipped the sibling columns
   on the real GHL-hosted dashboard once before). */
/* V0.6.0 job 3 (SUPERSEDED, see below): orb-col used to take 2.6fr of the row against 0.9fr
   each for notewell-col/live-replays-col.
   V1.3.0 (04 THE ORB, direct from Anric, "very rectangular"): orb-col's share is cut from
   2.6fr to 1.9fr and the reclaimed 0.7fr goes entirely to live-replays-col (0.9fr -> 1.6fr,
   per the brief: "give the reclaimed width to 05 LIVE and 06 REPLAYS"). notewell-col is
   untouched at 0.9fr - it was not named as a recipient. Total flexible share stays 4.4fr
   before and after (0.9+2.6+0.9 = 0.9+1.9+1.6), so this is a pure reallocation, not a change
   to how much of the row is fixed vs flexible. Measured at 1680px: orb-col 804px -> 587px
   (27% narrower), live-replays-col 278px -> ~495px (78% wider). The orb's own internal
   proportions (centre 44%, big gears 28%, small 22%, momentum.css section 10) are relative
   to .gear-cluster-zone's own box, not this column, so they are unaffected by this change.

   V1.4.0 (FIX 3, direct from Anric: "we don't really need all of that width on Box 05 and
   06. We can probably use more width on Box 02 and 03, so I would space them out evenly.").
   V1.3.0 handed ALL of the width reclaimed from the orb to the right-hand column, which left
   the two content columns 217px apart at 1680 (notewell 278 vs live 495) and wrapped the
   LATEST RELEASES copy every few words. The two content columns are now EQUAL flexible
   tracks: 0.9fr/1.6fr become 1.25fr/1.25fr, which is the same 2.5fr of flexible share
   redistributed evenly, so the total flexible share is still 4.4fr (1.25+1.9+1.25) and the
   orb is untouched at 1.9fr - Anric is not complaining about the orb now. This is expressed
   as two identical fr tracks, not as four hardcoded pixel widths, so the two columns stay
   equal at every viewport width above the stacking breakpoints, and minmax(0, ...) keeps a
   long unbroken string inside either column from forcing that track wider than its share.
   Predicted at 1680 (flexible pool measured at 1359px): notewell 386, orb 587, live 386. */
.shell-row--main {
  display: grid;
  grid-template-columns: 240px minmax(0, 1.25fr) minmax(0, 1.9fr) minmax(0, 1.25fr);
  gap: var(--mom-space-6);
  height: var(--mvp-row-h); /* CHOSEN explicit row height: the fixed sibling this row is governed by */
  align-items: stretch;
}
.shell-row--main > * {
  height: 100%;
  min-height: 0;
}

/* ---- Portal rail (zone 1) ---- */
.portal-rail {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.portal-rail .mom-portal-list {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
}

/* ---- Welcome note + release feed column (zone 2) ---- */
.notewell-col {
  display: flex;
  flex-direction: column;
  gap: var(--mom-space-6);
  min-height: 0;
}
.notewell-col > .mom-panel {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.notewell-body,
.release-body {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  position: relative; /* V0.7.0 (change 5): containing block for .scroll-fade, see below */
}

/* Dark thin scrollbars for the three panels that actually scroll their own content: 02
   ALERTS (.notewell-body), 03 LATEST RELEASES (.release-body) and 06 REPLAYS
   (.replays-body, defined further below). None of these overflow-y:auto containers set a
   scrollbar color before, so WebKit fell back to its light default and drew a white bar
   against this dark panel. Track stays transparent so the panel's own background shows
   through; thumb is a neutral dark tone, not gold, so it reads as chrome rather than an
   accent. */
.notewell-body,
.release-body,
.replays-body {
  scrollbar-width: thin;
  scrollbar-color: rgba(58, 52, 42, 0.65) transparent;
}
.notewell-body::-webkit-scrollbar,
.release-body::-webkit-scrollbar,
.replays-body::-webkit-scrollbar {
  width: 8px;
}
.notewell-body::-webkit-scrollbar-track,
.release-body::-webkit-scrollbar-track,
.replays-body::-webkit-scrollbar-track {
  background: transparent;
}
.notewell-body::-webkit-scrollbar-thumb,
.release-body::-webkit-scrollbar-thumb,
.replays-body::-webkit-scrollbar-thumb {
  background: rgba(58, 52, 42, 0.65);
  border-radius: 4px;
}
.notewell-body:hover::-webkit-scrollbar-thumb,
.release-body:hover::-webkit-scrollbar-thumb,
.replays-body:hover::-webkit-scrollbar-thumb {
  background: rgba(74, 66, 54, 0.85);
}
.note-lead {
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: var(--mom-text-xl);
  color: var(--mom-gold);
  margin: 0 0 var(--mom-space-4);
}
.note-sec {
  padding: var(--mom-space-3) 0;
  border-bottom: 1px solid var(--mom-border-faint);
}
.note-sec:last-of-type {
  border-bottom: 0;
}
.note-sec-title {
  font-family: var(--mom-font-mono);
  font-size: var(--mom-text-sm);
  font-weight: 700;
  letter-spacing: 0.6px;
  color: var(--mom-text);
  margin-bottom: 3px;
}
.note-sec-body {
  font-size: var(--mom-text-base);
  color: var(--mom-text-soft);
  margin: 0;
}
.note-sec-body a {
  color: var(--mom-gold);
}
.note-signoff {
  margin-top: var(--mom-space-4);
  font-size: var(--mom-text-sm);
  color: var(--mom-text-muted);
  font-style: normal;
}

/* V1.3.0 (03 LATEST RELEASES, direct from Anric): "absolutely" left aligned, and the status
   badge (new/updated/beta) moved OUT of the text flow to a right-aligned column so copy
   starts flush left on every row. justify-content:space-between + the badge's own
   flex-shrink:0 pins it to the row's right edge regardless of label width, which is what
   makes it read as a column rather than a trailing inline chip. */
.release-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--mom-space-3);
  padding: 8px 0;
  border-bottom: 1px solid var(--mom-border-faint);
  text-align: left;
}
.release-row:last-child {
  border-bottom: 0;
}
.release-row-body {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--mom-text-base);
  color: var(--mom-text-soft);
  text-align: left;
}
.release-row-body a {
  color: var(--mom-gold);
}
.release-row .mom-badge {
  flex-shrink: 0;
  margin-top: 1px;
}

/* ---- Orb column (zone 3): the real gear-cluster orb (data-driven, see app.js buildOrb()
   and momentum.css section 10). V0.6.0 job 3: this column now takes the majority share of
   the row's horizontal width (see .shell-row--main grid-template-columns below) instead of
   the placeholder's fixed small ring. ---- */
.orb-col {
  align-items: center;
  justify-content: center;
  gap: var(--mom-space-3);
  overflow: hidden;
}

/* ---- Gear one-liner tooltip (card 04 THE ORB) ----
   Optional per-gear "oneLiner" (data/orb.json, app.js gearHTML()) gets a styled hover/focus
   tooltip here. Absolutely positioned relative to the .gear anchor (already
   position:absolute, see momentum.css section 10), so it never adds to document flow and can
   never shift or resize a dial. All tokens borrowed from momentum.css, nothing new
   introduced. Radius is --mom-radius-lg (9px): squared, inside the 6-10px band, never a pill.
   Per-position placement: the compass position classes (.gear.pos-*, momentum.css section 10)
   tell us where on the ring a gear sits, so the tooltip flips to the side with more real
   room instead of a single fixed direction that would run the top row off the top of the
   panel or the bottom row off the bottom (both card edges the brief requires never overflow).
   Top-half gears (n/ne/nw) open downward, toward the ring's own centre; bottom-half gears
   (s/se/sw) open upward, same reasoning. Side gears (e/w) stay vertically centred and instead
   anchor horizontally inward (toward centre) so the box never runs past the panel's left or
   right edge on a narrow viewport.

   DEFECT FIX (Anric, 2026-08-14): the styled box was painting BEHIND the orb's own TOOLS /
   PROGRAMS / EVENTS / LIBRARY corner tiles (momentum.css .corner-shortcut, z-index:5). Root
   cause is a stacking context, not a z-index number: momentum.css's .gear-cluster (the direct
   parent of every .gear) is `position: relative; z-index: 1`, and ANY element that is
   positioned with an explicit z-index becomes a new stacking context, full stop. That traps
   this tooltip's own z-index (below) inside .gear-cluster's context - it can never climb out
   to compete against .corner-shortcut, which sits one level up as a sibling of .gear-cluster,
   no matter how large a number this rule uses. A bigger z-index here would have done nothing;
   .orb-col's overflow:hidden was checked too and is not the cause, since every tooltip
   already stays inside the panel by the placement rules above.
   The fix is the one-line override directly below: neutralise .gear-cluster's z-index so it
   stops creating that inner stacking context. .gear-cluster was already painting below
   .corner-shortcut before this change (1 < 5) and still does after (auto sits at the same
   paint tier as momentum.css's other unstacked/zero-index orb layers, still under the
   corners' explicit z-index:5) - the 8 gear discs and the 4 corner tiles keep their exact
   existing overlap order in the resting state. Only .gear-tooltip, no longer trapped, now
   escapes to compare its own z-index directly against .corner-shortcut's, and wins. */
.gear-cluster {
  z-index: auto;
}
.gear-tooltip {
  position: absolute;
  z-index: 20;
  top: calc(100% + 30px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 200px;
  padding: var(--mom-space-2) var(--mom-space-3);
  background: var(--mom-bg-modal);
  border: 1px solid var(--mom-border-strong);
  border-radius: var(--mom-radius-lg);
  box-shadow: var(--mom-shadow-modal);
  color: var(--mom-text-body);
  font-family: var(--mom-font-body-member);
  font-size: var(--mom-text-xs);
  font-style: normal;
  line-height: 1.4;
  text-align: center;
  text-transform: none;
  letter-spacing: normal;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.gear:hover .gear-tooltip,
.gear:focus-visible .gear-tooltip {
  opacity: 1;
  visibility: visible;
}

/* Bottom-row gears: open upward instead of downward, toward the ring centre. */
.gear.pos-s .gear-tooltip,
.gear.pos-se .gear-tooltip,
.gear.pos-sw .gear-tooltip {
  top: auto;
  bottom: calc(100% + 12px);
}

/* Right-side gears: anchor to the gear's own right edge and grow leftward, toward centre. */
.gear.pos-e .gear-tooltip,
.gear.pos-ne .gear-tooltip,
.gear.pos-se .gear-tooltip {
  left: auto;
  right: 0;
  transform: none;
}

/* Left-side gears: anchor to the gear's own left edge and grow rightward, toward centre. */
.gear.pos-w .gear-tooltip,
.gear.pos-nw .gear-tooltip,
.gear.pos-sw .gear-tooltip {
  left: 0;
  transform: none;
}

/* ---- Live sessions + replays column (zone 4) ---- */
.live-replays-col {
  display: flex;
  flex-direction: column;
  gap: var(--mom-space-6);
  min-height: 0;
}
.live-replays-col > .mom-panel {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* V1.4.0 (FIX 2): this column carries THREE panels now (05 LIVE, PROGRESS, 06 REPLAYS)
   where it carried two, and 05 LIVE itself gained a time line, two more buttons and a third
   event row. Left on the equal "flex: 1 1 0" share above, each panel got a third of the
   row's fixed height and 05 LIVE's three rotation rows were squeezed out of sight into its
   own internal scroller - which is exactly the "the live box is still not showing up
   properly" symptom this fix exists to remove. So: 05 LIVE and PROGRESS are content-sized
   (flex: 0 0 auto, and .live-rotation no longer scrolls internally, so all three rows are
   always visible in full), and 06 REPLAYS takes whatever is left with its own internal
   scroll, which is what it already did. */
.live-replays-col > .live-sessions-panel,
.live-replays-col > .live-progress-panel {
  flex: 0 0 auto;
}
.live-replays-col > .replays-panel {
  flex: 1 1 0;
  min-height: 132px;
}

.live-sessions-panel {
  gap: var(--mom-space-3);
}
/* ── 05 LIVE (V1.4.0, FIX 2) ────────────────────────────────────────────────────────────
   Ported from Anric's own Box 03 WEDNESDAY ROTATION rules in
   docs/reference/v3-source/02A_STYLES.html (.mvp-cmd .lr-row / .lr-tag / .lr-name /
   .lr-host / .lr-cd / .lr-times / .live-cta-row / .live-cta.primary|ghost|cafe, and
   .panel.mini-progress), re-expressed against this repo's momentum.css tokens where a token
   holds the identical value (--mom-red is #dc143c, the exact crimson his .lr-tag and
   .live-cta.primary use; --mom-gold is #f0c173, the exact gold his .lr-cd and .live-cta.ghost
   use). His literal pixel values for size, padding, radius and gap are kept as written.
   NO overflow:hidden and NO negative margins anywhere in this block: that pairing is what
   clipped "NEXT" to "EXT" and "Anric and Lauralouise" to "nric and Lauralouise" in V1.3.0.
   Long titles and hosts wrap now instead of being cut. */
.live-rotation {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 0 0 auto; /* V1.4.0: exactly three rows, always all three visible, never a scroller */
  position: relative;
}
/* His .lr-row: 3 columns, chip / stacked name+host / right-aligned countdown. His literal
   px values are stepped down about one point across this block (14.5 -> 13.5 on the title,
   11 -> 10 on the chip, 13px -> 12px row padding, and so on) for one measured reason: this
   clone's right-hand column is 386px wide where his is roughly 500px, and at his sizes the
   three titles wrapped to two lines each and pushed the panel past the row's height budget.
   Proportions, colours and structure are his, unchanged. */
.live-rotation-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 9px;
  align-items: center;
  padding: 9px 12px;
  background: rgba(220, 20, 60, 0.05);
  border: 1px solid rgba(220, 20, 60, 0.18);
  border-radius: 9px;
}
.live-rotation-row.is-next {
  background: rgba(220, 20, 60, 0.12);
  border-color: rgba(220, 20, 60, 0.5);
  box-shadow: 0 0 18px rgba(220, 20, 60, 0.18);
}
/* His .lr-tag: the left chip. NEXT on the soonest row, the short date on the rest. */
.live-rotation-tag {
  font-family: var(--mom-font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--mom-red);
  text-transform: uppercase;
  background: rgba(220, 20, 60, 0.1);
  border: 1px solid rgba(220, 20, 60, 0.3);
  padding: 3px 7px;
  border-radius: 5px;
  white-space: nowrap;
}
.live-rotation-row.is-next .live-rotation-tag {
  background: var(--mom-red);
  color: #fff;
  border-color: var(--mom-red);
}
.live-rotation-body {
  min-width: 0;
}
/* His .lr-name / .lr-host. Both wrap rather than clip - see the block comment above. */
.live-rotation-name {
  display: block;
  font-size: 13.5px;
  color: var(--mom-text);
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.live-rotation-host {
  display: block;
  font-family: var(--mom-font-mono);
  font-size: 11px;
  color: #aaa;
  margin-top: 3px;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
/* His .lr-cd. */
.live-rotation-cd {
  font-family: var(--mom-font-mono);
  font-size: 11.5px;
  color: var(--mom-gold);
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* His .lr-times: one centred line, dashed rule above and below. */
.live-times {
  font-family: var(--mom-font-mono);
  font-size: 11.5px;
  color: #888;
  text-align: center;
  margin: 0;
  padding: 8px 0;
  border-top: 1px dashed rgba(255, 255, 255, 0.06);
  border-bottom: 1px dashed rgba(255, 255, 255, 0.06);
  letter-spacing: 0.8px;
}
/* His two .live-cta-row rows, expressed as the one 2x2 grid they read as:
   JOIN ROOM | REPLAYS on top, ADD TO CALENDAR | MAGNUM CAFE beneath. */
.live-cta-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-top: 12px;
}
.live-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 9px;
  padding: 10px 10px;
  text-decoration: none;
  border-radius: 8px;
  font-family: var(--mom-font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.8px;
  line-height: 1.25;
  transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease,
    transform 0.18s ease, color 0.18s ease;
}
/* His .live-cta.primary is flat #DC143C. Anric's V1.3.0 note on this same button ("JOIN ROOM
   needs more shadow and gradient so it reads three-dimensional") is kept by giving that same
   crimson a two-stop gradient of itself plus the contact/ambient shadow pair and inset top
   sheen already used on this page - the colour is his, the depth is the note he gave. */
.live-cta--primary {
  color: #fff;
  background-image: linear-gradient(135deg, #e8264c 0%, var(--mom-red) 55%, #a8102e 100%);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45), 0 4px 14px rgba(220, 20, 60, 0.4),
    0 10px 30px rgba(220, 20, 60, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.live-cta--primary:hover,
.live-cta--primary:focus-visible {
  background-image: linear-gradient(135deg, #f0355b 0%, #c81236 55%, #970d29 100%);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5), 0 6px 20px rgba(220, 20, 60, 0.55),
    0 12px 36px rgba(220, 20, 60, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.34);
  transform: translateY(-1px);
}
/* His .live-cta.ghost. */
.live-cta--ghost {
  background: rgba(240, 193, 115, 0.06);
  border: 1px solid rgba(240, 193, 115, 0.3);
  color: var(--mom-gold);
}
.live-cta--ghost:hover,
.live-cta--ghost:focus-visible {
  background: rgba(240, 193, 115, 0.14);
  border-color: var(--mom-gold);
}
/* His .live-cta.cafe: same crimson family as JOIN ROOM but visibly quieter, so JOIN ROOM
   stays the primary. No border, matching his .primary. */
.live-cta--cafe {
  background: #9c1f33;
  color: #fff;
  box-shadow: 0 4px 12px rgba(220, 20, 60, 0.25);
}
.live-cta--cafe:hover,
.live-cta--cafe:focus-visible {
  background: #b8243a;
  box-shadow: 0 6px 16px rgba(220, 20, 60, 0.4);
  transform: translateY(-1px);
}

/* PROGRESS, his .panel.mini-progress. Sits under 05 LIVE in the same column, framed the same
   way every other .mom-panel on this page is framed. */
.live-progress-panel {
  gap: 0;
  padding-top: 12px;
  padding-bottom: 12px;
}
.live-progress-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mom-font-mono);
  font-size: 11.5px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(240, 193, 115, 0.14);
}
.live-progress-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--mom-gold);
  box-shadow: 0 0 10px var(--mom-gold);
  flex-shrink: 0;
}
.live-progress-label {
  color: var(--mom-gold);
  font-weight: 600;
}
.live-progress-value {
  font-family: var(--mom-font-mono);
  font-size: 11.5px;
  color: var(--mom-gold);
  letter-spacing: 0.9px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

/* The 2x2 grid holds all the way down to 390px (measured: 155px per cell there, enough for
   ADD TO CALENDAR on one line). Only below 360px, where the cells would be too narrow for
   the longest label, does it fall back to a single column. Still four buttons, same order. */
@media (max-width: 359px) {
  .live-cta-grid {
    grid-template-columns: 1fr;
  }
}

/* prefers-reduced-motion: the only motion in this block is the 1px lift on the CTA buttons. */
@media (prefers-reduced-motion: reduce) {
  .live-cta,
  .live-cta--primary:hover,
  .live-cta--primary:focus-visible,
  .live-cta--cafe:hover,
  .live-cta--cafe:focus-visible {
    transition: none;
    transform: none;
  }
}


.replays-body {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  position: relative; /* V0.7.0 (change 5): containing block for .scroll-fade */
}
/* V1.3.0 (06 REPLAYS, direct from Anric): two-line entries (his example: the May 13 row)
   were being swallowed. align-items:baseline snapped a 2-line title's baseline to the single-
   line date column, which visually clipped/mis-set the row's height at some widths; switched
   to flex-start so the date pins to the title's first line and the row grows to whatever
   height a wrapped 2-line title needs. .replay-title gets an explicit flex/min-width so it
   wraps within the row instead of being squeezed by the fixed-width date column, and
   white-space/overflow are pinned to normal/visible so nothing upstream can silently clip it
   again. */
.replay-row {
  display: flex;
  align-items: flex-start;
  gap: var(--mom-space-3);
  padding: 7px 0;
  border-bottom: 1px solid var(--mom-border-faint);
  text-decoration: none;
}
.replay-row:last-child {
  border-bottom: 0;
}
.replay-row:hover .replay-title,
.replay-row:focus-visible .replay-title {
  color: var(--mom-gold);
}
.replay-date {
  flex-shrink: 0;
  align-self: flex-start;
  padding-top: 1px; /* optical alignment with the title's first line now that align-items is flex-start */
  font-family: var(--mom-font-mono);
  font-size: var(--mom-text-xs);
  letter-spacing: 0.8px;
  color: var(--mom-text-muted);
  width: 6ch;
}
/* V1.6.0 (snag 5, direct from Anric: "the font of the details in card number six of the
 replays is too small and unreadable"). Root cause, measured: .replay-title - the replay's
 own name, the thing actually being read in this row - was set to --mom-text-sm (11px), the
 SAME metadata-tier size used elsewhere for captions and micro-labels (.cm-meta,
 .welcome-sub), one tier below --mom-text-base (13px), which is what every sibling panel uses
 for its own "thing being read" row text (.release-row-body in card 03, .note-sec-body in
 card 02). .replay-date (the metadata next to it: just a short date) is correctly small at
 --mom-text-xs/10px and is left alone - per the design system, metadata can stay small, but
 the title is not metadata. Bumped .replay-title to the same body tier its siblings already
 use, restoring the hierarchy rather than uniformly enlarging the row. */
.replay-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--mom-text-base);
  color: var(--mom-text-soft);
  white-space: normal;
  overflow: visible;
}

/* ---- Catalog telemetry strip (not one of the four named zones, still present) ----
   V0.7.0 (change 3): computed panel height cut roughly in half. All 7 figures (TOTAL ITEMS
   hero, LIVE, NEW, BETA, COMING SOON, NO URL count+meter, FACETS) still render - nothing
   dropped, every count is still buildTelemetry()'s own independent state.items filter,
   app.js untouched - this is a type/spacing-only compaction. The hero figure is pinned to
   --mom-text-4xl (28px, the rule's "largest text on the page stays at least 28px" floor)
   rather than the previous --mom-text-5xl (32px); every other size below was walked down
   from there, not shrunk arbitrarily.

   Measuring the strip's own padding/gap/font shrinks alone (below) only took the panel from
   127.8px to 115.8px at 1680px - most of the panel's height turned out to be
   `.mom-section-label` (the "CATALOG TELEMETRY" heading, shared by every panel on the page)
   plus its own margin-bottom, not the strip content. Since that class is shared chrome used
   on every OTHER panel too, it is left untouched at its base definition (momentum.css) -
   instead it is scoped down for JUST this panel below, the same "targeted, don't touch what
   isn't named" rule the rest of this change follows.

   Measured before/after with getBoundingClientRect() on #telemetry-panel at 1680px:
   127.8px -> 73.1px (43% shorter). Not an exact half: the remaining floor is the hero
   figure itself (28px, line-height 1) plus its micro-label (--mom-text-2xs, 8px - already
   the system's documented smallest real UI text, see momentum.css section 1) plus a 2px
   gap, ~41.6px total, and the rule set for this task is explicit that the 28px hero floor
   wins over hitting an exact half ("don't shrink that below 28px even when halving the
   panel") - so this stops at the true achievable floor rather than either breaking that
   rule or leaving easy padding/heading savings on the table. */
.telemetry-strip {
  padding: var(--mom-space-1) var(--mom-space-6); /* was space-5/space-7 (14px 18px) */
}
.telemetry-strip .mom-section-label {
  font-size: var(--mom-text-xs); /* 10px, was --mom-text-lg (16px) - scoped to this panel
    only, .mom-section-label's base rule (used by every other panel heading) is untouched.
    10px is the same micro-label tier already used elsewhere in this system (.mom-label,
    .mom-badge sit at 10-10.5px), not a one-off invented size. */
  margin-bottom: var(--mom-space-1); /* 4px, was space-6 (16px) */
  padding-bottom: 2px; /* was space-4 (12px) */
}
.telemetry-strip-body {
  display: flex;
  align-items: center;
  gap: var(--mom-space-6); /* was space-9 (22px) */
  flex-wrap: wrap;
}
.telemetry-strip .telemetry-hero {
  flex-shrink: 0;
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: 0;
  padding-right: var(--mom-space-5); /* was space-9 (22px) */
  border-right: 1px solid var(--mom-border-faint);
}
.telemetry-strip .telemetry-hero-figure {
  font-size: var(--mom-text-4xl); /* 28px: was --mom-text-5xl (32px) - the type-scale floor
    for the page's one hero figure, not shrunk further. */
}
.telemetry-strip .telemetry-meter-list {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(108px, 1fr));
  gap: var(--mom-space-2) var(--mom-space-5); /* was a flat space-5 (14px); row gap tightened
    to space-2 (8px), column gap kept so the 6 figures don't crowd horizontally. */
}
/* Compact row: label/figure text held in the median 12-13px band the brief calls for
   (was 13px already for the label, unchanged; the figure drops from --mom-text-2xl at 22px,
   a size that was fighting the hero figure for attention in a strip half this tall, down to
   --mom-text-md at 14px) and both the row gap and the meter bar itself are slimmed to match. */
.telemetry-strip .telemetry-row {
  gap: 3px; /* was the base .mom-meter's 5px */
}
.telemetry-strip .telemetry-figure {
  font-size: var(--mom-text-md); /* 14px: was --mom-text-2xl (22px) */
}
.telemetry-strip .mom-meter-track {
  height: 3px; /* was the base .mom-meter-track's 4px */
}

/* ---- Responsive ---- */
@media (max-width: 1180px) {
  .shell-row--main {
    /* V1.4.0 (FIX 3): already two equal content tracks at this breakpoint, stated with
       minmax(0, ...) for the same reason as the desktop rule above. */
    grid-template-columns: 200px minmax(0, 1fr) minmax(0, 1fr);
    height: auto;
  }
  .orb-col {
    grid-column: 2;
    grid-row: 2;
    height: 220px;
  }
  .live-replays-col {
    grid-column: 3;
    grid-row: 1 / span 2;
    height: var(--mvp-row-h);
  }
  .notewell-col {
    grid-column: 2;
    grid-row: 1;
    height: var(--mvp-row-h);
  }
  .portal-rail {
    grid-row: 1 / span 2;
    height: var(--mvp-row-h);
  }
}
@media (max-width: 900px) {
  /* V4.2.0 (Anric: "on mobile, it seems to cut off certain boxes, they should stack, so we
     should have a mobile version that shows the live box 05 first, then the portals and the
     orb and then alerts, then quick links"). This is the real single-column stacking
     breakpoint in this file (there is no 768px breakpoint anywhere in app.css/momentum.css
     for this layout - the brief that asked for one was wrong about that; 900px, already used
     by every rule below, is where the four-zone row actually collapses to one column, so the
     reorder is scoped here instead of inventing a new breakpoint).

     .shell-row--main, .notewell-col and .live-replays-col go display:contents so their
     children stop being grouped inside three wrapper boxes and instead become direct flex
     items of <main> itself (main is `display:flex; flex-direction:column; gap: ...`
     unconditionally, see the top of this file) - that is what makes 02 ALERTS orderable
     independently of 03 LATEST RELEASES, and 05 LIVE independently of PROGRESS/06 REPLAYS,
     without duplicating any markup. Desktop (>900px) is untouched: .shell-row--main stays a
     real CSS grid there, nothing in this media query reaches it. */
  .shell-row--main,
  .notewell-col,
  .live-replays-col {
    display: contents;
  }
  .shell-row--main > * {
    height: auto;
  }

  /* Mobile reading order. The five Anric named get order 1-5; every card he did not name
     keeps its prior relative order after them (it had: 03 LATEST RELEASES right after 02
     ALERTS, then PROGRESS and 06 REPLAYS right after 05 LIVE, then 07 CATALOG TELEMETRY,
     then 12 FIND BY TOPIC - that sequence is preserved as one block, order 6-10, rather than
     scattering it). */
  #live-sessions-panel { order: 1; }  /* 05 LIVE */
  #portal-rail { order: 2; }          /* 01 PORTALS */
  #orb-col { order: 3; }              /* 04 THE ORB */
  #note-panel { order: 4; }           /* 02 ALERTS */
  #quick-links-panel { order: 5; }    /* QUICK LINKS */
  #release-feed-panel { order: 6; }   /* 03 LATEST RELEASES, not named, was right after ALERTS */
  #live-progress-panel { order: 7; }  /* PROGRESS, not named, was right after LIVE */
  #replays-panel { order: 8; }        /* 06 REPLAYS, not named */
  #telemetry-panel { order: 9; }      /* 07 CATALOG TELEMETRY, not named */
  #topic-browser-panel { order: 10; } /* 12 FIND BY TOPIC, not named */

  /* V1.6.0: found while measuring the eleven-portal rail at 390px, and NOT caused by the
     eleventh portal - it reproduced identically with ten. The desktop rule
     `.portal-rail .mom-portal-list { flex: 1 1 0; min-height: 0 }` gives this list a
     flex-basis of 0 and lets it grow into the free space of a fixed-height rail. At this
     breakpoint the rail's height becomes auto, so there is no free space to grow into, and
     a flex-basis of 0 collapsed the list to exactly 0px: every portal row was laid out and
     then clipped by the rail's own overflow:hidden. The primary navigation was invisible on
     a phone. `flex: 0 0 auto` makes the list size to its content again.
     max-height goes with it. The old 320px cap matched the other stacked panels' height,
     but it could only ever produce a scrolling rail here (ten rows were already 470px), and
     Anric's condition for accepting an eleventh portal was that the rail does not scroll.
     Content height wins over matching the neighbours: 517px, no scroll, at every width. */
  .portal-rail .mom-portal-list {
    flex: 0 0 auto;
    max-height: none;
    overflow-y: visible;
  }

  /* V4.2.0: measured root cause of 02 ALERTS / 03 LATEST RELEASES rendering as a header row
     with no visible content underneath (375px, before this fix: #note-panel height 38px,
     #note-body scrollHeight 1893px but clientHeight 0 - real content, zero visible height).
     `.notewell-col > .mom-panel`'s always-on base rule (further up this file) is
     `flex: 1 1 0`, a flex-basis of 0. With .notewell-col now display:contents it has no
     fixed height for that flex-basis to grow into, so the 320px below never took effect and
     both panels collapsed toward their min-content (basically just the section label).
     #live-sessions-panel/#live-progress-panel never had this bug because they already carry
     `flex: 0 0 auto` (also further up, unconditional) - flex-basis auto lets their own
     height apply directly. Giving the notewell panels that same, already-proven
     `flex: 0 0 auto` is the fix, scoped to this breakpoint only. */
  .notewell-col > .mom-panel {
    flex: 0 0 auto;
    height: 320px;
  }
  /* V4.2.0: the old `.live-replays-col > .mom-panel { height: 320px }` rule that used to sit
     here is gone. Measured after reordering 05 LIVE to lead the mobile stack (375px): it was
     never doing what it looked like it did. #replays-panel ignores it either way (flex: 1 1 0
     collapses under it, min-height: 132px is the real floor, same mechanism documented on
     the desktop rule above). #live-sessions-panel and #live-progress-panel DO have
     `flex: 0 0 auto` (unconditional, above), so the 320px height did apply to them - and for
     live-sessions-panel that is 129px short of its real content (three rotation rows, the
     times line, and the 2x2 CTA grid) with no overflow:hidden anywhere in this block, so the
     CTA row was rendering 129px below the panel's own edge, invisibly bleeding into whatever
     came next. Harmless-looking on V4.1.2 because that overflow spilled onto its own next
     -door sibling, PROGRESS, a visually similar panel; glaring now that 05 LIVE's very next
     panel is 01 PORTALS. Removing the height cap restores the content-sized behaviour the
     V1.4.0 comment above (`.live-replays-col > .live-sessions-panel, ...live-progress-panel`)
     already says is the intent - "all three rotation rows are always visible in full" - on
     mobile as well as desktop, instead of fighting it with a fixed height that quietly broke
     one of the two panels it could actually reach. */

  /* V4.2.0: measured root cause of 04 THE ORB being sliced at the bottom (375px, before this
     fix: .orb-col allocated 280px / 278px usable, its own .gear-cluster-zone alone measured
     341px scrollHeight - before even counting the "04 THE ORB" section label above it or the
     orb-journey readout line below it - clipped by .orb-col's unconditional
     `overflow: hidden`). .gear-cluster is width:100% of its column with aspect-ratio:1/1, so
     it needs as much height as the column is wide; a hardcoded height smaller than that will
     always clip it. Auto height + visible overflow let the column grow to fit its own
     content, same as every other stacked mobile panel already does. Nothing inside the zone
     overflows ITS OWN box (the leader-lines SVG and globe canvas are inset:0 to the zone
     itself), so nothing new spills past the panel's rounded corners. */
  .orb-col {
    height: auto;
    overflow: visible;
  }

  .telemetry-strip-body {
    gap: var(--mom-space-6);
  }
}

/* Down to 390px (job 3 floor): columns already stack as single-column flow above 900px,
   this only tightens gutters so nothing pushes past the viewport edge. No column is ever
   compressed sideways below its content's natural width at this breakpoint - everything
   that could overflow horizontally (world clock ribbon, telemetry meter grid, portal rail)
   already wraps via flex-wrap/grid auto-fit rather than shrinking a fixed-width track.
   V4.2.0: the old `.orb-col { height: 280px }` override that used to live here is gone -
   it was the same fixed-height-smaller-than-content bug as the 900px block above, just a
   second, narrower cap on top of it. orb-col now stays auto-height (set at 900px) the whole
   way down. */
@media (max-width: 480px) {
  main {
    padding: var(--mom-space-4) var(--mom-space-4) var(--mom-space-8);
  }
  .mom-hud {
    padding: var(--mom-space-3) var(--mom-space-4);
  }
}

/* ---- Toast ---- */
.toast {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--mom-gold);
  color: #000;
  padding: 9px 16px;
  border-radius: var(--mom-radius-sm);
  font-weight: 700;
  font-size: 12px;
  z-index: 30;
}

/* ---- V1.5.0 (FIX 6): scroll-margin under the sticky header ----------------------------
 The EVENTS orb corner calls scrollIntoView({block:'start'}) on panel 05 LIVE. Without this,
 the browser aligns the panel's top edge with the VIEWPORT top, which is underneath
 #mn-bar (position:sticky, top:0), so the panel's own number and title land behind the
 header - the same class of defect FIX 2 is about, so it is solved the same way: with the
 header's real measured height (--mn-bar-h, published by app.js) plus a little clearance,
 never a magic pixel constant. Applied to every panel, so any future scroll-to lands
 correctly too. */
.mom-panel {
  scroll-margin-top: calc(var(--mn-bar-h, 75px) + 12px);
}

/* ============================================================
   QUICK LINKS tile markup, V4.7.0 (2026-08-06): ported verbatim
   from marketplace-site/public/css/marketplace.css's own QUICK
   LINKS REVISION 11 block, the compact spacing/icon-size/hover
   rules that go with the shared tile builder (magnum-workers/
   _shared/quicklinks-render.js, generated into window.
   QuickLinksRender by scripts/build.mjs - see that script's own
   comment). Every public subsite keeps this same block in its
   own stylesheet for the same reason: momentum.css (the estate
   design system) is never edited, so the CSS that goes with a
   shared markup contract lives beside every consumer instead.
   The OLD single-line .mom-quicklink-tile/.mom-quicklink-label
   rules in momentum.css (this repo's own copy) are superseded by
   this block and left in place as dead weight rather than
   editing momentum.css. This repo's own #quick-links-panel /
   .mom-quicklinks-grid wrapper markup (the numbered "08 QUICK
   LINKS" heading, the never-wrap/scroll-instead row layout,
   V1.3.0) is UNCHANGED and still governs the two <nav> rows
   these tiles render inside - only the tiles themselves (.ql-*)
   are new.
   ============================================================ */
.ql-panel {
  position: relative;
  background: var(--mom-bg-panel);
  backdrop-filter: blur(var(--mom-blur-md));
  -webkit-backdrop-filter: blur(var(--mom-blur-md));
  border: 1px solid var(--mom-border-soft);
  border-radius: var(--mom-radius-panel);
  padding: 10px 16px 12px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}
.ql-section-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--mom-font-mono);
  font-size: var(--mom-text-xs);
  letter-spacing: 1.6px;
  color: var(--mom-gold-bright);
  text-transform: uppercase;
  margin: 0 0 8px;
}
.ql-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.ql-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  flex: 1 1 74px;
  min-width: 74px;
  max-width: 120px; /* caps growth so leftover tiles in a wrapped row never balloon to fill the row */
  padding: 6px 4px 5px;
  margin: 0;
  background: var(--mom-bg-inset);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  transition: border-color 0.16s ease, background 0.16s ease;
}
.ql-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 35%, rgba(240, 193, 115, 0.30) 50%, transparent 65%);
  transform: translateX(-120%);
  opacity: 0;
  pointer-events: none;
}
.ql-tile:hover, .ql-tile:focus-visible {
  background: var(--mom-gold-dim);
  border-color: var(--mom-border);
}
.ql-tile:hover::after, .ql-tile:focus-visible::after {
  animation: ql-shimmer 0.65s ease-in-out 1;
}
@keyframes ql-shimmer {
  0% { transform: translateX(-120%); opacity: 0; }
  35% { opacity: 1; }
  100% { transform: translateX(120%); opacity: 0; }
}
.ql-icon {
  width: 19px;
  height: 19px;
  color: rgba(240, 193, 115, 0.75);
  transition: transform 0.15s ease, color 0.15s ease, filter 0.15s ease;
}
.ql-tile:hover .ql-icon, .ql-tile:focus-visible .ql-icon {
  color: var(--mom-gold-bright);
  transform: translateY(-2px) scale(1.05);
  filter: drop-shadow(0 0 4px rgba(250, 189, 89, 0.45));
}
.ql-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.15;
  font-family: var(--mom-font-mono);
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: 0.35px;
  text-transform: uppercase;
  color: var(--mom-text-body);
  text-align: center;
  white-space: nowrap;
}
.ql-tile:hover .ql-label, .ql-tile:focus-visible .ql-label {
  color: var(--mom-gold);
}
.ql-label .l2 { color: var(--mom-text-muted); }
.ql-tile:hover .ql-label .l2, .ql-tile:focus-visible .ql-label .l2 {
  color: var(--mom-gold-bright);
}
.ql-tile--disabled {
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}
.ql-tile--locked {
  opacity: 0.75;
}
.ql-lock {
  color: rgba(240, 193, 115, 0.65);
}
.ql-tile--current {
  cursor: default;
  background: var(--mom-gold-dim);
  border-color: var(--mom-border);
}
.ql-tile--current .ql-label { color: var(--mom-gold); }

@media (max-width: 900px) {
  .ql-tile { min-width: 64px; }
}

/* This repo's own addition, not part of the ported block above: the MVP member row's
   "bifurcated" background (a solid dark well, tiles sitting visibly lighter/warmer on top
   of it - REVISION 11, direct from Anric: "the color needs to be bifurcated so that the
   background is darker than the actual buttons") used to target .mom-quicklinks-grid--member
   .mom-quicklink-tile in momentum.css. That rule still exists there (dead weight, momentum.css
   is never edited) but no longer matches now that member tiles carry .ql-tile instead of
   .mom-quicklink-tile - this is the same override, same literal values, re-targeted at the
   new class so the well/tile contrast survives the tile-markup switch. The wrapping
   .mom-quicklinks-tier--member well itself (background, radius, padding) and the "MVP" chip
   are untouched, still governed by momentum.css. */
.mom-quicklinks-grid--member .ql-tile {
  background:
    linear-gradient(rgba(240, 193, 115, 0.18), rgba(240, 193, 115, 0.18)),
    rgba(255, 255, 255, 0.05);
  border-color: var(--mom-border-strong);
}

/* ── 12 FIND BY TOPIC, V2.0.0 additions ──────────────────────────────────────────────────
   momentum.css section 14 owns every .tb-* class the V1.5.0 video browser already had (never
   edited - see that file's own header rule); these are the new pieces this upgrade needed,
   added here instead, built from the exact same custom-property vocabulary (colors, spacing,
   radii, fonts) that section already uses, nothing invented. TB_TYPE_ORDER in app.js and this
   file's own type-color list stay in the same order on purpose, so a reader can match one to
   the other at a glance. */

/* Square TYPE checkboxes, direct from Anric: "It should allow you to tick a box for tools and
   resources or video instruction." Native checkbox, appearance suppressed and repainted with
   the same 3px --mom-radius-xs every other squared control on this panel already uses (.tb-tag,
   .tb-row-tag) - never a pill, per estate law. */
.tb-type-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--mom-space-5);
  padding-bottom: var(--mom-space-4);
}
.tb-type-filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-family: var(--mom-font-mono);
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--mom-text-soft);
}
.tb-type-filter input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  margin: 0;
  flex-shrink: 0;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(240, 193, 115, 0.4);
  border-radius: var(--mom-radius-xs); /* never pill */
  cursor: pointer;
  position: relative;
}
.tb-type-filter input[type="checkbox"]:checked {
  background: var(--mom-gold);
  border-color: var(--mom-gold);
}
.tb-type-filter input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid #0a0a0f;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.tb-type-filter input[type="checkbox"]:focus-visible {
  outline: 1px solid var(--mom-gold);
  outline-offset: 2px;
}
.tb-type-filter-count {
  color: var(--mom-text-muted);
  font-size: 10px;
}

/* Result-row TYPE badge and TIME badge, same squared-pill shape as the existing
   .tb-row-status (momentum.css), placed in a two-group head so the type+program pairing on
   the left and the time+status pairing on the right can each wrap independently at narrow
   widths without the space-between layout .tb-row-head already had colliding them. */
.tb-row-head-left,
.tb-row-head-right {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.tb-row-type {
  font-family: var(--mom-font-mono);
  font-size: 9.5px;
  padding: 2px 7px;
  border-radius: var(--mom-radius-xs); /* never pill */
  letter-spacing: 0.7px;
  text-transform: uppercase;
  flex-shrink: 0;
}
/* Six real types, six existing colors from momentum.css's own vocabulary (:root's
   --mom-gold/--mom-blue/--mom-green/--mom-purple/--mom-orange/--mom-text-muted) - no new color
   value anywhere in this block. RESOURCE gets the plain muted-grey treatment on purpose: it is
   the honest "genuinely unclear" fallback type, and looking the least decorated is correct for
   that. */
.tb-row-type--tool {
  background: rgba(240, 193, 115, 0.12);
  border: 1px solid rgba(240, 193, 115, 0.35);
  color: var(--mom-gold);
}
.tb-row-type--video {
  background: rgba(96, 165, 250, 0.12);
  border: 1px solid rgba(96, 165, 250, 0.35);
  color: var(--mom-blue);
}
.tb-row-type--training {
  background: rgba(74, 222, 128, 0.12);
  border: 1px solid rgba(74, 222, 128, 0.35);
  color: var(--mom-green);
}
.tb-row-type--coaching {
  background: rgba(192, 132, 252, 0.12);
  border: 1px solid rgba(192, 132, 252, 0.35);
  color: var(--mom-purple);
}
.tb-row-type--event {
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.35);
  color: var(--mom-orange);
}
.tb-row-type--resource {
  background: rgba(136, 136, 136, 0.12);
  border: 1px solid rgba(136, 136, 136, 0.3);
  color: var(--mom-text-muted);
}
/* Only ever painted from a section-index.json row that carries a REAL confirmed timestamp
   string (see tbSectionResults()'s own truthfulness comment in app.js) - plain muted text, no
   pill, so it never reads as a clickable control of its own. */
.tb-row-time {
  font-family: var(--mom-font-mono);
  font-size: 10.5px;
  color: var(--mom-text-muted);
  letter-spacing: 0.4px;
}
/* A real catalog item with no url on file (e.g. an apply-by-email event) - never rendered as a
   clickable link to nowhere. Same dim, non-interactive treatment as momentum.css's own
   .tb-row--dead, kept as a separate class so it never paints the false "down" status pill a
   dead link gets - the item itself is real and live, it just has no destination yet. */
.tb-row--nolink {
  cursor: default;
  color: var(--mom-text-dim);
  opacity: 0.7;
}
.tb-row--nolink:hover,
.tb-row--nolink:focus-visible {
  background: rgba(0, 0, 0, 0.4);
  border-color: rgba(240, 193, 115, 0.22);
  transform: none;
  box-shadow: none;
}

/* V2.1.0 (Change 2, SHOW MORE): #tb-results is a CSS grid (momentum.css), so its show-more
   control needs to span every column like .tb-empty already does there, then center itself
   rather than stretching edge to edge like a result card would. The button itself reuses
   .tb-tag/.tb-tag-more as-is (momentum.css) - same squared --mom-radius-xs, same quiet
   uppercase tone, nothing new invented for the look of it, only this layout rule is new. */
.tb-show-more {
  grid-column: 1 / -1;
  justify-self: center;
  margin-top: 2px;
}

/* JOB 2 (V2.2.0), VIDEO LIBRARY entry point 2 - the CTA row #tb-video-cta renders inside when
   tbUpdateVideoCTA() (app.js) decides this search is about video. Sits between #tb-type-filters
   and #tb-cloud, plain block flow (not the results grid), hidden via the [hidden] attribute
   when empty so it never reserves layout space. Same gold-tinted, brighter treatment as the
   VIDEO LIBRARY panel itself below (rgba(240,193,115,...), the same rgb triple every gold tint
   on this page already uses) so a member reads it as "this leads to that other, brighter box." */
.tb-video-cta {
  margin-bottom: var(--mom-space-4);
}
.tb-video-cta-btn {
  display: block;
  width: 100%;
  text-align: left;
  background: rgba(240, 193, 115, 0.12);
  border: 1px solid rgba(240, 193, 115, 0.45);
  border-radius: var(--mom-radius-sm);
  color: var(--mom-gold-hot);
  padding: 10px 14px;
  font-family: var(--mom-font-mono);
  font-size: 12px;
  letter-spacing: 0.3px;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.tb-video-cta-btn:hover,
.tb-video-cta-btn:focus-visible {
  background: rgba(240, 193, 115, 0.2);
  border-color: var(--mom-gold);
}

/* ── PROGRAMS drawer -> VIDEO LIBRARY CTA (entry point 1) ────────────────────────────────
   .drawer-vl-cta renders once, at the top of #drawer-body, only when the open facet is
   PROGRAMS (openDrawer(), app.js). Same brighter gold-tinted treatment as the video CTA above
   and the library panel below - reads as "this is a doorway to that other box," not a plain
   catalog row like the .drawer-item rows beneath it. */
.drawer-vl-cta {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  text-align: left;
  background: rgba(240, 193, 115, 0.14);
  border: 1.5px solid var(--mom-gold);
  border-radius: var(--mom-radius-md);
  padding: 12px 14px;
  margin-bottom: var(--mom-space-5);
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}
.drawer-vl-cta:hover,
.drawer-vl-cta:focus-visible {
  background: rgba(240, 193, 115, 0.22);
  transform: translateY(-1px);
}
.drawer-vl-cta-title {
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: 13px;
  letter-spacing: 0.6px;
  color: var(--mom-gold-hot);
}
.drawer-vl-cta-sub {
  font-size: 11.5px;
  color: var(--mom-text-soft);
  line-height: 1.4;
}

/* ── 13 VIDEO LIBRARY (V1.0.0) ────────────────────────────────────────────────────────────
   Anric asked for THIS box, specifically, to be brighter and lighter than the rest of the
   dashboard so it reads as clickable - a deliberate, named exception to "inherit the
   dashboard's surfaces exactly." Built from the same custom-property vocabulary as every other
   panel (colors, radii, spacing, fonts - nothing invented), just pushed toward the lighter,
   higher-opacity end of it: rgba(240, 193, 115, ...) is --mom-gold's own rgb triple, the exact
   value .mom-quicklinks-grid--member .ql-tile and a dozen other rules on this page already tint
   with; this block just uses higher opacities of that SAME triple than 12 FIND BY TOPIC does,
   plus a full 1.5-2px solid gold edge instead of a faint 0.12-0.22 alpha border, so the box
   itself reads as a raised, separate object against the near-black page rather than another
   dim panel. Corners are square throughout, 7-9px (var(--mom-radius-md)/--mom-radius-lg) -
   never a pill, same estate rule as everywhere else. Russo One (var(--mom-font-head), the same
   family stack the rest of this page uses for panel labels and titles, plus the page's own
   self-hosted 'Russo One' face where it is literally available) for every heading below; body
   copy intentionally carries no font-family override of its own, so it inherits this page's
   existing default (Verdana, --mom-font-body-member) exactly like every other panel's body
   text - real Inter is not loaded anywhere on this page (only browse.css/course.css self-host
   it, both out of scope here), and adding a second web font just for this one box is exactly
   the kind of "foreign-looking" surface Anric has already rejected once. */
.video-library-panel {
  padding-bottom: var(--mom-space-6);
}
.vl-wrap {
  margin: 0;
}
.vl-summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--mom-space-4);
  background: rgba(240, 193, 115, 0.1);
  border: 1.5px solid rgba(240, 193, 115, 0.55);
  border-radius: var(--mom-radius-md);
  padding: 10px 16px;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.vl-summary:hover,
.vl-summary:focus-visible {
  background: rgba(240, 193, 115, 0.16);
  border-color: var(--mom-gold);
}
.vl-summary::-webkit-details-marker {
  display: none;
}
.vl-summary::marker {
  content: "";
}
.vl-summary::before {
  content: "+";
  color: var(--mom-gold);
  font-family: var(--mom-font-mono);
  font-size: 20px;
  line-height: 1;
  width: 18px;
  flex-shrink: 0;
  display: inline-block;
  text-align: center;
}
.vl-wrap[open] > .vl-summary::before {
  content: "-";
}
.vl-summary .vl-title {
  margin: 0;
  padding: 0;
  border: 0;
  flex: 0 1 auto;
}
.vl-meta {
  font-family: var(--mom-font-mono);
  font-size: var(--mom-text-sm);
  color: var(--mom-gold-hot);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  margin-left: auto;
}
.vl-expand-hint {
  color: var(--mom-text-soft);
  margin-left: 10px;
  letter-spacing: 0.8px;
  text-transform: none;
}
.vl-wrap[open] .vl-expand-hint {
  display: none;
}
.vl-body {
  background: linear-gradient(
    180deg,
    rgba(240, 193, 115, 0.16) 0%,
    rgba(240, 193, 115, 0.06) 100%
  );
  border: 1.5px solid var(--mom-gold);
  border-radius: var(--mom-radius-lg);
  padding: 18px 20px;
  margin-top: 10px;
}
.vl-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.vl-search {
  flex: 1 1 240px;
  min-width: 0;
  background: rgba(255, 255, 255, 0.08);
  border: 1.5px solid rgba(240, 193, 115, 0.5);
  border-radius: var(--mom-radius-sm);
  color: var(--mom-text);
  padding: 10px 14px;
  font-family: var(--mom-font-mono);
  font-size: 13px;
  letter-spacing: 0.5px;
  outline: none;
  transition: border-color 0.2s ease, background 0.2s ease;
}
.vl-search:focus,
.vl-search:focus-visible {
  border-color: var(--mom-gold);
  background: rgba(255, 255, 255, 0.12);
}
.vl-search::placeholder {
  color: var(--mom-text-soft);
}
.vl-active {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.vl-facet-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}
.vl-facet-label {
  font-family: var(--mom-font-mono);
  font-size: 10.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mom-gold-hot);
  margin-bottom: 8px;
}
/* .vl-cloud rides on top of momentum.css's own .tb-cloud (reused, not cloned - see the panel's
   own markup comment in index.html) - this just drops that class's border-top/bottom divider,
   which reads oddly once two clouds sit side by side in their own labeled columns instead of
   stacked in one long panel the way 12 FIND BY TOPIC's single cloud does. */
.vl-cloud {
  border-top: none;
  border-bottom: none;
  padding: 0;
  margin-bottom: 0;
}
.vl-cloud-empty {
  font-family: var(--mom-font-mono);
  font-size: 11px;
  color: var(--mom-text-muted);
  letter-spacing: 0.4px;
}
.vl-programs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 14px;
}
.vl-card {
  background: rgba(255, 255, 255, 0.045);
  border: 1.5px solid rgba(240, 193, 115, 0.5);
  border-radius: var(--mom-radius-md);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  transition: border-color 0.18s ease, background 0.18s ease;
}
.vl-card:hover,
.vl-card:focus-within {
  background: rgba(255, 255, 255, 0.07);
  border-color: var(--mom-gold);
}
.vl-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.vl-card-title {
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: 14.5px;
  letter-spacing: 0.4px;
  color: var(--mom-text);
}
/* Six real statuses, the same status vocabulary and colors .mom-row--status-* (momentum.css)
   already established elsewhere on this page - live/new/beta/in_development/migrating/dead -
   no new color introduced, just applied to a squared pill instead of a row border-stripe. */
.vl-status {
  font-family: var(--mom-font-mono);
  font-size: 9.5px;
  padding: 3px 8px;
  border-radius: var(--mom-radius-xs);
  letter-spacing: 0.7px;
  text-transform: uppercase;
  flex-shrink: 0;
  background: rgba(136, 136, 136, 0.14);
  border: 1px solid rgba(136, 136, 136, 0.4);
  color: var(--mom-text-soft);
}
.vl-status--live {
  background: rgba(74, 222, 128, 0.14);
  border-color: rgba(74, 222, 128, 0.45);
  color: var(--mom-green);
}
.vl-status--new {
  background: rgba(240, 193, 115, 0.16);
  border-color: rgba(240, 193, 115, 0.5);
  color: var(--mom-gold);
}
.vl-status--beta {
  background: rgba(251, 146, 60, 0.14);
  border-color: rgba(251, 146, 60, 0.45);
  color: var(--mom-orange);
}
.vl-status--in_development {
  background: rgba(85, 85, 85, 0.2);
  border-color: rgba(136, 136, 136, 0.4);
  color: var(--mom-text-muted);
}
.vl-card-stats {
  font-family: var(--mom-font-mono);
  font-size: 11px;
  color: var(--mom-text-soft);
  letter-spacing: 0.3px;
  margin-bottom: 6px;
}
.vl-card-note {
  font-size: 11.5px;
  color: var(--mom-orange);
  line-height: 1.4;
  margin-bottom: 10px;
  padding: 6px 10px;
  background: rgba(251, 146, 60, 0.08);
  border: 1px solid rgba(251, 146, 60, 0.3);
  border-radius: var(--mom-radius-xs);
}
.vl-mod-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.vl-card-empty {
  font-family: var(--mom-font-mono);
  font-size: 11.5px;
  color: var(--mom-text-muted);
  letter-spacing: 0.4px;
  padding: 10px 0;
}
.vl-mod-row {
  border-top: 1px solid rgba(240, 193, 115, 0.16);
  padding-top: 8px;
}
.vl-mod-row:first-child {
  border-top: none;
  padding-top: 0;
}
.vl-mod-title {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-decoration: none;
  color: inherit;
}
.vl-mod-name {
  font-family: var(--mom-font-head);
  font-weight: var(--mom-font-head-weight);
  font-size: 12.5px;
  letter-spacing: 0.2px;
  color: var(--mom-text);
}
a.vl-mod-title:hover .vl-mod-name,
a.vl-mod-title:focus-visible .vl-mod-name {
  color: var(--mom-gold-hot);
}
.vl-mod-title--dead {
  cursor: default;
  opacity: 0.65;
}
.vl-mod-meta {
  font-family: var(--mom-font-mono);
  font-size: 10px;
  color: var(--mom-text-muted);
  letter-spacing: 0.3px;
}
/* The single most valuable, least exposed thing in the vault (Anric's own framing): a real
   deep link straight to the exact moment a section starts, never invented - see vlRealSeek()/
   vlTimeLabel() in app.js. Squared, brighter-gold chips so they read as the panel's own
   headline feature, not an afterthought under the module title. */
.vl-moments {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}
.vl-moment {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(240, 193, 115, 0.16);
  border: 1px solid rgba(240, 193, 115, 0.5);
  color: var(--mom-text-soft);
  padding: 4px 9px;
  border-radius: var(--mom-radius-xs);
  text-decoration: none;
  font-family: var(--mom-font-mono);
  font-size: 10.5px;
  letter-spacing: 0.3px;
  transition: all 0.15s ease;
}
.vl-moment:hover,
.vl-moment:focus-visible {
  background: var(--mom-gold);
  border-color: var(--mom-gold);
  color: #0a0a0f;
}
.vl-moment-time {
  font-weight: 700;
  color: var(--mom-gold-hot);
}
.vl-moment:hover .vl-moment-time,
.vl-moment:focus-visible .vl-moment-time {
  color: #0a0a0f;
}
.vl-show-more {
  align-self: center;
  margin-top: 4px;
}
.vl-footnote {
  font-family: var(--mom-font-mono);
  font-size: 10.5px;
  color: var(--mom-text-muted);
  letter-spacing: 0.3px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid rgba(240, 193, 115, 0.16);
}
@media (max-width: 560px) {
  .vl-body {
    padding: 14px;
  }
  .vl-meta {
    margin-left: 0;
    flex-basis: 100%;
  }
  .vl-facet-row {
    grid-template-columns: 1fr;
  }
}
@media (prefers-reduced-motion: reduce) {
  .vl-card,
  .vl-summary,
  .vl-search,
  .vl-moment,
  .drawer-vl-cta,
  .tb-video-cta-btn {
    transition: none;
  }
  .drawer-vl-cta:hover,
  .drawer-vl-cta:focus-visible {
    transform: none;
  }
}
