:root {
  /* Surfaces, darkest to lightest: page, inset boxes, panels, controls, borders. */
  --bg: #17181d;
  --panel-2: #1c1d23;
  --panel: #262830;
  --control: #33353f;
  --line: #40424d;
  /* Text: body, labels, secondary notes. All read on every surface above. */
  --text: #eef0f4;
  --label: #cfd2db;
  --muted: #b3b6c2;
  --light-square: #eeeed2;
  --dark-square: #769656;
  --accent: #6ea8fe;
  --accent-soft: rgba(110, 168, 254, 0.16);

  /* Piece colours: a solid body with a contrasting outline so it reads on both squares. */
  --piece-white-color: #f6f6f6;
  --piece-white-outline: #1b1b1b;
  --piece-black-color: #2c2c2c;
  --piece-black-outline: #f0f0f0;
}

* { box-sizing: border-box; }

/* The hidden attribute must win over any display rule below. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  background: var(--bg);
  color: var(--text);
}

/* Keyboard focus is visible everywhere; mouse clicks do not leave a ring behind. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 24px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

.header-controls {
  display: flex;
  align-items: center;
  gap: 18px;
}

.color-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
}

.toggle-label {
  color: var(--muted);
  font-size: 0.95rem;
  margin-right: 4px;
}

.toggle-btn {
  padding: 7px 16px;
  border-radius: 999px;
}

.toggle-btn[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #101318;
  font-weight: 600;
}

header h1 {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

main {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr) 350px;
  gap: 24px;
  padding: 24px;
  align-items: start;
}

@media (max-width: 1000px) {
  main {
    grid-template-columns: 1fr;
  }
  #sidebar .piece-list,
  #sidebar .mode-list {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

/* ---------- Sidebar: pieces and modes ---------- */

#sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--panel);
  border-radius: 12px;
  padding: 14px;
}

.sidebar-title {
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 10px;
  padding-left: 4px;
}

.sidebar-title:first-child { margin-top: 0; }

.piece-list,
.mode-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.piece-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
  padding: 6px 10px;
  font-size: 1.02rem;
  border-color: transparent;
  background: transparent;
}

.piece-btn:hover {
  background: var(--panel-2);
  border-color: transparent;
}

.piece-btn.active {
  background: var(--panel-2);
  border-color: var(--accent);
  font-weight: 600;
}

.piece.icon {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--dark-square);
  border-radius: 6px;
  flex-shrink: 0;
}

.piece.icon svg {
  width: 88%;
  height: 88%;
}

.mode-btn {
  text-align: left;
  padding: 8px 12px;
  font-size: 0.98rem;
  border-color: transparent;
  background: transparent;
  box-shadow: inset 3px 0 0 transparent;
}

.mode-btn:hover {
  background: var(--panel-2);
  border-color: transparent;
}

.mode-btn.active {
  background: var(--accent-soft);
  border-color: transparent;
  box-shadow: inset 3px 0 0 var(--accent);
  font-weight: 600;
}

.prefs {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px 6px;
  font-size: 0.95rem;
}

/* The build line (js/version.js): pushed to the foot of the rail, quiet, two short lines. */
.version {
  margin-top: auto;
  padding: 14px 4px 0;
  color: var(--muted);
  font-size: 0.72rem;
  line-height: 1.4;
  letter-spacing: 0.02em;
}

.version-build {
  font-variant-numeric: tabular-nums;
}

/* "King" small on top, "Explorer" big underneath. */
#mode-title {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.2;
}

.mode-kicker {
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.lesson {
  margin: 0;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--panel-2);
  line-height: 1.5;
  font-size: 1rem;
}

/* ---------- Board ---------- */

#board-wrap {
  flex: 1 1 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.board-hint {
  text-align: center;
  font-size: 0.9rem;
}

/* One board normally; two side by side when "Both sides" is on. */
.boards {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 16px;
  width: 100%;
}

.board-figure {
  position: relative; /* the move ghost sits over the board */
  container-type: inline-size;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: min(100%, 80vh, 640px);
}

.boards.dual .board-figure {
  width: auto;
  flex: 1 1 0;
  min-width: 0;
  max-width: min(80vh, 640px);
}

/*
 * Two boards, level with each other. The scoreboard puts a ticker and a name
 * plate above the first board and more under it (the column order below), so
 * as flex items the second board would sit higher than the first. On a desktop
 * the pair is a grid instead: seven rows, one per piece of furniture, and
 * each figure a subgrid of them, so both boards share row 3 whatever stands
 * above or below the first. A row with nothing in it is 0 tall; the gaps are
 * margins on the furniture, not grid gaps, so empty rows cost nothing. A
 * subgrid cannot be a size container, so the pair is the container instead
 * and the move ghost's cqw units are halved to match (one board is half the
 * pair). The phone never shows the second board (css/mobile-deck.css).
 */
@media (min-width: 761px) and (min-height: 521px) {
  @supports (grid-template-rows: subgrid) {
    .boards.dual {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, min(80vh, 640px)));
      grid-template-rows: repeat(7, auto);
      column-gap: 16px;
      row-gap: 0;
      container-type: inline-size;
    }

    .boards.dual .board-figure {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: 1 / -1;
      justify-items: center;
      gap: 0;
      max-width: none;
      container-type: normal;
    }

    .boards.dual .move-ghost-san { font-size: clamp(2.6rem, 11cqw, 9rem); }
    .boards.dual .move-ghost-words { font-size: clamp(0.9rem, 2.5cqw, 2rem); }

    .boards.dual .board-figure > * { margin-top: 6px; }
    .boards.dual .board-figure > .move-ghost,
    .boards.dual .board-figure > .moves-sheet { margin-top: 0; }

    .boards.dual .board-figure > .ticker { grid-row: 1; }
    .boards.dual .board-figure > .plates .plate { grid-row: 4; }
    .boards.dual .board-figure[data-bottom="white"] > .plates .plate[data-side="black"],
    .boards.dual .board-figure[data-bottom="black"] > .plates .plate[data-side="white"] { grid-row: 2; }
    .boards.dual .board-figure > .board { grid-row: 3; }
    .boards.dual .board-figure > .analysis-graph { grid-row: 5; }
    .boards.dual .board-figure > .move-nav { grid-row: 6; }
    .boards.dual .board-figure > .board-caption { grid-row: 7; }

    .boards.dual .board-figure > .ticker,
    .boards.dual .board-figure > .plates .plate,
    .boards.dual .board-figure > .analysis-graph { justify-self: stretch; }
  }
}

.board-caption {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--muted);
}

.board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  width: 100%;
  aspect-ratio: 1;
  border: 3px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
  user-select: none;
  transition: filter 0.5s ease, box-shadow 0.5s ease;
}

/*
 * The end of a game, from the side you are viewing. js/personalize.js puts
 * one of these on <body> for two seconds (Personalize.react, from the sound
 * kind): the board glows gold on a win, drains of colour and dips on a loss,
 * and settles under a soft grey ring on a draw or stalemate. The shared
 * boards only; the Arena's cells have their own overlays.
 */
body.game-won .boards .board {
  box-shadow: 0 0 0 4px rgba(255, 200, 60, 0.75), 0 0 32px 8px rgba(255, 200, 60, 0.45);
  animation: game-won 0.6s ease-out;
}

body.game-lost .boards .board {
  filter: grayscale(0.85) brightness(0.72);
  animation: game-lost 0.7s ease-in;
}

body.game-drawn .boards .board {
  box-shadow: 0 0 0 4px rgba(200, 205, 215, 0.55), 0 6px 24px rgba(0, 0, 0, 0.35);
  filter: saturate(0.7);
}

@keyframes game-won {
  0% { transform: scale(1); }
  35% { transform: scale(1.025); }
  100% { transform: scale(1); }
}

@keyframes game-lost {
  0% { transform: translateY(0); }
  40% { transform: translateY(6px); }
  100% { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  body.game-won .boards .board,
  body.game-lost .boards .board {
    animation: none;
  }
}

.square {
  position: relative;
  cursor: pointer;
}

.square.light { background: var(--light-square); }
.square.dark  { background: var(--dark-square); }

.square:hover::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.15);
  pointer-events: none;
}

/* Whole-square tint used by heatmaps; sits under everything else */
.square .heat {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transition: background-color 150ms ease;
}

/* Small note in the top-left corner, e.g. attack counts */
.square .corner {
  position: absolute;
  top: 1px;
  left: 3px;
  font-size: clamp(8px, 1.5vmin, 13px);
  font-weight: 700;
  color: rgba(0, 0, 0, 0.7);
  pointer-events: none;
  font-variant-numeric: tabular-nums;
}

/*
 * Badge over a piece, e.g. a hanging-piece warning. Width and height are both
 * set: with only an aspect ratio the "!" line box is the badge's minimum
 * height, and on a phone square (12px of badge, 14px of text) that stretched
 * it into a tall oval. line-height 1 and the clipped overflow keep the text
 * inside the circle at every square size.
 */
.square .badge {
  position: absolute;
  top: 4%;
  right: 4%;
  width: 30%;
  height: 30%;
  min-height: 0;
  box-sizing: border-box;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: clamp(8px, 1.8vmin, 16px);
  line-height: 1;
  font-weight: 800;
  color: #fff;
  background: #e53935;
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  pointer-events: auto;
  cursor: help;
  z-index: 2;
}

.square .badge.target {
  background: #43a047;
}

.square .badge.soft {
  opacity: 0.8;
  border-style: dashed;
}

.legend-swatch.badge-swatch {
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #fff;
}

/* Coloured disc marker, centred in the square */
.square .highlight {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 46%;
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0.6);
  opacity: 0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35), inset 0 0 0 2px rgba(255, 255, 255, 0.35);
  transition: opacity 150ms ease, transform 150ms ease, background-color 150ms ease;
}

.square.highlighted .highlight {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Move count sits inside the disc */
.square .label {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: clamp(10px, 2.2vmin, 18px);
  font-weight: 700;
  color: rgba(0, 0, 0, 0.8);
  pointer-events: none;
}

.square .piece {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(20px, 6vmin, 52px);
  line-height: 1;
  pointer-events: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* A piece in flight (the move animation in js/board.js): a copy rides in the
   destination square, animated in from the old square's offset, while the
   real piece waits underneath hidden. The copy draws over neighbouring
   squares and arrows on its way. */
.square.arriving > .piece:not(.flying) {
  visibility: hidden;
}

.square .piece.flying {
  z-index: 6;
  will-change: transform, filter;
}

.piece svg {
  width: 84%;
  height: 84%;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));
}

.piece .body {
  fill: var(--piece-white-color);
  stroke: var(--piece-white-outline);
}

.piece .detail {
  fill: var(--piece-white-outline);
  stroke: var(--piece-white-outline);
}

.piece .line {
  fill: none;
  stroke: var(--piece-white-outline);
}

.piece.black .body {
  fill: var(--piece-black-color);
  stroke: var(--piece-black-outline);
}

.piece.black .detail {
  fill: var(--piece-black-outline);
  stroke: var(--piece-black-outline);
}

.piece.black .line {
  fill: none;
  stroke: var(--piece-black-outline);
}

.square .coord {
  position: absolute;
  font-size: clamp(9px, 1.6vmin, 14px);
  font-weight: 700;
  pointer-events: none;
  opacity: 0.9;
}

.square.light .coord { color: var(--dark-square); }
.square.dark  .coord { color: var(--light-square); }

.square .coord.file { bottom: 2px; right: 4px; }
.square .coord.rank { top: 2px; right: 4px; }

/* ---------- Obstacles and target ---------- */

.square.obstacle::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(45deg, rgba(0, 0, 0, 0.45) 0 6%, transparent 6% 14%),
    rgba(40, 40, 46, 0.55);
  pointer-events: none;
}

.square.target .piece::before {
  content: "";
  position: absolute;
  width: 58%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 3px solid #e53935;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.7), inset 0 0 0 3px rgba(255, 255, 255, 0.7);
  background: radial-gradient(circle, #e53935 0 22%, transparent 24%);
}

/* ---------- Selection, legal moves, dragging ---------- */

.square.selected {
  box-shadow: inset 0 0 0 4px rgba(255, 213, 79, 0.95);
}

.square.legal .highlight {
  width: 30%;
  box-shadow: none;
}

/* A reachable target keeps its bullseye and gains a dark halo instead of a dot. */
.square.legal.target .highlight {
  display: none;
}

.square.legal.target .piece::before {
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, 0.7),
    0 0 0 8px rgba(0, 0, 0, 0.28),
    inset 0 0 0 3px rgba(255, 255, 255, 0.7);
}

/* Free play: last move, check, and capturable pieces */
.square.last-move {
  box-shadow: inset 0 0 0 100px rgba(255, 213, 79, 0.42);
}

.square.check {
  box-shadow: inset 0 0 0 100px rgba(229, 57, 53, 0.55);
}

.square.selected.last-move,
.square.selected.check {
  box-shadow: inset 0 0 0 4px rgba(255, 213, 79, 0.95), inset 0 0 0 100px rgba(255, 213, 79, 0.42);
}

.square.capture .highlight {
  width: 84%;
  background: transparent !important;
  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.32);
}

.piece.icon.board-icon {
  background: transparent;
}

.piece.icon.board-icon svg {
  width: 100%;
  height: 100%;
  border-radius: 6px;
}

.turn-status {
  font-size: 1.08rem;
  font-weight: 700;
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--panel-2);
}

.turn-status.alert {
  background: rgba(229, 57, 53, 0.2);
  border: 1px solid #e53935;
}

.roster {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 0.92rem;
}

.roster-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 4px;
  border-radius: 4px;
}

.roster-row:hover { background: var(--panel-2); }

.roster-name { flex: 1; }

/* Clear and Reset under the roster list. */
.roster-tools {
  display: flex;
  gap: 8px;
  margin-top: 6px;
}

/* The bot's own description under its picker in a side box. */
.side-about {
  margin: 2px 0 4px;
  font-size: 0.8rem;
}

.side-about:empty { display: none; }

.roster-row button.subtle {
  padding: 0 6px;
  align-self: center;
}

.ratings-table {
  table-layout: fixed;
  font-size: 0.85rem;
}

.ratings-table th,
.ratings-table td {
  white-space: nowrap;
  padding: 3px 4px;
}

.ratings-table th:first-child,
.ratings-table td:first-child {
  width: 46%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.engine-params {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.engine-params:empty { display: none; }

/*
 * The explanation under a bot's slider, switch or picker (a param's
 * description, js/engines/engines.js): a quiet hint in the muted colour,
 * one size down, never bold. Under a switch it wraps to its own line and
 * lines up with the switch's text.
 */
.field .param-help {
  display: block;
  font-size: 0.8rem;
  line-height: 1.3;
  font-weight: 400;
  color: var(--muted);
  margin-top: 1px;
}

.field.inline {
  flex-wrap: wrap;
}

.field.inline .param-help {
  flex-basis: 100%;
  padding-left: 26px;
  margin-top: -2px;
}

/* Long switch lists fold into labelled groups (see `group` in js/engines/README.md). */
.engine-params-group {
  min-width: 0;
  margin: 2px 0 0;
  padding: 4px 10px 8px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 4px 14px;
}

.engine-params-group legend {
  padding: 0 4px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.engine-params-group .field { font-size: 0.92rem; }

.side-box {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border-radius: 8px;
  background: var(--panel-2);
}

.side-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
}

.side-head .piece.icon {
  width: 26px;
  height: 26px;
}

.turn-status {
  position: relative;
  overflow: hidden;
}

.turn-status.thinking {
  color: var(--accent);
  animation: pulse 1.2s ease-in-out infinite;
}

/*
 * The think bar: a thin line along the foot of the status that fills from
 * left to right over the think time (--think, set by the bot modes), so a
 * child sees how long the bot has left. It restarts with each turn because
 * the thinking class comes off between moves.
 */
.turn-status.thinking::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  width: 100%;
  background: var(--accent);
  transform-origin: left;
  transform: scaleX(0);
  animation: think-bar var(--think, 1000ms) linear forwards;
}

@keyframes think-bar {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/*
 * Name plates (Game.renderPlates): one per side, with the side's name, the
 * pieces it has taken and, when it is ahead, its lead. In the panel they
 * stack under the status; on a phone js/mobile.js sets them above and below
 * the board. A side choosing a move gets a pulsing dot.
 */
/*
 * The scoreboard. A whole-board mode builds a .ticker and a .plates element
 * in its panel; js/scoreboard.js moves both into the big board's figure, and
 * this column order puts the ticker on top, the far side's plate under it,
 * the board, then the near side's plate. data-bottom (set by js/app.js's
 * render: the mode's view, else Play as) says which side is near. The plates element is display:
 * contents so each plate joins the figure's column on its own; the ticker is
 * one box, ordered first.
 */
.board-figure > .plates {
  display: contents;
}

.board-figure > .ticker {
  order: -3;
  align-self: stretch;
}

.board-figure > .plates .plate {
  align-self: stretch;
  order: 1;
}

.board-figure[data-bottom="white"] > .plates .plate[data-side="black"],
.board-figure[data-bottom="black"] > .plates .plate[data-side="white"] {
  order: -1;
}

/* The shell's analysis graph joins the column under the near side's plate (js/scoreboard.js SHELL). */
.board-figure > .analysis-graph {
  order: 2;
  align-self: stretch;
  max-width: none;
}

/* Previous / next move (js/move-nav.js) sits under the graph, on every screen. */
.board-figure > .move-nav {
  order: 3;
  align-self: center;
}

.board-figure > .board-caption {
  order: 4;
}

.move-nav {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.move-nav-btn {
  min-width: 44px;
  height: 32px;
  padding: 0 12px;
  font-size: 1.25rem;
  line-height: 1;
}

.move-nav-at {
  min-width: 5ch;
  text-align: center;
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

/* The move ghost is placed from the figure's top; --board-top (js/scoreboard.js) is where the board starts. */
.board-figure > .move-ghost {
  top: var(--board-top, 0px);
}

/*
 * The move ticker: three columns, the moves before on the left trailing off
 * (oldest clipped first), the move just played large in the middle, and an
 * empty right column that keeps it centred.
 */
.ticker {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  min-height: 30px;
  padding: 2px 10px;
  box-sizing: border-box;
  border-radius: 8px;
  background: var(--panel-2);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
}

/* A tap on the ticker opens the move history over the board (js/scoreboard.js). */
.ticker[role="button"] {
  cursor: pointer;
}

.ticker[role="button"]:hover,
.ticker[aria-expanded="true"] {
  box-shadow: inset 0 0 0 1px var(--accent);
}

.board-figure > .moves-sheet {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--board-top, 0px);
  z-index: 5;
  max-height: calc(100% - var(--board-top, 0px) - 8px);
  display: flex;
  flex-direction: column;
  border-radius: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}

.moves-sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 8px 8px 12px;
  border-bottom: 1px solid var(--line);
}

.moves-sheet-title {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.moves-sheet-close {
  min-height: 32px;
  padding: 4px 12px;
}

.moves-sheet-body {
  overflow-y: auto;
  padding: 8px 12px 12px;
}

.moves-sheet-body .move-list {
  max-height: none;
}

.ticker-past {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  color: var(--muted);
  font-size: 0.85rem;
  mask-image: linear-gradient(to right, transparent, #000 40%);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 40%);
}

.ticker-move,
.ticker-now {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  white-space: nowrap;
}

.ticker-no {
  font-size: 0.75em;
  color: var(--muted);
}

.ticker-now {
  font-size: 1.3rem;
  font-weight: 700;
}

.ticker-now .ticker-empty {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--muted);
}

.ticker-pop {
  animation: ticker-pop 0.35s ease-out;
}

@keyframes ticker-pop {
  from { transform: scale(1.35); opacity: 0.4; }
  to { transform: none; opacity: 1; }
}

/* Not in a figure (a test, or a mode that keeps them in its panel): stacked. */
.plates {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.plate {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 32px;
  padding: 4px 10px;
  border-radius: 8px;
  background: var(--panel-2);
  font-size: 0.92rem;
}

/* The name and the Elo never give way; the rack of taken pieces does. */
.plate-who {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  max-width: 60%;
  min-width: 0;
}

.plate-elo {
  font-variant-numeric: tabular-nums;
  font-size: 0.82em;
  color: var(--muted);
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--panel);
}

.plate-dot {
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--piece-white-outline);
  background: var(--piece-white-color);
}

.plate[data-side="black"] .plate-dot {
  border-color: var(--piece-black-outline);
  background: var(--piece-black-color);
}

.plate-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.plate[data-thinking] .plate-name {
  color: var(--accent);
}

.plate[data-thinking] .plate-dot {
  box-shadow: 0 0 0 3px var(--accent-soft);
  animation: pulse 1.2s ease-in-out infinite;
}

/*
 * The rack of taken pieces. It takes what room is left on one line and
 * squishes rather than wrapping or pushing the name out: from the eighth
 * piece on they overlap, and past that the rack clips at its left edge,
 * which is where the smallest pieces sit (they are sorted, queen first).
 */
.plate-taken {
  display: flex;
  flex: 1 1 0;
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: 1px;
  min-width: 0;
  overflow: hidden;
}

.plate-taken:has(> :nth-child(8)) .plate-piece + .plate-piece {
  margin-left: -7px;
}

.plate-taken:has(> :nth-child(13)) .plate-piece + .plate-piece {
  margin-left: -11px;
}

.plate-piece {
  display: inline-flex;
  width: 22px;
  height: 22px;
}

.plate-piece svg {
  width: 100%;
  height: 100%;
}

.plate-lead {
  margin-left: auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.plate-lead:empty {
  display: none;
}

.move-list {
  max-height: 220px;
  overflow-y: auto;
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  background: var(--panel-2);
  border-radius: 10px;
  padding: 8px 12px;
}

.move-row {
  display: grid;
  grid-template-columns: 32px 1fr 1fr;
  gap: 6px;
  padding: 2px 0;
}

.move-no {
  color: var(--muted);
}

.move-san {
  display: flex;
  justify-content: space-between;
  gap: 6px;
}

.move-eval {
  color: var(--muted);
  font-size: 0.8em;
}

/* ---------- Analysis graph (whole-board modes) ---------- */

/* The Analysis drawer under the board: the switch and the algorithm, folded away until wanted. */
.analysis-bar {
  width: 100%;
  max-width: min(80vh, 640px);
  font-size: 0.95rem;
}

.analysis-bar > .drawer-body {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 18px;
}

.analysis-algo select {
  width: auto;
}

.analysis-graph {
  position: relative;
  width: 100%;
  max-width: min(80vh, 640px);
  background: var(--panel);
  border-radius: 8px;
  overflow: hidden;
}

.analysis-svg {
  display: block;
  cursor: crosshair;
}

.analysis-area.white { fill: rgba(238, 238, 210, 0.32); }
.analysis-area.black { fill: rgba(0, 0, 0, 0.45); }

.analysis-line {
  fill: none;
  stroke: #d6d7de;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.analysis-grid {
  stroke: var(--line);
  stroke-width: 1;
}

.analysis-now {
  fill: rgba(110, 168, 254, 0.05);
}

.analysis-label {
  fill: var(--muted);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.analysis-value {
  fill: var(--text);
  font-size: 13px;
  font-weight: 700;
}

.analysis-dot { fill: #d6d7de; }
.analysis-ring { fill: var(--panel); }

.analysis-crosshair {
  stroke: var(--accent);
  stroke-width: 1;
}

.analysis-tooltip {
  position: absolute;
  top: 6px;
  padding: 5px 8px;
  border-radius: 6px;
  background: #101318;
  border: 1px solid var(--line);
  font-size: 0.8rem;
  pointer-events: none;
  white-space: nowrap;
}

.analysis-tooltip strong {
  font-size: 0.95rem;
}

.analysis-tooltip-when {
  color: var(--muted);
}

/* Squares a pawn attacks: a red ring rather than a dot, since it cannot move there. */
.square.attack .highlight {
  width: 30%;
  background: transparent !important;
  box-shadow: inset 0 0 0 3px rgba(229, 57, 53, 0.8);
}

.square.dragging .piece {
  opacity: 0.25;
}

.drag-ghost {
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  pointer-events: none;
  z-index: 100;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
  will-change: transform;
}

/* ---------- Arrow overlay ---------- */

.board { position: relative; touch-action: none; }

/* Coordinate drill: labels hidden, answer flashes, big prompt */
.board.no-coords .coord { display: none; }

.square.flash-good { box-shadow: inset 0 0 0 100px rgba(76, 175, 80, 0.6); }
.square.flash-bad { box-shadow: inset 0 0 0 100px rgba(229, 57, 53, 0.6); }
.square.coord-reveal { box-shadow: inset 0 0 0 5px rgba(255, 213, 79, 0.95); }

.coords-prompt {
  font-size: 2.2rem;
  font-weight: 700;
  text-align: center;
  padding: 12px;
  border-radius: 8px;
  background: var(--panel-2);
}

.coords-prompt small {
  display: block;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--muted);
}

.board .overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}

.overlay .arrow {
  stroke: none;
  filter: drop-shadow(0 0.02px 0.04px rgba(0, 0, 0, 0.45));
}

/* Live preview while right-dragging a planning arrow */
.overlay .arrow-preview {
  fill: #fb8c00;
  opacity: 0.55;
}

/* ---------- Move ghost: the move's name fading over the board ---------- */

.move-ghost {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15em;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
  text-align: center;
  color: #fff;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.7), 0 0 28px rgba(0, 0, 0, 0.55);
}

.move-ghost.live { animation: move-ghost 2.2s ease-out forwards; }

.move-ghost-san {
  font-size: clamp(2.6rem, 22cqw, 9rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.02em;
}

.move-ghost-words {
  font-size: clamp(0.9rem, 5cqw, 2rem);
  font-weight: 600;
}

/* "Faintly", per Jordan: it should read, not shout. The pieces underneath stay
   the picture; the name is a caption laid over them for a moment. */
@keyframes move-ghost {
  0%   { opacity: 0; transform: scale(0.85); }
  12%  { opacity: 0.55; transform: scale(1); }
  65%  { opacity: 0.45; transform: scale(1.02); }
  100% { opacity: 0; transform: scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  @keyframes move-ghost {
    0%   { opacity: 0.5; transform: none; }
    75%  { opacity: 0.5; transform: none; }
    100% { opacity: 0; transform: none; }
  }
}

/* ---------- Panel ---------- */

#panel {
  flex: 0 1 300px;
  background: var(--panel);
  border-radius: 12px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Every mode's controls stack with air between them. */
#viz-controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/*
 * A drawer (UI.drawer): a section that folds behind its title. Native
 * <details>, styled like the "Make it yours" section: a chevron that turns,
 * the body indented under it. Open on a desktop, closed on a phone.
 */
.drawer {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
}

.drawer > .drawer-title {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  min-height: 36px;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.drawer > .drawer-title::-webkit-details-marker { display: none; }

.drawer > .drawer-title::before {
  content: "";
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
  flex-shrink: 0;
  margin-right: 2px;
}

.drawer[open] > .drawer-title::before {
  transform: rotate(45deg);
}

.drawer > .drawer-title:hover {
  color: var(--text);
}

.drawer > .drawer-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 2px 12px 12px;
}

#viz-controls:empty { display: none; }

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.95rem;
}

.field span { color: var(--label); }

.field.inline {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.field.inline span { color: var(--text); }

/* Native controls big enough for small fingers and coloured to match. */
input[type="checkbox"],
input[type="radio"] {
  width: 18px;
  height: 18px;
  margin: 0;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

input[type="range"] {
  accent-color: var(--accent);
  cursor: pointer;
}

select, input[type="range"] {
  width: 100%;
}

select, button {
  font: inherit;
  font-size: 0.95rem;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--control);
  color: var(--text);
}

button {
  cursor: pointer;
  transition: background-color 0.1s ease, border-color 0.1s ease;
}

button:hover {
  border-color: var(--accent);
  background: #3a3d48;
}

#clear-btn {
  margin-top: 4px;
}

.hint {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--muted);
}

.radio-group {
  display: flex;
  gap: 6px;
}

.radio {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 6px;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  font-size: 0.92rem;
}

.radio:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
  font-weight: 600;
}

.radio input { margin: 0; }

.button-row {
  display: flex;
  gap: 6px;
}

.button-row button {
  flex: 1;
}

button:disabled {
  opacity: 0.45;
  cursor: default;
}

button:disabled:hover {
  border-color: var(--line);
}

button.subtle {
  font-size: 0.85rem;
  padding: 4px 10px;
  color: var(--muted);
  background: transparent;
  align-self: flex-start;
}

/* ---------- Sprint ---------- */

.sprint-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--panel-2);
}

.sprint-clock {
  font-size: 2rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.sprint-clock.urgent {
  color: #ff7043;
}

.sprint-counters {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.sprint-solved {
  font-weight: 600;
}

.strikes {
  display: flex;
  gap: 4px;
}

.strike {
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  border: 1px solid var(--line);
  color: var(--line);
  font-weight: 700;
  font-size: 0.85rem;
}

.strike.hit {
  background: #e53935;
  border-color: #e53935;
  color: #fff;
}

.ledger {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.ledger:empty { display: none; }

.chip {
  min-width: 28px;
  padding: 3px 7px;
  border-radius: 999px;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #111;
}

.chip.par  { background: #66bb6a; }
.chip.over { background: #ffee58; }

.score-box {
  text-align: center;
  padding: 12px;
  border-radius: 8px;
  background: rgba(110, 168, 254, 0.12);
  border: 1px solid var(--accent);
}

.score-box:empty { display: none; }

.score-reason {
  color: var(--muted);
  font-size: 0.85rem;
}

.score-main {
  font-size: 1.6rem;
  font-weight: 700;
}

.score-sub {
  font-size: 0.85rem;
  color: var(--muted);
}

.bests {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
}

.bests-summary {
  display: flex;
  gap: 8px;
}

.stat-tile {
  flex: 1;
  text-align: center;
  padding: 8px 4px;
  border-radius: 6px;
  background: var(--panel-2);
}

.stat-value {
  font-size: 1.3rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.stat-label {
  color: var(--muted);
  font-size: 0.75rem;
}

.bests-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.bests-table th,
.bests-table td {
  padding: 4px 6px;
  text-align: right;
  border-bottom: 1px solid var(--line);
}

.bests-table th:first-child,
.bests-table td:first-child {
  text-align: left;
}

.bests-table th {
  color: var(--muted);
  font-weight: 600;
}

.info {
  font-size: 0.98rem;
  line-height: 1.45;
  word-break: break-word;
}

.info:empty { display: none; }

.value {
  font-weight: 600;
  color: var(--accent);
}

/* ---------- Legend ---------- */

#legend {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--panel-2);
  font-size: 0.92rem;
}

#legend:empty { display: none; }

/* Modes borrow .legend-title for their own small headings; only the real legend shouts. */
.legend-title {
  color: var(--muted);
  font-size: 0.88rem;
  font-weight: 600;
}

#legend .legend-title {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.legend-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.legend-swatch {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
}

.legend-swatch.ring {
  background: transparent;
  border: 3px solid;
}

/* ---------- Personalization: themes, team colours, profile, confetti ---------- */

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.player-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 6px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--line);
  font-size: 0.9rem;
  white-space: nowrap;
}

.player-badge .player-avatar { font-size: 1.15rem; line-height: 1; }
.player-badge .player-name { font-weight: 600; }

.pref-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pref-label {
  color: var(--label);
  font-size: 0.88rem;
}

.swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-width: 170px;
}

.swatch {
  width: 24px;
  height: 24px;
  padding: 0;
  margin: 0;
  border-radius: 50%;
  border: 2px solid transparent;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45) inset, 0 1px 2px rgba(0, 0, 0, 0.35);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.08s ease;
  color: inherit;
}

.swatch:hover { transform: scale(1.15); }

.swatch.selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);
}

/* Piece-style swatches show a knight drawn in that style. */
.swatch-art {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--bg);
  position: static;
}
.swatch-art svg { width: 26px; height: 26px; }
.swatch-art.selected { background: var(--panel); }

/* The "any colour" picker: a native colour input dressed as a rainbow swatch. */
.swatch-custom {
  -webkit-appearance: none;
  appearance: none;
  background: conic-gradient(#f44, #fb3, #4c4, #4cf, #55f, #f4f, #f44);
  overflow: hidden;
}
.swatch-custom::-webkit-color-swatch-wrapper { padding: 0; }
.swatch-custom::-webkit-color-swatch { border: none; opacity: 0; }
.swatch-custom::-moz-color-swatch { border: none; opacity: 0; }

.pref-name {
  width: 100%;
  max-width: 160px;
  padding: 5px 8px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
}

.pref-name:focus { outline: none; border-color: var(--accent); }

.confetti {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1000;
}

/* Theme-specific touches. Squares come from the theme's CSS variables; these are extras. */
[data-theme="space"] .square.dark  { box-shadow: inset 0 0 12px rgba(120, 140, 255, 0.18); }
[data-theme="space"] .square.light { box-shadow: inset 0 0 10px rgba(160, 170, 255, 0.12); }
[data-theme="chalk"] .square.light .coord,
[data-theme="chalk"] .square.dark  .coord { color: #dfe8e0; }
[data-theme="space"] .square.light .coord,
[data-theme="space"] .square.dark  .coord { color: #c9ccff; }

.pref-sound-pack,
.pref-select { width: 100%; padding: 6px 8px; font-size: 0.92rem; }

/* ---------- Leaderboard ---------- */

.lb-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.lb-podium {
  display: grid;
  grid-template-columns: 1fr 1.15fr 1fr;
  gap: 6px;
  align-items: end;
}

.lb-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 6px 6px;
  border-radius: 10px 10px 4px 4px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text);
  min-width: 0;
  cursor: pointer;
}

.lb-step:hover { border-color: var(--accent); }
.lb-step.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.lb-step-1 { padding-top: 14px; padding-bottom: 12px; background: linear-gradient(180deg, rgba(245, 197, 66, 0.18), var(--panel-2) 70%); }
.lb-step-2 { background: linear-gradient(180deg, rgba(201, 206, 216, 0.14), var(--panel-2) 70%); }
.lb-step-3 { background: linear-gradient(180deg, rgba(205, 138, 75, 0.16), var(--panel-2) 70%); }
.lb-medal { font-size: 1.4rem; line-height: 1; }
.lb-step-1 .lb-medal { font-size: 1.8rem; }
.lb-step-name {
  font-size: 0.78rem;
  font-weight: 600;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-step-elo { font-size: 1.05rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.lb-step-1 .lb-step-elo { font-size: 1.25rem; }
.lb-step-record { font-size: 0.72rem; color: var(--muted); font-variant-numeric: tabular-nums; }

.lb-sort > span { white-space: nowrap; }
.lb-sort select { padding: 3px 6px; font-size: 0.85rem; flex: 1; }
.lb-table th:nth-child(2), .lb-table td:nth-child(2) { text-align: left; }

.lb-table {
  table-layout: fixed;
  font-size: 0.85rem;
  width: 100%;
}
.lb-table th, .lb-table td { white-space: nowrap; padding: 3px 4px; }
.lb-table th:first-child, .lb-table td:first-child { width: 26px; }
.lb-table th:nth-child(2), .lb-table td:nth-child(2) { width: auto; overflow: hidden; text-overflow: ellipsis; }
.lb-table th:nth-child(3), .lb-table td:nth-child(3) { width: 44px; text-align: right; }
.lb-table th:nth-child(4), .lb-table td:nth-child(4) { width: 36px; text-align: right; }
.lb-table th:nth-child(5), .lb-table td:nth-child(5) { width: 58px; }
.lb-table th:nth-child(6), .lb-table td:nth-child(6) { width: 26px; text-align: right; }
.lb-table tbody tr { cursor: pointer; }
.lb-table tbody tr:hover { background: var(--panel-2); }
.lb-table tbody tr.selected { background: rgba(110, 168, 254, 0.14); }
.lb-table tbody tr:focus-visible { outline: 1px solid var(--accent); }
.lb-rank { font-weight: 700; color: var(--muted); }
.lb-rank[style] { color: var(--bar); }
.lb-elo { font-weight: 600; font-variant-numeric: tabular-nums; }
.lb-delta { font-variant-numeric: tabular-nums; color: var(--muted); }
.lb-delta.up { color: #4fd1b0; }
.lb-delta.down { color: #ef6f6f; }
.lb-games { color: var(--muted); font-variant-numeric: tabular-nums; }

.lb-form { display: inline-flex; gap: 3px; align-items: center; }
.lb-form-none { color: var(--muted); }
.lb-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.lb-dot-w { background: #4fd1b0; }
.lb-dot-l { background: #ef6f6f; }
.lb-dot-d { background: #8a8d96; }

.lb-detail {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.lb-detail-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.lb-detail-name { font-weight: 600; font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-detail-elo { font-weight: 700; font-size: 1.05rem; font-variant-numeric: tabular-nums; }

.lb-spark { width: 100%; height: 64px; display: block; }
.lb-spark-base { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 3; }
.lb-spark-area { fill: rgba(110, 168, 254, 0.18); }
.lb-spark-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.lb-spark-dot { fill: var(--accent); }
.lb-spark-empty { fill: var(--muted); font-size: 12px; }

.lb-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.lb-fact { display: flex; flex-direction: column; align-items: center; padding: 4px; border-radius: 6px; background: var(--panel); }
.lb-fact-value { font-weight: 700; font-variant-numeric: tabular-nums; font-size: 0.9rem; }
.lb-fact-label { font-size: 0.68rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }

.lb-h2h { display: flex; flex-direction: column; gap: 3px; }
.lb-h2h-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 70px 46px;
  align-items: center;
  gap: 6px;
  padding: 2px 4px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font-size: 0.78rem;
  text-align: left;
  cursor: pointer;
  border-radius: 4px;
}
.lb-h2h-row:hover { background: var(--panel); }
.lb-h2h-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-h2h-bar {
  height: 8px;
  border-radius: 4px;
  background: linear-gradient(90deg, #4fd1b0 var(--pct, 50%), #ef6f6f var(--pct, 50%));
}
.lb-h2h-score { text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); }

.lb-summary { display: flex; flex-direction: column; gap: 3px; font-size: 0.82rem; }
.lb-summary-line { color: var(--muted); }
.lb-file-note { font-size: 0.72rem; opacity: 0.7; }

/* The bar chart on the stage: one row per bot, longer is stronger, the
   dashed marker is the starting rating. --bar carries the row's colour. */
.lb-chart {
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px 18px 18px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
}

.lb-chart-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.lb-chart-title {
  font-size: 1.1rem;
  font-weight: 700;
}

.lb-chart-note {
  color: var(--muted);
  font-size: 0.88rem;
}

.lb-row {
  display: grid;
  grid-template-columns: 2em minmax(150px, 0.42fr) 1fr 4.5em;
  align-items: center;
  gap: 12px;
  padding: 5px 8px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: opacity 0.2s ease, background-color 0.15s ease;
}

.lb-row:hover { background: var(--panel-2); border-color: transparent; }
.lb-row.selected { background: var(--accent-soft); border-color: var(--accent); }
.lb-row.dim { opacity: 0.45; }

.lb-row-rank {
  font-weight: 800;
  text-align: right;
  color: var(--bar);
  font-variant-numeric: tabular-nums;
}

.lb-row-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.lb-row-track {
  position: relative;
  display: block;
  height: 18px;
  border-radius: 9px;
  background: var(--panel-2);
}

.lb-row-fill {
  display: block;
  height: 100%;
  width: var(--w, 0%);
  min-width: 8px;
  border-radius: 9px;
  background: var(--bar);
  box-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.18);
  transition: width 0.4s ease;
}

.lb-row-start {
  position: absolute;
  top: -4px;
  bottom: -4px;
  left: var(--start, 50%);
  border-left: 2px dashed rgba(255, 255, 255, 0.45);
  pointer-events: none;
}

.lb-row-elo {
  font-weight: 700;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.lb-row-elo.provisional { color: var(--muted); }

.lb-chart-empty {
  padding: 48px 24px;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.lb-chart-empty-title {
  font-size: 1.3rem;
  font-weight: 700;
}

.lb-chart-empty-text {
  color: var(--muted);
  max-width: 34em;
  margin: 0 auto;
}

@media (max-width: 600px) {
  .lb-row { grid-template-columns: 1.6em minmax(80px, 0.4fr) 1fr 4em; gap: 8px; }
  .lb-chart-note { display: none; }
}

.personalize-details summary {
  cursor: pointer;
  color: var(--text);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  user-select: none;
}
.personalize-details summary::-webkit-details-marker { display: none; }
.personalize-details summary::before {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
  margin-left: 3px;
}
.personalize-details[open] summary::before { transform: rotate(45deg); }

.personalize {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-top: 10px;
}

/* ---------- Sound designer (js/sound-designer.js) ---------- */

.sound-designer {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.sd-intro {
  margin: 0;
}

.sd-event {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
}

/* The sidebar is narrow: the event's name on its own line, its buttons under it. */
.sd-event-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
}

.sd-event-name {
  flex: 1 0 100%;
  font-weight: 600;
}

.sd-play {
  min-width: 72px;
}

.sd-layer {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px 8px 8px;
  border-radius: 6px;
  background: var(--panel-2);
}

.sd-layer .field {
  font-size: 0.85rem;
  gap: 2px;
}

.sd-layer-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
}

.sd-layer-no {
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  flex: 1 1 auto;
}

.sd-select {
  width: auto;
  padding: 4px 8px;
  font-size: 0.85rem;
}

.sd-remove {
  min-width: 32px;
  padding: 2px 8px;
}

.sd-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.sd-share {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-2);
}

.sd-share > summary {
  list-style: none;
  cursor: pointer;
  padding: 8px 12px;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.sd-share-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 12px 12px;
}

.sd-json {
  width: 100%;
  box-sizing: border-box;
  min-height: 72px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font: 12px ui-monospace, Consolas, monospace;
  resize: vertical;
}

/* ---------- Position lab ---------- */

.lab-message {
  font-size: 0.85rem;
  color: #ffab91;
}

.lab-message:empty { display: none; }

.palette {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.palette-btn {
  width: 40px;
  height: 40px;
  padding: 2px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.palette-btn .piece.icon {
  width: 32px;
  height: 32px;
}

.palette-btn.erase {
  font-weight: 700;
  color: #ffab91;
}

.palette-btn.active,
.button-row button.active {
  border-color: var(--accent);
  background: rgba(110, 168, 254, 0.14);
}

.castling-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px 8px;
  font-size: 0.85rem;
}

.fen-row {
  display: flex;
  gap: 6px;
  align-items: flex-start;
}

.fen-input,
.pgn-out {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 0.8rem;
  font-family: ui-monospace, Consolas, monospace;
  padding: 5px 7px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text);
}

.pgn-out {
  resize: vertical;
}

.lab-setup,
.lab-play,
.lab-export {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.lab-numbers {
  font-size: 0.85rem;
  color: var(--muted);
}

.bench {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.bench-engine {
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--panel-2);
}

.bench-head {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.bench-name {
  font-weight: 600;
}

.bench-table td button.subtle {
  padding: 1px 8px;
}

/* ---------- Arena: many small boards at once ----------
   Markup comes from js/visualizations/arena.js; the class names and data
   attributes are the contract. Sizes derive from --arena-cols so 4 to 16
   boards all fit. The overlay's fade is the animation arena.js waits for. */

.stage {
  width: 100%;
}

.arena-grid {
  display: grid;
  grid-template-columns: repeat(var(--arena-cols, 3), minmax(0, 1fr));
  gap: clamp(8px, calc(40px / var(--arena-cols, 3)), 16px);
  width: 100%;
  max-width: min(100%, 90vh + 120px, 900px);
  margin: 0 auto;
}

.arena-cell {
  position: relative;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  padding: 8px 8px 10px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.arena-cell[data-state="idle"] { opacity: 0.55; }

/* This board's bot is thinking: only its side dot turns blue, and slowly, so
   sixteen boards changing turn every second do not flicker. */
.arena-cell[data-thinking="self"] .arena-name::before {
  background: var(--accent);
  border-color: var(--accent);
}

/* Small boards: thin border, no shadow, no hover flash, nothing to click.
   They take no pointer input at all: a finger on one scrolls the page
   instead of starting a drag or a long press, and a mouse cannot draw arrows
   on a game it is only watching. */
.arena-board {
  border-width: 2px;
  border-radius: 4px;
  box-shadow: none;
  pointer-events: none;
  touch-action: auto;
}

.arena-board .square { cursor: default; }
.arena-board .square:hover::after { display: none; }

/* Plates: opponent above the board, this board's bot below with a side dot and score. */
.arena-opponent,
.arena-name {
  min-width: 0;
  text-align: center;
  line-height: 1.3;
}

.arena-opponent {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: clamp(0.7rem, calc(2.4rem / var(--arena-cols, 3)), 0.85rem);
  color: var(--muted);
}

.arena-name {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4em;
  font-size: clamp(0.82rem, calc(3rem / var(--arena-cols, 3)), 1.1rem);
  font-weight: 700;
}

.arena-cell[data-side] .arena-name::before {
  content: "";
  flex-shrink: 0;
  width: 0.7em;
  height: 0.7em;
  border-radius: 50%;
  background: var(--piece-white-color);
  border: 1px solid var(--piece-white-outline);
  transition: background-color 0.4s ease, border-color 0.4s ease;
}

.arena-cell[data-side="black"] .arena-name::before {
  background: var(--piece-black-color);
  border-color: var(--piece-black-outline);
}

.arena-name-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.arena-score {
  flex-shrink: 0;
  font-weight: 600;
  font-size: 0.85em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Elo on the plate: a small pill after the score, "1000?" while provisional; an idle plate has none, so no empty pill. */
.arena-elo:empty { display: none; }

.arena-elo {
  flex-shrink: 0;
  padding: 0 0.45em;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  font-size: 0.78em;
  font-weight: 700;
  color: var(--label);
  font-variant-numeric: tabular-nums;
}

.arena-elo[data-provisional] {
  color: var(--muted);
  border-style: dashed;
}

/* The rating change from the game that just ended floats up off the plate
   and fades on the same clock as the result pill. */
.arena-cell[data-delta]::after {
  content: attr(data-delta);
  position: absolute;
  top: 6px;
  right: 8px;
  padding: 0.1em 0.5em;
  border-radius: 999px;
  font-size: clamp(0.8rem, calc(3rem / var(--arena-cols, 3)), 1rem);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: #0b2b0e;
  background: #66bb6a;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  pointer-events: none;
  animation: arena-delta 2.2s ease-out forwards;
}

.arena-cell[data-delta^="-"]::after {
  color: #fff;
  background: #ef6f6f;
}

@keyframes arena-delta {
  0% { opacity: 0; transform: translateY(6px); }
  15% { opacity: 1; transform: translateY(0); }
  70% { opacity: 1; transform: translateY(-6px); }
  100% { opacity: 0; transform: translateY(-14px); }
}

@media (prefers-reduced-motion: reduce) {
  .arena-cell[data-delta]::after { animation: arena-delta-still 2.2s forwards; }
}

@keyframes arena-delta-still {
  0%, 70% { opacity: 1; }
  100% { opacity: 0; }
}

/* Standings under the tally: rank, name, Elo, change, games. */
.arena-standings {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.arena-standings .lb-table th:nth-child(5),
.arena-standings .lb-table td:nth-child(5) {
  width: 40px;
  text-align: right;
}

/* The result: hidden until the cell is done, then pops in and fades out.
   arena.js resets the cell on the animationend of arena-overlay-out. */
.arena-overlay {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  pointer-events: none;
  opacity: 0;
}

.arena-cell[data-state="done"] .arena-overlay {
  display: flex;
  animation: arena-overlay-in 0.35s cubic-bezier(0.2, 1.4, 0.4, 1) forwards,
             arena-overlay-out 0.6s ease-in 1.6s forwards;
}

.arena-overlay-text {
  max-width: 92%;
  padding: 0.35em 0.9em;
  border-radius: 999px;
  font-size: clamp(0.85rem, calc(4rem / var(--arena-cols, 3)), 1.5rem);
  font-weight: 800;
  letter-spacing: 0.01em;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #111;
  background: #ffd54f;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
}

.arena-cell[data-outcome="win"] .arena-overlay { background: rgba(102, 187, 106, 0.28); }
.arena-cell[data-outcome="win"] .arena-overlay-text { background: #66bb6a; color: #0b2b0e; }
.arena-cell[data-outcome="win"] .arena-overlay-text::before { content: "🎉 "; }

.arena-cell[data-outcome="lose"] .arena-overlay { background: rgba(0, 0, 0, 0.42); }
.arena-cell[data-outcome="lose"] .arena-overlay-text { background: #3b3d47; color: #eceef2; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6); }

.arena-cell[data-outcome="draw"] .arena-overlay { background: rgba(255, 213, 79, 0.18); }
.arena-cell[data-outcome="draw"] .arena-overlay-text { background: #ffd54f; color: #2a2000; }
.arena-cell[data-outcome="draw"] .arena-overlay-text::before { content: "🤝 "; }

@keyframes arena-overlay-in {
  from { opacity: 0; transform: scale(0.7); }
  to { opacity: 1; transform: scale(1); }
}

@keyframes arena-overlay-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .arena-cell[data-state="done"] .arena-overlay {
    animation: arena-overlay-in 0.01s forwards, arena-overlay-out 0.01s 1.6s forwards;
  }
}

/* Panel: the bots taking part, two to a row, with a group heading spanning each run. */
.arena-participants {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 4px 10px;
  font-size: 0.92rem;
}

.arena-participants .legend-title {
  grid-column: 1 / -1;
  margin-top: 6px;
}

.arena-participants .legend-title:first-child { margin-top: 0; }

/* ---------- Bot trial ---------- */

/* The bot's parameters sit in a fieldset so the whole form greys out together while a run is live. */
.trial-params {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}

.trial-params:disabled { opacity: 0.55; }

/* The opponents: the Arena's checklist, two to a row, group headings spanning each run. */
.trial-opponents {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 4px 10px;
  font-size: 0.92rem;
}

.trial-opponents .legend-title {
  grid-column: 1 / -1;
  margin-top: 6px;
}

.trial-opponents .legend-title:first-child { margin-top: 0; }

/* The report: the headline reads as the result, the rest as notes. */
.trial-report {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.trial-headline {
  margin: 0;
  font-size: 1.02rem;
  font-weight: 700;
  line-height: 1.4;
}

.trial-distinct { margin: 0; }

.trial-table { overflow-x: auto; }

.trial-opponent-table { font-size: 0.85rem; }

.trial-opponent-table th,
.trial-opponent-table td { padding: 3px 5px; }

.trial-opp-name { white-space: nowrap; }

.trial-opp-elo {
  margin-left: 6px;
  color: var(--muted);
  font-size: 0.8em;
}

/* The words under each opponent's numbers: how the games were lost and drawn, where it went bad. */
.trial-opp-detail td {
  text-align: left;
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.35;
  padding-top: 0;
  white-space: normal;
}

.trial-opp-detail td:first-child { padding-left: 12px; }

.trial-lines {
  margin: 0;
  padding-left: 18px;
  font-size: 0.9rem;
  line-height: 1.45;
}

.trial-lines li + li { margin-top: 4px; }

.trial-report > button.subtle { align-self: flex-start; }

/* The games: one line each, the result coloured by its dot, Replay at the end. */
.trial-games {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.9rem;
}

.trial-game {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 4px;
  border-radius: 4px;
}

.trial-game::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--muted);
}

.trial-game-win::before { background: var(--accent); }
.trial-game-lose::before { background: #e53935; }

.trial-game-text { flex: 1; min-width: 0; }

.trial-game button.subtle { padding: 0 6px; }

/* The textarea the clipboard fallback selects from: present, never seen. */
.trial-clipboard {
  position: fixed;
  left: -9999px;
  top: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* ---------- Tactics drills ---------- */

.piece.icon.tactics-icon svg {
  width: 80%;
  height: 80%;
}

/* The line of a pin, skewer or masked attack: a soft red wash over each square. */
.square.tactic-line {
  box-shadow: inset 0 0 0 100px rgba(229, 57, 53, 0.22);
}

/* Where the attacker came from: a dashed ghost ring. */
.square.tactic-origin::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 56%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 3px dashed #8e24aa;
  opacity: 0.8;
  pointer-events: none;
}

.tactics-nav {
  align-items: center;
  justify-content: space-between;
}

.tactics-counter {
  font-weight: 600;
  color: var(--label);
  white-space: nowrap;
}

.tactics-layers {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.tactics-quiz {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.tactics-streak {
  font-weight: 600;
  color: var(--accent);
}
