/**
 * @file games/v2-surface-responsive.css
 * @project KAINYNE Website
 * @description [REQ-866] Shared responsive stylesheet for every Tabletop
 *   OS v2 surface (`games/<slug>/v2/index.html`). Linked from each surface
 *   AFTER its inline `<style>` block, so its rules win the cascade at equal
 *   specificity by source order — no `!important`, no inline trimming.
 *
 *   Supersedes REQ-707's phone-only inline `@media (max-width: 480px)`
 *   block: this sheet implements RESPONSIVE REFLOW (no horizontal overflow
 *   at any width, fluid `clamp()`/`vw` sizing, vertical scroll allowed)
 *   across the four canonical device classes from
 *   `/src/responsive-viewport.js` + `/src/responsive-breakpoints.css`
 *   (REQ-543/544):
 *     - mobile-portrait   ←  `@media (max-width: 639px)`
 *     - tablet            ←  `@media (min-width: 640px) and (max-width: 1023px)`
 *     - desktop           ←  `@media (min-width: 1024px)`
 *     - mobile-landscape  ←  `@media (orientation: landscape) and (max-height: 500px)`
 *
 *   The landscape block is placed LAST so it beats the width-keyed tiers
 *   at equal specificity (mirroring the JS classifier, where the landscape
 *   rule wins). Fluid card sizing reuses the v1 WAR client's proven
 *   REQ-335 `clamp()` values.
 *
 *   NOTE: CSS custom properties cannot be referenced inside `@media`
 *   conditions per spec, so the `@media` thresholds below carry literal
 *   `px`. The `:root` `--bp-*` props are declared purely so the parity
 *   drift gate (`src/v2-surface-responsive.test.js`) can assert they match
 *   the JS BREAKPOINTS — exactly as `/src/responsive-breakpoints.css` does.
 *   [REQ-870] layers a no-scroll vertical-fit pass on the mobile-portrait
 *   tier only: it compresses the portrait layout (drops the mid-play lede,
 *   slims the stacked CTAs, wraps a long action-button run into a grid via
 *   the runtime's `.engine-v0-button-row`) so a typical play state fits one
 *   handset screen without vertical scrolling — a deliberate tightening of
 *   this sheet's otherwise scroll-allowed reflow, scoped to portrait phones.
 *   [REQ-926] hardens that intent into a NON-SCROLLABLE app-shell lock across
 *   every device class: `html, body` are pinned to one `100dvh` viewport with
 *   `overflow-y: hidden`, `#root`/`.engine-v0-root` become the flex spine, and
 *   the playable regions (hand / grid / board) carry the only internal scroll
 *   — so the page can no longer slide up and down; the chrome stays fixed and
 *   any genuine overflow is confined to the play area.
 * @module Shared/V2SurfaceResponsive
 * @requirements REQ-866, REQ-870, REQ-881, REQ-926
 * @hazards Styling-only; aside from the single REQ-926 `#root` flex-spine rule
 *   (the runtime's fixed mount-point wrapper, present on every surface) no
 *   selectors target IDs or alter markup. The `overflow-x: hidden` guard on
 *   `html, body` is a backstop — the tiered fluid sizing is designed so
 *   genuine reflow happens first and clipping rarely engages; the REQ-926
 *   `overflow-y: auto` on `.engine-v0-root` is the matching no-clip backstop
 *   for the vertical lock. Grid column count stays JS-controlled
 *   (`gridTemplateColumns: repeat(N,1fr)`); reflow comes from the
 *   `width: 100%` container + fluid tile sizing, not a CSS column override.
 * @notes Linked via `<link rel="stylesheet"
 *   href="/games/v2-surface-responsive.css?v=1">` by
 *   `scripts/link-v2-responsive-css.js`. Bump the `?v=N` on every edit
 *   (CLAUDE.md cache-bust rule).
 */

:root {
  /* [REQ-866] Mirror of /src/responsive-breakpoints.css canonical
     thresholds (REQ-544) — kept byte-identical to the JS BREAKPOINTS in
     /src/responsive-viewport.js by the parity drift gate. */
  --bp-mobile-max: 639px;
  --bp-tablet-max: 1023px;
  --bp-landscape-max-height: 500px;
}

/* ── Global overflow guards (no media query — every device class) ────── */

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

/* [REQ-866] Hard backstop against horizontal scroll. */
html, body { max-width: 100%; overflow-x: hidden; }

/* [REQ-926] Non-scrollable app-shell lock — pin every surface to exactly one
   viewport so the PAGE never scrolls (no rubber-band, stable address bar).
   The body becomes a flex spine; the surface fills the locked height and any
   genuine overflow is confined to the playable region (hand / grid / board),
   which scrolls INTERNALLY — the title, status, action buttons and footer
   stay fixed on screen instead of the whole page sliding up and down. Layered
   here in the global (no-media) section so it holds across every device
   class; the per-tier compression rules (REQ-870) still run first to make a
   typical play state fit without ever engaging the inner scroll. */
html, body {
  height: 100vh;
  height: 100dvh; /* [REQ-335] dvh fallback — proven in the v1 WAR client. */
  overflow-y: hidden;
}
body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
/* The runtime mounts the surface inside `#root`; make it the flex spine so
   `.engine-v0-root` can claim the full locked height. */
#root {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

img, svg, canvas, video { max-width: 100%; height: auto; }

/* [REQ-866] Neutralise the varying per-game `.engine-v0-root` caps
   (560–780px) with one fluid container that never exceeds the viewport. */
.engine-v0-root {
  width: 100%;
  max-width: min(780px, 100%);
  margin-inline: auto;
  /* [REQ-926] Fill the locked viewport spine. `overflow-y: auto` is the
     universal no-clip backstop: surfaces WITH a flexible play region (hand /
     grid / board, below) keep their chrome pinned because that region absorbs
     the overflow and this never engages; surfaces without one get a contained
     inner scroll here — still never the page itself. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* [REQ-926] The playable regions flex to fill the leftover column space and
   gain their own internal scroll, so a full hand / large board overflows
   inside its panel while the surrounding chrome stays fixed. */
.engine-v0-hand,
.engine-v0-grid,
.engine-v0-hands-board {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* [REQ-335] Fluid cards replace the fixed 84×118 inline sizing so single-
   card and multi-card surfaces both fit the available width. */
.engine-v0-card {
  width: clamp(56px, 18vw, 100px);
  height: clamp(78px, 25vw, 140px);
}

.engine-v0-hand { flex-wrap: wrap; }

/* [REQ-870] The UI Runtime groups each run of consecutive action buttons
   into an `.engine-v0-button-row`. `display:contents` makes the wrapper
   transparent at every width (the buttons lay out exactly as direct root
   children — zero desktop change); the mobile-portrait block below flips
   it to a wrapping grid so a long CTA stack collapses instead of forcing
   vertical scroll. */
.engine-v0-button-row { display: contents; }

/* Long words / room codes / share links never force horizontal overflow. */
.engine-v0-hand-card,
.engine-v0-option,
.engine-v0-grid-tile { overflow-wrap: anywhere; }

/* ── Mobile-portrait — `@media (max-width: 639px)` ───────────────────── */

@media (max-width: 639px) {
  body { padding: 1.25rem 1rem; }
  h1 { font-size: clamp(1.6rem, 8vw, 1.9rem); }
  .engine-v0-root { max-width: 100%; }

  /* Full-width primary CTA; the ghost "How to Play" stays small + right. */
  .engine-v0-button { width: 100%; align-self: stretch; padding: 0.9rem 1rem; }
  .engine-v0-howto-button { width: auto; align-self: flex-end; }
  .engine-v0-howto-close { width: 100%; }

  /* 44px touch floor on the tappable controls. */
  .engine-v0-hand-card,
  .engine-v0-option,
  .engine-v0-grid-tile,
  .engine-v0-button { min-height: 44px; }

  /* Fluid grid: tighter gutters + a tile that shrinks with the viewport
     (column count stays JS-controlled — `repeat(N,1fr)` auto-shrinks in a
     width:100% container). */
  .engine-v0-grid { gap: 0.4rem; padding: 0.5rem; }
  .engine-v0-grid-tile {
    min-height: clamp(40px, 12vw, 64px);
    padding: 0.35rem;
    font-size: 0.7rem;
  }
  .engine-v0-hand-card { min-width: clamp(64px, 22vw, 84px); }

  /* [REQ-870] No-scroll vertical fit — compress the portrait layout so a
     typical play state fits one handset screen without vertical scrolling.
     Layered AFTER the REQ-866 reflow rules above so it wins at equal
     specificity by source order; deliberately tighter than REQ-866's
     scroll-allowed defaults (drops the mid-play lede, slims the stacked
     CTAs, and wraps long button runs into a grid). */
  body { padding: 0.75rem 0.9rem; }
  h1 { font-size: clamp(1.3rem, 6.5vw, 1.5rem); line-height: 1.05; }
  .engine-v0-root { gap: 0.3rem; }
  .engine-v0-lede { display: none; }
  .engine-v0-text { font-size: 0.8rem; line-height: 1.15; }
  /* [REQ-883] Slim option padding so a short-label option grid (e.g.
     Azul's `F1: B` draft picks) packs more per row — fewer rows of the
     44px-floor buttons. */
  .engine-v0-option { padding: 0.45rem 0.5rem; }
  .engine-v0-label { margin-top: 0.3rem; }
  .engine-v0-turn-indicator { padding: 0.3rem 0.6rem; }
  .engine-v0-hand { padding: 0.5rem; gap: 0.3rem; }
  .engine-v0-scoreboard { padding: 0.4rem 0.6rem; }

  /* Smaller hand tiles pack ~6 per row, so a full 13-card hand is ~3 rows
     instead of ~5 (the 44px coarse-pointer floor still applies). */
  .engine-v0-hand-card {
    min-width: clamp(46px, 13vw, 62px);
    padding: 0.4rem 0.3rem;
    font-size: 0.78rem;
  }

  /* Slim the stacked CTAs while holding the 44px touch floor (set above). */
  .engine-v0-button { padding: 0.5rem 1rem; margin: 0; }

  /* Wrap a run of action buttons into a compact grid instead of a tall
     full-width stack (e.g. a 0–13 bid collapses from ~14 rows to ~3). */
  .engine-v0-button-row { display: flex; flex-wrap: wrap; gap: 0.3rem; }
  .engine-v0-button-row .engine-v0-button { width: auto; flex: 1 1 auto; }

  /* Trim the trailing onboarding + cast/back footer. */
  .engine-v0-teach { padding: 0.6rem 0.7rem; gap: 0.35rem; margin-bottom: 0.3rem; }
  .engine-v0-teach-line { font-size: 0.85rem; line-height: 1.35; }
  .engine-v0-cast-panel { margin-top: 0.6rem; padding: 0.5rem; }
  .engine-v0-cast-join { padding: 0.3rem 0.5rem; }
  /* [REQ-881] The trailing footer is a stack of `.v2-back-link`s (Cast to a
     screen / Cast live / Back to classic), each carrying its own border-top
     divider + 1rem padding — ~135px of mostly-auxiliary nav. Densify it on a
     phone: drop the per-link dividers + shrink the rhythm (keeps every link,
     just tighter) so the playable surface clears the fold. */
  .v2-back-link {
    margin-top: 0.35rem;
    padding-top: 0.25rem;
    border-top: none;
    font-size: 0.72rem;
  }
}

/* ── Tablet — `@media (min-width: 640px) and (max-width: 1023px)` ─────── */

@media (min-width: 640px) and (max-width: 1023px) {
  .engine-v0-root { max-width: min(720px, 100%); }
  h1 { font-size: 2.3rem; }
  .engine-v0-button { width: auto; }
  .engine-v0-grid-tile { min-height: clamp(56px, 9vw, 72px); }
}

/* ── Desktop — `@media (min-width: 1024px)` ──────────────────────────── */

@media (min-width: 1024px) {
  /* Roomier than the 560–780px inline caps now the viewport allows it. */
  .engine-v0-root { max-width: min(880px, 100%); }
  h1 { font-size: 2.6rem; }
  .engine-v0-card {
    width: clamp(84px, 8vw, 110px);
    height: clamp(118px, 11vw, 154px);
  }
}

/* ── Mobile-landscape — placed LAST so it wins at equal specificity ──── */

@media (orientation: landscape) and (max-height: 500px) {
  body { padding: 0.75rem 1rem; }
  h1 { font-size: clamp(1.3rem, 5vh, 1.7rem); }
  /* Reclaim vertical space on a short viewport. */
  .engine-v0-lede { display: none; }
  .engine-v0-button { width: auto; min-height: 40px; padding: 0.5rem 1rem; }
  /* Size cards off the SHORT axis (height) so they never exceed the band. */
  .engine-v0-card {
    width: clamp(48px, 12vh, 80px);
    height: clamp(66px, 17vh, 112px);
  }
  .engine-v0-howto-modal { max-height: 92vh; }
}

/* ── Coarse pointer — 44px touch floor regardless of width ───────────── */

@media (pointer: coarse) {
  .engine-v0-button,
  .engine-v0-option,
  .engine-v0-hand-card,
  .engine-v0-grid-tile,
  .engine-v0-howto-button,
  .engine-v0-howto-close { min-height: 44px; }
}

/* ── Keyboard focus ring (REQ-922) ───────────────────────────────────── */

/* [REQ-922] Until now no v2 surface rendered a visible focus indicator:
   the UI Runtime makes every control keyboard-reachable (tabindex +
   focusOrder, REQ-845) but the shared sheet shipped no `:focus-visible`
   rule, so a keyboard / switch-access user could tab through a game with
   no idea which control was focused. `:focus-visible` (not `:focus`)
   shows the ring only for keyboard / programmatic focus, never on a
   mouse / touch press — so the pointer experience is unchanged. The ring
   reuses the per-surface `--accent` brand token (each index.html sets it
   in its inline `:root`) with a 2px offset so it reads clearly against
   the dark `--surface` card fills. */
.engine-v0-button:focus-visible,
.engine-v0-option:focus-visible,
.engine-v0-hand-card:focus-visible,
.engine-v0-grid-tile:focus-visible,
.engine-v0-howto-button:focus-visible,
.engine-v0-howto-close:focus-visible {
  outline: 2px solid var(--accent, #e8f020);
  outline-offset: 2px;
  border-radius: 4px;
}

/* [REQ-922] Forced-colors (Windows High Contrast) flattens the `--accent`
   custom property, which can collapse the ring to an invisible colour.
   Re-pin the outline to the system `Highlight` keyword so the focus ring
   survives high-contrast mode. */
@media (forced-colors: active) {
  .engine-v0-button:focus-visible,
  .engine-v0-option:focus-visible,
  .engine-v0-hand-card:focus-visible,
  .engine-v0-grid-tile:focus-visible,
  .engine-v0-howto-button:focus-visible,
  .engine-v0-howto-close:focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}
