/* ─────────────────────────────────────────────────────────────
   Slick FM brand layer (Fas 0)

   Self-hosted woff2 fonts and the full Miami Vice palette, set up
   as dormant aliases alongside the original control-surface tokens
   below. Nothing in this block changes the rendered output yet —
   no selector references the brand-* variables and no element asks
   for Monoton / Audiowide / Orbitron. The fonts therefore stay
   unfetched until Fas 1 wires them up.
   ───────────────────────────────────────────────────────────── */

/* Audiowide — frequency, callsigns, labels. */
@font-face {
  font-family: "Audiowide";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/img/fonts/audiowide-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}
@font-face {
  font-family: "Audiowide";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/img/fonts/audiowide-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Monoton — display wordmark only. Heavy bevel-on-bevel display face;
   never used at body sizes. */
@font-face {
  font-family: "Monoton";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/img/fonts/monoton-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}
@font-face {
  font-family: "Monoton";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/img/fonts/monoton-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Orbitron — variable-axis weight 400→800, single woff2. Body, titles,
   and the eventual hero clock face. */
@font-face {
  font-family: "Orbitron";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/img/fonts/orbitron-variable.woff2") format("woff2-variations"),
       url("/img/fonts/orbitron-variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}

:root {
  /* Miami Vice palette — additive. Tokens below override existing
     surface tokens only when a selector chooses to reference them. */
  --brand-deep-night:  #0b0226;
  --brand-purple:      #2a0a55;
  --brand-plum:        #8c1273;
  --brand-hot-pink:    #ff2d95;
  --brand-sunset:      #ff7a3c;
  --brand-gold:        #ffd24a;
  --brand-cyan:        #00f0ff;
  --brand-cream:       #ffe2f4;
  --brand-tongue-deep: #5a0220;
  --brand-tongue-rose: #ff8db4;

  /* Chrome gradient — six-stop anodised-steel ribbon. Used for the
     wordmark in Fas 1 and the hero clock value in Fas 1 (max-effort
     spec from the design brief). */
  --brand-chrome:
    linear-gradient(180deg,
      #ffffff   0%,
      #ffe2f4  22%,
      #ff6ec7  49%,
      #ffd24a  51%,
      #9b1a72  82%,
      #3a0046 100%);

  /* Typography stacks. Brand-display is reserved for the wordmark;
     brand-frequency for the 93.6 MHz lockup; brand-sans is the body
     face that progressively replaces the system-ui stack in Fas 1–3. */
  --brand-display:   "Monoton",  "Impact", "Arial Black", sans-serif;
  --brand-frequency: "Audiowide", "Arial Black", sans-serif;
  --brand-sans:      "Orbitron", -apple-system, "SF Pro Text", system-ui, sans-serif;
}

/* Slick FM — control surface aesthetic.
   Dark, mono-tinted, a touch of broadcast warmth. No frameworks. */

:root {
  --bg: #0a0d12;
  --bg-2: #11161e;
  --line: #1d242f;
  --ink: #e8edf3;
  --ink-dim: #8a93a3;
  --accent: #ff5a3c;     /* on-air orange */
  --accent-2: #5ad7ff;   /* monitor cyan */
  --good: #6dd49a;
  --warn: #f5c451;
  --bad:  #ff5e6c;
  --radius: 14px;
  --shadow: 0 1px 0 rgba(255,255,255,0.04), 0 8px 30px rgba(0,0,0,0.45);
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: ui-sans-serif, -apple-system, "SF Pro Text", system-ui, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 24px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, #0e131a, #0a0d12);
  position: sticky; top: 0; z-index: 5;
}
header h1 {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.02em;
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
}

/* Small circular brand portrait inline with the title — keeps the
   header tight on mobile while still landing as a recognition cue. */
.avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  object-fit: cover;
  vertical-align: middle;
  margin-right: 4px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

.head-right { display: flex; gap: 10px; align-items: center; }

.pill {
  font: 500 12px/1 var(--mono);
  padding: 6px 10px;
  border-radius: 999px;
  background: #232a36;
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.pill.ok   { background: rgba(109,212,154,0.15); color: var(--good); }
.pill.warn { background: rgba(245,196,81,0.15); color: var(--warn); }
.pill.bad  { background: rgba(255,94,108,0.15); color: var(--bad); }

/* ElevenLabs v3 audio-tag label — rendered inline anywhere a manuscript
   surfaces in the GUI. Miami-Vice magenta on a low-alpha wash with a
   small neon glow, sized below the surrounding copy. The raw "[warmly]"
   bracket syntax never reaches the DOM — see formatAudioTagsHtml. */
.audio-tag {
  display: inline-block;
  font-family: var(--mono);
  font-size: clamp(10px, 0.78em, 13px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #ff3c98;
  background: rgba(255, 60, 152, 0.10);
  padding: 2px 6px;
  border-radius: 4px;
  margin: 0 3px;
  vertical-align: 0.08em;
  text-shadow: 0 0 10px rgba(255, 60, 152, 0.5);
  border: 1px solid rgba(255, 60, 152, 0.28);
}

main {
  max-width: 980px;
  margin: 0 auto;
  padding: 24px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
.card.log { grid-column: 1 / -1; }

.card {
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 18px 16px;
  box-shadow: var(--shadow);
}
.card h2 {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 0 0 14px;
  color: var(--ink-dim);
}

.track {
  padding: 8px 0;
  border-top: 1px dashed var(--line);
}
.track:first-of-type { border-top: 0; }
.track.muted .title { opacity: 0.55; }
.role {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: 4px;
}
.title { font-size: 16px; font-weight: 500; }
.track.current .title { color: var(--accent-2); font-weight: 600; }

.bar {
  position: relative;
  height: 4px;
  background: #1c2330;
  border-radius: 2px;
  margin-top: 8px;
  overflow: hidden;
}
#bar-fill {
  position: absolute; inset: 0 auto 0 0;
  width: 0%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width 0.6s linear;
}
.time {
  font: 12px var(--mono);
  color: var(--ink-dim);
  margin-top: 4px;
}

.row {
  display: flex; gap: 10px; align-items: center;
  flex-wrap: wrap;
  margin-top: 12px;
}
.hint {
  margin: 0 0 10px;
  color: var(--ink-dim);
  font-size: 13px;
}

button {
  font: 500 14px var(--sans);
  background: #1d2632;
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 14px;
  cursor: pointer;
  transition: transform 0.05s ease, background 0.15s ease;
}
button:hover { background: #243042; }
button:active { transform: translateY(1px); }
button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #18110d;
  font-weight: 600;
}
button.primary:hover { background: #ff7459; }

a { color: var(--accent-2); }

.auto {
  font-size: 13px;
  color: var(--ink-dim);
  display: inline-flex; align-items: center; gap: 8px;
  user-select: none;
}
.auto input { accent-color: var(--accent); }

.latest {
  margin-top: 14px;
  padding: 12px;
  background: #0d1219;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.line {
  font-size: 15px;
  color: var(--ink);
  font-style: italic;
  min-height: 1.4em;
}
audio {
  width: 100%;
  margin-top: 10px;
  filter: invert(0.9) hue-rotate(180deg);
}

.log ol { list-style: none; padding: 0; margin: 0; }
.log li {
  font: 13px var(--mono);
  padding: 8px 10px;
  border-top: 1px dashed var(--line);
  display: flex; gap: 12px;
  align-items: baseline;
}
.log li:first-child { border-top: 0; }
.log .ts   { color: var(--ink-dim); flex-shrink: 0; }
.log .body { color: var(--ink); }
.log .body .text { color: var(--accent-2); }

/* Failed rows: red text, subtle red wash and a left-accent bar so they
   stand out at a glance. Inset shadow used instead of border-left so the
   row's flex layout and padding stay aligned with successful rows. */
.log li.bad {
  background: rgba(255, 94, 108, 0.07);
  box-shadow: inset 3px 0 0 var(--bad);
  padding-left: 14px;
}
.log li.bad .body { color: var(--bad); }

/* ── Control: info cards + stats grid ─────────────────── */

.card.info dl.kv {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 10px 16px;
  margin: 0;
}
.card.info dl.kv dt {
  font: 500 11px/1.2 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-dim);
  align-self: center;
}
.card.info dl.kv dd {
  margin: 0;
  font-size: 14px;
  color: var(--ink);
  word-break: break-word;
}
.card.info dl.kv dd.mono {
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--accent-2);
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.stat {
  background: #0d1219;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px 12px;
  text-align: center;
}
.stat-value {
  font: 600 22px/1 var(--sans);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.stat-label {
  font: 500 10px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  margin-top: 6px;
}

@media (max-width: 720px) {
  main { grid-template-columns: 1fr; }
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ── Player page — 2026 broadcast aesthetic ───────────── */

body[data-page="player"],
body[data-page="showcase"] {
  /* Remap surface and accent tokens inside the player scope so every
     selector below that consumes them — .dot, .wm-accent, #clock-fill,
     #trow-bar-fill, .arm-btn, .live-tag, .now-line, a — repaints in
     Miami Vice colours without a single declaration needing a rewrite.
     Form-only change: every element keeps its identity, layout, and
     JS-driven animation; only the pigment shifts. */
  --bg:       var(--brand-deep-night);
  --bg-2:     var(--brand-purple);
  --accent:   var(--brand-hot-pink);
  --accent-2: var(--brand-cyan);

  background:
    radial-gradient(1400px 700px at 50% -15%, rgba(255, 45, 149, 0.22), transparent 62%),
    radial-gradient(900px  700px at 110% 90%, rgba(0,   240, 255, 0.10), transparent 60%),
    var(--bg);
  overflow-x: hidden;
}

/* ── Outrun overlay — perspective grid + scanline veil ──
   Two body-scoped pseudos. The grid (::before) lives in the lower
   70vh, mask-faded toward the horizon; the scanline veil (::after)
   covers the whole viewport at very low alpha with mix-blend-mode:
   overlay so legibility is preserved. Both pointer-events:none so
   nothing in the player UI loses click-through. Stacking order at
   body level — verified, not changed:
     1. body background
     2. body::before (z-auto)            — grid
     3. .aurora (z:0, unchanged)         — ribbons
     4. .player-shell (z:1, unchanged)   — content
     5. body::after (z:9)                — scanlines on top
   No existing z-index values touched; nothing in .aurora,
   .player-shell, or any child element changed. Pure form overlay. */
body[data-page="player"]::before,
body[data-page="showcase"]::before {
  content: "";
  position: fixed;
  left: -10vw;
  right: -10vw;
  bottom: -8vh;
  height: 70vh;
  pointer-events: none;
  background:
    repeating-linear-gradient(
      0deg,
      transparent 0,
      transparent 38px,
      rgba(0, 240, 255, 0.55) 38px,
      rgba(0, 240, 255, 0.55) 40px
    ),
    repeating-linear-gradient(
      90deg,
      transparent 0,
      transparent 38px,
      rgba(255, 45, 149, 0.55) 38px,
      rgba(255, 45, 149, 0.55) 40px
    );
  transform: perspective(420px) rotateX(60deg);
  transform-origin: bottom center;
  -webkit-mask-image: linear-gradient(
    0deg,
    rgba(0, 0, 0, 1)   0%,
    rgba(0, 0, 0, 0.9) 30%,
    rgba(0, 0, 0, 0) 100%
  );
          mask-image: linear-gradient(
    0deg,
    rgba(0, 0, 0, 1)   0%,
    rgba(0, 0, 0, 0.9) 30%,
    rgba(0, 0, 0, 0) 100%
  );
  opacity: 0.65;
}
body[data-page="player"]::after,
body[data-page="showcase"]::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9;
  background: repeating-linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.025) 0,
    rgba(255, 255, 255, 0.025) 1px,
    transparent 1px,
    transparent 3px
  );
  mix-blend-mode: overlay;
}

/* Aurora ribbons drifting behind everything — three blurred conics on
   their own composited layer so they animate without re-rasterising the
   page text. Pointer-events off so nothing interferes with clicks. */
.aurora {
  position: fixed;
  inset: -10vh -10vw;
  z-index: 0;
  pointer-events: none;
  filter: blur(90px) saturate(120%);
  opacity: 0.55;
}
.aurora span {
  position: absolute;
  width: 60vmax;
  height: 60vmax;
  border-radius: 50%;
  mix-blend-mode: screen;
  will-change: transform;
}
.aurora span:nth-child(1) {
  background: radial-gradient(circle, rgba(255, 45, 149, 0.55), transparent 70%);
  top: -20vmax; left: -10vmax;
  animation: aurora-drift-a 28s ease-in-out infinite alternate;
}
.aurora span:nth-child(2) {
  background: radial-gradient(circle, rgba(0, 240, 255, 0.40), transparent 70%);
  bottom: -25vmax; right: -10vmax;
  animation: aurora-drift-b 34s ease-in-out infinite alternate;
}
.aurora span:nth-child(3) {
  background: radial-gradient(circle, rgba(255, 122, 60, 0.30), transparent 70%);
  top: 30vmax; left: 30vmax;
  animation: aurora-drift-c 42s ease-in-out infinite alternate;
}
@keyframes aurora-drift-a {
  0%   { transform: translate3d(0,0,0) scale(1); }
  100% { transform: translate3d(8vw,6vh,0) scale(1.15); }
}
@keyframes aurora-drift-b {
  0%   { transform: translate3d(0,0,0) scale(1); }
  100% { transform: translate3d(-10vw,-4vh,0) scale(1.2); }
}
@keyframes aurora-drift-c {
  0%   { transform: translate3d(0,0,0) scale(0.95); }
  100% { transform: translate3d(-6vw,8vh,0) scale(1.1); }
}

.player-shell {
  position: relative;
  z-index: 1;
  max-width: 760px;
  margin: 0 auto;
  display: block;
  padding: 0 24px 56px;
}

.p-head {
  position: sticky;
  top: 0;
  background: linear-gradient(180deg, rgba(10,13,18,0.92), rgba(10,13,18,0.55) 80%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  padding: 18px 4px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  display: flex;
  align-items: center;
  justify-content: space-between;
  z-index: 4;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 18px;
  letter-spacing: 0.03em;
}
.brand .dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 14px var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
}
/* Monoton wordmark — Miami Vice display face. The whole wordmark
   glides at -10° to echo the angled bevel-on-bevel lettering in the
   brand SVG; .wm-freq counter-skews back upright so the frequency
   reads as a stable callsign. The two-layer look (neon pink "Slick"
   under chrome "FM") mirrors the SVG's filtered pink layer behind
   the chromed top layer. */
.wordmark {
  font-family: var(--brand-display);
  font-weight: 400;            /* Monoton ships single-weight */
  font-size: 28px;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;   /* keep "SLICK" capped even if HTML caps the S */
  display: inline-block;
  transform: skewX(-10deg);
  transform-origin: 50% 50%;
  color: var(--brand-hot-pink);
  text-shadow:
    0 0 14px rgba(255, 45, 149, 0.45),
    0 0 28px rgba(255, 45, 149, 0.20);
}
.wm-accent {
  /* "FM" — six-stop chrome gradient text-clip on top of the neon-pink
     wordmark layer. The parent's skew already carries this span; we
     just paint the chrome and clip to glyphs. */
  background: var(--brand-chrome);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  margin-left: 2px;
  /* The text-shadow inherits from .wordmark by default — re-apply with
     a tighter halo so the chrome "FM" gets its own pink underglow that
     reads as part of the wordmark, not as parent bleed. */
  text-shadow: 0 0 18px rgba(255, 45, 149, 0.55);
}
.wm-freq {
  /* Audiowide frequency tag. Counter-skewed back to upright so the
     callsign sits stable next to the angled Monoton wordmark, even
     though it's a child element inside the skewed .wordmark span. */
  font-family: var(--brand-frequency);
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
  margin-left: 12px;
  text-transform: uppercase;
  display: inline-block;
  transform: skewX(10deg);
  text-shadow: none;           /* opt out of the parent's pink halo */
}

/* Control page brand: small frequency tag aligned with the rest of the
   header title. Audiowide so the callsign reads in the same broadcast
   typographic register as the player's wordmark, but dim so it doesn't
   compete with the station name. */
header h1 .brand-freq {
  font-family: var(--brand-frequency);
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
  margin-left: 10px;
  text-transform: uppercase;
}

/* ── Control page — Miami Vice palette remap ──
   Same scoping pattern as the player: redefine the four surface and
   accent tokens inside body[data-page="control"] so every existing
   selector that consumes them — .card, .track.current .title, #bar-fill,
   button.primary, .dot, header border, the audio control filter —
   repaints in brand colours without a single declaration further down
   the file changing. Header background and the slate pill/bar literals
   that the original CSS hard-coded get scoped overrides below. */
body[data-page="control"] {
  --bg:       var(--brand-deep-night);
  --bg-2:     var(--brand-purple);
  --accent:   var(--brand-hot-pink);
  --accent-2: var(--brand-cyan);
  --line:     rgba(255, 226, 244, 0.08);
}
body[data-page="control"] header {
  border-bottom: 1px solid rgba(255, 45, 149, 0.20);
  background: linear-gradient(180deg, rgba(26, 6, 58, 0.92), var(--brand-deep-night));
}
body[data-page="control"] .pill {
  background: rgba(255, 226, 244, 0.06);
}
body[data-page="control"] .bar {
  background: rgba(255, 226, 244, 0.08);
}
body[data-page="control"] .avatar {
  border-color: rgba(255, 45, 149, 0.45);
  box-shadow: 0 0 10px rgba(255, 45, 149, 0.25);
}
body[data-page="control"] .latest {
  background: rgba(11, 2, 38, 0.55);
  border-color: rgba(255, 226, 244, 0.06);
}
body[data-page="control"] .stat {
  background: rgba(11, 2, 38, 0.55);
  border-color: rgba(255, 226, 244, 0.06);
}
body[data-page="control"] button {
  background: rgba(255, 226, 244, 0.04);
  border-color: rgba(255, 226, 244, 0.10);
}
body[data-page="control"] button:hover {
  background: rgba(255, 45, 149, 0.10);
}

/* ── Prompt editor — Miami Vice palette remap ──
   The prompt editor's inline <style> block uses literal colours
   rather than tokens, so we add scoped external overrides for each
   selector that defines visible chrome — textarea, .placeholders
   code, .pill (both states), pre.preview, .sep, .section, header
   nav. CSS specificity (body[data-page] + element/class) is two
   classes higher than the bare inline selectors, so these overrides
   always win regardless of cascade order. Same body-scoped token
   remap as /player and /control. */
body[data-page="prompt"] {
  --bg:       var(--brand-deep-night);
  --bg-2:     var(--brand-purple);
  --accent:   var(--brand-hot-pink);
  --accent-2: var(--brand-cyan);
  --line:     rgba(255, 226, 244, 0.08);
}
body[data-page="prompt"] header {
  border-bottom: 1px solid rgba(255, 45, 149, 0.20);
  background: linear-gradient(180deg, rgba(26, 6, 58, 0.92), var(--brand-deep-night));
}
body[data-page="prompt"] .pill {
  background: rgba(255, 226, 244, 0.06);
  color: var(--ink-dim);
}
body[data-page="prompt"] .pill.modified {
  /* Unsaved-state amber re-mapped to brand sunset; reads as warning
     without breaking the colour temperature of the page. */
  background: rgba(255, 122, 60, 0.20);
  color: var(--brand-sunset);
}
body[data-page="prompt"] .section {
  background: rgba(255, 226, 244, 0.03);
  border-color: rgba(255, 226, 244, 0.08);
}
body[data-page="prompt"] textarea {
  background: rgba(11, 2, 38, 0.60);
  border: 1px solid rgba(255, 226, 244, 0.08);
  color: var(--ink);
}
body[data-page="prompt"] textarea:focus {
  border-color: var(--brand-cyan);
  box-shadow: 0 0 0 3px rgba(0, 240, 255, 0.18);
}
body[data-page="prompt"] .placeholders code,
body[data-page="prompt"] code.placeholder {
  background: rgba(0, 240, 255, 0.10);
  color: var(--brand-cyan);
}
body[data-page="prompt"] .placeholders code:hover {
  background: rgba(0, 240, 255, 0.20);
}
body[data-page="prompt"] pre.preview {
  background: rgba(11, 2, 38, 0.60);
  border-color: rgba(255, 226, 244, 0.06);
}
body[data-page="prompt"] .sep {
  color: var(--brand-cyan);
}
body[data-page="prompt"] .head-right a {
  color: var(--brand-cyan);
}

/* Hero — portrait + clock side by side on wide, stacked on narrow. */
.hero {
  display: grid;
  /* Left column was 220 px (portrait + conic ring). Bumped to 280 px so
     the new roulette ring (inset:-40 px of the 200 px portrait-wrap, =
     280 px wide) fits without overlapping the clock face on the right.
     Showcase uses the same shell but no roulette ring — the extra slack
     just gives the portrait more visual mass against the aurora. */
  grid-template-columns: 280px 1fr;
  gap: 28px;
  align-items: center;
  margin-top: 32px;
  padding: 24px;
  background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.01));
  border: 1px solid rgba(255,255,255,0.06);
  border-radius: 22px;
  box-shadow: var(--shadow);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
}

/* Portrait column wraps the spinning portrait (+ ring + roulette ring)
   and the roulette result chip that surfaces when the wheel lands.
   The chip lives outside .portrait-wrap so its layout doesn't compete
   with the absolutely-positioned ring elements above it. */
.portrait-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  min-width: 0;
}
.portrait-wrap {
  position: relative;
  width: 200px;
  height: 200px;
  /* Roulette ring extends 40 px past every edge of .portrait-wrap;
     allowing overflow keeps it visible without resizing the layout
     slot inside .hero. */
  overflow: visible;
}
.portrait-wrap .ring {
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    var(--accent),
    var(--accent-2),
    var(--brand-gold),
    var(--accent)
  );
  filter: blur(1px);
  /* Rotation is JS-driven so we can ease the spin up when the imager
     voice talks and ease it down when it stops, matching the artwork
     ring's behaviour during the song. CSS-animation removed on purpose. */
  opacity: 0.9;
  transform: rotate(0deg);
  will-change: transform;
}
.portrait-wrap .ring::after {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 50%;
  background: var(--bg);
}
.portrait-wrap .portrait {
  position: relative;
  z-index: 1;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  object-fit: cover;
  margin: 0;
  box-shadow:
    0 0 0 2px rgba(0,0,0,0.6),
    0 18px 50px rgba(0, 0, 0, 0.6);
  /* Vinyl spin — angle is driven by JS so it can ease in and out
     around playback events. The ring counter-rotates in player.js. */
  transform: rotate(0deg);
  will-change: transform;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}

.clock-block {
  text-align: left;
}
.clock-label {
  /* Audiowide callsign tag — broadcast-monitor style. Sits in cyan
     above the chrome clock face for the deep-night→pink→gold
     vertical reading order the brand brief specifies. */
  font-family: var(--brand-frequency);
  font-weight: 400;
  font-size: 11px;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--brand-cyan);
  margin-bottom: 8px;
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.35);
}
.clock-value {
  /* Hero clock face. Orbitron 800 + the full six-stop chrome gradient
     from --brand-chrome, plus a three-layer drop-shadow stack:
       (1) wide hot-pink halo grounds the face into the deep-night
           background and tints the ambient light pink;
       (2) tight gold rim on the underside reads as catch-light from
           the sunset glow in the aurora;
       (3) micro cream highlight on top edge adds the anodised lift.
     A 0.5px plum text-stroke echoes the SVG lockup's
       stroke="#3a0046" paint-order="stroke"
     construction, giving each glyph the same deep-plum hairline
     definition the printed wordmark has. tabular-nums keeps every
     digit on a fixed advance so the MM:SS countdown does not jitter
     pixel-by-pixel as numerals tick down. */
  font-family: var(--brand-sans);
  font-weight: 800;
  font-size: clamp(56px, 11vw, 96px);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  background: var(--brand-chrome);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  -webkit-text-stroke: 0.5px rgba(58, 0, 70, 0.65);
  filter:
    drop-shadow(0 0 30px rgba(255, 45, 149, 0.45))
    drop-shadow(0 2px 1px rgba(255, 210, 74, 0.35))
    drop-shadow(0 -1px 0 rgba(255, 226, 244, 0.55));
}
.clock-bar {
  position: relative;
  height: 4px;
  margin-top: 16px;
  background: rgba(255,255,255,0.06);
  border-radius: 2px;
  overflow: hidden;
}
#clock-fill {
  position: absolute; inset: 0 auto 0 0;
  width: 0%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  box-shadow: 0 0 16px rgba(255, 45, 149, 0.40);
  transition: width 0.18s linear;
}

/* Three-track strip. The current track sits in a brighter, lifted card
   with its own progress bar. Previous and next are visually quieter so
   the hierarchy reads at a glance. */
.tracks {
  margin-top: 22px;
  display: grid;
  gap: 10px;
}
.trow {
  padding: 14px 18px;
  border-radius: 16px;
  background: rgba(255,255,255,0.02);
  border: 1px solid rgba(255,255,255,0.04);
  transition: background 0.3s ease, transform 0.3s ease;
}
.trow--prev, .trow--next {
  opacity: 0.78;
}
.trow--curr {
  position: relative;
  background:
    linear-gradient(180deg, rgba(255, 45, 149, 0.10), rgba(0, 240, 255, 0.05)),
    rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 45, 149, 0.25);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.06),
    0 14px 40px rgba(0,0,0,0.45);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 18px;
  align-items: center;
}
.trow--curr.is-playing { transform: translateY(-1px); }
.trow-meta { min-width: 0; }

/* Artwork circle — same Miami-beach conic ring as the portrait, sized
   smaller so it fits inside the now-playing row. The ring rotation is
   driven entirely by JS (see player.js) so it can ease in/out matching
   the song's playback state — never an abrupt start or stop. */
.art-wrap {
  position: relative;
  width: 96px;
  height: 96px;
  flex-shrink: 0;
}
.art-ring {
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    var(--accent),
    var(--accent-2),
    var(--brand-gold),
    var(--accent)
  );
  filter: blur(1px);
  opacity: 0.9;
  transform: rotate(0deg);
  will-change: transform;
}
.art-ring::after {
  content: "";
  position: absolute;
  inset: 5px;
  border-radius: 50%;
  background: var(--bg-2);
}
.art-stack {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  box-shadow:
    0 0 0 2px rgba(0,0,0,0.6),
    0 10px 28px rgba(0,0,0,0.55);
  /* Vinyl spin — angle is driven by JS in lockstep with the artwork
     ring's counter-rotation. The circular clip plus the stacked images
     mean the visible edge stays put while the cover art turns. */
  transform: rotate(0deg);
  will-change: transform;
}
.art-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* 700 ms cross-fade — long enough to feel intentional, short enough
     not to overlap with the previous track's outro under the imager. */
  transition: opacity 0.7s ease-in-out;
}
.art-image.is-visible { opacity: 1; }
.art-fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 30% 30%, rgba(255,90,60,0.35), transparent 60%),
    linear-gradient(135deg, #1c2330, #11161e);
  opacity: 1;
  transition: opacity 0.45s ease-out;
}
.art-fallback.is-hidden { opacity: 0; }
.art-fallback-mark {
  font: 700 18px/1 var(--sans);
  letter-spacing: 0.16em;
  color: rgba(255,255,255,0.85);
  text-transform: uppercase;
}

.trow-role {
  font: 500 10px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink-dim);
  margin-bottom: 6px;
}
.live-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent);
  font-weight: 600;
}
.live-tag::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
}
.trow-title {
  font-size: clamp(18px, 3.4vw, 26px);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.trow--curr .trow-title {
  background: linear-gradient(180deg, #ffffff 0%, #d8e3f2 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.trow-artist {
  margin-top: 4px;
  color: var(--ink-dim);
  font-size: 14px;
}
.trow-bar {
  position: relative;
  height: 3px;
  margin-top: 12px;
  background: rgba(255,255,255,0.06);
  border-radius: 2px;
  overflow: hidden;
}
#trow-bar-fill {
  position: absolute; inset: 0 auto 0 0;
  width: 0%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width 0.18s linear;
}
.trow-time {
  margin-top: 6px;
  font: 12px var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink-dim);
}

/* Controls cluster — arm button, current line, audio element. */
.controls {
  margin-top: 22px;
  padding: 20px;
  background: rgba(255,255,255,0.02);
  border: 1px solid rgba(255,255,255,0.04);
  border-radius: 16px;
  text-align: center;
}
.arm-btn {
  font: 600 14px/1 var(--sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--accent), var(--brand-plum));
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: #18110d;
  box-shadow:
    0 0 0 3px  rgba(255, 45, 149, 0.18),
    0 12px 28px rgba(255, 45, 149, 0.28);
  cursor: pointer;
  transition: transform 0.05s ease, filter 0.2s ease;
}
.arm-btn:hover { filter: brightness(1.06); }
.arm-btn:active { transform: translateY(1px); }
.arm-btn:disabled {
  background: rgba(255,255,255,0.08);
  color: var(--ink-dim);
  box-shadow: none;
  filter: none;
}
.now-line {
  /* Manuscript display under the Arm button. Bumped from 18 → 22 px so
     the spoken line reads as the primary content of the controls panel
     rather than competing with the clock face above it; cream-on-deep-
     night with a soft pink halo so it sits in the brand register
     instead of the previous flat cyan. */
  font: 500 22px/1.45 var(--brand-sans);
  color: var(--brand-cream);
  letter-spacing: 0.005em;
  margin: 18px 0 14px;
  min-height: 1.5em;
  text-shadow: 0 0 18px rgba(255, 45, 149, 0.18);
}

/* Listen-block — Icecast HTML5 player on the public showcase.
   Slim card matching the .recent-block aesthetic: low-alpha wash on
   the deep-night base, hot-pink hairline only on the title and state
   pill so the controls themselves stay native (each browser renders
   its own audio chrome — we don't fight that battle). The block is
   `hidden` at boot and only revealed when /api/live carries a
   station.streamUrl, so the page is visually unchanged until the
   Icecast service is online. */
.listen-block {
  margin-top: 22px;
  padding: 14px 20px 16px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 16px;
  display: grid;
  gap: 10px;
}
.listen-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.listen-label {
  font: 500 11px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--brand-cyan);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.30);
}
.listen-state {
  font: 500 11px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.10em;
  padding: 5px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink-dim);
}
.listen-state.ok   { background: rgba(109, 212, 154, 0.15); color: var(--good); }
.listen-state.warn { background: rgba(245, 196, 81, 0.15); color: var(--warn); }
.listen-state.bad  { background: rgba(255, 94, 108, 0.15); color: var(--bad); }
.listen-audio {
  width: 100%;
  /* native controls keep accessibility + keyboard handling for free;
     filter mutes the bright Chrome/Safari default panel into the
     dark broadcast palette without overriding the rendering itself. */
  filter: invert(0.92) hue-rotate(180deg) saturate(0.85);
  border-radius: 10px;
}
.listen-hint {
  margin: 0;
  font: 12px/1.4 var(--mono);
  color: var(--warn);
  opacity: 0.85;
}

/* Recent links — compact monospace list, time gutter, faded chrome. */
.recent-block {
  margin-top: 22px;
  padding: 18px 20px 12px;
  background: rgba(255,255,255,0.02);
  border: 1px solid rgba(255,255,255,0.04);
  border-radius: 16px;
}
.recent-head {
  font: 500 11px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink-dim);
  margin: 0 0 8px;
}
#recent {
  list-style: none;
  margin: 0; padding: 0;
}
#recent li {
  padding: 8px 0;
  border-top: 1px dashed rgba(255,255,255,0.06);
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: 12px;
  align-items: baseline;
}
#recent li:first-child { border-top: 0; }
.recent-ts {
  font: 11px var(--mono);
  color: var(--ink-dim);
  letter-spacing: 0.06em;
}
.recent-text {
  color: var(--ink);
  font-size: 14px;
}

@media (max-width: 640px) {
  .hero {
    grid-template-columns: 1fr;
    text-align: center;
    padding: 24px 18px;
  }
  .portrait-wrap { margin: 0 auto; }
  .clock-block { text-align: center; }
  .trow-title { font-size: 20px; }
}

/* ── Showcase page — public broadcast vitrin ───────────────────────────
   The page reuses every player rule via the comma-extended selectors
   above. The two additions here are: the broadcast-line quote shown
   under the track strip (the latest TTS manuscript with audio-tag
   directives stripped server-side), and the off-air visual state that
   dims tracks and disables the live-tag pulse so the page reads as
   "paused but still recognisably Slick FM". */
body[data-page="showcase"] .latest-line {
  /* Public broadcast quote. Significantly larger than the operator
     /player's .now-line so the manuscript reads as the centrepiece of
     the showcase page — it's the one thing visitors are here to see.
     Hot-pink halo + cream text stays inside the brand register; the
     panel keeps its low-alpha wash so it sits over the aurora without
     stamping a hard edge. */
  margin: 26px 0 0;
  padding: 24px 28px;
  background: rgba(11, 2, 38, 0.42);
  border: 1px solid rgba(255, 45, 149, 0.18);
  border-radius: 18px;
  font-family: var(--brand-sans);
  font-weight: 500;
  font-size: clamp(20px, 3vw, 32px);
  line-height: 1.4;
  color: var(--brand-cream);
  font-style: italic;
  letter-spacing: 0.005em;
  text-shadow: 0 0 22px rgba(255, 45, 149, 0.20);
  box-shadow:
    inset 0 1px 0 rgba(255, 226, 244, 0.06),
    0 18px 50px rgba(0, 0, 0, 0.35);
}

body[data-page="showcase"].is-off-air .trow-title,
body[data-page="showcase"].is-off-air .trow-artist {
  opacity: 0.45;
}
body[data-page="showcase"].is-off-air .live-tag {
  color: var(--ink-dim);
}
body[data-page="showcase"].is-off-air .live-tag::before {
  background: var(--ink-dim);
  box-shadow: none;
  animation: none;
}
body[data-page="showcase"].is-off-air .clock-value {
  font-size: clamp(36px, 6.5vw, 64px);
  letter-spacing: 0.04em;
  filter: drop-shadow(0 0 18px rgba(255, 45, 149, 0.20));
}

/* ── Header pills + breathing room (public-facing pages) ───────────────
   /player and /showcase share the same sticky .p-head. The brand block
   on the left and the status pill on the right now read as distinct
   broadcast bugs: each sits inside its own dark capsule with a hair-
   line stroke in the Miami-pink register, and both are inset from the
   .player-shell edge so a comfortable air gap surrounds them. /desk
   and /prompt are tighter control surfaces and stay on the slim
   header — they're not touched here. */
body[data-page="player"] .p-head,
body[data-page="showcase"] .p-head {
  padding: 16px 0;
  gap: 16px;
}
body[data-page="player"] .p-head .brand,
body[data-page="showcase"] .p-head .brand {
  padding: 10px 18px 10px 16px;
  margin-left: 8px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(11, 2, 38, 0.85), rgba(11, 2, 38, 0.65));
  border: 1px solid rgba(255, 45, 149, 0.22);
  box-shadow:
    inset 0 1px 0 rgba(255, 226, 244, 0.05),
    0 4px 18px rgba(0, 0, 0, 0.35);
}
body[data-page="player"] .p-head #status,
body[data-page="showcase"] .p-head #status {
  margin-right: 8px;
  padding: 8px 14px;
  background: rgba(11, 2, 38, 0.85);
  border: 1px solid rgba(255, 226, 244, 0.10);
  box-shadow:
    inset 0 1px 0 rgba(255, 226, 244, 0.04),
    0 4px 18px rgba(0, 0, 0, 0.35);
}

/* ── Log readability — "rejäl" theme treatment ────────────────────────
   The recent-links block on /player and /showcase, and the event-log
   card on /desk, all pull manuscript text into brand-cream with a
   hot-pink timestamp gutter and a left-edge accent strip. The lines
   read as broadcast bugs rather than the previous faded-chrome rows
   that were easy to skim past. Failed-row treatment on /desk keeps
   its red accent. */
.recent-block .recent-head {
  color: var(--brand-cyan);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.30);
  font-size: 12px;
}
#recent li {
  padding: 10px 0 10px 12px;
  border-top-color: rgba(255, 226, 244, 0.08);
  box-shadow: inset 3px 0 0 rgba(255, 45, 149, 0.55);
  grid-template-columns: 76px 1fr;
}
.recent-ts {
  color: var(--brand-hot-pink);
  font-weight: 600;
  letter-spacing: 0.08em;
}
.recent-text {
  color: var(--brand-cream);
  font-size: 15px;
  line-height: 1.45;
  font-style: italic;
}

body[data-page="control"] .card.log h2 {
  color: var(--brand-cyan);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.30);
}
body[data-page="control"] .log li {
  padding-left: 14px;
  box-shadow: inset 3px 0 0 rgba(255, 45, 149, 0.55);
  font-size: 14px;
  border-top-color: rgba(255, 226, 244, 0.08);
}
body[data-page="control"] .log .ts {
  color: var(--brand-hot-pink);
  font-weight: 600;
  letter-spacing: 0.06em;
}
body[data-page="control"] .log .body .text {
  color: var(--brand-cream);
  font-style: italic;
}
body[data-page="control"] .log li.bad {
  box-shadow: inset 3px 0 0 var(--bad);
}

/* ── Roulette ring around the portrait (player only) ──────────────────
   The portrait keeps its conic colour ring (.ring) unchanged — both
   look and the JS-driven counter-rotation are untouched. The new
   roulette-ring SVG sits directly outside the conic ring with no
   margin, 37 European-wheel segments in the brand palette: hot-pink
   for the "red" pockets, deep-night/plum for the "black" pockets,
   cyan for the single zero. A fixed gold pointer marks the top of
   the ring; the segment under it when the wheel comes to rest is
   announced in the result chip below the portrait. */
.roulette-ring {
  position: absolute;
  inset: -40px;
  width: 280px;
  height: 280px;
  pointer-events: none;
  /* Sits above the conic .ring band (which uses an opaque inner mask
     via ::after) but below the portrait image. Both transforms are
     JS-driven from the same shared portrait-ring rotation in
     tickRings, so conic + roulette read as one wheel. */
  z-index: 0;
  will-change: transform;
  /* Drop-shadow puts a soft pink halo around the wheel so the
     numbers don't disappear into the aurora gradient. */
  filter: drop-shadow(0 0 18px rgba(255, 45, 149, 0.22));
}
.roulette-ring .rr-wedge {
  stroke: rgba(11, 2, 38, 0.85);
  stroke-width: 0.6;
}
.roulette-ring .rr-wedge--red    { fill: #ff2d95; }
.roulette-ring .rr-wedge--black  { fill: #1a063e; }
.roulette-ring .rr-wedge--green  { fill: #00f0ff; }
.roulette-ring .rr-num {
  font-family: var(--brand-frequency);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0;
  fill: #ffe2f4;
  paint-order: stroke;
  stroke: rgba(11, 2, 38, 0.65);
  stroke-width: 0.5;
}
.roulette-ring .rr-num--green {
  /* Cyan pockets are lighter than the cream digits — flip the digit
     to deep-night so "0" still reads at-a-glance. */
  fill: #0b0226;
  stroke: rgba(255, 226, 244, 0.4);
}

/* Pointer — gold isoceles triangle just above the wheel's outer
   edge. Tip pierces ~3 px into the roulette band so the indicated
   segment is unambiguous. */
.roulette-pointer {
  position: absolute;
  top: -46px;
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-top: 16px solid var(--brand-gold);
  filter: drop-shadow(0 0 10px rgba(255, 210, 74, 0.65));
  z-index: 3;
}
.roulette-pointer::after {
  /* Small dot at the very top so the pointer reads as "broadcast
     monitor" rather than a generic arrow. */
  content: "";
  position: absolute;
  top: -10px;
  left: -3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand-gold);
  box-shadow: 0 0 8px rgba(255, 210, 74, 0.7);
}

/* Result chip — surfaces once the wheel has stopped after a spin.
   Lives directly under .clock-bar so it reads as a banner tied to the
   countdown bar. width: 100% + box-sizing matches the bar's footprint
   exactly; the children stay on one horizontal axis via flex. Aria-
   live=polite on the wrapping element announces the result to screen
   readers without interrupting other broadcast updates. */
.roulette-result {
  display: flex;
  width: 100%;
  box-sizing: border-box;
  margin-top: 12px;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 8px 12px;
  border-radius: 999px;
  background: rgba(11, 2, 38, 0.78);
  border: 1px solid rgba(255, 45, 149, 0.22);
  box-shadow:
    inset 0 1px 0 rgba(255, 226, 244, 0.05),
    0 6px 22px rgba(0, 0, 0, 0.40);
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-cream);
}
.roulette-result[hidden] { display: none; }
.roulette-result .rr-label {
  color: var(--brand-cyan);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.30);
}
.roulette-result .rr-arrow {
  color: rgba(255, 226, 244, 0.55);
  font-family: var(--brand-frequency);
  font-size: 13px;
}
.roulette-result .rr-number {
  font: 700 16px/1 var(--brand-frequency);
  letter-spacing: 0;
  padding: 5px 10px;
  border-radius: 6px;
  background: rgba(255, 226, 244, 0.08);
  color: var(--brand-cream);
  text-transform: none;
  min-width: 28px;
  text-align: center;
}
.roulette-result.is-red .rr-number {
  background: #ff2d95;
  color: #0b0226;
}
.roulette-result.is-black .rr-number {
  background: #1a063e;
  color: var(--brand-cream);
  border: 1px solid rgba(255, 45, 149, 0.18);
}
.roulette-result.is-green .rr-number {
  background: #00f0ff;
  color: #0b0226;
}
.roulette-result .rr-meta {
  color: var(--brand-cream);
  letter-spacing: 0.10em;
  white-space: nowrap;
}

@media (max-width: 640px) {
  /* On narrow viewports the hero collapses to a single column already.
     Shrink the roulette ring slightly so it doesn't dominate. */
  .roulette-ring { inset: -32px; width: 264px; height: 264px; }
  .roulette-pointer { top: -38px; }
}

