/* DragoXStream Player — two themes, one system.
   Light is the base on bare :root; dark is written twice, once inside
   prefers-color-scheme (guarded so an explicit light override wins) and once
   under [data-theme="dark"] (so the toggle wins in both directions). Every
   colour has a value on bare :root, so nothing renders as "nothing" before JS.
   Zero dependencies, no webfont, no third-party anything.
   Every gated pair in this file was computed, not eyeballed. */

/* ========================================================================== */
/* 1. THEME-INVARIANT TOKENS                                                  */
/* ========================================================================== */

:root {
  /* ---- accent gradient: FILL. Identical in both themes. ---- */
  --grad-a:     #2563EB;
  --grad-b:     #7C3AED;
  --on-accent:  #FFFFFF;          /* 5.17 / 5.70, worst interior 5.16 */

  /* ---- flavour lines, COMPONENT weight: one hex per flavour, >=3:1 on BOTH
     grounds. These are spent where the line carries meaning and SC 1.4.11
     applies — the trust pills, the selected result row, the #status error block,
     the quality chip. They are theme-invariant because a boundary that must
     clear 3:1 on white AND on near-black has to sit in the middle. ----
     The GROUPING weight is a different job and a different token: see
     --line-soft-* in each theme block. A section shell is neither a UI component
     nor a meaningful graphic; painting a 4.47:1 boundary around four large
     blocks on a white page outlines them instead of grouping them. */
  --line-indigo:  #6366F1;        /* 4.37 dark / 4.47 light */
  --line-violet:  #8B5CF6;        /* 4.61 / 4.23 */
  --line-emerald: #059669;        /* 5.18 / 3.77 */
  --line-danger:  #DC2626;        /* 4.04 / 4.83 */

  /* ---- media surface ----
     The stage and its chrome do NOT follow the page theme. A light-mode
     scrubber cannot satisfy knob-vs-rail, played-vs-rail and buffered-vs-rail
     at 3:1 simultaneously with a mid-luminance accent — the solution space is
     empty. A player is a media surface; it reads as a deliberate dark object on
     a white page, the way every native player does. */
  --stage:       #000000;
  --ctl-bg:      #0D1422;
  --ctl-bg-2:    #1B2435;
  --ctl-ink:     #EAEFF7;         /* 15.95 on the bar */
  --ctl-ink-2:   #B6C0D2;         /* 10.05 */
  --ctl-line:    #7C879B;         /* 5.08 */
  --rail:        #030711;
  --buffered:    #5C6678;         /* 3.48 vs rail */
  --knob:        #F2F5FA;         /* 18.44 vs rail, 4.73 worst vs played */
  --focus-stage: #EAF0FF;
  --halo-stage:  #0D1422;

  /* ---- the CTA band is the fill gradient in both themes, so its ink and its
     focus ring are invariant too. --grad-ink-a flips with the theme and its
     dark value is 2.07:1 on white; this one does not. ---- */
  --cta-ink:       #1D4ED8;       /* 6.70 on #FFFFFF */
  --cta-focus:     #070C1A;       /* 19.51 vs its white halo */
  --cta-halo:      #FFFFFF;       /* 5.17 / 5.70 vs the gradient */

  /* ---- radii ---- */
  --r-1: 6px; --r-2: 10px; --r-3: 14px; --r-4: 18px; --r-5: 24px; --r-full: 999px;

  /* ---- spacing (4px base) ---- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px; --sp-5: 24px;
  --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;

  /* ---- type ---- */
  --fs-1: .75rem;     /* 12 — eyebrow, kbd, micro-meta */
  --fs-2: .8125rem;   /* 13 — chips, domains          */
  --fs-3: .875rem;    /* 14 — secondary body, hint    */
  --fs-4: 1rem;       /* 16 — body                    */
  --fs-5: 1.125rem;   /* 18 — lede, card title        */
  --fs-6: 1.375rem;   /* 22 — h3, FAQ question        */
  --fs-7: 1.75rem;    /* 28 — h2 section head         */
  --fs-8: clamp(2rem, 7.5vw, 2.75rem);   /* 32 -> 44 — h1 */
  --lh-tight: 1.15; --lh-snug: 1.3; --lh-ui: 1.4; --lh-body: 1.6;
  --ls-display: -.02em; --ls-eyebrow: .12em;

  /* ---- layout ---- */
  --w-tool:  46rem;   /* hero, tool, player, results — never wider */
  --w-page:  64rem;   /* explanatory sections at >=1280            */
  --w-frame: var(--w-tool);
  --gutter:  clamp(16px, 4vw, 24px);
  --header-h: 56px;
  --tap: 44px;

  /* ---- motion ---- */
  --dur-1: 120ms; --dur-2: 180ms;
  --ease: cubic-bezier(.2, 0, 0, 1);
  --spin: 900ms;

  --shadow-knob: 0 1px 2px rgba(0, 0, 0, .65);
}

/* ========================================================================== */
/* 2. LIGHT — the base. Every colour has a value here.                        */
/* ========================================================================== */

:root {
  color-scheme: light dark;

  /* Elevation runs the same direction the shadows claim it does. The hero is
     page -> tray -> field: #FFFFFF ground, a tray one step DOWN (1.10:1, the
     same step dark uses from ground to shell), and the writable field back up at
     pure white — 1.10:1 above its tray, so the field is the brightest thing in
     the composition and .resolve-form's shadow describes a tray under it. The
     previous ramp was the dark one transposed: shell and field both ~1.05 of
     white, the field's fill contributing nothing and the whole hero carried by
     one border. */
  --surface-0:      #FFFFFF;
  --surface-1:      #F1F4FA;      /* 1.10 below the page */
  --surface-2:      #FFFFFF;
  --surface-3:      #E9EDF5;
  --surface-sunken: #FFFFFF;      /* the field: 1.10 ABOVE its tray */

  --hairline:       #E4E8F0;
  --border:         #C7D0E0;
  --border-control: #6A7489;      /* 4.70 vs ground — gated at 3:1 */

  --text-1:         #0D1426;      /* 18.34 on ground */
  --text-2:         #414C61;      /* 8.64 */
  --text-3:         #5A6478;      /* 5.95 */

  --grad-ink-a:     #1D4ED8;      /* gradient TEXT stop 1, and the fallback paint */
  --grad-ink-b:     #6D28D9;      /* gradient TEXT stop 2 */

  /* Deep enough to read as a fill on white (1.11-1.17 vs the page, up from
     1.05-1.12 where the emerald shell had no measurable interior at all).
     --ink-emerald drops a step with it so the pill text stays above 4.5 on the
     deeper green: 5.18 on the tint, 5.77 on white (was 4.78 / 5.02). */
  --tint-indigo:    #E8EDFD;  --ink-indigo:  #3730A3;   /* ink 8.50 on tint */
  --tint-violet:    #F1EBFE;  --ink-violet:  #6D28D9;   /* 6.11 */
  --tint-emerald:   #E2F8EA;  --ink-emerald: #15753A;   /* 5.18 */

  /* Grouping weight for .section only — roughly the reference's own section
     border (#C8D2F6 sampled from light_05 y=600, 1.50:1 vs white). A shell is a
     grouping, so it gets a boundary you can see, not one that outlines it. */
  --line-soft-indigo:  #C7D2FE;   /* 1.49 vs page, 1.28 vs its own fill */
  --line-soft-violet:  #DDD0FE;   /* 1.45 / 1.24 */
  --line-soft-emerald: #B3E7C8;   /* 1.38 / 1.24 */

  --num-blue:       #1D4ED8;  --num-emerald: #15803D;
  --num-violet:     #6D28D9;
  --num-ink:        #FFFFFF;

  --danger:         #B42318;  --danger-tint: #FEF3F2;
  --ok:             #066E3F;

  --focus:          #070C1A;  --focus-halo:  #FFFFFF;

  --shadow-1: 0 1px 2px rgba(13, 20, 38, .06), 0 1px 3px rgba(13, 20, 38, .10);
  --shadow-2: 0 4px 12px rgba(13, 20, 38, .09);
  --shadow-3: 0 16px 40px -12px rgba(13, 20, 38, .18);
  --bloom:    0 18px 48px -20px rgba(99, 102, 241, .55);
}

/* ========================================================================== */
/* 3. DARK — written twice, identically. The :not() guard is load-bearing.    */
/* ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --surface-0:      #070C1A;
    --surface-1:      #101828;
    --surface-2:      #1B2435;
    --surface-3:      #27314A;
    --surface-sunken: #030711;

    --hairline:       #1E2739;
    --border:         #303B50;
    --border-control: #7C879B;

    --text-1:         #F2F5FA;
    --text-2:         #B6C0D2;
    --text-3:         #95A1B5;

    --grad-ink-a:     #7DA9FF;
    --grad-ink-b:     #B99BFF;

    --tint-indigo:    #0B1230;  --ink-indigo:  #9BB0FF;
    --tint-violet:    #120C2E;  --ink-violet:  #C4B5FD;
    --tint-emerald:   #06201C;  --ink-emerald: #4ADE80;

    /* One step lighter than each tint, the reference's own section-border
       strength on near-black (#264097, dark_09 y=500, 2.16:1 on its ground). */
    --line-soft-indigo:  #26408F;   /* 2.06 vs ground, 1.93 vs its fill */
    --line-soft-violet:  #46339B;   /* 2.05 / 1.97 */
    --line-soft-emerald: #124A41;   /* 1.93 / 1.69 */

    --num-blue:       #60A5FA;  --num-emerald: #4ADE80;
    --num-violet:     #C4B5FD;
    --num-ink:        #070C1A;

    --danger:         #FF8D7C;  --danger-tint: #2B1310;
    --ok:             #4ADE80;

    --focus:          #EAF0FF;  --focus-halo:  #070C1A;

    /* A shadow cast on #070C1A composites to ~#050810 — 1.05:1, i.e. nothing.
       Elevation in dark comes from the surface step plus --border. */
    --shadow-1: none;
    --shadow-2: none;
    --shadow-3: none;
    --bloom:    0 18px 48px -20px rgba(124, 58, 237, .45);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --surface-0:      #070C1A;
  --surface-1:      #101828;
  --surface-2:      #1B2435;
  --surface-3:      #27314A;
  --surface-sunken: #030711;

  --hairline:       #1E2739;
  --border:         #303B50;
  --border-control: #7C879B;

  --text-1:         #F2F5FA;
  --text-2:         #B6C0D2;
  --text-3:         #95A1B5;

  --grad-ink-a:     #7DA9FF;
  --grad-ink-b:     #B99BFF;

  --tint-indigo:    #0B1230;  --ink-indigo:  #9BB0FF;
  --tint-violet:    #120C2E;  --ink-violet:  #C4B5FD;
  --tint-emerald:   #06201C;  --ink-emerald: #4ADE80;

  --line-soft-indigo:  #26408F;
  --line-soft-violet:  #46339B;
  --line-soft-emerald: #124A41;

  --num-blue:       #60A5FA;  --num-emerald: #4ADE80;
  --num-violet:     #C4B5FD;
  --num-ink:        #070C1A;

  --danger:         #FF8D7C;  --danger-tint: #2B1310;
  --ok:             #4ADE80;

  --focus:          #EAF0FF;  --focus-halo:  #070C1A;

  --shadow-1: none;
  --shadow-2: none;
  --shadow-3: none;
  --bloom:    0 18px 48px -20px rgba(124, 58, 237, .45);
}

:root[data-theme="light"] { color-scheme: light; }

/* ========================================================================== */
/* 4. BASE                                                                    */
/* ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* several blocks below set an explicit display, which would otherwise beat [hidden] */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  /* fragment targets must not park under the sticky header */
  scroll-padding-top: calc(var(--header-h) + 16px);
}

/* No transition on the page ground. A colour transition here turns the
   one-frame flash an override user sees on load into a visible 180ms wipe. */
body {
  margin: 0;
  background: var(--surface-0);
  color: var(--text-1);
  font: 400 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

h1, h2, h3, p, ul, ol { margin: 0; }
ul, ol { list-style: none; padding: 0; }
img, svg, video { max-width: 100%; }
code { font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace; font-size: .9em; }
strong { font-weight: 700; }

/* ---------- gradient text ----------
   Three lines, and all three matter. `color` is a real paint, so a UA without
   background-clip:text renders solid --grad-ink-a (6.70 light / 8.35 dark)
   rather than nothing. The transparent fill is set ONLY inside @supports.
   forced-colors does NOT revert -webkit-text-fill-color, so resetting `color`
   alone leaves the text invisible in Windows High Contrast — all three
   properties are reset together. */
.grad-text {
  color: var(--grad-ink-a);
  background-image: linear-gradient(100deg, var(--grad-ink-a) 0%, var(--grad-ink-b) 100%);
  -webkit-background-clip: text;
  background-clip: text;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .grad-text { -webkit-text-fill-color: transparent; color: transparent; }
}
@media (forced-colors: active) {
  .grad-text {
    background-image: none;
    color: CanvasText;
    -webkit-text-fill-color: CanvasText;
  }
}
@media print {
  .grad-text { background-image: none; color: #1D4ED8; -webkit-text-fill-color: #1D4ED8; }
}

/* ---------- focus: one system, two contexts ----------
   The halo fills the gap the offset opens, so the ring's inner neighbour is
   always the theme's own ground. Ring vs halo 17.10 dark / 19.51 light; halo vs
   the gradient button 3.77/3.42 dark and 5.17/5.70 light; ring vs the gradient
   4.53/4.99 dark and 3.77/3.42 light. Every leg clears 3:1.
   Light deliberately uses the dark theme's ground as its ring: a #2563EB ring
   would be 1.0:1 against the button it is meant to surround. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--focus-halo);
}
:focus:not(:focus-visible) { outline: none; }

/* Inside the black stage and the dark control bar, in BOTH themes. */
.stage :focus-visible,
.controls :focus-visible {
  outline-color: var(--focus-stage);
  box-shadow: 0 0 0 2px var(--halo-stage);
}

/* SC 2.4.11 Focus Not Obscured (Minimum). .band--head is sticky and opaque, so
   it covers the top of the scrollport permanently. A browser scrolls a newly
   focused element the minimum distance to bring it inside the scrollport, which
   on backward (Shift+Tab) motion parks it flush at y=0 — entirely under the
   header for anything shorter than the header. */
a[href],
button,
input,
select,
textarea,
summary,
[tabindex]:not([tabindex="-1"]) {
  scroll-margin-top: calc(var(--header-h) + 16px);
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--sp-2);
  z-index: 30;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  background: var(--grad-a);
  color: var(--on-accent);        /* 5.17 */
  padding: 12px 16px;
  border-radius: var(--r-2);
  font-weight: 600;
  text-decoration: none;
}
.skip-link:focus { left: var(--sp-2); }

/* ========================================================================== */
/* 5. BANDS                                                                   */
/* ========================================================================== */

.band { width: 100%; }
.band__inner {
  max-width: var(--w-frame);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.band--hero .band__inner { max-width: var(--w-tool); }

.band--head {
  background: var(--surface-0);
  border-bottom: 1px solid var(--hairline);
  position: sticky;
  top: 0;
  z-index: 10;
}
/* The top pad is --sp-5, not --sp-6, and that is a budget, not a taste: at
   375px the bottom edge of #resolve-btn lands at ~382 CSS px from the document
   top, inside the 400px ceiling that keeps the whole cold hero — H1, field,
   button and the first line of #status — on one 375x667 screen. */
.band--hero { background: var(--surface-0); padding-block: var(--sp-5); }
.band--main { background: var(--surface-0); padding-block: var(--sp-5) 0; }
.band--foot {
  background: var(--surface-1);
  border-top: 1px solid var(--hairline);
  padding-block: var(--sp-7);
  margin-top: var(--sp-7);
}

/* ========================================================================== */
/* 6. HEADER + THEME TOGGLE                                                   */
/* ========================================================================== */

/* nowrap, not wrap: a wrapping header renders ~75px tall while --header-h still
   claims 56, and every focus target the browser scrolls for us then lands under
   the sticky bar. The rendered height must equal the token. */
.head-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--header-h);
  flex-wrap: nowrap;
}
/* The auto margin lives here, not on the toggle: .brand-sub is display:none
   below 600px but still matches an adjacent-sibling selector, so hanging the
   push off `.brand-sub + .theme-toggle` would strand the toggle mid-header on
   every phone. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  margin-inline-end: auto;
}
/* The 24px mark is not gradient-filled: a glyph that small loses the hue range
   and renders as one muddy colour. */
.brand-mark { color: var(--grad-ink-a); flex: none; }
.brand-text {
  font-size: var(--fs-5);
  font-weight: 700;
  letter-spacing: var(--ls-display);
  line-height: 1.2;
  white-space: nowrap;
}
.brand-sub {
  display: none;
  color: var(--text-3);           /* 7.47 dark / 5.95 light */
  font-size: var(--fs-2);
}

.theme-toggle {
  -webkit-appearance: none;
  appearance: none;
  width: var(--tap);
  height: var(--tap);
  flex: none;
  display: inline-grid;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--surface-1);
  border: 1px solid var(--border-control);   /* 5.38 dark / 4.70 light */
  color: var(--text-1);
  cursor: pointer;
  padding: 0;
  transition: background-color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              transform var(--dur-2) var(--ease);
}
.theme-toggle .icon { width: 20px; height: 20px; display: block; }
.theme-toggle:hover { background: var(--surface-3); border-color: var(--text-3); }
.theme-toggle:active { background: var(--surface-3); transform: scale(.96); }

/* The icon shows the CURRENT theme, and the swap is pure CSS off the media
   query and the attribute — so it is right before app.js runs. */
.theme-toggle .icon-moon { display: none; }
.theme-toggle .icon-sun { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
}
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: block; }

/* ========================================================================== */
/* 7. HERO                                                                    */
/* ========================================================================== */

.hero-inner { display: block; }

.display {
  font-size: var(--fs-8);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
}
/* .grad-text must wrap only the words: on a padded block the gradient stretches
   across empty box space and the visible hue range collapses. */
.display .grad-text { display: inline; }

.lede {
  margin-top: var(--sp-3);
  font-size: var(--fs-5);
  line-height: var(--lh-body);
  color: var(--text-2);           /* 10.64 dark / 8.64 light */
  max-width: 38ch;
}

/* ========================================================================== */
/* 8. PASTE FIELD + PRIMARY BUTTON                                            */
/* ========================================================================== */

/* The reference wraps field and button in one rounded shell with a coloured
   bloom underneath (dark_00.png, light_00.png). */
.resolve-form {
  margin-top: var(--sp-5);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-2);
  align-items: end;
  background: var(--surface-1);          /* the tray: one step below the page */
  border: 1px solid var(--border);
  border-radius: var(--r-4);
  padding: var(--sp-2);
  box-shadow: var(--shadow-2), var(--bloom);
}
.field { display: grid; gap: 6px; min-width: 0; }

.field-label,
.eyebrow,
.recent-title {
  font-size: var(--fs-1);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-3);
}

.input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  color: var(--text-1);
  background: var(--surface-sunken);
  border: 1px solid var(--border-control);   /* 5.56 dark / 4.70 light */
  border-radius: var(--r-3);
  font: inherit;
  font-size: 16px;                /* stops the iOS zoom-on-focus */
  transition: border-color var(--dur-1) var(--ease);
}
.input::placeholder { color: var(--text-3); opacity: 1; }  /* 7.72 / 5.95 */
.input:hover { border-color: var(--text-3); }
.input[aria-invalid="true"] { border-color: var(--line-danger); }  /* never colour alone: #status carries the sentence */

/* ========================================================================== */
/* 9. BUTTONS                                                                 */
/* ========================================================================== */

.btn {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 48px;
  padding: 0 var(--sp-5);
  border: 0;
  border-radius: var(--r-3);
  background: transparent;
  color: var(--text-1);
  font: inherit;
  font-size: var(--fs-4);
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  transition: background-color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease),
              filter var(--dur-1) var(--ease),
              box-shadow var(--dur-2) var(--ease),
              transform var(--dur-2) var(--ease);
}

/* 100deg, not 90: the hue shift stays visible across a wide button and still
   reads left-to-right on a 343px mobile field. --grad-a is also set as a flat
   background-color, the paint of last resort. */
.btn-primary {
  background-color: var(--grad-a);
  background-image: linear-gradient(100deg, var(--grad-a) 0%, var(--grad-b) 100%);
  color: var(--on-accent);
  min-width: 120px;
}
.btn-primary:hover { filter: brightness(1.08); transform: translateY(-1px); box-shadow: var(--shadow-2); }
.btn-primary:active { transform: translateY(0) scale(.985); filter: brightness(.94); }

/* Loading keeps the gradient and keeps the button enabled and focusable. */
#resolve-btn[data-loading="true"] { cursor: progress; }
#resolve-btn[data-loading="true"] .spinner { display: block; }

/* Never opacity for a disabled state: it multiplies through and makes the
   computed ratio unverifiable. An explicit fill/ink pair stays measurable. */
.btn:disabled {
  background-image: none;
  background-color: var(--surface-3);
  color: var(--text-3);           /* 4.95 dark / 5.07 light */
  border: 1px solid var(--border-control);
  cursor: not-allowed;
  filter: none;
  transform: none;
}

/* only ever inside the stage overlay, which is theme-invariant */
.btn-secondary {
  min-height: 40px;
  padding: 0 var(--sp-4);
  font-size: var(--fs-3);
  background: var(--ctl-bg-2);
  border: 1px solid var(--ctl-line);
  color: var(--ctl-ink);          /* 13.47 */
}
.btn-secondary:hover { background: var(--rail); }
.btn-secondary:active { background: var(--rail); transform: scale(.985); }

.btn-quiet {
  -webkit-appearance: none;
  appearance: none;
  min-height: 32px;
  padding: 0 var(--sp-2);
  border: 0;
  border-radius: var(--r-1);
  background: transparent;
  color: var(--text-3);
  font: inherit;
  font-size: var(--fs-2);
  font-weight: 600;
  cursor: pointer;
  transition: color var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease);
}
.btn-quiet:hover { color: var(--text-1); background: var(--surface-3); }
.btn-quiet:active { color: var(--text-1); background: var(--surface-3); }

/* icon + text buttons live only inside .controls, which is theme-invariant */
.btn-icon {
  width: var(--tap);
  height: var(--tap);
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0;
  border-radius: var(--r-2);
  color: var(--ctl-ink);          /* 15.95 on the bar */
}
.btn-icon .icon { width: 22px; height: 22px; display: block; }
.btn-icon:hover:not(:disabled) { background: var(--ctl-bg-2); }
.btn-icon:active:not(:disabled) { background: var(--ctl-bg-2); transform: scale(.94); }
.btn-icon:disabled { background: transparent; border: 0; color: var(--ctl-ink-2); }  /* 10.05, no opacity */

.btn-text {
  height: var(--tap);
  min-height: var(--tap);
  min-width: 56px;
  padding: 0 var(--sp-2);
  font-size: var(--fs-3);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--ctl-line);
  border-radius: var(--r-2);
  color: var(--ctl-ink);
}
.btn-text:hover:not(:disabled) { background: var(--ctl-bg-2); }
.btn-text:active:not(:disabled) { background: var(--ctl-bg-2); transform: scale(.96); }
.btn-text:disabled { border-color: var(--ctl-line); color: var(--ctl-ink-2); background: transparent; }

/* spinners */
.spinner {
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  display: none;
  animation: spin var(--spin) linear infinite;
  flex: none;
}
.spinner-lg {
  width: 34px; height: 34px;
  border-width: 3px;
  display: block;
  color: var(--ctl-ink);
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ========================================================================== */
/* 10. STATUS — four data-states                                              */
/* ========================================================================== */

/* The icon is a pseudo-element on purpose: app.js owns #status.textContent, so
   a child node would be destroyed on the next state change. It is drawn in CSS,
   not fetched as an image, so it follows the state colour in both themes with
   no second copy of every hex. Shape AND colour move in every state; the error
   state also changes weight and gains a block. */
.status {
  margin-top: var(--sp-3);
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-height: 44px;               /* reserved: no layout jump between states */
  font-size: var(--fs-3);
  line-height: var(--lh-ui);
  color: var(--text-3);           /* idle — 7.47 / 5.95 */
  border-radius: var(--r-2);
  transition: color var(--dur-1) var(--ease);
  scroll-margin-top: calc(var(--header-h) + 16px);
}
.status::before {
  content: "";
  flex: none;
  width: 16px; height: 16px;
  margin-top: 3px;
}
.status[data-state="idle"]::before { display: none; }

.status[data-state="loading"] { color: var(--text-2); }   /* 10.64 / 8.64 */
.status[data-state="loading"]::before {
  border: 2px solid var(--grad-ink-a);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin var(--spin) linear infinite;
}

.status[data-state="ready"] { color: var(--ok); }         /* 11.19 / 6.34 */
.status[data-state="ready"]::before {
  width: 9px; height: 15px;
  margin-top: 1px; margin-inline: 3px 4px;
  border: solid currentColor;
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
}

.status[data-state="error"] {
  color: var(--danger);           /* 7.77 / 6.05 inside the block */
  font-weight: 600;
  margin-top: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  background: var(--danger-tint);
  border: 1px solid var(--line-danger);   /* 3.61 dark / 4.44 light */
}
/* a solid warning triangle: shape, not only hue */
.status[data-state="error"]::before {
  width: 0; height: 0;
  margin-top: 4px;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-bottom: 14px solid currentColor;
}

/* ========================================================================== */
/* 11. TRUST PILLS                                                            */
/* ========================================================================== */

/* The reference's pill row (dark_01.png) without its gradient border and glow:
   a 1px flavour line plus the tint is the same read at a quarter the cost, and
   it is measurable. These are labels, not filters — no hover, no press. */
.trust {
  margin-top: var(--sp-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.trust-item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 28px;
  padding: 6px var(--sp-3);
  border-radius: var(--r-full);
  font-size: var(--fs-2);
  font-weight: 600;
  line-height: var(--lh-ui);
  background: var(--tint);
  border: 1px solid var(--line);
  color: var(--ink);
}
.trust-mark { flex: none; }
.trust-item--indigo  { --tint: var(--tint-indigo);  --line: var(--line-indigo);  --ink: var(--ink-indigo);  }
.trust-item--violet  { --tint: var(--tint-violet);  --line: var(--line-violet);  --ink: var(--ink-violet);  }
.trust-item--emerald { --tint: var(--tint-emerald); --line: var(--line-emerald); --ink: var(--ink-emerald); }

/* ========================================================================== */
/* 12. RECENT                                                                 */
/* ========================================================================== */

.recent {
  margin-top: var(--sp-5);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--hairline);
}
.recent-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}
.recent-list { display: grid; gap: var(--sp-1); margin-top: var(--sp-2); }
.recent-row { display: grid; grid-template-columns: 1fr auto; gap: var(--sp-1); align-items: center; }

.recent-item {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  min-height: var(--tap);
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 10px;
  align-items: center;
  text-align: left;
  padding: 10px 12px;
  border: 0;
  border-radius: var(--r-2);
  background: transparent;
  color: var(--text-2);
  font: inherit;
  cursor: pointer;
  min-width: 0;
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.recent-item:hover { background: var(--surface-3); color: var(--text-1); }
.recent-item:active { background: var(--surface-3); color: var(--text-1); }
.recent-mark { color: var(--text-3); flex: none; }
.recent-lines { display: grid; gap: 2px; min-width: 0; }
.recent-label {
  font-size: var(--fs-3);
  color: inherit;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.recent-sub {
  font-size: var(--fs-1);
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.recent-remove {
  -webkit-appearance: none;
  appearance: none;
  width: 32px; height: 32px;
  display: inline-grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-1);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.recent-remove:hover { background: var(--surface-3); color: var(--text-1); }
.recent-remove:active { background: var(--surface-3); color: var(--text-1); }
.recent-remove svg { width: 14px; height: 14px; display: block; }

/* ========================================================================== */
/* 13. PLAYER — theme-invariant                                               */
/* ========================================================================== */

.main-inner { display: grid; gap: var(--sp-6); }

.player {
  display: grid;
  gap: 0;
  background: var(--ctl-bg);
  border: 1px solid var(--border);   /* reads as a placed object on a white page too */
  border-radius: var(--r-4);
  overflow: hidden;
  box-shadow: var(--shadow-3);
  scroll-margin-top: calc(var(--header-h) + 16px);
}
.player:focus { outline: none; }

.media-title {
  font-size: var(--fs-5);
  font-weight: 600;
  line-height: var(--lh-snug);
  letter-spacing: -.01em;
  color: var(--ctl-ink);          /* 15.95 */
  overflow-wrap: anywhere;
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
}

.stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: min(70vh, 560px);
  background: var(--stage);
  overflow: hidden;
}
.video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-height: min(70vh, 560px);
  object-fit: contain;
  background: var(--stage);
  display: block;
}

.stage-toggle {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 0;
  z-index: 1;
}
.stage-toggle-ring {
  width: 72px; height: 72px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  /* Opaque, not a translucent scrim: over a bright video frame a 72% fill
     composites to mid-grey and the ring's own 1px edge drops to 1.8:1. */
  background: var(--ctl-bg);
  border: 1px solid var(--ctl-line);   /* 5.08 against that fill */
  color: var(--ctl-ink);               /* 15.95 against that fill */
  transition: background-color var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease),
              transform var(--dur-2) var(--ease);
}
.stage-toggle-ring .icon { width: 28px; height: 28px; display: block; margin-left: 3px; }
.stage-toggle:hover[data-playing="false"] .stage-toggle-ring {
  transform: scale(1.04);
  background-color: var(--grad-a);
  background-image: linear-gradient(100deg, var(--grad-a) 0%, var(--grad-b) 100%);
  border-color: var(--grad-b);
  color: var(--on-accent);
}
/* :hover never fires on a phone, so every interactive type needs a press state
   of its own or the tap goes unacknowledged. */
.stage-toggle:active[data-playing="false"] .stage-toggle-ring {
  background: var(--ctl-bg-2);
  border-color: var(--focus-stage);
  transform: scale(.96);
}
/* data-playing="true" hides the element outright — no opacity, so nothing
   invisible is left holding a tab stop. */
.stage-toggle[data-playing="true"] .stage-toggle-ring { display: none; }
/* The full-stage button's ring is drawn INSIDE, over whatever frame is playing,
   so an outward halo is clipped and useless. A 6px inset band of the control
   colour gives the ring a known neighbour (16.14:1) instead of a white video
   frame (1.06:1). This rule follows `.stage :focus-visible` and has the same
   specificity, so it wins on order. */
.stage-toggle:focus-visible {
  outline-offset: -4px;
  box-shadow: inset 0 0 0 6px var(--halo-stage);
}

.stage-spinner {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--sp-3);
  /* Worst case is NOT the black first-load poster: this scrim's real job is the
     `waiting`/`stalled` rebuffer, over whatever frame is on screen. Over a white
     frame .55 composited to rgb(118,119,120) and gave 4.07:1 text and a 2.43:1
     ring — both illegal. .72 leaves margin and still reads as a scrim. */
  background: rgba(3, 7, 17, .72);
  pointer-events: none;
  z-index: 2;
}
.stage-spinner-text {
  font-size: var(--fs-2);
  color: var(--ctl-ink);
  text-align: center;
}

.stage-error {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4);
  text-align: center;
  background: rgba(13, 20, 34, .94);
}
/* The danger hue here is the dark-theme value in BOTH themes, because the scrim
   is theme-invariant: #FF8D7C is 8.4:1 on this scrim, where the light theme's
   #B42318 would be 1.9:1 on it. The glyph's inner strokes are #0D1422, set on
   the SVG element itself — a presentational attribute, not a style= attribute. */
.stage-error-icon { color: #FF8D7C; flex: none; }
.stage-error-text {
  color: var(--ctl-ink);
  font-size: var(--fs-3);
  line-height: var(--lh-ui);
  max-width: 34ch;
  overflow-wrap: anywhere;
}
.stage-error-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }

/* The same box, reporting progress instead of a fault: a re-resolve started
   from "Load the link again" answers here, where the reader is looking. The
   busy state is a spinner, not a red triangle — it is not an error. */
.stage-error-spinner {
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 3px solid var(--focus-stage);
  border-top-color: transparent;
  display: none;
  animation: spin var(--spin) linear infinite;
  flex: none;
}
.stage-error[data-state="busy"] .stage-error-spinner { display: block; }
.stage-error[data-state="busy"] .stage-error-icon { display: none; }

/* ========================================================================== */
/* 14. CONTROLS — theme-invariant                                             */
/* ========================================================================== */

.controls {
  display: grid;
  gap: var(--sp-2);
  background: var(--ctl-bg);
  padding: var(--sp-3);
}

.seek-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--sp-2);
}
.time {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-2);
  color: var(--ctl-ink-2);        /* 10.05 */
  min-width: 5ch;
  text-align: center;
}

.seek-wrap {
  position: relative;
  height: var(--tap);
  display: flex;
  align-items: center;
  min-width: 0;
  --played: 0%;
}
.seek-track, .seek-buffered, .seek-played {
  position: absolute;
  left: 0;
  height: 6px;
  border-radius: var(--r-full);
  pointer-events: none;
  top: 50%;
  transform: translateY(-50%);
}
.seek-track { width: 100%; background: var(--rail); }
.seek-buffered { width: 100%; overflow: hidden; background: transparent; }
.seek-buffered span {
  position: absolute;
  top: 0;
  height: 100%;
  background: var(--buffered);    /* 3.48 vs the rail interior */
  border-radius: var(--r-full);
  left: var(--from, 0%);
  width: var(--span, 0%);
}
.seek-played {
  width: var(--played);
  background-color: var(--grad-a);
  background-image: linear-gradient(100deg, var(--grad-a) 0%, var(--grad-b) 100%);
}

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  width: 100%;
  margin: 0;
  height: var(--tap);
  cursor: pointer;
  position: relative;
  z-index: 2;
}
input[type="range"]:focus-visible { border-radius: var(--r-full); }
input[type="range"]::-webkit-slider-runnable-track { height: 6px; background: transparent; border-radius: var(--r-full); }
input[type="range"]::-moz-range-track { height: 6px; background: transparent; border-radius: var(--r-full); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px; height: 14px;
  margin-top: -4px;
  border-radius: 50%;
  background: var(--knob);
  border: 3px solid var(--rail);   /* the dark ring is what makes it legal over the played gradient */
  box-shadow: var(--shadow-knob);
  transition: width var(--dur-2) var(--ease), height var(--dur-2) var(--ease);
}
input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--knob);
  border: 3px solid var(--rail);
  box-shadow: var(--shadow-knob);
}
input[type="range"]:hover::-webkit-slider-thumb { width: 18px; height: 18px; margin-top: -6px; }
input[type="range"]:hover::-moz-range-thumb { width: 18px; height: 18px; }
input[type="range"]:disabled { cursor: not-allowed; }
input[type="range"]:disabled::-webkit-slider-thumb { background: var(--ctl-ink-2); }
input[type="range"]:disabled::-moz-range-thumb { background: var(--ctl-ink-2); }

.buttons {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.spacer { flex: 1 1 0; min-width: 0; }

.volume-group { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }

.volume-wrap {
  position: relative;
  width: 88px;
  flex: none;
  height: var(--tap);
  display: flex;
  align-items: center;
  --level: 100%;
}
.vol-track, .vol-level {
  position: absolute;
  left: 0;
  height: 4px;
  border-radius: var(--r-full);
  pointer-events: none;
  top: 50%;
  transform: translateY(-50%);
}
.vol-track { width: 100%; background: var(--rail); }
.vol-level {
  width: var(--level);
  background-color: var(--grad-a);
  background-image: linear-gradient(100deg, var(--grad-a) 0%, var(--grad-b) 100%);
}
.volume { width: 100%; }

#play-btn .icon-pause, #play-btn[data-playing="true"] .icon-play { display: none; }
#play-btn[data-playing="true"] .icon-pause { display: block; }
#mute-btn .icon-muted, #mute-btn[data-muted="true"] .icon-vol { display: none; }
#mute-btn[data-muted="true"] .icon-muted { display: block; }
#mute-btn[data-muted="true"] { color: var(--ctl-ink-2); }
#fullscreen-btn[data-active="true"] { background: var(--ctl-bg-2); }

.hint {
  font-size: var(--fs-2);
  line-height: 1.7;
  color: var(--ctl-ink-2);        /* 10.05 */
  margin-top: var(--sp-1);
}
kbd {
  font: inherit;
  font-size: var(--fs-1);
  font-weight: 700;
  color: var(--ctl-ink);
  background: var(--ctl-bg-2);
  border: 1px solid var(--ctl-line);
  border-radius: var(--r-1);
  padding: 1px 5px;
}

/* ========================================================================== */
/* 15. RESULTS                                                                */
/* ========================================================================== */

.results-section {
  display: grid;
  gap: var(--sp-3);
  /* renderResults() focuses #results-heading and scrollIntoView({block:'start'})
     on this section, which aligns it with the scrollport top — directly under
     the opaque sticky header. SC 2.4.11. */
  scroll-margin-top: calc(var(--header-h) + 16px);
}
.results-section .eyebrow:focus { outline: none; }
.results { display: grid; gap: var(--sp-2); }

.result-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-1);
  align-items: center;
}

.result-item {
  -webkit-appearance: none;
  appearance: none;
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: var(--sp-3);
  align-items: center;
  width: 100%;
  min-width: 0;
  text-align: left;
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  background: var(--surface-2);
  box-shadow: var(--shadow-1);
  color: var(--text-1);
  font: inherit;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: background-color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-2) var(--ease),
              transform var(--dur-2) var(--ease);
}
.result-item:hover { background: var(--surface-3); border-color: var(--border-control); box-shadow: var(--shadow-2); transform: translateY(-2px); }
.result-item:active { background: var(--surface-3); transform: translateY(0); }

/* Selection is carried by THREE signals — border hue, the inset edge bar and
   the "Now playing" chip — so it survives greyscale and forced-colors.
   The fill is the indigo TINT, not --surface-3: #6366F1 on #27314A is 2.89:1,
   so a selected card would have had a boundary its own interior swallowed. On
   its own flavour tint the same line is 4.11 dark / 3.82 light. */
.result-item[aria-current="true"] {
  background: var(--tint-indigo);
  border-color: var(--line-indigo);
}
.result-item[aria-current="true"]::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block: 6px;
  width: 3px;
  border-radius: var(--r-full);
  background-color: var(--grad-a);
  background-image: linear-gradient(180deg, var(--grad-a) 0%, var(--grad-b) 100%);
}

.thumb {
  position: relative;
  display: block;
  width: 72px;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: var(--r-1);
  overflow: hidden;
  background: var(--surface-3);   /* not black: a dark frame must not read as a hole */
  flex: none;
}
.result-item:hover .thumb,
.result-item[aria-current="true"] .thumb { border-color: var(--border-control); }
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb[data-state="loaded"]::after {
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 0 1px var(--border);
  pointer-events: none;
}

.thumb-glyph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  gap: 2px;
  align-content: center;
  text-align: center;
  padding: 2px;
}
.thumb-glyph svg { width: 20px; height: 20px; display: block; }
/* the pulse is a scale, not an opacity, so contrast stays computable */
.thumb[data-state="loading"] .thumb-glyph {
  color: var(--text-3);
  animation: thumb-pulse 1600ms ease-in-out infinite;
}
.thumb[data-state="failed"] .thumb-glyph { color: var(--text-3); }  /* 5.96 / 5.95 — never red */
.thumb-ext {
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-3);
}
@keyframes thumb-pulse { 0%, 100% { transform: scale(.9); } 50% { transform: scale(1.06); } }

.thumb-badge {
  position: absolute;
  left: 5px;
  bottom: 5px;
  width: 20px; height: 20px;
  border-radius: 5px;
  background-color: var(--ctl-bg);
  border: 1px solid var(--ctl-line);
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20d='M6%204.5l6%203.5-6%203.5z'%20fill='%23FFFFFF'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 13px 13px;
}
.result-item[aria-current="true"] .thumb-badge {
  background-color: var(--grad-a);
  border-color: var(--grad-b);
}

.result-body { display: grid; gap: 6px; min-width: 0; }
.result-name {
  display: -webkit-box;
  font-weight: 600;
  font-size: var(--fs-4);
  line-height: 1.35;
  letter-spacing: -.005em;
  overflow-wrap: anywhere;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.result-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px var(--sp-2);
  align-items: center;
}

/* three kinds of fact, three visual forms — never three grey pills */
.chip {
  display: inline-block;
  font-size: var(--fs-1);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: var(--r-full);
  white-space: nowrap;
}
/* Quality is the one decision-relevant badge, so it is the only coloured one. */
.chip-quality {
  color: var(--ink-indigo);       /* 8.79 dark / 8.50 light on its tint */
  background: var(--tint-indigo);
  border: 1px solid var(--line-indigo);
}
.meta-size {
  font-size: var(--fs-2);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-1);           /* the one thing a person checks before committing */
  white-space: nowrap;
}
.meta-format {
  font-size: var(--fs-2);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-3);           /* a fact, not a badge */
  white-space: nowrap;
}
.meta-kind {
  font-size: var(--fs-2);
  color: var(--text-3);
  white-space: nowrap;
}
.meta-sep { color: var(--text-3); }

.result-state {
  display: none;
  font-size: var(--fs-1);
  font-weight: 700;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: var(--r-full);
  background: var(--tint-indigo);
  /* the card it sits on is the same tint, so the chip needs its own line to
     stay a chip rather than a floating word */
  border: 1px solid var(--line-indigo);
  color: var(--ink-indigo);
  white-space: nowrap;
}
.result-item[aria-current="true"] .result-state { display: inline-block; }

.result-download {
  width: var(--tap);
  height: var(--tap);
  display: inline-grid;
  place-items: center;
  border-radius: var(--r-2);
  color: var(--text-2);
  flex: none;
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.result-download svg { width: 20px; height: 20px; display: block; }
.result-download:hover { background: var(--surface-3); color: var(--text-1); }
.result-download:active { background: var(--surface-3); color: var(--text-1); }

/* ========================================================================== */
/* 16. EXPLANATORY SECTIONS                                                   */
/* ========================================================================== */

.section {
  background: var(--tint);
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  padding: var(--sp-6) var(--sp-4);
}
/* --line-soft-*, not --line-*: the shell groups, it does not signal. The 3:1
   component line stays where it means something (.trust-item, the selected row,
   the error block, .chip-quality) — at shell scale it out-contrasts the fill it
   is meant to be softening and reads as four outlined boxes down a white page. */
.section--indigo  { --tint: var(--tint-indigo);  --line: var(--line-soft-indigo);  --ink: var(--ink-indigo);  }
.section--violet  { --tint: var(--tint-violet);  --line: var(--line-soft-violet);  --ink: var(--ink-violet);  }
.section--emerald { --tint: var(--tint-emerald); --line: var(--line-soft-emerald); --ink: var(--ink-emerald); }
/* the one neutral shell — its head earns the gradient instead of a flavour ink */
.section--plain   { --tint: var(--surface-1);    --line: var(--hairline);     --ink: var(--text-1);      }

/* The flavour ink, not the gradient. This is what stops the page reading as one
   long gradient — and it is exactly what the reference does (dark_04/07/14). */
.section-head {
  font-size: var(--fs-7);
  font-weight: 700;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-display);
  text-align: center;
  color: var(--ink);
}
.section-lede {
  margin-top: var(--sp-3);
  margin-inline: auto;
  max-width: 52ch;
  text-align: center;
  font-size: var(--fs-4);
  line-height: var(--lh-body);
  color: var(--text-2);
}
.section-foot {
  margin-top: var(--sp-4);
  font-size: var(--fs-3);
  line-height: var(--lh-body);
  color: var(--text-2);
  text-align: center;
  max-width: 60ch;
  margin-inline: auto;
}

/* ---- the shared card chassis ---- */
.card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-1);
  padding: var(--sp-5) var(--sp-4);
}
.card-body { display: grid; gap: 6px; min-width: 0; }
.card-title {
  display: block;
  font-size: var(--fs-5);
  font-weight: 700;
  line-height: var(--lh-snug);
  color: var(--text-1);
}
.card-text {
  display: block;
  font-size: var(--fs-4);
  line-height: var(--lh-body);
  color: var(--text-2);
}

/* ---- numbered steps ---- */
.steps, .features {
  display: grid;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
}
/* Non-interactive, so no hover. A card that lifts under the cursor but does
   nothing when clicked is a lie. */
.step { display: grid; grid-template-columns: 56px 1fr; gap: var(--sp-4); align-items: start; }
.step-num {
  width: 56px; height: 56px;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  font-size: var(--fs-6);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--num-ink);
  flex: none;
}
/* The circles invert between themes: dark gets a light fill and a near-black
   numeral, light gets a dark fill and a white one. Every combination is >=5.02
   for the numeral and >=5.02 for the circle against its card. The reference
   puts white on #22c55e in both themes — 2.2:1 — and that is not copied. */
.step-num--1 { background: var(--num-blue); }
.step-num--2 { background: var(--num-emerald); }
.step-num--3 { background: var(--num-violet); }

/* ---- feature cards ---- */
.feature { display: grid; grid-template-columns: 40px 1fr; gap: var(--sp-4); align-items: start; }
.feature-chip {
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border-radius: var(--r-2);
  background: var(--surface-3);
  color: var(--ink-violet);       /* 8.42 dark / 7.10 light on the card */
  flex: none;
}
.feature-chip .icon { width: 20px; height: 20px; display: block; }

/* ---- provider domains ---- */
.sources { display: grid; gap: var(--sp-5); margin-top: var(--sp-5); }
.source-name {
  font-size: var(--fs-1);
  font-weight: 700;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--sp-2);
}
.domains {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--sp-2);
}
.domain {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-2);
  padding: 10px var(--sp-3);
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: var(--fs-2);
  color: var(--ink-emerald);      /* 8.92 dark / 5.77 light on the card */
  text-align: center;
  overflow-wrap: anywhere;
}

/* ---- FAQ: open cards, not a disclosure widget ----
   Seven short answers do not justify one, and collapsing them would hide
   exactly the trust answers this section exists to deliver. */
.faq { display: grid; gap: var(--sp-3); margin-top: var(--sp-5); }
.faq-item .card-title { font-size: var(--fs-6); }
.faq-item .card-text { margin-top: var(--sp-2); }

/* ---- closing CTA: navigation, not marketing ---- */
.cta {
  background-color: var(--grad-a);
  background-image: linear-gradient(100deg, var(--grad-a) 0%, var(--grad-b) 100%);
  border-radius: var(--r-4);
  padding: var(--sp-7) var(--sp-4);
  text-align: center;
}
.cta-head {
  font-size: var(--fs-7);
  font-weight: 700;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-display);
  color: var(--on-accent);        /* 5.16 worst interior */
}
.cta-sub {
  margin-top: var(--sp-3);
  font-size: var(--fs-5);
  line-height: var(--lh-body);
  color: var(--on-accent);
}
.cta-btn {
  margin-top: var(--sp-5);
  min-height: 52px;
  background: #FFFFFF;
  color: var(--cta-ink);          /* 6.70 — invariant, because the band is */
  text-decoration: none;
}
.cta-btn:hover { background: #F5F7FB; transform: translateY(-1px); }
.cta-btn:active { background: #E9EDF5; transform: scale(.985); }
/* On a white button the ring must be near-black with a white halo: the page
   ring would be 1.0:1 against one of its two neighbours in one of the themes. */
.cta .btn:focus-visible {
  outline-color: var(--cta-focus);
  box-shadow: 0 0 0 2px var(--cta-halo);
}

/* ========================================================================== */
/* 17. FOOTER                                                                 */
/* ========================================================================== */

.foot-inner {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 10px;
  align-items: start;
  font-size: var(--fs-3);
  line-height: var(--lh-body);
  color: var(--text-2);           /* 9.68 dark / 8.05 light */
  max-width: calc(var(--w-tool) + var(--gutter) * 2);
}
.foot-mark { color: var(--line-emerald); margin-top: 3px; }
.foot-inner > p { grid-column: 2; max-width: 60ch; }
.foot-note { margin-top: var(--sp-3); color: var(--text-3); }
.foot-back { margin-top: var(--sp-3); }
.foot-back a {
  color: var(--grad-ink-a);       /* 8.35 dark / 6.70 light */
  font-weight: 600;
  border-radius: var(--r-1);
}

/* ========================================================================== */
/* 18. RESPONSIVE                                                             */
/* ========================================================================== */

@media (max-width: 25rem) {             /* 400px and below: tighten the control row */
  .buttons { gap: var(--sp-1); }
  .btn-text { min-width: var(--tap); padding: 0 6px; }
  .result-item { grid-template-columns: 64px 1fr; gap: 10px; padding: 10px; }
  .thumb { width: 64px; }
  .step { grid-template-columns: 48px 1fr; gap: var(--sp-3); }
  .step-num { width: 48px; height: 48px; font-size: var(--fs-5); }
}

@media (max-width: 22.5rem) {           /* 360px and below */
  /* Six 44px targets plus their gaps must clear 288px of content at a 320px
     viewport. The gap shrinks; the targets never do. 6x44 + 5x2 = 274. */
  .buttons { gap: 2px; }
  .domains { grid-template-columns: 1fr; }
}

/* A pointer user in a narrow window keeps the volume slider; it narrows instead
   of vanishing. 56px is still a draggable level — the knob alone is 14px. */
@media (max-width: 30rem) and (hover: hover) and (pointer: fine) {
  .volume-wrap { width: 56px; }
}

/* Below ~418px the row cannot hold one line at any legal target size, so make
   the wrap deliberate rather than letting it orphan #download-btn. */
@media (max-width: 26rem) and (hover: hover) and (pointer: fine) {
  .spacer { flex-basis: 100%; height: 0; }
}

@media (min-width: 35rem) {             /* 560px: field and button share a row */
  .resolve-form { grid-template-columns: 1fr auto; gap: var(--sp-2); }
  #resolve-btn { min-width: 148px; }
}

@media (min-width: 37.5rem) {           /* 600px */
  :root { --header-h: 64px; }
  .brand-sub { display: inline; }
  .band--hero { padding-block: var(--sp-7) var(--sp-6); }
  .band--main { padding-block: var(--sp-6) 0; }
  .band--foot { padding-block: var(--sp-7); }
  .media-title { font-size: 1.25rem; padding: var(--sp-4) var(--sp-5) var(--sp-2); }
  .controls { padding: var(--sp-4); }
  .result-item { grid-template-columns: 88px 1fr; gap: var(--sp-4); padding: var(--sp-3); }
  .thumb { width: 88px; }
  .main-inner { gap: var(--sp-7); }
  .section { padding: var(--sp-7) var(--sp-5); border-radius: var(--r-5); }
  .cta { padding: var(--sp-8) var(--sp-5); border-radius: var(--r-5); }
}

@media (min-width: 48rem) {             /* 768px */
  .volume-wrap { width: 104px; }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .features { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sources { grid-template-columns: 1fr 3fr; gap: var(--sp-6); }
}

@media (min-width: 80rem) {             /* 1280px: only the explanatory sections widen */
  :root { --w-frame: var(--w-page); }
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .features { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* The tool column stays pinned: the field must not become a 1000px trough,
     and the player is 16:9 — a wider stage just pushes the controls off-screen. */
  #player-section,
  #results-section {
    max-width: var(--w-tool);
    width: 100%;
    margin-inline: auto;
  }
  .foot-inner { margin-inline: auto; }
}

/* ---------- gated on input type, not on a width ----------
   A 430px phone has no keyboard and a 380px desktop window does.
   .hint: a keyboard legend is useless without a keyboard.
   .volume-wrap: iOS ignores HTMLMediaElement.volume outright and Android has
   hardware keys, so this is a touch test, not a width test — a width test also
   matched a 1280px window at 400% zoom, the exact viewport SC 1.4.10 is
   verified at, and deleted the only level control for the low-vision pointer
   users the criterion exists to protect. The element stays in the DOM either
   way. */
@media not all and (hover: hover) and (pointer: fine) {
  .hint { display: none; }
  .volume-wrap { display: none; }
}

/* ========================================================================== */
/* 19. REDUCED MOTION                                                         */
/* ========================================================================== */

/* 1ms, not 0: transitionend listeners still fire, so nothing hangs waiting for
   an event that never arrives. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  /* A spinner is the only signal a resolve is in flight, so it must not vanish —
     it becomes a complete static ring rather than a broken-looking gapped one. */
  .spinner, .spinner-lg, .status[data-state="loading"]::before {
    animation: none !important;
    border-top-color: currentColor;
  }
  .status[data-state="loading"]::before { border-top-color: var(--grad-ink-a); }
  .stage-error-spinner { animation: none !important; border-top-color: var(--focus-stage); }
  .thumb[data-state="loading"] .thumb-glyph { animation: none; transform: none; }
  .btn:active, .btn:hover,
  .result-item:hover, .result-item:active,
  .cta-btn:hover, .cta-btn:active,
  .theme-toggle:active { transform: none; }
  .stage-toggle:hover[data-playing="false"] .stage-toggle-ring,
  .stage-toggle:active[data-playing="false"] .stage-toggle-ring { transform: none; }
  input[type="range"]:hover::-webkit-slider-thumb { width: 14px; height: 14px; margin-top: -4px; }
  input[type="range"]:hover::-moz-range-thumb { width: 14px; height: 14px; }
}

/* ========================================================================== */
/* 20. FORCED COLORS                                                          */
/* ========================================================================== */

@media (forced-colors: active) {
  .btn, .input, .result-item, .thumb, .stage, .seek-track, .vol-track,
  .btn-icon, .btn-text, .theme-toggle, .card, .domain, .trust-item, .section, .cta {
    border: 1px solid CanvasText;
  }
  .status[data-state="error"] { border: 1px solid CanvasText; }
  .result-item[aria-current="true"] { border-width: 3px; }
  .step-num { border: 1px solid CanvasText; }
  :focus-visible { outline-color: Highlight; box-shadow: none; }
  .cta .btn:focus-visible { outline-color: Highlight; box-shadow: none; }
}

/* ========================================================================== */
/* 21. FULLSCREEN                                                             */
/* ========================================================================== */

.player:fullscreen {
  background: #000;
  border: 0;
  border-radius: 0;
  padding: 0;
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 0;
  width: 100vw;
  height: 100vh;
  max-width: none;
}
.player:fullscreen .media-title,
.player:fullscreen .hint { display: none; }
.player:fullscreen .stage {
  max-height: none;
  height: 100%;
  width: 100%;
  margin-inline: 0;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
}
.player:fullscreen .video { max-height: none; }
.player:fullscreen .controls {
  padding: var(--sp-2) clamp(8px, 2vw, 20px) max(var(--sp-2), env(safe-area-inset-bottom));
  background: rgba(13, 20, 34, .92);
}

.player:-webkit-full-screen { background: #000; border: 0; border-radius: 0; padding: 0; }
.player:-webkit-full-screen .stage { max-height: none; height: auto; margin-inline: 0; }
.player:-webkit-full-screen .video { max-height: none; }

/* ---------- document pages (about / privacy / terms / dmca) ----------
   Prose pages served from app/templates. They reuse the band + token system;
   only the running-text rhythm is new. */
.doc { max-width: 42rem; margin-inline: auto; padding-block: var(--sp-5) var(--sp-7); }
.doc h2 {
  font-size: var(--fs-6);
  font-weight: 700;
  color: var(--text-1);
  margin: var(--sp-7) 0 var(--sp-3);
}
.doc h2:first-of-type { margin-top: var(--sp-6); }
.doc p, .doc li { color: var(--text-2); font-size: var(--fs-4); line-height: 1.65; }
.doc p { margin: 0 0 var(--sp-4); }
.doc ul, .doc ol { margin: 0 0 var(--sp-4); padding-left: var(--sp-5); }
.doc li { margin-bottom: var(--sp-2); }
.doc strong { color: var(--text-1); font-weight: 600; }
.doc code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-2);
  background: var(--surface-3);
  border-radius: var(--r-1);
  padding: 2px 6px;
  overflow-wrap: anywhere;
}
.doc-lead { font-size: var(--fs-5); color: var(--text-1); margin-bottom: var(--sp-5); }
.doc-meta { font-size: var(--fs-3); color: var(--text-3); margin-top: var(--sp-6); }

/* The draft banner is deliberately loud: these pages carry [[MARKER]] gaps and
   must never be mistaken for reviewed legal text. */
.doc-draft {
  background: var(--tint-violet);
  border: 1px solid var(--line-violet);
  border-radius: var(--r-3);
  padding: var(--sp-4);
  color: var(--ink-violet);
  margin-bottom: var(--sp-6);
}
.doc-draft strong { color: var(--ink-violet); }

/* Centred link rows over a hairline, then the disclaimer and the copyright —
   the reference footer's shape. Two tiers: the page's own sections read first,
   the standing information pages sit quieter beneath them. */
/* The footer used to be "16px shield column + paragraph", so it was a grid. It is
   now a centred stack, and the grid was actively fighting it: `> p` was pinned to
   column 2 and capped at 60ch, so paragraphs centred on column 2's axis while the
   full-width navs centred on the block's — about 117px apart at desktop. A nav left
   to auto-place landed in the 16px column and wrapped one word per line. One layout
   for everything instead. */
.foot-inner {
  display: block;
  text-align: center;
  margin-inline: auto;
}
.foot-inner > p { max-width: 60ch; margin-inline: auto; }
.foot-mark { display: block; margin: 0 auto var(--sp-2); }

.foot-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-2) var(--sp-5);
  margin: 0 0 var(--sp-3);
}
.foot-nav a {
  color: var(--text-2);
  font-size: var(--fs-3);
  text-decoration: none;
  padding: var(--sp-1) 0;
}
.foot-nav a:hover { color: var(--text-1); text-decoration: underline; }

.foot-nav--minor {
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  margin-bottom: var(--sp-5);
}
.foot-nav--minor a { font-size: var(--fs-2); color: var(--text-3); }
.foot-nav--minor a:hover { color: var(--text-1); }

.foot-copy {
  font-size: var(--fs-2);
  color: var(--text-3);
  margin: var(--sp-3) 0 0;
}

/* ========================================================================== */
/* 22. ADVERTISING SYSTEM (PRE-ROLL & DOWNLOAD AD MODAL)                      */
/* ========================================================================== */

/* ---- stage pre-roll video ad overlay ---- */
.stage-ad {
  position: absolute;
  inset: 0;
  z-index: 15;
  background: rgba(13, 20, 34, .95);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--sp-4);
  color: #FFFFFF;
}
.stage-ad[hidden] { display: none !important; }

.stage-ad-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-2);
}

.stage-ad-badge {
  font-size: var(--fs-1);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  background: var(--tint-emerald);
  color: var(--ink-emerald);
  border: 1px solid var(--line-emerald);
  border-radius: var(--r-full);
  padding: 3px 10px;
}

.stage-ad-timer {
  font-size: var(--fs-2);
  font-weight: 600;
  color: #FFFFFF;
  background: rgba(0, 0, 0, .6);
  border: 1px solid rgba(255, 255, 255, .25);
  padding: 3px 12px;
  border-radius: var(--r-full);
  font-variant-numeric: tabular-nums;
}

.stage-ad-card {
  margin: auto;
  text-align: center;
  max-width: 440px;
  padding: var(--sp-5) var(--sp-4);
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .15);
  border-radius: var(--r-3);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
}

.stage-ad-card-badge {
  font-size: .6875rem;
  font-weight: 800;
  letter-spacing: .12em;
  color: var(--grad-ink-a);
  text-transform: uppercase;
}

.stage-ad-title {
  font-size: var(--fs-5);
  font-weight: 700;
  color: #FFFFFF;
  letter-spacing: var(--ls-display);
  margin: 0;
}

.stage-ad-desc {
  font-size: var(--fs-3);
  color: rgba(255, 255, 255, .82);
  line-height: var(--lh-body);
  margin: 0 0 var(--sp-2);
  max-width: 38ch;
}

.stage-ad-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  padding: 8px 24px;
  font-size: var(--fs-3);
  font-weight: 600;
  border-radius: var(--r-2);
}

.stage-ad-bottom {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.stage-ad-progress-bar {
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, .2);
  border-radius: var(--r-full);
  overflow: hidden;
}

.stage-ad-progress {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--grad-a), var(--grad-b));
  transition: width 100ms linear;
}

.stage-ad-skip-btn {
  align-self: flex-end;
  background: rgba(0, 0, 0, .75);
  border: 1px solid rgba(255, 255, 255, .3);
  color: #FFFFFF;
  padding: 6px 18px;
  border-radius: var(--r-full);
  font-size: var(--fs-2);
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.stage-ad-skip-btn:not([disabled]) {
  background: var(--grad-a);
  border-color: var(--grad-b);
}
.stage-ad-skip-btn:not([disabled]):hover {
  transform: translateY(-1px);
}
.stage-ad-skip-btn[disabled] {
  opacity: .7;
  cursor: not-allowed;
}

/* ---- download ad modal ---- */
body.modal-open {
  overflow: hidden;
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  padding: var(--sp-4);
  background: rgba(13, 20, 34, .75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.modal-backdrop[hidden] { display: none !important; }

.modal-card {
  background: var(--surface-1);
  border: 1px solid var(--border-control);
  border-radius: var(--r-4);
  box-shadow: 0 20px 48px rgba(0, 0, 0, .35);
  width: 100%;
  max-width: 480px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: modal-pop 200ms var(--ease);
}

@keyframes modal-pop {
  from { transform: scale(.95); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--hairline);
  background: var(--surface-1);
}

.modal-badge-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.badge-sponsored {
  font-size: var(--fs-1);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  background: var(--tint-violet);
  color: var(--ink-violet);
  border: 1px solid var(--line-violet);
  border-radius: var(--r-full);
  padding: 2px 8px;
  width: fit-content;
}

.modal-title {
  font-size: var(--fs-5);
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: var(--ls-display);
  margin: 0;
}

.modal-close-btn {
  color: var(--text-3);
  flex: none;
}
.modal-close-btn:hover { color: var(--text-1); }

.modal-body {
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.modal-file-info {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 10px var(--sp-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-2);
}

.modal-file-icon {
  width: 20px;
  height: 20px;
  color: var(--grad-ink-a);
  flex: none;
}

.modal-file-name {
  font-size: var(--fs-3);
  font-weight: 600;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.modal-ad-card {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-4);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  align-items: flex-start;
}

.modal-ad-media {
  flex: none;
  margin-top: 2px;
}

.modal-ad-tag {
  font-size: .625rem;
  font-weight: 800;
  letter-spacing: .08em;
  color: var(--ink-indigo);
  background: var(--tint-indigo);
  border: 1px solid var(--line-indigo);
  border-radius: 4px;
  padding: 2px 6px;
}

.modal-ad-content {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.modal-ad-title {
  font-size: var(--fs-4);
  font-weight: 700;
  color: var(--text-1);
  margin: 0;
}

.modal-ad-desc {
  font-size: var(--fs-2);
  color: var(--text-2);
  line-height: var(--lh-body);
  margin: 0;
}

.modal-ad-link {
  align-self: flex-start;
  margin-top: var(--sp-2);
  font-size: var(--fs-2);
  padding: 6px 14px;
  text-decoration: none;
}

.modal-timer-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: var(--sp-1);
}

.modal-timer-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.modal-timer-label {
  font-size: var(--fs-3);
  color: var(--text-2);
}

.modal-timer-countdown {
  font-size: var(--fs-4);
  font-weight: 700;
  color: var(--grad-ink-a);
  font-variant-numeric: tabular-nums;
}

.modal-progress-track {
  width: 100%;
  height: 6px;
  background: var(--surface-3);
  border-radius: var(--r-full);
  overflow: hidden;
}

.modal-progress-fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--grad-a), var(--grad-b));
  transition: width 100ms linear;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--hairline);
  background: var(--surface-0);
}

/* ---- accessibility overrides ---- */
@media (prefers-reduced-motion: reduce) {
  .modal-card { animation: none !important; }
  .stage-ad-progress, .modal-progress-fill { transition: none !important; }
}

@media (forced-colors: active) {
  .stage-ad, .modal-card, .modal-ad-card, .modal-file-info {
    border: 1px solid CanvasText;
  }
}

/* ---- Google AdSense layout containers ---- */
.ad-banner-section {
  width: 100%;
  margin-block: var(--sp-4) var(--sp-6);
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 90px;
}

.ad-banner-inner {
  width: 100%;
  max-width: 728px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  padding: var(--sp-2);
  min-height: 90px;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

.modal-google-ad {
  width: 100%;
  min-height: 100px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--r-2);
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  margin-bottom: var(--sp-2);
}

.stage-ad-google {
  width: 100%;
  max-width: 380px;
  min-height: 80px;
  margin-bottom: var(--sp-2);
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

.adsbygoogle {
  display: block !important;
  width: 100%;
}

