/* ─────────────────────────────────────────────
   maybaah.github.io design system
   Minimal. Confident. Dark-first. No noise.
   ───────────────────────────────────────────── */

/* The default grey ramp is shadcn's zinc scale, written as hex because every
   other token in this file is. Lightness steps are theirs: 0.141 base, 0.21
   surface, 0.274 elevated, 0.552 muted text, 0.705 secondary text, 0.92 accent.
   Borders are white at low alpha rather than a fixed grey, so a line stays
   visible whichever surface it lands on. */
:root {
  color-scheme: dark;

  --bg-base: #09090b;
  --bg-surface: #18181b;
  --bg-elevated: #27272a;
  --bg-overlay: #3f3f46;

  --border: rgba(255, 255, 255, 0.10);
  --border-subtle: rgba(255, 255, 255, 0.06);
  --border-focus: rgba(255, 255, 255, 0.18);

  --text-primary: #fafafa;
  --text-secondary: #a1a1aa;
  /* ornament only: this measures 4.12:1 on the base, under AA, so nothing
     a reader reads may use it. Reading text takes --text-secondary. */
  --text-muted: #71717a;

  --accent: #e4e4e7;
  --accent-hover: #fafafa;
  --accent-ink: #18181b;
  --danger: #fb6a69;
  --success: #4ade80;
  --warning: #fbbf24;

  --nav-bg: rgba(9, 9, 11, 0.85);

  --font-sans: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "Cascadia Code", Consolas, monospace;

  --radius-sm: 6px;
  --radius-md: 8px;
  --radius: 10px;
  --radius-lg: 14px;
  --container: 1040px;

  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.28);
  --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.34), 0 1px 2px -1px rgba(0, 0, 0, 0.34);
}

/* ── themes ──────────────────────────────────────────────────────────────
   Bought in /shop/ with arcade coins and applied by arcade.js, which stamps
   data-theme on <html> before anything paints. Every one of them is the same
   design system with different tokens: nothing below this block knows which
   theme is on. */

[data-theme="ember"] {
  --bg-base: #0c0a09;
  --bg-surface: #14100e;
  --bg-elevated: #1e1815;
  --bg-overlay: #26201c;
  --border: #302722;
  --border-subtle: #221c18;
  --border-focus: rgba(255, 200, 150, 0.18);
  --text-primary: #f5efe9;
  --text-secondary: #9a8b7f;
  --text-muted: #635749;
  --accent: #f0a24a;
  --accent-hover: #ffb865;
  --accent-ink: #1a1005;
  --nav-bg: rgba(12, 10, 9, 0.85);
}

[data-theme="forest"] {
  --bg-base: #070c09;
  --bg-surface: #0d140f;
  --bg-elevated: #141d17;
  --bg-overlay: #1b261e;
  --border: #22302a;
  --border-subtle: #17211b;
  --border-focus: rgba(150, 255, 200, 0.18);
  --text-primary: #eaf3ec;
  --text-secondary: #7f9a89;
  --text-muted: #4e6357;
  --accent: #6ee7a8;
  --accent-hover: #8ff7c0;
  --accent-ink: #04150c;
  --nav-bg: rgba(7, 12, 9, 0.85);
}

[data-theme="ultraviolet"] {
  --bg-base: #0a0812;
  --bg-surface: #110e1c;
  --bg-elevated: #191428;
  --bg-overlay: #221b34;
  --border: #2c2442;
  --border-subtle: #1d1830;
  --border-focus: rgba(200, 170, 255, 0.2);
  --text-primary: #efeafb;
  --text-secondary: #948aae;
  --text-muted: #5f5680;
  --accent: #c4a2ff;
  --accent-hover: #d9c0ff;
  --accent-ink: #10061f;
  --nav-bg: rgba(10, 8, 18, 0.85);
}

[data-theme="neon"] {
  --bg-base: #050a10;
  --bg-surface: #0a1119;
  --bg-elevated: #101a25;
  --bg-overlay: #16232f;
  --border: #1e3040;
  --border-subtle: #14202c;
  --border-focus: rgba(94, 242, 224, 0.24);
  --text-primary: #e6f6ff;
  --text-secondary: #7f9cb0;
  --text-muted: #4e6b7d;
  --accent: #5ef2e0;
  --accent-hover: #8dfff1;
  --accent-ink: #02141a;
  --nav-bg: rgba(5, 10, 16, 0.85);
}

/* The one light theme. Cabinets that paint their own board stay dark inside
   their frame, the way a screen does in a lit room. */
[data-theme="paper"] {
  color-scheme: light;

  --bg-base: #f6f5f2;
  --bg-surface: #ffffff;
  --bg-elevated: #eeece7;
  --bg-overlay: #e4e1da;
  --border: #d9d5cc;
  --border-subtle: #e7e4dd;
  --border-focus: rgba(0, 0, 0, 0.24);
  --text-primary: #17150f;
  --text-secondary: #5f5a50;
  --text-muted: #6f6a5e;
  --accent: #1c1a15;
  --accent-hover: #000000;
  --accent-ink: #f8f7f4;
  --danger: #b91c1c;
  --success: #15803d;
  --warning: #b45309;
  --nav-bg: rgba(246, 245, 242, 0.85);

  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.10), 0 1px 2px -1px rgba(0, 0, 0, 0.10);
}

/* ── shadcn names ──────────────────────────────────────────────────────────
   The same tokens under the names shadcn/ui uses, so component CSS lifted from
   there drops in unchanged. These are aliases, not a second palette: var()
   resolves on <html>, which is also where data-theme lands, so a theme that
   moves --bg-surface moves --card with it and nothing here needs repeating per
   theme. Note --accent is ours (the bright primary fill) and theirs is a muted
   hover surface, so their name for ours is --primary. */
:root {
  --background: var(--bg-base);
  --foreground: var(--text-primary);
  --card: var(--bg-surface);
  --card-foreground: var(--text-primary);
  --popover: var(--bg-surface);
  --popover-foreground: var(--text-primary);
  --primary: var(--accent);
  --primary-foreground: var(--accent-ink);
  --secondary: var(--bg-elevated);
  --secondary-foreground: var(--text-primary);
  --muted: var(--bg-elevated);
  --muted-foreground: var(--text-secondary);
  --destructive: var(--danger);
  --input: var(--border-focus);
  --ring: var(--text-muted);
}

/* ── reset ── */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
img, svg { max-width: 100%; display: block; }
h1, h2, h3, h4, p { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; padding: 0; }

:focus-visible {
  outline: 2px solid var(--accent-hover);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
::selection { background: var(--bg-overlay); color: var(--text-primary); }

/* ── layout ── */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 24px;
}
main { flex: 1; }
.section { padding-block: 72px; }
.section + .section { padding-top: 0; }

/* ── type scale ── */
h1 { font-size: clamp(32px, 6vw, 48px); font-weight: 600; line-height: 1.1; letter-spacing: -0.02em; }
h2 { font-size: 24px; font-weight: 600; letter-spacing: -0.01em; }
h3 { font-size: 16px; font-weight: 600; }
.lead { font-size: 18px; color: var(--text-secondary); }
.mono { font-family: var(--font-mono); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--text-secondary);
}

/* ── nav ── */
.site-nav {
  border-bottom: 1px solid var(--border-subtle);
  background: var(--nav-bg);
  backdrop-filter: blur(12px);
  position: sticky;
  top: 0;
  z-index: 50;
}
.site-nav .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
  gap: 16px;
}
.wordmark {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.wordmark .tld { color: var(--text-secondary); font-weight: 400; }
.wordmark { flex: none; }
/* The row scrolls rather than the page: a narrow phone with the coin chip and
   four links in the nav used to push the whole document sideways. */
.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.nav-links::-webkit-scrollbar { width: 0; height: 0; }
.nav-links > * { flex: none; }
.nav-links a {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  transition: color 150ms ease, background 150ms ease;
}
.nav-links a:hover { color: var(--text-primary); background: var(--bg-elevated); }
.nav-links a[aria-current="page"] { color: var(--text-primary); }

/* ── the coin chip ──
   arcade.js puts this in front of the nav links on every page that has a nav,
   so a wallet does not have to be pasted into ten heads. */
.nav-links .coin-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  padding: 4px 11px;
  margin-right: 4px;
  border: 1px solid var(--border);
  border-radius: 999px;
}
.nav-links .coin-chip:hover { background: transparent; border-color: var(--border-focus); }
.coin-chip .coin {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  background: var(--warning);
  box-shadow: inset 0 0 0 1.5px rgba(0, 0, 0, 0.35);
}
.coin-toast {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  pointer-events: none;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 16px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--warning);
  animation: coin-rise 2600ms ease forwards;
}
@keyframes coin-rise {
  0% { opacity: 0; transform: translateY(8px); }
  8% { opacity: 1; transform: translateY(0); }
  85% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-6px); }
}

/* ── buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
  padding: 9px 18px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease, transform 150ms ease;
  white-space: nowrap;
}
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-secondary { border-color: var(--border); color: var(--text-primary); }
.btn-secondary:hover { border-color: var(--border-focus); background: var(--bg-elevated); }
.btn-ghost { color: var(--text-secondary); }
.btn-ghost:hover { background: var(--bg-elevated); color: var(--text-primary); }
.btn-sm { padding: 6px 12px; font-size: 13px; }
.btn:disabled { opacity: 0.45; cursor: default; }
.btn-secondary:disabled:hover { border-color: var(--border); background: none; }

/* ── badges ── */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 10px;
}
.badge .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  flex: none;
}
.badge .dot.off { background: var(--text-muted); }
.badge .dot.warn { background: var(--warning); }
.badge-secondary { background: var(--bg-elevated); border-color: transparent; color: var(--text-primary); }

/* ── separator ── */
.separator { height: 1px; border: 0; margin: 0; background: var(--border-subtle); }

/* ── cards ──
   Header, content and footer are separate slots so a card can hold prose or a
   list of rows without either one guessing at the other's padding. .flush
   hands the padding to the slots, which is what lets a row reach the edge and
   still light up across the whole card on hover. */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px;
  box-shadow: var(--shadow-xs);
}
.card-header { display: grid; grid-template-columns: 1fr; gap: 6px; align-items: start; }
.card-header:has(.card-action) { grid-template-columns: 1fr auto; }
.card-title { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
.card-description { color: var(--text-secondary); font-size: 14px; }
.card-action { grid-column: 2; grid-row: 1 / span 2; justify-self: end; align-self: start; }
.card-footer { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.card.flush { padding: 0; }
.card.flush > .card-header { padding: 22px 22px 18px; }
.card.flush > .card-footer {
  padding: 14px 22px;
  border-top: 1px solid var(--border-subtle);
  font-size: 13px;
  color: var(--text-secondary);
}

/* ── row list ── */
.row-list { display: flex; flex-direction: column; border-top: 1px solid var(--border-subtle); }
.row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 2px 16px;
  padding: 14px 22px;
  border-bottom: 1px solid var(--border-subtle);
  transition: background 150ms ease;
}
.row:last-child { border-bottom: 0; }
a.row:hover { background: var(--bg-elevated); }
.row-title { font-size: 14px; font-weight: 500; }
.row-desc { grid-column: 1; grid-row: 2; font-size: 13px; color: var(--text-secondary); }
/* Labels sit on the secondary step, not the muted one: at 11px the muted grey
   lands under 4.5:1 on a card. Size, case and tracking carry the hierarchy
   instead, which is how shadcn separates a label from body copy. */
.row-meta {
  grid-row: 1 / span 2;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.row .arrow { grid-row: 1 / span 2; color: var(--text-muted); transition: transform 150ms ease, color 150ms ease; }
a.row:hover .arrow { transform: translateX(3px); color: var(--text-primary); }

/* ── field list ── */
.field-list { margin: 0; }
.field {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 4px 16px;
  align-items: baseline;
  padding: 13px 0;
  border-bottom: 1px solid var(--border-subtle);
}
.field:first-child { padding-top: 0; }
.field:last-child { padding-bottom: 0; border-bottom: 0; }
.field dt {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-secondary);
}
.field dd { margin: 0; font-size: 14px; font-family: var(--font-mono); }
.field dd a { border-bottom: 1px solid var(--border); transition: border-color 150ms ease; }
.field dd a:hover { border-bottom-color: var(--text-secondary); }

/* ── stack strip ── */
.stack-strip { display: flex; flex-wrap: wrap; gap: 8px; }
.stack-strip span {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 5px 10px;
}

/* ── game cards (arcade) ── */
.game-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 16px;
}
.game-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px;
  transition: border-color 150ms ease, background 150ms ease;
}
.game-card:hover { border-color: var(--border-focus); background: var(--bg-elevated); }
.game-card header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.game-card h3 { font-size: 18px; }
.game-card .desc { color: var(--text-secondary); font-size: 14px; flex: 1; }
/* ── hover card ──
   A card's numbers are the least of what it has to say and they were sitting
   in the middle of every one of them. They live in here now, opened by the
   trigger in the action row.

   On hover and on focus, not hover alone: a hover-only panel is unreachable
   by keyboard and does not exist on a phone. :focus-within covers both, since
   tapping the trigger focuses it, and that is also why this needs no script.
   The panel is inert rather than absent between times, so the ids inside it
   stay findable by the page's own getElementById. */
.hovercard { position: relative; display: inline-flex; flex: none; }
/* The trigger takes the slot the status badge used to hold, so it is the badge
   shape with the manners of a button: the old one was a green dot reporting a
   liveness nothing measured, and it read the same on eleven of thirteen cards. */
.badge-trigger {
  cursor: pointer;
  transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
}
.badge-trigger::after {
  content: "";
  width: 5px;
  height: 5px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-1px) rotate(45deg);
  transition: transform 150ms ease;
}
.hovercard:hover .badge-trigger,
.hovercard:focus-within .badge-trigger {
  color: var(--text-primary);
  border-color: var(--border-focus);
  background: var(--bg-elevated);
}
.hovercard:hover .badge-trigger::after,
.hovercard:focus-within .badge-trigger::after { transform: translateY(-3px) rotate(225deg); }

/* Opens downward: the trigger sits in the card's head, and a panel above it
   would hang over the card in the row before. */
.hovercard-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 60;
  min-width: 208px;
  padding: 12px 14px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 130ms ease, transform 130ms ease, visibility 130ms;
}
.hovercard:hover .hovercard-panel,
.hovercard:focus-within .hovercard-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* The label is words, so it is set in the sans face; the value is a number,
   which is the only thing the mono face is for, and tabular figures keep a
   column of times from stepping about. */
.hovercard-panel dl {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 18px;
  font-size: 12px;
}
.hovercard-panel dt { color: var(--text-secondary); white-space: nowrap; }
.hovercard-panel dd {
  margin: 0;
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.game-card .actions { display: flex; gap: 8px; align-items: center; }
.game-card.soon { border-style: dashed; opacity: 0.75; }
.game-card.soon:hover { background: var(--bg-surface); }

/* ── the cabinet shell ──
   Every game page is the same frame: a centred column, a head carrying the
   cabinet number and its mode pills, a row of counters, the board, and a
   toolbar under it. This lived in twelve <style> blocks and drifted, so a
   cabinet now sets --wrap for how wide its board wants to be and inherits the
   rest. */
.game-wrap {
  --wrap: 520px;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 24px;
}
.game-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 40px;
}
.game-head h1 { font-size: 28px; margin-top: 6px; }

/* Pills that pick a variant. Inside the head they sit beside the title; a
   cabinet with too many of them to fit puts the group under the head instead
   and picks up the gap from the sibling rule. */
.mode-pills { display: flex; gap: 6px; flex-wrap: wrap; }
.game-head + .mode-pills { margin-top: 18px; }

/* Counters, in the two shapes a cabinet uses: boxed totals beside the title,
   or a mono strip under it with the toggles pushed to the right by .spacer. */
.score-row { display: flex; gap: 10px; }
.score-box {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  padding: 8px 16px;
  text-align: center;
  min-width: var(--score-w, 88px);
}
.score-box label {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-secondary);
}
/* Tabular figures so a counter ticking 9 to 10 does not widen the box and
   shove the row beside it. */
.score-box span {
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.hud {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: 24px;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-secondary);
}
/* Numbers are right aligned in a tabular figure so a ticking clock does not
   shuffle the row sideways; the width of each slot is the cabinet's business. */
.hud b {
  display: inline-block;
  text-align: right;
  color: var(--text-primary);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.hud .spacer { flex: 1; }

.statusline {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 20px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
}
.statusline b { color: var(--text-primary); font-weight: 500; }
/* A refereed game says one sentence here rather than a row of counters, so it
   takes the shape of an alert: a bordered strip that holds its height whether
   or not there is anything to say, because a line appearing under the board
   used to shift the toolbar down mid-game. */
.statusline.solo {
  display: flex;
  align-items: center;
  margin-top: 16px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-surface);
  font-size: 12px;
  color: var(--text-secondary);
  min-height: 40px;
}
.statusline.solo.warn { color: var(--warning); border-color: var(--warning); }

/* The row under the board: the cabinet's own actions first, then Arcade and
   Leaderboard last, in that order on every page. */
.toolbar { display: flex; gap: 8px; margin-top: 20px; flex-wrap: wrap; }

/* ── the board overlay ──
   Ready, paused and game over, in the shape of a dialog: a scrim across the
   board and a panel standing on it, rather than text floating on a blur. Five
   cabinets each carried a copy of this and had already drifted on scrim
   opacity and title size, so it lives here now and a cabinet only decides when
   to add .show. The radius is inherited so the scrim follows whatever corner
   the board it covers happens to have. */
#overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  border-radius: inherit;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(3px);
}
#overlay.show { display: flex; }
/* The scrim is its own dark on every theme, because the board under it is, so
   the panel and its type name their own colours here rather than following the
   site tokens. On the light theme this is still a dark dialog over a dark
   board, which is the point: the cabinet is a screen in a lit room. */
.overlay-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-width: 380px;
  padding: 22px 26px;
  text-align: center;
  background: #18181b;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px -6px rgba(0, 0, 0, 0.6);
}
.overlay-panel h2 {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 600;
  color: #fafafa;
}
.overlay-panel p {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  color: #a1a1aa;
}
.overlay-panel p:empty { display: none; }

/* Name the run, then submit it. Hidden until a run finishes, and shown by each
   game.js setting display, so the base state stays none here. */
.submit-run {
  display: none;
  margin-top: 20px;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.submit-run .run-status { font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary); }

/* ── input ──
   One field shape for every text box on the site. The border, not a fill, is
   what says "type here", so the field reads the same sitting on the page as it
   does inside a panel. */
.input, .submit-run input, .lobby input {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 13px;
  padding: 7px 12px;
  transition: border-color 150ms ease;
}
.input::placeholder, .submit-run input::placeholder, .lobby input::placeholder { color: var(--text-muted); }
.input:focus-visible, .submit-run input:focus-visible, .lobby input:focus-visible { border-color: var(--border-focus); }
.input:disabled, .submit-run input:disabled, .lobby input:disabled { opacity: 0.5; cursor: not-allowed; }
.submit-run input { width: 150px; }

/* ── kbd ── */
.kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-xs);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
}

/* ── the room panel ──
   Create-or-join, the share link and the hint under them, shared by every
   cabinet that seats two people in a room. */
.lobby {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-top: 16px;
}
.lobby-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.lobby input { font-size: 15px; }
.lobby label {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-secondary);
}
.lobby .hint {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
  margin-top: 10px;
  line-height: 1.6;
}
#join-code { letter-spacing: 0.24em; text-transform: uppercase; width: 110px; }
.share { display: flex; gap: 8px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.share code {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  overflow-wrap: anywhere;
}

/* ── the touch pad ──
   One d-pad for every cabinet that needs one, shown only where there is no
   keyboard to reach for. */
.touch-controls { display: none; margin-top: 20px; align-items: center; justify-content: center; gap: 24px; }
.dpad {
  display: none;
  grid-template-columns: repeat(3, 48px);
  grid-template-rows: repeat(3, 48px);
  gap: 6px;
  width: max-content;
  margin-inline: auto;
}
.dpad button {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 16px;
  user-select: none;
  -webkit-user-select: none;
}
.dpad button:active { background: var(--bg-elevated); color: var(--text-primary); }
.dpad .spacer { visibility: hidden; }
@media (hover: none) and (pointer: coarse) {
  .touch-controls { display: flex; }
  .dpad { display: grid; }
}

/* ── tables / leaderboard ── */
.board-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.board-table th {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-secondary);
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}
.board-table td { padding: 10px 12px; border-bottom: 1px solid var(--border-subtle); }
.board-table td.num { font-family: var(--font-mono); font-size: 13px; color: var(--text-secondary); }
.board-table tr:hover td { background: var(--bg-surface); }
.board-table .rank { color: var(--text-secondary); font-family: var(--font-mono); width: 40px; }
.board-table tr.top .rank { color: var(--warning); }

/* ── tabs ── */
.tabs { display: flex; gap: 4px; flex-wrap: wrap; border-bottom: 1px solid var(--border-subtle); padding-bottom: 0; }
.tab {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  padding: 8px 14px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  border-bottom: 2px solid transparent;
  transition: color 150ms ease;
  margin-bottom: -1px;
}
.tab:hover { color: var(--text-primary); }
.tab[aria-selected="true"] { color: var(--text-primary); border-bottom-color: var(--accent); }

/* ── board controls ──
   Shared by /leaderboard/ and the board widget every game page mounts, so these
   live here rather than being copied into each page's own style block. */
/* A group of pills is one segmented control, not a row of loose chips: the
   group carries a sunk track and the pressed pill is the one lifted out of it.
   That reads as a single choice at a glance, which a row of outlined chips
   does not, and it stops a pressed pill shouting in full accent next to the
   Play button. */
.sub-pills, .mode-pills {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
  width: fit-content;
  max-width: 100%;
  padding: 3px;
  background: var(--bg-elevated);
  border-radius: var(--radius);
}
.sub-pills { margin-bottom: 20px; }
.pill {
  font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--text-secondary);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 5px 12px;
  transition: color 150ms ease, border-color 150ms ease, background 150ms ease, box-shadow 150ms ease;
}
.pill:hover { color: var(--text-primary); }
.pill[aria-pressed="true"] {
  color: var(--text-primary);
  background: var(--bg-base);
  border-color: var(--border);
  box-shadow: var(--shadow-xs);
}
.board-meta { font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary); margin-bottom: 14px; }
.you { color: var(--success); font-family: var(--font-mono); font-size: 10px; margin-left: 8px; letter-spacing: 0.1em; }

/* ── the board widget on a game page ── */
.board-embed { margin-top: 40px; }
.board-embed > header {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 14px;
}
.board-embed h2 { font-size: 15px; font-weight: 500; }
.board-embed .full-board { font-family: var(--font-mono); font-size: 11px; color: var(--text-secondary); }
.board-embed .full-board:hover { color: var(--text-primary); }
.board-embed .sub-pills { margin-bottom: 12px; }
/* the page-level .empty is padded for a full-width panel and towers over a
   472px slot, so the embedded one is squatter */
.board-embed .empty { padding: 24px 16px; font-size: 13px; }

/* ── empty state ── */
.empty {
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
  padding: 40px 24px;
  text-align: center;
  color: var(--text-secondary);
  font-size: 14px;
}
.empty .mono { color: var(--text-secondary); font-size: 12px; }

/* ── footer ── */
.site-footer {
  border-top: 1px solid var(--border-subtle);
  margin-top: 72px;
}
.site-footer .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding-block: 28px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-secondary);
}
.site-footer a { color: var(--text-secondary); transition: color 150ms ease; }
.site-footer a:hover { color: var(--text-primary); }
.site-footer .links { display: flex; gap: 16px; flex-wrap: wrap; }

/* ── motion ── */
@keyframes fade-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}
.fade-up {
  opacity: 0;
  animation: fade-up 500ms ease forwards;
  animation-delay: calc(var(--d, 0) * 70ms);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .fade-up { animation: none; opacity: 1; }
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ── responsive ── */
@media (max-width: 640px) {
  .section { padding-block: 48px; }
  .nav-links a { padding: 6px 7px; }
  .row { grid-template-columns: 1fr auto; padding-inline: 18px; }
  .row-meta { display: none; }
  .card.flush > .card-header { padding: 18px 18px 16px; }
  .card.flush > .card-footer { padding: 12px 18px; }
  .field { grid-template-columns: 1fr; gap: 2px; }
}
