/* ─── Reset & tokens ────────────────────────────────────────────── */

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

:root {
  --bg: #0a0a0a;
  --bg-surface: #141414;
  --bg-surface-2: #1a1a1a;
  --text-primary: #e8e0d0;
  --text-secondary: #888;
  --text-dim: #555;
  --accent: #d4a843;
  --accent-soft: rgba(212, 168, 67, 0.12);
  --accent-glow: rgba(212, 168, 67, 0.35);
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);
  --danger: #c87a6a;
  --radius: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --t-fast: 0.15s ease-out;
  --t-med: 0.25s ease-out;
}

html, body { height: 100%; }
html { background: var(--bg); }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: radial-gradient(ellipse at center, #1a1a1a 0%, #0a0a0a 70%);
  color: var(--text-primary);
  min-height: 100%;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overflow-x: hidden;
}

#app { min-height: 100dvh; }

/* ─── Screens ───────────────────────────────────────────────────── */

.screen {
  display: none;
  min-height: 100dvh;
  padding: 4.5rem 1.25rem 2rem;
  padding-left: max(1.25rem, env(safe-area-inset-left));
  padding-right: max(1.25rem, env(safe-area-inset-right));
  padding-bottom: max(2rem, env(safe-area-inset-bottom));
}
.screen.active { display: block; }

.container {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
}
.container-narrow { max-width: 420px; }

.title {
  font-size: 1.75rem;
  letter-spacing: 0.18em;
  color: var(--accent);
  text-align: center;
  margin-bottom: 0.4rem;
}
.subtitle {
  font-size: 0.85rem;
  letter-spacing: 0.05em;
  color: var(--text-secondary);
  text-align: center;
  margin-bottom: 2rem;
}
.form-label {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-top: 0.6rem;
  margin-bottom: -0.2rem;
}
.title { margin-bottom: 1.5rem; }
.screen-title {
  font-size: 1.25rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-primary);
  text-align: center;
  margin-bottom: 0.4rem;
}
.eyebrow {
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  text-align: center;
  margin-bottom: 0.5rem;
}
.eyebrow-lg {
  font-size: 0.85rem;
  letter-spacing: 0.22em;
  margin-bottom: 0.9rem;
}
.hint {
  font-size: 0.78rem;
  color: var(--text-secondary);
  text-align: center;
  margin-bottom: 1.5rem;
}

/* ─── Buttons ───────────────────────────────────────────────────── */

.btn {
  display: inline-block;
  width: 100%;
  padding: 0.85rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: transform var(--t-fast), background var(--t-med), border-color var(--t-med), color var(--t-med);
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary {
  background: var(--accent);
  color: #1a1200;
}
.btn-primary:hover:not(:disabled),
.btn-primary:focus-visible:not(:disabled) {
  background: #e0b95a;
  outline: none;
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border);
  color: var(--text-primary);
}
.btn-secondary:hover:not(:disabled),
.btn-secondary:focus-visible:not(:disabled) {
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.07);
  outline: none;
}

.btn-ghost {
  display: inline-block;
  width: auto;
  padding: 0.4rem 0.7rem;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-secondary);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.btn-ghost:hover, .btn-ghost:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
  outline: none;
}

/* Top-left back/leave button. Matches Auction's pattern: dark blurred
   background so it stays readable even if it sits over game content
   on small screens. The fixed position + safe-area-aware top keeps it
   clear of the iOS notch/status bar. */
.btn-home {
  position: fixed;
  top: max(0.75rem, env(safe-area-inset-top, 0px));
  left: max(0.75rem, env(safe-area-inset-left, 0px));
  padding: 0.45rem 0.75rem;
  color: var(--text-primary);
  background: rgba(10, 10, 10, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: var(--radius);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  text-decoration: none;
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
  z-index: 50;
}
.btn-home:hover, .btn-home:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(10, 10, 10, 0.9);
  outline: none;
}

.hidden { display: none !important; }

/* ─── Form ──────────────────────────────────────────────────────── */

.form { display: flex; flex-direction: column; gap: 0.9rem; }

.input {
  width: 100%;
  padding: 0.85rem 1rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 1rem;
  letter-spacing: 0.02em;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.input::placeholder { color: var(--text-dim); letter-spacing: 0.04em; }
.input:focus {
  outline: none;
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.06);
}

.input-code {
  text-align: center;
  font-size: 1.25rem;
  letter-spacing: 0.6em;
  text-transform: uppercase;
  padding-left: 0.6em;
  flex: 1 1 auto;
  min-width: 0;
}

.divider {
  position: relative;
  text-align: center;
  margin: 0.4rem 0 0.2rem;
  color: var(--text-dim);
  font-size: 0.72rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}
.divider::before, .divider::after {
  content: "";
  position: absolute;
  top: 50%;
  width: calc(50% - 3rem);
  height: 1px;
  background: var(--border);
}
.divider::before { left: 0; }
.divider::after { right: 0; }

.join-row {
  display: flex;
  gap: 0.6rem;
}
.join-row .btn { width: auto; flex: 0 0 auto; padding-left: 1.4rem; padding-right: 1.4rem; }

/* ─── Picker ────────────────────────────────────────────────────── */

/* Landing layout: name + join up top, picker anchored to the bottom
   so the available games are always within thumb reach on a phone. */
.screen.landing {
  display: none;
  padding: 0;
}
.screen.landing.active {
  display: flex;
  flex-direction: column;
}
.landing-inner {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  /* Vertically center the whole landing content rather than pinning
     the tiles to the bottom. The top stack lands roughly in the
     middle, with the picker tiles immediately under it — that puts
     the tiles at ~60% from the top (3rd quadrant) on a phone, which
     keeps them within thumb reach but not glued to the edge. */
  justify-content: center;
  width: 100%;
  max-width: 460px;
  margin: 0 auto;
  padding: 4.5rem 1.25rem 2rem;
  padding-left: max(1.25rem, env(safe-area-inset-left));
  padding-right: max(1.25rem, env(safe-area-inset-right));
  padding-bottom: max(2rem, env(safe-area-inset-bottom));
}
.landing-top { flex: 0 0 auto; }
.landing-bottom {
  /* position:relative anchors the right-edge fade gradient that
     hints "there are more games — scroll" once the tile row
     overflows horizontally. */
  position: relative;
  flex: 0 0 auto;
  padding-top: 2.5rem;
}
.landing-bottom.has-overflow::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0.25rem;
  width: 2rem;
  pointer-events: none;
  background: linear-gradient(to right, rgba(10, 10, 10, 0), rgba(10, 10, 10, 0.85));
  border-top-right-radius: var(--radius-lg);
  border-bottom-right-radius: var(--radius-lg);
}
.landing-bottom-label {
  margin-bottom: 0.7rem;
  text-align: center;
}

/* Horizontal row of game tiles. Tiles share width when ≤3 fit; once
   the catalog grows past that, they keep their min-width and the row
   becomes a snap-scrollable carousel so the design doesn't crunch. */
.picker-list {
  display: flex;
  gap: 0.7rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  /* Hide the scrollbar but keep wheel/touch scroll working. */
  scrollbar-width: none;
  padding-bottom: 0.25rem;
}
.picker-list::-webkit-scrollbar { display: none; }
.picker-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: 1 1 0;
  min-width: 130px;
  scroll-snap-align: start;
  padding: 1rem 0.6rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  color: var(--text-primary);
  cursor: pointer;
  font-family: inherit;
  min-height: 78px;
  transition: transform var(--t-fast), border-color var(--t-med), background var(--t-med);
  position: relative;
}
.picker-tile:hover:not(:disabled),
.picker-tile:focus-visible:not(:disabled) {
  transform: translateY(-1px);
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.05);
  outline: none;
}
.picker-tile:disabled {
  cursor: not-allowed;
  opacity: 0.35;
}
.picker-tile-name {
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  line-height: 1.25;
}
.picker-tile-meta {
  position: absolute;
  bottom: 0.4rem;
  left: 0;
  right: 0;
  font-size: 0.58rem;
  color: var(--text-dim);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.picker-tile-soon { color: var(--accent); opacity: 0.7; }

/* ─── Room ──────────────────────────────────────────────────────── */

/* Room code is itself a tap-to-copy button. Style it so it looks
   like a clickable label rather than a generic button — matches the
   pattern Auction uses (no separate "Copy" button). */
.room-code {
  display: block;
  margin: 0.5rem auto 0.4rem;
  padding: 0.4rem 0.4rem 0.4rem 0.8em;
  background: transparent;
  border: none;
  font-family: inherit;
  font-size: 2rem;
  letter-spacing: 0.4em;
  color: var(--accent);
  text-shadow: 0 0 24px var(--accent-glow);
  font-weight: 700;
  cursor: pointer;
  border-radius: var(--radius);
  transition: text-shadow var(--t-fast), transform var(--t-fast);
}
.room-code:hover, .room-code:focus-visible {
  outline: none;
  text-shadow: 0 0 32px var(--accent-glow);
  transform: scale(1.02);
}
.room-code:active { transform: scale(0.99); }

.people {
  margin: 1.25rem 0 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.people-label {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 0.5rem;
}
.people-count {
  color: var(--text-dim);
  margin-left: 0.4em;
}
.people-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.person {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.92rem;
}
.person.is-host { border-color: var(--accent-soft); }
.person.is-disconnected { opacity: 0.5; }
.person-name { flex: 1 1 auto; }
.person-tag {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 0.2rem 0.45rem;
  border-radius: 4px;
}
.person-tag-self {
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border);
}
.person-tag-mark {
  color: var(--accent);
  background: transparent;
  border: 1px solid var(--accent-soft);
  font-weight: 700;
  letter-spacing: 0.05em;
}
.person-tag-bot {
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-secondary);
  border: 1px solid var(--border);
}
.person-remove {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  width: 26px;
  height: 26px;
  border-radius: 50%;
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.person-remove:hover, .person-remove:focus-visible {
  color: var(--danger);
  border-color: var(--danger);
  outline: none;
}

.room-actions {
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: center;
}
.waiting-msg {
  font-size: 0.78rem;
  color: var(--text-secondary);
  letter-spacing: 0.05em;
  text-align: center;
}

/* ─── Game ──────────────────────────────────────────────────────── */

.game-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  margin-bottom: 1.5rem;
}
.turn-banner {
  font-size: 1rem;
  letter-spacing: 0.05em;
  color: var(--text-primary);
  text-align: center;
  min-height: 1.4em;
}
.turn-banner .accent { color: var(--accent); font-weight: 700; }

.game-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  margin-bottom: 1.75rem;
}

/* ─── Tic-Tac-Toe board ─────────────────────────────────────────── */

.ttt-board {
  position: relative;
  display: grid;
  /* Explicit equal rows so a placed mark can't push its row taller
     than the empty rows. The X glyph is large; without grid-template-rows,
     the row sizes itself to fit content. */
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 0.6rem;
  width: min(86vw, 360px);
  aspect-ratio: 1;
  padding: 0.6rem;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}
.ttt-cell {
  position: relative;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  cursor: pointer;
  transition: background var(--t-med), border-color var(--t-med), transform var(--t-fast);
  padding: 0;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
.ttt-cell:disabled { cursor: default; }
.ttt-cell.is-clickable:hover,
.ttt-cell.is-clickable:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--accent);
  outline: none;
}
.ttt-cell.is-clickable:active { transform: scale(0.97); }

.ttt-mark {
  font-size: clamp(2.6rem, 12vw, 4rem);
  font-weight: 300;
  color: var(--accent);
  line-height: 1;
  display: block;
  user-select: none;
  animation: mark-in 0.18s ease-out;
}
.ttt-mark.is-o { color: var(--text-primary); }

.ttt-cell.is-winning {
  background: var(--accent-soft);
  border-color: var(--accent);
  box-shadow: 0 0 28px -8px var(--accent-glow);
}

/* Winning line — SVG overlay on top of the board. The line is drawn
   in coordinate space 0..3 (one unit per cell), so coordinates
   come straight from cell row/col + 0.5. We animate stroke-dashoffset
   from the line length down to 0 to "draw" it. */
.ttt-winline {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}
.ttt-winline-stroke {
  stroke: var(--accent);
  stroke-linecap: round;
  fill: none;
  filter: drop-shadow(0 0 8px var(--accent-glow));
  stroke-dasharray: var(--len, 400);
  stroke-dashoffset: var(--len, 400);
  animation: draw-winline 0.55s ease-out forwards;
}
@keyframes draw-winline { to { stroke-dashoffset: 0; } }

@keyframes mark-in {
  from { transform: scale(0.6); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}

/* ─── Four in a Row ─────────────────────────────────────────────── */

/* Two distinct token colors: gold (player A, the existing accent)
   and a warm rust (player B). Both share the same chill palette
   the rest of the site uses. */
:root {
  --fr-color-a: var(--accent);
  --fr-color-a-glow: rgba(212, 168, 67, 0.45);
  --fr-color-b: #c87a6a;
  --fr-color-b-glow: rgba(200, 122, 106, 0.5);
}

.is-color-a { color: var(--fr-color-a); }
.is-color-b { color: var(--fr-color-b); }

/* Board: a flat 7×6 grid in row-major order. The previous version
   used a nested column-major grid (.fr-col > .fr-cell × 6), which
   collapsed because the implicit single row sized itself to the
   (zero-content-height) buttons. Going flat eliminates the row-
   sizing puzzle entirely — each cell is a real grid item with
   its own row track from grid-template-rows: repeat(6, 1fr).

   Aspect-ratio 7:6 + width clamp keeps the board proportional and
   centred on every screen size. The panel uses a warm, gold-tinted
   surface (vs the page's near-black) so the dark sockets pop —
   mirroring the strong contrast you'd see on a physical board. */
.fr-board {
  --fr-cols: 7;
  --fr-rows: 6;
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--fr-cols), 1fr);
  grid-template-rows: repeat(var(--fr-rows), 1fr);
  gap: 0.45rem;
  width: min(92vw, 480px);
  aspect-ratio: 7 / 6;
  padding: 0.7rem;
  background:
    linear-gradient(180deg, #2a2418 0%, #1d1a13 100%);
  border: 1px solid rgba(212, 168, 67, 0.18);
  border-radius: var(--radius-xl);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 -2px 4px rgba(0, 0, 0, 0.4),
    0 4px 18px rgba(0, 0, 0, 0.45);
}

.fr-cell {
  position: relative;
  background: #050505;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  min-width: 0;
  min-height: 0;
  cursor: default;
  /* Hard inset shadow so each socket reads as a drilled hole in
     the panel rather than a flat circle. */
  box-shadow:
    inset 0 3px 5px rgba(0, 0, 0, 0.85),
    inset 0 -1px 1px rgba(255, 255, 255, 0.04);
  transition: background var(--t-fast);
}
.fr-cell.is-clickable { cursor: pointer; }
/* Column hover (driven by JS). All cells in the hovered column get
   .is-col-hover; we lift them subtly and add a faint accent tint so
   the column reads as the active drop target. */
.fr-cell.is-col-hover {
  background: #0a0805;
  box-shadow:
    inset 0 3px 5px rgba(0, 0, 0, 0.85),
    inset 0 0 0 2px rgba(212, 168, 67, 0.18);
}

/* Floating preview disc above the hovered column, in the local
   player's color. Position is set in JS via --hover-col so the disc
   tracks the column. */
.fr-board::before {
  content: "";
  position: absolute;
  top: -0.7rem;
  width: calc((100% - 1.4rem - 0.45rem * (var(--fr-cols) - 1)) / var(--fr-cols) * 0.7);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--fr-color-a);
  opacity: 0;
  transition: opacity var(--t-fast), left var(--t-fast);
  pointer-events: none;
  /* Centre-x of the hovered column track. */
  left: calc(
    0.7rem +
    (var(--hover-col, 0) + 0.5) *
    ((100% - 1.4rem - 0.45rem * (var(--fr-cols) - 1)) / var(--fr-cols)) +
    var(--hover-col, 0) * 0.45rem
  );
  transform: translateX(-50%);
}
.fr-board[data-hover-col]::before { opacity: 0.85; }
.fr-board.is-color-b::before { background: var(--fr-color-b); }
.fr-token {
  width: 86%;
  height: 86%;
  border-radius: 50%;
  background: var(--fr-color-a);
  box-shadow:
    inset 0 -3px 6px rgba(0, 0, 0, 0.3),
    inset 0 3px 4px rgba(255, 255, 255, 0.22),
    0 1px 2px rgba(0, 0, 0, 0.5);
}
.fr-token.is-color-a { background: var(--fr-color-a); }
.fr-token.is-color-b { background: var(--fr-color-b); }

/* Newly-dropped token falls from above. The fall distance is the
   landing row + 1 (in cell heights) — passed in as --fall-rows.
   Cubic-bezier with a slight overshoot gives a satisfying "thud"
   without being cartoonish. */
.fr-token.is-falling {
  animation: fr-fall 0.42s cubic-bezier(0.34, 1.25, 0.64, 1);
}
@keyframes fr-fall {
  0%   { transform: translateY(calc(-100% * var(--fall-rows, 6) - 60%)); opacity: 0.6; }
  60%  { opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}

/* Highlight winning tokens with the accent glow (regardless of
   which colour formed the run — both pop). */
.fr-token.is-winning {
  box-shadow:
    inset 0 -3px 6px rgba(0, 0, 0, 0.3),
    inset 0 3px 4px rgba(255, 255, 255, 0.25),
    0 0 22px 3px var(--accent-glow);
  animation: fr-winglow 1.1s ease-in-out infinite alternate;
}
@keyframes fr-winglow {
  from { filter: brightness(1); }
  to   { filter: brightness(1.22); }
}

/* Winning line — SVG overlay on top of the board. Mirrors the
   TTT winline (same `draw-winline` keyframe), but coloured in the
   winner's token colour so the four-in-a-row run reads at a glance.
   The stroke is thicker than TTT's (the FIAR tokens are larger
   relative to the board, so a thin line would look meek). */
.fr-winline {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}
.fr-winline-stroke {
  stroke: var(--accent);
  stroke-linecap: round;
  fill: none;
  filter: drop-shadow(0 0 8px var(--accent-glow));
  stroke-dasharray: var(--len, 400);
  stroke-dashoffset: var(--len, 400);
  animation: draw-winline 0.6s ease-out forwards;
}
.fr-winline.is-color-a .fr-winline-stroke {
  stroke: var(--fr-color-a);
  filter: drop-shadow(0 0 10px var(--fr-color-a-glow));
}
.fr-winline.is-color-b .fr-winline-stroke {
  stroke: var(--fr-color-b);
  filter: drop-shadow(0 0 10px var(--fr-color-b-glow));
}

/* ─── Dots & Boxes ───────────────────────────────────────────────
   The board is a single SVG with viewBox 0..N (with PAD on each
   side). All positioning is in unit coordinates (one box = 1 unit)
   so every visual scales cleanly with the SVG width. */
.db-board {
  width: min(92vw, 460px);
  /* SVG viewBox is square (N + 2*PAD wide), so the rendered SVG is
     also square — preserveAspectRatio: xMidYMid meet keeps it that
     way without us having to fix a height. */
  display: block;
  margin: 0 auto;
}
.db-panel {
  fill: #1d1a13;
  stroke: rgba(212, 168, 67, 0.18);
  stroke-width: 0.02;
}

/* Dots — small bright pips at each grid intersection. */
.db-dot {
  fill: var(--text-secondary);
}

/* Drawn line: the colored ink the player just laid down. The
   .is-last class on the most recent line gets a pulsing glow so
   you can see what your opponent did between turns. */
.db-line {
  stroke: var(--accent);
  stroke-width: 0.09;
  stroke-linecap: round;
  pointer-events: none;
  filter: drop-shadow(0 0.005px 0.01px rgba(0, 0, 0, 0.3));
}
.db-line.is-color-a { stroke: var(--fr-color-a); }
.db-line.is-color-b { stroke: var(--fr-color-b); }
.db-line.is-last {
  animation: db-line-in 0.32s ease-out;
}
@keyframes db-line-in {
  from { stroke-dasharray: 0 1.2; stroke-dashoffset: 0; opacity: 0.5; }
  to   { stroke-dasharray: 1.2 0; opacity: 1; }
}

/* Filled boxes (claimed). Stamped with a soft fill in the owner's
   color and a tiny pop animation when first claimed. */
.db-box {
  fill: transparent;
  transition: fill 0.18s ease-out;
}
.db-box.is-claimed {
  animation: db-box-pop 0.45s cubic-bezier(0.34, 1.4, 0.64, 1);
}
.db-box.is-claimed.is-color-a { fill: rgba(212, 168, 67, 0.35); }
.db-box.is-claimed.is-color-b { fill: rgba(200, 122, 106, 0.35); }
@keyframes db-box-pop {
  0%   { transform: scale(0.6); transform-origin: center; opacity: 0; }
  100% { transform: scale(1);   transform-origin: center; opacity: 1; }
}

/* Hit area for an undrawn line. Invisible by default; shows a faint
   preview in the local player's colour on hover so you can see what
   you're about to play. The .is-color-* class is the local player's
   mark, set in renderDotsAndBoxes. */
.db-hit {
  fill: transparent;
  cursor: pointer;
  transition: fill var(--t-fast);
}
.db-hit.is-color-a:hover { fill: rgba(212, 168, 67, 0.22); }
.db-hit.is-color-b:hover { fill: rgba(200, 122, 106, 0.22); }
.db-hit:focus-visible {
  outline: none;
  fill: rgba(255, 255, 255, 0.06);
}

/* ─── Mafia ─────────────────────────────────────────────────────── */

:root {
  --mafia-mafia: #c87a6a;
  --mafia-detective: #7aa9c8;
  --mafia-civilian: var(--text-primary);
}

.mafia {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  width: min(94vw, 460px);
  margin: 0 auto;
}

.dim { color: var(--text-secondary); }
.is-color-mafia { color: var(--mafia-mafia); }

/* Reveal-phase card. Front says "Tap to reveal", back shows your role.
   3D flip on tap. */
.mafia-reveal {
  display: flex;
  justify-content: center;
  margin-top: 0.75rem;
}
.mafia-reveal-card {
  width: min(86vw, 320px);
  aspect-ratio: 5 / 7;
  perspective: 900px;
  cursor: pointer;
  background: transparent;
  border: none;
  position: relative;
}
.mafia-reveal-card.mafia-reveal-spectate { aspect-ratio: 5 / 2; cursor: default; }
.mafia-reveal-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transition: transform 0.55s cubic-bezier(0.34, 1.18, 0.64, 1);
  transform-style: preserve-3d;
}
.mafia-reveal-card.is-flipped .mafia-reveal-inner { transform: rotateY(180deg); }
.mafia-reveal-front, .mafia-reveal-back {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1.25rem;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.mafia-reveal-front {
  background:
    repeating-linear-gradient(
      135deg,
      rgba(255, 255, 255, 0.025) 0 8px,
      rgba(255, 255, 255, 0.045) 8px 16px
    ),
    linear-gradient(180deg, #1c1814 0%, #0e0c08 100%);
  border: 1px solid rgba(212, 168, 67, 0.25);
}
.mafia-reveal-back {
  transform: rotateY(180deg);
  background: linear-gradient(180deg, #1c1814 0%, #0e0c08 100%);
  border: 1px solid rgba(212, 168, 67, 0.45);
  box-shadow: 0 0 24px -4px var(--accent-glow);
}
.mafia-reveal-eyebrow {
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 1rem;
}
.mafia-reveal-tap {
  font-size: 0.95rem;
  letter-spacing: 0.1em;
  color: var(--accent);
  font-weight: 600;
}
.mafia-reveal-flavor {
  margin-top: 1rem;
  font-size: 0.88rem;
  color: var(--text-primary);
  line-height: 1.5;
}

/* Role badges — color-coded pill. */
.mafia-role-badge {
  display: inline-block;
  padding: 0.18rem 0.55rem;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-radius: 4px;
  border: 1px solid;
}
.mafia-role-badge.is-role-mafia {
  color: var(--mafia-mafia);
  background: rgba(200, 122, 106, 0.12);
  border-color: rgba(200, 122, 106, 0.4);
}
.mafia-role-badge.is-role-detective {
  color: var(--mafia-detective);
  background: rgba(122, 169, 200, 0.12);
  border-color: rgba(122, 169, 200, 0.4);
}
.mafia-role-badge.is-role-civilian {
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border);
}
.mafia-role-badge.is-out {
  color: var(--text-dim);
  background: transparent;
  border-color: var(--border);
}

/* Generic card frame for night/day sections. */
.mafia-card {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1rem 1.1rem;
}
.mafia-card-quiet {
  background: transparent;
  border-color: var(--border);
  text-align: center;
}
.mafia-card-heading {
  font-size: 0.9rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.5rem;
  font-weight: 600;
}
.mafia-card-sub {
  font-size: 0.82rem;
  color: var(--text-secondary);
  line-height: 1.5;
  margin-bottom: 0.85rem;
}
.mafia-detective-result {
  font-size: 1rem;
  color: var(--text-primary);
  margin: 0.6rem 0 0.2rem;
}

/* Vote list — alive players as tappable rows showing the running tally. */
.mafia-vote-list {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}
.mafia-vote-btn {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 0.7rem 0.9rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 0.92rem;
  cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.mafia-vote-btn:hover, .mafia-vote-btn:focus-visible {
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.05);
  outline: none;
}
.mafia-vote-btn.is-mine {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.mafia-vote-btn.is-static {
  cursor: default;
  opacity: 0.85;
}
.mafia-vote-name { font-weight: 500; }
/* Vote counts get prominent so the running tally is the loudest
   thing on the row. Zero-counts stay quiet; once anyone votes for
   that target the chip lights up in the accent. The leader (most
   votes for any single target) gets an extra bold treatment via
   .is-leader added by the renderer. */
.mafia-vote-count {
  min-width: 1.6em;
  text-align: center;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-dim);
  letter-spacing: 0.04em;
  background: rgba(255, 255, 255, 0.04);
  padding: 0.18rem 0.55rem;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  transition: color var(--t-fast), background var(--t-fast), transform var(--t-fast);
}
.mafia-vote-count.has-votes {
  color: var(--accent);
  background: var(--accent-soft);
}
.mafia-vote-count.is-leader {
  color: #1a1200;
  background: var(--accent);
  transform: scale(1.05);
}
.mafia-vote-btn.is-mine .mafia-vote-name { color: var(--accent); }
.mafia-vote-skip {
  background: transparent;
  border-style: dashed;
  color: var(--text-secondary);
}

.mafia-spectate-list {
  list-style: none;
  margin: 0.5rem 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
}
.mafia-progress {
  text-align: center;
  font-size: 0.78rem;
  color: var(--text-secondary);
  letter-spacing: 0.05em;
  margin-top: 0.5rem;
}

/* Day phase — banners for what just happened. */
.mafia-day-killed, .mafia-day-resolved {
  padding: 0.75rem 0.95rem;
  background: rgba(200, 122, 106, 0.08);
  border: 1px solid rgba(200, 122, 106, 0.25);
  border-radius: var(--radius);
  font-size: 0.88rem;
  text-align: center;
  line-height: 1.55;
}
.mafia-day-resolved {
  background: rgba(212, 168, 67, 0.08);
  border-color: rgba(212, 168, 67, 0.25);
}

/* Detective's persistent investigation readout during day, so they
   can point to it while talking. Detective-blue tint to differentiate
   from the kill / eliminated banners above. */
.mafia-detective-recap {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.7rem 0.95rem;
  background: rgba(122, 169, 200, 0.08);
  border: 1px solid rgba(122, 169, 200, 0.3);
  border-radius: var(--radius);
}
.mafia-detective-recap-label {
  font-size: 0.65rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(122, 169, 200, 0.9);
}
.mafia-detective-recap-body {
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text-primary);
}

/* Players row — running list shown on every screen. Eliminated
   players fade out so the table can see who's left. */
.mafia-players {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  justify-content: center;
}
.mafia-player {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.7rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.82rem;
  color: var(--text-primary);
}
.mafia-player.is-self { border-color: var(--accent-soft); }
.mafia-player.is-out {
  opacity: 0.45;
  text-decoration: line-through;
}

/* Game-over roles reveal. */
.mafia-roles-reveal {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  width: 100%;
  max-width: 320px;
  margin: 0 auto;
}
.mafia-roles-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem 0.8rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.88rem;
}
.mafia-roles-row.is-role-mafia { border-color: rgba(200, 122, 106, 0.35); }
.mafia-roles-row.is-role-detective { border-color: rgba(122, 169, 200, 0.35); }
.mafia-roles-name { font-weight: 500; }

/* Game-over: the event that ended the round (banner above the role
   reveal). */
.mafia-trigger {
  text-align: center;
  margin: 0 auto 1rem;
  max-width: 320px;
  padding: 0.7rem 0.95rem;
  background: rgba(212, 168, 67, 0.08);
  border: 1px solid rgba(212, 168, 67, 0.25);
  border-radius: var(--radius);
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text-primary);
}

/* Round-by-round history accordion. Collapsed by default; tap the
   summary to open. */
.mafia-history {
  width: 100%;
  max-width: 320px;
  margin: 1.25rem auto 0;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.mafia-history-summary {
  padding: 0.7rem 0.95rem;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-secondary);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.mafia-history-summary::-webkit-details-marker { display: none; }
.mafia-history-summary::after {
  content: " ▾";
  color: var(--text-dim);
}
.mafia-history[open] .mafia-history-summary::after { content: " ▴"; }
.mafia-history-round {
  border-top: 1px solid var(--border);
  padding: 0.6rem 0.95rem 0.7rem;
}
.mafia-history-round-head {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.4rem;
}
.mafia-history-line {
  font-size: 0.85rem;
  line-height: 1.55;
  color: var(--text-primary);
  margin: 0.25rem 0;
}

/* Score-card disc — a small filled circle in the player's color.
   Replaces the plain X/O letter the TTT scoreboard uses. Shared
   between Four in a Row and Dots & Boxes. */
.score-card-mark.fr-disc {
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  border-radius: 50%;
  vertical-align: -2px;
  margin-right: 0.45rem;
  background: var(--fr-color-a);
}
.score-card-mark.fr-disc.is-color-a { background: var(--fr-color-a); }
.score-card-mark.fr-disc.is-color-b { background: var(--fr-color-b); }

/* ─── Scoreboard ────────────────────────────────────────────────── */

.scoreboard {
  display: flex;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}
.score-card {
  min-width: 120px;
  padding: 0.7rem 0.9rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: center;
}
.score-card.is-active { border-color: var(--accent); }
.score-card.is-celebrating {
  animation: score-pulse 1.1s ease-out;
}
@keyframes score-pulse {
  0%   { box-shadow: 0 0 0 0 var(--accent-glow); border-color: var(--accent); }
  60%  { box-shadow: 0 0 22px 6px var(--accent-glow); border-color: var(--accent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.score-card-name {
  display: block;
  font-size: 0.8rem;
  color: var(--text-secondary);
  letter-spacing: 0.04em;
  margin-bottom: 0.2rem;
}
.score-card-mark {
  display: inline-block;
  font-weight: 700;
  color: var(--accent);
  margin-right: 0.4rem;
}
.score-card-wins {
  font-size: 1.15rem;
  color: var(--text-primary);
  font-weight: 600;
}

/* ─── Game over ─────────────────────────────────────────────────── */

.gameover-title {
  color: var(--accent);
  text-shadow: 0 0 24px var(--accent-glow);
  margin-bottom: 0.3rem;
}

/* ─── Toast & overlay ──────────────────────────────────────────── */

.toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-surface);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  padding: 0.7rem 1.1rem;
  border-radius: var(--radius);
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  z-index: 200;
  opacity: 0;
  transition: opacity var(--t-med);
  pointer-events: none;
  max-width: calc(100% - 2rem);
  text-align: center;
}
.toast.show { opacity: 1; }

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 150;
}
.overlay.hidden { display: none; }
.overlay-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.5rem 2rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  color: var(--text-secondary);
  font-size: 0.9rem;
}
.spinner {
  width: 28px;
  height: 28px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ─── Responsive ───────────────────────────────────────────────── */

@media (min-width: 720px) {
  .title { font-size: 2rem; }
  .screen { padding-top: 5rem; }
}
