/* ═══════════════════════════════════════════════════════════════════════════
   UFCR LIVE — THEMES, the variable layer.

   live.css owns the two registers. This file adds no look of its own: it
   re-expresses the colours live.css (and the projector's show.css) hard-coded
   as literals so they become custom properties, each defaulting to the exact
   value it has today. Load this file and nothing changes. Set a variable and
   the register repaints.

   ── LOAD ORDER ────────────────────────────────────────────────────────────
   Link this LAST in <head>, after live.css / show.css / controller.css and
   after any page's own <style> block:

       <link rel="stylesheet" href="/live/assets/live.css?v=7">
       <link rel="stylesheet" href="/live/assets/show.css?v=1">       (projector)
       <link rel="stylesheet" href="/live/assets/controller.css?v=1"> (phone)
       <link rel="stylesheet" href="/live/assets/themes.css?v=1">     <-- last

   Every selector here is one element-name heavier than the rule it replaces
   (`body.sky .panel` against live.css's `.sky .panel`), so this file still
   wins if it is ever linked out of order, or if a page adds its own <style>.

   ── THE CONTRACT ──────────────────────────────────────────────────────────
   Nothing here sets a colour that is not a var(). Nothing here is applied by a
   class, a data-attribute, or any media query other than reduced-motion.
   themes.js changes a theme by writing custom properties onto ONE element and
   doing nothing else, so a theme can be applied before first paint.

   ── THE STATE COLOURS ARE MEANING, NOT DECORATION ─────────────────────────
   A theme may recolour these. A theme may not invert what they say.
     --good / --good-lift / --green   correct, gained, live, up          GREEN
     --bad  / --bad-lift  / --red     wrong, lost, danger, down          RED
     --orange-ink / --timer-low       warning, running out               AMBER
     --yellow                         the thing you have selected        (a bg)
     --gold                           the winner / the thing to look at
   themes.js `auditTheme()` enforces both the hue bands and the contrast floors.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── the sky itself (body.sky::before) ─────────────────────────────────
     Held as four stops plus two ellipse glows, with the geometry left in the
     rule, so the composite behind any given line of projector type can be
     computed exactly rather than guessed at. */
  --sky-glow-a: rgba(250, 70, 22, .55);   /* the horizon burn */
  --sky-glow-b: rgba(240, 168, 48, .18);  /* the wider warm haze */
  --sky-1: #05070f;   /* 0%   zenith */
  --sky-2: #0b1240;   /* 38%  upper */
  --sky-3: #1a1a5e;   /* 55%  the band the glow sits in */
  --sky-4: #0A0E1A;   /* 60%+ the floor */

  /* ── the grid floor (body.sky::after) ── */
  --grid-ink: rgba(250, 70, 22, .85);
  --grid-x: 120px;
  --grid-y: 60px;
  --grid-haze: rgba(10, 14, 26, .2);
  --grid-floor: var(--dark);
  --grid-opacity: .75;
  --grid-tilt: 58deg;
  --grid-persp: 520px;

  /* ── the striped sun ── */
  --sun-bg: linear-gradient(180deg, #ffd166 0%, #ff8a3d 45%, #ff3d7f 100%);
  --sun-glow: 0 0 80px rgba(255, 120, 60, .45);
  --sun-opacity: 1;

  /* ── the CRT ── */
  --scan-ink: rgba(0, 0, 0, .28);
  --scan-blend: multiply;
  --scan-opacity: 1;

  /* ── display type ──
     --blue is already the hard offset shadow in every rule that has one, in
     both live.css and show.css. Set it close to the ground to retire the
     offset without disturbing anything else. */
  --display-ink: #fff;                          /* .sky .h-display  */
  --bloom: 0 0 22px rgba(255, 90, 31, .45);     /* the halo, phone-side */
  --eyebrow-ink: var(--gold);

  /* ── sky edges, from hairline to heavy. Each maps to a literal live.css
        uses at that exact alpha; keeping them separate is what lets the
        house theme come out pixel-identical. ── */
  --sky-line-2: rgba(255, 255, 255, .2);    /* .sky .shift-row            */
  --sky-edge-1: rgba(255, 255, 255, .3);    /* inputs, toasts, lb rows    */
  --sky-edge-2: rgba(255, 255, 255, .4);    /* .progress, shift head, img */
  --sky-edge-3: rgba(255, 255, 255, .55);   /* bar track, pj-opt, podium  */
  --sky-ghost-line: rgba(255, 255, 255, .35);
  --sky-ghost-hover: rgba(255, 255, 255, .08);

  /* ── sky fills ── */
  --sky-well-1: rgba(0, 0, 0, .3);     /* .progress          */
  --sky-well-2: rgba(0, 0, 0, .35);    /* .bar .track        */
  --sky-well-3: rgba(0, 0, 0, .4);     /* .input             */
  --sky-row-bg: rgba(0, 12, 36, .55);  /* .lb-row, .pj-opt   */
  --sky-card-bg: rgba(0, 12, 36, .6);  /* .rank              */
  --sky-panel: rgba(0, 12, 36, .72);   /* .panel             */
  --sky-toast-bg: rgba(0, 12, 36, .92);
  --sky-btn-hover: #ffc35a;

  /* ── result bars ── */
  --bar-fill: linear-gradient(90deg, var(--orange), #ff8a3d);
  --bar-glow: 0 0 18px rgba(250, 70, 22, .6);
  --bar-win-fill: linear-gradient(90deg, var(--gold), #ffd77a);
  --bar-win-glow: 0 0 22px rgba(240, 168, 48, .7);
  --bar-unsure: #bdbdbd;
  /* On the sky register live.css's `.bar.unsure .track > i` (#bdbdbd) and
     `.sky .bar .track > i` (the orange fill) have IDENTICAL specificity, and
     the sky rule is written later — so today a projector paints "Not sure"
     with the same ramp as the leading answer. That is a state colour saying
     the wrong thing, but it is what the house looks like, so the default here
     reproduces it exactly and each new theme opts into grey instead. Worth
     fixing properly in live.css; see the report. */
  --bar-unsure-sky: var(--bar-fill);
  --bar-unsure-glow: var(--bar-glow);

  /* ── state, lifted onto the dark register ── */
  --good-lift: #7dffb0;   /* .sky .shift .up,   .sky .pill.on  */
  --bad-lift:  #ff9d8a;   /* .sky .shift .down, .sky .pill.bad */
  --timer-low: var(--orange-ink);   /* .timer.low .countdown   */

  /* ── state washes on paper. live.css only; controller.css never uses these,
        so recolouring them cannot desync the phone's two stylesheets. ── */
  --good-wash: #d8f3e1;
  --danger-wash: #ffd9d2;
  --danger-wash-hover: #ff9d8a;
  --select-wash: #fff6bf;

  /* ── the projector ── */
  --pj-edge: var(--show-edge);
  --pj-card: var(--show-card);
  --pj-bloom: 0 0 30px rgba(255, 90, 31, .45);      /* big-screen halo  */
  --pj-bloom-gold: 0 0 6vh rgba(240, 168, 48, .85); /* the winner's halo */
  --pj-podium: linear-gradient(180deg, rgba(0, 33, 165, .55), rgba(0, 12, 36, .8));
  --hist-fill: linear-gradient(180deg, var(--gold), var(--orange));

  /* A QR code needs a light quiet zone or a phone camera will not find it.
     A theme may tint this; auditTheme() refuses anything dark. */
  --qr-mat: #fff;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SKY — the ground.
   Each rule overrides only the properties it names; position, z-index, sizing
   and masking all stay with live.css.
   ═══════════════════════════════════════════════════════════════════════════ */
body.sky { color: var(--display-ink); background: var(--dark); }

body.sky::before {
  background:
    radial-gradient(ellipse 70% 42% at 50% 62%, var(--sky-glow-a), transparent 70%),
    radial-gradient(ellipse 90% 60% at 50% 70%, var(--sky-glow-b), transparent 70%),
    linear-gradient(180deg, var(--sky-1) 0%, var(--sky-2) 38%, var(--sky-3) 55%, var(--sky-4) 60%);
}

body.sky::after {
  background:
    repeating-linear-gradient(90deg, var(--grid-ink) 0 2px, transparent 2px var(--grid-x)),
    repeating-linear-gradient(0deg,  var(--grid-ink) 0 2px, transparent 2px var(--grid-y)),
    linear-gradient(180deg, var(--grid-haze), var(--grid-floor) 90%);
  transform: perspective(var(--grid-persp)) rotateX(var(--grid-tilt));
  opacity: var(--grid-opacity);
}

body .sun { background: var(--sun-bg); box-shadow: var(--sun-glow); opacity: var(--sun-opacity); }

body .scanlines {
  background: repeating-linear-gradient(0deg, var(--scan-ink) 0 2px, rgba(0, 0, 0, 0) 2px 4px);
  mix-blend-mode: var(--scan-blend);
  opacity: var(--scan-opacity);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SKY — type and furniture
   ═══════════════════════════════════════════════════════════════════════════ */
body.sky .eyebrow { color: var(--eyebrow-ink); }
body.sky .h-display { color: var(--display-ink); text-shadow: var(--bloom), 4px 4px 0 var(--blue); }
body.sky .lede, body.sky .muted { color: var(--sky-muted); }
body.sky .faint { color: var(--sky-faint); }
body.sky .countdown { text-shadow: 3px 3px 0 var(--blue); }

body.sky .panel { background: var(--sky-panel); border-color: var(--sky-line); }
body.sky .btn:hover { background: var(--sky-btn-hover); }
body.sky .btn-ghost { color: var(--display-ink); border-color: var(--sky-ghost-line); background: transparent; }
body.sky .btn-ghost:hover { background: var(--sky-ghost-hover); }
body.sky .input { background: var(--sky-well-3); border-color: var(--sky-edge-1); color: var(--display-ink); }
body.sky .input:focus { border-color: var(--gold); }
body.sky .toast { background: var(--sky-toast-bg); color: var(--display-ink); border-color: var(--sky-edge-1); }
body.sky .wait-dots i { background: var(--gold); }
body.sky .ev { border-top-color: var(--sky-line); }

/* ═══════════════════════════════════════════════════════════════════════════
   SKY — state.
   The pill rules also beat the copies inside live/index.html's own <style>,
   which is the reason every selector here carries `body`.
   ═══════════════════════════════════════════════════════════════════════════ */
body.sky .shift .up,
body.sky .pill.on      { color: var(--good-lift); }
body.sky .pill.on      { border-color: var(--good-lift); }
body.sky .shift .down,
body.sky .pill.bad,
body.sky .rail-mv.down { color: var(--bad-lift); }
body.sky .pill.bad     { border-color: var(--bad-lift); }
body.sky .pill.warn    { color: var(--gold); border-color: var(--gold); }
body.sky .timer.low .countdown { color: var(--timer-low); }

body.sky .progress { border-color: var(--sky-edge-2); background: var(--sky-well-1); }
body.sky .progress > i { background: var(--bar-fill); }
body.sky .bar .track { border-color: var(--sky-edge-3); background: var(--sky-well-2); }
body.sky .bar .track > i { background: var(--bar-fill); box-shadow: var(--bar-glow); }
body.sky .bar.win .track > i { background: var(--bar-win-fill); box-shadow: var(--bar-win-glow); }
body.sky .bar.unsure .track > i { background: var(--bar-unsure-sky); box-shadow: var(--bar-unsure-glow); }
body.sky .bar .opt .key { border-color: var(--gold); color: var(--gold); }
body.sky .shift-head { color: var(--gold); border-color: var(--sky-edge-2); }
body.sky .shift-row { border-color: var(--sky-line-2); }

/* ═══════════════════════════════════════════════════════════════════════════
   PROJECTOR — the .pj-* set, which lives in live.css
   ═══════════════════════════════════════════════════════════════════════════ */
body.sky .pj-kicker { color: var(--eyebrow-ink); }
body.sky .pj-sub, body.sky .pj-foot, body.sky .rank-meta, body.sky .hist-col span { color: var(--show-dim); }
body.sky .pj-body { color: var(--show-ink); }
body.sky .pj-opt { border-color: var(--sky-edge-3); background: var(--sky-row-bg); }
body.sky .pj-opt .key { border-color: var(--gold); color: var(--gold); }
body.sky .pj-img { border-color: var(--sky-edge-2); }
body.sky .big-num { color: var(--show-ink); text-shadow: 3px 3px 0 var(--blue); }
body.sky .pj-quote { color: var(--show-ink); text-shadow: 3px 3px 0 var(--blue); }
body.sky .pj-author, body.sky .pj-foot .gold { color: var(--gold); }
body.sky .rank { border-color: var(--pj-edge); background: var(--sky-card-bg); }
body.sky .rank[data-rank="1"] { border-color: var(--gold); }
body.sky .rank-no { color: var(--gold); text-shadow: 3px 3px 0 var(--blue); }
body.sky .rank-text { color: var(--show-ink); }
body.sky .hist-col i { background: var(--hist-fill); border-color: var(--pj-edge); }
body.sky .cloud span { text-shadow: 2px 2px 0 var(--blue); }
body.sky .lb-row { border-color: var(--sky-edge-1); background: var(--sky-row-bg); }
body.sky .lb-row:nth-child(1) { border-color: var(--gold); }
body.sky .lb-no { color: var(--gold); }
body .qr { background: var(--qr-mat); border-color: var(--qr-mat); }

/* ═══════════════════════════════════════════════════════════════════════════
   PROJECTOR — show.css.
   show.css already routes every hard offset through var(--blue) and every
   accent through var(--gold), so only two things need restating here: the
   display ink it writes as #fff, and the warm halo it writes as a literal.
   Offsets are repeated at their exact original sizes so the house theme comes
   out identical.
   ═══════════════════════════════════════════════════════════════════════════ */
body.sky .lob-title,
body.sky .lob-num,
body.sky .tr-title,
body.sky .vs-side,
body.sky .cd-num,
body.sky .wh-name,
body.sky .bz-open,
body.sky .bz-name,
body.sky .pod-no,
body.sky .celeb-text,
body.sky .qcard-q,
body.sky .dr-artist,
body.sky .pj-code { color: var(--show-ink); }

body.sky .lob-title  { text-shadow: var(--pj-bloom), .5vh .5vh 0 var(--blue); }
body.sky .lob-num    { text-shadow: var(--pj-bloom), .5vh .5vh 0 var(--blue); }
body.sky .pj-code    { text-shadow: var(--pj-bloom), .55vh .55vh 0 var(--blue); }
body.sky .tr-title   { text-shadow: var(--pj-bloom), .6vh .6vh 0 var(--blue); }
body.sky .vs-side    { text-shadow: var(--pj-bloom), .55vh .55vh 0 var(--blue); }
body.sky .vs-mid     { text-shadow: var(--pj-bloom), .5vh .5vh 0 var(--blue); }
body.sky .cd-num     { text-shadow: var(--pj-bloom), 1vh 1vh 0 var(--blue); }
body.sky .bz-open    { text-shadow: var(--pj-bloom), 1vh 1vh 0 var(--blue); }
body.sky .pod-no     { text-shadow: var(--pj-bloom), .6vh .6vh 0 var(--blue); }
body.sky .qcard-q    { text-shadow: var(--pj-bloom), .5vh .5vh 0 var(--blue); }
body.sky .tr-double .tr-title { text-shadow: var(--pj-bloom-gold), .6vh .6vh 0 var(--blue); }
body.sky .wh-name    { text-shadow: var(--pj-bloom-gold), .55vh .55vh 0 var(--blue); }
body.sky .bz-name    { text-shadow: var(--pj-bloom-gold), 1vh 1vh 0 var(--blue); }
body.sky .celeb-text { text-shadow: var(--pj-bloom-gold), .5vh .5vh 0 var(--blue); border-color: var(--gold); }
body.sky .pod-block  { border-color: var(--sky-edge-3); background: var(--pj-podium); }
body.sky .bz-tag     { color: var(--show-dim); border-color: var(--sky-edge-1); background: var(--sky-card-bg); }

/* ═══════════════════════════════════════════════════════════════════════════
   PAPER — the phone, once it has joined.

   Deliberately thin. The joined phone's chrome is drawn by controller.css,
   which is not ours and which hard-codes #fff cards and #000 drop-shadows in
   51 places. Re-routing live.css's copies of those literals here would leave
   live.css's cards and controller.css's cards two different colours on the
   same screen, so they stay as they are, and the paper register is themed
   through the variables both files already share: --paper --ink --ink-2 --grey
   --yellow --orange --orange-ink --gold --good --bad --bevel-color and the
   three fonts. The only literals restated are the four state washes that
   controller.css does not use, so "wrong" can be recoloured without desync.
   ═══════════════════════════════════════════════════════════════════════════ */
body.paper .btn-good   { background: var(--good-wash); }
body.paper .btn-danger { background: var(--danger-wash); }
body.paper .btn-danger:hover { background: var(--danger-wash-hover); }
body.paper .toast.good { background: var(--good-wash); }
body.paper .toast.bad  { background: var(--danger-wash); }
body.paper .conn.bad   { background: var(--danger-wash); }
body.paper .item.on,
body.paper .selected-card { background: var(--select-wash); }
body.paper .bar.unsure .track > i { background: var(--bar-unsure); }
body.paper .timer.low .countdown { color: var(--timer-low); }

/* ═══════════════════════════════════════════════════════════════════════════
   MOTION
   live.css already clamps animation-duration under reduced-motion, but an
   infinite animation clamped to 0.01ms still runs — it just runs impossibly
   fast, which is worse than not running at all. The ambient loops are stopped
   outright here, and the ticker is parked where it can be read.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  body.sky::after,
  body.sky.drift::after,
  body .sun.drift,
  body.sky .bz-open,
  body.sky .tr-double .tr-title,
  body .pill.live .dot,
  body .timer.low .countdown,
  body .wait-dots i { animation: none !important; }
  body .ticker > span { animation: none !important; padding-left: 0; }
}
