/* ═══════════════════════════════════════════════════════════════════════════
   Themes. Loaded last so it wins on colour without touching layout.

   style.css owns structure and declares the design tokens; this file redefines
   those tokens per theme and adds the skin rules a token can't express — a
   moulded plastic frame, an outlined display face, a per-side accent.

   The canvas half of each theme (mino palette, cell bevel, well texture) is in
   theme.js, because neither renderer can read CSS variables. Change one, check
   the other.

   Selected by [data-theme] on <html>, set by the inline script in index.html
   before first paint and made authoritative by theme.js.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ╔═════════════════════════════════════════════════════════════════════════╗
   ║ ARCADE — the default.                                                   ║
   ║                                                                         ║
   ║ Bubble-tea cyan into spring green, each playfield a piece of glossy     ║
   ║ moulded plastic with the Next/Hold pods bolted on, and chunky outlined  ║
   ║ lettering. Three light sources are consistent throughout — a specular   ║
   ║ strip along the top of every raised surface, a dark lip along the       ║
   ║ bottom, and a hard teal-black keyline around everything.                ║
   ╚═════════════════════════════════════════════════════════════════════════╝ */
:root[data-theme="arcade"] {
  --bg: #01b3c9;
  /* Cyan down into spring green, landing on the palette's own near-white. The
     board is its own near-black world, which is what lets the field swing this
     far without a single mino having to move. */
  --bg-image:
    radial-gradient(150% 92% at 50% 122%, rgba(255, 255, 255, 0.9), transparent 60%),
    linear-gradient(180deg, #027d8f 0%, #01b3c9 32%, #16d37b 64%, #ebf4f8 100%);

  --panel: linear-gradient(180deg, #ffffff, #ebf4f8);
  --panel-2: #dfeef4;
  --panel-3: #cbe3ec;
  --well: #ffffff;
  --board: #20242a;

  --text: #06323a;
  --muted: #2f7b88;
  --accent: #ffbfcf;
  --accent-2: #ff9acc;
  --accent-3: #16d37b;
  --on-accent: #3d0a22;
  /* Pink is unreadable as text on white, so light surfaces get this instead. */
  --accent-ink: #a81f5e;

  /* The danger family keeps its reds. Every tone in it lands on a dark overlay
     — the lose banner, the urgent clock — and never on the field beside a pink
     control, so the two are never asked to be told apart side by side. */
  --danger: #f0453c;
  --danger-2: #8a1a13;
  --warn: #ff8a17;
  /* Gold survives the repaint because it is a board colour, not a UI one: it
     marks combos, clear popups and winner badges, all of which float over the
     near-black playfield, where a warm highlight still has somewhere to sit. */
  --gold: #ffc21a;
  --ok: #16d37b;

  --border: rgba(6, 50, 58, 0.24);
  --border-hover: rgba(6, 50, 58, 0.55);
  --scrim: rgba(5, 20, 24, 0.86);
  --scrim-modal: rgba(4, 42, 52, 0.62);
  --shadow-panel: 0 7px 0 rgba(6, 50, 58, 0.16), 0 26px 40px rgba(4, 70, 84, 0.3);

  /* No --font-display here any more: the arcade face in style.css is the
     display face in every theme, and it has one weight and its own built-in
     spacing, so --display-weight and --display-spacing are not a theme's to set
     either. Case still is — this cabinet shouts. */
  --display-transform: uppercase;

  /* The outline ring. -webkit-text-stroke draws the stroke *over* the glyph and
     thins it; a text-shadow ring surrounds it instead, which is how the Flash
     original did it. */
  --ink-out: #0a2a30;
  --outline:
    2px 0 var(--ink-out), -2px 0 var(--ink-out), 0 2px var(--ink-out), 0 -2px var(--ink-out),
    1.5px 1.5px var(--ink-out), -1.5px 1.5px var(--ink-out),
    1.5px -1.5px var(--ink-out), -1.5px -1.5px var(--ink-out);
  --outline-drop: 0 4px 0 rgba(10, 42, 48, 0.34);

  /* Moulded plastic: the rig, its pods, and the lip under a button. */
  --shell: linear-gradient(180deg, #626c78 0%, #3a424b 5%, #262c33 26%, #171b20 100%);
  --shell-edge: #0d1116;
  --shell-ink: #d7eef4;
  --shell-muted: #90b3bd;
  --pod: linear-gradient(180deg, #39414a 0%, #262c33 40%, #1a1f25 100%);
  --btn-face: #dceef4;
  --btn-lip: #0a2a30;

  /* The heading sprites again, for a card that is nearly white. The metals keep
     their hues and lose their glow, and the outline stops being a formality: on
     the dark themes it is a shadow, here it is the thing that holds the trophy
     together.
     Every ink here is set against --panel-2 (#dfeef4), the leaderboard card,
     because that is what all three sprites are drawn on. The swords and the
     star carry no outline at all — nothing but their own colour separates them
     from the card — so those two are the ones with margin to spare. */
  --icon-ink: rgba(6, 50, 58, 0.85);
  --icon-gold: #ad7700;
  /* The specular pixel, and the one ink on this card that cannot reach 3:1: it
     has to stay lighter than the gold it is a highlight on, and anything
     lighter than a 3.3:1 gold is under 3:1 by arithmetic. Taken as dark as it
     can go while still reading as the lit edge (1.9:1, up from 1.3:1), and left
     there — it is one interior pixel of a decorative sprite, inside an outline
     that is 7.7:1, beside a heading that says the same thing in words. */
  --icon-gold-hi: #d9a327;
  --icon-steel: #5f7d9b;
  --icon-grip: #8a5323;
  --icon-medal: #a3761c;

  /* The rank ramp again, in inks. The default ramp is built for a near-black
     card, where a bright gold row is the loudest thing on it; on this one it is
     the faintest. Same hues, same order, all of it darkened until it holds
     against the pale blue. */
  --rank-1: #0f8a4a;
  --rank-2: #06323a;
  --rank-3: #14505c;
  --rank-4: #8a6000;
  --rank-5: #a05205;
  --rank-6: #b0400c;
  --rank-7: #bd1f28;
  --rank-8: #7b2fbe;
  --rank-9: #a81f5e;
  --rank-10: #106b8c;
}

/* A vignette over the field. Negative z-index paints above the body background
   but below content, so it needs no wrapper element. */
:root[data-theme="arcade"] body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(120% 80% at 50% 40%, transparent 46%, rgba(8, 39, 46, 0.26) 100%);
}

/* ── display type ───────────────────────────────────────────────────────── */
/* h1 in style.css clips a gradient to the text, so the gradient has to be
   cleared here as well as the transparent fill. */
:root[data-theme="arcade"] h1 {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: #fff;
  text-shadow: var(--outline), var(--outline-drop);
  /* Fluid for the same reason as the base rule: ten fixed-width capitals. */
  font-size: clamp(1.55rem, 6.5vw, 2.5rem);
}
:root[data-theme="arcade"] .tagline {
  font-weight: 700;
  color: #266775;
}

/* ── menu card ──────────────────────────────────────────────────────────── */
:root[data-theme="arcade"] #menu {
  border: 3px solid var(--btn-lip);
  border-radius: 22px;
}
:root[data-theme="arcade"] #mascot {
  filter: drop-shadow(0 7px 10px rgba(6, 42, 50, 0.35));
}
:root[data-theme="arcade"] .divider { color: #3d808f; }
:root[data-theme="arcade"] .divider::before,
:root[data-theme="arcade"] .divider::after { background: #89c3d0; }

/* ── buttons: a face, a lip, and travel when pressed ───────────────────── */
:root[data-theme="arcade"] button {
  border: 2px solid var(--btn-lip);
  border-radius: 30px;
  background: var(--btn-face);
  color: #10323a;
  /* An offset block shadow rather than a lip under the bottom edge: the light
     now comes from the top left and the key is lifted off the card, so the
     press is a diagonal move onto its own shadow instead of a drop. */
  box-shadow: 4px 4px 0 0 var(--btn-lip);
  transition: transform 0.07s ease, background 0.15s ease, box-shadow 0.07s ease;
}
:root[data-theme="arcade"] button:hover {
  background: #ffffff;
  border-color: var(--btn-lip);
}
:root[data-theme="arcade"] button:active {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 0 var(--btn-lip);
}
/* The mode keys keep the face and the shadow but not the full pill: two of them
   sit on one track, and a 30px radius on a box that narrow eats into the label
   at both ends. */
:root[data-theme="arcade"] .mode-tile { border-radius: 18px; }

/* The map picker's tiles are pictures, not keys. The face, the pill and the
   block shadow would sit a second panel behind a well that already has an edge
   of its own — a white slab inside a blue one — and a 30px radius on a box this
   small rounds the corners into the art. So the button gives up its chrome and
   the lip moves onto the well itself: one outline, drawn around the picture. */
:root[data-theme="arcade"] .bs-map {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
:root[data-theme="arcade"] .bs-map:hover { background: none; }
:root[data-theme="arcade"] .bs-map:active { transform: none; box-shadow: none; }
:root[data-theme="arcade"] .bs-map-art {
  border-width: 2px;
  box-shadow: 3px 3px 0 0 var(--btn-lip);
  transition: transform 0.07s ease, box-shadow 0.07s ease;
}
:root[data-theme="arcade"] .bs-map:active .bs-map-art {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 0 var(--btn-lip);
}
:root[data-theme="arcade"] .bs-map:hover .bs-map-art { border-color: var(--btn-lip); }
/* --accent out here is the pale pink of the shell, which cannot mark a choice
   against a white well. The ink is the same family at a weight that can. */
:root[data-theme="arcade"] .bs-map.on .bs-map-art {
  border-color: var(--accent-ink);
  box-shadow: 3px 3px 0 0 var(--accent-ink);
}
:root[data-theme="arcade"] .bs-map.on .bs-map-name { color: var(--accent-ink); }
/* Same trade in the difficulty list, and for the same reason: pale pink pips
   on the shell's own pale face are a ladder you have to squint at. */
:root[data-theme="arcade"] .cpu-pips i { background: rgba(6, 50, 58, 0.2); }
:root[data-theme="arcade"] .cpu-pips i.on { background: var(--accent-ink); }
:root[data-theme="arcade"] .cpu-item.last { border-color: var(--accent-ink); }
:root[data-theme="arcade"] button.primary {
  text-transform: uppercase;
  color: #fff;
  text-shadow: var(--outline);
  background: #ff6aad;
  border: 2px solid var(--btn-lip);
  box-shadow: 4px 4px 0 0 var(--btn-lip);
}
:root[data-theme="arcade"] button.primary:hover {
  filter: none;
  background: #ff85bd;
}
:root[data-theme="arcade"] button.primary:active {
  box-shadow: 2px 2px 0 0 var(--btn-lip);
}
:root[data-theme="arcade"] button.ghost {
  background: #e0f0f3;
  color: #1f5d6b;
}
:root[data-theme="arcade"] button.ghost:hover { background: #d0e7ec; color: #10323a; }
/* A field, not a key. These had the key's exact chrome — the same lip, the same
   4px block shadow lifting them off the card — and on a theme whose card is
   white and whose well is also white, that shadow was the only thing the eye
   had to go on: the name box read as a second big button stacked over Quick
   match, and CODE read as a disabled one next to Join. The theme already states
   where its light comes from, so the fix is to obey it — a key is raised and a
   well is sunk. The shadow turns inward, the fill drops below the card's
   white, and the two objects stop being the same object. */
:root[data-theme="arcade"] .name-input,
:root[data-theme="arcade"] .join-row input {
  border: 2px solid var(--btn-lip);
  border-radius: 30px;
  background: #eef7fa;
  box-shadow: inset 0 3px 0 0 rgba(6, 50, 58, 0.15);
  font-weight: 700;
}
:root[data-theme="arcade"] .name-input:focus,
:root[data-theme="arcade"] .join-row input:focus {
  background: #ffffff;
}

/* ── the rig: one piece of moulded plastic ──────────────────────────────── */
:root[data-theme="arcade"] .player {
  background: var(--shell);
  border: 3px solid var(--shell-edge);
  border-radius: 26px;
  padding: 14px 12px 16px;
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.42),
    inset 0 -3px 0 rgba(0, 0, 0, 0.5),
    0 8px 0 rgba(13, 17, 22, 0.22),
    0 22px 32px rgba(10, 51, 60, 0.34);
}
/* An *outset* ring on the canvas itself. Inset shadows are painted under a
   canvas's own bitmap and never show, and putting the ring on .board-wrap would
   frame the nameplate too — the playfield has to read as its own recessed part. */
:root[data-theme="arcade"] canvas.board {
  border-radius: 5px;
  box-shadow: 0 0 0 3px var(--shell-edge), 0 3px 8px rgba(0, 0, 0, 0.55);
}
:root[data-theme="arcade"] .board-wrap { padding-top: 2px; }
/* The nameplate is a second recessed part in the same shell, so it has to line
   up with the playfield below it. Its edge is an *outset* ring, not a border:
   the canvas above uses one (an inset shadow never shows through a canvas's own
   bitmap), and box-sizing is border-box everywhere — so a 2px border sat inside
   the plate's box while the canvas's 3px ring sat outside its own. Same colour,
   opposite sides of the box, and the board ended up 3px wider per side than the
   plate. Padding absorbs the 4px the dropped border was holding, and the radius
   is the canvas's 5px + 3px ring, so both parts round identically. */
:root[data-theme="arcade"] .name-tag {
  margin-bottom: 14px;   /* 3px of it is the ring; 8px reads as the gap */
  padding: 8px 14px 9px;
  border-radius: 8px;
  background: linear-gradient(180deg, #1c2127, #0f1216);
  border: none;
  box-shadow:
    0 0 0 3px var(--shell-edge),
    inset 0 1px 0 rgba(255, 255, 255, 0.15),
    inset 0 3px 7px rgba(0, 0, 0, 0.55);
  line-height: 1.15;
}

:root[data-theme="arcade"] .side h3 { color: var(--shell-muted); }
:root[data-theme="arcade"] .slot {
  background: var(--pod);
  border: 2px solid var(--shell-edge);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.26);
}
:root[data-theme="arcade"] .stat .label { color: var(--shell-muted); }
:root[data-theme="arcade"] .stat .value {
  color: #fff;
  text-shadow: var(--outline);
}
:root[data-theme="arcade"] .name-tag {
  text-transform: uppercase;
  color: #fff;
  text-shadow: var(--outline);
}
:root[data-theme="arcade"] .badge {
  background: linear-gradient(180deg, #e6f5f8, #c2dfe6);
  color: #1f5d6b;
  border: 1.5px solid var(--shell-edge);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.35);
}
:root[data-theme="arcade"] .garbage-meter {
  background: #14181d;
  border: 2px solid var(--shell-edge);
  box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.6);
}
/* ── control deck ──────────────────────────────────────────────────────── */
/* The deck is the same moulded plastic as a rig, hung off the top of the
   screen: specular strip along its top, dark lip along the bottom, hard
   keyline all round. The three light sources are the ones every other raised
   surface in this theme uses, which is what makes it read as one machine
   rather than a bar that happens to be dark. */
:root[data-theme="arcade"] .deck {
  background: var(--shell);
  border: 3px solid var(--shell-edge);
  border-top: none;
  border-radius: 0 0 20px 20px;
  padding: 9px 8px 11px;
  box-shadow:
    inset 0 -4px 0 rgba(0, 0, 0, 0.5),
    inset 0 2px 0 rgba(255, 255, 255, 0.14),
    0 8px 0 rgba(12, 33, 38, 0.14),
    0 20px 34px rgba(10, 51, 60, 0.32);
}
/* A moulding seam: the shadowed side of the split, then the lit side. */
:root[data-theme="arcade"] .deck-bay-mid {
  border-inline: none;
  box-shadow:
    inset 1px 0 0 rgba(255, 255, 255, 0.08), inset 2px 0 0 rgba(0, 0, 0, 0.45),
    inset -1px 0 0 rgba(255, 255, 255, 0.08), inset -2px 0 0 rgba(0, 0, 0, 0.45);
}
/* Cream key with a lip, seated in the moulding — the same button the menu
   screen uses, so the one control in a match is a control you have pressed. */
:root[data-theme="arcade"] .burger {
  background: var(--btn-face);
  border: 2px solid var(--btn-lip);
  border-radius: 30px;
  box-shadow: 4px 4px 0 0 var(--btn-lip);
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
:root[data-theme="arcade"] .burger:active {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 0 var(--btn-lip);
}
:root[data-theme="arcade"] .burger-bars i { background: #10323a; }
:root[data-theme="arcade"] .burger:hover .burger-bars i { background: #a81f5e; }
:root[data-theme="arcade"] .burger-text {
  color: #10323a;
}
:root[data-theme="arcade"] .burger:hover .burger-text { color: #a81f5e; }

/* Engraved into the moulding rather than printed on it: ink the colour of the
   shell's shadow, lifted by a one-pixel highlight underneath. */
:root[data-theme="arcade"] .mp-name {
  color: var(--shell-ink);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.55);
}
:root[data-theme="arcade"] .mp-note { color: var(--shell-muted); }
:root[data-theme="arcade"] .sb-name {
  color: var(--shell-ink);
}
:root[data-theme="arcade"] .deck-crest {
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.55));
}
:root[data-theme="arcade"] .deck-wordmark {
  color: var(--shell-muted);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.55);
}

/* Nudge the combo readout clear of the taller nameplate. */
:root[data-theme="arcade"] .combo-indicator { top: 54px; }

/* ── in-play callouts: outlined, never gradient-clipped ────────────────── */
:root[data-theme="arcade"] .combo-indicator .c,
:root[data-theme="arcade"] .combo-indicator .b,
:root[data-theme="arcade"] .clear-popup .pl,
:root[data-theme="arcade"] .clear-popup .pp,
:root[data-theme="arcade"] .countdown span.go {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  filter: none;
}
:root[data-theme="arcade"] .combo-indicator .c { color: #fff; text-shadow: var(--outline); }
:root[data-theme="arcade"] .combo-indicator .b { color: var(--gold); text-shadow: var(--outline); }
:root[data-theme="arcade"] .clear-popup .pl { color: #fff; text-shadow: var(--outline), var(--outline-drop); }
:root[data-theme="arcade"] .clear-popup .pp { color: var(--gold); text-shadow: var(--outline); }
:root[data-theme="arcade"] .countdown span,
:root[data-theme="arcade"] .countdown span.go {
  color: var(--gold);
  text-shadow: var(--outline), 0 8px 0 rgba(10, 29, 33, 0.3);
}
:root[data-theme="arcade"] .overlay .big {
  text-transform: uppercase;
  color: #fff;
  text-shadow: var(--outline);
}
:root[data-theme="arcade"] .overlay.win .big { color: #3ef0a0; }
:root[data-theme="arcade"] .overlay.lose .big { color: #ff8a8a; }
:root[data-theme="arcade"] .overlay .ov-btn {
  text-transform: uppercase;
  color: #fff;
  text-shadow: var(--outline);
  background: #ff6aad;
  border: 2px solid var(--btn-lip);
  box-shadow: 4px 4px 0 0 var(--btn-lip);
}
:root[data-theme="arcade"] .overlay .ov-btn-extra {
  background: var(--btn-face);
  color: #10323a;
  text-shadow: none;
  text-transform: none;
}

/* ── the round clock and KO counter ─────────────────────────────────────── */
/* A lit window sunk into the deck, not a plate stuck on it: the well is darker
   than the moulding, the light comes from inside the glass, and the frame
   catches a highlight only along its bottom edge — the opposite of every
   raised surface here, which is what makes it read as a hole. */
:root[data-theme="arcade"] .match-clock {
  padding: 5px 16px 7px;
  border-radius: 11px;
  background: radial-gradient(120% 140% at 50% 0%, #232a32, #10141a 72%);
  border: 2px solid #0a0d11;
  box-shadow:
    inset 0 3px 6px rgba(0, 0, 0, 0.75),
    inset 0 -1px 0 rgba(255, 255, 255, 0.1),
    0 1px 0 rgba(255, 255, 255, 0.07);
}
:root[data-theme="arcade"] .mc-label { color: var(--shell-muted); }
:root[data-theme="arcade"] .mc-time {
  color: var(--gold);
  text-shadow: var(--outline);
}
:root[data-theme="arcade"] .match-clock.urgent .mc-time { color: #ff6b5e; }
:root[data-theme="arcade"] .mc-drain {
  background: #0a0d11;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.8);
}
:root[data-theme="arcade"] .mc-drain i {
  background: linear-gradient(180deg, #ffe066, var(--gold));
  box-shadow: 0 0 6px rgba(255, 194, 26, 0.75);
}
:root[data-theme="arcade"] .match-clock.urgent .mc-drain i {
  background: linear-gradient(180deg, #ff9b8f, #f0453c);
  box-shadow: 0 0 7px rgba(240, 69, 60, 0.85);
}
:root[data-theme="arcade"] .ko-pip {
  background: #14181d;
  border: 2px solid var(--shell-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
:root[data-theme="arcade"] .ko-pip.on {
  background: radial-gradient(circle at 40% 30%, #fff3b0, var(--gold));
  border-color: var(--shell-edge);
  box-shadow: 0 0 9px rgba(255, 194, 26, 0.9);
}
:root[data-theme="arcade"] .ko-flash {
  color: #fff;
  text-shadow: var(--outline), 0 0 26px rgba(255, 90, 60, 0.9);
}

/* ── control deck ──────────────────────────────────────────────────────── */
/* No moulding here: the deck is a flat slab a shade above the page, held down
   by a single hairline and separated from the field by air, not by shadow. */
:root[data-theme="night"] .deck {
  background: linear-gradient(180deg, #161c2b, #10141f);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-top: none;
  box-shadow: 0 18px 34px rgba(0, 0, 0, 0.5);
}
:root[data-theme="night"] .deck-bay-mid {
  border-inline: 1px solid rgba(255, 255, 255, 0.07);
}
:root[data-theme="night"] .burger {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.09);
}
:root[data-theme="night"] .burger:hover { background: rgba(255, 255, 255, 0.09); }
:root[data-theme="night"] .burger-text {
  color: var(--muted);
}
:root[data-theme="night"] .burger:hover .burger-text { color: var(--text); }
:root[data-theme="night"] .match-clock {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.06);
}
:root[data-theme="night"] .mc-drain { background: rgba(255, 255, 255, 0.07); }
:root[data-theme="night"] .ko-pip { background: rgba(255, 255, 255, 0.07); }
/* Yours lights in your colour, theirs in theirs — same rule as the board rim. */
:root[data-theme="night"] .sb-you .ko-pip.on {
  background: var(--side-you);
  border-color: var(--side-you);
  box-shadow: 0 0 9px color-mix(in srgb, var(--side-you) 70%, transparent);
}
:root[data-theme="night"] .sb-opp .ko-pip.on {
  background: var(--side-them);
  border-color: var(--side-them);
  box-shadow: 0 0 9px color-mix(in srgb, var(--side-them) 70%, transparent);
}
:root[data-theme="night"] .ko-flash {
  color: var(--danger);
  text-shadow: 0 0 26px rgba(255, 84, 112, 0.7);
}

/* ── light-surface accents ──────────────────────────────────────────────── */
/* .lb-plain only: the ranked boards colour their own values from the rank ramp
   below, and a blanket .lb-val rule here was repainting every score in one
   magenta and taking the bottom half of the ramp with it. "Your bests" has no
   ranking and does still want the accent ink. */
:root[data-theme="arcade"] .lb-plain .lb-val,
:root[data-theme="arcade"] .pz-goal,
:root[data-theme="arcade"] .modal-card .room-code,
:root[data-theme="arcade"] .spec-toast,
:root[data-theme="arcade"] .lvl-num,
:root[data-theme="arcade"] .lvl-pop-num { color: var(--accent-ink); }
/* The level-up banner is the same cream pod as the results card, so it takes
   the same treatment: the cyan glow is tuned for a scrim over the playfield
   and only smears here. The card keeps its shape from the lip instead. */
:root[data-theme="arcade"] .lvl-pop {
  border: 3px solid var(--btn-lip);
  box-shadow: 0 12px 34px rgba(12, 33, 38, 0.28);
}
:root[data-theme="arcade"] .lvl-pop-num { text-shadow: none; }
:root[data-theme="arcade"] .lb-col h4 { color: #266775; }
/* The headline clips a gradient of --accent/--accent-2 to its own glyphs, which
   out here are the shell's two pinks: 1.4:1 and 1.8:1 against the near-white
   menu card, i.e. a title nobody can read. Same treatment the theme's other
   clipped headings get — the gradient cleared, the ink put back — and the ink is
   the one this palette keeps for light surfaces. */
:root[data-theme="arcade"] .lb-headline {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--accent-ink);
}
:root[data-theme="arcade"] .modal-card h2 {
  text-transform: uppercase;
  color: #10323a;
}
:root[data-theme="arcade"] .modal-card { border: 3px solid var(--btn-lip); }
/* The results card is cream, not board-dark, so it can't take the bright
   overlay colours — those are tuned to sit on a scrim over the playfield and
   wash out here. Deeper ink of the same two hues instead. */
:root[data-theme="arcade"] .modal-card.sz-res-card.win .sz-res-title { color: #0d7a47; }
:root[data-theme="arcade"] .modal-card.sz-res-card.lose .sz-res-title { color: #b3261e; }
:root[data-theme="arcade"] .netline .chip,
:root[data-theme="arcade"] .controls-hint kbd {
  background: #e0f0f3;
  border: 1.5px solid rgba(12, 33, 38, 0.4);
  color: #1f5d6b;
  font-weight: 700;
}
:root[data-theme="arcade"] .chat-head { background: #cae6ec; }
:root[data-theme="arcade"] .chat { border: 2px solid var(--btn-lip); }
:root[data-theme="arcade"] .chat-msg.mine .txt {
  background: linear-gradient(180deg, #ffa2cc, #f964a7);
  color: #3d0a22;
  font-weight: 600;
}
/* The specials panel is mounted inside the rig's side column, so it has to be
   another pod — a cream card there reads as a hole in the moulding. */
:root[data-theme="arcade"] .side .spec-bar {
  background: var(--pod);
  border: 2px solid var(--shell-edge);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.26);
}
:root[data-theme="arcade"] .side .spec-meter {
  background: #14181d;
  border: 1px solid var(--shell-edge);
}
:root[data-theme="arcade"] .spec-slot {
  background: linear-gradient(180deg, #2f363e, #171b20);
  border: 2px solid var(--shell-edge);
  color: var(--shell-ink);
}
:root[data-theme="arcade"] .spec-slot.ready {
  border-color: var(--gold);
  background: linear-gradient(180deg, #4a4227, #2a2415);
}
:root[data-theme="arcade"] .spec-slot .sk { color: var(--shell-muted); }
/* The floating toast is over the field, not in the rig, so it stays cream. */
:root[data-theme="arcade"] .side .spec-toast { border: 2px solid var(--btn-lip); }


/* ╔═════════════════════════════════════════════════════════════════════════╗
   ║ NIGHT MATCH — the option.                                               ║
   ║                                                                         ║
   ║ Dark, but committed instead of hedged. One accent per side — yours mint, ║
   ║ theirs coral — carried through the board's rim light, the nameplate and  ║
   ║ the garbage meter, so you never lose track of whose stack is whose.      ║
   ║ Condensed uppercase labels, tabular figures, and no gradients anywhere.  ║
   ╚═════════════════════════════════════════════════════════════════════════╝ */
:root[data-theme="night"] {
  --bg: #0a0c12;
  --bg-image:
    radial-gradient(900px 520px at 50% -12%, #1d2440, transparent),
    repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.014) 0 1px, transparent 1px 44px);

  --panel: linear-gradient(180deg, #141926, #0d111b);
  --panel-2: rgba(255, 255, 255, 0.045);
  --panel-3: rgba(255, 255, 255, 0.085);
  --well: #070910;
  --board: #070910;

  --text: #eef1f6;
  --muted: #7f8798;
  --accent: #3ddc97;
  --accent-2: #35c6e8;
  --accent-3: #b96ae8;
  --on-accent: #05130c;
  --accent-ink: #3ddc97;

  --danger: #ff5470;
  --danger-2: #6d1526;
  --warn: #e8bd2e;
  --gold: #e8bd2e;
  --ok: #3ddc97;

  --border: rgba(255, 255, 255, 0.07);
  --border-hover: rgba(255, 255, 255, 0.18);
  --scrim: rgba(6, 8, 14, 0.84);
  --scrim-modal: rgba(4, 6, 12, 0.76);
  --shadow-panel: 0 24px 44px rgba(0, 0, 0, 0.55);

  /* Condensed sans was this theme's display face until the arcade face became
     the site's; see the note in the arcade block above. */
  --display-transform: uppercase;

  --side-you: #3ddc97;
  --side-them: #ff5470;
  --side: var(--side-you);
  /* The rank ramp against a nearly black card. Brighter than classic's, and
     pulled apart at the ends on purpose: this palette's --ok and --accent are
     the same green, which would have finished the ramp where it started. */
  --rank-1: #4ade80;
  --rank-2: #eef1f6;
  --rank-3: #c3cad6;
  --rank-4: #e8bd2e;
  --rank-5: #f0a52b;
  --rank-6: #f58b3c;
  --rank-7: #ff5470;
  --rank-8: #b96ae8;
  --rank-9: #f07ad0;
  --rank-10: #35c6e8;
}

:root[data-theme="night"] h1 {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--text);
  /* Fluid for the same reason as the base rule: ten fixed-width capitals. */
  font-size: clamp(1.55rem, 6.5vw, 2.5rem);
}
/* A short mint rule instead of a gradient fill — the accent is spent on one
   mark rather than smeared across the wordmark. */
:root[data-theme="night"] h1::after {
  content: "";
  display: block;
  width: 56px;
  height: 3px;
  margin: 10px auto 0;
  border-radius: 2px;
  background: var(--accent);
}

:root[data-theme="night"] #menu { border-radius: 12px; }
:root[data-theme="night"] #mascot {
  filter: drop-shadow(0 6px 18px rgba(61, 220, 151, 0.22));
}
:root[data-theme="night"] button { border-radius: 7px; }
:root[data-theme="night"] button:hover {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: rgba(61, 220, 151, 0.09);
}
:root[data-theme="night"] button.primary {
  text-transform: uppercase;
  background: var(--accent);
  color: var(--on-accent);
}
:root[data-theme="night"] button.primary:hover { filter: brightness(1.08); }
:root[data-theme="night"] .name-input,
:root[data-theme="night"] .join-row input { border-radius: 7px; }

/* ── per-side identity ──────────────────────────────────────────────────── */
:root[data-theme="night"] .player {
  position: relative;
  border-radius: 12px;
  --side: var(--side-them);
}
:root[data-theme="night"] .player.mine { --side: var(--side-you); }
/* A single hairline of the side's colour along the top of the rig. */
:root[data-theme="night"] .player::before {
  content: "";
  position: absolute;
  left: 14px;
  right: 14px;
  top: 0;
  height: 2px;
  border-radius: 0 0 3px 3px;
  background: var(--side);
}
/* The rim light is the whole point of the per-side colour, so it has to be
   visible without lighting up the stack next to it: a hard 1px edge plus a
   short, low glow. */
:root[data-theme="night"] canvas.board {
  border-radius: 4px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--side) 62%, transparent),
    0 0 18px -4px color-mix(in srgb, var(--side) 45%, transparent);
}
:root[data-theme="night"] .name-tag {
  text-transform: uppercase;
  color: var(--side);
  /* A hairline under the name separates it from the well without adding a
     second panel — the rig is already one flat surface here. */
  padding-bottom: 7px;
  margin-bottom: 10px;
  border-bottom: 1px solid color-mix(in srgb, var(--side) 22%, transparent);
}
:root[data-theme="night"] .slot { border-radius: 8px; }
:root[data-theme="night"] .garbage-meter .fill {
  background: linear-gradient(180deg, var(--side), color-mix(in srgb, var(--side) 45%, #000));
}
:root[data-theme="night"] .burger:hover span { background: var(--accent); }

/* ── in-play callouts: solid colour, no gradient clipping ──────────────── */
:root[data-theme="night"] .combo-indicator .c,
:root[data-theme="night"] .combo-indicator .b,
:root[data-theme="night"] .clear-popup .pl {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  text-transform: uppercase;
}
:root[data-theme="night"] .combo-indicator .c {
  color: var(--accent);
  filter: drop-shadow(0 0 12px rgba(61, 220, 151, 0.55));
}
:root[data-theme="night"] .combo-indicator .b {
  color: var(--gold);
  filter: drop-shadow(0 0 12px rgba(232, 189, 46, 0.5));
}
:root[data-theme="night"] .clear-popup .pl {
  color: var(--text);
  filter: drop-shadow(0 0 16px rgba(61, 220, 151, 0.45));
}
:root[data-theme="night"] .clear-popup .pp { color: var(--gold); }
:root[data-theme="night"] .countdown span {
  text-shadow: 0 0 30px rgba(61, 220, 151, 0.55), 0 6px 24px rgba(0, 0, 0, 0.6);
}
:root[data-theme="night"] .countdown span.go {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--accent);
}
:root[data-theme="night"] .overlay .big {
  text-transform: uppercase;
}
:root[data-theme="night"] .overlay .ov-btn {
  background: var(--accent);
  color: var(--on-accent);
  text-transform: uppercase;
}
:root[data-theme="night"] .chat-msg.mine .txt {
  background: var(--accent);
  color: var(--on-accent);
}
:root[data-theme="night"] .spec-meter-fill { background: var(--accent); }
:root[data-theme="night"] .modal-card h2 {
  text-transform: uppercase;
}
/* No .lb-col h4 rule here on purpose. This theme puts its labels in condensed
   uppercase with 0.14em of tracking, and the board headings used to take that
   too — but the leaderboard is one component set in one bitmap face now, at a
   size (9px) picked for that face and paired with an 18px sprite. A condensed
   sans at 9px is a smaller, blurrier heading, and the tracking is spacing the
   scoreboard face already carries inside every glyph. */


/* ── settings dialog: controls that are <button> but must not look like one ──
   The theme's button skin is a broad `button` selector, so the close ✕ and the
   pill toggles have to opt back out of the face-and-lip treatment. ───────── */
:root[data-theme="arcade"] .sz-close-btn {
  background: none;
  border: none;
  box-shadow: none;
  color: #266775;
}
:root[data-theme="arcade"] .sz-close-btn:hover {
  background: var(--panel-3);
  color: #10323a;
  transform: none;
  box-shadow: none;
}
:root[data-theme="arcade"] .sz-toggle,
:root[data-theme="night"] .sz-toggle { border-radius: 999px; padding: 0; }
:root[data-theme="arcade"] .sz-toggle {
  background: #cce5eb;
  border: 2px solid var(--btn-lip);
  box-shadow: inset 0 2px 3px rgba(12, 33, 38, 0.28);
  /* A 2px border takes 2px off the box the knob moves in, and the knob here
     also wears a 1.5px keyline ring (below) that has to clear the inside of
     that border. 14px in a 3px gap leaves the ring 1.5px all round — the same
     above and below as to the sides. The default 18px left it nothing, so the
     ring came out clipped flat against the inside of the track. */
  --sz-knob: 14px;
  --sz-knob-gap: 3px;
}
:root[data-theme="arcade"] .sz-toggle:hover {
  background: #bcdce3;
  transform: none;
  box-shadow: inset 0 2px 3px rgba(12, 33, 38, 0.28);
}
:root[data-theme="arcade"] .sz-toggle:active { transform: none; }
:root[data-theme="arcade"] .sz-toggle.on {
  background: linear-gradient(180deg, #ffa2cc, #fa5ba3);
  border-color: var(--btn-lip);
}
:root[data-theme="arcade"] .sz-toggle::after {
  box-shadow: 0 0 0 1.5px var(--btn-lip);
}
/* Sliders as one more moulded part: a recessed cream channel with the same
   hard keyline as the toggles, and a gold cap for the thumb. The shared rules
   in style.css give it the shape and the --sz-fill gradient; this only
   restates the surfaces.
   The -webkit- and -moz- track rules are kept apart on purpose: a selector
   list is thrown out whole by any browser that doesn't know one of its
   selectors, so grouping them means neither engine applies either. */
:root[data-theme="arcade"] .modal-card input[type="range"]::-webkit-slider-runnable-track {
  height: 9px;
  border: 2px solid var(--btn-lip);
  background: linear-gradient(
    90deg,
    #fa5ba3 var(--sz-fill, 50%),
    #cce5eb var(--sz-fill, 50%)
  );
  box-shadow: inset 0 2px 3px rgba(12, 33, 38, 0.28);
}
:root[data-theme="arcade"] .modal-card input[type="range"]::-moz-range-track {
  height: 9px;
  border: 2px solid var(--btn-lip);
  background: linear-gradient(
    90deg,
    #fa5ba3 var(--sz-fill, 50%),
    #cce5eb var(--sz-fill, 50%)
  );
  box-shadow: inset 0 2px 3px rgba(12, 33, 38, 0.28);
}
:root[data-theme="arcade"] .modal-card input[type="range"]::-webkit-slider-thumb {
  width: 17px;
  height: 17px;
  /* Restated because both terms changed: 9/2 - 2 - 17/2. See the base rule in
     style.css for why the border is in there. */
  margin-top: -6px;
  border: 2px solid var(--btn-lip);
  background: linear-gradient(180deg, #ffacd2, #fa5ba3);
  box-shadow: 0 1px 0 rgba(12, 33, 38, 0.45);
}
:root[data-theme="arcade"] .modal-card input[type="range"]::-moz-range-thumb {
  width: 17px;
  height: 17px;
  border: 2px solid var(--btn-lip);
  background: linear-gradient(180deg, #ffacd2, #fa5ba3);
}

/* Selected theme: filled, not just outlined — an outline alone is easy to miss
   against a button that already has a hard border. */
.sz-theme-opt .sz-theme-minos i { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35); }
:root[data-theme="arcade"] .sz-theme-opt[aria-pressed="true"] {
  background: #ff8fc1;
  box-shadow: 4px 4px 0 0 var(--btn-lip), inset 0 0 0 2px rgba(255, 255, 255, 0.5);
}
:root[data-theme="night"] .sz-theme-opt[aria-pressed="true"] {
  background: rgba(61, 220, 151, 0.12);
  border-color: var(--accent);
}

/* ── shared: a focus ring that is visible on both grounds ───────────────── */
:root[data-theme] button:focus-visible,
:root[data-theme] input:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 80%, #fff);
  outline-offset: 2px;
}

/* ── theme picker in the settings dialog (built by settings.js) ─────────── */
.sz-theme-row { display: flex; gap: 8px; margin: 2px 0 4px; }
.sz-theme-opt {
  flex: 1;
  display: grid;
  gap: 6px;
  justify-items: stretch;
  text-align: left;
  padding: 9px 10px;
}
.sz-theme-opt .sz-theme-name { font-size: 13px; }
.sz-theme-opt .sz-theme-minos { display: flex; gap: 3px; }
.sz-theme-opt .sz-theme-minos i {
  flex: 1;
  height: 10px;
  border-radius: 2px;
}
.sz-theme-opt[aria-pressed="true"] {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
/* ── the deck's mark ───────────────────────────────────────────────────────
   A crest and a wordmark that happen to be pressable — it goes home, the same
   as the menu key. Both themes skin every <button> with a face, a lip and a
   shadow, so like .linkish below it has to opt back out here, or the marquee
   end grows a second key opposite the real one. */
:root[data-theme="arcade"] .deck-mark,
:root[data-theme="night"] .deck-mark {
  background: none;
  border: none;
  box-shadow: none;
}
:root[data-theme="arcade"] .deck-mark:hover,
:root[data-theme="night"] .deck-mark:hover {
  background: none;
  border-color: transparent;
  box-shadow: none;
  transform: none;
}
:root[data-theme="arcade"] .deck-mark:active,
:root[data-theme="night"] .deck-mark:active {
  transform: none;
  box-shadow: none;
}
/* What is left as the press: the crest takes the travel the key would have. */
:root[data-theme="arcade"] .deck-mark:active .deck-crest,
:root[data-theme="night"] .deck-mark:active .deck-crest { transform: translateY(1px); }

/* ── link-shaped buttons ───────────────────────────────────────────────────
   A <button> that is a link in a sentence, not a control to press: the guest
   note under the name box, and the ad panel's "already ad-free?" row. Both
   themes give every button a face, a lip and a drop shadow, and those rules
   are specific enough to beat a bare .linkish in style.css — so the opt-out
   has to live here, next to what it is opting out of. */
:root[data-theme="arcade"] .linkish,
:root[data-theme="night"] .linkish {
  border: none;
  border-radius: 0;
  background: none;
  box-shadow: none;
  /* --accent-ink, not --accent: on arcade's near-white panel the accent is a
     pale pink that a link cannot be read in. Night defines the two the same,
     so the shared rule stays shared. */
  color: var(--accent-ink);
  font-weight: inherit;
  padding: 0;
  text-decoration: underline;
}
:root[data-theme="arcade"] .linkish:hover,
:root[data-theme="night"] .linkish:hover {
  background: none;
  border-color: transparent;
  box-shadow: none;
  transform: none;
  filter: brightness(1.15);
}

/* ── the gamepad cursor, where pale pink cannot hold a white ground ──────── */
/* Same trade as .bs-map.on above: arcade's --accent is the shell's own pink and
   disappears against it, so the cursor borrows the ink weight instead. */
:root[data-theme="arcade"] .sz-nav-cursor {
  /* A shade thicker here too: arcade's buttons are chunky and sit on a pale
     shell, and a 3px ring reads as a hairline next to a 4px button lip. */
  outline: 4px solid var(--accent-ink);
  animation-name: sz-nav-pulse-ink;
}
@keyframes sz-nav-pulse-ink {
  50% { outline-color: color-mix(in srgb, var(--accent-ink) 40%, transparent); }
}
