/* ==========================================================================
   KilobyteChess theme — the ONE file that controls the look of the whole site.
   Change the variables in :root to re-skin everything.
   Fonts: Orbitron (headings), Rajdhani (text), Share Tech Mono (code/clocks)
   ========================================================================== */

:root {
  /* Surfaces */
  --bg: #07090f;
  --bg-grid: rgba(0, 229, 255, 0.035);
  --surface: #0d121c;
  --surface-2: #131a28;
  --surface-3: #1a2336;
  --border: #22304a;
  --border-strong: #2f4366;

  /* Text */
  --text: #d8e3f5;
  --text-strong: #ffffff;      /* headings, brand, emphasis */
  --text-dim: #8a9bb8;
  --text-faint: #5b6b87;

  /* Accents */
  --accent: #00e5ff;          /* cyan */
  --accent-2: #ff2bd6;        /* magenta */
  --accent-3: #9dff3d;        /* lime */
  --accent-glow: rgba(0, 229, 255, 0.35);
  --warn: #ffb02e;
  --danger: #ff4d6d;
  --ok: #3dffa0;

  /* Board */
  --sq-light: #2a3a57;
  --sq-dark: #16213a;
  --sq-last: rgba(0, 229, 255, 0.28);
  --sq-select: rgba(255, 43, 214, 0.35);
  --sq-target: rgba(157, 255, 61, 0.45);
  --sq-premove: rgba(255, 165, 0, 0.30);
  --sq-premove-edge: rgba(255, 165, 0, 0.75);
  --sq-check: rgba(255, 77, 109, 0.55);
  --piece-white: #f4f8ff;
  --piece-black: #0a0d14;
  --piece-white-stroke: #00e5ff;
  --piece-black-stroke: #ff2bd6;

  /* Type */
  --font-display: "Orbitron", "Segoe UI", sans-serif;
  --font-body: "Rajdhani", "Segoe UI", sans-serif;
  --font-mono: "Share Tech Mono", "Consolas", monospace;

  --radius: 6px;
  --radius-lg: 10px;
  --topbar: rgba(7, 9, 15, 0.92);
  --shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
  --max-width: 1200px;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html { color-scheme: dark; }

body {
  margin: 0;
  background-color: var(--bg);
  background-image:
    linear-gradient(var(--bg-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
  background-size: 32px 32px;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--text-strong); text-shadow: 0 0 8px var(--accent-glow); }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  letter-spacing: 0.04em;
  line-height: 1.2;
  margin: 0 0 0.6em;
  color: var(--text-strong);
}
h1 { font-size: 1.9rem; }
h2 { font-size: 1.3rem; color: var(--accent); }
h3 { font-size: 1.05rem; }

code, pre, .mono { font-family: var(--font-mono); }
code { background: var(--surface-3); padding: 0.1em 0.35em; border-radius: 4px; font-size: 0.92em; color: var(--accent-3); }
pre {
  background: #05070c;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  overflow: auto;
  font-size: 0.86rem;
  line-height: 1.45;
  color: #c9d7ee;
}
pre code { background: none; padding: 0; color: inherit; }

/* ---- Layout -------------------------------------------------------------- */
.container { width: 100%; max-width: var(--max-width); margin: 0 auto; padding: 0 16px; }
main { flex: 1; padding: 28px 0 48px; }

.topbar {
  background: var(--topbar);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
  backdrop-filter: blur(6px);
}
/* Wraps rather than spills. Between the drawer breakpoint and a full-width
   window the brand, the menus and the sign-in buttons can together want
   more room than there is, and none of them can shrink - the labels are
   all nowrap. Without this the sign-in buttons simply left the screen.
   `min-height` because a wrapped second row needs the space. */
.topbar .container { display: flex; align-items: center; gap: 22px;
  min-height: 60px; flex-wrap: wrap; }
.brand {
  font-family: var(--font-display); font-weight: 800; font-size: 1.25rem; color: var(--text-strong);
  letter-spacing: 0.12em; white-space: nowrap;
}
.brand span { color: var(--accent); text-shadow: 0 0 12px var(--accent-glow); }
/* No overflow here. `overflow-x: auto` makes overflow-y compute to auto as
   well, which turns this into a scroll container and clips the dropdown
   menus that hang below it - they lay out at full height and are simply
   never drawn. The bar fits without scrolling now that it is grouped. */
.nav { display: flex; gap: 4px; flex: 1; overflow: visible; }
.nav a {
  font-family: var(--font-display); font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim); padding: 8px 10px; border-radius: var(--radius); white-space: nowrap;
}
.nav a:hover, .nav a.active { color: var(--text-strong); background: var(--surface-2); text-shadow: none; }
.userbox { display: flex; gap: 10px; align-items: center; font-size: 0.95rem; white-space: nowrap; }
.userbox form { margin: 0; }

footer { border-top: 1px solid var(--border); color: var(--text-faint); font-size: 0.9rem; padding: 18px 0; }

.grid { display: grid; gap: 18px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 900px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .topbar .container { flex-wrap: wrap; height: auto; padding-top: 8px; padding-bottom: 8px; gap: 8px; }
  .nav { order: 3; flex-basis: 100%; }
}
.row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.spread { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.stack > * + * { margin-top: 14px; }

/* ---- Cards & panels ------------------------------------------------------ */
.card {
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  box-shadow: var(--shadow);
  min-width: 0;
}
.card > h2:first-child, .card > h3:first-child { margin-top: 0; }
.card.glow { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-glow), var(--shadow); }

.hero { padding: 34px 0 20px; }
.hero h1 { font-size: 2.6rem; margin-bottom: 0.2em; }
.hero h1 .accent { color: var(--accent); text-shadow: 0 0 18px var(--accent-glow); }
.hero p { color: var(--text-dim); font-size: 1.2rem; max-width: 720px; }

.stat { font-family: var(--font-display); font-size: 1.6rem; color: var(--text-strong); }
.stat-label { color: var(--text-dim); font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.08em; }

.muted { color: var(--text-dim); }
.faint { color: var(--text-faint); }
.small { font-size: 0.88rem; }
.center { text-align: center; }

/* ---- Buttons & forms ----------------------------------------------------- */
.btn, button, input[type=submit] {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-family: var(--font-display); font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase;
  background: transparent; color: var(--accent);
  border: 1px solid var(--accent); border-radius: var(--radius);
  padding: 10px 16px; cursor: pointer; transition: all 0.15s ease;
}
.btn:hover, button:hover, input[type=submit]:hover {
  background: var(--accent); color: #001018; box-shadow: 0 0 16px var(--accent-glow); text-shadow: none;
}
.btn.primary { background: var(--accent); color: #001018; }
.btn.primary:hover { background: var(--text-strong); border-color: var(--text-strong); }
.btn.secondary { color: var(--accent-2); border-color: var(--accent-2); }
.btn.secondary:hover { background: var(--accent-2); color: #14000f; box-shadow: 0 0 16px rgba(255, 43, 214, 0.4); }
.btn.danger { color: var(--danger); border-color: var(--danger); }
.btn.danger:hover { background: var(--danger); color: #fff; }
.btn.small, button.small { padding: 6px 10px; font-size: 0.68rem; }
.btn.link { border: none; padding: 0; color: var(--accent); }
.btn.link:hover { background: none; color: var(--text-strong); box-shadow: none; }

input[type=text], input[type=email], input[type=password], input[type=number], input[type=search],
input[type=url], input[type=datetime-local], select, textarea {
  width: 100%; background: #05070c; color: var(--text); border: 1px solid var(--border-strong);
  border-radius: var(--radius); padding: 9px 11px; font-family: var(--font-body); font-size: 1rem;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-glow); }
input[type=file] { color: var(--text-dim); font-family: var(--font-body); }
input[type=checkbox] { accent-color: var(--accent); width: 18px; height: 18px; vertical-align: middle; }

.form-row { margin-bottom: 14px; }
.form-row label { display: block; font-weight: 600; margin-bottom: 4px; color: var(--text-strong); }
.form-row.check label { display: inline; margin-left: 6px; }
.form-row .help { color: var(--text-faint); font-size: 0.88rem; margin-top: 3px; }
.errorlist { list-style: none; margin: 4px 0; padding: 0; color: var(--danger); font-size: 0.92rem; }
.form-inline { display: flex; gap: 10px; flex-wrap: wrap; align-items: end; }
.form-inline .form-row { margin: 0; }

/* ---- Tables -------------------------------------------------------------- */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 0.97rem; }
th {
  font-family: var(--font-display); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim); text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}
td { padding: 8px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
tr:hover td { background: rgba(0, 229, 255, 0.03); }
td.num, th.num { text-align: right; font-family: var(--font-mono); }

/* ---- Badges & messages --------------------------------------------------- */
.badge {
  display: inline-block; font-family: var(--font-display); font-size: 0.62rem; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 3px 7px; border-radius: 4px; border: 1px solid var(--border-strong);
  color: var(--text-dim); white-space: nowrap; vertical-align: middle;
}
.badge.live { color: var(--danger); border-color: var(--danger); animation: pulse 1.6s infinite; }
.badge.ok, .badge.passed, .badge.finished { color: var(--ok); border-color: var(--ok); }
.badge.warn, .badge.testing, .badge.queued { color: var(--warn); border-color: var(--warn); }
.badge.bad, .badge.failed, .badge.aborted { color: var(--danger); border-color: var(--danger); }
.badge.agent { color: var(--accent-2); border-color: var(--accent-2); }
.badge.hand { color: var(--accent-3); border-color: var(--accent-3); }
.badge.cls { color: var(--accent); border-color: var(--accent); }
.badge.learning { color: var(--accent-2); border-color: var(--accent-2); box-shadow: 0 0 6px var(--accent-glow); }
@keyframes pulse { 50% { opacity: 0.45; } }

.messages { list-style: none; padding: 0; margin: 0 0 18px; }
.messages li { padding: 10px 14px; border-radius: var(--radius); border: 1px solid var(--border-strong); background: var(--surface-2); margin-bottom: 8px; }
.messages li.success { border-color: var(--ok); }
.messages li.error { border-color: var(--danger); }
.messages li.warning { border-color: var(--warn); }
.notice { border-left: 3px solid var(--warn); background: rgba(255, 176, 46, 0.07); padding: 10px 14px; border-radius: 0 var(--radius) var(--radius) 0; }

/* ---- Chess board --------------------------------------------------------- */
.game-layout { display: grid; grid-template-columns: minmax(0, 560px) minmax(260px, 1fr); gap: 22px; align-items: start; }
@media (max-width: 900px) { .game-layout { grid-template-columns: minmax(0, 1fr); } }

.board-wrap { width: 100%; max-width: 560px; }
.board {
  /* Both axes need explicit equal tracks. With only columns defined, rows are
     implicit "auto" tracks sized by content, so ranks with no pieces collapse. */
  display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); grid-template-rows: repeat(8, minmax(0, 1fr));
  width: 100%; aspect-ratio: 1 / 1;
  /* The analysis arrows are an absolutely positioned overlay; without this they
     measure `inset: 0` against the page instead of the board. */
  position: relative;
  border: 2px solid var(--border-strong); border-radius: 4px; overflow: hidden;
  box-shadow: 0 0 0 1px var(--accent-glow), var(--shadow); user-select: none;
}
.sq { position: relative; min-width: 0; min-height: 0; overflow: hidden; display: flex; align-items: center; justify-content: center; font-size: clamp(22px, 7.2vw, 54px); line-height: 1; }
.sq.light { background: var(--sq-light); }
.sq.dark { background: var(--sq-dark); }
.sq.last::after, .sq.sel::after, .sq.target::after, .sq.check::after, .sq.premove::after { content: ""; position: absolute; inset: 0; pointer-events: none; }
.sq.last::after { background: var(--sq-last); }
.sq.sel::after { background: var(--sq-select); }
.sq.target::after { background: radial-gradient(circle, var(--sq-target) 22%, transparent 24%); }
/* A move waiting for the opponent. Deliberately unlike `last` and `sel`,
   so it never reads as something that has already happened. */
.sq.premove::after { background: var(--sq-premove); box-shadow: inset 0 0 0 2px var(--sq-premove-edge); }
.advanced { margin-top: 10px; border-top: 1px solid var(--border); padding-top: 8px; }
.advanced > summary { cursor: pointer; }
.premove-options { gap: 12px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
.premove-options .check { display: inline-flex; align-items: center; gap: 5px; margin: 0; }
.sq.check::after { background: radial-gradient(circle, var(--sq-check) 30%, transparent 70%); }
.sq .coord { position: absolute; font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); pointer-events: none; }
.sq .coord.file { right: 3px; bottom: 1px; }
.sq .coord.rank { left: 3px; top: 1px; }
.piece { position: relative; z-index: 1; cursor: default; }
.piece.w { color: var(--piece-white); text-shadow: 0 0 2px var(--piece-white-stroke), 0 0 6px rgba(0, 229, 255, 0.5); }
.piece.b { color: var(--piece-black); text-shadow: 0 0 2px var(--piece-black-stroke), 0 0 1px var(--piece-black-stroke), 0 0 7px rgba(255, 43, 214, 0.6); }
.board.interactive .piece { cursor: pointer; }

.player-bar {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 8px 12px; margin: 8px 0;
}
.player-bar .name { font-weight: 700; color: var(--text-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clock {
  font-family: var(--font-mono); font-size: 1.5rem; padding: 2px 10px; border-radius: 4px;
  background: #05070c; border: 1px solid var(--border); color: var(--text-dim); min-width: 96px; text-align: center;
}
.clock.running { color: var(--accent); border-color: var(--accent); box-shadow: 0 0 10px var(--accent-glow); }
.clock.low { color: var(--danger); border-color: var(--danger); }

.movelist {
  font-family: var(--font-mono); font-size: 0.95rem; max-height: 340px; overflow-y: auto;
  display: grid; grid-template-columns: 3em 1fr 1fr; gap: 2px 6px; align-content: start;
}
.movelist .no { color: var(--text-faint); }
.movelist .mv { padding: 1px 4px; border-radius: 3px; cursor: pointer; }
.movelist .mv:hover { background: var(--surface-3); }
.movelist .mv.current { background: var(--accent); color: #001018; }
.movelist .mv sup { font-size: 0.7em; margin-left: 1px; }
.movelist .mv.inaccuracy sup { color: var(--accent-3); }
.movelist .mv.mistake sup { color: var(--warn); }
.movelist .mv.blunder sup { color: var(--danger); }
.movelist .mv.current sup { color: #001018; }
.result-banner { font-family: var(--font-display); font-size: 1.2rem; color: var(--accent-3); }
.controls { display: flex; gap: 6px; flex-wrap: wrap; }

/* ---- Sparkline / charts -------------------------------------------------- */
.spark { width: 100%; height: 80px; }
.spark path.line { fill: none; stroke: var(--accent); stroke-width: 2; }
.spark path.area { fill: rgba(0, 229, 255, 0.08); stroke: none; }
.evalgraph { width: 100%; height: 140px; background: #05070c; border: 1px solid var(--border); border-radius: var(--radius); }
.evalgraph .white-area { fill: rgba(244, 248, 255, 0.75); }
.evalgraph .mid { stroke: var(--border-strong); }

/* ---- Brackets ------------------------------------------------------------ */
.bracket { display: flex; gap: 28px; overflow-x: auto; padding-bottom: 8px; }
.bracket .round { display: flex; flex-direction: column; justify-content: space-around; gap: 14px; min-width: 200px; }
.bracket .round h4 { font-size: 0.72rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.1em; margin: 0 0 4px; }
.match-box { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; font-size: 0.95rem; }
.match-box .slot { display: flex; justify-content: space-between; gap: 8px; padding: 5px 9px; }
.match-box .slot + .slot { border-top: 1px solid var(--border); }
.match-box .slot.win { color: var(--accent-3); font-weight: 700; }
.match-box .slot .score { font-family: var(--font-mono); }
.match-box.running { border-color: var(--danger); }
.match-box a { color: inherit; }

/* ---- Live TV ------------------------------------------------------------- */
.tv-card { display: flex; flex-direction: column; gap: 6px; color: var(--text); }
.tv-card:hover { border-color: var(--accent); text-shadow: none; }
.tv-board .sq { font-size: clamp(16px, 3.2vw, 34px); }
.tv-board .coord { display: none; }
.clock.small-clock { font-size: 0.95rem; min-width: 64px; padding: 0 6px; }

/* ---- Arrows, dragging ---------------------------------------------------- */
.board svg.arrows { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; }
.board .arrow { stroke-width: 0.17; stroke-linecap: round; opacity: 0.85; }
.board .arrow.best { stroke: var(--accent-3); }
.board .arrow.alt { stroke: var(--accent); opacity: 0.6; }
.board .arrow.bad { stroke: var(--danger); opacity: 0.7; }
.board .ah-best { fill: var(--accent-3); }
.board .ah-alt { fill: var(--accent); }
.board .ah-bad { fill: var(--danger); }
.board.interactive { touch-action: none; }
.piece.ghost { position: fixed; z-index: 100; pointer-events: none; transform: translate(-50%, -50%); text-align: center; line-height: 1; }

/* ---- Analysis board ------------------------------------------------------ */
.analysis-layout { display: grid; grid-template-columns: 34px minmax(0, 560px) minmax(280px, 1fr); gap: 14px; align-items: start; }
@media (max-width: 900px) { .analysis-layout { grid-template-columns: 26px minmax(0, 1fr); } .analysis-side { grid-column: 1 / -1; } }
.evalbar { position: relative; width: 100%; aspect-ratio: 1 / 16; max-height: 560px; background: #0a0d14; border: 1px solid var(--border-strong); border-radius: 4px; overflow: hidden; cursor: pointer; }
.evalbar .fill { position: absolute; left: 0; right: 0; bottom: 0; background: #e8eef9; transition: height 0.3s ease; }
.evalbar .label { position: absolute; left: 0; right: 0; font-family: var(--font-mono); font-size: 11px; text-align: center; z-index: 1; }
.evalbar .label.top { top: 4px; color: #e8eef9; }
.evalbar .label.bottom { bottom: 4px; color: #0a0d14; }
.evalbar.off { opacity: 0.35; }
.engine-lines { font-family: var(--font-mono); font-size: 0.9rem; }
.engine-line { display: flex; gap: 8px; padding: 5px 6px; border-bottom: 1px solid var(--border); cursor: pointer; align-items: baseline; }
.engine-line:hover { background: var(--surface-3); }
.engine-line .ev { min-width: 58px; text-align: center; border-radius: 3px; padding: 0 4px; font-weight: 700; }
.engine-line .ev.white { background: #e8eef9; color: #0a0d14; }
.engine-line .ev.black { background: #05070c; color: #e8eef9; border: 1px solid var(--border-strong); }
.engine-line .pv { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--text-dim); }
.amoves { font-family: var(--font-mono); font-size: 0.93rem; line-height: 1.9; max-height: 360px; overflow-y: auto; }
.amoves .mv { padding: 1px 4px; border-radius: 3px; cursor: pointer; white-space: nowrap; }
.amoves .mv:hover { background: var(--surface-3); }
.amoves .mv.current { background: var(--accent); color: #001018; }
.amoves .no { color: var(--text-faint); margin-left: 4px; }
.amoves .var { color: var(--text-dim); font-size: 0.86rem; }
.amoves .var .mv { color: var(--text-dim); }
.g { font-size: 0.75em; margin-left: 2px; font-weight: 700; }
.g-brilliant { color: #1de9b6; } .g-great { color: #4fa3ff; } .g-best { color: var(--accent-3); } .g-excellent { color: #8fd16a; }
.g-good { color: var(--text-dim); } .g-inaccuracy { color: #f7c948; } .g-mistake { color: var(--warn); } .g-blunder { color: var(--danger); }
.move-verdict { padding: 8px 10px; border-radius: var(--radius); background: var(--surface-3); margin-top: 8px; min-height: 2.4em; }

/* ---- Player bars: ratings, captured pieces, move times --------------------- */
.player-bar .who { display: flex; flex-direction: column; min-width: 0; }
.player-bar .rating { font-family: var(--font-mono); font-size: 0.85rem; color: var(--text-dim); margin-left: 6px; }
.rating .up { color: var(--ok); }
.rating .down { color: var(--danger); }
.rating .cal { color: var(--accent); font-size: 0.8em; }
.captured { min-height: 1.1em; font-size: 1.05rem; line-height: 1.1; white-space: nowrap; overflow: hidden; }
.captured .cap { margin-right: -0.18em; }
.captured .cap.w { color: var(--piece-white); text-shadow: 0 0 2px var(--piece-white-stroke); }
.captured .cap.b { color: var(--piece-black); text-shadow: 0 0 2px var(--piece-black-stroke), 0 0 1px var(--piece-black-stroke); }
.captured .lead { font-family: var(--font-mono); font-size: 0.8rem; color: var(--text-dim); margin-left: 6px; }
.mt { color: var(--text-faint); font-size: 0.72em; margin-left: 3px; font-family: var(--font-mono); }
.movelist .mv.current .mt, .amoves .mv.current .mt { color: #003040; }
.analysis-col { display: flex; flex-direction: column; }
.analysis-col .bar-black { order: 0; } .analysis-col #board { order: 1; } .analysis-col .bar-white { order: 2; }
.analysis-col .controls { order: 3; } .analysis-col .move-verdict { order: 4; }
.analysis-col.flipped .bar-black { order: 2; } .analysis-col.flipped .bar-white { order: 0; }


/* ---- Mobile ---------------------------------------------------------------- */
.navtoggle { display: none; }
img, svg, video, canvas { max-width: 100%; }
td, th { overflow-wrap: anywhere; }
th { overflow-wrap: normal; }

@media (max-width: 760px) {
  body { font-size: 16px; }
  .topbar .container { flex-wrap: wrap; height: auto; min-height: 54px; padding-top: 8px; padding-bottom: 8px; gap: 8px 12px; }
  .navtoggle { display: inline-flex; order: 2; margin-left: auto; padding: 6px 12px; font-size: 1.2rem; }
  .userbox { order: 3; font-size: 0.9rem; }
  .nav { display: none; order: 4; flex-basis: 100%; flex-direction: column; gap: 2px; overflow: visible; }
  body.nav-open .nav { display: flex; }
  .nav a { padding: 11px 10px; font-size: 0.8rem; }
  main { padding: 18px 0 36px; }
  h1 { font-size: 1.45rem; }
  h2 { font-size: 1.1rem; }
  .hero { padding: 16px 0 8px; }
  .hero h1 { font-size: 1.8rem; }
  .hero p { font-size: 1.05rem; }
  .card { padding: 14px; }
  .grid { gap: 12px; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .stat { font-size: 1.3rem; }
  table { font-size: 0.9rem; }
  th, td { padding: 6px 7px; }
  .hide-sm { display: none; }
  .btn, button, input[type=submit] { padding: 10px 14px; }   /* keep a good tap size */
  .row, .spread { gap: 8px; }
  /* Boards fill the width; bars, clocks and move lists stack under them. */
  .game-layout, .analysis-layout { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .analysis-layout { grid-template-columns: 22px minmax(0, 1fr); }
  .analysis-side { grid-column: 1 / -1; }
  .board-wrap { max-width: 100%; }
  .sq { font-size: clamp(20px, 10.5vw, 46px); }
  .tv-board .sq { font-size: clamp(18px, 9vw, 40px); }
  .player-bar { padding: 6px 8px; margin: 6px 0; }
  .player-bar .rating { font-size: 0.78rem; }
  .clock { font-size: 1.15rem; min-width: 74px; padding: 2px 6px; }
  .movelist, .amoves { max-height: 240px; }
  .controls button { flex: 1 1 auto; }
  .bracket .round { min-width: 170px; }
  pre { font-size: 0.8rem; }
  .form-inline { flex-direction: column; align-items: stretch; }
  footer .container { flex-direction: column; align-items: flex-start; }
}

@media (max-width: 400px) {
  .container { padding: 0 12px; }
  .brand { font-size: 1.05rem; }
  .badge { font-size: 0.56rem; padding: 2px 5px; }
}

/* ==========================================================================
   Light mode
   The board's own colours come from inline custom properties on <html> (see
   core/appearance.py), so only the surfaces, text and accents change here.
   `data-resolved-theme` is set before first paint, so "match my device" never
   flashes the wrong colours.
   ========================================================================== */
:root[data-resolved-theme="light"] {
  color-scheme: light;

  --bg: #f3f6fb;
  --bg-grid: rgba(16, 32, 56, 0.035);
  --surface: #ffffff;
  --surface-2: #eef2f8;
  --surface-3: #e3e9f3;
  --border: #d3dbe8;
  --border-strong: #b4c0d2;

  --text: #16202e;
  --text-strong: #0a1320;
  --text-dim: #4e5d75;
  --text-faint: #7c8aa0;

  /* Darkened so they still pass as readable on white. */
  --accent: #0077a8;
  --accent-2: #b3148f;
  --accent-3: #4a8500;
  --accent-glow: rgba(0, 119, 168, 0.20);
  --warn: #9a6200;
  --danger: #c3233f;
  --ok: #0f7d52;

  --topbar: rgba(255, 255, 255, 0.92);
  --shadow: 0 8px 24px rgba(16, 32, 56, 0.12);
}
html { color-scheme: dark; }
:root[data-resolved-theme="light"] body { background-color: var(--bg); }

/* The neon glow belongs to the neon board. On wood, paper or green the pieces
   want a crisp edge instead, or they look smeared. */
:root:not([data-board="neon"]) .piece.w,
:root:not([data-board="neon"]) .piece.b {
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.18), 0 0 1px var(--piece-black-stroke);
}
:root:not([data-board="neon"]) .piece.w { --piece-black-stroke: rgba(0, 0, 0, 0.5); }
:root:not([data-board="neon"]) .piece.b { --piece-black-stroke: rgba(255, 255, 255, 0.35); }

/* ---- Light/dark toggle ---------------------------------------------------- */
.themetoggle {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-dim);
  border-radius: 50%;
  width: 34px; height: 34px;
  padding: 0;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  flex: 0 0 auto;
}
.themetoggle:hover { color: var(--accent); border-color: var(--accent); }

/* ---- Appearance picker ---------------------------------------------------- */
.boardgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 10px; }
.boardswatch { display: block; cursor: pointer; text-align: center; }
.boardswatch input { position: absolute; opacity: 0; width: 0; height: 0; }
.boardswatch .mini {
  display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 1fr);
  width: 100%; aspect-ratio: 1 / 1; border: 2px solid var(--border); border-radius: 4px;
  overflow: hidden;
}
.boardswatch .mini i { display: block; }
.boardswatch input:checked + .mini { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-glow); }
.boardswatch .name { display: block; font-size: 0.68rem; color: var(--text-dim); margin-top: 4px; }
.boardswatch input:checked ~ .name { color: var(--accent); }

/* ==========================================================================
   Motion
   All of it behind prefers-reduced-motion, so anyone who has asked their
   device for less movement gets a still board.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .sq::after { transition: opacity 0.18s ease; }
  .card, .btn, button, .nav a, .badge { transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; }
  .clock { transition: color 0.2s ease, background 0.2s ease; }

  /* The piece that just moved slides in from where it came. board.js measures
     the squares and sets --dx/--dy; the animation only has to undo them. */
  .piece.sliding { animation: kc-slide 0.17s ease-out; }
  @keyframes kc-slide {
    from { transform: translate(var(--dx, 0px), var(--dy, 0px)); }
    to   { transform: none; }
  }
  /* A captured piece has no square to come from, so it just lands. */
  .piece.arriving { animation: kc-arrive 0.16s ease-out; }
  @keyframes kc-arrive {
    from { transform: scale(0.84); opacity: 0.4; }
    to   { transform: none; opacity: 1; }
  }
  .messages li { animation: kc-arrive 0.2s ease-out; }
}

/* ==========================================================================
   Phones, continued
   ========================================================================== */
/* Stops iOS zooming the whole page when a field is focused. */
input, select, textarea { font-size: max(16px, 1rem); }

@media (max-width: 760px) {
  /* Notched phones: keep content out from under the rounded corners. */
  .container { padding-left: max(16px, env(safe-area-inset-left)); padding-right: max(16px, env(safe-area-inset-right)); }
  footer { padding-bottom: max(18px, env(safe-area-inset-bottom)); }

  /* No grey flash on tap, and no accidental double-tap zoom on the controls. */
  a, button, .btn, .sq { -webkit-tap-highlight-color: transparent; }
  .controls, .nav, .userbox { touch-action: manipulation; }

  /* Real tap targets: 44px is the smallest comfortable one. */
  .controls button { min-height: 44px; min-width: 44px; font-size: 1rem; }
  .themetoggle { width: 40px; height: 40px; font-size: 1.1rem; }
  .boardgrid { grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); }

  /* Tables that cannot shrink any further scroll on their own rather than
     stretching the page sideways. */
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* ---- Lobby: time presets ------------------------------------------------- */
.presetrow { gap: 6px; flex-wrap: wrap; }
.preset { position: relative; cursor: pointer; }
.preset input { position: absolute; opacity: 0; width: 0; height: 0; }
.preset span {
  display: inline-block; padding: 7px 13px; min-width: 56px; text-align: center;
  font-family: var(--font-mono); font-size: 0.9rem;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface-2); color: var(--text-dim);
}
.preset input:checked + span {
  border-color: var(--accent); color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-glow);
}
.preset input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 760px) {
  .preset span { padding: 10px 14px; min-width: 64px; }   /* a real tap target */
}

/* ---- Reviewing moves by category ---------------------------------------- */
.countlink {
  background: none; border: none; padding: 0 2px; cursor: pointer;
  font: inherit; color: var(--accent); border-bottom: 1px dotted var(--accent);
}
.countlink:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }
.reviewbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 10px; margin-bottom: 10px;
  background: var(--surface-3); border-radius: var(--radius);
  border-left: 3px solid var(--accent);
}
.reviewbar .row { margin-left: auto; gap: 6px; }
@media (max-width: 760px) {
  .reviewbar .row { margin-left: 0; width: 100%; }
  .reviewbar .row button { flex: 1 1 auto; min-height: 40px; }
  .countlink { padding: 4px 8px; }   /* easier to hit than a bare number */
}

/* ---- Sound toggle -------------------------------------------------------- */
#sound-toggle.off { color: var(--text-faint); border-color: var(--border); }
#sound-toggle.off:hover { color: var(--danger); border-color: var(--danger); }

/* ---- Puzzles ------------------------------------------------------------- */
.move-verdict.good { border-left: 3px solid var(--ok); color: var(--ok); }
.move-verdict.bad { border-left: 3px solid var(--warn); color: var(--warn); }

/* ==========================================================================
   Four-player chess
   Fourteen squares each way with the corners cut out. The cut cells are still
   in the grid so the rows line up; they are simply not drawn.
   ========================================================================== */
.four-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, 340px); gap: 16px; align-items: start; }
@media (max-width: 900px) { .four-layout { grid-template-columns: 1fr; } }

.fourboard {
  display: grid;
  grid-template-columns: repeat(14, minmax(0, 1fr));
  grid-template-rows: repeat(14, minmax(0, 1fr));
  width: 100%; max-width: 620px; aspect-ratio: 1 / 1;
  position: relative;
  border: 2px solid var(--border-strong); border-radius: 4px;
  box-shadow: 0 0 0 1px var(--accent-glow), var(--shadow);
  user-select: none;
}
.fsq {
  position: relative; min-width: 0; min-height: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-size: clamp(10px, 2.6vw, 26px); line-height: 1; cursor: pointer;
}
.fsq.light { background: var(--sq-light); }
.fsq.dark { background: var(--sq-dark); }
.fsq.cut { background: transparent; cursor: default; }
.fsq.sel { box-shadow: inset 0 0 0 2px var(--accent-2); }
.fsq.target::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle, var(--sq-target) 24%, transparent 26%);
}
.fsq.check { background: var(--sq-check); }

/* Each army needs to be told apart at a glance, so the pieces are coloured
   rather than just outlined. */
.fpiece { display: block; }
.fpiece.f-red { color: #ff5b5b; text-shadow: 0 0 2px #2a0000, 0 1px 0 rgba(0,0,0,0.5); }
.fpiece.f-blue { color: #5aa8ff; text-shadow: 0 0 2px #001a2e, 0 1px 0 rgba(0,0,0,0.5); }
.fpiece.f-yellow { color: #ffd84a; text-shadow: 0 0 2px #2e2200, 0 1px 0 rgba(0,0,0,0.5); }
.fpiece.f-green { color: #5ce08a; text-shadow: 0 0 2px #00230f, 0 1px 0 rgba(0,0,0,0.5); }

.fdot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; vertical-align: middle; }
.fdot.f-red { background: #ff5b5b; }
.fdot.f-blue { background: #5aa8ff; }
.fdot.f-yellow { background: #ffd84a; }
.fdot.f-green { background: #5ce08a; }

@media (max-width: 760px) {
  .fourboard { max-width: 100%; }
  .fsq { font-size: clamp(9px, 5.4vw, 22px); }
}

/* ==========================================================================
   Navigation menus
   There are far more places to go than fit across a bar, so the bar carries
   a handful of headings and each opens a menu. Hover on a pointer, tap on a
   touchscreen, and inside the phone drawer the menus simply stack.
   ========================================================================== */
.navgroup { position: relative; }
.navtop {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-display); font-size: 0.72rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-dim);
  background: none; border: 0; padding: 8px 10px; border-radius: var(--radius);
  cursor: pointer; white-space: nowrap;
}
a.navtop.plain { text-decoration: none; }
.navtop:hover, .navgroup:hover > .navtop, .navgroup.open > .navtop { color: var(--text-strong); background: var(--surface-2); }
.navgroup.active > .navtop, a.navtop.active { color: var(--accent); }
.navtop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The little arrow turns over when the menu is open. */
.caret { width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent;
         border-top: 4px solid currentColor; opacity: 0.8; transition: transform 0.18s ease; }
.navgroup:hover .caret, .navgroup.open .caret { transform: rotate(180deg); }

/* Shown and hidden with `display` rather than visibility and opacity. There is
   no transition timing to get subtly wrong, nothing can be left half-visible,
   and the drop-in is a keyframe on the way in, which is the only direction
   worth animating. */
.navmenu {
  display: none;
  position: absolute; top: 100%; left: 0; z-index: 40;
  min-width: 190px; padding: 6px;
  flex-direction: column; gap: 2px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
}
.navgroup:hover > .navmenu,
.navgroup:focus-within > .navmenu,
.navgroup.open > .navmenu {
  display: flex;
  animation: kc-menu-in 0.16s ease-out;
}
@keyframes kc-menu-in {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .navgroup:hover > .navmenu,
  .navgroup:focus-within > .navmenu,
  .navgroup.open > .navmenu { animation: none; }
}
.navmenu a {
  display: block; padding: 8px 10px; border-radius: var(--radius);
  font-family: var(--font-body); font-size: 0.92rem; letter-spacing: 0;
  text-transform: none; color: var(--text); white-space: nowrap;
}
.navmenu a:hover { background: var(--surface-3); color: var(--accent); text-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .navmenu, .caret { transition: none; }
}

@media (max-width: 760px) {
  /* In the drawer there is nothing to hover, and no room to float: the
     menus become part of the list and open on a tap. */
  .navgroup { width: 100%; }
  .navtop { width: 100%; justify-content: space-between; padding: 11px 10px; font-size: 0.8rem; }
  .navmenu {
    position: static; transform: none;
    border: 0; box-shadow: none; background: transparent;
    padding: 0 0 0 12px;
  }
  /* Nothing to hover in a drawer, so only a tap opens these. */
  .navgroup:hover > .navmenu { display: none; }
  .navgroup.open > .navmenu, .navgroup.open:hover > .navmenu { display: flex; }
  .navmenu a { padding: 10px; }
}

/* ---- Four-player seats and clocks ---------------------------------------- */
[data-clock].running { color: var(--accent); }
[data-clock].low { color: var(--danger); }
.seatedit summary { cursor: pointer; color: var(--accent); }
.seatedit[open] { background: var(--surface-2); padding: 8px; border-radius: var(--radius); margin-top: 6px; }
.seatedit form { margin-top: 6px; }

/* ---- Game chat and comments ---------------------------------------------- */
.chatlog {
  list-style: none; margin: 0 0 10px; padding: 0; max-height: 260px; overflow-y: auto;
  overflow-wrap: anywhere;
}
.chatlog li { padding: 4px 0; border-bottom: 1px solid var(--border); }
.chatlog li b { color: var(--accent); font-weight: 600; }
.chatform { display: flex; gap: 8px; }
.chatform input { flex: 1; min-width: 0; }
.comment { padding: 8px 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
.comment p { margin: 4px 0 0; }
form.inline { display: inline; }

/* ---- Staff messages to visitors ------------------------------------------ */
.staff-notes {
  position: fixed; right: 16px; bottom: 16px; z-index: 1000;
  width: min(360px, calc(100vw - 32px)); display: flex; flex-direction: column; gap: 10px;
}
.staff-note { padding: 14px 16px; }
.staff-note .note-body { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text-strong); }
.staff-note textarea { font-size: 0.95rem; }
.watch-layout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .watch-layout { grid-template-columns: minmax(0, 1fr); } }
.threadlog { max-height: 420px; overflow-y: auto; margin-bottom: 10px; }
.tmsg { padding: 8px 10px; border-radius: var(--radius); margin-bottom: 8px; white-space: pre-wrap;
  overflow-wrap: anywhere; border: 1px solid var(--border); }
.tmsg.us { border-color: var(--accent); }
.tmsg.them { border-color: var(--accent-2); }
.section-gap { margin-top: 22px; }
.gwlist { list-style: none; margin: 0 0 8px; padding: 0; }
.gwlist li { display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 6px 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
#gw-thread .threadlog { max-height: 240px; }

/* ==========================================================================
   Phones: data tables become cards
   static/js/tables.js labels every cell of a table with four or more
   columns and marks it `.cards`. Under 640px each row is laid out as a small
   card: the naming column across the top, the rest as labelled pairs.
   Wider screens keep the ordinary table.
   ========================================================================== */
@media (max-width: 640px) {
  table.cards, table.cards tbody { display: block; width: 100%; }
  table.cards thead { display: none; }
  table.cards tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px;
    padding: 10px 2px; border-bottom: 1px solid var(--border);
  }
  table.cards tr:hover td { background: none; }
  table.cards td {
    display: block; flex: 1 1 28%; max-width: 100%; padding: 0; border: 0;
    text-align: left; overflow-wrap: break-word;
  }
  table.cards td[data-label]:not([data-label=""])::before {
    content: attr(data-label); display: block; margin-bottom: 1px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    font-family: var(--font-display); font-size: 0.6rem; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text-faint);
  }
  table.cards td:empty { display: none; }
  table.cards td.cell-rank { flex: 0 0 auto; color: var(--text-faint); font-family: var(--font-mono); }
  table.cards td.cell-rank[data-label]::before { content: "#"; display: inline; font: inherit; letter-spacing: 0; color: inherit; }
  table.cards td.num { flex-basis: 13%; }   /* short numbers pack several to a line */
  table.cards td.cell-main { flex: 1 1 70%; font-weight: 700; font-size: 1rem; }
  table.cards td.cell-main::before { display: none !important; }
  table.cards tr.card-note td { flex-basis: 100%; }
  table.cards .badge { white-space: nowrap; }
  table.cards form, table.cards .btn, table.cards button { max-width: 100%; }
  .table-wrap:has(table.cards) { overflow-x: visible; }

  /* Game report: the two names head the columns; let them wrap instead of
     squeezing the move categories one letter per line. */
  td.num, td.mono { white-space: nowrap; }

  #summary th { white-space: normal; overflow-wrap: anywhere; font-size: 0.6rem; }
  #summary td:first-child { white-space: nowrap; }
}

/* ==========================================================================
   Pieces, board surfaces and backgrounds
   Chosen on the profile page; core/appearance.py is the list of choices and
   sets data-pieces / data-pstyle / data-texture / data-backdrop on <html>.
   ========================================================================== */

/* Piece sets: each font is cut down to the twelve chess symbols (a few KB),
   and is only downloaded by somebody who picked it. "block" rather than
   "swap", so a slow connection shows nothing for a moment instead of one set
   of pieces turning into another. See static/fonts/pieces/LICENSES.md. */
@font-face { font-family: "KC Pieces Modern"; src: url("../fonts/pieces/modern.42cdbfe3bd72.woff2") format("woff2"); font-display: block; unicode-range: U+2654-265F, U+FE0E; }
@font-face { font-family: "KC Pieces Elegant"; src: url("../fonts/pieces/elegant.9dae61db4dd1.woff2") format("woff2"); font-display: block; unicode-range: U+2654-265F, U+FE0E; }
@font-face { font-family: "KC Pieces Newspaper"; src: url("../fonts/pieces/newspaper.365f32ece20c.woff2") format("woff2"); font-display: block; unicode-range: U+2654-265F, U+FE0E; }
@font-face { font-family: "KC Pieces Pixel"; src: url("../fonts/pieces/pixel.0783ab43f757.woff2") format("woff2"); font-display: block; unicode-range: U+2654-265F, U+FE0E; }

:root:not([data-pieces="device"]) .piece,
:root:not([data-pieces="device"]) .captured .cap,
:root:not([data-pieces="device"]) .fpiece,
:root:not([data-pieces="device"]) .piece-sample {
  font-family: var(--font-pieces), "Segoe UI Symbol", "DejaVu Sans", sans-serif;
}
:root:not([data-pieces="device"]) .piece { font-size: calc(var(--piece-scale, 1) * 1em); }
.piece-sample[data-set="modern"] { font-family: "KC Pieces Modern"; }
.piece-sample[data-set="elegant"] { font-family: "KC Pieces Elegant"; }
.piece-sample[data-set="newspaper"] { font-family: "KC Pieces Newspaper"; font-size: 1.15em; }
.piece-sample[data-set="pixel"] { font-family: "KC Pieces Pixel"; }

/* The hollow glyph for each piece, which the two-tone style lays over the
   solid one. board.js puts the piece letter in data-p. */
.piece[data-p="k"] { --outline-glyph: "\2654\FE0E"; }
.piece[data-p="q"] { --outline-glyph: "\2655\FE0E"; }
.piece[data-p="r"] { --outline-glyph: "\2656\FE0E"; }
.piece[data-p="b"] { --outline-glyph: "\2657\FE0E"; }
.piece[data-p="n"] { --outline-glyph: "\2658\FE0E"; }
.piece[data-p="p"] { --outline-glyph: "\2659\FE0E"; }

/* Piece styles. Each is written after the board's own rules above, at the
   same specificity, so a chosen style wins and "auto" leaves them alone. */
:root[data-pstyle="flat"] .piece.w,
:root[data-pstyle="flat"] .piece.b { text-shadow: none; }

:root[data-pstyle="classic"] .piece.w,
:root[data-pstyle="classic"] .piece.b { text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); }
:root[data-pstyle="classic"] .piece::after {
  content: var(--outline-glyph, "");
  position: absolute; left: 0; top: 0; width: 100%; text-align: center;
  pointer-events: none; text-shadow: none;
}
:root[data-pstyle="classic"] .piece.w::after { color: rgba(0, 0, 0, 0.85); }
:root[data-pstyle="classic"] .piece.b::after { color: rgba(255, 255, 255, 0.45); }

:root[data-pstyle="raised"] .piece.w {
  text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.35), 0 1px 0 rgba(0, 0, 0, 0.55),
               0 3px 4px rgba(0, 0, 0, 0.45), 0 0 1px rgba(0, 0, 0, 0.8);
}
:root[data-pstyle="raised"] .piece.b {
  text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.28), 0 1px 0 rgba(0, 0, 0, 0.6),
               0 3px 4px rgba(0, 0, 0, 0.5);
}

:root[data-pstyle="glow"] .piece.w { text-shadow: 0 0 2px #00e5ff, 0 0 6px rgba(0, 229, 255, 0.6), 0 0 12px rgba(0, 229, 255, 0.35); }
:root[data-pstyle="glow"] .piece.b { text-shadow: 0 0 2px #ff2bd6, 0 0 1px #ff2bd6, 0 0 7px rgba(255, 43, 214, 0.65), 0 0 12px rgba(255, 43, 214, 0.35); }

:root[data-pstyle="outline"] .piece.w {
  text-shadow: 1px 0 0 #000, -1px 0 0 #000, 0 1px 0 #000, 0 -1px 0 #000,
               1px 1px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000;
}
:root[data-pstyle="outline"] .piece.b {
  text-shadow: 1px 0 0 #fff, -1px 0 0 #fff, 0 1px 0 #fff, 0 -1px 0 #fff,
               1px 1px 0 #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff;
}

/* Board surfaces. One layer over the whole board, so wood grain or marble
   runs across the squares instead of repeating in each. It sits under the
   pieces (z-index 1) and the arrows (2) and never takes a click. The patterns
   are grey and blended, so they work over every board colour. */
.board::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  display: none; background-size: cover;
}
:root[data-texture="wood"] .board::after,
:root[data-texture="marble"] .board::after,
:root[data-texture="linen"] .board::after,
:root[data-texture="metal"] .board::after,
:root[data-texture="glass"] .board::after,
:root[data-texture="felt"] .board::after,
.lookswatch .tx-felt::after { display: block; }

:root[data-texture="wood"] .board::after,
.lookswatch .tx-wood::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='480'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.006 0.22' numOctaves='3' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay; opacity: 0.55;
}
:root[data-texture="marble"] .board::after,
.lookswatch .tx-marble::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='480'%3E%3Cfilter id='m' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='turbulence' baseFrequency='0.011' numOctaves='5' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix values='-1.4 0 0 0 1.25 -1.4 0 0 0 1.25 -1.4 0 0 0 1.25 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23m)'/%3E%3C/svg%3E");
  mix-blend-mode: soft-light; opacity: 0.85;
}
:root[data-texture="linen"] .board::after,
.lookswatch .tx-linen::after {
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.07) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.07) 0 1px, transparent 1px 3px);
  background-size: auto;
}
:root[data-texture="metal"] .board::after,
.lookswatch .tx-metal::after {
  background-image:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.06) 0 1px, rgba(0, 0, 0, 0.05) 1px 2px, transparent 2px 4px),
    linear-gradient(125deg, rgba(255, 255, 255, 0.22) 0%, transparent 30%, rgba(255, 255, 255, 0.12) 55%, transparent 75%, rgba(0, 0, 0, 0.12) 100%);
  background-size: auto;
}
:root[data-texture="glass"] .board::after,
.lookswatch .tx-glass::after {
  background-image: linear-gradient(160deg, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.06) 42%, transparent 46%, rgba(0, 0, 0, 0.08) 100%);
}
:root[data-texture="glass"] .sq,
.lookswatch .tx-glass i { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), inset 0 -1px 0 rgba(0, 0, 0, 0.18); }
:root[data-texture="felt"] .board::after,
.lookswatch .tx-felt::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  background-size: 240px 240px; mix-blend-mode: overlay; opacity: 0.4;
}
:root[data-texture="tiles"] .sq,
.lookswatch .tx-tiles i {
  box-shadow: inset 2px 2px 0 rgba(255, 255, 255, 0.2), inset -2px -2px 0 rgba(0, 0, 0, 0.28);
}
:root[data-texture="grid"] .sq,
.lookswatch .tx-grid i { box-shadow: inset 0 0 0 1px rgba(0, 229, 255, 0.28), inset 0 0 10px rgba(0, 229, 255, 0.08); }

/* Backgrounds. "grid" is the site's own (on body, above). The rest are one
   fixed layer behind everything, painted once rather than on every scroll,
   and each tints the theme's own background so text stays readable in light
   and dark alike. */
:root:not([data-backdrop="grid"]) body { background-image: none; }
:root:not([data-backdrop="grid"]):not([data-backdrop="plain"]) body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
}
:root[data-backdrop="stars"] body::before,
.lookswatch .bd-stars::before {
  background-image:
    radial-gradient(1.5px 1.5px at 20px 30px, var(--text-dim), transparent),
    radial-gradient(1px 1px at 90px 140px, var(--text-faint), transparent),
    radial-gradient(1px 1px at 160px 60px, var(--text-dim), transparent),
    radial-gradient(1.5px 1.5px at 230px 190px, var(--text-faint), transparent),
    radial-gradient(1px 1px at 300px 100px, var(--text-dim), transparent),
    radial-gradient(1px 1px at 60px 250px, var(--text-faint), transparent),
    radial-gradient(2px 2px at 270px 280px, var(--accent-glow), transparent),
    radial-gradient(ellipse at 70% 0%, var(--accent-glow), transparent 55%);
  background-size: 320px 320px, 320px 320px, 320px 320px, 320px 320px, 320px 320px, 320px 320px, 320px 320px, 100% 100%;
  opacity: 0.8;
}
:root[data-backdrop="aurora"] body::before,
.lookswatch .bd-aurora::before {
  background-image:
    radial-gradient(ellipse 60% 45% at 15% 0%, rgba(0, 229, 255, 0.2), transparent),
    radial-gradient(ellipse 50% 40% at 85% 8%, rgba(255, 43, 214, 0.16), transparent),
    radial-gradient(ellipse 70% 40% at 50% 100%, rgba(157, 255, 61, 0.1), transparent);
}
:root[data-backdrop="sunset"] body::before,
.lookswatch .bd-sunset::before {
  background-image:
    radial-gradient(ellipse 80% 50% at 50% 110%, rgba(255, 150, 60, 0.28), transparent),
    linear-gradient(180deg, rgba(120, 40, 160, 0.16), rgba(255, 70, 120, 0.12) 55%, rgba(255, 150, 60, 0.14));
}
:root[data-backdrop="ocean"] body::before,
.lookswatch .bd-ocean::before {
  background-image:
    radial-gradient(ellipse 70% 40% at 30% 0%, rgba(80, 200, 255, 0.18), transparent),
    linear-gradient(180deg, rgba(0, 90, 170, 0.14), rgba(0, 30, 80, 0.24));
}
:root[data-backdrop="table"] body::before,
.lookswatch .bd-table::before {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.004 0.12' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.35 0 0 0 0 0.2 0 0 0 0 0.08 0.9 0 0 0 -0.25'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"),
    linear-gradient(rgba(120, 70, 30, 0.22), rgba(90, 50, 20, 0.28));
  background-size: 600px 600px, auto;
}
:root[data-backdrop="felt"] body::before,
.lookswatch .bd-felt::before {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='5' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0.2 0 0 0 0 0.1 0.25 0 0 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
    radial-gradient(ellipse at 50% 40%, rgba(30, 140, 80, 0.28), rgba(10, 80, 45, 0.34));
  background-size: 200px 200px, auto;
}
:root[data-backdrop="carbon"] body::before,
.lookswatch .bd-carbon::before {
  background-image:
    linear-gradient(27deg, rgba(0, 0, 0, 0.22) 5px, transparent 5px),
    linear-gradient(207deg, rgba(0, 0, 0, 0.22) 5px, transparent 5px),
    linear-gradient(27deg, rgba(255, 255, 255, 0.04) 5px, transparent 5px),
    linear-gradient(207deg, rgba(255, 255, 255, 0.04) 5px, transparent 5px),
    linear-gradient(90deg, rgba(0, 0, 0, 0.12) 10px, transparent 10px),
    linear-gradient(rgba(0, 0, 0, 0.1) 25%, rgba(0, 0, 0, 0.06) 25%, rgba(0, 0, 0, 0.06) 50%, transparent 50%, transparent 75%, rgba(255, 255, 255, 0.03) 75%);
  background-position: 0 5px, 10px 0, 0 10px, 10px 5px, 0 0, 0 0;
  background-size: 20px 20px;
}
:root[data-backdrop="blueprint"] body::before,
.lookswatch .bd-blueprint::before {
  background-image:
    linear-gradient(rgba(110, 170, 255, 0.16) 1px, transparent 1px),
    linear-gradient(90deg, rgba(110, 170, 255, 0.16) 1px, transparent 1px),
    linear-gradient(rgba(110, 170, 255, 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(110, 170, 255, 0.07) 1px, transparent 1px),
    linear-gradient(rgba(30, 90, 190, 0.18), rgba(30, 90, 190, 0.18));
  background-size: 96px 96px, 96px 96px, 24px 24px, 24px 24px, auto;
}
:root[data-backdrop="dots"] body::before,
.lookswatch .bd-dots::before {
  background-image: radial-gradient(var(--border-strong) 2px, transparent 2.5px);
  background-size: 24px 24px;
}
:root[data-backdrop="checker"] body::before,
.lookswatch .bd-checker::before {
  background-image: conic-gradient(rgba(127, 127, 127, 0.08) 25%, transparent 0 50%, rgba(127, 127, 127, 0.08) 0 75%, transparent 0);
  background-size: 160px 160px;
}

/* ---- The pickers on the profile page ------------------------------------- */
.lookgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 10px; }
.lookswatch { display: block; cursor: pointer; text-align: center; position: relative; }
.lookswatch input { position: absolute; opacity: 0; width: 0; height: 0; }
.lookswatch .tile {
  display: flex; align-items: center; justify-content: center; gap: 2px;
  width: 100%; aspect-ratio: 16 / 10; border: 2px solid var(--border); border-radius: 6px;
  overflow: hidden; position: relative; font-size: 1.7rem; line-height: 1;
  background: linear-gradient(135deg, var(--sq-light) 50%, var(--sq-dark) 50%);
}
.lookswatch input:checked + .tile { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-glow); }
.lookswatch input:focus-visible + .tile { outline: 2px solid var(--accent); outline-offset: 2px; }
.lookswatch .name { display: block; font-size: 0.72rem; color: var(--text-dim); margin-top: 4px; }
.lookswatch input:checked ~ .name { color: var(--accent); }
.lookswatch .tile .piece { font-size: 1.7rem; }
.lookswatch .tile.words { aspect-ratio: auto; min-height: 44px; padding: 6px; font-size: 0.85rem; background: var(--surface-2); color: var(--text); }
.lookswatch .dot { width: 22px; height: 22px; border-radius: 50%; border: 1px solid rgba(127, 127, 127, 0.6); }
.lookswatch .tile.backdrop { background: var(--bg); }
.lookswatch .tile.backdrop::before { content: ""; position: absolute; inset: 0; }
.lookswatch .tile.backdrop.bd-grid {
  background-image: linear-gradient(var(--bg-grid) 1px, transparent 1px), linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
  background-size: 16px 16px;
}
.lookswatch .tile.texture { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 1fr); gap: 0; aspect-ratio: 1 / 1; background: none; }
.lookswatch .tile.texture i { display: block; }
.lookswatch .tile.texture i.l { background: var(--sq-light); }
.lookswatch .tile.texture i.d { background: var(--sq-dark); }
.lookswatch .tile.texture::after { content: ""; position: absolute; inset: 0; pointer-events: none; background-size: cover; }
.look-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 18px; align-items: start; }
.look-preview { position: sticky; top: 76px; }
.look-preview .board-wrap { max-width: 300px; }
.look-preview .sq { font-size: clamp(18px, 4.6vw, 32px); }
@media (max-width: 900px) {
  .look-layout { grid-template-columns: minmax(0, 1fr); }
  .look-preview { position: static; order: -1; }
  .look-preview .board-wrap { max-width: 280px; margin: 0 auto; }
}

/* ---- Server settings page -------------------------------------------------- */
.settings-status .status-pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 12px; }
.pill { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 0.8rem; border: 1px solid var(--border-strong); color: var(--text-dim); }
.pill.ok { border-color: color-mix(in srgb, var(--ok) 60%, transparent); color: var(--ok); }
.pill.warn { border-color: color-mix(in srgb, var(--warn) 60%, transparent); color: var(--warn); }
.pill.bad { border-color: color-mix(in srgb, var(--danger) 60%, transparent); color: var(--danger); }
.pill.off { color: var(--text-faint); }
.status-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px 16px; }
.status-grid > div { display: flex; flex-direction: column; }
.status-grid strong { font-family: var(--font-mono); font-weight: 400; font-size: 1.05rem; color: var(--text-strong); }
.corebar { display: flex; height: 12px; border-radius: 6px; overflow: hidden; margin: 14px 0 6px; background: var(--surface-3); }
.corebar .seg { flex-basis: 0; min-width: 0; transition: flex-grow 0.4s ease; }
.corebar .games, .corelegend i.games { background: var(--accent); }
.corebar .kept, .corelegend i.kept { background: var(--accent-2); }
.corebar .free, .corelegend i.free { background: var(--surface-3); }
.corelegend { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.corelegend i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; vertical-align: middle; border: 1px solid var(--border-strong); }
.warnline { border-left: 3px solid var(--warn); padding: 6px 10px; margin: 10px 0 0; background: var(--surface-2); font-size: 0.9rem; }

.settings-layout { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 18px; align-items: start; margin-top: 18px; }
.settings-nav { position: sticky; top: 76px; display: flex; flex-direction: column; gap: 2px; }
.settings-nav input[type=search] { width: 100%; margin-bottom: 8px; }
.settings-nav a { padding: 6px 10px; border-radius: var(--radius); color: var(--text-dim); display: flex; justify-content: space-between; align-items: center; }
.settings-nav a:hover { background: var(--surface-2); color: var(--text-strong); text-shadow: none; }
.settings-nav .errdot { color: var(--danger); }
.settings-nav .changed-count { font-size: 0.7rem; background: var(--accent); color: var(--bg); border-radius: 999px; padding: 0 7px; }
.settings-section { scroll-margin-top: 80px; }
.settings-section .effect { margin: -4px 0 12px; }
.setting { border-left: 3px solid transparent; padding-left: 10px; margin-left: -13px; }
.setting.changed { border-left-color: var(--accent); }
.setting.has-error { border-left-color: var(--danger); }
.setting-meta { display: flex; gap: 12px; align-items: baseline; margin-top: 2px; min-height: 1.2em; }
.setting-meta .unit-hint { color: var(--accent-3); }
.linkish { background: none; border: 0; padding: 0; color: var(--accent); cursor: pointer; font: inherit; text-decoration: underline; }
.class-elo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px; }
.setting.compact { margin: 0; }
.setting.compact label { font-size: 0.8rem; }
.setting.compact input { width: 100%; }
.profiles { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; margin-bottom: 14px; }
.profiles .row { margin-top: 6px; flex-wrap: wrap; gap: 6px; }
.savebar {
  grid-column: 1 / -1; position: sticky; bottom: 0; z-index: 5;
  display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--topbar); backdrop-filter: blur(6px); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 14px; margin-top: 4px;
}
.savebar.dirty { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-glow); }
@media (max-width: 900px) {
  .settings-layout { grid-template-columns: minmax(0, 1fr); }
  .settings-nav { position: static; flex-direction: row; flex-wrap: wrap; }
  .settings-nav input[type=search] { flex: 1 1 100%; }
  .setting { margin-left: -8px; padding-left: 6px; }
}
