/* Stoa Games — component layer (`sg-*`), built on the Stoa design tokens.
 *
 * Foundation: ../tokens/*.css (`--sg-*` custom properties).
 * This file is the Stoa Games design system: atoms → molecules → organisms.
 * Accessibility-first for the older, big-screen personas (Returning Renée,
 * Suburban Susan): comfortable base size, large targets, AA contrast,
 * visible focus, reduced-motion support. Throwaway prototype CSS. */

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

:root {
  /* A slightly larger comfort base than 16px for the older audience. */
  --sg-body-size: 1.0625rem;     /* 17px */
  --sg-tap-min: 2.75rem;         /* 44px minimum interactive target */
}

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

body {
  margin: 0;
  background: var(--sg-bg-base);
  color: var(--sg-text-primary);
  font-family: var(--sg-font-sans);
  font-size: var(--sg-body-size);
  line-height: var(--sg-leading-normal);
  -webkit-font-smoothing: antialiased;
}

:where(a) { color: var(--sg-brand); }

:where(button, [role="button"], a, input, select, textarea):focus-visible {
  outline: 3px solid var(--sg-brand);
  outline-offset: 2px;
  border-radius: var(--sg-radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* Visually-hidden but screen-reader-available — for a11y labels like "Locked". */
.sg-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ── ATOMS ────────────────────────────────────────────────────────────── */

/* Display / heading helpers (Clash Display for headings, Inter for body). */
.sg-display { font-family: var(--sg-font-display); font-weight: var(--sg-font-semibold); letter-spacing: var(--sg-tracking-tight); line-height: var(--sg-leading-tight); }
.sg-h1 { font: var(--sg-font-semibold) var(--sg-text-4xl)/1.1 var(--sg-font-display); letter-spacing: var(--sg-tracking-tight); margin: 0; }
.sg-h2 { font: var(--sg-font-semibold) var(--sg-text-2xl)/1.2 var(--sg-font-display); margin: 0; }
.sg-h3 { font: var(--sg-font-medium) var(--sg-text-xl)/1.25 var(--sg-font-display); margin: 0; }
.sg-body { font-size: var(--sg-text-base); color: var(--sg-text-secondary); }
.sg-muted { color: var(--sg-text-muted); }
.sg-overline { font-size: var(--sg-text-xs); letter-spacing: var(--sg-tracking-widest); text-transform: uppercase; color: var(--sg-text-muted); font-weight: var(--sg-font-semibold); }

/* Button */
.sg-btn {
  --_bg: var(--sg-bg-elevated);
  --_fg: var(--sg-text-primary);
  --_bd: var(--sg-border-medium);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sg-space-2);
  min-height: var(--sg-tap-min);
  padding: var(--sg-space-3) var(--sg-space-5);
  font: var(--sg-font-semibold) var(--sg-text-base)/1 var(--sg-font-sans);
  color: var(--_fg);
  background: var(--_bg);
  border: 1px solid var(--_bd);
  border-radius: var(--sg-radius-lg);
  text-decoration: none;              /* anchors styled as buttons */
  cursor: pointer;
  transition: filter var(--sg-duration-base) var(--sg-ease-default),
              transform var(--sg-duration-fast) var(--sg-ease-default);
}
.sg-btn:hover { filter: brightness(1.08); }
.sg-btn:active { transform: translateY(1px); }
.sg-btn--primary { --_bg: var(--sg-brand); --_fg: var(--sg-text-on-brand); --_bd: transparent; box-shadow: var(--sg-glow-brand); }
.sg-btn--secondary { --_bg: transparent; --_fg: var(--sg-text-primary); --_bd: var(--sg-border-strong); }
.sg-btn--ghost { --_bg: transparent; --_fg: var(--sg-text-secondary); --_bd: transparent; box-shadow: none; }
.sg-btn--danger { --_bg: var(--sg-danger-strong); --_fg: #fff; --_bd: transparent; }  /* -strong: white ink AA (#3) */
.sg-btn--sm { min-height: var(--sg-tap-min); padding: var(--sg-space-2) var(--sg-space-3); font-size: var(--sg-text-sm); }
.sg-btn--lg { min-height: 3.25rem; padding: var(--sg-space-4) var(--sg-space-8); font-size: var(--sg-text-lg); }
.sg-btn--block { width: 100%; }
.sg-btn--icon { padding: var(--sg-space-3); aspect-ratio: 1; }
.sg-btn[disabled], .sg-btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; filter: none; }
.sg-btn--loading { color: transparent; position: relative; pointer-events: none; }
.sg-btn--loading::after {
  content: ""; position: absolute; width: 1.1em; height: 1.1em;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
  color: var(--_fg, #fff); animation: sg-spin 0.7s linear infinite;
}

/* Badge / tag */
.sg-badge {
  display: inline-flex; align-items: center; gap: var(--sg-space-1);
  padding: 0.2em 0.6em; border-radius: var(--sg-radius-full);
  font-size: var(--sg-text-xs); font-weight: var(--sg-font-semibold);
  letter-spacing: var(--sg-tracking-wide);
  background: var(--sg-brand-grey-dim); color: var(--sg-text-secondary);
}
.sg-badge--brand { background: var(--sg-brand); color: var(--sg-text-on-brand); }
/* Semantic badges = semantic text on the loud -dim tint. success/warning clear AA at their
 * plain value in both themes (dark bright, light darkened). danger/info are darker hues whose
 * plain value only clears ~4:1 on the DARK tint, so in dark they take the brighter -light
 * variant; light theme overrides back to the darkened plain value (AA on the ivory tint). (#3) */
.sg-badge--success { background: var(--sg-success-dim); color: var(--sg-success); }
.sg-badge--warning { background: var(--sg-warning-dim); color: var(--sg-warning); }
.sg-badge--danger { background: var(--sg-danger-dim); color: var(--sg-danger-light); }
.sg-badge--info { background: var(--sg-info-dim); color: var(--sg-info-light); }
[data-theme="light"] .sg-badge--danger { color: var(--sg-danger); }
[data-theme="light"] .sg-badge--info { color: var(--sg-info); }
.sg-badge--outline { background: transparent; box-shadow: inset 0 0 0 1px var(--sg-border-strong); }

/* Inputs */
.sg-input, .sg-select, .sg-textarea {
  width: 100%; min-height: var(--sg-tap-min);
  padding: var(--sg-space-3) var(--sg-space-4);
  font: var(--sg-font-normal) var(--sg-text-base)/1.4 var(--sg-font-sans);
  color: var(--sg-text-primary);
  background: var(--sg-bg-surface);
  border: 1px solid var(--sg-border-medium);
  border-radius: var(--sg-radius-md);
}
.sg-input::placeholder, .sg-textarea::placeholder { color: var(--sg-text-muted); }
.sg-input:focus, .sg-select:focus, .sg-textarea:focus { border-color: var(--sg-brand); }
.sg-textarea { min-height: 6rem; resize: vertical; }
.sg-input--error { border-color: var(--sg-danger); }

/* Toggle / checkbox (CSS-only visual) */
.sg-switch { position: relative; display: inline-block; width: 3.25rem; height: 1.875rem; }
.sg-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.sg-switch span {
  position: absolute; inset: 0; border-radius: var(--sg-radius-full);
  background: var(--sg-border-strong); transition: background var(--sg-duration-base) var(--sg-ease-default);
}
.sg-switch span::before {
  content: ""; position: absolute; top: 0.1875rem; left: 0.1875rem; width: 1.5rem; height: 1.5rem;
  background: #fff; border-radius: 50%; transition: transform var(--sg-duration-base) var(--sg-ease-spring);
}
.sg-switch input:checked + span { background: var(--sg-brand); }
.sg-switch input:checked + span::before { transform: translateX(1.375rem); }

/* Brand coin (the Stoa / Zeno medallion). Token-tinted mask (#4): ONE element,
 * colored by --sg-coin-ink, shaped by --sg-coin-mask. The mark's colorway is a
 * token, never a filename — the old "pick a black/white/jade SVG" approach let
 * three surfaces drift (styleguide black, app jade, site black) in light theme.
 *
 * Two weight masks, keyed by theme, preserve the shipped optical correction: the
 * dark mark is deliberately thinned (feMorphology erode, ~41% less ink) because
 * a light mark blooms on charcoal; the light mark keeps full weight.
 *   dark  → white ink (#FFFFFF, ~18:1 on bg-base / ~15:1 on bg-chrome ✓) · thin mask
 *   light → jade  ink (--sg-brand #14654E, 6.6:1 on bg-base=bg-chrome ✓)   · regular mask
 * Non-text UI, so the bar is 3:1; both clear it comfortably. A consumer retints
 * with one declaration: `--sg-coin-ink: <color>`.
 *
 * Fallback: if mask-image is unsupported (all current targets support it with the
 * -webkit- prefix), the element degrades to a solid --sg-coin-ink square — visible,
 * not invisible. */
:root {
  --sg-coin-ink: #FFFFFF;                                   /* dark: white mark */
  --sg-coin-mask: url("../assets/stoa-coin-mask-thin.svg"); /* dark: thinned weight */
}
[data-theme="light"] {
  --sg-coin-ink: var(--sg-brand);                           /* light: jade mark */
  --sg-coin-mask: url("../assets/stoa-coin-mask.svg");      /* light: regular weight */
}
.sg-coin { display: block; width: 2.5rem; height: 2.5rem; }
/* The token-tinted mask coin — any non-<img> element (span / i / div). */
.sg-coin:not(img) {
  background-color: var(--sg-coin-ink);
  -webkit-mask: var(--sg-coin-mask) center / contain no-repeat;
          mask: var(--sg-coin-mask) center / contain no-repeat;
}
.sg-lockup { display: inline-flex; align-items: center; gap: var(--sg-space-3); }
/* Logo sizes — favicon → app-bar → header → hero. */
.sg-coin--sm { width: 1.5rem; height: 1.5rem; }    /* 24 — favicon / inline */
.sg-coin--md { width: 2.5rem; height: 2.5rem; }    /* 40 — app bar / lockup */
.sg-coin--lg { width: 4rem; height: 4rem; }        /* 64 — section header */
.sg-coin--xl { width: 6rem; height: 6rem; }        /* 96 — hero / splash */

/* Avatar */
/* Avatar carries initials — SOLID brand fill, not the gradient: --sg-text-on-brand clears AA
 * on solid --sg-brand (5.35:1 dark / 7.0:1 light) but fails at the gradient's pale end (#3). */
.sg-avatar { display: inline-flex; align-items: center; justify-content: center; width: 2.5rem; height: 2.5rem; border-radius: 50%; background: var(--sg-brand); color: var(--sg-text-on-brand); font-weight: var(--sg-font-semibold); font-family: var(--sg-font-display); }
.sg-avatar--sm { width: 2rem; height: 2rem; font-size: var(--sg-text-sm); }
.sg-avatar--lg { width: 3.5rem; height: 3.5rem; font-size: var(--sg-text-xl); }

/* Spinner */
.sg-spinner { display: inline-block; width: 1.5rem; height: 1.5rem; border: 3px solid var(--sg-border-medium); border-top-color: var(--sg-brand); border-radius: 50%; animation: sg-spin 0.8s linear infinite; }

/* Divider */
.sg-divider { height: 1px; background: var(--sg-border-subtle); border: 0; margin: var(--sg-space-6) 0; }

/* ── MOLECULES ────────────────────────────────────────────────────────── */

/* Form field (label + control + hint/error) */
.sg-field { display: grid; gap: var(--sg-space-2); }
.sg-label { font-size: var(--sg-text-sm); font-weight: var(--sg-font-semibold); color: var(--sg-text-secondary); letter-spacing: var(--sg-tracking-wide); }
.sg-help { font-size: var(--sg-text-sm); color: var(--sg-text-muted); }
.sg-help--error { color: var(--sg-danger); }

/* Card */
.sg-card {
  background: var(--sg-bg-surface);
  border: 1px solid var(--sg-border-subtle);
  border-radius: var(--sg-radius-xl);
  padding: var(--sg-space-6);
}
.sg-card--elevated { box-shadow: var(--sg-shadow-lg); border-color: transparent; }
.sg-card--glass { background: var(--sg-glass-bg); border-color: var(--sg-glass-border); -webkit-backdrop-filter: var(--sg-glass-blur) var(--sg-glass-saturate); backdrop-filter: var(--sg-glass-blur) var(--sg-glass-saturate); }
/* Interactive lift — for cards that are links/tappable. Ported from EPM Labs DS. */
.sg-card--hover { transition: border-color var(--sg-duration-base) var(--sg-ease-default), box-shadow var(--sg-duration-base) var(--sg-ease-default), transform var(--sg-duration-base) var(--sg-ease-default); }
.sg-card--hover:hover { border-color: var(--sg-brand); box-shadow: var(--sg-shadow-md); transform: translateY(-2px); }
/* Brand-gradient border card (premium). Ported from EPM Labs `card-gradient`. */
.sg-card--gradient { border: 2px solid transparent; background-image: linear-gradient(var(--sg-bg-surface), var(--sg-bg-surface)), var(--sg-brand-gradient); background-origin: border-box; background-clip: padding-box, border-box; transition: box-shadow var(--sg-duration-base) var(--sg-ease-default); }
.sg-card--gradient:hover { box-shadow: var(--sg-glow-brand); }

/* ── DECORATIVE EFFECTS (ported faithfully from the EPM Labs DS) ─────────
   sg-hero-grid     — masked dot grid for hero / full-bleed sections.
   sg-noise-overlay — fixed, whisper-subtle grain film; one per page, in <body>.
   sg-glow          — brand box-shadow halo for a featured card. */

/* Hero Grid — EPM Labs `hero-grid`. The grid renders in ::before so mask-image
   clips only the pattern, not the section's children. A top-anchored linear
   fade dissolves the dots into the page canvas below. Light theme darkens the
   dots so they stay visible on a pale surface. */
.sg-hero-grid { position: relative; }
.sg-hero-grid::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(rgba(229, 231, 235, 0.10) 1px, transparent 0);
  background-size: 20px 20px;
  -webkit-mask-image: linear-gradient(to bottom, #000 50%, transparent 95%);
  mask-image: linear-gradient(to bottom, #000 50%, transparent 95%);
}
[data-theme="light"] .sg-hero-grid::before { background-image: radial-gradient(rgba(28, 25, 23, 0.15) 1px, transparent 0); }
/* Keep the host's own content above the grid. */
.sg-hero-grid > * { position: relative; z-index: 1; }

/* Noise Grain — EPM Labs `noise-overlay`. A fixed, full-viewport grain film
   applied at z-index 9999 (pointer-events:none). Adds tactile depth to flat
   surfaces; opacity is intentionally tiny (0.034). Drop one
   `<div class="sg-noise-overlay">` in <body>; the .webp texture swaps per theme.
   The url() is relative to THIS file (css/), so it resolves the same way in
   every consumer that mounts the design system as a submodule. */
.sg-noise-overlay {
  --sg-noise-size: 200px 200px;
  --sg-noise-opacity: 0.034;
  position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  background-image: url("../assets/background-noise.webp");
  background-size: var(--sg-noise-size);
  opacity: var(--sg-noise-opacity);
}
[data-theme="light"] .sg-noise-overlay {
  --sg-noise-size: 256px 256px;
  background-image: url("../assets/light-background-noise.webp");
}

/* Glow — brand halo for a featured / premium card. */
.sg-glow { box-shadow: var(--sg-glow-brand); }

/* List tile (settings row / menu item) */
.sg-tile {
  display: flex; align-items: center; gap: var(--sg-space-4);
  min-height: var(--sg-tap-min); padding: var(--sg-space-3) var(--sg-space-4);
  border-radius: var(--sg-radius-lg); background: var(--sg-bg-surface);
  border: 1px solid var(--sg-border-subtle);
}
.sg-tile__icon { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: var(--sg-radius-md); background: var(--sg-brand-grey-dim); color: var(--sg-brand); font-size: 1.25rem; flex: none; }
.sg-tile__text { flex: 1; min-width: 0; display: grid; gap: 0.1rem; }
.sg-tile__title { font-weight: var(--sg-font-medium); }
.sg-tile__sub { font-size: var(--sg-text-sm); color: var(--sg-text-muted); }

/* Stat */
.sg-stat { display: grid; gap: 0.15rem; }
.sg-stat__num { font: var(--sg-font-bold) var(--sg-text-3xl)/1 var(--sg-font-display); color: var(--sg-brand); }
.sg-stat__label { font-size: var(--sg-text-sm); color: var(--sg-text-muted); }

/* Segmented control */
.sg-segmented { display: inline-flex; padding: 0.25rem; gap: 0.25rem; background: var(--sg-bg-elevated); border-radius: var(--sg-radius-lg); }
.sg-segmented button { min-height: var(--sg-tap-min); padding: 0 var(--sg-space-4); border: 0; border-radius: var(--sg-radius-md); background: transparent; color: var(--sg-text-secondary); font-weight: var(--sg-font-medium); cursor: pointer; }
.sg-segmented button[aria-pressed="true"] { background: var(--sg-bg-surface); color: var(--sg-text-primary); box-shadow: var(--sg-shadow-sm); }

/* Progress bar */
.sg-progress { height: 0.625rem; border-radius: var(--sg-radius-full); background: var(--sg-bg-elevated); overflow: hidden; }
.sg-progress__fill { height: 100%; border-radius: inherit; background: var(--sg-brand-gradient); }

/* Streak chip */
.sg-streak { display: inline-flex; align-items: center; gap: var(--sg-space-2); padding: var(--sg-space-2) var(--sg-space-3); border-radius: var(--sg-radius-full); background: var(--sg-brand-dim); color: var(--sg-brand); font-weight: var(--sg-font-semibold); }

/* Callout (Stoa "takeaway" / why-it-matters) */
.sg-callout { display: grid; gap: var(--sg-space-2); padding: var(--sg-space-4) var(--sg-space-5); border-radius: var(--sg-radius-lg); background: var(--sg-brand-gradient-subtle); border-left: 3px solid var(--sg-brand); }
.sg-callout__label { font-size: var(--sg-text-xs); text-transform: uppercase; letter-spacing: var(--sg-tracking-widest); color: var(--sg-brand); font-weight: var(--sg-font-bold); }

/* Hero — the centered focus-flow header (icon circle + overline + title + sub).
   Promoted 2026-07-10 from cs-/rv-/nf-hero (card-season, review, notifications). */
.sg-hero { text-align: center; display: grid; gap: var(--sg-space-3); justify-items: center; }
.sg-hero__icon { width: 4rem; height: 4rem; border-radius: 50%; background: var(--sg-brand-gradient-subtle); color: var(--sg-brand); display: grid; place-items: center; }
.sg-hero__icon .material-symbols-rounded { font-size: 2rem; }
.sg-hero__title { margin: 0; font: var(--sg-font-bold) var(--sg-text-3xl)/1.05 var(--sg-font-display); }
.sg-hero__sub { margin: 0; color: var(--sg-text-secondary); max-width: 26rem; }

/* Feature list — icon-led value list (icon + bold line + subtext).
   Promoted 2026-07-10 from cs-list / nf-values / ob-list. */
.sg-featurelist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sg-space-3); }
.sg-featurelist li { display: flex; gap: var(--sg-space-3); align-items: flex-start; }
.sg-featurelist > li > .material-symbols-rounded { color: var(--sg-brand); flex: none; }
.sg-featurelist b { display: block; }
.sg-featurelist span span { font-size: var(--sg-text-sm); color: var(--sg-text-muted); }

/* ── ORGANISMS ────────────────────────────────────────────────────────── */

/* Top app bar */
.sg-topbar { display: flex; align-items: center; justify-content: space-between; gap: var(--sg-space-4); padding: var(--sg-space-3) var(--sg-space-5); background: var(--sg-bg-chrome); border-bottom: 1px solid var(--sg-border-subtle); border-radius: var(--sg-radius-lg) var(--sg-radius-lg) 0 0; }
.sg-topbar__title { font: var(--sg-font-semibold) var(--sg-text-xl)/1 var(--sg-font-display); }

/* App bar — back + centered title (the detail-screen chrome, à la Stoa Poker).
 * Sits inside .sg-topbar. A 3-column grid keeps the title optically centered
 * regardless of the leading back button / trailing action width. The trailing
 * .sg-appbar__action slot is optional (leave an empty span to hold the column). */
.sg-appbar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--sg-space-2); width: 100%; }
.sg-appbar__back { justify-self: start; display: inline-grid; place-items: center; width: var(--sg-tap-min); height: var(--sg-tap-min); border-radius: var(--sg-radius-md); color: var(--sg-text-primary); text-decoration: none; }
.sg-appbar__back:hover { background: var(--sg-bg-elevated); }
.sg-appbar__back .material-symbols-rounded { font-size: 1.5rem; }
.sg-appbar__title { justify-self: center; text-align: center; font: var(--sg-font-semibold) var(--sg-text-xl)/1 var(--sg-font-display); }
.sg-appbar__action { justify-self: end; }
/* Trailing icon action (e.g. the settings gear) in .sg-appbar__action. */
.sg-appbar__gear { display: inline-grid; place-items: center; width: var(--sg-tap-min); height: var(--sg-tap-min); border-radius: var(--sg-radius-md); color: var(--sg-text-primary); text-decoration: none; }
.sg-appbar__gear:hover { background: var(--sg-bg-elevated); }
.sg-appbar__gear .material-symbols-rounded { font-size: 1.4rem; }

/* Game switcher — the per-game top-bar control shared by the Skills + Stats tabs.
 * A button in sg-appbar's centered title slot that swaps the active game, plus a
 * dropdown menu + scrim. Pair with .sg-appbar__gear in the trailing action slot. */
.sg-gameswitch { background: none; border: 0; cursor: pointer; color: inherit; font: var(--sg-font-semibold) var(--sg-text-xl)/1 var(--sg-font-display); display: inline-flex; align-items: center; gap: 0.1rem; padding: 0.25rem 0.4rem; border-radius: var(--sg-radius-md); }
.sg-gameswitch:hover { background: var(--sg-bg-elevated); }
.sg-gameswitch .material-symbols-rounded { font-size: 1.35rem; color: var(--sg-text-muted); }
.sg-gamemenu-scrim { position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 40; }
.sg-gamemenu-scrim[hidden] { display: none; }
.sg-gamemenu { position: fixed; top: 3.75rem; left: 50%; transform: translateX(-50%); z-index: 50; width: min(18rem, calc(100vw - 2rem)); background: var(--sg-bg-elevated); border: 1px solid var(--sg-border-medium); border-radius: var(--sg-radius-lg); box-shadow: var(--sg-shadow-xl); padding: var(--sg-space-2); display: grid; gap: 0.1rem; }
.sg-gamemenu[hidden] { display: none; }
.sg-gamemenu__item { display: flex; align-items: center; gap: var(--sg-space-2); width: 100%; text-align: left; background: none; border: 0; cursor: pointer; color: inherit; font: inherit; font-size: var(--sg-text-base); padding: var(--sg-space-3); border-radius: var(--sg-radius-md); }
.sg-gamemenu__item:hover { background: var(--sg-bg-surface); }
.sg-gamemenu__check { color: var(--sg-brand); visibility: hidden; }
.sg-gamemenu__item[aria-current="true"] .sg-gamemenu__check { visibility: visible; }

/* Game-picker card (the multi-game hub) */
.sg-gamecard { display: grid; gap: var(--sg-space-3); padding: var(--sg-space-5); border-radius: var(--sg-radius-xl); background: var(--sg-bg-surface); border: 1px solid var(--sg-border-subtle); position: relative; overflow: hidden; }
.sg-gamecard__title { font: var(--sg-font-semibold) var(--sg-text-xl)/1.1 var(--sg-font-display); }
.sg-gamecard__meta { display: flex; align-items: center; justify-content: space-between; gap: var(--sg-space-2); }
.sg-gamecard--locked { opacity: 0.85; }

/* Lesson card */
.sg-lesson { display: flex; align-items: center; gap: var(--sg-space-4); padding: var(--sg-space-4); border-radius: var(--sg-radius-lg); background: var(--sg-bg-surface); border: 1px solid var(--sg-border-subtle); }
.sg-lesson__num { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; flex: none; border-radius: 50%; background: var(--sg-brand-grey-dim); color: var(--sg-brand); font: var(--sg-font-bold) var(--sg-text-lg)/1 var(--sg-font-display); }
.sg-lesson__num--done { background: var(--sg-success-dim); color: var(--sg-success); }
.sg-lesson__body { flex: 1; min-width: 0; display: grid; gap: 0.25rem; }
.sg-lesson__title { font-weight: var(--sg-font-semibold); }
.sg-lesson__obj { font-size: var(--sg-text-sm); color: var(--sg-text-muted); }

/* Drill prompt (the teaching core — prompt, choices, hint, "why") */
.sg-drill { display: grid; gap: var(--sg-space-4); padding: var(--sg-space-6); border-radius: var(--sg-radius-xl); background: var(--sg-bg-surface); border: 1px solid var(--sg-border-subtle); }
.sg-drill__q { font: var(--sg-font-medium) var(--sg-text-xl)/1.3 var(--sg-font-display); }
.sg-choices { display: grid; gap: var(--sg-space-3); }
.sg-choice { display: flex; align-items: center; gap: var(--sg-space-3); min-height: var(--sg-tap-min); padding: var(--sg-space-3) var(--sg-space-4); border-radius: var(--sg-radius-lg); background: var(--sg-bg-elevated); border: 2px solid transparent; cursor: pointer; text-align: left; font-size: var(--sg-text-base); color: var(--sg-text-primary); }
.sg-choice--correct { border-color: var(--sg-success); background: var(--sg-success-dim); }
.sg-choice--wrong { border-color: var(--sg-danger); background: var(--sg-danger-dim); }

/* Paywall tier */
.sg-tier { display: grid; gap: var(--sg-space-4); padding: var(--sg-space-6); border-radius: var(--sg-radius-xl); background: var(--sg-bg-surface); border: 1px solid var(--sg-border-subtle); }
.sg-tier--featured { border-color: var(--sg-brand); box-shadow: var(--sg-glow-brand); }
.sg-tier__price { font: var(--sg-font-bold) var(--sg-text-4xl)/1 var(--sg-font-display); }
.sg-tier__price small { font-size: var(--sg-text-base); color: var(--sg-text-muted); font-weight: var(--sg-font-normal); }
.sg-tier__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sg-space-2); color: var(--sg-text-secondary); }
.sg-tier__list li::before { content: "✓ "; color: var(--sg-success); font-weight: var(--sg-font-bold); }

/* Modal / bottom sheet */
.sg-sheet { max-width: 28rem; border-radius: var(--sg-radius-2xl); background: var(--sg-bg-elevated); border: 1px solid var(--sg-border-subtle); box-shadow: var(--sg-shadow-xl); padding: var(--sg-space-6); display: grid; gap: var(--sg-space-4); }
.sg-sheet__grip { width: 2.5rem; height: 0.25rem; border-radius: var(--sg-radius-full); background: var(--sg-border-strong); justify-self: center; }

/* Anchored bottom-sheet dialog + scrim (JS toggles the `hidden` attribute).
   Promoted 2026-07-10 from sub-/ac- dialog+scrim (subscription, account, upgrade).
   The [hidden] rules are baked in so display:grid can't override the attribute. */
.sg-scrim { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 40; }
.sg-scrim[hidden] { display: none; }
.sg-modal { position: fixed; left: 50%; bottom: 0; transform: translateX(-50%); z-index: 50; width: min(26rem, 100%); background: var(--sg-bg-elevated); border: 1px solid var(--sg-border-medium); border-radius: var(--sg-radius-2xl) var(--sg-radius-2xl) 0 0; padding: var(--sg-space-6); display: grid; gap: var(--sg-space-4); box-shadow: var(--sg-shadow-xl); }
.sg-modal[hidden] { display: none; }
.sg-modal__icon { font-size: 2.5rem; color: var(--sg-brand); justify-self: center; }

/* Tile strip — IP-CLEAN fictional tiles ONLY (never the NMJL card). */
.sg-tiles { display: flex; gap: var(--sg-space-2); flex-wrap: wrap; }
.sg-tile-face { width: 3rem; height: 4rem; display: grid; place-items: center; border-radius: var(--sg-radius-md); background: #FBFBF7; color: #1A1B1D; border: 1px solid var(--sg-border-strong); box-shadow: var(--sg-shadow-sm); font: var(--sg-font-bold) var(--sg-text-xl)/1 var(--sg-font-display); }
.sg-tile-face--accent { color: var(--sg-brand-deep); }
.sg-tile-face--green { color: #15803D; }

/* Empty state */
.sg-empty { display: grid; gap: var(--sg-space-3); place-items: center; text-align: center; padding: var(--sg-space-12) var(--sg-space-6); color: var(--sg-text-muted); }
.sg-empty__icon { font-size: 2.75rem; opacity: 0.7; }

/* ── GAME PIECES ──────────────────────────────────────────────────────── */
/* Generic, IP-clean playing pieces. No NMJL card or licensed-card data ever. */

/* Playing card (atom) — clean teaching style: one corner rank + one center
 * suit pip. Contents scale with the card (container query units) so the suit
 * never repeats or collides at small sizes. */
.sg-playcard {
  position: relative; flex: none;
  width: 4rem; height: 5.6rem;
  background: #FBFBF7; color: #1A1B1D;
  border: 1px solid var(--sg-border-strong);
  border-radius: var(--sg-radius-md);
  box-shadow: var(--sg-shadow-sm);
  font-family: var(--sg-font-display);
  container-type: size;
}
.sg-playcard--red { color: #C1121F; }                 /* hearts / diamonds */
.sg-playcard__rank { position: absolute; top: 7cqh; left: 9cqw; font-size: 30cqmin; font-weight: var(--sg-font-bold); line-height: 1; }
.sg-playcard__suit { position: absolute; inset: 0; display: grid; place-items: center; font-size: 58cqmin; line-height: 1; }
.sg-playcard--sm { width: 3rem; height: 4.2rem; }
.sg-playcard--lg { width: 5rem; height: 7rem; }
.sg-playcard--back { color: #fff; border-color: rgba(255,255,255,0.6); background:
  repeating-linear-gradient(45deg, var(--sg-brand-deep) 0 7px, var(--sg-brand) 7px 14px); }
.sg-playcard--selected { outline: 3px solid var(--sg-brand); outline-offset: 2px; transform: translateY(-0.4rem); }
.sg-playcard--dim { opacity: 0.45; }

/* Mahjong tile (atom) — ivory face with a thick base edge. */
.sg-mtile {
  position: relative; flex: none;
  width: 3rem; height: 4rem;
  display: grid; place-items: center;
  background: #FBFBF4; color: #1A1B1D;
  border: 1px solid #D8D6C8; border-bottom: 4px solid #CFC9B0;
  border-radius: var(--sg-radius-md);
  box-shadow: var(--sg-shadow-sm);
  font-family: var(--sg-font-display);
  container-type: size;                 /* face contents scale with the tile */
}
.sg-mtile__face { display: grid; place-items: center; gap: 3cqh; line-height: 1; padding: 0 8cqw; }
.sg-mtile__sym { font-size: 50cqmin; font-weight: var(--sg-font-bold); line-height: 1; }
.sg-mtile__sub { font-size: 30cqmin; font-weight: var(--sg-font-bold); line-height: 1; }   /* e.g. 萬 under the numeral */
.sg-mtile__cap { font-size: 17cqmin; color: var(--sg-text-muted); letter-spacing: -0.02em; white-space: nowrap; }
.sg-mtile__frame { width: 46cqw; height: 56cqh; border: 3px solid currentColor; border-radius: 3px; }  /* white dragon = blue frame */
.sg-mtile--char { color: #1A1B1D; }                   /* characters (萬) — ink */
.sg-mtile--dot  { color: #15598C; }                   /* dots (筒) — blue */
.sg-mtile--bam  { color: #15803D; }                   /* bamboo (索) — green */
.sg-mtile--red  { color: #C1121F; }                   /* red dragon / red five */
.sg-mtile--green{ color: #15803D; }                   /* green dragon */
.sg-mtile--back { background: linear-gradient(135deg, #1E7A52, #15603F); border-color: #0E4A30; border-bottom-color: #0E4A30; }
.sg-mtile--selected { outline: 3px solid var(--sg-brand); outline-offset: 2px; transform: translateY(-0.4rem); }
.sg-mtile--discard { opacity: 0.6; transform: scale(0.9); }
.sg-mtile--joker .sg-mtile__sym { color: var(--sg-brand-deep); }
/* dot / bamboo pip renderers — scale with the tile too */
.sg-pips { display: grid; gap: 4cqmin; }
.sg-pips--row3 { grid-template-columns: repeat(3, auto); }
.sg-dot { width: 17cqmin; height: 17cqmin; border-radius: 50%; background: currentColor; }
.sg-bams { display: flex; gap: 5cqmin; align-items: flex-end; }
.sg-bam { width: 8cqmin; height: 42cqmin; border-radius: 2px; background: currentColor; }

/* Hand / rack (molecule) — overlapping fan for cards, spaced row for tiles. */
.sg-fan { display: flex; padding-left: 1.25rem; }
.sg-fan > * { margin-left: -1.25rem; transition: transform var(--sg-duration-fast) var(--sg-ease-default); }
.sg-fan > *:hover { transform: translateY(-0.5rem); }
.sg-rack { display: flex; gap: 0.3rem; flex-wrap: wrap; }
/* Meld / exposure (molecule) — a claimed set, slightly inset + labeled. */
.sg-meld { display: inline-flex; gap: 0.2rem; padding: var(--sg-space-2); border-radius: var(--sg-radius-md); background: var(--sg-bg-elevated); }

/* ── LAYOUT / RESPONSIVE ──────────────────────────────────────────────── */
/* Container-query based (not viewport) so a component adapts to the space it's
 * given — phone-narrow vs tablet-wide — and the styleguide can show both at once.
 * Put `.sg-cq` on a sizing ancestor (a flow's root, or a device frame's screen);
 * the layouts below query that ancestor. Tablet breakpoint = 48rem (768px). */
.sg-cq { container-type: inline-size; }

/* Centered, readable content column. */
.sg-container { width: 100%; max-width: 44rem; margin-inline: auto; padding-inline: var(--sg-space-4); }
.sg-container--wide { max-width: 62rem; }

/* Responsive card grid: intrinsically fits as many columns as the space allows. */
.sg-card-grid { display: grid; gap: var(--sg-space-4); grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }

/* Master-detail: stacked on phone, two-pane on tablet. */
.sg-twopane { display: grid; gap: var(--sg-space-5); }
@container (min-width: 56rem) { .sg-twopane { grid-template-columns: 21rem 1fr; align-items: start; } }

/* App shell: top bar + scrolling main + bottom nav — at ALL widths (phone and
 * tablet/iPad). The nav stays a bottom bar; only the main content adapts to width. */
.sg-shell { display: grid; height: 100%; min-height: 100%; grid-template: auto 1fr auto / 1fr; background: var(--sg-bg-base); }
.sg-shell__main { overflow-y: auto; container-type: inline-size; }   /* content inside queries the main width */

/* Material Symbols (Rounded) — load the font per page via Google Fonts:
 * https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,400,0..1,0 */
.material-symbols-rounded { font-family: 'Material Symbols Rounded'; font-weight: normal; font-style: normal; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-smoothing: antialiased; font-variation-settings: 'opsz' 24, 'wght' 400, 'FILL' 0, 'GRAD' 0; }

/* Bottom nav bar — at all widths. Mirrors Stoa Poker's 5-tab nav: the active
 * item is a filled brand pill (SOLID, not gradient — its label + icon are
 * text-on-brand and must clear AA across the whole fill; #3). On wider screens
 * the bar centers its items so they don't spread edge-to-edge. */
.sg-rail { display: flex; flex-direction: row; justify-content: center; gap: var(--sg-space-2); background: var(--sg-bg-chrome); border-top: 1px solid var(--sg-border-subtle); padding: var(--sg-space-2); }
.sg-rail__item { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; min-width: 4rem; min-height: 2.75rem; padding: var(--sg-space-2); border-radius: var(--sg-radius-md); color: var(--sg-text-muted); text-decoration: none; font-size: var(--sg-text-sm); font-weight: var(--sg-font-medium); }
.sg-rail__icon { font-size: 1.6rem; line-height: 1; }
.sg-rail__item[aria-current="page"] { background: var(--sg-brand); color: var(--sg-text-on-brand); }
.sg-rail__item[aria-current="page"] .material-symbols-rounded { font-variation-settings: 'opsz' 24, 'wght' 500, 'FILL' 1, 'GRAD' 0; }

/* ── SKILL MAP (organism) ─────────────────────────────────────────────── */
/* A tiered, progressive skill list (the teaching curriculum). The tier ramp is
 * brand-aligned and reads as increasing brand intensity: Foundation neutral
 * taupe → Core brand jade → Advanced most-saturated jade. Progress + active
 * states use the brand; mastery/progress badges reuse the semantic
 * success/warning tokens.
 *
 * Advanced is theme-split because "more intense" inverts by theme — the same
 * principle the brand token itself follows (jade deepens from #3E9E7F to
 * #14654E in light). Going deeper in DARK is not an option: --sg-brand-deep
 * (#0E4A39) is 1.72:1 on bg-base and the dot/border would vanish. Swatches are
 * non-text UI (dot + 4px border), so the bar is 3:1. */
:root {
  --sg-tier-foundation: var(--sg-brand-grey);   /* taupe #8C8474 — 4.73:1 on bg-base ✓ */
  --sg-tier-core: var(--sg-brand);       /* jade #3E9E7F — 5.35:1 ✓ */
  --sg-tier-advanced: var(--sg-brand-light); /* light jade #5FB89B — 7.36:1 ✓ */
}
[data-theme="light"] {
  /* foundation taupe #6B6458 — 5.51:1 on bg-base ✓ · core jade #14654E — 6.59:1 ✓ */
  --sg-tier-advanced: var(--sg-brand-deep); /* deep jade #0E4A39 — 9.62:1 ✓ */
}
.sg-skilltier { display: grid; gap: var(--sg-space-3); margin-bottom: var(--sg-space-8); }
.sg-skilltier__head { display: flex; align-items: center; gap: var(--sg-space-3); }
.sg-skilltier__dot { width: 0.8rem; height: 0.8rem; border-radius: 3px; background: var(--_tier); flex: none; }
.sg-skilltier__name { font: var(--sg-font-semibold) var(--sg-text-lg)/1 var(--sg-font-display); }
.sg-skilltier__list { display: grid; gap: var(--sg-space-3); }
/* Badge ink rides --sg-text-on-brand (near-black in dark, white in light) —
 * the token that exists for exactly this. Every tier × theme clears AA:
 * dark 4.73/5.35/7.36 · light 5.85/7.00/10.21. The old hardcodes did not: white
 * on dark taupe was 3.71:1, and near-black on light-jade core was 2.46:1. */
.sg-skilltier--foundation { --_tier: var(--sg-tier-foundation); --_tier-ink: var(--sg-text-on-brand); }
.sg-skilltier--core { --_tier: var(--sg-tier-core); --_tier-ink: var(--sg-text-on-brand); }
.sg-skilltier--advanced { --_tier: var(--sg-tier-advanced); --_tier-ink: var(--sg-text-on-brand); }

/* Row = [number badge] · [body]. State rides the TITLE line (top-right); the
 * objective and the progress meter run the FULL body width below it — a shorter,
 * scannable card. One layout at all widths (the map column is never wide: on
 * tablet it's 1fr beside a 20rem detail pane), so no responsive state variant. */
.sg-skill { display: flex; align-items: flex-start; gap: var(--sg-space-4); width: 100%; text-align: left; padding: var(--sg-space-4); border-radius: var(--sg-radius-lg); background: var(--sg-bg-surface); border: 1px solid var(--sg-border-subtle); border-left: 4px solid var(--_tier); color: inherit; text-decoration: none; cursor: pointer; font: inherit; transition: transform var(--sg-duration-fast) var(--sg-ease-default); }
.sg-skill:hover { transform: translateY(-2px); }
.sg-skill:focus-visible { outline: 3px solid var(--sg-brand); outline-offset: 2px; }
.sg-skill__badge { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; flex: none; border-radius: var(--sg-radius-md); background: var(--_tier); color: var(--_tier-ink); font: var(--sg-font-bold) var(--sg-text-lg)/1 var(--sg-font-display); }
.sg-skill__body { flex: 1; min-width: 0; display: grid; gap: 0.35rem; }
/* Title line: name + trailing state, TOP-aligned so a long name wraps *under* the state. */
.sg-skill__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sg-space-3); }
.sg-skill__name { flex: 1; min-width: 0; font-weight: var(--sg-font-semibold); }
/* Trailing state slot — holds a chip (Mastered), plain text (In progress / Not
 * started), or the lock. De-toned on purpose: in-progress is NOT warning-amber
 * (progress is positive, not a caution); the meter below carries the degree. */
.sg-skill__state { flex: none; display: inline-flex; align-items: center; gap: var(--sg-space-1); font-size: var(--sg-text-sm); color: var(--sg-text-muted); }
.sg-skill__state--active { color: var(--sg-text-secondary); font-weight: var(--sg-font-semibold); }
.sg-skill__obj { font-size: var(--sg-text-sm); color: var(--sg-text-muted); }
/* Progress meter — full body width; show ONLY while a skill is in progress
 * (a full bar on a mastered card is noise; the ✓ chip already says it). */
.sg-skill__meter { display: flex; align-items: center; gap: var(--sg-space-2); font-size: var(--sg-text-xs); color: var(--sg-text-muted); }
.sg-skill__bar { flex: 1; max-width: 22rem; height: 0.5rem; border-radius: var(--sg-radius-full); background: var(--sg-bg-elevated); overflow: hidden; }
.sg-skill__bar-fill { height: 100%; background: var(--sg-brand); border-radius: inherit; }  /* progress = brand jade */
.sg-skill__level { flex: none; }
.sg-skill__lock { color: var(--sg-text-muted); font-size: 1.25rem; }
.sg-skill--locked { opacity: 0.8; }
.sg-skill--locked .sg-skill__badge { background: var(--sg-brand-grey-dim); color: var(--sg-text-muted); }
