/* =============================================================================
   MysteryBox — Design Tokens, Reset & Base Layer
   THEME: Pirate / Treasure Hunt  (PROJECT-BRIEF.md §11, ADDENDUM 3)
   Spec: docs/DESIGN-SYSTEM.md  ·  Owner: Tech Lead B (Frontend & Experience)

   Shared by BOTH frontends. Link this first on every page:
     web/index.html   -> <link rel="stylesheet" href="/css/tokens.css">
     admin/index.html -> <link rel="stylesheet" href="/css/tokens.css">

   RE-SKIN NOTE (2026-08): the Gen-Z neon palette was replaced by the pirate
   palette. EVERY token name from the neon system is preserved — only VALUES
   changed. Where a name is now semantically odd (--c-pink, --c-violet,
   --c-cyan, --c-lime, --c-amber) a readable alias sits directly beneath it.
   Prefer the alias in new code; both resolve to the same colour.

   Contains NO page-specific styling. Do not add component layout here.
   Do not redeclare these tokens anywhere else. No hex literals outside this file.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  color-scheme: dark;

  /* 1.1 Base & surfaces — deep sea / night water, NOT black ---------------- */
  --c-base-deep: #04121a;           /* page backdrop behind the sea gradient  */
  --c-base: #071b26;                /* canonical app background               */
  --c-surface-1: #0d2735;           /* cards, inputs, table rows              */
  --c-surface-2: #133344;           /* elevated: modals, sheets, table header */
  --c-surface-3: #16394a;           /* highest: toast, hovered rows           */
  --c-ink: #241708;                 /* text ON gold/parchment/light fills     */

  /* Light "parchment" surface family (cards, scrolls, readable panels).
     Text on these NEVER uses --c-text. Use the [data-surface] scope below. */
  --c-parchment: #f0e2c4;
  --c-parchment-deep: #e2cfa8;      /* shadowed parchment, card edge, wells   */
  --c-parchment-edge: #c9b083;      /* torn/burnt rim, decorative             */
  --c-sand: #d9c49a;                /* sandbar band, decorative fill          */

  /* Wood family — chest bodies and admin panelling ------------------------ */
  --c-wood-deep: #2e2013;           /* chest interior shadow, plank gap       */
  --c-wood: #4a3520;                /* oiled oak — the admin panel surface    */
  --c-wood-light: #7a5730;          /* lit plank face, raised band            */

  /* 1.2 Text (on DARK surfaces) ------------------------------------------- */
  --c-text: #f4ead8;                /* bone white — 14.74:1 on base           */
  --c-text-secondary: #c4b79c;      /*  8.87:1 on base                        */
  --c-text-muted: #b2a992;          /*  7.52:1 on base — safe for placeholders*/
  --c-text-disabled: #6e7a80;       /* [disabled] labels ONLY (SC 1.4.3 exempt)*/

  /* Text on LIGHT (parchment / sand / gold) surfaces ----------------------- */
  --c-ink-soft: #4a3a26;            /*  8.51:1 on parchment                   */
  --c-ink-muted: #6b5b45;           /*  5.10:1 on parchment ONLY (see §3.5)   */

  /* 1.3 Accent ramp — names kept from the neon system, values re-pointed --- */
  --c-pink: #e8705f;                /* weathered crimson — 5.79:1 on base     */
  --c-crimson: var(--c-pink);
  --c-pink-soft: #f2a08f;           /* the crimson for text on surface-2/3    */
  --c-crimson-soft: var(--c-pink-soft);
  --c-crimson-deep: #7c1d22;        /* BANNER + danger FILL (cream on it 8.56)*/

  --c-violet: #5183e0;              /* sapphire — FILL/BORDER/GLOW ONLY       */
  --c-sapphire: var(--c-violet);
  --c-violet-400: #7ba5ec;          /*  7.06:1 on base                        */
  --c-sapphire-400: var(--c-violet-400);
  --c-violet-text: #a8c4f2;         /*  9.91:1 on base — the sapphire for text*/
  --c-sapphire-text: var(--c-violet-text);

  --c-cyan: #4fd1c5;                /* turquoise shallows — 9.43:1 on base    */
  --c-turquoise: var(--c-cyan);
  --c-sea: #1b7f8c;                 /* mid water — FILL ONLY (3.73:1)         */
  --c-sea-deep: #0f5f6b;            /* water fill that carries cream (6.13:1) */
  --c-sky: #f2c9a0;                 /* hazy horizon — gradient stop only      */

  --c-lime: #9ad16b;               /* jungle green — 9.80:1 on base           */
  --c-verdigris: var(--c-lime);

  --c-amber: #e7b23a;              /* TREASURE GOLD — 9.06:1 on base          */
  --c-gold: var(--c-amber);
  --c-gold-bright: #f2c75b;        /* lit gold — 10.96:1 on base              */
  --c-gold-deep: #c88a2e;          /* gradient end-stop, engraved gold        */
  --c-brass: #b8862f;              /* bands, filigree, rules — 5.43:1 on base */
  --c-brass-deep: #5a3a18;         /* the gold that carries TEXT ON PARCHMENT */
  --c-bronze: #c08a52;             /* common tier — 5.86:1 on base            */
  --c-bronze-light: #d9a874;       /* the bronze for text on surface-2/3/tint */
  --c-rope: #c9a46a;               /* rope highlight, decorative              */
  --c-rope-dark: #8a6b3d;          /* rope shadow, decorative                 */
  --c-wax: #8e2118;                /* wax-seal body (cream on it 7.39:1)      */

  /* 1.4 Semantic ----------------------------------------------------------- */
  --c-success: #6fc98c;
  --c-success-tint: rgb(111 201 140 / 0.16);
  --c-danger: #f58275;              /* danger as TEXT / BORDER (4.85:1 worst) */
  --c-danger-tint: rgb(245 130 117 / 0.16);
  --c-danger-fill: var(--c-crimson-deep); /* danger as a FILL, cream text     */
  --c-warning: #e7b23a;
  --c-warning-tint: rgb(231 178 58 / 0.16);
  --c-info: #4fd1c5;
  --c-info-tint: rgb(79 209 197 / 0.16);

  /* 1.5 Prize tiers (schema: jackpot | grand | common | zonk) --------------- */
  --c-tier-jackpot: #f2c75b;        /* gold + sapphire coins                  */
  --c-tier-grand: #cfd0c2;          /* silver-gold electrum                   */
  --c-tier-common: #c08a52;         /* bronze / copper                        */
  --c-tier-zonk: #afa48e;           /* weathered driftwood                    */
  /* Text-safe variants for tier labels on tinted/elevated backgrounds.       */
  --c-tier-common-text: var(--c-bronze-light);

  /* 1.6 Borders ------------------------------------------------------------ */
  --c-border-subtle: rgb(244 234 216 / 0.08);
  --c-border: rgb(244 234 216 / 0.14);
  --c-border-interactive: #9a8358;  /* >=3:1 on every DARK surface (SC 1.4.11)*/
  --c-border-interactive-light: var(--c-brass-deep); /* the same role on parchment */
  --c-border-strong: rgb(244 234 216 / 0.30);
  --c-scrim: rgb(4 18 26 / 0.72);
  --c-scrim-solid: rgb(4 18 26 / 0.94);

  /* 1.7 Gradients ---------------------------------------------------------- */
  --grad-primary: linear-gradient(135deg, #f2c75b 0%, #c88a2e 100%);
  --grad-primary-hover: linear-gradient(135deg, #fbda85 0%, #dda144 100%);
  --grad-success: linear-gradient(135deg, #9ad16b 0%, #4fa97a 100%);
  --grad-danger: linear-gradient(135deg, #7c1d22 0%, #a33731 100%);

  /* The treasure-chest tile. --grad-tile is the chest BODY (planked oak),
     --grad-chest-lid is the lid face. Both take gold/brass detailing. */
  --grad-tile: linear-gradient(165deg, #6e4c29 0%, #4a3520 46%, #2e2013 100%);
  --grad-tile-hover: linear-gradient(165deg, #855d31 0%, #5a4127 46%, #3a2818 100%);
  --grad-chest-lid: linear-gradient(180deg, #7a5730 0%, #55391f 62%, #3b2715 100%);
  --grad-wood: linear-gradient(92deg, #4a3520 0%, #573d24 34%, #43301d 67%, #4f3822 100%);

  /* Brass / gold sheen for bands, locks, filigree and rules. */
  --grad-brass: linear-gradient(180deg, #f2c75b 0%, #c88a2e 42%, #8a6b3d 78%, #e7b23a 100%);
  --grad-banner: linear-gradient(180deg, #a33731 0%, #7c1d22 55%, #611318 100%);
  --grad-parchment: linear-gradient(168deg, #f5ebd4 0%, #f0e2c4 46%, #e2cfa8 100%);

  --grad-text: linear-gradient(100deg, #f7de9b 0%, #f2c75b 45%, #c88a2e 100%);

  /* Sea & sky. Replaces the neon mesh. Warm hazy sky at the horizon,
     turquoise shallows, deep water sinking into --c-base-deep at the foot.
     This is the fallback whenever the admin background image is absent
     or fails to load (ADDENDUM 2 §10.3). */
  --grad-sky: linear-gradient(180deg, #f2c9a0 0%, #e8a878 38%, #b9764f 100%);
  --grad-sea: linear-gradient(180deg, #4fd1c5 0%, #1b7f8c 44%, #0f5f6b 78%, #04121a 100%);
  --grad-mesh:
    radial-gradient(128% 62% at 50% -14%, rgb(242 201 160 / 0.22) 0%,
                                          rgb(224 138 92 / 0.11) 34%, transparent 72%),
    radial-gradient(88% 50% at 10% 24%, rgb(79 209 197 / 0.13) 0%, transparent 66%),
    radial-gradient(96% 58% at 90% 32%, rgb(27 127 140 / 0.20) 0%, transparent 68%),
    linear-gradient(180deg,
      rgb(19 51 68 / 0) 0%,
      rgb(15 95 107 / 0.22) 46%,
      rgb(4 18 26 / 0.88) 100%);

  --grad-skeleton: linear-gradient(
    100deg, var(--c-surface-2) 20%, var(--c-surface-3) 42%, var(--c-surface-2) 64%);

  /* 1.8 Typography --------------------------------------------------------- */
  /* Display = inscriptional/engraved (Cinzel, Trajan family). HEADINGS ONLY,
     never below --fs-lg. Body = Plus Jakarta Sans (Indonesian typeface, kept
     from the previous system because the rationale still holds). */
  --font-display: "Cinzel", "Trajan Pro 3", "Trajan Pro", Optima,
    "Palatino Linotype", "Book Antiqua", Palatino, "Noto Serif", "Times New Roman",
    Georgia, serif;
  --font-ui: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto,
    "Noto Sans", "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "JetBrains Mono", SFMono-Regular, "SF Mono", Menlo,
    Consolas, "Liberation Mono", monospace;

  --fs-2xs: clamp(0.6875rem, 0.66rem + 0.14vw, 0.75rem);
  --fs-xs: clamp(0.75rem, 0.72rem + 0.15vw, 0.8125rem);
  --fs-sm: clamp(0.8125rem, 0.78rem + 0.17vw, 0.875rem);
  --fs-base: clamp(0.9375rem, 0.9rem + 0.19vw, 1rem);
  --fs-md: clamp(1.0625rem, 1rem + 0.31vw, 1.125rem);
  --fs-lg: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
  --fs-xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);
  --fs-2xl: clamp(1.875rem, 1.5rem + 1.9vw, 2.75rem);
  --fs-3xl: clamp(2.25rem, 1.6rem + 3.2vw, 4rem);
  --fs-display: clamp(2.5rem, 1.6rem + 4.6vw, 5rem);

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-black: 800;

  --lh-tight: 1.14;                 /* raised from 1.05 — caps need headroom  */
  --lh-snug: 1.28;
  --lh-normal: 1.55;
  --lh-loose: 1.7;

  /* An inscriptional face wants POSITIVE tracking. --ls-tight keeps its name
     (the base heading rule reads it) but is now the display tracking value. */
  --ls-tight: 0.015em;
  --ls-display: var(--ls-tight);
  --ls-normal: 0em;
  --ls-wide: 0.04em;
  --ls-caps: 0.1em;

  --measure: 68ch;
  --measure-page: 1160px;

  /* 1.9 Spacing ------------------------------------------------------------ */
  --sp-0: 0;
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.25rem;
  --sp-6: 1.5rem;
  --sp-8: 2rem;
  --sp-10: 2.5rem;
  --sp-12: 3rem;
  --sp-16: 4rem;
  --sp-20: 5rem;
  --sp-24: 6rem;
  --sp-section: clamp(3rem, 2rem + 5vw, 7rem);
  --sp-gutter: clamp(1rem, 0.6rem + 1.8vw, 2rem);

  /* 1.10 Radius — tightened. Wood, brass and parchment are not bubble-gum. -- */
  --r-xs: 4px;
  --r-sm: 7px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 18px;
  --r-2xl: 24px;
  --r-pill: 999px;

  /* 1.11 Elevation & glow — lantern light, gold rim, carved wood ----------- */
  --sh-1: 0 1px 2px rgb(0 0 0 / 0.44), 0 2px 8px rgb(0 0 0 / 0.30);
  --sh-2: 0 4px 12px rgb(0 0 0 / 0.46), 0 12px 32px rgb(0 0 0 / 0.36);
  --sh-3: 0 12px 28px rgb(0 0 0 / 0.52), 0 32px 64px rgb(0 0 0 / 0.46);
  --sh-inset: inset 0 1px 0 rgb(244 234 216 / 0.09);
  --sh-carved: inset 0 1px 0 rgb(244 234 216 / 0.10),
               inset 0 -1px 0 rgb(0 0 0 / 0.45);

  --glow-pink: 0 0 0 1px rgb(232 112 95 / 0.38), 0 8px 32px rgb(232 112 95 / 0.30);
  --glow-violet: 0 0 0 1px rgb(81 131 224 / 0.38), 0 8px 32px rgb(81 131 224 / 0.30);
  --glow-cyan: 0 0 0 1px rgb(79 209 197 / 0.38), 0 8px 32px rgb(79 209 197 / 0.28);
  --glow-lime: 0 0 0 1px rgb(154 209 107 / 0.38), 0 8px 32px rgb(154 209 107 / 0.26);
  --glow-amber: 0 0 0 1px rgb(242 199 91 / 0.40), 0 8px 32px rgb(242 199 91 / 0.30);
  --glow-gold: var(--glow-amber);
  --glow-lantern: 0 0 0 1px rgb(231 178 58 / 0.30), 0 10px 40px rgb(200 138 46 / 0.34);
  --glow-rim-gold: inset 0 0 0 1px rgb(242 199 91 / 0.55),
                   inset 0 1px 0 rgb(247 222 155 / 0.45);
  --glow-strong: 0 0 48px rgb(242 199 91 / 0.55), 0 0 96px rgb(200 138 46 / 0.42);

  /* 1.12 Focus (SC 2.4.11) — dual ring, ink inner + turquoise outer -------- */
  --focus-inner: 2px;
  --focus-outer: 3px;
  --focus-ring:
    0 0 0 var(--focus-inner) var(--c-ink),
    0 0 0 calc(var(--focus-inner) + var(--focus-outer)) var(--c-cyan);
  --focus-ring-quiet: 0 0 0 2px var(--c-cyan);
  /* Inverted ring for controls sitting on parchment/gold. See DESIGN-SYSTEM §3.6. */
  --focus-ring-light:
    0 0 0 var(--focus-inner) var(--c-parchment),
    0 0 0 calc(var(--focus-inner) + var(--focus-outer)) var(--c-ink);

  /* 1.13 Z-index ----------------------------------------------------------- */
  --z-below: -1;
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-header: 200;
  --z-overlay: 800;
  --z-modal: 900;
  --z-toast: 1000;
  --z-max: 9999;

  /* 1.14 Motion ------------------------------------------------------------ */
  --dur-instant: 90ms;
  --dur-fast: 160ms;
  --dur-base: 240ms;
  --dur-slow: 380ms;
  --dur-slower: 560ms;
  --dur-reveal: 750ms;
  --dur-bob: 4200ms;                /* idle float — decorative, killed by RM  */
  --stagger: 45ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.55, 0, 1, 0.45);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.5, 0.64, 1);
  --ease-bounce: cubic-bezier(0.5, -0.35, 0.3, 1.4);   /* heavier: it is oak  */
  --ease-water: cubic-bezier(0.45, 0.05, 0.55, 0.95);  /* swell, not a spring */

  /* 1.15 Controls ---------------------------------------------------------- */
  --target-min: 44px;               /* SC 2.5.8 — we exceed the 24px AA floor */
  --control-h-sm: 44px;
  --control-h: 52px;
  --control-h-lg: 60px;
  --board-cols: 2;
  --board-gap: var(--sp-3);
  --board-max: 880px;
}

/* Admin density overrides. Add class="admin" to <html> or <body> in /admin. */
.admin {
  --r-lg: 10px;
  --r-xl: 14px;
  --r-2xl: 18px;
  --control-h: 44px;
  --control-h-lg: 52px;
  --sp-section: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);
}

/* -----------------------------------------------------------------------------
   1.16 LIGHT-SURFACE SCOPES  (opt-in, additive)
   A pirate palette has two readable grounds, not one. Put
   data-surface="parchment" on a parchment card / scroll panel, or
   data-surface="wood" on an admin wooden panel, and the text, border and focus
   tokens re-point to the audited pair for that ground. Never hand-pick a text
   colour for a light surface — use the scope. Ratios: DESIGN-SYSTEM.md §3.5.
   -------------------------------------------------------------------------- */
[data-surface="parchment"] {
  color-scheme: light;
  --c-text: var(--c-ink);                          /* 13.64:1 on parchment    */
  --c-text-secondary: var(--c-ink-soft);           /*  8.51:1                 */
  --c-text-muted: var(--c-ink-muted);              /*  5.10:1 (see §3.5 note) */
  --c-text-disabled: #8a7c66;
  --c-border-subtle: rgb(36 23 8 / 0.12);
  --c-border: rgb(36 23 8 / 0.22);
  --c-border-interactive: var(--c-border-interactive-light); /* 7.97:1        */
  --c-border-strong: rgb(36 23 8 / 0.50);
  --c-danger: var(--c-crimson-deep);               /*  7.96:1 on parchment    */
  --focus-ring: var(--focus-ring-light);
  --focus-ring-quiet: 0 0 0 2px var(--c-ink);
  color: var(--c-text);
}

[data-surface="wood"] {
  --c-surface-1: var(--c-wood);
  --c-surface-2: var(--c-wood-light);
  --c-surface-3: var(--c-wood-deep);
  /* Text tokens are unchanged: bone/sand on oiled oak measures 9.67 / 5.82 /
     4.93:1. Do NOT place --c-amber text on --c-wood-light (3.34:1, §3.4 F3). */
}

/* -----------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scrollbar-gutter: stable;
}

body {
  min-height: 100dvh;
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  line-height: var(--lh-normal);
  color: var(--c-text);
  background-color: var(--c-base-deep);
  background-image: var(--grad-mesh);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img,
picture,
svg,
video,
canvas { display: block; max-width: 100%; }

img,
video { height: auto; }

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button { background: none; border: none; }

p,
h1,
h2,
h3,
h4,
li { overflow-wrap: break-word; }

ul[class],
ol[class] { list-style: none; padding: 0; }

table { border-collapse: collapse; border-spacing: 0; }

:target { scroll-margin-block: var(--sp-16); }

/* -----------------------------------------------------------------------------
   3. BASE ELEMENTS
   -------------------------------------------------------------------------- */
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  text-wrap: balance;
}

h1 { font-size: var(--fs-2xl); font-weight: var(--fw-black); line-height: var(--lh-tight); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }

/* h4 is the floor of the display face. Anything smaller uses --font-ui:
   Cinzel is a heading-only face and is illegible below ~20px (§4.1). */
h4 {
  font-size: var(--fs-md);
  font-family: var(--font-ui);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-normal);
}

p { max-width: var(--measure); text-wrap: pretty; }

small { font-size: var(--fs-xs); color: var(--c-text-muted); }

a {
  color: var(--c-cyan);
  text-decoration: underline;
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.18em;
  border-radius: var(--r-xs);
  transition: color var(--dur-instant) var(--ease-out);
}
a:hover { color: var(--c-amber); }

/* Turquoise is invisible on parchment (1.45:1). Links on a light ground take
   the deep-water blue-green instead (5.70:1). */
[data-surface="parchment"] a { color: var(--c-sea-deep); }
[data-surface="parchment"] a:hover { color: var(--c-crimson-deep); }

code,
kbd,
samp,
pre { font-family: var(--font-mono); font-size: 0.94em; }

hr { border: 0; border-top: 1px solid var(--c-border-subtle); margin-block: var(--sp-8); }

::placeholder { color: var(--c-text-muted); opacity: 1; }

::selection { background: var(--c-amber); color: var(--c-ink); }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Programmatic focus targets (modal shell, result region) get the quiet ring. */
[tabindex="-1"]:focus-visible { outline: none; box-shadow: var(--focus-ring-quiet); }

[hidden] { display: none !important; }

[aria-disabled="true"],
:disabled { cursor: not-allowed; }

/* -----------------------------------------------------------------------------
   4. UTILITIES
   -------------------------------------------------------------------------- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  inset-block-start: var(--sp-2);
  inset-inline-start: var(--sp-2);
  z-index: var(--z-max);
  padding: var(--sp-3) var(--sp-5);
  min-height: var(--target-min);
  display: grid;
  place-items: center;
  border-radius: var(--r-lg);
  background: var(--c-surface-2);
  color: var(--c-text);
  text-decoration: none;
  box-shadow: var(--sh-3);
  transform: translateY(-160%);
  transition: transform var(--dur-fast) var(--ease-out);
}
.skip-link:focus-visible { transform: translateY(0); box-shadow: var(--focus-ring), var(--sh-3); }

.u-container {
  width: 100%;
  max-width: var(--measure-page);
  margin-inline: auto;
  padding-inline: var(--sp-gutter);
}

.u-stack { display: flex; flex-direction: column; gap: var(--gap, var(--sp-4)); }

.u-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap, var(--sp-3));
}

.u-center { display: grid; place-items: center; }

.u-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.u-tabular { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

.u-code {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  font-variant-numeric: tabular-nums slashed-zero;
}

.u-caps {
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
}

/* Gradient display text — gold leaf. Falls back to solid gold where clipping
   is unsupported. DARK GROUNDS ONLY: every stop is >=5.97:1 on --c-base but
   the same gradient measures 1.5:1 on parchment (§3.4 F2). */
.u-grad-text { color: var(--c-amber); }
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .u-grad-text {
    background-image: var(--grad-text);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
[data-surface="parchment"] .u-grad-text {
  background-image: none;
  color: var(--c-brass-deep);
}

/* Expands a small control's hit area to 44x44 without changing its box (SC 2.5.8). */
.u-hit-area { position: relative; }
.u-hit-area::after {
  content: "";
  position: absolute;
  inset: 50% 50% 50% 50%;
  width: var(--target-min);
  height: var(--target-min);
  translate: -50% -50%;
}

.u-glow-pink { box-shadow: var(--glow-pink); }
.u-glow-violet { box-shadow: var(--glow-violet); }
.u-glow-cyan { box-shadow: var(--glow-cyan); }
.u-glow-lime { box-shadow: var(--glow-lime); }
.u-glow-amber { box-shadow: var(--glow-amber); }
.u-glow-lantern { box-shadow: var(--glow-lantern); }
.u-rim-gold { box-shadow: var(--glow-rim-gold); }

.u-elevate-1 { box-shadow: var(--sh-1); }
.u-elevate-2 { box-shadow: var(--sh-2); }
.u-elevate-3 { box-shadow: var(--sh-3); }

.u-surface {
  background: var(--c-surface-1);
  border: 1px solid var(--c-border);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2), var(--sh-inset);
}

/* Parchment card ground. Pair with data-surface="parchment" on the same node. */
.u-parchment {
  background-image: var(--grad-parchment);
  background-color: var(--c-parchment);
  border: 1px solid var(--c-parchment-edge);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2);
}

/* Wooden panel ground (admin). Pair with data-surface="wood". */
.u-wood {
  background-image: var(--grad-wood);
  background-color: var(--c-wood);
  border: 1px solid var(--c-wood-deep);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-2), var(--sh-carved);
}

/* Rope rule / brass rule — decorative separators, aria-hidden at call site. */
.u-rope-rule {
  height: 3px;
  border-radius: var(--r-pill);
  background: repeating-linear-gradient(
    68deg, var(--c-rope) 0 5px, var(--c-rope-dark) 5px 10px);
}
.u-brass-rule {
  height: 2px;
  border-radius: var(--r-pill);
  background-image: var(--grad-brass);
}

/* Skeleton loader. Mark the container aria-busy="true" aria-hidden="true". */
.skeleton {
  background-color: var(--c-surface-2);
  background-image: var(--grad-skeleton);
  background-size: 220% 100%;
  background-position: 180% 0;
  border-radius: var(--r-sm);
  animation: mb-shimmer 1400ms var(--ease-in-out) infinite;
}
.skeleton--text { height: 0.85em; margin-block: 0.35em; }
.skeleton--tile { aspect-ratio: 1; border-radius: var(--r-xl); }

@keyframes mb-shimmer {
  to { background-position: -40% 0; }
}

@keyframes mb-spin {
  to { rotate: 360deg; }
}

@keyframes mb-rise {
  from { opacity: 0; translate: 0 12px; }
  to { opacity: 1; translate: 0 0; }
}

/* Gentle bob — something floating on water. Replaces the neon "pulse".
   Decorative only: it never carries state and is removed under reduced motion. */
@keyframes mb-bob {
  0%, 100% { translate: 0 0; rotate: -0.4deg; }
  50% { translate: 0 -5px; rotate: 0.4deg; }
}

.u-rise { animation: mb-rise var(--dur-base) var(--ease-out) both; }
.u-bob { animation: mb-bob var(--dur-bob) var(--ease-water) infinite; }

/* -----------------------------------------------------------------------------
   5. RESPONSIVE BOARD VARIABLES
   Consumed by the board grid in web/css/. See DESIGN-SYSTEM.md §10.1.
   -------------------------------------------------------------------------- */
@media (min-width: 480px) {
  :root { --board-gap: var(--sp-4); }
}
@media (min-width: 768px) {
  :root { --board-cols: 4; --board-gap: var(--sp-5); }
}
@media (min-width: 1024px) {
  :root { --board-gap: var(--sp-6); }
}
@media (min-width: 1200px) {
  :root { --board-gap: 1.75rem; }
}

/* -----------------------------------------------------------------------------
   6. REDUCED MOTION (SC 2.3.3)
   Durations collapse at :root so every token-driven transition follows.
   State changes stay visible — only the movement is removed.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 1ms;
    --dur-fast: 1ms;
    --dur-base: 1ms;
    --dur-slow: 1ms;
    --dur-slower: 1ms;
    --dur-reveal: 1ms;
    --dur-bob: 1ms;
    --stagger: 0ms;
    --ease-out: linear;
    --ease-spring: linear;
    --ease-bounce: linear;
    --ease-water: linear;
  }

  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  .skeleton { animation: none !important; background-image: none; }
  .u-rise { animation: none !important; }

  /* The idle float is decorative: remove the motion, keep the element. */
  .u-bob { animation: none !important; translate: none !important; rotate: none !important; }

  /* Purely decorative particle layers are removed outright.
     .mb-confetti is retained for back-compat; .mb-coinburst is the pirate
     coin/gem burst that replaces it. Neither ever carries information —
     the win is announced in #mb-result and drawn on the reveal card. */
  [data-decorative-motion],
  .mb-confetti,
  .mb-coinburst,
  .mb-sea-swell { display: none !important; }
}

/* -----------------------------------------------------------------------------
   7. FORCED COLORS / HIGH CONTRAST
   -------------------------------------------------------------------------- */
@media (forced-colors: active) {
  :where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 3px solid CanvasText;
    outline-offset: 2px;
    box-shadow: none;
  }
  .u-surface,
  .u-parchment,
  .u-wood,
  .skeleton { border: 1px solid CanvasText; }
  .u-grad-text { color: CanvasText; background-image: none; }
  .u-rope-rule,
  .u-brass-rule { background: CanvasText; forced-color-adjust: none; }
}

/* -----------------------------------------------------------------------------
   8. PRINT (admin exports)
   -------------------------------------------------------------------------- */
@media print {
  body { background: #fff; color: #000; background-image: none; }
  .skip-link,
  .mb-confetti,
  .mb-coinburst { display: none; }
  a::after { content: " (" attr(href) ")"; font-size: 0.85em; }
}
