/* Colours and typography follow the site so the page does not feel bolted on.
   The custom properties are the same names and values the site's stylesheet
   defines, and the theme is chosen the same way: a `theme` entry in
   localStorage of system / light / dark. */

/* Roboto is what lichess itself sets for headings and UI chrome — see
   `%roboto` (`font-family: Roboto, sans-serif`) in lichess-org/lila's
   `ui/lib/css/abstract/_extends.scss`, used throughout `ui/lib/css/component/
   _button.scss` and `ui/lib/css/base/_typography.scss`'s heading rules.
   Self-hosted (Apache-2.0, Google) rather than left to "if the visitor's OS
   happens to have it" the way this page's fonts previously were — see
   web/vendor/fonts/roboto/ATTRIBUTION.md for where the file came from and
   why only this one family is vendored. One `@font-face` with a weight range
   covers every weight below because the file is a variable font (source
   confirms this: four separate Google Fonts `@font-face` weight rules for
   Roboto's "latin" subset all point at the exact same bytes). */
@font-face {
  font-family: "Roboto";
  src: url("../vendor/fonts/roboto/roboto-latin-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;
  --global-bg-color: #ffffff;
  --global-code-bg-color: rgba(181, 9, 172, 0.05);
  --global-text-color: #000000;
  --global-text-color-light: #828282;
  --global-theme-color: #b509ac;
  --global-hover-color: #b509ac;
  --global-hover-text-color: #ffffff;
  --global-divider-color: rgba(0, 0, 0, 0.1);
  --global-card-bg-color: #ffffff;
  /* Universal "this is destructive" red — lila's `$c-bad`, hsl(0 60% 50%),
     which is not overridden by the light theme either (`_theme.light.scss`
     leaves it inherited from `_theme.default.scss`), so one value serves
     both themes here too. Used only for resign, never as a second accent. */
  --danger-color: hsl(0 60% 50%);

  /* lila's `$box-radius-size`, `var(---ui-roundness, 7px)` in
     `ui/lib/css/abstract/_variables.scss` — the rounding on every button,
     panel and input across the site. `--radius-sm` mirrors its
     `$small-box-radius-size` (that variable halved) for smaller chips like
     the clock and the connection banner. */
  --radius: 7px;
  --radius-sm: 4px;

  /* Lichess's own default board theme ("brown"), sampled from the actual
     pixels of public/images/board/brown.png in lichess-org/lila (and
     matching the hex pair in that repo's bin/gen/generate_css_for_a_board_
     with_hexcodes.py) — not a guess or a lookalike. */
  --light-square: #f0d9b5;
  --dark-square: #b58863;
  --square-selected: rgba(181, 9, 172, 0.35);
  --square-last: rgba(233, 202, 60, 0.65);
  --square-check: radial-gradient(circle, rgba(220, 40, 40, 0.85) 12%, rgba(220, 40, 40, 0) 72%);
}

html[data-theme="dark"] {
  color-scheme: dark;
  --global-bg-color: #1c1c1d;
  --global-code-bg-color: #2c3237;
  --global-text-color: #e8e8e8;
  --global-text-color-light: #828282;
  --global-theme-color: #2698ba;
  --global-hover-color: #2698ba;
  --global-hover-text-color: #ffffff;
  --global-divider-color: #424246;
  --global-card-bg-color: #212529;

  /* Same lichess "brown" board colours as the light theme — the board is
     meant to look like lichess's regardless of which site skin it sits in. */
  --light-square: #f0d9b5;
  --dark-square: #b58863;
  --square-selected: rgba(38, 152, 186, 0.45);
  --square-last: rgba(233, 202, 60, 0.55);
}

* {
  box-sizing: border-box;
}

/* Several things here are flex or grid, which would otherwise beat `hidden`. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--global-bg-color);
  color: var(--global-text-color);
  /* lila's own fallback chain (`%base-font-fallback`, `_extends.scss`) is
     "Noto Sans, sans-serif" for body copy specifically — Roboto there is
     reserved for headings and buttons via the separate `%roboto` rule. Noto
     Sans and Roboto are both Google's own in-house grotesques and are very
     close in shape and metrics at body sizes, so rather than vendor a
     second whole font family for a difference that is hard to see, this
     page uses the one it already carries (Roboto, self-hosted above)
     everywhere and leans on the system stack only as a fallback if that
     somehow fails to load. */
  font-family: "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 1rem;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

h1,
h2,
h3 {
  /* No trace of a slab serif anywhere in lila's current stylesheets —
     `Roboto Slab` (what this rule used to say) does not appear once in the
     repository; it reads like a leftover from a much older lichess design.
     lila's actual heading rule (`ui/lib/css/base/_typography.scss`) is
     `%roboto`: plain Roboto at weight 300, the same family as the rest of
     the page, just lighter. */
  font-family: "Roboto", "Segoe UI", Helvetica, Arial, sans-serif;
  font-weight: 300;
  margin: 0;
}

.wrap {
  max-width: 60rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
}

.page-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid var(--global-divider-color);
  padding-bottom: 0.6rem;
  margin-bottom: 1.5rem;
}

.page-head h1 {
  font-size: 2rem;
  letter-spacing: 0.02em;
}

a,
.link {
  color: var(--global-theme-color);
  text-decoration: none;
}

a:hover {
  color: var(--global-hover-color);
  text-decoration: underline;
}

.hint {
  color: var(--global-text-color-light);
  font-size: 0.85rem;
  margin: 0.35rem 0 0;
}

.error {
  color: #b71c1c;
  font-size: 0.9rem;
  margin: 0.75rem 0 0;
}

html[data-theme="dark"] .error {
  color: #ff8a80;
}

.connection {
  border: 1px solid var(--global-divider-color);
  border-left: 3px solid var(--global-theme-color);
  background: var(--global-card-bg-color);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.75rem;
  margin: 0 0 1rem;
  font-size: 0.9rem;
}

/* --------------------------------------------------------------- controls */

button {
  font: inherit;
  cursor: pointer;
  border-radius: var(--radius);
  border: 1px solid var(--global-divider-color);
  background: transparent;
  color: var(--global-text-color);
  padding: 0.55rem 1.1rem;
  /* lila's own button (`ui/lib/css/component/_button.scss`'s `.button`):
     uppercase, medium weight, a touch of letter-spacing — one of its more
     recognisable traits, not just a colour. Left off the segmented chips,
     the theme toggle and the promotion picker below, which read as
     labels/icons rather than commands. */
  text-transform: uppercase;
  font-weight: 500;
  letter-spacing: 0.02em;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, filter 0.15s ease;
  /* Every button on the page can plausibly be tapped twice in quick
     succession (select/deselect, resign/confirm, rematch, theme toggle...):
     without this, a fast double-tap is read by the browser as a zoom
     gesture instead of two clicks, on iOS Safari in particular. */
  touch-action: manipulation;
}

button:hover {
  background: var(--global-hover-color);
  color: var(--global-hover-text-color);
  border-color: var(--global-hover-color);
}

button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--global-theme-color) 35%, transparent);
}

button.primary {
  background: var(--global-theme-color);
  border-color: var(--global-theme-color);
  color: #ffffff;
}

button.primary:hover {
  /* lila's own hover on `.button`: `filter: brightness(1.15)` rather than a
     colour swap, since it is already the filled/accent style. */
  filter: brightness(1.15);
  color: #ffffff;
}

/* Resigning is the one button lila itself special-cases with a different
   hover colour instead of the shared brightness bump (`ui/round/css/
   _control.scss`: `&.resign:not(.disabled):hover { background: $c-bad; }`) —
   a deliberate exception for the one destructive action here, not an
   inconsistency with the rest of the accent-colour system. */
#resign:hover {
  background: var(--danger-color);
  border-color: var(--danger-color);
  color: #ffffff;
}

button:disabled {
  opacity: 0.45;
  cursor: default;
  background: transparent;
  color: var(--global-text-color);
  border-color: var(--global-divider-color);
  filter: none;
}

.icon-button {
  border: none;
  color: var(--global-text-color-light);
  font-size: 0.8rem;
  text-transform: lowercase;
  font-weight: 400;
  letter-spacing: normal;
  padding: 0.2rem 0.5rem;
}

.panel {
  border: 1px solid var(--global-divider-color);
  background: var(--global-card-bg-color);
  border-radius: var(--radius);
  padding: 1.25rem;
  max-width: 32rem;
}

.field {
  margin-bottom: 1.4rem;
}

.field > label {
  display: block;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--global-text-color-light);
  margin-bottom: 0.4rem;
}

/* `appearance: none` strips the OS's own combo-box chrome so the rounding,
   border and focus ring below actually show instead of being drawn over by
   the platform; the dropdown arrow is redrawn by hand as a background image
   since removing the native one removes it entirely. `#828282` in the arrow
   is `--global-text-color-light`, which happens to be identical in both
   themes, so one arrow serves both without a second data URI. */
select {
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  color: var(--global-text-color);
  background-color: var(--global-bg-color);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23828282' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 0.7rem;
  border: 1px solid var(--global-divider-color);
  border-radius: var(--radius);
  padding: 0.5rem 2.25rem 0.5rem 0.75rem;
  width: 100%;
  cursor: pointer;
  transition: border-color 0.15s ease;
}

select:hover {
  border-color: var(--global-text-color-light);
}

select:focus-visible {
  outline: none;
  border-color: var(--global-theme-color);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--global-theme-color) 35%, transparent);
}

.segmented {
  display: flex;
  border: 1px solid var(--global-divider-color);
  border-radius: var(--radius);
  overflow: hidden;
  width: fit-content;
}

.segmented button {
  border: none;
  border-right: 1px solid var(--global-divider-color);
  border-radius: 0;
  padding: 0.45rem 1.1rem;
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
}

.segmented button:last-child {
  border-right: none;
}

.segmented button.on {
  background: var(--global-theme-color);
  color: #ffffff;
}

.slider-row {
  display: block;
  margin-top: 0.9rem;
}

.slider-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--global-text-color-light);
}

.slider-label b {
  color: var(--global-text-color);
  font-weight: 500;
}

/* A custom track and thumb rather than the OS's own slider — lila's own
   range input (`ui/lib/css/form/_range.scss`) is exactly this shape: a
   plain rounded track (its `range-track` mixin: `border-radius:
   $box-radius-size; background: $c-shade;`) and an oblong rounded thumb
   (`range-thumb`: `border-radius: $box-radius-size; width: 1.5em; height:
   1em;`), styled the same way cross-browser with the vendor pseudo-elements
   below. One thing here is *not* from lila: its track has no filled
   progress portion at all, just a flat shade colour the whole way — for
   these particular sliders (choosing a value out of a long list of stops,
   where "how far along" is genuinely informative) a filled portion in the
   accent colour reads better, so `--fill` (set from `main.js` on input) adds
   one. That is this app's own call, not lifted from a source. */
input[type="range"] {
  --fill: 0%;
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 1.4rem;
  background: transparent;
  margin-top: 0.35rem;
  cursor: pointer;
}

input[type="range"]:focus-visible {
  outline: none;
}

input[type="range"]::-webkit-slider-runnable-track {
  height: 0.4rem;
  border-radius: var(--radius);
  background: linear-gradient(
    to right,
    var(--global-theme-color) 0%,
    var(--global-theme-color) var(--fill),
    var(--global-divider-color) var(--fill),
    var(--global-divider-color) 100%
  );
}

input[type="range"]::-moz-range-track {
  height: 0.4rem;
  border-radius: var(--radius);
  background: var(--global-divider-color);
}

/* Firefox fills the track up to the thumb on its own via this pseudo
   element; -webkit browsers get the same effect from the gradient above. */
input[type="range"]::-moz-range-progress {
  height: 0.4rem;
  border-radius: var(--radius);
  background: var(--global-theme-color);
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: -0.4rem;
  border-radius: 50%;
  background: var(--global-theme-color);
  border: 2px solid var(--global-bg-color);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition: transform 0.15s ease;
}

input[type="range"]::-moz-range-thumb {
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background: var(--global-theme-color);
  border: 2px solid var(--global-bg-color);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition: transform 0.15s ease;
}

input[type="range"]:hover::-webkit-slider-thumb,
input[type="range"]:focus-visible::-webkit-slider-thumb {
  transform: scale(1.15);
}

input[type="range"]:hover::-moz-range-thumb,
input[type="range"]:focus-visible::-moz-range-thumb {
  transform: scale(1.15);
}

.tc-summary {
  margin: 1rem 0 0;
  font-size: 1.1rem;
}

.tc-summary b {
  font-family: "Roboto", sans-serif;
  font-weight: 500;
  margin-right: 0.5rem;
}

.tc-summary span {
  color: var(--global-text-color-light);
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

input[type="text"] {
  font: inherit;
  font-size: 0.85rem;
  width: 100%;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--global-divider-color);
  border-radius: var(--radius);
  background: var(--global-bg-color);
  color: var(--global-text-color);
  transition: border-color 0.15s ease;
}

input[type="text"]:focus-visible {
  outline: none;
  border-color: var(--global-theme-color);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--global-theme-color) 35%, transparent);
}

/* ------------------------------------------------------------------ game */

.game {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 18rem;
  gap: 1.75rem;
  align-items: start;
}

.board-column {
  min-width: 0;
}

.player-strip {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.35rem 0.1rem;
  font-size: 0.95rem;
}

.player-strip .who {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--global-text-color-light);
}

.player-strip .dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--global-text-color-light);
}

.player-strip.online .dot {
  background: #42b983;
}

.player-strip.offline .dot {
  background: #e7c000;
}

/* The clock is one of the most visually distinct elements on lichess's own
   board page: a big, bold, boxed numeral (`ui/lib/css/game/_clock.scss`'s
   `.time`, sized 2.8em-3.6em depending on viewport, in a box with its own
   background that changes when the clock is running or low). One detail is
   deliberately not copied: lila's own rule is `font-weight: normal` at that
   huge size, relying on scale rather than boldness for prominence — here the
   weight is bumped to a genuine 700 as well, since a smaller box at this
   page's scale reads as more "prominent" with real boldness behind it too. */
.clock {
  font-family: "Roboto", sans-serif;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: 0.02em;
  font-size: 2rem;
  padding: 0.15rem 0.8rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--global-code-bg-color);
  color: var(--global-text-color-light);
  min-width: 6rem;
  text-align: center;
  transition: background 0.15s ease, color 0.15s ease;
}

.clock.running {
  /* Tinted with this site's own accent rather than lila's green
     `$c-secondary` (`.rclock.running .time`), to keep one consistent accent
     colour across every control instead of introducing a second one just
     for the clock. */
  color: var(--global-text-color);
  background: color-mix(in oklab, var(--global-theme-color) 22%, var(--global-bg-color));
}

.clock.low {
  color: #ffffff;
  background: color-mix(in oklab, var(--danger-color) 55%, var(--global-bg-color));
}

.board-frame {
  position: relative;
  width: 100%;
  /* The pieces and the coordinates are sized from the board's own width, so
     the board scales without a line of javascript. */
  container-type: inline-size;
}

/* While browsing a past position from the move list (see replay.js and
   main.js's `updateBoardView`) the board dims slightly so it never reads as
   the live position — on top of the "Move N / M" label in the nav bar below
   it and every move button being disabled, rather than relying on any one
   of those alone. */
.board-frame.browsing .board {
  opacity: 0.72;
  filter: saturate(0.85);
  transition: opacity 0.15s ease, filter 0.15s ease;
}

.board-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  margin-top: 0.6rem;
}

.board-nav button {
  padding: 0.35rem 0.7rem;
  font-size: 0.95rem;
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
  line-height: 1;
}

.board-nav-label {
  min-width: 6rem;
  text-align: center;
  font-size: 0.8rem;
  color: var(--global-text-color-light);
  font-variant-numeric: tabular-nums;
}

.board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  aspect-ratio: 1 / 1;
  width: 100%;
  border: 1px solid var(--global-divider-color);
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}

.sq {
  position: relative;
  /* Its own stacking context, so the z-indexes below (highlight behind the
     piece, dots above it) are settled per square and never leak into or
     depend on paint order across the other 63. */
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  /* Belt and suspenders alongside `.board`'s own touch-action: a tap that
     selects, then a second tap that deselects or lands a move (possibly
     close to a legal-move dot), must never be read as a double-tap zoom. */
  touch-action: manipulation;
}

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

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

/* Both overlays paint above the square's own background but below the piece
   (z-index: 2 below), so a highlighted or selected square tints the square,
   not the piece standing on it. */
.sq.last::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--square-last);
  pointer-events: none;
}

.sq.selected::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--square-selected);
  pointer-events: none;
}

.sq.check {
  background-image: var(--square-check);
}

.sq .coord {
  position: absolute;
  font-size: 2.1cqi;
  line-height: 1;
  opacity: 0.65;
  color: #33281f;
  pointer-events: none;
}

.sq.dark .coord {
  color: #f1e5d6;
}

.sq .coord.file {
  right: 0.15rem;
  bottom: 0.1rem;
}

.sq .coord.rank {
  left: 0.15rem;
  top: 0.1rem;
}

/* The cburnett SVGs (web/vendor/pieces/cburnett/) are already drawn centred
   in a square 45x45 viewBox, so a piece that exactly fills its square, both
   axes, centres itself with no further nudging — unlike the Unicode glyphs
   this replaced, whose ink sat visibly high in the box on every platform
   font that rendered them. */
.piece {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  pointer-events: none;
}

.piece img {
  display: block;
  width: 100%;
  height: 100%;
  -webkit-user-drag: none;
  user-select: none;
}

.piece.dragging {
  opacity: 0.35;
}

.sq .dot-move,
.sq .dot-capture {
  position: absolute;
  z-index: 3;
  pointer-events: none;
}

.sq .dot-move {
  width: 30%;
  height: 30%;
  border-radius: 50%;
  background: rgba(20, 20, 20, 0.28);
}

.sq .dot-capture {
  inset: 6%;
  border-radius: 50%;
  border: 0.35rem solid rgba(20, 20, 20, 0.28);
}

.drag-ghost {
  position: fixed;
  z-index: 40;
  pointer-events: none;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
}

.promotion {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  z-index: 30;
}

.promotion button {
  background: var(--global-card-bg-color);
  width: 4rem;
  height: 4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.4rem;
  padding: 0;
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
}

.promotion button:hover {
  background: var(--global-hover-color);
}

/* ------------------------------------------------------------ side panel */

.status {
  font-family: "Roboto", sans-serif;
  font-weight: 400;
  font-size: 1.05rem;
  margin: 0 0 1rem;
  min-height: 1.6em;
}

.status.over {
  color: var(--global-theme-color);
}

.invite {
  border: 1px solid var(--global-divider-color);
  border-radius: var(--radius);
  padding: 0.75rem;
  margin-bottom: 1rem;
  background: var(--global-card-bg-color);
}

.invite-row {
  display: flex;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

.invite-row button {
  flex: none;
}

.qr {
  margin-top: 0.75rem;
  display: flex;
  justify-content: center;
}

.qr svg {
  width: 11rem;
  height: 11rem;
  background: #ffffff;
  padding: 0.5rem;
  border-radius: var(--radius-sm);
}

/* Captured material used to be drawn with Unicode chess glyphs, which — like
   the pieces on the board before the cburnett swap — do not sit consistently
   across platform fonts. It now draws with the same cburnett SVGs as the
   board itself, just small, so a captured piece actually looks like the
   piece that was captured. */
.captured {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-height: 2.8rem;
}

.captured-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.1rem;
  min-height: 1.4rem;
}

.captured-piece {
  width: 1.3rem;
  height: 1.3rem;
  opacity: 0.85;
}

/* A floating clone of a just-captured piece (see board.js's `_flyCapture`),
   scaling down and fading out as it travels toward the tray above. Not
   something lichess itself does — its own board library just fades a
   captured piece out in place (chessground's `anim.ts`) — but a small,
   deliberate embellishment asked for on top of that baseline. */
.capture-ghost {
  position: fixed;
  z-index: 45;
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.capture-ghost img {
  width: 100%;
  height: 100%;
}

.moves {
  list-style: none;
  margin: 0.5rem 0 1rem;
  padding: 0;
  display: grid;
  grid-template-columns: 2.2rem 1fr 1fr;
  gap: 0.1rem 0.4rem;
  max-height: 16rem;
  overflow-y: auto;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  border-top: 1px solid var(--global-divider-color);
  padding-top: 0.5rem;
}

.moves .num {
  color: var(--global-text-color-light);
}

.moves .move {
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: 0.05rem 0.3rem;
  margin: -0.05rem -0.3rem;
  transition: background 0.15s ease, color 0.15s ease;
}

.moves .move:hover {
  background: var(--global-hover-color);
  color: var(--global-hover-text-color);
}

.moves .move.active {
  background: var(--global-theme-color);
  color: #ffffff;
  font-weight: 500;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* ---------------------------------------------------------------- phones */

@media (max-width: 44rem) {
  .wrap {
    padding: 1rem 0.75rem 3rem;
  }

  .game {
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
  }

  .page-head h1 {
    font-size: 1.6rem;
  }

  .clock {
    font-size: 1.6rem;
    min-width: 5rem;
  }

  .moves {
    max-height: 9rem;
  }

  .panel {
    padding: 1rem;
  }

  .qr svg {
    width: 9rem;
    height: 9rem;
  }

  .board-nav button {
    padding: 0.3rem 0.6rem;
    font-size: 0.85rem;
  }

  .board-nav-label {
    min-width: 5rem;
    font-size: 0.75rem;
  }
}

/* Phone widths specifically (iPhone SE at 375px up to the Pro Max at
   430px): the whole game screen — board, both clocks, the move buttons and
   the game-over banner — has to fit in one short viewport with no
   scrolling, so spacing that is comfortable at tablet width gets trimmed
   further here rather than just shrinking text. */
@media (max-width: 30rem) {
  .wrap {
    padding: 0.5rem 0.5rem 1rem;
  }

  .page-head {
    padding-bottom: 0.4rem;
    margin-bottom: 0.6rem;
  }

  .page-head h1 {
    font-size: 1.3rem;
  }

  .game {
    gap: 0.6rem;
  }

  .player-strip {
    padding: 0.2rem 0.1rem;
  }

  .clock {
    font-size: 1.4rem;
    min-width: 4.4rem;
    padding: 0.1rem 0.5rem;
  }

  .status {
    margin: 0 0 0.5rem;
    font-size: 0.95rem;
    min-height: 1.3em;
  }

  .captured {
    min-height: 1.6rem;
  }

  .captured-piece {
    width: 1.1rem;
    height: 1.1rem;
  }

  .moves {
    margin: 0.35rem 0 0.6rem;
    max-height: 6rem;
    padding-top: 0.35rem;
  }

  .board-nav {
    margin-top: 0.4rem;
    gap: 0.2rem;
  }

  .board-nav button {
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
  }

  .board-nav-label {
    min-width: 4.2rem;
    font-size: 0.7rem;
  }

  .actions {
    gap: 0.3rem;
  }

  .actions button {
    padding: 0.4rem 0.7rem;
    font-size: 0.9rem;
  }
}
