/*
 * app.css — the page, the board, and the promotion picker.
 *
 * The vendored chessground stylesheets do the heavy lifting (board texture,
 * piece sprites, destination dots). What is here is the page around them: the
 * board's size and framing, where the coordinate labels sit, the keyboard
 * cursor, and the promotion picker. Board interaction is `js/board.js`'s;
 * nothing in this file assumes anything about chess.
 *
 * Two rules of the house, both already true here and both checked: no layout
 * overflow from 320 px upwards, and nothing carried by colour alone.
 */

:root {
  --ink: #1b1d21;
  --ink-muted: #565c66;
  --surface: #ffffff;
  --surface-sunken: #f4f5f7;
  --line: #ccd0d7;
  --accent: #1f5fbf;
  --approximate-ink: #6b4c00;
  --approximate-surface: #fff4d6;
  --approximate-line: #a97b12;
  /*
   * The two square colours. Ours rather than the vendored brown theme's, and
   * chosen so the light and dark squares differ in *lightness*: the theme's pair
   * (a 20 % black wash over #f0d9b5) measures about 1.6:1, which is a difference
   * a colour-blind player still has but a subtle one. This pair measures about
   * 3.3:1 — the measured figure is in
   * `docs/verification-m5-accessibility.md` (VAL-UI-006).
   */
  --board-light: #f0d9b5;
  --board-dark: #9a6c42;
  --danger-ink: #8a1c1c;
  --danger-line: #8a1c1c;
  --radius: 6px;
  --gap: 1rem;
}

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

body {
  margin: 0;
  padding: var(--gap);
  background: var(--surface-sunken);
  color: var(--ink);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-height: 100vh;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.site-header h1 {
  margin: 0;
  font-size: 1.5rem;
}

.tagline {
  margin: 0.25rem 0 0;
  color: var(--ink-muted);
}

.layout {
  display: grid;
  gap: var(--gap);
  align-items: start;
}

.board-panel,
.side-panel {
  min-width: 0;
}

.note {
  margin: 0.5rem 0 0;
  color: var(--ink-muted);
  font-size: 0.875rem;
}

.panel-block {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap);
}

.panel-block + .panel-block {
  margin-top: var(--gap);
}

.panel-block h2 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.status {
  margin: 0 0 0.75rem;
  font-variant-numeric: tabular-nums;
}

.field-label {
  display: block;
  margin: 0 0 0.25rem;
  font-size: 0.875rem;
  color: var(--ink-muted);
}

.select {
  display: block;
  width: 100%;
  margin: 0 0 0.75rem;
  font: inherit;
  padding: 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}

/*
 * The approximate marking beside the strength selector (FEAT-013). It is a
 * badge plus a sentence, on the page and visible without a hover — a tooltip
 * would not be "presented as approximate". The badge carries the word as well
 * as the colour, so nothing here is carried by colour alone.
 */
.marking {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0 0 0.5rem;
  font-size: 0.875rem;
  color: var(--ink-muted);
}

.marking-badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-sunken);
  color: var(--ink);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.marking[data-approximate='true'] .marking-badge {
  background: var(--approximate-surface);
  border-color: var(--approximate-line);
  color: var(--approximate-ink);
}

.marking-badge[hidden] {
  display: none;
}

.marking-text {
  flex: 1 1 12rem;
  min-width: 0;
}

/*
 * Where the strength in play came from (FEAT-017, VAL-RATING-003). Same badge
 * and sentence shape as the approximate marking above — the word carries the
 * meaning, the tint only reinforces it — so a suggested opponent and a chosen
 * one are told apart by reading, not by colour (VAL-UI-006).
 */
.marking[data-source='suggestion'] .marking-badge {
  background: #e8f0fc;
  border-color: var(--accent);
  color: #123a75;
}

.marking[data-source='choice'] .marking-badge {
  background: var(--surface);
  border-color: var(--ink);
  color: var(--ink);
}

/*
 * The floor note (FEAT-017, VAL-RATING-004). It exists only when the rating has
 * run out of room at the bottom, and it is drawn as a statement rather than as
 * another line of small print: a rule down its left edge and a surface behind
 * it, both of which are geometry rather than colour — a reader who cannot tell
 * the tint apart still sees the block.
 */
#rating-floor-note {
  padding: 0.5rem 0.65rem;
  border-left: 3px solid var(--ink-muted);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--surface-sunken);
  color: var(--ink);
}

#rating-floor-note[hidden] {
  display: none;
}

.button {
  font: inherit;
  padding: 0.5rem 1rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent);
  color: #ffffff;
  cursor: pointer;
}

.button[disabled] {
  background: var(--surface-sunken);
  border-color: var(--line);
  color: var(--ink-muted);
  cursor: default;
}

/*
 * Resign is the one control that ends the game, so it is drawn as an outline
 * rather than a filled action and carries the colour *and* the word. Nothing
 * here is signalled by colour alone.
 */
.button-danger {
  background: var(--surface);
  border-color: var(--danger-line);
  color: var(--danger-ink);
}

.button-danger[disabled] {
  background: var(--surface-sunken);
  border-color: var(--line);
  color: var(--ink-muted);
}

/*
 * The control row wraps rather than shrinking, and its buttons may not be
 * squeezed below their own label — which is what would push the page wider than
 * a 320 px viewport (VAL-UI-003).
 */
.control-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.control-row .button {
  flex: 0 1 auto;
  min-width: 0;
}

.fieldset {
  margin: 0 0 0.75rem;
  padding: 0;
  border: 0;
}

.choice-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
}

.choice {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.9375rem;
}

.choice + .choice {
  margin-top: 0.35rem;
}

.choice input {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  accent-color: var(--accent);
}

.button:focus-visible,
.select:focus-visible,
.choice input:focus-visible,
a:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 2px;
}

.move-list {
  margin: 0;
  padding-left: 1.5rem;
  min-height: 1.5rem;
}

.move-list:empty + .note {
  margin-top: 0;
}

.site-footer {
  margin-top: auto;
  color: var(--ink-muted);
  font-size: 0.875rem;
}

.site-footer p {
  margin: 0;
}

/*
 * The licensing notice (FEAT-019, VAL-DEPLOY-003). A licence a visitor cannot
 * read is not a source offer, so this is drawn as a block on the page — border,
 * surface and a heading — rather than as small print. Its links are ordinary
 * anchors, so the `a:focus-visible` rule above already gives them the 3 px ring
 * every other control carries (VAL-UI-006); the underline is explicit so the
 * affordance is never carried by colour alone. The link row wraps rather than
 * shrinking, and long paths inside it may break anywhere, which is what keeps
 * 320 px free of overflow (VAL-UI-003).
 */
.licensing {
  margin: 0 0 var(--gap);
  padding: var(--gap);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}

.licensing h2 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.licensing p {
  margin: 0 0 0.5rem;
}

.licensing code {
  font-size: 0.9em;
  overflow-wrap: anywhere;
}

.licensing-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0.25rem 0 0;
}

.licensing-links a {
  color: var(--accent);
  text-decoration: underline;
  overflow-wrap: anywhere;
}

@media (min-width: 900px) {
  .layout {
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
  }
}

/* --- the board ------------------------------------------------------------ */

/*
 * `#board` is the focusable frame (`js/board.js` makes it focusable); the
 * chessground instance is the `.board-surface` inside it, and the promotion
 * picker is a sibling of that — so a board flip, which makes chessground rebuild
 * its own DOM, cannot take the picker with it.
 */
.board {
  position: relative;
  width: 100%;
  max-width: min(100%, 68vh);
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--board-dark);
  touch-action: none; /* a drag on the board moves a piece; it never scrolls the page */
}

.board-surface {
  width: 100%;
  height: 100%;
}

/*
 * The squares. chessground's brown theme paints a #f0d9b5 board with a 20 %
 * black wash on the dark squares — about 1.6:1 in relative luminance, a
 * difference that survives greyscale but only just. This draws the same 8×8
 * checker from the two variables above instead, so the square colours are ours,
 * measured, and chosen for a luminance ratio of about 3.3:1 (the measured
 * figures are in `docs/verification-m5-accessibility.md`, VAL-UI-006).
 *
 * The geometry is the standard one: a four-quadrant conic gradient repeated at
 * `background-size: 25% 25%` is one 2×2 tile per two squares, so each quadrant
 * is exactly one square, and the top-left quadrant is light — which is a8, and
 * correct. The probe measures the rendered pixels, so the orientation is
 * checked rather than assumed.
 */
cg-board {
  background-color: var(--board-light);
  background-image: conic-gradient(
    var(--board-dark) 90deg,
    var(--board-light) 90deg 180deg,
    var(--board-dark) 180deg 270deg,
    var(--board-light) 270deg
  );
  background-size: 25% 25%;
}

/*
 * Selection and check carry an outline as well as a colour, for the same reason
 * the keyboard cursor does: the board's state is not allowed to depend on hue
 * alone (VAL-UI-006).
 */
cg-board square.selected,
cg-board square.check {
  outline: 3px solid var(--ink);
  outline-offset: -3px;
}

.board:focus-visible {
  /* Inset: an outline drawn outside the board would be layout overflow at 320 px. */
  outline: 3px solid var(--ink);
  outline-offset: -3px;
}

/* Coordinate labels are drawn *inside* the squares (`coordinatesOnSquares` in
   `js/board.js`), one name per square in its corner — so nothing is ever drawn
   outside the board, which is what keeps the layout from overflowing at 320 px.
   Each label sits on its own square, so its colour is picked to contrast with
   that square rather than carrying meaning on its own.

   These rules are scoped to `#board` deliberately. The vendored brown theme
   colours the same labels with a two-class, one-type selector, so a
   same-shape rule here would lose on specificity and the theme's colours would
   win silently — which is exactly the kind of thing that looks fine in a diff
   and is wrong on the page. The measured ratios are in
   `docs/verification-m5-accessibility.md`; the probe reads the *computed*
   colours back, so a rule that stopped winning would fail it. */
#board coords {
  /* chessground draws every coordinate layer at 80 % opacity. At full opacity
     these two colours clear the 4.5:1 text bar; at 80 % the dark-square one
     would not (it measures 2.87:1), so the opacity is not cosmetic. */
  opacity: 1;
}

#board coords.squares coord {
  font-size: 10px;
  font-weight: 600;
}

#board coords.squares coord.coord-light {
  color: #4a3018; /* on a light square — 9.6:1 */
}

#board coords.squares coord.coord-dark {
  color: #ffffff; /* on a dark square — 4.6:1 */
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.45);
}

/* The keyboard cursor: an outline, not a colour, so it reads on any square. */
cg-board square.cursor {
  outline: 3px solid var(--ink);
  outline-offset: -3px;
  background-color: rgba(31, 95, 191, 0.25);
}

/* --- the promotion picker ------------------------------------------------- */

/*
 * Positioned cell-by-cell over the board. `pointer-events` are off for the
 * layer and on for the buttons, so clicking the board beside the picker is a
 * click on the board (which cancels the promotion) rather than a dead zone.
 *
 * This element carries chessground's `cg-wrap` class on purpose: it is what the
 * vendored `.cg-wrap piece.<role>.<colour>` rules key off, so the picker shows
 * the same piece sprites as the board instead of a second copy of the artwork.
 */
.promotion {
  position: absolute;
  inset: 0;
  z-index: 20;
  pointer-events: none;
}

.promotion[hidden] {
  display: none;
}

.promotion-option {
  position: absolute;
  display: block;
  margin: 0;
  padding: 0;
  pointer-events: auto;
  border: 1px solid var(--ink-muted);
  border-radius: 3px;
  background: var(--surface);
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

.promotion-option + .promotion-option {
  border-top: 0;
}

/* A `piece` inside the picker fills its button; on the board it is one square. */
.promotion-option piece {
  position: static;
  display: block;
  width: 100%;
  height: 100%;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}

.promotion-option.is-active {
  background: var(--surface-sunken);
  outline: 3px solid var(--ink);
  outline-offset: -3px;
}

.promotion-option:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: -3px;
}
