/* Recollect play client — paper&ink, cohesive with the website brand
   (docs/decisions/brand_and_accessibility.md). Trunk bundles this via the
   `<link data-trunk rel="css">` in index.html. The wgpu canvas draws the board;
   every legal move is a labeled <button>, so play is keyboard- + screen-reader-
   reachable. WCAG-AA contrast. */
:root {
  color-scheme: light;
  --paper: #f5f0e3;
  --night: #17171f;
  --seat-a: #2e5c9e;
  --seat-b: #a83d33;
  --soft: #44434c;
  --rule: #d8d1bf;
  --card: #fbf8f0;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* Screen-reader-only: present to assistive tech, invisible on screen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

body {
  margin: 0;
  /* No horizontal scroll on any breakpoint. */
  overflow-x: hidden;
  background: var(--paper);
  color: var(--night);
  font: 15px/1.5 "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh; /* the dynamic viewport (mobile URL bar) where supported */
}

.skip-link {
  position: absolute; left: 0; top: -3rem; z-index: 5;
  background: var(--night); color: var(--paper);
  padding: 0.5rem 1rem; border-radius: 0 0 6px 0; text-decoration: none;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 0; }

/* ── The shared site nav (matches site/css/brand.css so the play page wears the
   same chrome as Guide / Cards / Rules / Lore) + the play settings cluster. ── */
.site-header { border-bottom: 1px solid var(--rule); flex: 0 0 auto; background: var(--paper); }
.site-header .container {
  width: 100%; max-width: 64rem; margin-inline: auto;
  padding: 0.85rem clamp(12px, 4vw, 1.75rem);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1.5rem;
}
.site-header .brand {
  font-size: 1.4rem; font-weight: 700; color: var(--night);
  text-decoration: none; letter-spacing: 0.01em;
}
/* The nav fills the bar to the right of the brand so the Options control can sit at the FAR
   RIGHT of the bar (item 1) via `margin-left:auto`, opposite the page links on the left. */
.site-nav { display: flex; gap: 1.25rem; flex-wrap: wrap; align-items: baseline; flex: 1 1 auto; }
.site-nav a { color: var(--seat-a); text-decoration: none; text-underline-offset: 0.15em; }
.site-nav a:hover { color: var(--seat-b); }
.site-nav a[aria-current="page"] { color: var(--night); font-weight: 700; }

/* Item 1 — the Options disclosure button: reads as a nav item, opens the settings panel, and is
   pushed to the RIGHT end of the nav bar (`margin-left:auto`), set apart from the page links. */
.nav-options {
  font: inherit; color: var(--seat-a); background: none; border: 0; padding: 0;
  cursor: pointer; text-underline-offset: 0.15em; margin-left: auto;
}
.nav-options:hover { color: var(--seat-b); }
.nav-options[aria-expanded="true"] { color: var(--night); font-weight: 700; }
.nav-options::after { content: " ▾"; font-size: 0.8em; opacity: 0.7; }

/* The Options panel — a dropdown card holding the play settings (sound · reduced-motion ·
   animation-speed). Anchored under the nav on the right; a soft card on the warm paper. */
.options-panel {
  position: absolute; right: clamp(12px, 4vw, 1.75rem); margin-top: 0.4rem; z-index: 20;
  background: var(--paper); border: 1px solid var(--rule); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(23, 23, 31, 0.18);
}
.options-panel[hidden] { display: none; }
.options-inner { padding: 0.9rem 1.1rem; }
.options-title {
  margin: 0 0 0.6rem; font-size: 0.95rem; font-weight: 700; color: var(--night);
  letter-spacing: 0.04em; text-transform: uppercase;
}
/* The play settings — sound · reduced-motion · animation-speed (design §Page shell). Now
   stacked vertically inside the Options panel. */
.play-settings {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 0.7rem; color: var(--soft); font-size: 0.95rem;
}
.play-settings .setting { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.play-settings .setting-check { cursor: pointer; }
.play-settings .setting-check input { width: 1rem; height: 1rem; accent-color: var(--seat-a); }
.play-settings select {
  font: inherit; color: var(--night); background: var(--paper);
  border: 1px solid var(--rule); border-radius: 6px; padding: 2px 6px;
}
/* The header is the positioning context for the absolute Options panel. */
.site-header { position: relative; }

/* ── The stage: the surface below the nav. In the canvas-native shell it is FULL-BLEED
   (the canvas fills 100% width × the viewport height under the nav, portrait-first);
   off-shell (picker / online / 2v2) it centers a bounded board with the DOM chrome. ── */
.stage {
  flex: 1 1 auto;
  min-height: 0; /* let the flex child shrink below content so 100% heights resolve */
  position: relative; /* the full-bleed canvas absolutely fills this box */
  display: flex; flex-direction: column; align-items: center;
  width: 100%;
  padding: 0 env(safe-area-inset-right) calc(16px + env(safe-area-inset-bottom)) env(safe-area-inset-left);
  gap: 10px;
}

#board {
  /* Off-shell (the picker / online / 2v2 board-only draw): a square board, bounded by
     both axes so it never clips nor forces horizontal scroll. The wgpu backing buffer is
     resized to the displayed size × DPR (fitCanvas), so it stays crisp 320px → 4K. */
  width: min(74vmin, 520px);
  height: min(74vmin, 520px);
  max-width: 100%;
  margin-top: 10px;
  cursor: pointer; /* the board is an input surface (tap a spirit, then a tile) */
  touch-action: none; /* the canvas owns pan/zoom — drag-to-act + swipe-the-hand */
}

/* #100 §Page shell — the canvas-native LOCAL 1v1 shell: the canvas is FULL-BLEED. The
   whole game (HUD · opponent strip · board · hand carousel · FABs) is drawn IN it, so it
   fills the entire stage — 100% width × (viewport − nav) — and fitCanvas matches the wgpu
   backing buffer to that box × DPR (portrait-first; the layout reflows for landscape). */
body.shell .stage { padding: 0; gap: 0; }
body.shell #board {
  /* Absolutely fill the stage box, so the canvas CSS size is the viewport-below-nav box
     — NOT its (square) backing-buffer attribute size. fitCanvas then matches the backing
     buffer to THIS box × DPR, so the in-canvas shell is full-bleed + correctly-proportioned
     (portrait on a phone, landscape on a desktop), never a square that overflows. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
}
/* In the shell the DOM chrome is drawn in-canvas — keep the picker/online/2v2 nodes out
   of the layout entirely so nothing competes with the full-bleed canvas. */
body.shell #picker,
body.shell #hand,
body.shell #moves,
body.shell #actions { display: none; }

/* The board is a focusable input surface (Tab reaches it; arrows move the in-canvas
   cursor). A clear outline when it has keyboard focus, alongside the gold per-tile ring. */
#board:focus-visible { outline: 3px solid var(--seat-a); outline-offset: -3px; }
#board:focus:not(:focus-visible) { outline: none; }

/* #status / #board-sr / #shell-a11y / #detail are always .visually-hidden (the canvas
   is the visible surface; these are the a11y mirror — §a11y). No visible styling. */

#hand, #moves, #actions {
  display: flex; gap: 8px; flex-wrap: wrap; justify-content: center;
  width: 100%; max-width: 760px; padding: 0 clamp(8px, 3vw, 12px);
}
/* The move list can grow long; cap it and scroll inside rather than push the page
   (and the End-Turn control, which is ordered first) off-screen. Momentum scroll
   on touch, and scroll stays contained to this box. */
#moves {
  max-height: clamp(160px, 34vh, 360px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  align-content: flex-start;
}

button {
  background: var(--paper); color: var(--night); border: 1px solid var(--rule);
  border-radius: 6px; padding: 6px 10px; cursor: pointer; font: inherit;
}
button:hover { border-color: var(--seat-a); }
button:focus-visible { outline: 3px solid var(--seat-a); outline-offset: 2px; }
#actions button { border-color: var(--seat-b); }

/* #90 the End Turn control — a filled, set-apart button (nothing auto-ends; this is
   how the turn passes). Listed first in #moves, visually distinct from the plays. */
button.end-turn {
  background: var(--night); color: var(--paper); border-color: var(--night);
  font-weight: 600; order: -1; margin-right: 6px;
}
button.end-turn:hover { background: var(--seat-a); border-color: var(--seat-a); }

#picker { width: 100%; max-width: 640px; display: none; padding: 0 12px; }
#picker h3 { text-align: center; margin: 14px 0; }
.style {
  border: 1px solid var(--rule); border-radius: 8px; padding: 12px 14px; margin: 10px 0;
  cursor: pointer; background: var(--card); color: var(--night);
}
/* The actionable style cards are real <button>s (keyboard-operable Tab stops);
   reset the browser chrome so they read as the cards they are (full-width, left-aligned,
   inheriting the page font) and carry the same visible focus ring as every other control. */
button.style.advance {
  display: block; width: 100%; text-align: left; font: inherit; line-height: 1.45;
}
.style:hover { border-color: var(--seat-a); }
.style:focus-visible { outline: 3px solid var(--seat-a); outline-offset: 2px; }
.style small { color: var(--soft); display: block; margin-top: 6px; }

/* The objective selection-info chips: resonance lean · tempo · aggression · body-mix.
   A quiet, paper-toned row under the blurb — the SHAPE of the deck at a glance. The same
   facts ride the button's aria-label as words (the chips are aria-hidden), so a screen
   reader hears the substance, not a row of unlabelled colour. */
.style .facets {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 9px 0 2px;
}
.style .facet {
  display: inline-flex; align-items: baseline; gap: 5px;
  border: 1px solid var(--rule); border-radius: 999px; padding: 2px 9px;
  background: var(--paper); font-size: 0.8rem; color: var(--night); font-weight: 600;
  white-space: nowrap;
}
.style .facet-k {
  font-size: 0.66rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--soft);
}

#hand .chip {
  background: var(--card); border: 1px solid var(--rule); border-radius: 5px;
  padding: 4px 8px; cursor: pointer;
}
.chip:hover { border-color: var(--seat-a); }
/* #97 Hand chips act as buttons (pick up to place / inspect) — keyboard-focusable,
   so they carry the same visible focus ring as every other control. */
.chip:focus-visible { outline: 3px solid var(--seat-a); outline-offset: 2px; }

/* #detail is the sr-only inspect twin (.visually-hidden) — it shares the in-canvas inspect
   panel's data for screen readers, but never renders visibly, so it carries NO box styling
   (any padding/width here would give the clipped element an on-screen footprint). */

select, #diff {
  background: #fff; color: var(--night); border: 1px solid var(--rule);
  border-radius: 6px; padding: 5px 8px; font: inherit;
}

/* Motion — subtle; disabled under prefers-reduced-motion below. */
button, .chip, .style, .host-form input, .host-form select {
  transition: border-color .15s ease, background-color .15s ease, transform .12s ease;
}
button:hover { transform: translateY(-1px); }
button:active { transform: translateY(0); }
/* The full-width style cards settle in place — the border-color shift is their hover
   affordance (matching the rest of the picker); a 1px lift on a wide card reads as jitter. */
button.style.advance:hover, button.style.advance:active { transform: none; }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* Host-a-match form */
.host-form { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: end; margin: 12px 0; }
.host-form label { display: flex; flex-direction: column; gap: 3px; font-size: 0.85rem; color: var(--soft); min-width: 0; }
.host-form input, .host-form select {
  font: inherit; padding: 4px 6px; border: 1px solid var(--rule); border-radius: 5px;
  background: #fff; color: var(--night); max-width: 100%;
}
#ho-2v2:not([hidden]) { display: flex; gap: 10px 14px; flex-wrap: wrap; }
.host-form button {
  background: var(--night); color: var(--paper); border: 1px solid var(--night);
  border-radius: 6px; padding: 7px 14px; cursor: pointer; align-self: end;
}
.host-form button:hover { background: var(--seat-a); border-color: var(--seat-a); }
.host-join { margin-top: 8px; color: var(--soft); }
/* Flexible width so the join input never overruns a 320px viewport. */
.host-join input {
  font: inherit; padding: 3px 6px; border: 1px solid var(--rule); border-radius: 5px;
  background: #fff; color: var(--night); width: min(170px, 100%);
}

/* ── Responsive: signature-tier across mobile / tablet / desktop ──────────────
   The base layout above is already fluid (vmin board, flex-wrap rows, %-bounded
   containers). These blocks tune the *feel* per device: touch ergonomics, a
   side-by-side board+controls on landscape phones, and roomier desktop spacing. */

/* Touch / coarse-pointer devices (phones, tablets): WCAG-AA 2.5.5 target size.
   Every tappable thing gets a ≥44px touch target without changing the visual
   density of the desktop mouse build. */
@media (hover: none), (pointer: coarse) {
  button, #hand .chip, .style, select, #diff,
  .host-form input, .host-form select, .host-join input {
    min-height: 44px;
  }
  button, #hand .chip { padding: 10px 14px; display: inline-flex; align-items: center; }
  /* The full-width style cards stay block (the inline-flex above is for compact buttons);
     keep their roomy card padding rather than the compact button padding. */
  button.style.advance { display: block; padding: 12px 14px; }
  .host-form input, .host-form select, select, #diff { padding: 9px 10px; }
  #hand, #moves, #actions { gap: 10px; }
  /* Hover-lift is sticky on touch (the tap leaves the element "hovered"); drop it. */
  button:hover { transform: none; border-color: var(--rule); }
  button.end-turn:hover { background: var(--night); border-color: var(--night); }
  .chip:hover, .style:hover { border-color: var(--rule); }
}

/* Small phones (portrait): the off-shell board takes the width; the move list grows.
   (In the canvas-native shell the full-bleed canvas owns its own responsive layout.) */
@media (max-width: 30rem) {
  .stage { font-size: 14px; }
  .site-header .container { padding: 0.7rem 12px; }
  .site-header .brand { font-size: 1.2rem; }
  body:not(.shell) #board { width: min(92vmin, 92vw); height: min(92vmin, 92vw); }
  #moves { max-height: 46vh; }
}

/* Landscape phones / short wide viewports (OFF-SHELL only): place the board beside the
   controls so it isn't squeezed by the address bar. CSS-only float, no JS layout. The
   canvas-native shell handles landscape IN the canvas (it reflows the bands wider). */
@media (max-height: 32rem) and (min-width: 40rem) and (orientation: landscape) {
  body:not(.shell) .stage { display: block; padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
  body:not(.shell) #board {
    float: left; margin: 10px 16px 8px 12px;
    width: min(86vh, 60vw); height: min(86vh, 60vw);
  }
  body:not(.shell) #hand, body:not(.shell) #moves, body:not(.shell) #actions { justify-content: flex-start; }
  body:not(.shell) #moves { max-height: 56vh; }
  body:not(.shell) #actions { clear: left; }
}

/* Tablet and up: a touch more breathing room and a wider control band. */
@media (min-width: 48rem) {
  #hand, #moves, #actions { max-width: 820px; }
  #picker { max-width: 680px; }
}

/* Desktop: cap the board generously and keep the move list comfortably tall. */
@media (min-width: 64rem) {
  #moves { max-height: 38vh; }
}
