/**
 * @file games/v2-engine-surface.css
 * @project KAINYNE Website
 * @description [REQ-885] Shared Tabletop OS engine surface stylesheet
 *   (RFE-353a §5). The engine equivalent of `src/ui/tokens.css`: it
 *   declares the brand palette + engine layout/motion tokens as `:root`
 *   defaults so a v2 surface inherits the kainyne brand with ZERO inline
 *   CSS, hosts the common `.engine-v0-*` base rules (lifted + deduped
 *   from the per-surface inline blocks), and carries the named-preset
 *   palettes (§6) keyed on `[data-engine-preset]`.
 *
 *   A surface's `ui-config.json#theme` overrides any token: the runtime's
 *   `themeToCssVars` (REQ-885) sets the matching base brand var (e.g.
 *   `--accent`) inline on the engine root, which wins over these defaults.
 *   The CANONICAL_BRAND_VARS map in `src/engine/ui-runtime.js` is the
 *   companion source of truth for which keys map to which var; the
 *   contract is pinned by `src/engine/test/v2-engine-surface-css.test.js`.
 * @module Shared/V2EngineSurface
 * @requirements REQ-885
 * @hazards Token defaults read through `var(--token, fallback)` so a
 *   per-surface override flows without the rules knowing about it — do
 *   NOT hard-code values back into the rules. Presets re-declare the
 *   palette at `:root` via `:has([data-engine-preset])` so the whole page
 *   (body backdrop included) takes the identity, not just the board.
 * @notes Sibling of `games/v2-surface-responsive.css`. Linked per surface
 *   with a cache-bust `?v=N` (CLAUDE.md cache-bust rule). Not yet linked
 *   by any surface — the Coup pilot (RFE-353a §8 step 2) is first.
 */

/* [REQ-885] Token layer — brand palette + engine tokens as defaults. */
:root {
  --bg: #0a0b0f;
  --surface: #111318;
  --border: #2a2d38;
  --text: #e8e9ef;
  --muted: #80849a;
  --accent: #e8f020;
  --accent-ink: #0a0b0f;
  --danger: #e84a4a;
  /* [REQ-885] Legacy alias — inline rules still reading var(--red). */
  --red: var(--danger);

  --font-display: "Bebas Neue", sans-serif;
  --font-body: "DM Sans", sans-serif;
  --font-mono: "DM Mono", monospace;

  /* [REQ-885] Engine-only tokens (no brand equivalent). */
  --engine-radius: 6px;
  --engine-max-width: 680px;
  --engine-motion-fast: 220ms;
  --engine-motion-base: 360ms;
}

/* [REQ-885] Reset + page frame. */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  min-height: 100vh;
  padding: 2rem 1.5rem;
}
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background: repeating-linear-gradient(
    0deg,
    transparent,
    transparent 2px,
    rgba(0, 0, 0, 0.07) 2px,
    rgba(0, 0, 0, 0.07) 4px
  );
  pointer-events: none;
  z-index: 999;
}

/* [REQ-885] Common engine region rules — tokenized. */
.engine-v0-root {
  max-width: var(--engine-max-width);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  position: relative;
  z-index: 1;
}
h1 {
  font-family: var(--font-display);
  font-size: 2.5rem;
  color: var(--accent);
  letter-spacing: 0.1em;
}
.engine-v0-lede {
  color: var(--muted);
  margin-bottom: 1rem;
  font-size: 0.85rem;
  line-height: 1.5;
}
.engine-v0-text {
  font-family: var(--font-mono);
  color: var(--muted);
  font-size: 0.85rem;
  /* [REQ-885] break-word is the majority default (8/9 surfaces set it) and
     the safer overflow behaviour for a text region — promoted to the base. */
  word-break: break-word;
}
.engine-v0-label {
  color: var(--text);
  font-weight: 600;
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.engine-v0-deck-count {
  font-family: var(--font-mono);
  color: var(--muted);
  font-size: 0.8rem;
}
.engine-v0-hand {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--engine-radius);
}
.engine-v0-hand-card {
  min-width: 84px;
  padding: 0.5rem 0.7rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 600;
  cursor: default;
  text-align: center;
}
/* [REQ-NEW-cheat-shading] Removed opacity reduction for disabled hand cards in Cheat
   so cards remain visible during opponent's turn */
.engine-v0-button {
  padding: 0.6rem 1rem;
  margin: 0.25rem 0.4rem 0 0;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
}
.engine-v0-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.engine-v0-button:enabled:hover {
  border-color: var(--accent);
}
/* [PTR-143][PTR-144][REQ-942][REQ-1074] Selected-state feedback for the
   multiSelect hand (Cheat's 1–4 card claims) and the free-rank rank-picker.
   Both toggle `engine-v0-card-selected`; without these rules a picked card or
   rank was visually identical to an unpicked one, so players couldn't tell
   what they'd chosen. The lift + accent ring + fill make the selection
   unmistakable. */
.engine-v0-card-selected,
.engine-v0-hand-card.engine-v0-card-selected,
.engine-v0-claim-rank.engine-v0-card-selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  transform: translateY(-6px);
}
/* [PTR-144][REQ-1074] Rank-picker buttons (free-rank "claim any rank to
   bluff") — laid out as a tidy, tappable selector row instead of the
   unstyled default buttons. */
.engine-v0-claim-rank {
  min-width: 44px;
  padding: 0.5rem 0.6rem;
  margin: 0.2rem 0.3rem 0 0;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
}
.engine-v0-claim-rank:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.engine-v0-claim-rank:enabled:hover {
  border-color: var(--accent);
}
/* [PTR-144][REQ-1074] Caption rendered above the rank-picker so the row
   reads as "pick the rank you'll claim", not loose buttons. */
.engine-v0-claim-rank-label {
  margin: 0.6rem 0 0.15rem;
  font-size: 0.8rem;
  font-weight: 600;
  opacity: 0.85;
}
.engine-v0-winner-modal {
  background: var(--accent);
  color: var(--accent-ink);
  padding: 1.25rem;
  text-align: center;
  font-size: 1.1rem;
  font-weight: 600;
  border-radius: var(--engine-radius);
  margin-top: 1rem;
}
.v2-back-link {
  display: inline-block;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-decoration: none;
  margin-top: 2rem;
  border-top: 1px solid var(--border);
  padding-top: 1rem;
}
.v2-back-link:hover {
  color: var(--accent);
}

/* [REQ-705] Live turn / status announcer. */
.engine-v0-turn-indicator {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--muted);
  text-align: center;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--engine-radius);
  background: var(--surface);
}
.engine-v0-turn-mine {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}
.engine-v0-turn-over {
  color: var(--text);
  background: transparent;
  border-style: dashed;
}
/* [REQ-994] "Your turn" attention pulse (RFE-354e) — the visual
   follow-up REQ-705 deferred. The runtime adds this class to the live
   turn indicator only on the LOCAL seat's turn (opt-in via
   uiConfig.turnPulse) and only when motion is allowed; the ring breathes
   a few times to draw the eye, then settles. Gated again below for
   defence in depth. */
.engine-v0-turn-pulse {
  animation: engine-v0-turn-pulse 1.4s ease-in-out 3;
}
@keyframes engine-v0-turn-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 transparent;
  }
  50% {
    box-shadow: 0 0 0 4px var(--accent);
  }
}

/* [REQ-706] How to Play onboarding — ghost toggle + modal overlay. */
.engine-v0-howto-button {
  align-self: flex-end;
  margin-top: 0;
  padding: 0.4rem 0.9rem;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
}
.engine-v0-howto-button:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.engine-v0-howto-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1000;
  width: calc(100% - 3rem);
  max-width: 420px;
  max-height: 80vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6);
}
.engine-v0-howto-modal::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: rgba(0, 0, 0, 0.65);
}
.engine-v0-howto-title {
  font-family: var(--font-display);
  color: var(--accent);
  font-size: 1.6rem;
  letter-spacing: 0.08em;
  margin: 0;
}
.engine-v0-howto-line {
  font-family: var(--font-body);
  color: var(--text);
  font-size: 0.9rem;
  line-height: 1.5;
  margin: 0;
  position: relative;
  padding-left: 1.1rem;
}
.engine-v0-howto-line::before {
  content: "\203A";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: 600;
}
.engine-v0-howto-close {
  align-self: stretch;
  margin-top: 0.5rem;
}

/* [REQ-707] Mobile responsiveness — phone breakpoint. */
@media (max-width: 480px) {
  body {
    padding: 1.25rem 1rem;
  }
  h1 {
    font-size: 1.9rem;
  }
  .engine-v0-button {
    width: 100%;
    align-self: stretch;
    padding: 0.9rem 1rem;
  }
  .engine-v0-howto-button {
    width: auto;
    align-self: flex-end;
    padding: 0.45rem 0.8rem;
  }
  .engine-v0-howto-close {
    width: 100%;
  }
  .engine-v0-hand-card,
  .engine-v0-option,
  .engine-v0-grid-tile {
    min-height: 44px;
  }
  .engine-v0-card {
    width: 84px;
    height: 118px;
  }
}

/* [REQ-842/843/847] Event-feed + region animations. The runtime applies
   these class names; gated on prefers-reduced-motion below. */
@keyframes engine-v0-pulse {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.04);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes engine-v0-flash {
  0%,
  100% {
    background: rgba(0, 0, 0, 0.03);
  }
  50% {
    background: var(--accent);
  }
}
@keyframes engine-v0-rise {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.engine-v0-anim-pulse {
  animation: engine-v0-pulse var(--engine-motion-base) ease-out;
}
.engine-v0-anim-flash {
  animation: engine-v0-flash 600ms ease-in-out;
}
.engine-v0-trans-rise {
  animation: engine-v0-rise var(--engine-motion-fast) ease-out;
}

/* [REQ-847] FLIP — the runtime sets an inverted transform with no
   transition (Invert), then clears it under this class (Play) so a moved
   card glides to its new position. */
.engine-v0-flipping {
  transition: transform 240ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* [REQ-856] Legal-move highlight (RFE-357) — a playable control reads as
   an affordance. */
.engine-v0-legal {
  box-shadow: 0 0 0 2px var(--accent);
}

/* [REQ-995] Optimistic press feedback (RFE-354c) — the runtime adds this
   class to a control on pointer-down (opt-in via uiConfig.pressFeedback)
   so a tapped control depresses the instant the tap lands, before the
   move's rerender. Instant (no transition) to stay snappy and to avoid
   fighting the REQ-847 .engine-v0-flipping transition; reduced-motion off
   below. Generalises the RFE-299 button-press affordance to every engine
   control. */
.engine-v0-pressed {
  transform: scale(0.96);
}

/* [REQ-996] Opt-in hover affordances (RFE-354b) — when a surface sets
   uiConfig.hoverAffordance the runtime tags the host .engine-v0-hover, and
   a pointer device gets an elevation + accent cue on the non-disabled
   control under the cursor so it reads as interactive. Motion-free
   (box-shadow + border, no transform) so it never fights the REQ-847 FLIP
   transform and needs no reduced-motion gate; @media (hover: hover) keeps
   it off touch screens (no sticky hover left after a tap). */
@media (hover: hover) {
  .engine-v0-hover .engine-v0-button:not(:disabled):hover,
  .engine-v0-hover .engine-v0-option:not(:disabled):hover,
  .engine-v0-hover .engine-v0-hand-card:not(:disabled):hover,
  .engine-v0-hover .engine-v0-grid-tile:not(:disabled):hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
    border-color: var(--accent);
    cursor: pointer;
  }
}

@media (prefers-reduced-motion: reduce) {
  .engine-v0-anim-pulse,
  .engine-v0-anim-flash,
  .engine-v0-trans-rise,
  .engine-v0-turn-pulse {
    animation: none;
  }
  .engine-v0-flipping {
    transition: none;
  }
  .engine-v0-pressed {
    transform: none;
  }
}

/* [REQ-885] Common region families shared by most surfaces (scoreBoard /
   options / card colours / trick). Tokenised; a surface still overrides
   any of these from its inline <style> (loaded after) or drops the inline
   copy and inherits these. Canonical values lifted from the per-surface
   inline blocks they replace. */
.engine-v0-scoreboard {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.5rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--engine-radius);
}
.engine-v0-scoreboard-row {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 0.85rem;
}
.engine-v0-scoreboard-label { color: var(--muted); }
.engine-v0-scoreboard-value { color: var(--text); font-weight: 600; }

/* [REQ-1039] Viewer-relative N-seat roster (Coup 2-6 players). One row
   per seat: label · coins · hidden influence count. Motion-free. */
.engine-v0-seat-summary {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.5rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--engine-radius);
}
.engine-v0-seat-summary-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.85rem;
}
.engine-v0-seat-summary-label { color: var(--muted); font-weight: 600; }
.engine-v0-seat-summary-coins,
.engine-v0-seat-summary-influence { color: var(--text); }
.engine-v0-seat-summary-row.engine-v0-seat-self .engine-v0-seat-summary-label {
  color: var(--accent);
}
.engine-v0-seat-summary-row.engine-v0-seat-out {
  opacity: 0.5;
  text-decoration: line-through;
}
.engine-v0-seat-summary-row.engine-v0-active-seat {
  border-left: 3px solid var(--accent);
  padding-left: 0.4rem;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

.engine-v0-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 0.5rem 0;
}
.engine-v0-option {
  padding: 0.5rem 0.8rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}

.engine-v0-card-red { color: var(--red); }
.engine-v0-card-black { color: var(--text); }
.engine-v0-card-empty { color: var(--muted); border-style: dashed; }

/* [REQ-908] Standard playing-card face. The runtime (applyCardFace) turns
   a {rank,suit} standard-deck card into corner indices + a centre pip; this
   styles it as a real white card. Works on a sized card tile, a hand-card
   button, or a trick slot — `--cf-scale` lets each context tune the type
   size. Red/black come from the .engine-v0-card-red/-black classes. */
.engine-v0-card-face {
  --cf-scale: 1;
  position: relative;
  box-sizing: border-box;
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-family: "Georgia", "Times New Roman", serif;
  line-height: 1;
}
/* [REQ-908] Compound specificity (0,2,0) so the white card face beats a
   per-game inline `.engine-v0-card { background: var(--surface) }` tile rule
   (war / president / gin_rummy / ers / speed / euchre) regardless of source
   order — those dark tiles become real white cards when they hold a card. */
.engine-v0-card.engine-v0-card-face,
.engine-v0-hand-card.engine-v0-card-face,
.engine-v0-trick-card.engine-v0-card-face {
  background: #fafaf7;
  border: 1px solid #c7cbd6;
}
.engine-v0-card-face.engine-v0-card-red { color: #d11f2d; }
.engine-v0-card-face.engine-v0-card-black { color: #16181d; }
.engine-v0-card-index {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 0.85;
  font-weight: 700;
}
.engine-v0-card-index-tl {
  top: calc(4px * var(--cf-scale));
  left: calc(5px * var(--cf-scale));
}
.engine-v0-card-index-br {
  bottom: calc(4px * var(--cf-scale));
  right: calc(5px * var(--cf-scale));
  transform: rotate(180deg);
}
.engine-v0-cf-rank {
  font-size: calc(0.95rem * var(--cf-scale));
}
.engine-v0-cf-suit {
  font-size: calc(0.8rem * var(--cf-scale));
}
/* [REQ-924] Pip layouts for number ranks 2–10. The runtime positions each
   pip by inline left/top % within this central area (inset so it clears the
   corner indices); lower-half pips carry -pip-flip (rotated 180°). */
.engine-v0-card-pips {
  position: absolute;
  inset: 12% 16%;
}
.engine-v0-card-pip {
  position: absolute;
  transform: translate(-50%, -50%);
  font-size: calc(0.72rem * var(--cf-scale));
  line-height: 1;
}
.engine-v0-card-pip-flip {
  transform: translate(-50%, -50%) rotate(180deg);
}
/* [REQ-924] Ace — a single large centre pip. */
.engine-v0-card-ace {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: calc(2.3rem * var(--cf-scale));
}
/* [REQ-1059] Court (J/Q/K) — illustrated panel: top suit row, chess-piece
   figure (♞/♛/♚), rank label, mirrored bottom suit row. */
.engine-v0-card-court {
  position: absolute;
  inset: 14% 16%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: calc(2px * var(--cf-scale)) calc(3px * var(--cf-scale));
  border: 1.5px solid currentColor;
  border-radius: 4px;
  overflow: hidden;
}
.engine-v0-card-court-suit-row {
  display: flex;
  justify-content: space-between;
  width: 100%;
  font-size: calc(0.5rem * var(--cf-scale));
  line-height: 1;
  opacity: 0.75;
}
.engine-v0-card-court-suit-row-flip {
  transform: rotate(180deg);
}
.engine-v0-card-court-figure {
  font-size: calc(1.7rem * var(--cf-scale)); /* fallback for text path */
  width: calc(1.7rem * var(--cf-scale));
  height: calc(1.7rem * var(--cf-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
/* [REQ-1140] SVG inherits currentColor for suit tint */
.engine-v0-card-court-figure svg {
  fill: currentColor;
  display: block;
}
.engine-v0-card-court-label {
  font-size: calc(0.6rem * var(--cf-scale));
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1;
}

/* [REQ-908] Hand-card + trick-card faces need a card geometry (the plain
   chips have none). This wins over a surface's inline .engine-v0-hand-card
   sizing by specificity, so migrated surfaces don't need per-game edits. */
.engine-v0-hand-card.engine-v0-card-face,
.engine-v0-trick-card.engine-v0-card-face {
  --cf-scale: 0.82;
  width: 46px;
  height: 64px;
  min-width: 46px;
  padding: 0;
  text-align: initial;
}
.engine-v0-hand-card.engine-v0-card-face:enabled:hover {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent);
}
/* Disabled card-face cards render normally (no opacity) */
@media (prefers-reduced-motion: no-preference) {
  .engine-v0-hand-card.engine-v0-card-face {
    transition: transform 120ms ease-out;
  }
  .engine-v0-hand-card.engine-v0-card-face:enabled:hover {
    transform: translateY(-4px);
  }
}

.engine-v0-trick {
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--engine-radius);
  min-height: 64px;
  flex-wrap: wrap;
}
.engine-v0-trick-empty {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.85rem;
}
.engine-v0-trick-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  min-width: 48px;
}
.engine-v0-trick-label {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.65rem;
}
.engine-v0-trick-card {
  font-family: var(--font-mono);
  font-size: 1rem;
  font-weight: 600;
}

/* [REQ-885] Named-preset palettes (§6). The runtime sets
   data-engine-preset on the engine root from theme.preset; we re-declare
   the palette at `:root` via `:has()` so the WHOLE page (body backdrop
   included), not just the board, takes the identity. `default` is the
   brand palette above (no block needed). Per-key theme overrides still
   win (inline on the root element, higher specificity). */
:root:has([data-engine-preset="parchment"]) {
  --bg: #efe6d3;
  --surface: #e3d7bd;
  --border: #c9b896;
  --text: #3a3326;
  --muted: #7a6f58;
  --accent: #b8860b;
  --accent-ink: #fdf8ec;
  --danger: #a23b2c;
}
:root:has([data-engine-preset="noir"]) {
  --bg: #000000;
  --surface: #0d0d0d;
  --border: #333333;
  --text: #f5f5f5;
  --muted: #888888;
  --accent: #ffffff;
  --accent-ink: #000000;
  --danger: #ff3b3b;
}

/* [REQ-972] Themed icon card faces — custom-deck cards (no French suit)
   that carry `glyph`/`label`/`tone` art (the runtime's applyIconFace builds
   the DOM). Unlike the white standard face, an icon card is a dark, neon-
   framed tile that reads against the brand's dark surface: a big centre
   glyph, a corner + centred name in the tone accent, and a tone-tinted
   gradient with a glowing border. The card data drives it, so only games
   that supply art (Exploding Kittens) opt in — every other surface is
   untouched. Sizing wins over the 46×64 standard-face geometry by source
   order at equal (0,2,0) specificity. */
.engine-v0-card-icon {
  --cf-scale: 1;
  --icon-accent: #c7cbd6;
  --icon-glow: rgba(199, 203, 214, 0.45);
  flex-direction: column;
  justify-content: center;
  gap: calc(0.12rem * var(--cf-scale));
  font-family: var(--font-mono);
  background: linear-gradient(160deg, #14161c, #191c24);
  border: 1.5px solid var(--icon-accent);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.4),
    0 0 10px -2px var(--icon-glow),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  color: var(--icon-accent);
}
/* Win over the white standard-face fill for hand/tile/trick contexts. */
.engine-v0-hand-card.engine-v0-card-icon,
.engine-v0-card.engine-v0-card-icon,
.engine-v0-trick-card.engine-v0-card-icon {
  --cf-scale: 1.05;
  width: 72px;
  height: 100px;
  min-width: 72px;
  background: linear-gradient(160deg, #14161c, #191c24);
  border: 1.5px solid var(--icon-accent);
}
.engine-v0-card-glyph {
  font-size: calc(2.1rem * var(--cf-scale));
  line-height: 1;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.55));
}
.engine-v0-card-name {
  font-size: calc(0.5rem * var(--cf-scale));
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--icon-accent);
}
.engine-v0-card-icon .engine-v0-card-index {
  flex-direction: row;
}
.engine-v0-card-iconlabel {
  font-size: calc(0.4rem * var(--cf-scale));
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--icon-accent);
}
/* Tone palettes — accent colour + glow per card kind. */
.engine-v0-card-tone-danger {
  --icon-accent: #ff6b5e;
  --icon-glow: rgba(255, 90, 77, 0.55);
  background: linear-gradient(160deg, #21100e, #2c1513);
}
.engine-v0-card-tone-safe {
  --icon-accent: #5fe0ad;
  --icon-glow: rgba(70, 211, 154, 0.5);
  background: linear-gradient(160deg, #0e1f18, #12271d);
}
.engine-v0-card-tone-info {
  --icon-accent: #6cc2ff;
  --icon-glow: rgba(77, 180, 255, 0.5);
  background: linear-gradient(160deg, #0e1824, #12202e);
}
.engine-v0-card-tone-magic {
  --icon-accent: #c79bff;
  --icon-glow: rgba(176, 123, 255, 0.5);
  background: linear-gradient(160deg, #170f24, #1e132e);
}
.engine-v0-card-tone-neutral {
  --icon-accent: #c7cbd6;
  --icon-glow: rgba(199, 203, 214, 0.4);
  background: linear-gradient(160deg, #14161c, #191c24);
}
/* Match the per-tone gradient/accent on the sized hand/tile/trick contexts
   too (those re-declared `background`/`border` above at higher specificity). */
.engine-v0-hand-card.engine-v0-card-tone-danger,
.engine-v0-card.engine-v0-card-tone-danger,
.engine-v0-trick-card.engine-v0-card-tone-danger {
  background: linear-gradient(160deg, #21100e, #2c1513);
}
.engine-v0-hand-card.engine-v0-card-tone-safe,
.engine-v0-card.engine-v0-card-tone-safe,
.engine-v0-trick-card.engine-v0-card-tone-safe {
  background: linear-gradient(160deg, #0e1f18, #12271d);
}
.engine-v0-hand-card.engine-v0-card-tone-info,
.engine-v0-card.engine-v0-card-tone-info,
.engine-v0-trick-card.engine-v0-card-tone-info {
  background: linear-gradient(160deg, #0e1824, #12202e);
}
.engine-v0-hand-card.engine-v0-card-tone-magic,
.engine-v0-card.engine-v0-card-tone-magic,
.engine-v0-trick-card.engine-v0-card-tone-magic {
  background: linear-gradient(160deg, #170f24, #1e132e);
}
/* A playable icon hand card (enabled) lifts + glows in its tone; a disabled
   one (not currently playable) dims, so the legal plays read at a glance. */
.engine-v0-hand-card.engine-v0-card-icon:enabled:hover {
  border-color: var(--icon-accent);
  box-shadow:
    0 4px 14px -2px var(--icon-glow),
    0 0 0 1px var(--icon-accent);
}
.engine-v0-hand-card.engine-v0-card-icon:disabled {
  opacity: 0.45;
  filter: saturate(0.6);
}

/* [REQ-910] Drag-and-drop (RFE-354b): a hand card mid-drag rides above its
   siblings and tracks the pointer crisply (no transition fighting the
   per-frame transform); the cursor reads as a grab. The transform itself is
   set inline by the runtime's pointer handlers. */
.engine-v0-hand-card.engine-v0-dragging {
  z-index: 10;
  transition: none;
  cursor: grabbing;
  touch-action: none;
}

/* [REQ-1001] Active-seat scoreboard highlight (RFE-354 "feel"): the
   scoreboard row of the seat on turn reads as live at a glance. Opt-in
   per region (region.activeSeatHighlight); the runtime tags only the
   active row. Motion-free (accent left-border + faint tint + weight), so
   it needs no prefers-reduced-motion gate. */
.engine-v0-scoreboard-row.engine-v0-active-seat {
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  padding-left: 0.4em;
  font-weight: 600;
}
