/* ==========================================================================
   The Board Games — DS-003 design system (from design/ds-003/css/app.css; prototype-only parts removed)
   Tokens: Neutral Modern (verbatim :root). Game hues are bound to existing
   palette tokens, never new hex. Dark ramp is the only extension (flagged).
   ========================================================================== */

/* ---------- 1. Tokens (Neutral Modern, verbatim) ---------- */
:root {
  --bg: #fafafa;
  --surface: #ffffff;
  --surface-warm: var(--surface);
  --fg: #111111;
  --fg-2: var(--fg);
  --muted: #595959;
  --meta: var(--muted);
  --border: #e5e5e5;
  --border-soft: var(--border);
  --accent: #2f6feb;
  --accent-on: #ffffff;
  --accent-hover: color-mix(in oklab, var(--accent), black 8%);
  --accent-active: color-mix(in oklab, var(--accent), black 14%);
  --success: #17a34a;
  --warn: #eab308;
  --danger: #dc2626;
  --mark-x: #166534; --mark-o: #b91c1c; /* Gomoku X / O (FR-45), >= 4.5:1 on the board; also the seat dots */
  --font-display: "Inter", -apple-system, system-ui, sans-serif;
  --font-body: "Inter", -apple-system, system-ui, sans-serif;
  --font-mono: ui-monospace, "JetBrains Mono", monospace;
  --text-xs: 12px;
  --text-sm: 14px;
  --text-base: 16px;
  --text-lg: 20px;
  --text-xl: 24px;
  --text-2xl: 32px;
  --text-3xl: 48px;
  --text-4xl: 64px;
  --leading-body: 1.5;
  --leading-tight: 1.2;
  --tracking-display: -0.01em;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-20: 80px;
  --section-y-desktop: 80px;
  --section-y-tablet: 48px;
  --section-y-phone: 32px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-pill: 9999px;
  --elev-flat: none;
  --elev-ring: 0 0 0 1px var(--border);
  --elev-raised: 0 2px 8px color-mix(in oklab, var(--fg), transparent 92%);
  --focus-ring: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 70%);
  --motion-fast: 150ms;
  --motion-base: 200ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --container-max: 1200px;
  --container-gutter-desktop: 24px;
  --container-gutter-tablet: 16px;
  --container-gutter-phone: 12px;
}

/* ---------- 2. Dark theme ----------
   WARNING: Neutral Modern ships no dark ramp. The values below are an
   agent-chosen extension (neutral greys, no hue) so the required dark toggle
   works. Owner can swap them without touching component CSS. */
:root[data-theme="dark"] {
  --bg: #121212;
  --surface: #1c1c1c;
  --fg: #f2f2f2;
  --muted: #a3a3a3;
  --border: #2f2f2f;
  /* text colours lifted so every text is >= 4.5:1 on the dark surfaces (QC-017); fills keep --accent */
  --danger: #f87171;
  --mark-x: #4ade80; --mark-o: #fca5a5;
  --link: #7aa7ff;
  --accent-hover: color-mix(in oklab, var(--accent), white 10%);
  --accent-active: color-mix(in oklab, var(--accent), white 18%);
  --elev-raised: 0 2px 12px color-mix(in oklab, black, transparent 50%);
  color-scheme: dark;
}

/* ---------- 3. Game hues (bound to palette tokens) ---------- */
[data-game] { --game: var(--accent); }
[data-game="caro"] { --game: var(--success); }
[data-game="chess"]  { --game: var(--accent); }
[data-game="xiangqi"], [data-game="jieqi"] { --game: var(--danger); }
[data-game="blocks"] { --game: var(--warn); }
[data-game] {
  --game-tint: color-mix(in oklab, var(--game) 12%, var(--surface));
  --game-soft: color-mix(in oklab, var(--game) 26%, var(--surface));
  --game-ink: color-mix(in oklab, var(--game) 45%, var(--fg));
}

/* ---------- 4. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font: 400 var(--text-base)/var(--leading-body) var(--font-body);
  min-height: 100dvh; display: flex; flex-direction: column;
  transition: background var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard);
}
h1, h2, h3 { font-family: var(--font-display); font-weight: 600; line-height: var(--leading-tight); margin: 0; text-wrap: balance; }
h1 { font-size: clamp(var(--text-2xl), 4.2vw, var(--text-3xl)); letter-spacing: var(--tracking-display); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-base); }
p { margin: 0; text-wrap: pretty; }
a { color: var(--link, var(--accent)); text-decoration: none; }
a:hover { text-decoration: underline; }
button, input, select { font: inherit; color: inherit; }
:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }
.small { font-size: var(--text-sm); }
.xs { font-size: var(--text-xs); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.container { width: 100%; max-width: var(--container-max); margin-inline: auto; padding-inline: var(--container-gutter-desktop); }
main { flex: 1; }
.stack-2 > * + * { margin-top: var(--space-2); }
.stack-3 > * + * { margin-top: var(--space-3); }
.stack-4 > * + * { margin-top: var(--space-4); }
.stack-6 > * + * { margin-top: var(--space-6); }
.row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
[hidden] { display: none !important; }

/* ---------- 5. Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 44px; padding: 10px 16px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: transparent; cursor: pointer;
  font-size: var(--text-sm); font-weight: 600; white-space: nowrap; text-decoration: none !important;
  transition: background var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard), transform var(--motion-fast) var(--ease-standard);
}
.btn:active { transform: translateY(1px); }
.btn:disabled { cursor: default; opacity: .6; transform: none; }
.btn-primary { background: var(--accent); color: var(--accent-on); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-active); }
.btn-secondary { border-color: var(--border); color: var(--fg); background: var(--surface); }
.btn-secondary:hover:not(:disabled) { border-color: color-mix(in oklab, var(--fg) 35%, var(--border)); }
.btn-ghost { color: var(--fg); }
.btn-ghost:hover:not(:disabled) { background: color-mix(in oklab, var(--fg) 6%, transparent); }
.btn-danger { color: var(--danger); border-color: color-mix(in oklab, var(--danger) 35%, var(--border)); background: var(--surface); }
.btn-danger:hover:not(:disabled) { background: color-mix(in oklab, var(--danger) 8%, var(--surface)); }
.btn-danger-solid { background: var(--danger); color: var(--accent-on); }
.btn-lg { min-height: 52px; padding-inline: 22px; font-size: var(--text-base); border-radius: var(--radius-md); }
.btn-block { width: 100%; }
.icon-btn {
  width: 44px; height: 44px; display: inline-grid; place-items: center; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface); cursor: pointer; color: var(--fg);
  transition: border-color var(--motion-fast) var(--ease-standard);
}
.icon-btn:hover { border-color: color-mix(in oklab, var(--fg) 35%, var(--border)); }
.icon { width: 20px; height: 20px; flex: none; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- 6. Top bar + brand ---------- */
.topbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in oklab, var(--bg) 86%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid color-mix(in oklab, var(--border) 70%, transparent);
}
.topbar .container { display: flex; align-items: center; gap: var(--space-4); height: 64px; }
.brand { flex: none; white-space: nowrap; display: inline-flex; align-items: center; gap: 10px; color: var(--fg); font-weight: 600; font-size: var(--text-lg); letter-spacing: var(--tracking-display); text-decoration: none !important; }
.brand-mark { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; width: 26px; height: 26px; transform: rotate(-8deg); }
.brand-mark i { border-radius: 4px; }
.brand-mark i:nth-child(1) { background: var(--success); }
.brand-mark i:nth-child(2) { background: var(--accent); }
.brand-mark i:nth-child(3) { background: var(--danger); }
.brand-mark i:nth-child(4) { background: var(--warn); }
.nav { display: flex; gap: var(--space-1); margin-left: var(--space-4); }
.nav a { color: var(--muted); font-weight: 500; font-size: var(--text-sm); padding: 10px 12px; border-radius: var(--radius-sm); text-decoration: none; }
.nav a:hover { color: var(--fg); background: color-mix(in oklab, var(--fg) 5%, transparent); }
.nav a[aria-current="page"] { color: var(--fg); }
.topbar-end { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); }
.me-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 4px 12px 4px 4px; border-radius: var(--radius-pill); border: 1px solid var(--border); background: var(--surface); color: var(--fg); font-size: var(--text-sm); font-weight: 500; text-decoration: none !important; max-width: 220px; }
.me-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- 7. Avatars, chips, badges ---------- */
.avatar {
  --av: var(--accent);
  width: 36px; height: 36px; flex: none; border-radius: var(--radius-pill);
  display: inline-grid; place-items: center; font-weight: 600; font-size: var(--text-sm);
  background: color-mix(in oklab, var(--av) 18%, var(--surface)); color: color-mix(in oklab, var(--av) 75%, var(--fg));
  border: 2px solid var(--surface); box-shadow: 0 0 0 1px color-mix(in oklab, var(--av) 30%, var(--border));
}
.avatar.sm { width: 28px; height: 28px; font-size: var(--text-xs); }
.avatar.lg { width: 56px; height: 56px; font-size: var(--text-lg); }
.avatar[data-hue="0"] { --av: var(--success); }
.avatar[data-hue="1"] { --av: var(--accent); }
.avatar[data-hue="2"] { --av: var(--danger); }
.avatar[data-hue="3"] { --av: var(--warn); }
.badge { display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border-radius: var(--radius-pill); font-size: var(--text-xs); font-weight: 600; background: color-mix(in oklab, var(--fg) 6%, var(--surface)); color: var(--muted); white-space: nowrap; }
.badge-dot::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge-win { background: color-mix(in oklab, var(--success) 14%, var(--surface)); color: color-mix(in oklab, var(--success) 70%, var(--fg)); }
.badge-loss { background: color-mix(in oklab, var(--danger) 12%, var(--surface)); color: color-mix(in oklab, var(--danger) 75%, var(--fg)); }
.badge-draw { background: color-mix(in oklab, var(--fg) 8%, var(--surface)); color: var(--muted); }
.badge-game { background: var(--game-tint); color: var(--game-ink); }
.chip { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 6px 14px; border-radius: var(--radius-pill); border: 1px solid var(--border); background: var(--surface); font-size: var(--text-sm); font-weight: 500; cursor: pointer; color: var(--fg); }
.chip[aria-pressed="true"] { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.chip .swatch { width: 10px; height: 10px; border-radius: 3px; background: var(--game, var(--muted)); }
.chip[aria-pressed="true"] .swatch { box-shadow: 0 0 0 1.5px var(--bg); }

/* ---------- 8. Cards, fields, tabs ---------- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-5); }
.card-lg { border-radius: var(--radius-lg); padding: var(--space-6); }
.field { display: grid; gap: var(--space-2); }
.field label { font-size: var(--text-sm); font-weight: 600; }
.field input {
  width: 100%; min-height: 44px; padding: 10px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface); color: var(--fg);
  transition: border-color var(--motion-fast) var(--ease-standard);
}
.field input::placeholder { color: var(--muted); }
.field input:focus-visible { border-color: var(--accent); box-shadow: var(--focus-ring); }
.field input[aria-invalid="true"] { border-color: var(--danger); }
.field-help { font-size: var(--text-sm); color: var(--muted); }
.field-error { font-size: var(--text-sm); color: var(--danger); font-weight: 500; }
.tabs { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--border); }
.tab { padding: 12px 14px; border: 0; background: none; cursor: pointer; font-weight: 600; font-size: var(--text-sm); color: var(--muted); border-bottom: 2px solid transparent; margin-bottom: -1px; min-height: 44px; }
.tab[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--fg); }
.notice { display: flex; gap: var(--space-3); align-items: flex-start; padding: var(--space-4); border-radius: var(--radius-md); background: color-mix(in oklab, var(--warn) 14%, var(--surface)); border: 1px solid color-mix(in oklab, var(--warn) 40%, var(--border)); font-size: var(--text-sm); }
.notice-info { background: color-mix(in oklab, var(--accent) 7%, var(--surface)); border-color: color-mix(in oklab, var(--accent) 25%, var(--border)); }

/* ---------- 9. Dialog + toast ---------- */
dialog.sheet {
  border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-6);
  background: var(--surface); color: var(--fg); width: min(440px, calc(100vw - 24px)); box-shadow: var(--elev-raised);
}
dialog.sheet::backdrop { background: color-mix(in oklab, var(--fg) 35%, transparent); }
dialog.sheet[open] { animation: pop var(--motion-base) var(--ease-standard); }
.sheet-actions { display: flex; gap: var(--space-2); justify-content: flex-end; margin-top: var(--space-6); flex-wrap: wrap; }
@keyframes pop { from { opacity: 0; transform: translateY(8px) scale(.98); } }
.toast-host { position: fixed; left: 50%; bottom: 88px; transform: translateX(-50%); z-index: 60; display: grid; gap: var(--space-2); pointer-events: none; }
.toast { background: var(--fg); color: var(--bg); padding: 10px 16px; border-radius: var(--radius-pill); font-size: var(--text-sm); font-weight: 500; box-shadow: var(--elev-raised); animation: pop var(--motion-base) var(--ease-standard); }

/* ---------- 10. Footer + mobile tab bar ---------- */
.footer { border-top: 1px solid var(--border); margin-top: var(--space-12); }
.footer .container { display: flex; gap: var(--space-4); align-items: center; justify-content: space-between; padding-block: var(--space-6); flex-wrap: wrap; font-size: var(--text-sm); color: var(--muted); }
.footer nav { display: flex; gap: var(--space-4); }
.footer a { color: var(--muted); }
.tabbar { display: none; }

/* ---------- 11. Home ---------- */
.hero { padding-block: var(--space-12) var(--space-8); display: grid; grid-template-columns: 1.1fr .9fr; gap: var(--space-12); align-items: center; }
.hero .lead { font-size: var(--text-lg); color: var(--muted); max-width: 44ch; margin-top: var(--space-4); }
.hero h1 em { font-style: normal; background: linear-gradient(transparent 62%, color-mix(in oklab, var(--warn) 55%, transparent) 62%); padding-inline: 2px; }
.hero-cta { margin-top: var(--space-6); }
.duo { position: relative; border-radius: var(--radius-lg); background: var(--surface); border: 1px solid var(--border); padding: var(--space-6); overflow: hidden; }
.duo-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-3); }
.duo-player { display: grid; justify-items: center; gap: var(--space-2); font-size: var(--text-sm); font-weight: 600; text-align: center; }
.duo-player small { font-weight: 400; color: var(--muted); }
.duo-wire { position: relative; height: 44px; }
.duo-wire::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; border-top: 2px dashed var(--border); }
.duo-link { position: absolute; top: 50%; left: 0; transform: translate(0, -50%); display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: var(--radius-pill); background: var(--accent); color: var(--accent-on); font-size: var(--text-xs); font-weight: 600; font-family: var(--font-mono); animation: travel 3.6s var(--ease-standard) infinite; white-space: nowrap; }
@keyframes travel { 0%, 12% { left: 0; opacity: 0; } 22% { opacity: 1; } 70% { opacity: 1; } 82%, 100% { left: calc(100% - 92px); opacity: 0; } }
.duo-board { margin-top: var(--space-5); display: grid; grid-template-columns: repeat(9, 1fr); gap: 4px; }
.duo-board i { aspect-ratio: 1; border-radius: 6px; background: color-mix(in oklab, var(--fg) 5%, var(--surface)); }
.duo-board i.x { background: var(--success); }
.duo-board i.o { background: color-mix(in oklab, var(--fg) 85%, var(--surface)); }
.duo-board i.pop { animation: dot 3.6s var(--ease-standard) infinite; }
@keyframes dot { 0%, 80% { transform: scale(0); } 90%, 100% { transform: scale(1); } }
.duo-caption { margin-top: var(--space-4); font-size: var(--text-sm); color: var(--muted); }

.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-5); flex-wrap: wrap; }
.game-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-5); }
.game-tile {
  position: relative; display: flex; flex-direction: column; border-radius: var(--radius-lg); overflow: hidden;
  background: var(--surface); border: 1px solid var(--border); color: var(--fg); text-decoration: none !important; cursor: pointer;
  transition: transform var(--motion-base) var(--ease-standard), border-color var(--motion-base) var(--ease-standard), box-shadow var(--motion-base) var(--ease-standard);
}
.game-tile:hover { transform: translateY(-4px) rotate(-.6deg); border-color: color-mix(in oklab, var(--game) 45%, var(--border)); box-shadow: var(--elev-raised); }
.game-tile:nth-child(even):hover { transform: translateY(-4px) rotate(.6deg); }
.tile-art { aspect-ratio: 4 / 3; background: var(--game-tint); display: grid; place-items: center; position: relative; overflow: hidden; }
.tile-body { padding: var(--space-5); display: grid; gap: var(--space-2); flex: 1; }
.tile-body h3 { font-size: var(--text-lg); }
.tile-meta { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: auto; padding-top: var(--space-3); }
.tile-go { position: absolute; right: var(--space-4); top: var(--space-4); width: 40px; height: 40px; border-radius: var(--radius-pill); background: var(--surface); display: grid; place-items: center; box-shadow: var(--elev-raised); color: var(--fg); transition: transform var(--motion-base) var(--ease-standard); }
.game-tile:hover .tile-go { transform: rotate(-45deg); }

/* tile art — small real boards drawn with CSS */
.art-gomoku { width: 72%; aspect-ratio: 1; display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; transform: rotate(-6deg); }
.art-gomoku i { border-radius: 50%; background: color-mix(in oklab, var(--game) 10%, var(--surface)); }
.art-gomoku i.x, .art-gomoku i.o { position: relative; background: color-mix(in oklab, var(--game) 10%, var(--surface)); }
.art-gomoku i.x::before, .art-gomoku i.x::after { content: ""; position: absolute; left: 50%; top: 50%; width: 80%; height: 18%; border-radius: 99px; background: var(--success); transform: translate(-50%, -50%) rotate(45deg); }
.art-gomoku i.x::after { transform: translate(-50%, -50%) rotate(-45deg); }
.art-gomoku i.o::before { content: ""; position: absolute; inset: 16%; border-radius: 50%; border: 3px solid var(--danger); }
.art-gomoku i.win { box-shadow: inset 0 0 0 2px color-mix(in oklab, var(--success) 45%, transparent); }
.art-chess { width: 66%; aspect-ratio: 1; display: grid; grid-template-columns: repeat(4, 1fr); border-radius: 10px; overflow: hidden; transform: rotate(5deg); box-shadow: var(--elev-raised); }
.art-chess i { display: grid; place-items: center; background: color-mix(in oklab, var(--accent) 5%, var(--surface)); }
.art-chess i:nth-child(8n+2), .art-chess i:nth-child(8n+4), .art-chess i:nth-child(8n+5), .art-chess i:nth-child(8n+7) { background: color-mix(in oklab, var(--accent) 26%, var(--surface)); }
.art-chess .pc { width: 82%; height: 82%; }
.art-xq { display: flex; gap: 10px; transform: rotate(-4deg); }
.xq-disc { width: clamp(44px, 5.4vw, 60px); aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center; background: var(--surface); border: 3px solid currentColor; font-size: clamp(20px, 2.6vw, 28px); font-weight: 600; box-shadow: var(--elev-raised); font-family: "Songti SC", "SimSun", "Noto Serif CJK SC", serif; }
.xq-disc.red { color: var(--danger); }
.xq-disc.black { color: var(--fg); }
.art-xq .xq-disc:nth-child(2) { transform: translateY(-14px); }
.art-blocks { display: grid; grid-template-columns: repeat(6, 1fr); width: 56%; gap: 3px; transform: rotate(4deg); }
.art-blocks i { aspect-ratio: 1; border-radius: 4px; }
.art-blocks i.f1 { background: var(--warn); }
.art-blocks i.f2 { background: var(--accent); }
.art-blocks i.f3 { background: var(--success); }
.art-blocks i.f4 { background: var(--danger); }
.art-blocks i.f5 { background: var(--fg); }

.recent { margin-top: var(--space-12); display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); }
.recent-list { display: grid; gap: var(--space-2); }
.recent-item { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-3); padding: var(--space-3); border-radius: var(--radius-md); background: color-mix(in oklab, var(--fg) 3%, var(--surface)); }
.recent-item .gdot { width: 36px; height: 36px; border-radius: 10px; background: var(--game-tint); color: var(--game-ink); display: grid; place-items: center; font-weight: 700; font-size: var(--text-sm); }
.how { display: grid; gap: var(--space-4); counter-reset: step; }
.how li { list-style: none; display: grid; grid-template-columns: 36px 1fr; gap: var(--space-3); align-items: start; }
.how li::before { counter-increment: step; content: counter(step); width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; font-weight: 600; background: color-mix(in oklab, var(--fg) 6%, var(--surface)); }
.how { padding: 0; margin: 0; }

/* ---------- 12. Waiting room ---------- */
.wait { padding-block: var(--space-12); display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 380px); gap: var(--space-8); align-items: start; }
.wait-card { position: relative; overflow: hidden; }
.wait-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 6px; background: var(--game); }
.link-box { display: flex; gap: var(--space-2); align-items: stretch; padding: 6px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg); }
.link-box input { flex: 1; min-width: 0; border: 0; background: transparent; padding: 0 10px; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg); }
.link-box input:focus-visible { box-shadow: none; }
.join-code { margin-top: var(--space-6); max-width: 44ch; }
.join-row { display: flex; gap: var(--space-2); }
.join-row input { flex: 1; min-width: 0; min-height: 44px; }
.join-row .btn { flex: none; min-height: 44px; }
.code-box { align-items: center; justify-content: space-between; padding-left: var(--space-3); }
.code-box .btn { min-height: 44px; flex: none; }
.code-box .code-big { flex: 1; min-width: 0; font-size: clamp(18px, 6vw, var(--text-2xl)); letter-spacing: .06em; overflow-wrap: anywhere; line-height: 1.1; }
.link-rows > * { min-width: 0; }
.code-big { font-family: var(--font-mono); font-size: var(--text-2xl); letter-spacing: .12em; font-weight: 600; }
.seats { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--space-4); }
.seat-slot { display: grid; justify-items: center; gap: var(--space-2); padding: var(--space-5) var(--space-3); border-radius: var(--radius-md); background: var(--game-tint); text-align: center; min-width: 0; }
.seat-slot b { font-size: var(--text-sm); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seat-slot.empty { background: transparent; border: 2px dashed var(--border); }
.seat-slot.empty .avatar { --av: var(--muted); animation: breathe 1.8s ease-in-out infinite; }
.seat-slot.joined { animation: pop var(--motion-base) var(--ease-standard); }
.vs { font-weight: 700; color: var(--muted); font-size: var(--text-sm); }
@keyframes breathe { 50% { transform: scale(.88); opacity: .55; } }
@keyframes low-pulse { 50% { opacity: .55; } } /* DEV-034: the warning pulses in colour only, its size stays put */
.steps-mini { display: grid; gap: var(--space-3); font-size: var(--text-sm); }
.steps-mini div { display: grid; grid-template-columns: 24px 1fr; gap: var(--space-2); }

/* ---------- 13. Play ---------- */
/* board never taller than the viewport minus header + two seat bars */
.play { --board-max: min(640px, calc(100dvh - 236px)); }
.play[data-game="xiangqi"], .play[data-game="jieqi"] { --board-max: min(640px, calc((100dvh - 236px) * .9)); }
.play[data-game="blocks"] { --board-max: 520px; }
.play { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--space-8); padding-block: var(--space-6) var(--space-8); align-items: start; align-content: start; }
.play-stage { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-3); justify-items: center; min-width: 0; } /* QC-034 L-1: a long captured row must not widen the column and resize the board */
.seat-bar { width: 100%; max-width: var(--board-max, 640px); display: flex; align-items: center; gap: var(--space-3); padding: 8px 12px 8px 8px; border-radius: var(--radius-md); background: var(--surface); border: 1px solid var(--border); transition: border-color var(--motion-base) var(--ease-standard), box-shadow var(--motion-base) var(--ease-standard), opacity var(--motion-base); }
.seat-bar .who { min-width: 0; display: grid; }
.seat-bar .who b { font-size: var(--text-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seat-bar .who span { font-size: var(--text-xs); color: var(--muted); }
.seat-bar .side { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600; color: var(--muted); }
.side-token { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--fg); }
.side-token.fill { background: var(--fg); }
.side-token.red { border-color: var(--danger); background: var(--danger); }
.side-token.mark-x { border-color: var(--mark-x); background: var(--mark-x); }
.side-token.mark-o { border-color: var(--mark-o); background: var(--mark-o); }
.side-token.green { border-color: var(--success); background: var(--success); }
.seat-bar.on-turn { border-color: var(--game); box-shadow: 0 0 0 3px color-mix(in oklab, var(--game) 22%, transparent); }
.seat-bar.offline { opacity: .5; }
.turn-pip { width: 8px; height: 8px; border-radius: 50%; background: var(--game); opacity: 0; }
.seat-bar.on-turn .turn-pip { opacity: 1; animation: breathe 1.4s ease-in-out infinite; }
.board-wrap { width: 100%; max-width: var(--board-max, 640px); position: relative; }
.play-side { display: grid; gap: var(--space-4); position: sticky; top: 88px; }
.status-card { padding: var(--space-5); border-radius: var(--radius-lg); background: var(--game-tint); border: 1px solid color-mix(in oklab, var(--game) 25%, var(--border)); }
.status-card .status-line { font-size: var(--text-xl); font-weight: 600; line-height: var(--leading-tight); }
.status-card .status-sub { font-size: var(--text-sm); color: color-mix(in oklab, var(--muted) 70%, var(--fg)); margin-top: 4px; }
/* DEV-034: a held hint line keeps its height, so the card does not change size with the turn */
.status-card .status-sub.held { visibility: hidden; }
.status-card.status-held { overflow: hidden; } /* chess, game over: the height it had during play (QC-037 L-8) */
.status-card.status-held :is(.status-line, .status-sub) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.status-card.alert { background: color-mix(in oklab, var(--warn) 16%, var(--surface)); border-color: color-mix(in oklab, var(--warn) 45%, var(--border)); }
.moves { max-height: 280px; overflow: auto; }
.moves ol { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: 32px 1fr 1fr; row-gap: 2px; font-family: var(--font-mono); font-size: var(--text-sm); }
.moves li { display: contents; }
.moves li span { padding: 4px 6px; border-radius: 6px; }
.moves li span:first-child { color: var(--muted); }
.moves li span.latest { background: var(--game-tint); }
.moves-empty { font-size: var(--text-sm); color: var(--muted); }
.side-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.play-mobile-actions { display: none; }

/* result sheet over the board */
.result {
  position: absolute; inset: 0; display: grid; place-items: center; padding: var(--space-4); z-index: 5;
  background: color-mix(in oklab, var(--bg) 22%, transparent); border-radius: var(--radius-md);
}
.result-card { width: min(360px, 100%); text-align: center; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-6); box-shadow: var(--elev-raised); animation: pop var(--motion-base) var(--ease-standard); }
.result-card h2 { font-size: var(--text-2xl); letter-spacing: var(--tracking-display); }
.result-card .reason { color: var(--muted); font-size: var(--text-sm); margin-top: var(--space-2); }
.result-stats { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-top: var(--space-5); }
.result-stats div { padding: var(--space-3); border-radius: var(--radius-md); background: color-mix(in oklab, var(--fg) 4%, var(--surface)); font-size: var(--text-xs); color: var(--muted); }
.result-stats b { display: block; font-size: var(--text-lg); color: var(--fg); font-family: var(--font-mono); }
.result-actions { display: grid; gap: var(--space-2); margin-top: var(--space-5); }
.result-note { font-size: var(--text-sm); color: var(--game-ink); font-weight: 600; margin-top: var(--space-3); min-height: 1.5em; }
.confetti { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 6; }
.confetti i { position: absolute; top: -12px; width: 10px; height: 10px; border-radius: 2px; animation: fall 1.6s var(--ease-standard) forwards; }
@keyframes fall { to { transform: translateY(var(--dy, 520px)) rotate(540deg); opacity: 0; } }

/* Gomoku board */
.gomoku { --hl-last: 24%; --hl-win: 18%; display: grid; grid-template-columns: repeat(20, 1fr); aspect-ratio: 1; padding: 2%; container-type: inline-size; border-radius: var(--radius-md); background: var(--game-tint); border: 1px solid color-mix(in oklab, var(--game) 25%, var(--border)); }
:root[data-theme="dark"] .gomoku { --hl-last: 14%; --hl-win: 14%; } /* >= 4.5:1 for X and O on the board in both themes (DEV-007) */
.gomoku button { position: relative; aspect-ratio: 1; border: 0; padding: 0; background: none; cursor: pointer; }
.gomoku button::before, .gomoku button::after { content: ""; position: absolute; background: color-mix(in oklab, var(--game) 35%, var(--border)); }
.gomoku button::before { left: 0; right: 0; top: 50%; height: 1px; }
.gomoku button::after { top: 0; bottom: 0; left: 50%; width: 1px; }
.gomoku button:nth-child(20n+1)::before { left: 50%; }
.gomoku button:nth-child(20n)::before { right: 50%; }
.gomoku button:nth-child(-n+20)::after { top: 50%; }
.gomoku button:nth-last-child(-n+20)::after { bottom: 50%; }
/* X = two bars (green), O = ring (red): FR-45, no round stones. The ::before/::after of the button are the grid lines. */
.gomoku .stone { position: absolute; inset: 14%; z-index: 1; animation: drop var(--motion-base) var(--ease-standard); }
.gomoku .stone.x::before, .gomoku .stone.x::after { content: ""; position: absolute; left: 50%; top: 50%; width: 118%; height: 17%; border-radius: 99px; background: var(--mark-x); transform: translate(-50%, -50%) rotate(45deg); }
.gomoku .stone.x::after { transform: translate(-50%, -50%) rotate(-45deg); }
.gomoku .stone.o { border-radius: 50%; border: clamp(2px, 1.1cqw, 5px) solid var(--mark-o); }
.gomoku .last { background: color-mix(in oklab, var(--warn) var(--hl-last), transparent); border-radius: 4px; }
.gomoku .win { background: color-mix(in oklab, var(--success) var(--hl-win), transparent); border-radius: 4px; }
.gomoku .win:has(.stone.o) { background: color-mix(in oklab, var(--danger) calc(var(--hl-win) * .6), transparent); }
/* hover / marked point: a faint X or O of my side (FR-45: no round stone). --ghost = the mark colour at low opacity. */
.gomoku[data-me="x"] { --me: var(--mark-x); }
.gomoku[data-me="o"] { --me: var(--mark-o); }
.caro-hint { min-height: 1.5em; margin: var(--space-2) 0 0; text-align: center; font-size: var(--text-sm); font-weight: 600; color: var(--fg); }
.gomoku.my-turn button:empty:hover, .gomoku button.pick:empty { --ghost: color-mix(in oklab, var(--me) 45%, transparent); border-radius: 4px; background-position: center; background-size: 72% 72%; background-repeat: no-repeat; }
.gomoku button.pick:empty { --ghost: color-mix(in oklab, var(--me) 80%, transparent); box-shadow: inset 0 0 0 2px var(--me); }
.gomoku[data-me="x"].my-turn button:empty:hover, .gomoku[data-me="x"] button.pick:empty { background-image: linear-gradient(45deg, transparent 44%, var(--ghost) 44%, var(--ghost) 56%, transparent 56%), linear-gradient(-45deg, transparent 44%, var(--ghost) 44%, var(--ghost) 56%, transparent 56%); }
.gomoku[data-me="o"].my-turn button:empty:hover, .gomoku[data-me="o"] button.pick:empty { background-image: radial-gradient(circle, transparent 46%, var(--ghost) 48%, var(--ghost) 70%, transparent 72%); }
@keyframes drop { from { transform: scale(.4); opacity: 0; } }

/* Chess board */
.chess { display: grid; grid-template-columns: repeat(8, 1fr); aspect-ratio: 1; border-radius: var(--radius-md); overflow: hidden; border: 1px solid var(--border); position: relative; isolation: isolate; }
.chess button { position: relative; aspect-ratio: 1; border: 0; padding: 0; cursor: pointer; display: grid; place-items: center; background: color-mix(in oklab, var(--accent) 5%, var(--surface)); font-size: clamp(26px, 6.2vw, 52px); line-height: 1; color: var(--fg); }
.chess button.dark { background: color-mix(in oklab, var(--accent) 26%, var(--surface)); }
/* Chess pieces — set v2 (design/ds-005, DEV-045). Pieces are physical objects: the same colours in both themes,
   except that a black piece gets a pale rim on dark boards and the ground shadow is stronger there. Contrast table: design/ds-005/chess-v2-notes.md. */
:root {
  --pcv2-w-hi: #ffffff; --pcv2-w-fill: #f4f7fd; --pcv2-w-shade: #c3d1ee; --pcv2-w-ink: #14254a;
  --pcv2-w-detail: #14254a; --pcv2-w-gloss: #ffffff; --pcv2-w-hl: #ffffff;
  --pcv2-b-hi: #3b5791; --pcv2-b-fill: #1f2d4f; --pcv2-b-shade: #0b1225; --pcv2-b-ink: #0b1225;
  --pcv2-b-detail: #a9bfee; --pcv2-b-gloss: #b8cbf2; --pcv2-b-hl: #8fa9de;
  --pcv2-gem-hi: #fde68a; --pcv2-gem: var(--warn); --pcv2-gem-lo: #a16207;
  --pcv2-ground: #000000; --pcv2-ground-a: .12; --pcv2-ground-core-a: .2;
  --pcv2-stroke: 3.6; --pcv2-b-stroke: 3.6;
}
:root[data-theme="dark"] {
  --pcv2-b-ink: #b8cbf2; --pcv2-b-stroke: 4;
  --pcv2-ground-a: .32; --pcv2-ground-core-a: .5;
}
.pc { display: block; overflow: visible; user-select: none; pointer-events: none; }
.pc.v2.w { --pc-hi: var(--pcv2-w-hi); --pc-fill: var(--pcv2-w-fill); --pc-shade: var(--pcv2-w-shade); --pc-ink: var(--pcv2-w-ink); --pc-detail: var(--pcv2-w-detail); --pc-gloss: var(--pcv2-w-gloss); --pc-hl: var(--pcv2-w-hl); --pc-sw: var(--pcv2-stroke); }
.pc.v2.b { --pc-hi: var(--pcv2-b-hi); --pc-fill: var(--pcv2-b-fill); --pc-shade: var(--pcv2-b-shade); --pc-ink: var(--pcv2-b-ink); --pc-detail: var(--pcv2-b-detail); --pc-gloss: var(--pcv2-b-gloss); --pc-hl: var(--pcv2-b-hl); --pc-sw: var(--pcv2-b-stroke); }
.pc.v2 .s0 { stop-color: var(--pc-hi); } .pc.v2 .s1 { stop-color: var(--pc-fill); } .pc.v2 .s2 { stop-color: var(--pc-shade); }
.pc.v2 .g0 { stop-color: var(--pcv2-gem-hi); } .pc.v2 .g1 { stop-color: var(--pcv2-gem); } .pc.v2 .g2 { stop-color: var(--pcv2-gem-lo); }
.pc.v2 .bd { stroke: var(--pc-ink); stroke-width: var(--pc-sw); stroke-linejoin: round; }
.pc.v2 .bn { fill: var(--pc-shade); stroke: var(--pc-ink); stroke-width: var(--pc-sw); stroke-linejoin: round; }
.pc.v2 .gm { stroke: var(--pc-ink); stroke-width: 2.6; stroke-linejoin: round; }
.pc.v2 .gs { fill: var(--pcv2-ground); opacity: var(--pcv2-ground-a); }
.pc.v2 .gs.core { opacity: var(--pcv2-ground-core-a); }
.pc.v2 .dt { fill: none; stroke: var(--pc-detail); stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round; }
.pc.v2 .df { fill: var(--pc-detail); }
.pc.v2 .hl { fill: none; stroke: var(--pc-hl); stroke-width: 3.2; stroke-linecap: round; opacity: .9; }
.pc.v2.b .hl { opacity: .55; }
.pc.v2 .gl { fill: var(--pc-gloss); opacity: .85; }
.pc.v2.b .gl { opacity: .4; }
.pc.v2 .mn { stroke: var(--pc-ink); stroke-width: 2.4; }
.pc.v2 .ey { fill: var(--pcv2-w-ink); }
.pc.v2.b .ey { fill: var(--pcv2-gem-hi); }
.pc.v2 .gt { fill: #ffffff; }
.pc.v2.b .gt { fill: var(--pcv2-b-fill); }
/* dark mode: lift the board and give ink pieces a pale rim so they never sink into dark squares */
:root[data-theme="dark"] .chess button { background: color-mix(in oklab, var(--accent) 16%, var(--surface)); }
:root[data-theme="dark"] .chess button.dark { background: color-mix(in oklab, var(--accent) 40%, var(--surface)); }
:root[data-theme="dark"] .chess button.last { background: color-mix(in oklab, var(--warn) 40%, var(--surface)); }
.chess .pc { width: 84%; height: 84%; transition: transform var(--motion-fast) var(--ease-standard); }
.chess .pc.landed { animation: land 260ms var(--ease-standard); }
@keyframes land { 0% { transform: translateY(-10%) scale(1.08); } 70% { transform: translateY(1%) scale(.98); } 100% { transform: none; } }
.chess button.sel { box-shadow: inset 0 0 0 4px var(--accent); }
.chess button.sel .pc { transform: translateY(-6%) scale(1.08); }
.chess button.sel .pc.v2 .gs { opacity: calc(var(--pcv2-ground-a) * .6); }
@media (hover: hover) { .chess button:hover .pc { transform: translateY(-3%); } }
/* Capture effect (DEV-045, design/ds-005/chess-v2-notes.md): 460 ms in a layer over the board. It is clipped by .chess, takes no tap and
   animates only transform and opacity, so nothing on the page moves. Flip board turns the node back, so the taken piece stands up and shards fall down. */
.chess-fx { position: absolute; inset: 0; z-index: 3; overflow: hidden; pointer-events: none; }
.cfx { position: absolute; width: 12.5%; height: 12.5%; display: grid; place-items: center; }
.board-wrap.flipped .board .cfx { rotate: 180deg; }
.board-wrap.flipped .board .cfx .pc { rotate: none; }
.cfx > .cfx-victim, .cfx > .cfx-ring { grid-area: 1 / 1; }
.cfx.w { --sh-fill: var(--pcv2-w-fill); --sh-ink: var(--pcv2-w-ink); }
.cfx.b { --sh-fill: var(--pcv2-b-fill); --sh-ink: var(--pcv2-b-ink); }
.cfx-victim { width: 84%; height: 84%; transform-origin: 50% 70%; animation: cfx-victim 260ms linear both; }
.chess .cfx-victim .pc { width: 100%; height: 100%; transition: none; }
.cfx-ring { width: 86%; height: 86%; border-radius: 50%; border: max(2px, calc(var(--s) * .05)) solid color-mix(in oklab, var(--warn) 75%, var(--fg)); opacity: 0; animation: cfx-ring 320ms var(--ease-standard) 60ms forwards; }
.cfx-p { position: absolute; left: 50%; top: 50%; width: var(--z); height: var(--z); opacity: 0; border: max(1px, calc(var(--s) * .02)) solid var(--sh-ink); animation: cfx-p 360ms linear 100ms forwards; }
.cfx-p.shard { height: calc(var(--z) * .62); border-radius: 30%; background: var(--sh-fill); }
.cfx-p.dot { border-radius: 50%; background: var(--pcv2-gem); }
@keyframes cfx-victim {
  0% { transform: translateY(0) scale(1); opacity: 1; animation-timing-function: cubic-bezier(.2, 0, 0, 1); }
  53.85% { transform: translateY(-4%) scale(1.18); opacity: 1; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  100% { transform: translateY(-2%) scale(.35); opacity: 0; }
}
@keyframes cfx-ring { 0% { transform: scale(.3); opacity: .9; } 100% { transform: scale(1.15); opacity: 0; } }
@keyframes cfx-p {
  0% { transform: translate(-50%, -50%) translate(0, 0) rotate(0deg) scale(.6); opacity: 1; animation-timing-function: cubic-bezier(.2, 0, 0, 1); }
  55% { transform: translate(-50%, -50%) translate(calc(var(--dx) * .78), calc(var(--dy) * .78 - var(--lift))) rotate(calc(var(--r) * .6)) scale(1); opacity: 1; animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  100% { transform: translate(-50%, -50%) translate(var(--dx), calc(var(--dy) + var(--fall))) rotate(var(--r)) scale(.5); opacity: 0; }
}
@keyframes cfx-fade { from { opacity: 1; } to { opacity: 0; } }
/* !important: the general reduced-motion rule (section 17) sets every animation to 1 ms with !important; this fade is the notes' 150 ms. */
@media (prefers-reduced-motion: reduce) {
  .chess-fx .cfx-ring, .chess-fx .cfx-p { display: none; }
  .chess-fx .cfx-victim { animation: cfx-fade 150ms linear forwards !important; }
  .chess .pc.landed { animation: none !important; }
  .chess button.sel .pc, .chess button:hover .pc { transform: none; }
}
/* captured pieces strip in the seat bar */
/* FR-46 (QC-033 L-1), every game: captured pieces stay on one row and overlap, with a count; the seat bar keeps its height at 0 or 15 pieces. */
.caps { display: flex; align-items: center; flex-wrap: nowrap; flex: 0 1000 auto; min-width: 0; height: 22px; overflow: hidden; margin-left: var(--space-2); }
.caps .cap { display: block; flex: 0 1 20px; min-width: 4px; height: 20px; }
.caps .cap:last-of-type { flex: none; width: 20px; }
/* The count comes first: if the row is very short it is the pieces that get clipped, never the number. */
.caps .cap-n { flex: none; order: -2; margin-right: 4px; font-size: var(--text-xs); color: var(--muted); }
.caps .prisoners { white-space: nowrap; }
.seat-bar .side, .seat-bar .clock { flex: none; }
.caps .pc { display: block; width: 20px; height: 20px; }
.caps .pc.v2 .gs { display: none; }
.caps .lead { flex: none; order: -1; margin-right: 4px; font-size: var(--text-xs); color: var(--muted); }
.caps:empty { display: none; }
.chess button.last { background: color-mix(in oklab, var(--warn) 38%, var(--surface)); }
.chess button.target::after { content: ""; position: absolute; width: 28%; height: 28%; border-radius: 50%; background: color-mix(in oklab, var(--fg) 28%, transparent); }
.chess button.target.capture::after { width: 86%; height: 86%; background: none; border: 4px solid color-mix(in oklab, var(--fg) 28%, transparent); }
.coord { position: absolute; font-size: 10px; font-weight: 600; color: color-mix(in oklab, var(--fg) 80%, transparent); font-family: var(--font-mono); }
.coord.file { right: 4px; bottom: 2px; }
.coord.rank { left: 4px; top: 2px; }

/* Xiangqi board */
.xiangqi { position: relative; aspect-ratio: 9 / 10; border-radius: var(--radius-md); background: var(--game-tint); border: 1px solid color-mix(in oklab, var(--game) 25%, var(--border)); }
.xiangqi svg.grid { position: absolute; inset: 0; width: 100%; height: 100%; }
.xiangqi svg.grid line, .xiangqi svg.grid rect { stroke: color-mix(in oklab, var(--game) 45%, var(--border)); stroke-width: .045; fill: none; }
.xiangqi svg.grid text { fill: color-mix(in oklab, var(--game) 55%, var(--muted)); font-size: .42px; font-family: "Songti SC", "SimSun", serif; }
.xiangqi .pt { position: absolute; width: calc(100% / 9); height: 10%; border: 0; padding: 0; background: none; cursor: pointer; display: grid; place-items: center; }
.xiangqi .xq-disc { width: 84%; height: auto; border-width: 2px; font-size: clamp(14px, 3.6vw, 28px); box-shadow: 0 2px 0 color-mix(in oklab, var(--fg) 25%, transparent); transition: transform var(--motion-fast) var(--ease-standard); }
.xiangqi .pt.sel .xq-disc { transform: translateY(-3px) scale(1.08); box-shadow: 0 0 0 3px var(--accent); }
.xiangqi .pt.last .xq-disc { box-shadow: 0 0 0 3px color-mix(in oklab, var(--warn) 70%, transparent); }
.xiangqi .pt.last:empty::after { content: ""; width: 34%; height: 34%; border: 2px solid color-mix(in oklab, var(--warn) 80%, var(--fg)); border-radius: 4px; }
.xiangqi .pt.target::before { content: ""; position: absolute; width: 24%; height: 24%; border-radius: 50%; background: color-mix(in oklab, var(--accent) 60%, transparent); z-index: 1; }
.xiangqi .pt.target .xq-disc { box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 60%, transparent); }

/* Block Battle */
.bb { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-4); align-items: start; }
.bb-main { position: relative; display: grid; grid-template-columns: repeat(10, 1fr); aspect-ratio: 1 / 2; max-height: calc(100dvh - 300px); margin-inline: auto; width: 100%; max-width: 340px; gap: 2px; padding: 6px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--fg) 88%, var(--surface)); }
:root[data-theme="dark"] .bb-main { background: color-mix(in oklab, var(--bg) 70%, black); border: 1px solid var(--border); }
.bb-main i, .bb-mini i { border-radius: 3px; background: color-mix(in oklab, var(--surface) 7%, transparent); }
.bb-side { display: grid; gap: var(--space-3); width: 112px; }
.bb-wait { position: absolute; inset: 0; display: grid; align-content: center; justify-items: center; gap: var(--space-1); padding: var(--space-3); text-align: center; border-radius: inherit; background: color-mix(in oklab, var(--surface) 90%, transparent); color: var(--fg); font-size: var(--text-sm); }
.bb-wait[hidden] { display: none; }
.bb-wait > b { font-size: var(--text-lg); }
.bb-panel { padding: var(--space-3); border-radius: var(--radius-md); background: var(--surface); border: 1px solid var(--border); font-size: var(--text-xs); color: var(--muted); }
.bb-panel b { display: block; font-size: var(--text-lg); color: var(--fg); font-family: var(--font-mono); }
.bb-mini { display: grid; grid-template-columns: repeat(10, 1fr); gap: 1px; padding: 3px; border-radius: 6px; background: color-mix(in oklab, var(--fg) 88%, var(--surface)); margin-top: 6px; }
.bb-mini i { aspect-ratio: 1; border-radius: 1px; }
.p0 { background: var(--warn) !important; }
.p1 { background: var(--accent) !important; }
.p2 { background: var(--success) !important; }
.p3 { background: var(--danger) !important; }
.p4 { background: color-mix(in oklab, var(--warn), var(--danger)) !important; }
.p5 { background: color-mix(in oklab, var(--accent), var(--success)) !important; }
.p6 { background: color-mix(in oklab, var(--accent), var(--danger)) !important; }
.pg { background: color-mix(in oklab, var(--muted) 70%, var(--surface)) !important; }
.bb-count { position: absolute; inset: 0; display: grid; place-items: center; font-size: var(--text-4xl); font-weight: 700; color: var(--warn); }
.bb-controls { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--space-2); width: 100%; max-width: 420px; }
.bb-controls button { min-height: 56px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--surface); font-size: var(--text-lg); cursor: pointer; touch-action: manipulation; }
.bb-controls button:active { background: var(--game-tint); }
.bb-controls button.drop { background: var(--warn); border-color: var(--warn); color: var(--fg); }
:root[data-theme="dark"] .bb-controls button.drop { color: var(--bg); }
.kbd-help { font-size: var(--text-xs); color: var(--muted); }
kbd { font-family: var(--font-mono); font-size: 11px; padding: 1px 5px; border-radius: 4px; border: 1px solid var(--border); background: var(--surface); }

/* ---------- 14. Sign in ---------- */
.auth { padding-block: var(--space-12); display: grid; place-items: start center; }
.auth-card { width: min(460px, 100%); }
.stepper { display: flex; gap: var(--space-2); margin-bottom: var(--space-6); }
.stepper span { flex: 1; height: 4px; border-radius: var(--radius-pill); background: var(--border); }
.stepper span.on { background: var(--accent); }
.google-slot { display: grid; gap: var(--space-2); padding: var(--space-4); border-radius: var(--radius-md); border: 1px dashed var(--border); background: var(--bg); }
.google-btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 44px; border-radius: var(--radius-pill); border: 1px solid var(--border); background: var(--surface); font-weight: 500; cursor: pointer; }
.g-mark { width: 18px; height: 18px; border-radius: 50%; background: conic-gradient(var(--danger) 0 25%, var(--warn) 0 50%, var(--success) 0 75%, var(--accent) 0); }
.keep-list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-2); font-size: var(--text-sm); }
.keep-list li { display: grid; grid-template-columns: 20px 1fr; gap: var(--space-2); }
.keep-list .yes { color: var(--success); font-weight: 700; }
.keep-list .no { color: var(--muted); font-weight: 700; }

/* ---------- 15. Account + history ---------- */
.page-head { padding-block: var(--space-8) var(--space-6); display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
.sum-card { padding: var(--space-4); border-radius: var(--radius-md); background: var(--game-tint); }
.sum-card h3 { font-size: var(--text-sm); display: flex; align-items: center; gap: 8px; }
.sum-card h3::before { content: ""; width: 10px; height: 10px; border-radius: 3px; background: var(--game); }
.wld { display: flex; gap: var(--space-4); margin-top: var(--space-3); font-size: var(--text-xs); color: var(--muted); }
.wld b { display: block; font-family: var(--font-mono); font-size: var(--text-xl); color: var(--fg); font-weight: 600; }
.wld-bar { display: flex; height: 6px; border-radius: var(--radius-pill); overflow: hidden; margin-top: var(--space-3); background: color-mix(in oklab, var(--fg) 8%, var(--surface)); }
.wld-bar i:nth-child(1) { background: var(--success); }
.wld-bar i:nth-child(2) { background: var(--danger); }
.wld-bar i:nth-child(3) { background: var(--muted); }
.filters { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-block: var(--space-6) var(--space-4); }
.matches { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.matches th { text-align: left; font-size: var(--text-xs); color: var(--muted); font-weight: 600; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.matches td { padding: 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.matches tr:last-child td { border-bottom: 0; }
.opp { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.opp span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.empty { text-align: center; padding: var(--space-12) var(--space-6); display: grid; gap: var(--space-3); justify-items: center; }
.empty-art { display: flex; gap: 6px; margin-bottom: var(--space-2); }
.empty-art i { width: 22px; height: 22px; border-radius: 6px; }
.settings { display: grid; gap: var(--space-4); max-width: 720px; }
.setting-row { display: grid; grid-template-columns: 1fr auto; gap: var(--space-4); align-items: center; }
.danger-zone { border-color: color-mix(in oklab, var(--danger) 30%, var(--border)); }

/* ---------- 16. Privacy ---------- */
.legal { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: var(--space-12); padding-block: var(--space-8); }
.toc { position: sticky; top: 88px; align-self: start; display: grid; gap: 2px; font-size: var(--text-sm); }
.toc a { color: var(--muted); padding: 6px 10px; border-radius: var(--radius-sm); text-decoration: none; }
.toc a:hover, .toc a.on { color: var(--fg); background: color-mix(in oklab, var(--fg) 5%, transparent); }
.legal article { max-width: 68ch; }
.legal section { padding-block: var(--space-6); border-top: 1px solid var(--border); scroll-margin-top: 80px; }
.legal section h2 { font-size: var(--text-lg); display: flex; gap: var(--space-3); align-items: baseline; }
.legal section h2 span { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); font-weight: 500; }
.legal p, .legal li { color: color-mix(in oklab, var(--fg) 85%, var(--muted)); }
.legal p + p, .legal p + ul, .legal ul + p { margin-top: var(--space-3); }
.legal ul { padding-left: 20px; margin: var(--space-3) 0 0; }
.store-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); margin-top: var(--space-3); }
.store-table th, .store-table td { text-align: left; padding: 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
.store-table th { font-size: var(--text-xs); color: var(--muted); }
.store-table code { font-family: var(--font-mono); font-size: var(--text-xs); }

/* ---------- 16b. Home tiles: whole tile = Play a friend (stretched link); .tile-actions is a container for more buttons ---------- */
.tile-link { color: inherit; text-decoration: none !important; }
.tile-link::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.tile-link:focus-visible { box-shadow: none; }
.game-tile:has(.tile-link:focus-visible) { box-shadow: var(--focus-ring); }
.tile-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); padding: 0 var(--space-5) var(--space-5); } /* QC-041 L-7: the buttons wrap at every width instead of spilling out of the tile */
.tile-cta { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); font-weight: 600; color: var(--game-ink); }
.tile-cta .icon { width: 16px; height: 16px; transition: transform var(--motion-base) var(--ease-standard); }
.game-tile:hover .tile-cta .icon { transform: translateX(3px); }
.tile-actions .btn { position: relative; z-index: 2; min-height: 40px; padding: 8px 12px; }

/* ---------- 16c. App-only additions (the prototype had no server: seats, modal, art fallbacks) ---------- */
.avatar::after { content: attr(data-initial); }
.players { display: contents; }
.players .seat-bar:first-child { order: 0; }
.board-wrap { order: 1; }
.players .seat-bar:last-child { order: 2; }
.play-mobile-actions { order: 3; }
.seat-bar .you { color: var(--muted); font-weight: 500; }
.board { touch-action: manipulation; user-select: none; -webkit-user-select: none; }
.status-card .warn { color: color-mix(in oklab, var(--warn) 55%, var(--fg)); font-weight: 600; }
.chess button.chk { box-shadow: inset 0 0 0 4px var(--danger); }
.chess button.last.chk { background: color-mix(in oklab, var(--danger) 30%, var(--surface)); }
.xiangqi .pt.chk .xq-disc { box-shadow: 0 0 0 3px var(--danger); }
.wait-card h1 { font-size: clamp(var(--text-xl), 4.2vw, var(--text-3xl)); }
.wait-card h1 .send { display: block; margin-top: var(--space-2); font-size: var(--text-base); font-weight: 400; color: var(--muted); letter-spacing: 0; }
.gomoku .stone .sr-only { position: absolute; }
.tile-art .tile-icon { font-size: 56px; line-height: 1; }
.modal { position: fixed; inset: 0; z-index: 50; display: grid; place-items: start center; padding: var(--space-12) var(--space-3); overflow-y: auto; background: color-mix(in oklab, var(--fg) 35%, transparent); }
.modal .auth-card { animation: pop var(--motion-base) var(--ease-standard); }
.google-slot .gsi { display: grid; justify-items: center; min-height: 44px; }
.me-chip .who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tabbar button { all: unset; box-sizing: border-box; display: grid; justify-items: center; gap: 2px; padding: 8px 4px; min-height: 56px; font-size: 11px; font-weight: 600; color: var(--muted); cursor: pointer; }
.tabbar button:focus-visible { box-shadow: var(--focus-ring); }
body[data-chrome="min"] .footer, body[data-chrome="min"] .tabbar { display: none; }
html[data-embed="1"] .topbar, html[data-embed="1"] .footer, html[data-embed="1"] .tabbar { display: none; } /* DEV-049: inside the app */
.bb canvas { display: block; }
.bb-main canvas { width: 100%; height: 100%; }
.bb-mini { display: block; }
.bb-mini canvas { width: 100%; height: auto; border-radius: 2px; }
.empty h1 { font-size: var(--text-2xl); }
.page-head h1 { font-size: var(--text-2xl); overflow-wrap: anywhere; }

/* ---------- 16d. Practice mode (FR-31…FR-35, DEV-006) ---------- */
.avatar.bot { --av: var(--fg); background: var(--fg); color: var(--bg); box-shadow: none; }
.avatar.bot .icon { width: 60%; height: 60%; }
dialog.practice { width: min(520px, calc(100vw - 24px)); }
dialog.practice h2 { font-size: var(--text-lg); }
.seg-field { border: 0; padding: 0; margin: var(--space-5) 0 0; min-width: 0; }
.seg-field legend { font-size: var(--text-sm); font-weight: 600; margin-bottom: var(--space-2); padding: 0; }
.seg { display: grid; gap: 6px; }
.seg-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.seg-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.seg-opt { position: relative; }
.seg-opt input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.seg-opt span { display: grid; place-items: center; min-height: 44px; padding: 6px 8px; text-align: center; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--surface); font-size: var(--text-sm); font-weight: 600; transition: background var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard); }
.seg-opt:hover span { border-color: color-mix(in oklab, var(--fg) 35%, var(--border)); }
.seg-opt input:checked + span { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.seg-opt[data-game] input:checked + span { background: var(--game-tint); color: var(--game-ink); border-color: var(--game); box-shadow: inset 0 0 0 1px var(--game); }
.seg-opt input:focus-visible + span { box-shadow: var(--focus-ring); }
.seg-field .field-help { margin-top: var(--space-2); min-height: 1.5em; }
.practice-badge { margin-bottom: var(--space-3); }
.status-note { font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-3); }
.side-level { justify-self: start; }
.play[data-mode="practice"] .side-actions { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }
.play[data-mode="practice"] .play-mobile-actions { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

.tile-actions .btn-practice .icon { width: 18px; height: 18px; }
.practice-dialog-note { margin-top: var(--space-3); }

/* ---------- 17. Responsive ---------- */
/* laptop / large tablet */
@media (max-width: 1180px) {
  .game-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tile-art { aspect-ratio: 16 / 9; }
  .play { grid-template-columns: minmax(0, 1fr) 300px; gap: var(--space-6); }
  .summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* tablet portrait & foldables: side panel moves under the board */
@media (max-width: 960px) {
  .container { padding-inline: var(--container-gutter-tablet); }
  .hero { grid-template-columns: 1fr; gap: var(--space-8); padding-block: var(--space-8) var(--space-6); }
  .play { grid-template-columns: 1fr; padding-block: var(--space-4); }
  .play-side { position: static; grid-template-columns: 1fr 1fr; }
  .play-side .status-card { grid-column: 1 / -1; }
  .wait { grid-template-columns: 1fr; padding-block: var(--space-8); }
  .legal { grid-template-columns: 1fr; gap: var(--space-4); }
  .toc { position: static; display: flex; overflow-x: auto; gap: var(--space-1); padding-bottom: var(--space-2); }
  .toc a { white-space: nowrap; border: 1px solid var(--border); border-radius: var(--radius-pill); }
  .recent { grid-template-columns: 1fr; }
}
/* phones: bottom tab bar, compact chrome, board edge to edge */
@media (max-width: 720px) {
  .nav, .topbar .hide-sm { display: none; }
  .topbar .container { height: 56px; }
  .tabbar {
    display: grid; grid-template-columns: repeat(3, 1fr); position: sticky; bottom: 0; z-index: 20;
    background: color-mix(in oklab, var(--surface) 92%, transparent); backdrop-filter: blur(10px);
    border-top: 1px solid var(--border); padding-bottom: env(safe-area-inset-bottom);
  }
  .tabbar a { display: grid; justify-items: center; gap: 2px; padding: 8px 4px; min-height: 56px; font-size: 11px; font-weight: 600; color: var(--muted); text-decoration: none; }
  .tabbar a[aria-current="page"] { color: var(--fg); }
  .footer { margin-top: var(--space-8); }
  .game-grid { grid-template-columns: 1fr; gap: var(--space-3); }
  .game-tile { flex-direction: row; align-items: stretch; }
  .game-tile:hover { transform: none; }
  .tile-art { aspect-ratio: auto; width: 112px; flex: none; }
  .tile-body { padding: var(--space-4); gap: 4px; }
  .tile-body h3 { font-size: var(--text-base); }
  .tile-go { display: none; }
  .tile-meta { padding-top: var(--space-2); }
  .game-tile { flex-wrap: wrap; }
  .tile-body { flex: 1 1 0; min-width: 0; }
  .tile-actions { flex: 1 0 100%; padding: var(--space-3) var(--space-4); border-top: 1px solid var(--border); }
  .seg-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .art-gomoku { width: 80%; } .art-chess { width: 70%; } .art-blocks { width: 70%; }
  .art-xq { gap: 4px; } .xq-disc { width: 34px; font-size: 16px; } .art-xq .xq-disc:nth-child(3) { display: none; }
  .hero .lead { font-size: var(--text-base); }
  .duo { padding: var(--space-4); }
  .duo-board { display: none; }
  .play-side { grid-template-columns: 1fr; order: -1; }
  .play { gap: var(--space-3); }
  .play-side .moves, .play-side .side-actions, .play-side .side-extra { display: none; }
  .play { --board-max: 640px; }
  .play-mobile-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); width: 100%; }
  .status-card { padding: var(--space-4); }
  .status-card .status-line { font-size: var(--text-lg); }
  .bb { grid-template-columns: minmax(0, 1fr) 84px; gap: var(--space-2); }
  .bb-side { width: 84px; }
  .bb-main { max-height: calc(100dvh - 420px); }
  [data-game="blocks"] .status-sub:not(.warn) { display: none; } /* QC-033 L-7: "Opponent disconnected" still shows */
  [data-game="blocks"] .seat-bar { padding-block: 4px; }
  [data-game="blocks"] .seat-bar .who > span { display: none; }
  .seats { grid-template-columns: 1fr; }
  .vs { justify-self: center; }
  .summary { grid-template-columns: 1fr 1fr; gap: var(--space-2); }
  .matches thead { display: none; }
  .matches tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "opp res" "game date"; align-items: center; gap: 6px var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
  .matches td { padding: 0; border: 0; min-width: 0; }
  .matches td.c-opp { grid-area: opp; } .matches td.c-res { grid-area: res; justify-self: end; }
  .matches td.c-game { grid-area: game; } .matches td.c-date { grid-area: date; justify-self: end; font-size: var(--text-xs); color: var(--muted); }
  .matches td.c-moves { display: none; }
  .setting-row { grid-template-columns: 1fr; }
  .toast-host { bottom: 76px; }
}
@media (max-width: 400px) {
  .container { padding-inline: var(--container-gutter-phone); }
  .me-chip span { max-width: 96px; }
  .tile-art { width: 92px; }
  .sum-card { padding: var(--space-3); }
  .wld { gap: var(--space-3); }
  .wld b { font-size: var(--text-lg); }
}
/* wide screens: give boards more room */
@media (min-width: 1600px) {
  :root { --container-max: 1360px; }
  .play { --board-max: min(760px, calc(100dvh - 236px)); grid-template-columns: minmax(0, 1fr) 380px; }
  .play[data-game="xiangqi"], .play[data-game="jieqi"] { --board-max: min(760px, calc((100dvh - 236px) * .9)); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
  .duo-link { left: 40%; opacity: 1; }
}

/* ---------- 18. Block Battle draws on canvas in the app (the prototype used DOM cells) ---------- */
.bb { --bb-h: calc(100dvh - 290px); }
.bb-controls { margin: var(--space-3) auto 0; }
.bb-main { display: block; aspect-ratio: auto; max-height: none; }
.bb-main { width: fit-content; max-width: 100%; margin-inline: auto; }
.bb-main canvas { display: block; width: min(336px, calc(var(--bb-h) / 2), calc(100vw - 128px)); height: auto; aspect-ratio: 1 / 2; }
.bb-mini canvas { width: 100%; height: auto; aspect-ratio: 1 / 2; }
.bb-side { align-content: start; }
.bb-panel span[data-k] { font-size: var(--text-xs); }
@media (max-width: 720px) { .bb { --bb-h: calc(100dvh - 440px); } .bb-main { max-height: none; } }
.seat-bar .who b span { font-size: inherit; color: inherit; }
.seat-bar .who b .you { color: var(--muted); font-weight: 500; }
#games, #how { scroll-margin-top: 80px; }
.status-card .status-line.warn { color: color-mix(in oklab, var(--warn) 55%, var(--fg)); }
.legal .warn { color: color-mix(in oklab, var(--warn) 55%, var(--fg)); }
.legal code { font-family: var(--font-mono); font-size: var(--text-sm); }
:root[data-theme="dark"] .btn-danger-solid { color: var(--bg); }
:root[data-theme="dark"] .coord { color: color-mix(in oklab, var(--fg) 80%, transparent); }
.topbar-end { min-width: 0; }
.me-chip { min-width: 0; }

/* ---------- Clocks (FR-36…FR-38, DEV-008) ---------- */
.clock { display: grid; justify-items: end; gap: 4px; min-width: 76px; }
.clock-main { min-width: calc(5ch + 20px); text-align: center; /* 10:00 and 9:59 are as wide (DEV-034) */ font-size: var(--text-lg); font-weight: 600; padding: 2px 10px; border-radius: var(--radius-sm); background: color-mix(in oklab, var(--fg) 5%, var(--surface)); color: var(--muted); transition: background var(--motion-base), color var(--motion-base); }
.clock-move { position: relative; width: 100%; height: 4px; border-radius: 99px; background: color-mix(in oklab, var(--fg) 8%, transparent); overflow: hidden; }
.clock-move i { position: absolute; inset: 0; transform-origin: left; background: var(--game); transition: transform 200ms linear; }
.clock:not(.running) .clock-move i { opacity: .25; }
.clock.running .clock-main { background: var(--fg); color: var(--bg); }
/* DEV-034: the move-time line always holds its place, hidden unless on turn: a change of turn must not make the seat bar taller (+20.5 px measured). */
.clock::after { content: "Move 0:00"; font-size: 11px; font-family: var(--font-mono); color: var(--muted); visibility: hidden; }
.clock.running::after { content: "Move " attr(data-move); visibility: visible; }
.clock.low .clock-main { background: var(--danger); color: var(--accent-on); animation: low-pulse 1s ease-in-out infinite; }
.clock.low .clock-move i { background: var(--danger); }
.clock.low::after { color: var(--danger); font-weight: 600; }
:root[data-theme="dark"] .clock.low .clock-main { color: var(--bg); }
.seat-bar .clock + .side, .seat-bar .side + .clock { margin-left: var(--space-2); }
.status-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--space-3); }
.seg-opt span small { display: block; font-size: var(--text-xs); font-weight: 500; opacity: .8; }

/* ---------- Spectator (FR-42…FR-44, DEV-010) ---------- */
.badge-live { background: color-mix(in oklab, var(--danger) 12%, var(--surface)); color: color-mix(in oklab, var(--danger) 80%, var(--fg)); }
.badge-live::before { animation: breathe 1.2s ease-in-out infinite; }
.watchers { animation: pop var(--motion-base) var(--ease-standard); }
.status-tags .badge .icon { width: 14px; height: 14px; }
.play[data-mode="watch"] .side-actions { grid-template-columns: 1fr 1fr; }
.play[data-mode="watch"] .side-actions .btn-ghost { grid-column: 1 / -1; }
.play[data-mode="watch"] .play-mobile-actions .btn-ghost { grid-column: 1 / -1; }
/* Flip board: the whole board turns 180° on this screen only. Anything that must stay readable (pieces, discs, labels,
   and a future game's glyphs: give them class "upright") is turned back. */
.board { transition: rotate 300ms var(--ease-standard); }
.board-wrap.flipped .board { rotate: 180deg; }
.board-wrap.flipped .board :is(.pc, .xq-disc, .coord, .upright) { rotate: 180deg; }
.board-wrap.flipped .board svg .upright { transform-box: fill-box; transform-origin: center; } /* an SVG glyph turns about itself, not about the corner of the picture (QC-022 L-1) */
@media (prefers-reduced-motion: reduce) { .board { transition: none; } }
.link-rows { display: grid; gap: var(--space-3); }
.link-label { font-size: var(--text-sm); font-weight: 600; display: flex; align-items: center; gap: 6px; }
.link-label .icon { width: 16px; height: 16px; flex: none; }
/* While the board turns, its corners swing out for a moment: clip them so the page never gets a sideways scrollbar. */
.play[data-mode="watch"] .board-wrap { overflow-x: clip; }

/* ---------- 19. Go (DEV-009, FR-40, FR-41): board, counting bar, captured count ---------- */
[data-game="go"] { --game: var(--fg); }
.go { position: relative; aspect-ratio: 1; border-radius: var(--radius-md); background: color-mix(in oklab, var(--warn) 14%, var(--surface)); border: 1px solid color-mix(in oklab, var(--warn) 30%, var(--border)); container-type: inline-size; }
:root[data-theme="dark"] .go { background: color-mix(in oklab, var(--warn) 22%, var(--surface)); }
.go svg.grid { position: absolute; inset: 0; width: 100%; height: 100%; }
.go svg.grid line { stroke: color-mix(in oklab, var(--fg) 55%, transparent); }
.go svg.grid circle { fill: color-mix(in oklab, var(--fg) 70%, transparent); }
.go .pt { position: absolute; border: 0; padding: 0; background: none; cursor: pointer; display: grid; place-items: center; }
.go .st { width: 92%; height: 92%; border-radius: 50%; animation: drop var(--motion-base) var(--ease-standard); }
.go .st.b { background: radial-gradient(circle at 35% 30%, color-mix(in oklab, var(--fg) 60%, white) 0 8%, color-mix(in oklab, var(--accent) 10%, black) 45%); box-shadow: 0 2px 2px color-mix(in oklab, black 35%, transparent); }
.go .st.w { background: radial-gradient(circle at 35% 30%, white 0 25%, color-mix(in oklab, var(--accent) 6%, white) 60%, color-mix(in oklab, var(--fg) 18%, white)); box-shadow: 0 2px 2px color-mix(in oklab, black 25%, transparent), inset 0 0 0 1px color-mix(in oklab, black 12%, transparent); }
.go .pt.last .st::after { content: ""; display: block; width: 34%; height: 34%; margin: 33%; border-radius: 50%; border: 2px solid var(--danger); }
.go.my-turn .pt:empty:hover::before { content: ""; width: 70%; height: 70%; border-radius: 50%; background: color-mix(in oklab, var(--fg) 25%, transparent); }
.go .pt.dead .st { opacity: .35; }
.go .pt.dead::after { content: ""; position: absolute; width: 36%; height: 36%; background: var(--danger); clip-path: polygon(20% 0, 50% 30%, 80% 0, 100% 20%, 70% 50%, 100% 80%, 80% 100%, 50% 70%, 20% 100%, 0 80%, 30% 50%, 0 20%); }
.go .pt.terr-b::after, .go .pt.terr-w::after { content: ""; position: absolute; width: 30%; height: 30%; border-radius: 2px; }
.go .pt.terr-b::after { background: color-mix(in oklab, var(--accent) 10%, black); }
.go .pt.terr-w::after { background: white; box-shadow: 0 0 0 1px color-mix(in oklab, black 30%, transparent); }
.caps .prisoners { font-size: var(--text-xs); color: var(--muted); font-weight: 600; }
.go.my-turn .pt.pend:empty::before, .go .pt.pend::before { content: ""; position: relative; z-index: 2; width: 125%; height: 125%; border-radius: 50%; background: color-mix(in oklab, var(--accent) 40%, transparent); box-shadow: 0 0 0 2px var(--fg); }
.go .pt:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 4px; }
.go-bar { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin-top: var(--space-3); font-size: var(--text-sm); }
.go-bar[hidden] { display: none; }
.go-bar b, .go-bar .go-result { font-family: var(--font-mono); }
.go-bar .go-result { font-size: var(--text-lg); font-weight: 600; }
.go-bar .hint { color: var(--muted); font-size: var(--text-xs); flex-basis: 100%; text-align: center; }
.go-bar .hint { min-height: 1.5em; } /* DEV-034: the line under Pass keeps its place when it empties */
@media (max-width: 359px) { .go-bar .hint { min-height: 3em; } } /* its longest text takes two lines here */
.go-bar .btn:disabled { opacity: 1; color: var(--muted); }
/* counting: a dead stone shows a red cross (it sits in the other side's territory); territory points are small squares, ringed in dark mode */
.go .pt.terr-b::after, .go .pt.terr-w::after { width: 26%; height: 26%; }
.go .pt.dead.terr-b::after, .go .pt.dead.terr-w::after { width: 40%; height: 40%; border-radius: 0; background: var(--danger); box-shadow: none; }
:root[data-theme="dark"] .go .pt.terr-b:not(.dead)::after { box-shadow: 0 0 0 1.5px white; }
/* the home tile picture */
.art-go { width: 64%; aspect-ratio: 1; position: relative; transform: rotate(-5deg); border-radius: 8px; background: color-mix(in oklab, var(--warn) 18%, var(--surface)); box-shadow: var(--elev-raised); background-image: linear-gradient(color-mix(in oklab, var(--fg) 45%, transparent) 1px, transparent 1px), linear-gradient(90deg, color-mix(in oklab, var(--fg) 45%, transparent) 1px, transparent 1px); background-size: 20% 20%; background-position: 10% 10%; }
.art-go i { position: absolute; width: 17%; height: 17%; border-radius: 50%; translate: -50% -50%; }
.art-go i.b { background: color-mix(in oklab, var(--accent) 10%, black); }
.art-go i.w { background: white; box-shadow: inset 0 0 0 1px color-mix(in oklab, black 20%, transparent); }
/* keep Pass / Accept score (the bar under the board) and my name bar on screen: the board gives up the height they need */
.play[data-game="go"] { --board-max: min(760px, calc(100dvh - 310px)); }
/* stacked layout (phones, tablets): while counting the bar goes above the board so Accept score stays on screen */
@media (max-width: 960px) {
  .play[data-game="go"] .board-wrap { display: flex; flex-direction: column; }
  .go-bar.counting { order: -1; margin: 0 0 var(--space-3); }
}

/* FR-46 (QC-033 L-1, L-15), continued. The card follows the board, and the board follows the height of the screen, so on a low screen the card needs a floor of its own.
   Wider than a phone the row sits beside the name: it gives way first, down to room for up to 16 overlapping pieces; then the name is cut. The clock and the side never give way. */
.play:not([data-game="blocks"]) .seat-bar { max-width: max(var(--board-max, 640px), 440px); }
@media (min-width: 561px) {
  .play:not([data-game="blocks"]) .seat-bar .who { flex: 0 1 auto; min-width: 64px; max-width: 45%; }
  .play:not([data-game="blocks"]) .seat-bar .caps:not(:empty) { min-width: 48px; }
  .play:not([data-game="blocks"]) .seat-bar .caps:has(.cap:nth-of-type(4)) { min-width: 92px; }
  .play:not([data-game="blocks"]) .seat-bar .caps:has(.prisoners) { flex-shrink: 0; } /* Go's count is words, not pieces that overlap */
}
/* Phone: the captured row takes the place of the presence line, so the bar is as high with 0 or 15 pieces. */
@media (max-width: 560px) {
  .play:not([data-game="blocks"]) .seat-bar { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; grid-template-rows: minmax(20px, 1fr) minmax(22px, 1fr); column-gap: var(--space-2); row-gap: 2px; align-items: center; }
  .play:not([data-game="blocks"]) .seat-bar .av-slot { grid-column: 1; grid-row: 1 / 3; }
  .play:not([data-game="blocks"]) .seat-bar .who { grid-column: 2; grid-row: 1 / 3; }
  .play:not([data-game="blocks"]) .seat-bar .side { grid-column: 3; grid-row: 1 / 3; margin-left: 0; }
  .play:not([data-game="blocks"]) .seat-bar .clock { grid-column: 4; grid-row: 1 / 3; margin-left: 0; }
  .play:not([data-game="blocks"]) .seat-bar .caps { grid-column: 2; grid-row: 2; margin-left: 0; }
  .play:not([data-game="blocks"]) .seat-bar:has(.caps:not(:empty)) .who { grid-column: 2 / 4; grid-row: 1; }
  .play:not([data-game="blocks"]) .seat-bar:has(.caps:not(:empty)):not(.offline) .presence { display: none; }
  .play:not([data-game="blocks"]) .seat-bar:has(.caps:not(:empty)) .side { grid-row: 2; }
  /* QC-032 L-8: offline, the name and "Offline" share the first line and the captured row keeps the second. */
  .play:not([data-game="blocks"]) .seat-bar.offline:has(.caps:not(:empty)) .who { display: flex; align-items: baseline; gap: var(--space-2); }
  .play:not([data-game="blocks"]) .seat-bar.offline:has(.caps:not(:empty)) .who b { min-width: 0; }
  .play:not([data-game="blocks"]) .seat-bar.offline:has(.caps:not(:empty)) .presence { flex: none; }
}
/* QC-033 L-12: the held Move line costs height on a phone; take it back from the padding, so Resign stays on the first screen. */
@media (max-width: 720px) {
  .play:not([data-game="blocks"]) .seat-bar { padding-block: 4px; }
  .seat-bar .clock { gap: 2px; }
  .play-mobile-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* QC-033 L-6: a phone on its side. The formula above left Go an 80 px board and 80 px seat bars; give it a usable board, the page scrolls like the other games. */
@media (max-height: 500px) and (min-width: 561px) { .play[data-game="go"] { --board-max: 320px; } }
/* ---------- Dark Xiangqi (DEV-033, FR-51): a hidden piece is a solid disc in its side's colour with a dashed ring and the letter of its square.
   Letter on disc and disc on board are at least 4.5:1 in both themes (tests-e2e/jieqi.e2e.mjs). */
:root { --jq-red: var(--mark-o); --jq-ink: #ffffff; --jq-black: #171717; }
:root[data-theme="dark"] { --jq-red: var(--danger); --jq-ink: #111111; --jq-black: #f2f2f2; }
.xq-disc.jq-hidden { position: relative; border-color: transparent; color: var(--jq-ink); font-family: var(--font-body); font-weight: 700; }
.xq-disc.jq-hidden.red { background: var(--jq-red); }
.xq-disc.jq-hidden.black { background: var(--jq-black); }
.xq-disc.jq-hidden::after { content: ""; position: absolute; inset: 7%; border-radius: 50%; border: 1.5px dashed var(--jq-ink); pointer-events: none; }
.xiangqi .xq-disc.jq-revealed { outline: 2px dashed currentColor; outline-offset: -6px; } /* it was still hidden when the game ended */
.caps .xq-disc { width: 20px; height: 20px; aspect-ratio: auto; font-size: 12px; border-width: 1px; box-shadow: none; }
.jieqi .pt.target.capture::before { display: none; } /* the ring on the disc marks a capture; a dot would sit on the letter */
/* Result card beside the board (DEV-033, QC-032 L-1): in the side panel on wide screens, between the status and the board on phones. */
.play-side .result { position: static; padding: 0; background: none; grid-column: 1 / -1; }
.play-side .result-card { width: 100%; padding: var(--space-4); }
.play-side .result-card h2 { font-size: var(--text-lg); }
.play-side .result-actions { margin-top: var(--space-3); }
.play-side .result-note { min-height: 0; margin-top: var(--space-2); }
.play-side .result-note:empty { display: none; }
@media (max-width: 960px) {
  .play:has(.play-side > .result) .play-side { order: -1; } /* tablet: the panel sits under the board, so Rematch would be off screen */
}
/* A long hint takes two lines; in practice "The computer is thinking" takes one. Keep the room for both, so the board stays put (QC-032 L-7). */
.play[data-game="jieqi"][data-mode="practice"] .status-sub { min-height: 2lh; }
/* Up to 15 discs a side: the token shows the side, and the row needs the room of the label to stay unclipped at 320 px. */
@media (max-width: 420px) { .play[data-game="jieqi"] .seat-bar .side-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); } }

/* FR-58: the colour on the last move goes 5 s after the move (lastfade.js sets .last-gone), and the square is its plain self again.
   Not: check, selection, the winning line. Go is not listed: its mark is a small ring on the stone, not a colour over the board. */
.board.last-gone .chess button.last:not(.chk) { background: color-mix(in oklab, var(--accent) 5%, var(--surface)); transition: background-color var(--last-fade, 600ms) linear; }
.board.last-gone .chess button.last.dark:not(.chk) { background: color-mix(in oklab, var(--accent) 26%, var(--surface)); }
:root[data-theme="dark"] .board.last-gone .chess button.last:not(.chk) { background: color-mix(in oklab, var(--accent) 16%, var(--surface)); }
:root[data-theme="dark"] .board.last-gone .chess button.last.dark:not(.chk) { background: color-mix(in oklab, var(--accent) 40%, var(--surface)); }
.board.last-gone .gomoku .last:not(.win) { background-color: transparent; transition: background-color var(--last-fade, 600ms) linear; }
.board.last-gone .xiangqi .pt.last:not(.sel, .chk, .target) .xq-disc { box-shadow: 0 2px 0 color-mix(in oklab, var(--fg) 25%, transparent); transition: box-shadow var(--last-fade, 600ms) linear, transform var(--motion-fast) var(--ease-standard); }
.board.last-gone .xiangqi .pt.last:empty::after { opacity: 0; transition: opacity var(--last-fade, 600ms) linear; }
@media (prefers-reduced-motion: reduce) { .board { --last-fade: 0s; } }

/* FR-59: the waiting card. One thing to press first; the watch link is folded away. On a phone a link box stacks, so a button never loses its words. */
.watch-more summary { display: flex; align-items: center; gap: 6px; min-height: 44px; font-size: var(--text-sm); font-weight: 600; color: var(--muted); cursor: pointer; }
.watch-more summary .icon { width: 16px; height: 16px; flex: none; }
.watch-more[open] summary { margin-bottom: var(--space-2); }
.link-box .btn { white-space: nowrap; flex: none; }
@media (max-width: 480px) {
  .link-box:not(.code-box) { flex-direction: column; }
  .link-box:not(.code-box) input { min-height: 36px; }
  .link-box:not(.code-box) .btn { width: 100%; justify-content: center; }
}
/* DEV-058 (FR-67): Pass & play face to face. Each player has a cluster on their own side; the far one is turned round, and so
   are the far side's pieces. Every line keeps one line and the buttons keep their width, so nothing moves when the turn changes. */
.face-side { width: 100%; max-width: max(var(--board-max, 640px), 440px); display: grid; gap: 6px; padding: 6px; border-radius: var(--radius-lg); background: var(--surface-2, var(--surface)); border: 1px solid var(--border); min-width: 0; }
.face-side.upside { transform: rotate(180deg); }
.face-side .seat-bar { max-width: none; border-color: transparent; }
.face-side .seat-bar.on-turn { border-color: var(--game); }
.players .face-side:first-child { order: 0; }
.players .face-side:last-child { order: 2; }
.face-note { order: 3; text-align: center; margin: 0; }
.face-row { display: flex; align-items: center; gap: var(--space-2); min-height: 48px; min-width: 0; }
.face-text { flex: 1 1 auto; min-width: 0; display: grid; padding-inline: 6px; }
.face-line { font-size: var(--text-lg); font-weight: 700; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.face-sub { font-size: var(--text-xs); color: var(--muted); line-height: 1.4; height: 2.8em; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow-wrap: anywhere; } /* QC-048 L-4: two lines, always the same height */
.face-btn { flex: none; min-height: 44px; min-width: 44px; padding-inline: 12px; }
.face-last { width: 8.5em; justify-content: center; } /* Resign, Confirm, Play again: one width */
.play[data-face] .board .pc.b, .play[data-face] .xiangqi .xq-disc.black { rotate: 180deg; }
/* QC-048 L-1: the board here is sized by the height left, so a disc's writing follows the board's own width, not the window's */
.play[data-face] .board-wrap { container-type: inline-size; }
.play[data-face] .xiangqi .xq-disc { font-size: clamp(9px, 5.2cqi, 28px); line-height: 1; overflow: hidden; }
/* QC-048 L-2: a short screen (phone, 320×568…): the clusters drop the second line and the avatar so the board keeps room */
@media (max-height: 700px) {
  .play[data-face] .face-side { gap: 2px; padding: 4px; }
  /* QC-048 L-7: one line under the turn line, inside the 44 px row; shown at the end (the reason), empty while playing */
  .play[data-face] .face-sub { height: 1.4em; -webkit-line-clamp: 1; }
  .play[data-face] .face-side:not(.ended) .face-sub { visibility: hidden; }
  .play[data-face] .face-row { min-height: 44px; }
  .play[data-face] .face-side .seat-bar { padding-block: 4px; }
  .play[data-face] .face-side .seat-bar .av-slot { display: none; }
  .play[data-face] .face-line { font-size: var(--text-md, 16px); }
  .play[data-face] { padding-block: var(--space-2); gap: var(--space-2); }
  .play[data-face] .play-stage { gap: var(--space-2); }
}
@media (max-width: 400px) { .face-btn { padding-inline: 8px; } .face-btn > span { font-size: var(--text-xs); } .face-last { width: 7.2em; } }

/* ---------- Tournaments (DEV-052, FR-73): /tournaments, /t/<code>; the content of design/ds-006-app/tournament-*.html in the web's look ---------- */
.t-page { padding-block: var(--space-8); display: grid; gap: var(--space-5); min-width: 0; }
.t-page > * { min-width: 0; }
.t-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.t-head h1 { font-size: var(--text-2xl); overflow-wrap: anywhere; margin-top: var(--space-2); }
.t-head .t-meta { margin-top: var(--space-1); }
.t-join { margin-top: 0; }
.t-list { display: grid; gap: var(--space-2); }
.t-item { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-3); color: var(--fg); text-decoration: none !important; padding: var(--space-4); }
.t-item:hover { border-color: color-mix(in oklab, var(--game) 45%, var(--border)); }
.t-item .gdot { width: 36px; height: 36px; border-radius: 10px; background: var(--game-tint); color: var(--game-ink); display: grid; place-items: center; font-weight: 700; }
.t-item-main { display: grid; gap: 2px; min-width: 0; }
.t-item-main b, .t-item-main span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.t-item .badge { white-space: normal; text-align: right; }
.t-empty { padding-block: var(--space-8); }
.t-entry { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-4); margin-top: var(--space-5); color: var(--fg); text-decoration: none !important; position: relative; }
.t-entry h2 { font-size: var(--text-lg); }
.t-entry-icon { width: 48px; height: 48px; border-radius: var(--radius-md); display: grid; place-items: center; background: color-mix(in oklab, var(--warn) 22%, var(--surface)); }
.t-entry .tile-go { position: static; }
.t-entry:hover { border-color: color-mix(in oklab, var(--fg) 35%, var(--border)); }
.t-lobby { display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
.t-code-card { display: grid; gap: var(--space-3); text-align: center; }
.t-code { font-size: clamp(28px, 9vw, 44px); letter-spacing: .08em; white-space: nowrap; }
.t-code-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.t-actions { display: grid; gap: var(--space-2); text-align: left; margin-top: var(--space-2); }
.t-players h2, .t-round h2, .t-standings h2 { font-size: var(--text-lg); }
.t-count { font-weight: 600; }
.t-plist { list-style: none; padding: 0; margin: var(--space-3) 0 0; display: grid; }
.t-prow { display: flex; align-items: center; gap: var(--space-3); min-height: 48px; border-bottom: 1px solid var(--border); min-width: 0; }
.t-prow:last-child { border-bottom: 0; }
.t-prow .t-who { flex: 1; }
.t-who { display: inline-flex; align-items: baseline; gap: 6px; min-width: 0; flex-wrap: wrap; }
.t-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; max-width: 100%; }
.t-who .you { color: var(--muted); font-weight: 500; }
.btn-sm { min-height: 36px; padding: 6px 12px; }
.t-mine { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; background: color-mix(in oklab, var(--accent) 7%, var(--surface)); border-color: color-mix(in oklab, var(--accent) 30%, var(--border)); }
.t-rtabs { display: flex; gap: var(--space-1); flex-wrap: wrap; }
.t-rtabs .chip { min-height: 32px; padding: 4px 10px; }
.t-pairs { width: 100%; border-collapse: collapse; margin-top: var(--space-3); table-layout: fixed; }
.t-pairs th { text-align: left; font-size: var(--text-xs); color: var(--muted); font-weight: 600; padding: 6px 4px; border-bottom: 1px solid var(--border); }
.t-pairs td { padding: 8px 4px; border-bottom: 1px solid var(--border); vertical-align: middle; min-width: 0; overflow: hidden; }
.t-pairs .t-bno { width: 44px; text-align: center; }
.t-pairs .t-res { width: 104px; text-align: right; white-space: nowrap; }
.t-pairs td.t-w, .t-pairs td.t-b { overflow: hidden; }
.t-pairs td .t-who { display: inline; }
.t-pairs td .t-name { display: inline; }
.t-pairs td.t-w, .t-pairs td.t-b { white-space: nowrap; text-overflow: ellipsis; }
.t-pairs tr.t-my td { background: color-mix(in oklab, var(--accent) 7%, var(--surface)); }
.t-pairs select { font: inherit; font-size: var(--text-sm); font-weight: 600; color: var(--accent); background: color-mix(in oklab, var(--accent) 8%, var(--surface)); border: 0; border-radius: var(--radius-sm); min-height: 36px; max-width: 100%; padding: 0 6px; }
.t-side { display: inline-block; width: 12px; height: 12px; border-radius: 3px; border: 1.5px solid var(--muted); margin-right: 6px; vertical-align: -1px; }
.t-side.w { background: #ffffff; }
.t-side.b { background: #1c1c1e; }
[data-game="xiangqi"] .t-side.w { background: var(--danger); border-color: var(--danger); }
.t-round-actions { display: grid; gap: var(--space-2); justify-items: start; margin-top: var(--space-4); }
.t-round-actions:empty { display: none; }
.t-scroll { overflow-x: auto; margin-top: var(--space-3); }
.t-table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
.t-table th, .t-table td { padding: 8px 6px; border-bottom: 1px solid var(--border); text-align: right; white-space: nowrap; }
.t-table th { font-size: var(--text-xs); color: var(--muted); font-weight: 600; }
.t-table .t-pcol { text-align: left; position: sticky; left: 0; background: var(--surface); max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
.t-table tr.t-my td { background: color-mix(in oklab, var(--accent) 7%, var(--surface)); }
.t-legend { display: grid; grid-template-columns: auto 1fr; gap: 2px var(--space-3); margin-top: var(--space-3); font-size: var(--text-xs); color: var(--muted); }
.t-legend dt { font-weight: 600; color: var(--fg); }
.t-legend dd { margin: 0; }
.t-tail { justify-content: flex-start; }
.t-note { align-items: center; }
/* Create box */
.t-steppers { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); margin-top: var(--space-5); }
.t-label { font-size: var(--text-sm); font-weight: 600; }
.t-stepper { display: grid; grid-template-columns: 44px minmax(0, 1fr) 44px; align-items: center; gap: 4px; }
.t-stepper .btn { padding: 0; font-size: var(--text-lg); }
.t-stepper output { text-align: center; font-weight: 600; font-size: var(--text-lg); }
.t-fixed { display: flex; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-5); font-size: var(--text-sm); }
.t-fixed span { font-weight: 600; }
.t-check { display: flex; gap: var(--space-2); align-items: center; margin-top: var(--space-4); font-size: var(--text-sm); font-weight: 600; min-height: 44px; }
.t-check input { width: 20px; height: 20px; }
.t-tb { list-style: none; padding: 0; margin: var(--space-3) 0 var(--space-2); display: grid; gap: 4px; }
.t-tb-row { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: var(--space-2); padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); cursor: grab; }
.t-tb-row.dragging { opacity: .5; }
.t-tb-n { width: 24px; height: 24px; border-radius: 50%; background: color-mix(in oklab, var(--fg) 8%, var(--surface)); display: grid; place-items: center; font-size: var(--text-xs); font-weight: 700; }
.t-tb-text { display: grid; min-width: 0; }
.t-tb-text b { font-size: var(--text-sm); }
.t-tb-move { display: flex; gap: 2px; }
.t-tb-move .icon-btn { width: 36px; height: 36px; }
.t-tb-move .icon-btn:disabled { opacity: .35; cursor: default; }
dialog.t-create { max-height: calc(100dvh - 24px); overflow-y: auto; }
/* A tournament room has no invite links: the opponent comes from the tournament page */
.wait.t-room .send, .wait.t-room .link-rows, .wait.t-room .steps-mini { display: none; }
@media (max-width: 720px) {
  .t-page { padding-block: var(--space-4); gap: var(--space-4); }
  .t-lobby { grid-template-columns: 1fr; }
  .t-head h1 { font-size: var(--text-xl); }
  /* phones: the two players of a board stack, as in the app design (pairing row) */
  .t-pairs thead { display: none; }
  .t-pairs, .t-pairs tbody { display: block; }
  .t-pairs tr { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; grid-template-areas: "bno w res" "bno b res"; align-items: center; column-gap: var(--space-2); border-bottom: 1px solid var(--border); padding: 6px 0; }
  .t-pairs td { border: 0; padding: 2px 0; width: auto !important; }
  .t-pairs td.t-bno { grid-area: bno; } .t-pairs td.t-w { grid-area: w; } .t-pairs td.t-b { grid-area: b; } .t-pairs td.t-res { grid-area: res; }
  .t-pairs select { width: 96px; }
  .t-pairs tr.t-my { background: color-mix(in oklab, var(--accent) 7%, var(--surface)); }
  .t-pairs tr.t-my td { background: transparent; }
  .t-entry { grid-template-columns: auto minmax(0, 1fr); }
  .t-entry .tile-go { display: none; }
}
.t-table .t-rm { min-height: 28px; padding: 2px 8px; margin-left: 4px; font-size: var(--text-xs); color: var(--danger); }
.t-table .t-pcol:has(.t-rm) { max-width: 260px; }

/* ---------- DEV-057 (FR-77): usage analytics consent bar and switch ---------- */
.consent-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; background: var(--surface); border-top: 1px solid var(--border);
  box-shadow: 0 -4px 16px color-mix(in oklab, var(--fg) 10%, transparent); padding-bottom: env(safe-area-inset-bottom); }
.consent-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); padding-block: var(--space-4); flex-wrap: wrap; }
.consent-inner p { margin: 0; font-size: var(--text-sm); max-width: 62ch; }
.consent-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); min-width: min(100%, 260px); }
.switch { appearance: none; width: 51px; height: 31px; border-radius: 999px; background: var(--border); position: relative; cursor: pointer; flex: none; margin: 0;
  transition: background var(--motion-fast) var(--ease-standard); }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.3); transition: transform var(--motion-fast) var(--ease-standard); }
.switch:checked { background: var(--success); }
.switch:checked::after { transform: translateX(20px); }
.switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 720px) { .consent-actions { width: 100%; } }
@media (max-width: 720px) { .play[data-face] .play-side { display: none; } } /* DEV-058: the phone page is the table; Games in the header leaves */
/* DEV-058: two clusters above and below the board: the board gets the height that is left (iPad landscape included) */
.play[data-face] { --board-max: max(200px, min(640px, calc(100dvh - 470px))); } /* first paint; practice.js fitBoard() then gives the exact room (QC-048 L-6: never under 200 px) */
/* QC-048 L-7: narrow phones (up to 370 px): Undo and Resign show their icon only (the name stays for screen readers and as a tooltip),
   so the result has the room to be read whole */
@media (max-width: 370px) {
  .play[data-face] .face-btn { width: 44px; min-width: 44px; padding: 0; justify-content: center; }
  .play[data-face] .face-btn > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .play[data-face] .face-last.asking { background: var(--danger); color: var(--accent-on); border-color: var(--danger); }
}
