/* ─── StudyVET PWA — calm clinical UI ────────────────────────────────────
 *
 * Palette: slate-tinted teal primary on slate-mist neutrals. Reads as a
 * serious study tool — exam prep, not a consumer game. Ambient four-hue
 * mesh and gradient text fills retired in this pass; flat surfaces with
 * hairline slate borders and a single accent stripe carry the visual
 * tone instead.
 *
 * Token discipline: every color used in components reads through one of
 * the variables below. Swapping a token here propagates globally.
 */

:root {
  /* Ambient backdrop — kept for back-compat (legacy rules read --blob-N
     and --bg-0) but the four-hue mesh is retired in body::before/::after.
     The blob values are now neutral so any straggler reading them gets a
     calm slate tint instead of teal/violet/amber soup. */
  --bg-0:      #0b1220;
  --blob-1:    rgba(15, 23, 42, 0);
  --blob-2:    rgba(15, 23, 42, 0);
  --blob-3:    rgba(15, 23, 42, 0);
  --blob-4:    rgba(15, 23, 42, 0);

  /* Surfaces — flat by default, glass reserved for floating overlays
     (toasts, popovers, lightbox). Cards/heroes/stats sit on solid
     surfaces with hairline borders; reads calmer than translucent. */
  --surface:    rgba(15, 23, 42, 0.72);
  --surface-2:  rgba(30, 41, 59, 0.55);
  --border:     rgba(148, 163, 184, 0.18);
  --border-strong: rgba(148, 163, 184, 0.32);

  /* Glass surfaces — same shape as before for back-compat (.toast,
     .lightbox, .popover still read these). Lower blur + saturation so
     it reads as subtle frosting, not frosted-window. */
  --glass:               rgba(15, 23, 42, 0.72);
  --glass-strong:        rgba(15, 23, 42, 0.85);
  --glass-weak:          rgba(15, 23, 42, 0.50);
  --glass-border:        rgba(148, 163, 184, 0.18);
  --glass-border-strong: rgba(148, 163, 184, 0.30);
  --glass-hi:            rgba(255, 255, 255, 0.04);

  /* Text — slate-cool, dropped the bluish tint of the old palette. */
  --ink:       #f1f5f9;        /* slate-100 — true heading ink (dark mode) */
  --text:      #e2e8f0;        /* slate-200 — body */
  --text-dim:  #94a3b8;        /* slate-400 — secondary body, .muted */
  --muted:     #64748b;        /* slate-500 — captions, table-cell meta */

  /* Accents — slate-tinted clinical teal. Less candy than #14b8a6, more
     authority. --accent retired (was triple-duty amber); split into
     role-specific --warn (warnings only) and --active (active tab,
     streak, timer — uses primary). */
  --primary:        #0ea5a3;   /* clinical teal */
  --primary-dark:   #0f766e;   /* teal-700 hover */
  --primary-soft:   rgba(14, 165, 163, 0.18);
  --primary-50:     #ccfbf1;   /* teal-100 — chip backgrounds, soft fills */
  --active:         var(--primary);

  --accent-sky:     #0284c7;   /* sky-600 — secondary, charts, info */

  --good:           #059669;   /* emerald-600 (was #22c55e — too candy) */
  --bad:            #dc2626;   /* red-600 */
  --warn:           #d97706;   /* amber-600 — warnings only */

  /* Legacy --accent alias — kept so old rules don't break, but points at
     --warn now (was the role amber actually played). New code should
     use --warn or --active explicitly. */
  --accent:         var(--warn);

  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius:    14px;           /* was 18 — less candy, more clinical-card */
  --radius-lg: 20px;           /* hero/modal only */
  --radius-s:  var(--radius-sm);   /* legacy alias */

  --blur:     12px;            /* was 18 — subtler frosting */
  --blur-lg:  20px;            /* was 28 */
  --saturate: 120%;            /* was 160 */

  /* ── Type scale ───────────────────────────────────────────────────────
   *   xs   11.5px  pill labels, captions, table-cell metadata
   *   sm   13px    secondary body, footnotes, .muted prose
   *   base 15px    default body  (was 14 — bumped 1px for clinical readability)
   *   md   16px    interactive label / button text  (was 15)
   *   lg   18px    section headings, prominent body  (was 17)
   *   xl   24px    page titles (h2)  (was 22)
   *   2xl  32px    hero headlines (h1, big stat numerals)  (was 30)
   *   3xl  40px    landing-only display
   */
  --text-xs:   11.5px;
  --text-sm:   13px;
  --text-base: 15px;
  --text-md:   16px;
  --text-lg:   18px;
  --text-xl:   24px;
  --text-2xl:  32px;
  --text-3xl:  40px;

  /* ── Elevation scale ─────────────────────────────────────────────────
   * Cool-slate shadows (not deep navy) with reduced saturation. Inset
   * highlights on light theme stripped — they read glassy/dated on
   * solid white. Added shadow-0 for hairline elevation (input focus,
   * hovered table rows) — old scale started too heavy for that role.
   */
  --shadow-0: 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-1: 0 1px 3px rgba(15, 23, 42, 0.10), 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-2: 0 4px 12px rgba(15, 23, 42, 0.16), 0 2px 4px rgba(15, 23, 42, 0.08);
  --shadow-3: 0 12px 30px rgba(15, 23, 42, 0.40), 0 4px 8px rgba(15, 23, 42, 0.10);

  /* Legacy aliases — existing rules still reference these. */
  --shadow:       var(--shadow-2);
  --shadow-hover: var(--shadow-3);

  /* ── Focus ring ──────────────────────────────────────────────────────
   * Slate-tinted teal — pulled toward --primary so it reads as one
   * brand color across all interactive states.
   */
  --ring:        rgba(14, 165, 163, 0.50);
  --ring-glow:   0 0 0 3px rgba(14, 165, 163, 0.22);

  /* ── Motion ──────────────────────────────────────────────────────────
   * Single curve + duration trio used everywhere. Calm clinical means
   * no overshoot, no spring — just smooth ease-out for entries.
   */
  --ease:    cubic-bezier(.2, .8, .2, 1);
  --dur-1:   120ms;            /* hover, micro */
  --dur-2:   220ms;            /* panel reveal, state change */
  --dur-3:   320ms;            /* page transition */
}

@media (prefers-color-scheme: light) {
  :root {
    --bg-0:      #f4f6fb;        /* slate-50 mist (was #e8ecf7 — cooler) */

    /* Light-theme surfaces — flat white with solid hairline borders.
       Glass tokens still defined for the few overlays that opt in
       (toasts, lightbox), but lower opacity than before. */
    --surface:    #ffffff;
    --surface-2:  #f8fafc;        /* slate-50 secondary */
    --border:     #e2e8f0;        /* slate-200 — flat hairline */
    --border-strong: #cbd5e1;     /* slate-300 — input focus */

    --glass:               rgba(255, 255, 255, 0.85);
    --glass-strong:        rgba(255, 255, 255, 0.95);
    --glass-weak:          rgba(255, 255, 255, 0.65);
    --glass-border:        #e2e8f0;
    --glass-border-strong: #cbd5e1;
    --glass-hi:            rgba(255, 255, 255, 0.70);

    --ink:       #0f172a;        /* slate-900 — true heading ink */
    --text:      #1e293b;        /* slate-800 */
    --text-dim:  #475569;        /* slate-600 (was #3d4a70 — bluer) */
    --muted:     #64748b;        /* slate-500 */

    --primary-soft: rgba(14, 165, 163, 0.10);

    /* Light-theme shadows — softer + cool slate, no white inset
       highlights (those read glassy/dated on solid white). */
    --shadow-0: 0 1px 2px rgba(15, 23, 42, 0.04);
    --shadow-1: 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 3px rgba(15, 23, 42, 0.06);
    --shadow-2: 0 4px 6px rgba(15, 23, 42, 0.05), 0 10px 15px rgba(15, 23, 42, 0.08);
    --shadow-3: 0 10px 25px rgba(15, 23, 42, 0.10), 0 20px 40px rgba(15, 23, 42, 0.06);
    --shadow:       var(--shadow-2);
    --shadow-hover: var(--shadow-3);
  }
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font: 16px/1.5 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-feature-settings: "cv11", "ss01", "ss03";
  color: var(--text);
  background: var(--bg-0);
  padding-bottom: env(safe-area-inset-bottom);
  min-height: 100%;
  position: relative;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* Stat numbers read cleaner with tabular figures. */
.stat-num, .big-score, .big-pct, .pb-num { font-variant-numeric: tabular-nums; }

/* ─── Skeleton loaders ──────────────────────────────────────────────────
 * Replace plain "Loading…" text with pulsing skeleton blocks shaped like
 * the content that's about to arrive. Gives the user a sense of layout
 * before the data loads, makes pages feel ~2x faster perceptually.
 *
 * Usage:
 *   <div class="skeleton skeleton-line"></div>             generic text-row
 *   <div class="skeleton skeleton-line lg"></div>          headline row
 *   <div class="skeleton skeleton-line w-60"></div>        partial-width row
 *   <div class="skeleton skeleton-block h-80"></div>       generic block
 *   <div class="skeleton skeleton-stat"></div>             stat-grid cell
 *   <div class="skeleton skeleton-icon"></div>             round 64px medallion
 *
 * Composition: each "loading" branch in a view returns HTML composed of
 * these primitives, sized to roughly match the real layout. When the
 * real data arrives, view.innerHTML swaps to the rendered content.
 */
@keyframes skeleton-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.skeleton {
  display: block;
  background:
    linear-gradient(
      90deg,
      var(--glass-weak) 0%,
      var(--glass) 50%,
      var(--glass-weak) 100%
    );
  background-size: 200% 100%;
  border-radius: 6px;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
  /* Slightly desaturate so the colours don't fight the real content
     when it arrives during the fade. */
  opacity: .85;
}
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
}

.skeleton-line { height: 14px; margin: 8px 0; width: 100%; }
.skeleton-line.lg { height: 22px; }
.skeleton-line.xl { height: 30px; }
.skeleton-line.w-30 { width: 30%; }
.skeleton-line.w-50 { width: 50%; }
.skeleton-line.w-60 { width: 60%; }
.skeleton-line.w-75 { width: 75%; }

.skeleton-block { width: 100%; height: 100px; border-radius: var(--radius-s); }
.skeleton-block.h-40  { height: 40px; }
.skeleton-block.h-60  { height: 60px; }
.skeleton-block.h-80  { height: 80px; }
.skeleton-block.h-120 { height: 120px; }
.skeleton-block.h-160 { height: 160px; }
.skeleton-block.h-200 { height: 200px; }

/* Stat-card placeholder — matches .stat shape so the swap is seamless. */
.skeleton-stat {
  width: 100%;
  height: 80px;
  border-radius: var(--radius-s);
}
.skeleton-stat-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
@media (min-width: 540px) {
  .skeleton-stat-grid { grid-template-columns: repeat(4, 1fr); }
}

/* Round medallion placeholder — matches the empty-state icon shape. */
.skeleton-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
}

/* Helper card-shape wrapper so the page-load layout matches a .card. */
.skeleton-card {
  padding: 22px;
  border-radius: var(--radius);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-1);
  margin-bottom: 16px;
}

/* ─── Universal card hover ──────────────────────────────────────────────
 * Anything that's clickable and shaped like a card should subtly lift on
 * hover — gives every interaction the same "alive" feel. We target
 * specific known patterns rather than every .card globally because most
 * info cards (stat grids, hero copy) are not clickable.
 */
.action-card,
.plan-card:not(.locked),
.admin-stat:not(.admin-stat-live),
a.bd:hover,
.dash-lock,
.dash-card,
.plan-card-featured {
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}

/* Lift + stronger shadow + slight border accent. We use the design-token
   shadow scale so dark/light themes adapt automatically. */
.plan-card:not(.locked):hover,
a.action-card:not(.locked):hover,
button.action-card:not(.locked):hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-3);
}
/* admin-stat lifts only when it actually links somewhere — the static
   stats on /admin/users are not anchors. */
a.admin-stat:hover,
button.admin-stat:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-3);
  border-color: var(--glass-border-strong);
}

/* Hover treatment for any anchor wrapping a .card — used by the admin
   hub nav cards and similar landing-page-style links. */
a > .card:hover,
.card a.card-link:hover,
a.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-3);
  border-color: rgba(45,212,191,.35);
}


/* ─── Global focus ring ──────────────────────────────────────────────────
 * One brand-teal ring used everywhere a keyboard user lands. :focus-visible
 * gates this to keyboard navigation only — mouse clicks don't trigger it,
 * so buttons don't get peppered with rings on every press.
 *
 * Inputs use a softer "glow" via box-shadow because outline gets clipped
 * by some glass surfaces. Buttons / links / chips use outline so the
 * ring sits cleanly outside the element's own border-radius.
 */
:focus { outline: none; }   /* ditch the browser-default blue ring */

a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
summary:focus-visible,
.chip-pick:focus-visible,
.fc-chip:focus-visible,
.fc-radio:focus-visible,
.theme-option:focus-visible,
.practice-preset:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: inherit;
}

input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--ring-glow);
}

/* ─── Unified status pill ────────────────────────────────────────────────
 * Standard shape for every small status indicator (Pro / Free / Active /
 * Past-due / Canceled / Trialing / etc.). Variants change only the colour;
 * the geometry stays the same so the pill family reads as a single
 * consistent element.
 *
 * Kept as a separate base from the older .sub-pill / .achv-chip / .tag
 * families. Migrate piecemeal — anything new should use .pill.
 */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  color: var(--text-dim);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: .04em;
  line-height: 1.2;
  text-transform: uppercase;
  white-space: nowrap;
}
.pill-pro      { color: #0f766e; background: rgba(45,212,191,.14);  border-color: rgba(45,212,191,.40); }
.pill-active   { color: #0f766e; background: rgba(45,212,191,.14);  border-color: rgba(45,212,191,.40); }
.pill-trial    { color: #1e40af; background: rgba(37,99,235,.14);   border-color: rgba(37,99,235,.40); }
.pill-warn     { color: #92400e; background: rgba(251,191,36,.14);  border-color: rgba(251,191,36,.45); }
.pill-bad      { color: #991b1b; background: rgba(239,68,68,.12);   border-color: rgba(239,68,68,.40); }
.pill-muted    { color: var(--muted); }   /* default look — explicit alias */
/* Calm clinical canvas — flat slate-mist with a single very subtle
   noise overlay to kill banding on dark mode. The four-hue mesh
   (teal/violet/amber/sky drifting blobs) was retired in this pass —
   it competed with content for attention and read as consumer-app,
   not study-tool. body::before/::after kept (zero-cost no-ops in
   light mode, faint dither in dark) so any external rule that
   expected the pseudo-element layers doesn't break. */
body::before {
  content: "";
  position: fixed; inset: 0;
  z-index: -2;
  background: var(--bg-0);
  pointer-events: none;
}
body::after {
  /* Faint dither — only visible on dark mode to soften the flat
     slate canvas. Negligible on light mode (low-contrast against
     #f4f6fb). 3x3 dot grid, 2% white noise. */
  content: "";
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none;
  background-image: radial-gradient(rgba(255,255,255,.02) 1px, transparent 1px);
  background-size: 3px 3px;
  opacity: .5;
}
@media (prefers-color-scheme: light) {
  body::after { opacity: 0; }   /* No noise on white — reads cleaner. */
}

/* ─── Top bar ────────────────────────────────────────────────────────── */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  background: var(--glass-strong);
  backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  border-bottom: 1px solid var(--glass-border);
  position: sticky; top: 0; z-index: 10;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  text-decoration: none; color: inherit;
  min-width: 0;
}
.logo {
  width: 34px; height: 34px;
  display: inline-grid; place-items: center;
  border-radius: 10px; overflow: hidden;
  box-shadow: 0 4px 16px rgba(14,165,233,.30), inset 0 1px 0 rgba(255,255,255,.25);
}
.logo svg,
.logo img { display: block; width: 100%; height: 100%; }
.brand-title {
  font-weight: 700; font-size: 18px; letter-spacing: -0.01em;
  color: var(--text);
}
/* VET accent in the wordmark — teal→cyan to echo the icon tile. */
.brand-accent {
  font-weight: 800;
  background: linear-gradient(135deg, #2dd4bf 0%, #14b8a6 55%, #0ea5e9 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  margin-left: 1px;
}
.top-right { display: flex; align-items: center; gap: 10px; }
.user-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 12px 5px 6px; border-radius: 999px;
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  color: var(--text-dim);
  font-size: 13px; max-width: 180px;
  text-decoration: none; cursor: pointer;
  border: 1px solid var(--glass-border);
  transition: border-color .15s, color .15s, background .15s, transform .1s;
}
a.user-chip:hover {
  color: var(--text); border-color: var(--glass-border-strong);
  background: var(--glass); transform: translateY(-1px);
}
.user-chip-avatar {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 999px;
  font-size: 17px; line-height: 1;
  background: rgba(255,255,255,.06);
  border: 1px solid var(--glass-border);
}
.user-chip-name {
  flex: 0 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}

/* Admin pill — neutral glass like user-chip with a subtle teal accent so
   the shield still reads as "privileged" without the eye-piercing amber. */
.admin-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  font-size: 13px; font-weight: 600; letter-spacing: 0.01em;
  color: var(--text-dim);
  text-decoration: none; cursor: pointer;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  transition: color .15s, background .15s, border-color .15s, transform .1s, box-shadow .15s;
}
.admin-pill:hover {
  color: var(--text); border-color: var(--glass-border-strong);
  background: var(--glass);
  transform: translateY(-1px);
}
.admin-pill .pill-icon {
  font-size: 13px;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.35));
}
.admin-pill .pill-text { line-height: 1; }
@media (max-width: 480px) {
  .admin-pill .pill-text { display: none; }
  .admin-pill { padding: 6px 9px; }
}

/* Circular icon button — used for sign-out in the top bar. */
.icon-btn {
  width: 34px; height: 34px; padding: 0;
  display: inline-grid; place-items: center;
  border-radius: 999px;
  color: var(--text-dim);
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  cursor: pointer;
  transition: color .15s, background .15s, border-color .15s, transform .1s;
}
.icon-btn:hover {
  color: #fca5a5;
  background: linear-gradient(135deg, rgba(239,68,68,.18), rgba(239,68,68,.08));
  border-color: rgba(239,68,68,.45);
  transform: translateY(-1px);
}
.icon-btn:focus-visible {
  outline: 2px solid rgba(239,68,68,.55); outline-offset: 2px;
}
.icon-btn svg { display: block; }

/* ─── Main view ──────────────────────────────────────────────────────── */
main#view {
  max-width: 860px; margin: 0 auto;
  padding: 24px 16px 120px;
  /* Page-transition fade between routes. The router toggles
     .view-leaving on route change; the same property handles fade-out
     (opacity → 0) and fade-in (opacity → 1 when class removed). */
  transition: opacity 120ms ease;
  opacity: 1;
  /* `will-change: opacity` hints the browser to keep the layer composited
     so the transition runs on the GPU, avoiding paint flashes on
     content-heavy pages like /dashboard. */
  will-change: opacity;
}
main#view.view-leaving {
  opacity: 0;
  /* During fade-out, refuse pointer events so users can't double-click
     another nav item mid-transition and queue stale renders. */
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  main#view { transition: none; }
  main#view.view-leaving { opacity: 1; }
}

/* Calm clinical card — flat surface (white on light, slate on dark)
   with hairline border + subtle shadow. The previous translucent glass
   with white "lip" highlight read glassy/dated on solid white; new
   treatment reads as a clean clinical card. Glass primitive still
   exists for floating overlays (toasts, popovers, lightbox). */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-1);
  position: relative;
  transition: box-shadow var(--dur-2) var(--ease);
}
.card > * { position: relative; }

h1, h2, h3 {
  margin: 0 0 12px;
  line-height: 1.25;
  letter-spacing: -0.011em;
  color: var(--ink);
  font-weight: 700;
}
h1 { font-size: var(--text-2xl); }       /* 32px */
h2 { font-size: var(--text-xl); }        /* 24px */
h3 { font-size: var(--text-lg); font-weight: 600; }  /* 18px */
.muted { color: var(--muted); }

/* ─── Buttons ──────────────────────────────────────────────────────────
 * Calm clinical button set — flat surfaces, single solid primary
 * (no gradient), slate hairline borders, soft shadow. Hover lifts
 * 1px with a tightened shadow rather than a wash of color change.
 * Previous gradient primary (#2dd4bf → #0ea5e9) read as marketing
 * page; solid --primary reads as a serious CTA. */
.btn, button.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 10px 20px; border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  font-weight: 600; font-size: var(--text-md);
  background: var(--surface);
  color: var(--text);
  cursor: pointer; text-decoration: none;
  transition: transform var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
  min-height: 44px;
  box-shadow: var(--shadow-1);
}
.btn:hover {
  transform: translateY(-1px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-2);
}
.btn:active { transform: translateY(0); box-shadow: var(--shadow-0); }
.btn-primary {
  background: var(--primary);
  color: #ffffff;
  border-color: var(--primary);
  box-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 4px 12px rgba(14, 165, 163, .25);
}
.btn-primary:hover {
  background: var(--primary-dark);
  border-color: var(--primary-dark);
  box-shadow: 0 2px 4px rgba(15, 23, 42, .06), 0 8px 20px rgba(14, 165, 163, .32);
}
.btn-ghost {
  background: transparent;
  border-color: var(--border);
  color: var(--text-dim);
  box-shadow: none;
}
.btn-ghost:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
  color: var(--ink);
  box-shadow: var(--shadow-0);
}
.btn-red {
  background: rgba(220, 38, 38, .08);
  color: var(--bad);
  border-color: rgba(220, 38, 38, .30);
}
.btn-red:hover {
  background: rgba(220, 38, 38, .14);
  border-color: rgba(220, 38, 38, .45);
  color: #991b1b;
}
.btn-yellow {
  background: rgba(217, 119, 6, .08);
  color: var(--warn);
  border-color: rgba(217, 119, 6, .30);
}
.btn-yellow:hover {
  background: rgba(217, 119, 6, .14);
  border-color: rgba(217, 119, 6, .45);
  color: #92400e;
}
.btn-green {
  background: rgba(5, 150, 105, .08);
  color: var(--good);
  border-color: rgba(5, 150, 105, .30);
}
.btn-green:hover {
  background: rgba(5, 150, 105, .14);
  border-color: rgba(5, 150, 105, .45);
  color: #047857;
}
@media (prefers-color-scheme: dark) {
  /* Dark-mode tonal buttons — the same accents but lighter text so
     the labels stay legible on dark backdrops. */
  .btn-red    { color: #fca5a5; }
  .btn-yellow { color: #fcd34d; }
  .btn-green  { color: #86efac; }
  .btn-red:hover    { color: #fecaca; }
  .btn-yellow:hover { color: #fde68a; }
  .btn-green:hover  { color: #bbf7d0; }
}
.btn.wide, .btn-primary.wide, .btn-ghost.wide { width: 100%; }
.btn-icon {
  background: transparent; border: none;
  font-size: 22px; color: var(--muted); padding: 4px 8px; cursor: pointer;
  transition: color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.btn-icon:hover { color: var(--ink); transform: scale(1.08); }
.btn-icon.on { color: var(--primary); }

/* ─── Home / dashboard ───────────────────────────────────────────────── */
/* Home hero — soft multi-tone pastel that flows mint → peach → rose
   left-to-right. Reads warmer and more inviting than a single-hue
   gradient, and pairs well with the teal home-hero avatar bubble.
   Different palette from the admin hero (warm amber→coral) so the
   user-facing landing and the ops console can't be confused. */
/* Calm clinical hero — flat surface + a single 4px teal accent stripe
   on the leading edge. The previous warm-pastel mint→peach→rose
   gradient with the orange→rose gradient h1 fill read as marketing
   page, not study tool. New treatment lets the user's name and
   greeting carry the page rather than a candy backdrop. */
.hero {
  position: relative;
  /* Padding evened out after removing the teal ::before accent stripe.
     Old left-padding (26px) was bumped to clear the 4px stripe; with
     the stripe gone we drop back to a uniform 22px on both sides. */
  padding: 20px 22px 18px 22px;
  margin: 4px 0 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.hero h1 {
  font-size: var(--text-2xl);
  margin-bottom: 2px;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.011em;
  /* Drop the orange→rose gradient text fill — solid ink reads as a
     serious headline, gradient reads as marketing. */
  background: none;
  -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: initial;
}
@media (max-width: 540px) {
  .hero { padding: 16px 16px 14px 22px; }
  .hero h1 { font-size: var(--text-xl); }
}
.stat-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px; margin: 18px 0;
}
@media (min-width: 540px) { .stat-grid { grid-template-columns: repeat(4, 1fr); } }
.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px; text-align: center;
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.stat:hover { box-shadow: var(--shadow-2); transform: translateY(-1px); }
/* Calm clinical stat numerals — solid --ink, no gradient text fill.
   Gradient was teal→sky which read as decorative marketing; solid ink
   with tabular-nums reads as data. Tabular-nums also prevents layout
   shift when numerals change (e.g., live counters). */
.stat-num {
  font-size: 28px; font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.011em;
  background: none;
  -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: initial;
}
.stat-lbl { font-size: var(--text-xs); color: var(--muted); margin-top: 4px; letter-spacing: .04em; text-transform: uppercase; }

/* "Today" tile — tints mint when the user has answered ≥1 question
   since local midnight, so the daily-progress signal stands out from
   the lifetime-stat tiles next to it. Sits subtle until you've earned
   it; turns into a small badge once you have. */
.stat.stat-today.is-active {
  background: rgba(20, 184, 166, 0.08);
  border-color: rgba(20, 184, 166, 0.35);
}
.stat.stat-today.is-active .stat-num { color: #0F6E56; }

.card-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* ─── Bento variant ──────────────────────────────────────────────
   `.card-grid-bento` opts a card grid into the "one primary +
   secondary tiles" layout. The primary tile (`.action-card-primary`)
   spans two columns on the 3-col desktop layout (taking the headline
   slot), shows a tinted background, larger title, and a primary CTA
   button. Mobile / narrow viewports collapse it to one column
   automatically via grid auto-fit. */
.card-grid-bento { gap: 12px; }
.action-card-primary {
  grid-column: span 2;
  display: flex;
  gap: 16px;
  align-items: flex-start;
  padding: 22px 24px;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  border: 1px solid var(--border, rgba(148,163,184,0.35));
  background: var(--surface, var(--glass-weak));
  transition: transform .12s, box-shadow .15s, border-color .15s;
}
.action-card-primary:hover { transform: translateY(-1px); box-shadow: var(--shadow-hover); }
.action-icon-primary {
  width: 48px; height: 48px;
  border-radius: 14px;
  font-size: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--glass-weak, rgba(148,163,184,0.12));
  line-height: 1;
}
.action-primary-body { display: flex; flex-direction: column; min-width: 0; gap: 4px; flex: 1; }
.action-primary-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim, var(--muted));
}
.action-primary-title {
  font-size: 19px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ink, var(--text));
  letter-spacing: -0.01em;
}
.action-primary-sub {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text-dim, var(--muted));
  margin-top: 2px;
}
.action-primary-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  background: var(--primary, #0F6E56);
  margin-top: 12px;
  align-self: flex-start;
  white-space: nowrap;
}

/* Accent tints — pick by data-accent. Background uses a light pastel
   from the matching ramp; border + CTA + eyebrow take the darker
   stops so they pop without overpowering the rest of the grid. */
.action-card-primary[data-accent="teal"] {
  background: #E1F5EE; border-color: rgba(15, 110, 86, 0.30);
}
.action-card-primary[data-accent="teal"] .action-primary-eyebrow { color: #085041; }
.action-card-primary[data-accent="teal"] .action-icon-primary    { background: rgba(15, 110, 86, 0.16); color: #0F6E56; }
.action-card-primary[data-accent="teal"] .action-primary-cta     { background: #0F6E56; }

.action-card-primary[data-accent="purple"] {
  background: #EEEDFE; border-color: rgba(60, 52, 137, 0.30);
}
.action-card-primary[data-accent="purple"] .action-primary-eyebrow { color: #3C3489; }
.action-card-primary[data-accent="purple"] .action-icon-primary    { background: rgba(60, 52, 137, 0.16); color: #3C3489; }
.action-card-primary[data-accent="purple"] .action-primary-cta     { background: #534AB7; }

.action-card-primary[data-accent="amber"] {
  background: #FAEEDA; border-color: rgba(186, 117, 23, 0.32);
}
.action-card-primary[data-accent="amber"] .action-primary-eyebrow { color: #633806; }
.action-card-primary[data-accent="amber"] .action-icon-primary    { background: rgba(186, 117, 23, 0.16); color: #854F0B; }
.action-card-primary[data-accent="amber"] .action-primary-cta     { background: #BA7517; }

.action-card-primary[data-accent="blue"] {
  background: #E6F1FB; border-color: rgba(24, 95, 165, 0.30);
}
.action-card-primary[data-accent="blue"] .action-primary-eyebrow { color: #0C447C; }
.action-card-primary[data-accent="blue"] .action-icon-primary    { background: rgba(24, 95, 165, 0.16); color: #185FA5; }
.action-card-primary[data-accent="blue"] .action-primary-cta     { background: #185FA5; }

/* Mobile — drop the 2-col span; primary tile becomes a tall single-
   column card. Slightly less padding, title scales down. */
@media (max-width: 540px) {
  .action-card-primary { grid-column: auto; padding: 18px 18px; gap: 12px; }
  .action-icon-primary { width: 40px; height: 40px; font-size: 20px; border-radius: 12px; }
  .action-primary-title { font-size: 17px; }
  .action-primary-sub { font-size: 12.5px; }
}
.action-card {
  position: relative;
  display: flex; align-items: center; gap: 14px;
  padding: 18px;
  background: var(--glass);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  text-decoration: none; color: var(--text);
  transition: border-color .15s, transform .1s, box-shadow .15s;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
}
.action-badge {
  position: absolute;
  top: 10px; right: 10px;
  min-width: 22px; height: 22px;
  padding: 0 7px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; line-height: 1;
  color: #042f2e;
  background: linear-gradient(135deg, #5eead4, #38bdf8);
  border: 1px solid rgba(45,212,191,.7);
  border-radius: 999px;
  box-shadow: 0 0 0 2px rgba(3,8,24,.6), 0 4px 12px rgba(45,212,191,.35);
  animation: actionBadgePulse 2.4s ease-in-out infinite;
}
.action-badge[hidden] { display: none; }
.action-badge.action-badge-urgent {
  color: #fff;
  background: linear-gradient(135deg, #f97316, #ef4444);
  border-color: rgba(239,68,68,.7);
  box-shadow: 0 0 0 2px rgba(3,8,24,.6), 0 4px 14px rgba(239,68,68,.45);
  animation: actionBadgeUrgent 1.1s ease-in-out infinite;
  min-width: 26px; height: 26px; font-size: 14px;
}
@keyframes actionBadgePulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.08); box-shadow: 0 0 0 2px rgba(3,8,24,.6), 0 6px 16px rgba(45,212,191,.5); }
}
@keyframes actionBadgeUrgent {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.15); box-shadow: 0 0 0 2px rgba(3,8,24,.6), 0 8px 20px rgba(239,68,68,.65); }
}
.action-card:hover {
  border-color: rgba(45,212,191,.45);
  transform: translateY(-2px);
  box-shadow: 0 10px 28px rgba(3,8,24,.30), inset 0 1px 0 rgba(255,255,255,.10);
}
.action-card.highlight {
  border-color: rgba(251,191,36,.50);
  box-shadow: 0 0 0 2px rgba(251,191,36,.18), inset 0 1px 0 rgba(255,255,255,.08);
}
.action-icon { font-size: 30px; }
/* When the action-icon hosts an inline SVG instead of an emoji, size it to
   match the visual weight of the surrounding 30px emoji glyphs. The
   container itself stays the same flex-item shape so the grid layout
   doesn't shift. */
.action-icon-svg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
}
.action-icon-svg svg {
  width: 30px;
  height: 30px;
}
.action-title { font-weight: 700; }
.action-sub { font-size: 13px; color: var(--muted); }

/* ─── Auth form ──────────────────────────────────────────────────────── */
.auth-wrap { max-width: 420px; margin: 24px auto 0; }
.auth-back { margin: 0 0 8px; font-size: 14px; }
.auth-back a { color: var(--text-dim); text-decoration: none; transition: color .15s; }
.auth-back a:hover { color: var(--accent); }
.auth-brand {
  display: flex; align-items: center; justify-content: center;
  gap: 12px;
  margin: 12px 0 4px;
}
.auth-logo {
  width: 56px; height: 56px;
  border-radius: 14px;
  box-shadow: 0 10px 30px rgba(20,184,166,.22);
}
.auth-wordmark {
  font-size: 30px; font-weight: 800; letter-spacing: .01em;
  color: var(--text);
  line-height: 1;
}
.auth-tagline {
  text-align: center;
  margin: 4px 0 18px;
  color: var(--muted);
  font-size: 14px;
  letter-spacing: .02em;
}
.auth-card { max-width: 420px; margin: 0 auto; }
.auth-title { font-size: 24px; }
.auth-sub { color: var(--muted); margin-bottom: 18px; }
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-dim); }
.auth-form input {
  padding: 12px 14px; font-size: 16px; border-radius: var(--radius-s);
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  color: var(--text);
  transition: border-color .15s, box-shadow .15s;
}
.auth-form input:focus {
  outline: none;
  border-color: rgba(45,212,191,.6);
  box-shadow: 0 0 0 3px rgba(45,212,191,.18);
}
.or { text-align: center; margin: 14px 0; color: var(--muted); font-size: 13px; }
.auth-toggle { text-align: center; margin-top: 12px; color: var(--text-dim); }
.auth-toggle a { color: var(--primary); }
.notice {
  padding: 12px 14px;
  background: linear-gradient(135deg, rgba(251,191,36,.18), rgba(251,191,36,.06));
  border: 1px solid rgba(251,191,36,.35);
  border-radius: var(--radius-s);
  color: var(--text); margin-bottom: 16px; font-size: 14px;
}

.banner {
  background: linear-gradient(135deg, rgba(251,191,36,.22), rgba(251,191,36,.10));
  color: var(--text);
  padding: 10px 14px; text-align: center; font-size: 13px;
  border-bottom: 1px solid rgba(251,191,36,.40);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
}

/* ─── Filters ────────────────────────────────────────────────────────── */
.filters { display: flex; flex-direction: column; gap: 18px; }
.filters fieldset { border: none; padding: 0; margin: 0; }
.filters legend { font-weight: 600; color: var(--text-dim); margin-bottom: 8px; letter-spacing: .02em; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chips-dense { gap: 6px; }
.chip-pick { position: relative; }
.chip-pick input { position: absolute; opacity: 0; pointer-events: none; }
.chip-pick span {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px;
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  color: var(--text-dim);
  border: 1px solid var(--glass-border); border-radius: 999px;
  font-size: 13px; cursor: pointer;
  transition: all .15s;
}
.chip-pick .chip-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 15px;
  line-height: 1;
  padding: 0;
  background: transparent;
  border: none;
  filter: saturate(1.1) drop-shadow(0 1px 1px rgba(0,0,0,.25));
  flex-shrink: 0;
}
.chip-pick .chip-text { display: inline-block; }
.chip-pick input:checked + span .chip-icon {
  filter: saturate(1.25) drop-shadow(0 1px 2px rgba(0,0,0,.35));
}
.chip-pick span:hover { color: var(--text); border-color: var(--glass-border-strong); }
.chip-pick input:checked + span {
  background: linear-gradient(135deg, rgba(45,212,191,.28), rgba(14,165,233,.22));
  color: var(--text);
  border-color: rgba(45,212,191,.55);
  box-shadow: 0 4px 14px rgba(45,212,191,.22), inset 0 1px 0 rgba(255,255,255,.12);
}
.seg { display: flex; gap: 6px; flex-wrap: wrap; }
.seg label { cursor: pointer; }
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg span {
  display: inline-flex; padding: 10px 18px;
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  color: var(--text-dim);
  border: 1px solid var(--glass-border); border-radius: var(--radius-s); font-size: 14px;
  transition: all .15s;
}
.seg span:hover { color: var(--text); }
.seg input:checked + span {
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
  color: white; border-color: rgba(255,255,255,.18);
  box-shadow: 0 4px 14px rgba(14,165,233,.30), inset 0 1px 0 rgba(255,255,255,.25);
}
.filter-actions {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  margin-top: 6px; flex-wrap: wrap;
}
.match-count { font-size: 13px; }

/* ─── Quiz card ──────────────────────────────────────────────────────── */
.quiz .quiz-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 8px; margin-bottom: 10px;
}
.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  font-size: 11px; padding: 4px 10px; border-radius: 999px;
  background: var(--glass-weak);
  color: var(--text-dim);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
}
.tag-species { color: #5eead4; border-color: rgba(45,212,191,.30); background: rgba(20,184,166,.12); }
.tag-subject { color: #fcd34d; border-color: rgba(251,191,36,.35); background: rgba(251,191,36,.12); }
.quiz-meta { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }
.progress-text { font-variant-numeric: tabular-nums; }
.question {
  font-size: 18px; line-height: 1.5; margin: 14px 0 18px;
  color: var(--text);
}

/* Organised question block: clinical vignette (framed card) + the actual
   prompt (coloured, bold). Rendered by fmtQuestion() in quiz.js. */
.question-block { margin: 14px 0 18px; }
.question-vignette {
  font-size: 17px;
  line-height: 1.55;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 14px;
}
.question-vignette p { margin: 0 0 8px; }
.question-vignette p:last-child { margin-bottom: 0; }
.question-prompt {
  font-size: 17px;
  line-height: 1.5;
  font-weight: 700;
  color: #5eead4;
  margin: 0;
}

.choices { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.choice {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px;
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border); border-radius: var(--radius-s);
  cursor: pointer; text-align: left; color: var(--text); font-size: 15px;
  min-height: 52px; line-height: 1.45;
  transition: border-color .15s, background .15s, transform .1s, box-shadow .15s;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}
.choice:not(:disabled):hover {
  border-color: rgba(45,212,191,.45);
  background: rgba(45,212,191,.08);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(3,8,24,.20), inset 0 1px 0 rgba(255,255,255,.09);
}
.choice .letter {
  flex: 0 0 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  font-weight: 700; font-size: 13px; color: var(--text-dim);
  transition: all .15s;
}
.choice.is-correct {
  border-color: rgba(34,197,94,.55);
  background: linear-gradient(135deg, rgba(34,197,94,.18), rgba(34,197,94,.06));
  box-shadow: 0 0 0 2px rgba(34,197,94,.14), inset 0 1px 0 rgba(255,255,255,.08);
}
.choice.is-correct .letter { background: var(--good); color: white; border-color: var(--good); }
.choice.is-wrong {
  border-color: rgba(239,68,68,.55);
  background: linear-gradient(135deg, rgba(239,68,68,.18), rgba(239,68,68,.06));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
}
.choice.is-wrong .letter { background: var(--bad); color: white; border-color: var(--bad); }
.choice.is-selected {
  border-color: rgba(45,212,191,.55);
  background: linear-gradient(135deg, rgba(45,212,191,.18), rgba(14,165,233,.10));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.08);
}
.choice.is-selected .letter { background: var(--primary); color: white; border-color: var(--primary); }
.choice:disabled { cursor: default; }

.feedback {
  padding: 14px 16px; border-radius: var(--radius-s);
  margin-bottom: 14px;
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
}
.feedback.ok  { background: linear-gradient(135deg, rgba(34,197,94,.18), rgba(34,197,94,.04)); border: 1px solid rgba(34,197,94,.40); }
.feedback.bad { background: linear-gradient(135deg, rgba(239,68,68,.16), rgba(239,68,68,.04)); border: 1px solid rgba(239,68,68,.40); }
.feedback-title { font-weight: 700; margin-bottom: 6px; font-size: 15px; }
.feedback.ok  .feedback-title { color: #86efac; }
.feedback.bad .feedback-title { color: #fca5a5; }
@media (prefers-color-scheme: light) {
  .feedback.ok  .feedback-title { color: #166534; }
  .feedback.bad .feedback-title { color: #991b1b; }
}
.feedback-answer { margin-bottom: 8px; }
.feedback-explain { color: var(--text-dim); font-size: 15px; line-height: 1.55; }
.feedback-explain p { margin: 0 0 10px; }
.feedback-explain p:last-child { margin-bottom: 0; }
.feedback-list {
  list-style: disc outside;
  padding-left: 20px;
  margin: 4px 0 10px;
}
.feedback-list li { margin: 2px 0; }
.feedback-refs {
  margin-top: 14px !important;
  padding-top: 10px;
  border-top: 1px solid var(--glass-border);
  font-size: 12.5px;
  color: var(--muted);
}
.feedback-refs strong { color: var(--text); }

.actions { display: flex; flex-direction: column; gap: 10px; }
.grade-row { display: flex; gap: 8px; }
.grade-row .btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  line-height: 1.15;
  padding-top: 10px;
  padding-bottom: 10px;
}
.grade-label { font-weight: 600; font-size: 1rem; }
.grade-hint  { font-size: 0.72rem; opacity: 0.78; font-weight: 500; letter-spacing: 0.01em; }
.grade-help  { margin-bottom: 2px; line-height: 1.35; }
@media (max-width: 420px) {
  .grade-hint { font-size: 0.66rem; }
  .grade-label { font-size: 0.95rem; }
}
.hidden { display: none !important; }

/* Prev + Next nav row — Prev ghost on the left, Next primary on the right,
   similar sizes so the pair reads as one control. Sits inside .actions so it
   stacks below any grade-row (review mode never passes onPrev, so this row
   only appears in practice mode today). */
.nav-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.nav-row .nav-prev,
.nav-row .nav-next { flex: 0 1 auto; min-width: 120px; }

/* ─── Install-app prompt (mobile only) ───────────────────────────────── */
/* Floats above the fixed bottom nav. The install-prompt module only ever
   inserts this element on mobile viewports, but the media query below keeps
   it off-screen on tablet/desktop widths regardless. */
.install-banner {
  position: fixed;
  left: 12px;
  right: 12px;
  /* Bottom nav is ~64px tall + safe-area inset. Clear that plus 10px gap. */
  bottom: calc(74px + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  background: var(--glass-strong);
  backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: 14px;
  padding: 12px 14px;
  box-shadow: 0 12px 36px rgba(3, 8, 24, 0.28);
  animation: install-rise 0.32s ease-out both;
}
.install-banner.hidden { display: none !important; }
.install-banner-inner {
  display: flex;
  align-items: center;
  gap: 12px;
}
.install-banner-icon {
  font-size: 24px;
  line-height: 1;
  flex: 0 0 auto;
}
.install-banner-text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  line-height: 1.35;
}
.install-banner-text strong { display: block; font-weight: 700; }
.install-banner-sub { display: block; font-size: 12.5px; margin-top: 2px; }
.install-banner-actions {
  display: flex;
  gap: 6px;
  flex: 0 0 auto;
  align-items: center;
}
.install-banner-actions .btn {
  padding: 7px 12px;
  font-size: 13px;
  min-width: 0;
}
.ios-share-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 2px;
  border: 1px solid var(--glass-border);
  border-radius: 4px;
  vertical-align: -4px;
  color: var(--text-dim);
}
@keyframes install-rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
/* On tablet/desktop the bottom nav is static and there's plenty of room —
   don't show the install CTA, mirroring the JS-side viewport check. */
@media (min-width: 900px) {
  .install-banner { display: none !important; }
}

/* ─── Session summary ────────────────────────────────────────────────── */
.summary { text-align: center; padding: 34px 20px; }
.big-score {
  font-size: 48px; font-weight: 800; margin: 16px 0 4px;
  background: linear-gradient(135deg, #2dd4bf 0%, #0ea5e9 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  letter-spacing: -0.02em;
}
.big-pct { font-size: 26px; font-weight: 600; color: var(--text-dim); margin-bottom: 22px; }
.summary-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* ─── Exam mode ──────────────────────────────────────────────────────── */
.exam-bar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 16px;
  background: var(--glass);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border-radius: var(--radius);
  border: 1px solid var(--glass-border); margin-bottom: 14px;
  font-size: 14px; gap: 10px; flex-wrap: wrap;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
}
.exam-timer { font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; font-size: 15px; }
.exam-nav { display: flex; justify-content: space-between; gap: 10px; margin-top: 12px; }
.exam-nav .btn { min-width: 120px; }

/* Dashboard vertical rhythm — keep every section visually separated. */
.dash { display: flex; flex-direction: column; gap: 16px; }
.dash > .two-col { margin-top: 0; } /* .dash gap handles spacing; avoid double gap */

/* Home vertical rhythm — hero, stats, card grid, recent exams, bookmarks. */
.home { display: flex; flex-direction: column; gap: 16px; }

/* Breakdown tables */
.two-col { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 16px; }
@media (min-width: 720px) { .two-col { grid-template-columns: 1fr 1fr; } }
.bd {
  background: var(--glass);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius); padding: 16px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
}
.bd-table { width: 100%; border-collapse: collapse; }
.bd-table td, .bd-table th { padding: 6px 8px; font-size: 14px; }
.bd-table .num { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-dim); }
.bd-table .bar-cell { width: 40%; }
.bar {
  height: 8px; background: var(--glass-weak); border-radius: 4px; overflow: hidden;
  border: 1px solid var(--glass-border);
}
.bar span {
  display: block; height: 100%;
  background: linear-gradient(90deg, #2dd4bf, #0ea5e9);
  border-radius: 4px;
  box-shadow: 0 0 12px rgba(45,212,191,.45);
}

/* ─── Bottom nav ─────────────────────────────────────────────────────────
 * Calm clinical bottom nav — single tonal language. SVG fills inherit
 * currentColor (set in index.html) so the active state lights up
 * --primary while inactive tabs sit at --text-dim. Subtle frosted
 * surface, slate hairline border, no candy shadow. */
.bottomnav {
  position: fixed; left: 0; right: 0; bottom: 0;
  /* 6 columns to accommodate Home / Practice / Review / Multiplayer /
     Flashcards / Stats. Each column is `minmax(0, 1fr)` so labels can
     truncate gracefully on narrow viewports instead of forcing the
     whole nav wider than the screen. */
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  background: var(--glass-strong);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border-top: 1px solid var(--border);
  padding: 6px 4px; padding-bottom: calc(6px + env(safe-area-inset-bottom));
  z-index: 20;
  box-shadow: 0 -1px 2px rgba(15, 23, 42, .04), 0 -4px 16px rgba(15, 23, 42, .06);
}
.bottomnav a {
  display: flex; flex-direction: column; align-items: center;
  padding: 9px 4px 7px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: var(--text-xs); gap: 3px;
  transition: color var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease),
              transform var(--dur-1) var(--ease);
  border-radius: var(--radius-sm);
  min-width: 0;   /* let grid track shrink below content width */
}
/* Truncate labels that don't fit (notably "Multiplayer" on narrow
   viewports — 6 tabs × ~12px font at <380px viewport runs out of
   horizontal room). Icon stays full-size; the label ellipsizes
   gracefully instead of forcing the nav to overflow. */
.bottomnav a .label {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bottomnav a .icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
}
.bottomnav a .icon svg {
  width: 22px; height: 22px;
  transition: transform var(--dur-2) var(--ease);
}
.bottomnav a.active {
  color: var(--primary);
  background: var(--primary-soft);
  font-weight: 600;
}
.bottomnav a.active .icon svg { transform: translateY(-1px); }
.bottomnav a:hover { color: var(--ink); }
.bottomnav a:hover .icon svg { transform: translateY(-1px); }
.bottomnav a.active:hover { color: var(--primary); }

/* ─── Toast stack ────────────────────────────────────────────────────────
 * Multiple toasts can fire close together (a save + a streak milestone +
 * a network warning all firing in the same tick is plausible). Stack them
 * vertically instead of letting the last one clobber the rest. Each toast
 * is its own element with its own enter/exit transition.
 *
 * Position: above the bottom nav (with safe-area inset on iPhone), centered
 * horizontally. The stack wrapper itself is pointer-events:none so toasts
 * never block taps to underlying UI; individual toasts opt back in for the
 * click-to-dismiss interaction.
 */
#toast-stack {
  position: fixed;
  left: 50%;
  bottom: calc(80px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 30;
  display: flex;
  flex-direction: column-reverse;     /* newest at the bottom of the stack visually */
  gap: 8px;
  pointer-events: none;
  width: max-content;
  max-width: calc(100vw - 24px);
}

.toast {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px 10px 12px;
  border-radius: 999px;
  background: var(--glass-strong);
  backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-3);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.4;
  pointer-events: auto;
  cursor: pointer;
  user-select: none;

  /* Animation states. The from-state is the default (out-of-stage); the
     `.toast-in` class commits the to-state via transition; `.toast-out`
     reverses (with a slight downward drift to feel like a dismissal). */
  opacity: 0;
  transform: translateY(20px) scale(.96);
  transition:
    opacity 220ms ease,
    transform 280ms cubic-bezier(.22, .9, .35, 1);
}
.toast-in  { opacity: 1; transform: translateY(0) scale(1); }
.toast-out { opacity: 0; transform: translateY(8px) scale(.96); }

@media (prefers-reduced-motion: reduce) {
  .toast { transition: opacity 120ms ease; transform: none !important; }
  .toast-in, .toast-out { transform: none !important; }
}

/* Status icon — colored circle with a single character glyph. Kept as
   a flexible 22×22 square so character-width variations (i / ! / ✓ / ✕)
   don't shift the layout. */
.toast-icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 13px;
  font-weight: 800;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: #fff;
  line-height: 1;
}
.toast-msg {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* Variant color mapping — only the icon background and the border change
   per variant; the toast body keeps the neutral glass look so the visual
   hierarchy is "icon shouts variant, body reads message".  */
.toast-ok    { border-color: rgba(34, 197, 94, .45); }
.toast-ok    .toast-icon { background: #22c55e; }

.toast-warn  { border-color: rgba(245, 158, 11, .45); }
.toast-warn  .toast-icon { background: #f59e0b; }

.toast-bad   { border-color: rgba(239,  68, 68, .45); }
.toast-bad   .toast-icon { background: #ef4444; }

.toast-info  { border-color: rgba(45, 212, 191, .40); }
.toast-info  .toast-icon { background: var(--primary, #14b8a6); }

/* Hover: slight lift + brighter border so users notice it's clickable. */
.toast:hover {
  box-shadow: 0 18px 56px rgba(3, 8, 24, 0.55);
  transform: translateY(-1px);
}

/* ─── Responsive: tablet / desktop ───────────────────────────────────── */
@media (min-width: 900px) {
  main#view { padding-bottom: 40px; }
  .bottomnav {
    position: static;
    padding: 0;
    max-width: 860px; margin: 0 auto 16px;
    border-radius: var(--radius);
    background: var(--glass);
    border: 1px solid var(--glass-border);
    box-shadow: var(--shadow);
  }
  .bottomnav a { padding: 12px 8px; font-size: 13px; flex-direction: row; gap: 8px; }
}

/* ─── Site footer ────────────────────────────────────────────────────── */
.site-footer {
  max-width: 860px;
  margin: 8px auto 0;
  padding: 18px 20px 140px;          /* bottom padding clears fixed mobile nav */
  text-align: center;
}
.site-footer .footer-copy {
  padding: 12px 0;
  border-top: 1px solid var(--glass-border);
  color: var(--muted);
  font-size: 12.5px;
  letter-spacing: .01em;
}
@media (min-width: 900px) {
  .site-footer { padding-bottom: 40px; }
}

/* ─── Dashboard hero (welcoming header on /dashboard) ─────────────────
   Mirrors the home hero's vibe but with a stats-page identity:
   eyebrow with date stamp, larger gradient headline, adaptive subtitle.
   Sits at the very top of the dashboard before the stat grid. */
/* Dashboard hero — same calm-clinical pattern as the home .hero:
   flat surface with a teal accent stripe on the leading edge. The
   previous teal-sky gradient panel + gradient h1 fill mismatched
   the new palette and read as marketing-y. */
.dash-hero {
  position: relative;
  margin: 4px 0 18px;
  padding: 20px 22px 18px 26px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.dash-hero::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--primary);
  border-radius: var(--radius) 0 0 var(--radius);
}
.dash-hero-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.dash-hero-text { min-width: 0; flex: 1 1 auto; }
.dash-hero-eyebrow {
  font-size: var(--text-xs); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--primary);
  margin-bottom: 4px;
}
.dash-hero h1 {
  margin: 0 0 6px;
  font-size: var(--text-2xl); line-height: 1.2;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.011em;
  /* Solid ink — no gradient text fill. */
  background: none;
  -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: initial;
}
.dash-hero-sub {
  margin: 0;
  font-size: var(--text-base); line-height: 1.5;
  color: var(--text-dim);
}
@media (max-width: 540px) {
  .dash-hero { padding: 16px 16px 14px 22px; }
  .dash-hero h1 { font-size: var(--text-xl); }
  .dash-hero-sub { font-size: var(--text-sm); }
}

/* ─── Subscription: pro chip, lock badges, paywall, upgrade page ───── */
.hero-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.hero-row h1 { margin: 0; }
.hero-greeting {
  display: flex; align-items: center; gap: 12px;
  min-width: 0;
}
/* Stats-loaded hero variant — greeting + Pro pill on top row, divider,
   then a row of glanceable chips (streak, today, due, accuracy). The
   chip palette uses light pastel fills with darker text from the same
   ramp for legibility. Hover lift is gentle so non-link chips don't
   feel falsely interactive. */
.hero-text { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.hero-text h1 { margin: 0; }
.hero-subtitle { font-size: 13px; margin: 0; line-height: 1.4; }
.hero-divider {
  border: 0;
  height: 1px;
  background: var(--border, rgba(148, 163, 184, 0.2));
  margin: 12px 0;
}
.hero-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.hero-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-decoration: none;
  border: 0.5px solid transparent;
  transition: filter .12s, transform .12s;
}
a.hero-chip { cursor: pointer; }
a.hero-chip:hover { filter: brightness(0.96); transform: translateY(-1px); }
.hero-chip-streak   { background: #FAEEDA; color: #633806; border-color: rgba(186, 117, 23, 0.18); }
.hero-chip-today    { background: #E6F1FB; color: #0C447C; border-color: rgba(24, 95, 165, 0.18); }
.hero-chip-due      { background: #FBEAF0; color: #72243E; border-color: rgba(153, 53, 86, 0.18); }
.hero-chip-due.hero-chip-zero { background: var(--glass-weak, rgba(148,163,184,0.12)); color: var(--text-dim, var(--muted)); border-color: var(--border, rgba(148,163,184,0.18)); }
.hero-chip-accuracy { background: var(--glass-weak, rgba(148,163,184,0.12)); color: var(--text-dim, var(--muted)); border-color: var(--border, rgba(148,163,184,0.18)); }
.hero-chip-quota    { background: #FCEBEB; color: #791F1F; border-color: rgba(163, 45, 45, 0.18); }
@media (max-width: 480px) {
  .hero-chips { gap: 6px; }
  .hero-chip { padding: 4px 9px; font-size: 11.5px; }
}

.pro-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12.5px; font-weight: 600; letter-spacing: .02em;
  background: linear-gradient(135deg, rgba(45,212,191,.18), rgba(14,165,233,.18));
  border: 1px solid rgba(45,212,191,.35);
  color: #5eead4;
  text-decoration: none;
  white-space: nowrap;
}
.pro-chip-free {
  color: var(--muted);
  background: var(--glass);
  border-color: var(--glass-border);
}
.pro-chip-free:hover { color: #5eead4; border-color: rgba(45,212,191,.4); }

.lock-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 8px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase;
  color: #fbbf24;
  background: rgba(251,191,36,.10);
  border: 1px solid rgba(251,191,36,.30);
  border-radius: 999px;
  vertical-align: 1px;
}

/* Locked action cards get a subtler look + a small lock accent via the badge. */
.action-card.locked { opacity: .85; }
.action-card.locked:hover { opacity: 1; }

/* Paywall interstitial */
.paywall {
  max-width: 640px;
  margin: 24px auto;
}
.paywall-card {
  text-align: center;
  padding: 32px 28px;
}
.paywall-icon {
  font-size: 40px; line-height: 1;
  margin-bottom: 8px;
}
.paywall-eyebrow {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: #5eead4;
  font-weight: 700;
  margin-bottom: 6px;
}
.paywall-title { margin: 4px 0 8px; font-size: 22px; }
.paywall-body { color: var(--muted); margin: 0 auto 18px; max-width: 440px; }
.paywall-actions {
  display: flex; gap: 10px; justify-content: center; flex-wrap: wrap;
  margin-top: 4px;
}
.paywall-note { margin-top: 16px; }

/* Dashboard free-tier lock card (in-page teaser, not full paywall) */
.dash-lock {
  border: 1px solid rgba(94, 234, 212, .22);
  background: linear-gradient(180deg, rgba(94, 234, 212, .07), rgba(94, 234, 212, .02));
}
.dash-lock-head {
  display: flex; align-items: flex-start; gap: 14px;
  margin-bottom: 10px;
}
.dash-lock-icon {
  font-size: 28px; line-height: 1;
  flex-shrink: 0;
  margin-top: 2px;
}
.dash-lock-eyebrow {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: #5eead4;
  font-weight: 700;
  margin-bottom: 2px;
}
.dash-lock-title { margin: 0; font-size: 19px; }
.dash-lock-list {
  list-style: none;
  padding: 0;
  margin: 8px 0 18px;
  display: grid; gap: 8px;
}
.dash-lock-list li {
  display: flex; align-items: center; gap: 10px;
  color: var(--fg);
}
.dash-lock-bullet {
  display: inline-grid; place-items: center;
  width: 26px; height: 26px;
  font-size: 15px;
  border-radius: 8px;
  background: rgba(94, 234, 212, .10);
  flex-shrink: 0;
}
.dash-lock-actions {
  display: flex; gap: 10px; flex-wrap: wrap;
}

/* Upgrade page */
.upgrade { max-width: 960px; margin: 0 auto; }
.upgrade-hero { text-align: center; margin: 8px 0 24px; }
.upgrade-eyebrow {
  display: inline-block;
  font-size: 30px;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: #5eead4;
  font-weight: 800;
  margin-bottom: 16px;
}
.upgrade-hero h1 { margin: 2px 0 10px; }
.upgrade-lede { max-width: 580px; margin: 0 auto; }
.upgrade-current {
  margin-top: 14px;
  display: inline-block;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--muted);
  font-size: 13.5px;
}
.upgrade-current .link { color: #5eead4; text-decoration: none; margin-left: 6px; }

/* ─── Intro promo banner ────────────────────────────────────────────────
   Shown to non-Pro users only on /upgrade. Mirrors the amber promo box
   in the day-1 email so a user who clicked through from the email sees
   a continuous visual identity. Two-column layout: price on the left,
   copyable promo-code chip on the right.

   Pulse animation (.intro-promo-banner-pulse) fires when the user lands
   here from the email's Try Pro CTA (?promo=Intro) — a subtle
   attention-pull so they can spot the offer they came for. */
.intro-promo-banner {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  align-items: center;
  justify-content: space-between;
  padding: 18px 22px;
  margin: 8px 0 18px;
  background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
  border: 1px solid #f59e0b;
  border-radius: var(--radius);
  box-shadow: 0 4px 18px rgba(245,158,11,.18), inset 0 1px 0 rgba(255,255,255,.4);
  color: #78350f;
}
.intro-promo-left { flex: 1 1 240px; min-width: 0; }
.intro-promo-eyebrow {
  font-size: 11.5px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: #92400e; margin-bottom: 4px;
}
.intro-promo-price {
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  margin-bottom: 4px;
}
.intro-promo-amount {
  font-size: 30px; font-weight: 800; color: #92400e; line-height: 1;
}
.intro-promo-amount-sub { font-size: 14px; font-weight: 600; color: #78350f; }
.intro-promo-fineprint {
  font-size: 12.5px; color: #78350f; opacity: .9; line-height: 1.4;
}
.intro-promo-fineprint s { color: #a16207; }

.intro-promo-right {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  min-width: 160px;
}
.intro-promo-codelabel {
  font-size: 11px; font-weight: 600; color: #92400e; opacity: .85;
  letter-spacing: .04em; text-transform: uppercase; text-align: center;
}
.intro-promo-codechip {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px; padding: 12px 18px;
  background: #ffffff;
  border: 2px dashed #b45309;
  border-radius: 8px;
  cursor: pointer;
  font: inherit;
  transition: transform .12s ease, box-shadow .12s ease, background .12s;
}
.intro-promo-codechip:hover {
  background: #fffbeb;
  box-shadow: 0 4px 12px rgba(180,83,9,.25);
  transform: translateY(-1px);
}
.intro-promo-codechip:active { transform: translateY(0); }
.intro-promo-codechip-copied {
  background: #d1fae5;
  border-color: #059669;
}
.intro-promo-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 800; font-size: 17px; letter-spacing: .1em;
  color: #b45309;
}
.intro-promo-codechip-copied .intro-promo-code { color: #059669; }
.intro-promo-copyicon { font-size: 14px; opacity: .8; }

/* Subtle pulse for users who arrived from the email's Intro CTA so they
   can immediately spot the offer they came for. Fires twice and stops. */
@keyframes intro-promo-pulse {
  0%   { box-shadow: 0 4px 18px rgba(245,158,11,.18), inset 0 1px 0 rgba(255,255,255,.4); }
  50%  { box-shadow: 0 6px 28px rgba(245,158,11,.45), inset 0 1px 0 rgba(255,255,255,.4); }
  100% { box-shadow: 0 4px 18px rgba(245,158,11,.18), inset 0 1px 0 rgba(255,255,255,.4); }
}
.intro-promo-banner-pulse {
  animation: intro-promo-pulse 1.4s ease-in-out 2;
}

@media (max-width: 480px) {
  .intro-promo-banner { flex-direction: column; align-items: stretch; gap: 12px; }
  /* When the parent switches to column direction, the left side's
     `flex: 1 1 240px` (sized for a 240px desktop COLUMN WIDTH) becomes a
     240px MIN-HEIGHT — inflating the price block with empty space below
     the fineprint. Reset to auto so it sizes to content. */
  .intro-promo-left  { flex: 0 0 auto; }
  .intro-promo-right { min-width: 0; }
}

.plan-grid {
  display: grid; gap: 16px;
  grid-template-columns: 1fr;
  margin: 16px 0 24px;
}
@media (min-width: 720px) {
  .plan-grid { grid-template-columns: 1fr 1fr; }
}
.plan-card {
  position: relative;
  padding: 24px 22px;
  border-radius: var(--radius);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow);
}
.plan-card-featured {
  border-color: rgba(45,212,191,.45);
  box-shadow: 0 10px 40px rgba(20,184,166,.12);
  background: linear-gradient(160deg, rgba(45,212,191,.08), var(--glass) 70%);
}
.plan-ribbon {
  position: absolute; top: -10px; right: 18px;
  padding: 3px 10px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  color: #0a0f1f;
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
  border-radius: 999px;
}
.plan-name {
  font-size: 14px; font-weight: 600; letter-spacing: .02em;
  color: var(--muted); text-transform: uppercase;
}
.plan-price { margin: 6px 0 2px; display: flex; align-items: baseline; gap: 6px; }
.plan-amount { font-size: 34px; font-weight: 700; }
.plan-per    { color: var(--muted); font-size: 14px; }
.plan-sub    { font-size: 13px; margin-bottom: 14px; }
.plan-cta    { width: 100%; }
.plan-cta[disabled] { opacity: .6; cursor: not-allowed; }
.plan-points {
  list-style: none; padding: 0; margin: 14px 0 0;
  font-size: 14px; color: var(--muted);
}
.plan-points li { padding: 4px 0; }
.plan-points li::before { content: "✓ "; color: #5eead4; font-weight: 700; }

.compare-card table.compare { width: 100%; border-collapse: collapse; font-size: 14px; }
.compare-card .compare th,
.compare-card .compare td {
  padding: 10px 8px;
  border-bottom: 1px solid var(--glass-border);
  text-align: left;
}
.compare-card .compare th:nth-child(2),
.compare-card .compare th:nth-child(3),
.compare-card .compare td.cmp-cell {
  text-align: center; width: 72px;
}
.compare-card .cmp-pro { color: #5eead4; font-weight: 700; }

.faq-card p { margin: 8px 0; color: var(--muted); font-size: 14px; }
.faq-card p strong { color: var(--text); }

/* Home hero free-tier quota strip */
.home-quota {
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: var(--radius-s);
  background: var(--glass);
  border: 1px solid var(--glass-border);
}
.home-quota-done {
  border-color: rgba(251,191,36,.45);
  background: rgba(251,191,36,.06);
}
.home-quota-label {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 8px;
}
.home-quota-label strong { color: var(--text); }
.home-quota-label .link { color: #5eead4; text-decoration: none; font-weight: 600; }
.home-quota-bar {
  height: 6px;
  background: rgba(255,255,255,.06);
  border-radius: 999px; overflow: hidden;
}
.home-quota-bar > span {
  display: block; height: 100%;
  background: linear-gradient(90deg, #2dd4bf, #0ea5e9);
  border-radius: 999px;
  transition: width .3s ease;
}
.home-quota-done .home-quota-bar > span { background: linear-gradient(90deg, #fbbf24, #f97316); }

/* Practice-filter quota banner (above the filter form) */
.quota-banner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin: 4px 0 14px;
  padding: 12px 14px;
  border-radius: var(--radius-s);
  background: linear-gradient(135deg, rgba(45,212,191,.08), rgba(14,165,233,.06));
  border: 1px solid rgba(45,212,191,.30);
}
.quota-banner-done {
  background: rgba(251,191,36,.08);
  border-color: rgba(251,191,36,.45);
}
.quota-text { font-size: 13.5px; color: var(--text); }
.quota-text strong { color: var(--text); }
.quota-cta { white-space: nowrap; }

/* Account page subscription pill — bumped up so the Pro/Free state reads
   at a glance from the right side of the Subscription row, instead of
   getting lost next to the heading. */
.sub-pill {
  display: inline-block;
  padding: 6px 16px;
  border-radius: 999px;
  font-size: 14px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase;
}
.sub-pill-pro {
  color: #0f766e;
  background: linear-gradient(135deg, rgba(94,234,212,.35), rgba(45,212,191,.20));
  border: 1px solid rgba(45,212,191,.55);
  box-shadow: 0 2px 8px rgba(45,212,191,.18), inset 0 1px 0 rgba(255,255,255,.18);
}
.sub-pill-free {
  color: var(--muted);
  background: var(--glass);
  border: 1px solid var(--glass-border);
}

/* ─── "Edited" badge ────────────────────────────────────────────────── */
.tag-edited {
  color: #5eead4;
  background: rgba(45,212,191,.12);
  border-color: rgba(45,212,191,.30);
}

/* ─── Modal overlay (edit form) ──────────────────────────────────────── */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(5,10,25,.45);
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  display: flex; align-items: flex-start; justify-content: center;
  z-index: 100;
  padding: 20px 12px;
  overflow-y: auto;
}
.modal-card {
  background: var(--glass-strong);
  backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur-lg)) saturate(var(--saturate));
  color: var(--text);
  border: 1px solid var(--glass-border-strong);
  border-radius: var(--radius);
  width: 100%; max-width: 640px;
  padding: 24px;
  box-shadow: var(--shadow-hover);
  margin: auto 0;
}
.modal-card h2 { margin-bottom: 4px; }

.edit-form { display: flex; flex-direction: column; gap: 14px; margin-top: 14px; }
.edit-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-dim); }
.edit-form label > span { font-weight: 600; }
.edit-form input, .edit-form textarea, .edit-form select {
  font: inherit; color: var(--text);
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s); padding: 10px 12px;
  width: 100%; box-sizing: border-box;
  resize: vertical;
  transition: border-color .15s, box-shadow .15s;
}
.edit-form input:focus, .edit-form textarea:focus, .edit-form select:focus {
  outline: none;
  border-color: rgba(45,212,191,.6);
  box-shadow: 0 0 0 3px rgba(45,212,191,.18);
}
.two-col-fields { display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 640px) { .two-col-fields { grid-template-columns: 1fr 1fr; } }
.modal-actions {
  display: flex; justify-content: flex-end; gap: 10px; margin-top: 8px;
  flex-wrap: wrap;
}

/* ─── Admin view ─────────────────────────────────────────────────────── */
.admin-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 12px; flex-wrap: wrap; margin-bottom: 12px;
}
.admin-head-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Admin hub hero — distinguishes the admin landing from the rest of the
   app with a warmer amber→coral gradient so a misclick into admin land
   reads instantly. Sits at the top of /admin before the nav cards.
   Same shape as the dashboard hero, different palette. */
/* Admin hero — same calm-clinical card shape as user-facing hero, but
   uses the --warn (amber) accent stripe to distinguish ops console
   from study surfaces. The previous orange→rose gradient panel + h1
   read as too consumer-y for an internal tool; the amber stripe
   keeps the "different from study pages" semantic without shouting. */
.admin-hero {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  padding: 20px 22px 18px 26px; margin: 4px 0 14px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.admin-hero::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--warn);
  border-radius: var(--radius) 0 0 var(--radius);
}
.admin-hero-text { flex: 1 1 auto; min-width: 0; }
.admin-hero-eyebrow {
  font-size: var(--text-xs); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--warn);
  margin-bottom: 4px;
}
.admin-hero-text h1 {
  margin: 0 0 6px;
  font-size: var(--text-2xl); line-height: 1.2;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.011em;
  background: none;
  -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: initial;
}
.admin-hero-sub {
  margin: 0;
  font-size: var(--text-base); line-height: 1.5;
  color: var(--text-dim);
}
.admin-hero-side { flex: 0 0 auto; }
@media (max-width: 540px) {
  .admin-hero { padding: 16px 16px 14px 22px; }
  .admin-hero-text h1 { font-size: var(--text-xl); }
  .admin-hero-sub { font-size: var(--text-sm); }
}

/* ─── Images inside quiz cards ───────────────────────────────────────── */
.quiz-figure { margin: 14px 0 18px; text-align: center; }
.quiz-figure .quiz-img-wrap { margin: 0; }
.quiz-img-caption {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--muted);
  font-style: italic;
  line-height: 1.4;
  text-align: center;
}
.feedback .quiz-figure { margin: 10px 0 0; }
/* .quiz-img-wrap was an <a target="_blank"> until the in-app lightbox
   landed — now a <button> that opens the fullscreen viewer. Reset all
   button-default chrome so the styling is identical to the old anchor. */
.quiz-img-wrap {
  display: block;
  margin: 14px 0 18px;
  text-align: center;
  text-decoration: none;
  background: none;
  border: 0;
  padding: 0;
  width: 100%;
  cursor: zoom-in;
  font: inherit;
  color: inherit;
}
.quiz-img-wrap:focus-visible {
  outline: 2px solid rgba(45,212,191,.55);
  outline-offset: 2px;
  border-radius: var(--radius-s);
}
.quiz-img {
  max-width: 100%;
  max-height: 360px;
  border-radius: var(--radius-s);
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  cursor: zoom-in;
  box-shadow: 0 6px 20px rgba(3,8,24,.20);
}
.feedback .quiz-img-wrap { margin: 10px 0 0; }
.feedback .quiz-img { max-height: 260px; }

/* ─── Image field (in edit modal) ────────────────────────────────────── */
.image-field {
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  padding: 12px 14px;
  margin: 0;
}
.image-field legend { padding: 0 6px; font-weight: 600; color: var(--text-dim); font-size: 13px; }
.image-preview {
  display: flex; justify-content: center;
  background: var(--glass-weak);
  border-radius: var(--radius-s);
  padding: 12px; min-height: 80px;
  margin-bottom: 10px;
  border: 1px solid var(--glass-border);
}
.image-preview-img { max-width: 100%; max-height: 220px; border-radius: 6px; background: var(--glass); }
.image-empty { font-size: 13px; }
.image-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.image-upload-btn { position: relative; cursor: pointer; }
.image-progress { font-size: 13px; flex: 1; min-width: 140px; }
.image-caption-label {
  display: block;
  margin-top: 12px;
  font-size: 13px;
  color: var(--text-dim);
}
.image-caption-label > span { display: block; margin-bottom: 4px; }
.image-caption-label input {
  width: 100%;
  padding: 8px 10px;
  font-size: 14px;
  border-radius: var(--radius-s);
  border: 1px solid var(--glass-border);
  background: var(--glass);
  color: var(--text);
}

.edit-list { list-style: none; padding: 0; margin: 0; }
.edit-item {
  padding: 14px 0;
  border-bottom: 1px solid var(--glass-border);
  display: flex; flex-direction: column; gap: 8px;
}
.edit-item:last-child { border-bottom: none; }
.edit-meta { display: flex; gap: 10px; flex-wrap: wrap; font-size: 13px; }
.edit-id { font-weight: 700; color: var(--primary); }
.edit-preview { font-size: 14px; color: var(--text); line-height: 1.5; }
.edit-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.edit-actions .btn { padding: 6px 12px; min-height: 36px; font-size: 13px; }

/* ─── My Account page ────────────────────────────────────────────────── */
/* Hero header — the personal landing zone for /account.
   Avatar + name + email + Pro chip in a single soft-gradient panel.
   Mirrors the dashboard hero pattern but with a colder, neutral
   gradient so the page reads "settings" rather than "stats". */
/* Account hero — same calm-clinical card pattern as dashboard / admin
   heroes. Sky-blue accent stripe distinguishes "settings" surface from
   "study" (teal) and "ops" (amber). Avatar bubble flat-tonal slate. */
.account-hero {
  position: relative;
  display: flex; align-items: center; gap: 18px;
  padding: 20px 22px 18px 26px; margin: 4px 0 14px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-1);
  flex-wrap: wrap;
  overflow: hidden;
}
.account-hero::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--accent-sky);
  border-radius: var(--radius) 0 0 var(--radius);
}
.account-hero-avatar {
  flex: 0 0 auto;
  width: 72px; height: 72px;
  display: flex; align-items: center; justify-content: center;
  font-size: 38px; line-height: 1;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.account-hero-info { flex: 1 1 auto; min-width: 0; }
.account-hero-eyebrow {
  font-size: var(--text-xs); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--accent-sky);
  margin-bottom: 4px;
}
.account-hero-info h1 {
  margin: 0 0 2px;
  font-size: var(--text-xl); line-height: 1.2;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.011em;
  word-break: break-word;
  background: none;
  -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: initial;
}
.account-hero-email {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-dim);
  word-break: break-all;
}
.account-hero-side { flex: 0 0 auto; }
@media (max-width: 540px) {
  .account-hero { padding: 16px 16px 14px 22px; gap: 14px; }
  .account-hero-avatar { width: 56px; height: 56px; font-size: 30px; }
  .account-hero-info h1 { font-size: var(--text-lg); }
}

/* Stat grid in the "Your study data" card — three stat tiles with the
   same gradient numerals used on the dashboard, so the data feels live
   and visual rather than a flat one-line summary. */
.account-stat-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
@media (max-width: 540px) { .account-stat-grid { grid-template-columns: repeat(3, 1fr); gap: 8px; } }
.account-stat {
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  padding: 14px 10px;
  text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}
.account-stat-num {
  font-size: 22px; font-weight: 700;
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.account-stat-lbl {
  font-size: 11.5px; color: var(--muted);
  margin-top: 4px; letter-spacing: .02em;
}

.account .account-sub { margin-top: -4px; margin-bottom: 16px; }
.account-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; padding: 10px 0;
  border-bottom: 1px dashed var(--glass-border);
  font-size: 14px;
}
.account-row:last-of-type { border-bottom: none; }
.account-lbl { color: var(--text-dim); flex: 0 0 auto; }
.account-val { color: var(--text); text-align: right; word-break: break-all; min-width: 0; }
.account-val.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 12px; color: var(--muted);
}
.account-form { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }
.account-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-dim); }

/* Change-password form — narrower than full-card width so the inputs don't
   stretch across the whole subscription/account card. Field-shaped controls
   read better when they're roughly the width of the data they accept. */
#pw-form { max-width: 420px; }

.account-form input {
  padding: 12px 14px; font-size: 16px; border-radius: var(--radius-s);
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  color: var(--text); font: inherit;
  transition: border-color .15s, box-shadow .15s;
}
.account-form input:focus {
  outline: none;
  border-color: rgba(45,212,191,.6);
  box-shadow: 0 0 0 3px rgba(45,212,191,.18);
}
.account-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
.account-stats { display: flex; flex-wrap: wrap; gap: 18px; color: var(--text-dim); font-size: 14px; }
.stat-inline strong { color: var(--primary); font-variant-numeric: tabular-nums; font-size: 16px; margin-right: 4px; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
.small { font-size: 12px; }
.danger-zone {
  border-color: rgba(239,68,68,.40);
  background:
    linear-gradient(180deg, rgba(239,68,68,.10), transparent 45%),
    var(--glass);
}
.danger-zone h3 { color: var(--bad); }

/* Free-user upgrade nudge on /account — replaces the old subscription card
   that used to render for free users with nothing to manage. */
.account-upsell {
  border-color: rgba(45,212,191,.35);
  background:
    linear-gradient(180deg, rgba(45,212,191,.08), transparent 70%),
    var(--glass);
}

/* The lone "Sign out" card — keep it visually quiet so it doesn't read as
   a primary action. */
.account-signout { padding-top: 12px; padding-bottom: 12px; }

/* Hint paragraph at the bottom of /account telling the user to email us if
   they want a reset. The destructive action lives on /admin/users now. */
.account-reset-hint {
  margin: 10px 4px 0;
  text-align: center;
  opacity: .8;
}

/* Admin danger zone inside the user-detail modal at /admin/users. Visually
   flagged red so it's obviously destructive, but compact so it doesn't
   dominate the modal layout. */
.admin-danger {
  border: 1px solid rgba(239,68,68,.35);
  background:
    linear-gradient(180deg, rgba(239,68,68,.10), transparent 70%),
    var(--glass-weak);
  border-radius: var(--radius-s);
  padding: 12px 14px;
}

/* ─── Personal bests card ────────────────────────────────────────────── */
.personal-bests h3 { margin-bottom: 14px; }
.pb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
}
.pb {
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  padding: 16px 12px;
  text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
}
.pb-num {
  font-size: 30px; font-weight: 800;
  background: linear-gradient(135deg, #fbbf24, #f59e0b);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.pb-lbl { font-size: 13px; color: var(--text-dim); font-weight: 600; margin-top: 4px; }
.pb-sub { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* ─── Answer reveal micro-animations ─────────────────────────────────── */
@keyframes sv-bounce {
  0%   { transform: scale(1);    }
  35%  { transform: scale(1.035);}
  60%  { transform: scale(0.99); }
  100% { transform: scale(1);    }
}
@keyframes sv-shake {
  0%,100% { transform: translateX(0); }
  20%     { transform: translateX(-4px); }
  40%     { transform: translateX(4px);  }
  60%     { transform: translateX(-3px); }
  80%     { transform: translateX(2px);  }
}
@keyframes sv-pop {
  0%   { transform: scale(0.2); opacity: 0; }
  70%  { transform: scale(1.1); opacity: 1; }
  100% { transform: scale(1);   opacity: 1; }
}
@keyframes sv-slide-down {
  0%   { opacity: 0; transform: translateY(-8px); }
  100% { opacity: 1; transform: translateY(0);    }
}

.choice.is-correct         { animation: sv-bounce 380ms ease-out; }
.choice.is-correct .letter { animation: sv-pop 340ms cubic-bezier(.2,1.2,.3,1) 80ms both; }
.choice.is-wrong           { animation: sv-shake 320ms ease-out; }
.feedback:not(.hidden)     { animation: sv-slide-down 260ms ease-out both; }
[data-role="actions"]:not(.hidden) { animation: sv-slide-down 300ms ease-out 80ms both; }

/* Toggle row (practice filters) */
.toggle-row {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border); border-radius: var(--radius-s);
  cursor: pointer; font-size: 14px;
}
.toggle-row input[type="checkbox"] { transform: scale(1.1); accent-color: var(--primary); }

@media (prefers-reduced-motion: reduce) {
  .choice.is-correct,
  .choice.is-wrong,
  .feedback:not(.hidden),
  [data-role="actions"]:not(.hidden),
  .choice.is-correct .letter {
    animation: none !important;
  }
}

/* ─── Exam question overview palette ─────────────────────────────────── */
.exam-bar-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
}
.exam-bar-actions .btn { padding: 8px 14px; min-height: 38px; font-size: 13px; }

.overview-modal {
  max-width: 560px;
  display: flex; flex-direction: column; gap: 14px;
}
.overview-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px;
}
.overview-head h2 { margin: 0; }

.overview-summary {
  display: flex; flex-wrap: wrap; gap: 14px 18px;
  padding: 10px 14px;
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  font-size: 13px; color: var(--text-dim);
}
.ov-legend { display: inline-flex; align-items: center; gap: 6px; }
.ov-legend strong { color: var(--text); font-variant-numeric: tabular-nums; }
.ov-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--glass-weak); border: 1px solid var(--glass-border);
}
.ov-dot.answered {
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
  border-color: rgba(255,255,255,.3);
  box-shadow: 0 0 6px rgba(45,212,191,.5);
}
.ov-dot.current {
  background: var(--accent);
  border-color: rgba(251,191,36,.6);
  box-shadow: 0 0 6px rgba(251,191,36,.6);
}

.overview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
  gap: 6px;
  max-height: 52vh;
  overflow-y: auto;
  padding: 4px 2px;
  /* faint fade at edges so scrollability is obvious */
  -webkit-mask-image: linear-gradient(180deg, transparent, black 8px, black calc(100% - 8px), transparent);
          mask-image: linear-gradient(180deg, transparent, black 8px, black calc(100% - 8px), transparent);
}

.overview-tile {
  aspect-ratio: 1;
  min-height: 44px;
  display: grid; place-items: center;
  padding: 0;
  font: 600 14px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: transform .08s, border-color .15s, box-shadow .15s, background .15s, color .15s;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}
.overview-tile:hover {
  transform: translateY(-1px);
  color: var(--text);
  border-color: var(--glass-border-strong);
  box-shadow: 0 4px 14px rgba(3,8,24,.22), inset 0 1px 0 rgba(255,255,255,.09);
}
.overview-tile:active { transform: translateY(0); }
.overview-tile.answered {
  background: linear-gradient(135deg, #2dd4bf 0%, #0ea5e9 100%);
  color: white;
  border-color: rgba(255,255,255,.20);
  box-shadow: 0 4px 14px rgba(14,165,233,.28), inset 0 1px 0 rgba(255,255,255,.25);
}
.overview-tile.answered:hover {
  box-shadow: 0 6px 20px rgba(14,165,233,.38), inset 0 1px 0 rgba(255,255,255,.30);
}
.overview-tile.current {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  color: var(--text);
  background: linear-gradient(135deg, rgba(251,191,36,.22), rgba(251,191,36,.08));
  border-color: rgba(251,191,36,.55);
}
.overview-tile.current.answered {
  /* Both: teal fill + amber ring */
  background: linear-gradient(135deg, #2dd4bf 0%, #0ea5e9 100%);
  color: white;
}

@media (max-width: 480px) {
  .overview-grid { grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); gap: 5px; }
  .overview-tile { min-height: 40px; font-size: 13px; }
}

/* ─── Personal notes panel ───────────────────────────────────────────── */
.note-panel {
  margin-top: 14px;
  border-radius: var(--radius-sm);
  background: var(--glass-weak);
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
  overflow: hidden;
}
.note-panel[open] {
  border-color: var(--glass-border-strong);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 4px 14px rgba(3,8,24,.18);
}
.note-summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 14px;
  color: var(--text-dim);
  user-select: none;
  transition: color .15s, background .15s;
}
.note-summary::-webkit-details-marker { display: none; }
.note-summary::before {
  content: "▸";
  display: inline-block;
  margin-right: 6px;
  color: var(--muted);
  transition: transform .15s;
  font-size: 12px;
}
.note-panel[open] .note-summary::before { transform: rotate(90deg); }
.note-summary:hover { color: var(--text); background: rgba(255,255,255,.02); }
.note-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 1;
}
.note-label.has-note::after {
  content: "✓";
  color: var(--accent);
  font-size: 12px;
  font-weight: 700;
}
.note-status {
  font-size: 12px;
  color: var(--muted);
}
.note-status.saving { color: var(--muted); }
.note-status.saved  { color: var(--accent); }
.note-status.error  { color: var(--bad); }
.note-body {
  padding: 0 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.note-input {
  width: 100%;
  resize: vertical;
  min-height: 80px;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text);
  background: rgba(10,15,30,.28);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-xs);
  outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.03);
}
.note-input::placeholder { color: var(--muted); }
.note-input:hover { border-color: var(--glass-border-strong); }
.note-input:focus {
  border-color: var(--accent);
  background: rgba(10,15,30,.38);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04), 0 0 0 3px rgba(45,212,191,.18);
}
.note-meta {
  font-size: 11px;
  color: var(--muted);
  min-height: 14px;
}
.note-meta.small { font-size: 11px; }

/* ─── Flag-for-review button ────────────────────────────────────────── */
.btn-flag {
  font-size: 18px;
  padding: 4px 10px;
  border-radius: var(--radius-xs);
  transition: color .15s, transform .1s, background .15s, box-shadow .15s;
}
.btn-flag:hover { color: #fbbf24; transform: scale(1.12); }
.btn-flag.on {
  color: #fbbf24;
  background: linear-gradient(135deg, rgba(251,191,36,.22), rgba(251,191,36,.08));
  box-shadow: 0 0 0 1px rgba(251,191,36,.35), 0 2px 8px rgba(251,191,36,.25);
}
.btn-flag.on:hover {
  box-shadow: 0 0 0 1px rgba(251,191,36,.55), 0 4px 12px rgba(251,191,36,.38);
}

/* ─── Overview palette: flagged states ──────────────────────────────── */
.overview-tile.flagged {
  border-color: rgba(251,191,36,.55);
  background: linear-gradient(135deg, rgba(251,191,36,.16), rgba(251,191,36,.05));
  color: var(--text);
}
.overview-tile.answered.flagged {
  /* Answered + flagged: keep teal fill, amber border stays visible */
  background: linear-gradient(135deg, #2dd4bf 0%, #0ea5e9 100%);
  color: white;
  border-color: rgba(251,191,36,.75);
  box-shadow: 0 4px 14px rgba(14,165,233,.28), inset 0 1px 0 rgba(255,255,255,.25),
              0 0 0 1px rgba(251,191,36,.35);
}
.overview-tile .ov-pip {
  position: absolute;
  top: 3px;
  right: 4px;
  font-size: 10px;
  line-height: 1;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.35));
  pointer-events: none;
}
.overview-tile { position: relative; }
.ov-dot.flagged { background: #fbbf24; box-shadow: 0 0 0 1px rgba(251,191,36,.4); }

/* ─── Accuracy trend chart ──────────────────────────────────────────── */
.trend-card { padding: 18px 20px 16px; }
.trend-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin-bottom: 10px;
}
.trend-head h3 { margin: 0; }
.trend-summary {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.trend-current {
  font: 700 22px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
  background: linear-gradient(135deg, #2dd4bf 0%, #0ea5e9 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.trend-sub { font-size: 13px; }
.trend-delta {
  font-size: 12px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
}
.trend-delta.up   { color: #2dd4bf; border-color: rgba(45,212,191,.45); }
.trend-delta.down { color: #f87171; border-color: rgba(248,113,113,.45); }
.trend-delta.flat { color: var(--muted); }

.trend-chart-wrap {
  width: 100%;
  margin: 4px 0 8px;
}
.trend-chart {
  width: 100%;
  height: auto;
  max-height: 220px;
  display: block;
}
.trend-grid {
  stroke: var(--glass-border);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}
.trend-grid-mid { stroke: var(--glass-border-strong); }
.trend-ylabel,
.trend-xlabel {
  fill: var(--muted);
  font: 500 10px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
}
.trend-bar {
  fill: rgba(148,163,184,.32);
  transition: fill .15s;
}
.trend-bar:hover { fill: rgba(148,163,184,.55); }
.trend-line {
  stroke: #2dd4bf;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 1px 4px rgba(45,212,191,.45));
}
.trend-dot {
  fill: #0ea5e9;
  stroke: rgba(255,255,255,.9);
  stroke-width: 1.2;
  transition: r .15s;
}
.trend-dot:hover { r: 4.5; }

/* spinner-2026-05-05 — small reusable rotating ring. Three variants:
   · .spinner          inline 14px ring, sits next to text in a sentence
   · .spinner-lg       larger 28px ring, used in centered card states
   · .spinner-center   flex wrapper that centers .spinner-lg + a label
                       when the entire card body is the loading state.
   Honours prefers-reduced-motion by stopping rotation (the ring still
   shows, just doesn't spin — keeps the visual cue for accessibility
   without inducing motion sickness). */
.spinner,
.spinner-lg {
  display: inline-block;
  vertical-align: -3px;
  border-radius: 50%;
  border-style: solid;
  border-color: var(--glass-border, rgba(0,0,0,.18));
  border-top-color: var(--accent, #14b8a6);
  animation: spinner-rotate 0.85s linear infinite;
  flex: 0 0 auto;
}
.spinner {
  width: 14px; height: 14px;
  border-width: 2px;
  margin-right: 6px;
}
.spinner-lg {
  width: 28px; height: 28px;
  border-width: 3px;
}
.spinner-center {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 28px 12px;
}
.spinner-center .spinner-label {
  color: var(--muted, #94a3b8);
  font-size: 13px;
}
@keyframes spinner-rotate {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .spinner, .spinner-lg { animation: none; }
}

/* dashboard-patterns-2026-05-05 — day-of-week + hour-of-day study
   patterns. Two stacked bar panels in one card. Same visual language
   as the trend chart (subtle baseline + tabular numerals on labels)
   so the dashboard reads as one cohesive set of charts. */
.patterns-card { padding: 18px 20px 16px; }
.patterns-head {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 8px;
  margin-bottom: 8px;
}
.patterns-head h3 { margin: 0; }
.patterns-section { margin: 12px 0 4px; }
.patterns-section-head {
  margin-bottom: 4px;
  text-transform: uppercase; letter-spacing: .04em;
  font-weight: 600;
}
.patterns-chart {
  width: 100%; height: 140px;
  display: block;
}
.patterns-axis {
  stroke: var(--glass-border, rgba(0,0,0,.08));
  stroke-width: 1;
}
.patterns-bar {
  fill: url(#patterns-bar-gradient, #14b8a6);
  fill: #14b8a6;
  fill-opacity: .80;
  transition: fill-opacity .15s;
}
.patterns-bar:hover { fill-opacity: 1; }
.patterns-label {
  fill: var(--muted, #94a3b8);
  font: 500 10px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
}

/* dashboard-growth-curve-2026-05-05 — cumulative questions over the
   last 90 days. Stepped line with a subtle filled area underneath.
   Reads as "ever-rising progress" because the curve only goes up. */
.growth-card { padding: 18px 20px 16px; }
.growth-head {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 8px;
  margin-bottom: 8px;
}
.growth-head h3 { margin: 0; }
.growth-summary {
  display: flex; align-items: baseline; gap: 10px;
  flex-wrap: wrap;
}
.growth-total {
  font: 700 22px/1.1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: var(--accent, #14b8a6);
  font-variant-numeric: tabular-nums;
}
.growth-sub { font-size: 13px; }
.growth-chart-wrap {
  margin-top: 4px;
}
.growth-chart {
  width: 100%; height: 200px;
  display: block;
}
.growth-grid {
  stroke: var(--glass-border, rgba(0,0,0,.06));
  stroke-width: 1;
  stroke-dasharray: 2 4;
}
.growth-ylabel,
.growth-xlabel {
  fill: var(--muted, #94a3b8);
  font: 500 10px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
}
.growth-line {
  stroke: #14b8a6;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
  filter: drop-shadow(0 1px 4px rgba(20,184,166,.30));
}
.growth-area {
  fill: rgba(20,184,166,.12);
  stroke: none;
}

.trend-legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 12px;
  padding-top: 4px;
}
.trend-legend .ov-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 4px;
  vertical-align: -1px;
}

/* ─── Subject-mastery radar ──────────────────────────────────────────── */
.radar-card { padding: 18px 20px 14px; }
.radar-head {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 8px; margin-bottom: 4px;
}
.radar-head h3 { margin: 0; }
.radar-svg {
  width: 100%; max-width: 460px; height: auto;
  display: block; margin: 4px auto 0;
}
.radar-ring {
  /* !important guards against any later rule (theme override, dark-mode
     block, etc.) accidentally giving the ring polygons a solid fill —
     the user reported a dark polygon rendering inside the radar that
     looked like the rings were being filled black somewhere. */
  fill: none !important;
  stroke: var(--glass-border);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}
.radar-ring-outer {
  fill: none !important;
  stroke: var(--glass-border-strong);
  stroke-dasharray: none;
}
.radar-spoke {
  stroke: var(--glass-border);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}
.radar-value {
  /* Mockup-N palette: solid soft mint fill + deep teal stroke + matching
     deep-teal vertex dots. No drop-shadow, no rgba alpha — the alpha
     version blended unpredictably against the card surface in some
     themes (came out near-black on dark surfaces). Solid Teal 100
     reads as the same soft mint on any background. */
  fill: #9FE1CB !important;
  fill-opacity: 0.85;
  stroke: #0F6E56;
  stroke-width: 1.6;
  stroke-linejoin: round;
}
.radar-dot {
  fill: #0F6E56;
  stroke: none;
  transition: r .15s;
}
.radar-dot:hover { r: 5; }
.radar-label {
  /* Muted slate, not black — the mockup keeps non-weak labels quiet
     so the dark-red below-70% labels (.radar-label-weak) read as the
     callout. */
  fill: var(--text-dim, var(--muted));
  font: 500 11px/1.2 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.radar-tick {
  fill: var(--muted);
  font: 500 9px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
}
.radar-foot { margin: 6px 4px 0; text-align: center; }

/* ─── Bank-coverage forecast ──────────────────────────────────────────── */
.forecast-card { padding: 18px 20px 14px; }
.forecast-head {
  display: flex; justify-content: space-between; align-items: baseline;
  flex-wrap: wrap; gap: 8px; margin-bottom: 10px;
}
.forecast-head h3 { margin: 0; }
.forecast-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-bottom: 10px;
}
@media (max-width: 540px) {
  .forecast-stats { grid-template-columns: 1fr; }
}
.forecast-stat {
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  padding: 10px 12px;
}
.forecast-num {
  font-size: 22px; font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.forecast-num-of {
  font-size: 13px; font-weight: 600; color: var(--muted); margin-left: 2px;
}
.forecast-lbl {
  font-size: 12px; color: var(--text-dim); margin-top: 2px;
}
.forecast-sub {
  font-size: 11px; margin-top: 4px;
}

/* Verdict pill — color signals exam-readiness state. */
.forecast-verdict {
  margin: 4px 0 10px;
  padding: 9px 12px;
  border-radius: var(--radius-s);
  font-size: 13px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  line-height: 1.45;
}
.forecast-verdict.ok {
  color: #0f766e;
  background: rgba(45,212,191,.10);
  border-color: rgba(45,212,191,.40);
}
.forecast-verdict.warn {
  color: #92400e;
  background: rgba(251,191,36,.10);
  border-color: rgba(251,191,36,.40);
}
.forecast-verdict.bad {
  color: #991b1b;
  background: rgba(239,68,68,.10);
  border-color: rgba(239,68,68,.40);
}

/* "All covered" celebratory variant. */
.forecast-card.forecast-done {
  background: linear-gradient(180deg, rgba(45,212,191,.12), transparent 70%), var(--glass);
  border-color: rgba(45,212,191,.40);
}

.forecast-chart-wrap { margin: 4px 0 0; }
.forecast-chart {
  width: 100%; height: auto; max-height: 180px; display: block;
}
.forecast-grid {
  stroke: var(--glass-border);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}
.forecast-ylabel,
.forecast-xlabel {
  fill: var(--muted);
  font: 500 10px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-variant-numeric: tabular-nums;
}
.forecast-area {
  fill: rgba(45,212,191,.14);
}
.forecast-line {
  stroke: #2dd4bf;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 1px 4px rgba(45,212,191,.40));
}
.forecast-today-dot {
  fill: #14b8a6;
  stroke: rgba(255,255,255,.95);
  stroke-width: 1.5;
}
.forecast-exam-line {
  stroke: #f59e0b;
  stroke-width: 1.5;
  stroke-dasharray: 4 3;
}
.forecast-exam-label {
  fill: #b45309;
  font: 600 10px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* ─── Practice start page ───────────────────────────────────────────────
 * Replaces the old wall-of-filters with a quick-start hero (3-4 preset
 * buttons that one-tap into a deck) plus a collapsible "Customize"
 * section that hides the full filter form by default. Most users start
 * via a preset and never see the chip walls; power users get the same
 * full form behind a single toggle.
 */
.practice-start { padding: 22px 22px 18px; }
.practice-hero { margin-bottom: 16px; }
.practice-hero h2 { margin: 0 0 6px; }
.practice-hero p { margin: 0; }

/* Quiet "← back" link shown above the title in scoped modes (e.g.
   bookmarks-only). Subdued so it doesn't compete with the page title,
   but always reachable when the user wants to climb back up. */
.practice-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  padding: 4px 10px 4px 6px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  transition: color .15s, background .15s, border-color .15s;
}
.practice-back:hover {
  color: var(--text);
  background: var(--glass);
  border-color: var(--glass-border-strong);
}

/* Slim toolbar above the in-session quiz card with a "← Back to setup"
   pill on the left and the question progress on the right. The back
   button ends the session destructively (with confirm) so the user can
   pick a fresh deck without first being trapped in the resume prompt. */
.session-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  padding: 0 4px;
}
.session-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  padding: 4px 12px 4px 8px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  cursor: pointer;
  transition: color .15s, background .15s, border-color .15s;
}
.session-back-btn:hover {
  color: var(--text);
  background: var(--glass);
  border-color: var(--glass-border-strong);
}
.session-toolbar-progress {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.practice-presets {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  /* Was margin: 8px 0 18px. Now that the preset tiles sit AFTER the
     Customize-filters Start button, they need visible separation —
     otherwise the row reads as a chained CTA cluster instead of a
     secondary "or pick a preset" exit. Border-top hairline + tighter
     padding-top + an "Or pick a preset" eyebrow (via ::before grid-
     spanning row) give the section its own space. */
  margin: 28px 0 18px;
  padding-top: 22px;
  border-top: 1px solid var(--border, var(--glass-border));
}
.practice-presets::before {
  content: "Or pick a preset";
  grid-column: 1 / -1;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim, var(--muted));
  margin: -4px 0 4px;
}
@media (min-width: 600px) {
  .practice-presets { grid-template-columns: 1fr 1fr; }
}

.practice-preset {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  text-align: left;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  font: inherit;
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s, background .15s;
}
.practice-preset:hover {
  transform: translateY(-1px);
  border-color: rgba(45,212,191,.55);
  box-shadow: 0 6px 18px rgba(15,23,42,.10);
  background: var(--glass);
}
.practice-preset:active { transform: translateY(0); }

/* Primary preset (Quick start) gets the strongest visual weight — this
   is the action ~80% of users want and the page should make that
   obvious without a dozen other competing chips. */
.practice-preset-primary {
  background:
    radial-gradient(ellipse at top left, rgba(45,212,191,.16), transparent 60%),
    var(--glass-weak);
  border-color: rgba(45,212,191,.55);
  box-shadow: 0 4px 14px rgba(45,212,191,.18);
}
.practice-preset-primary:hover {
  border-color: rgba(45,212,191,.80);
  box-shadow: 0 8px 22px rgba(45,212,191,.28);
}

.practice-preset-icon {
  font-size: 28px;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,.45), transparent 55%),
    linear-gradient(135deg, rgba(94,234,212,.45), rgba(20,184,166,.65));
  border: 1.5px solid rgba(13,148,136,.45);
  box-shadow:
    0 4px 10px rgba(13,148,136,.20),
    inset 0 -2px 4px rgba(0,0,0,.08),
    inset 0 2px 4px rgba(255,255,255,.30);
}
.practice-preset-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.practice-preset-title {
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
  line-height: 1.2;
}
.practice-preset-sub {
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.35;
}

/* The collapsible "Customize" disclosure that hides the existing form. */
.practice-customize {
  border-top: 1px solid var(--glass-border);
  padding-top: 12px;
  margin-top: 4px;
}
.practice-customize-summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  cursor: pointer;
  user-select: none;
  font-weight: 600;
  font-size: 14px;
  color: var(--text-dim);
  transition: color .15s;
}
.practice-customize-summary::-webkit-details-marker { display: none; }
.practice-customize-summary:hover { color: var(--text); }
.practice-customize-chevron {
  display: inline-block;
  transition: transform .2s ease;
  color: var(--muted);
  font-size: 14px;
  line-height: 1;
}
.practice-customize[open] .practice-customize-chevron {
  transform: rotate(180deg);
  color: var(--primary, #14b8a6);
}
.practice-customize > .filters {
  margin-top: 12px;
}


/* ─── Empty states ───────────────────────────────────────────────────────
 * Centered card-like block used wherever the app would otherwise just
 * print "No X." in muted text. The icon medallion + warm copy + CTA
 * pattern turns dead-end surfaces into pull-back moments.
 *
 * Variant theming follows the same per-category-color pattern used in
 * the badges gallery: each variant sets `--es-c1` / `--es-c2` /
 * `--es-c3` and the inner elements consume them. Add a new variant by
 * defining the three colors in a new selector below.
 */
.empty-state {
  --es-c1: rgba(94,234,212,.55);
  --es-c2: #14b8a6;
  --es-c3: rgba(45,212,191,.10);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 32px 20px 28px;
  background:
    radial-gradient(ellipse at 50% 0%, var(--es-c3) 0%, transparent 70%),
    transparent;
}
.empty-state-celebrate {
  --es-c1: rgba(110,231,183,.55);
  --es-c2: #10b981;
  --es-c3: rgba(16,185,129,.14);
}
.empty-state-info {
  --es-c1: rgba(186,230,253,.55);
  --es-c2: #0284c7;
  --es-c3: rgba(2,132,199,.12);
}
.empty-state-warn {
  --es-c1: rgba(253,230,138,.55);
  --es-c2: #d97706;
  --es-c3: rgba(217,119,6,.12);
}

.empty-state-icon {
  font-size: 38px;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,.45), transparent 55%),
    linear-gradient(135deg, var(--es-c1) 0%, var(--es-c2) 100%);
  border: 2px solid color-mix(in srgb, var(--es-c2) 60%, transparent);
  box-shadow:
    0 6px 18px color-mix(in srgb, var(--es-c2) 28%, transparent),
    inset 0 -2px 6px rgba(0,0,0,.08),
    inset 0 2px 4px rgba(255,255,255,.30);
}
/* Slow ambient pulse — same vibe as the unlocked-badge medallions, but
   gentler. Pulls the eye to the icon without distracting from the
   action buttons below. */
.empty-state-celebrate .empty-state-icon {
  animation: empty-state-pulse 2.6s ease-in-out infinite;
}
@keyframes empty-state-pulse {
  0%, 100% { box-shadow: 0 6px 18px color-mix(in srgb, var(--es-c2) 28%, transparent), inset 0 -2px 6px rgba(0,0,0,.08), inset 0 2px 4px rgba(255,255,255,.30); }
  50%      { box-shadow: 0 8px 26px color-mix(in srgb, var(--es-c2) 50%, transparent), inset 0 -2px 6px rgba(0,0,0,.08), inset 0 2px 4px rgba(255,255,255,.30); }
}

.empty-state-title {
  margin: 4px 0 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--ink, var(--text));
  line-height: 1.2;
}
.empty-state-body {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-dim);
  max-width: 38ch;
}
.empty-state-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--glass-weak);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 12.5px;
}
.empty-state-actions {
  display: inline-flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 6px;
}

/* Compact variant — for empty states inside narrower card slots (e.g.
   the user-detail modal in /admin/users). Half the vertical padding,
   smaller icon medallion, tighter type. */
.empty-state-compact {
  padding: 16px 12px 14px;
  gap: 8px;
}
.empty-state-compact .empty-state-icon {
  width: 48px;
  height: 48px;
  font-size: 24px;
}
.empty-state-compact .empty-state-title { font-size: 15px; }
.empty-state-compact .empty-state-body  { font-size: 13px; }


/* Onboarding tour styles removed. The in-app spotlight tour was torn
   out — all .ob-* selectors and the matching @media (max-width: 480px)
   override deleted as one block. For lightweight inline help, prefer
   a <details> disclosure inside the relevant card (see .mosaic-help
   in dashboard.js) over a modal overlay engine. */


/* ─── Google sign-in button ─────────────────────────────────────────── */
.btn-google {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px 18px;
  background: #ffffff;
  color: #1f1f1f;
  border: 1px solid #dadce0;
  border-radius: var(--radius-s);
  font: 500 15px/1 "Google Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  min-height: 44px;
  cursor: pointer;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: 0 1px 2px rgba(60,64,67,.08), 0 1px 3px rgba(60,64,67,.12);
  transition: box-shadow .15s, background .15s, border-color .15s, transform .08s;
}
.btn-google:hover {
  background: #f8faff;
  border-color: #d2e3fc;
  box-shadow: 0 1px 3px rgba(60,64,67,.15), 0 4px 10px rgba(66,133,244,.18);
  transform: translateY(-1px);
}
.btn-google:active { transform: translateY(0); }
.btn-google:focus-visible {
  outline: none;
  border-color: #4285F4;
  box-shadow: 0 0 0 3px rgba(66,133,244,.28);
}
.btn-google .google-g {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  display: block;
}
.btn-google span { font-weight: 500; letter-spacing: .25px; }

@media (prefers-color-scheme: dark) {
  /* Keep Google's recommended light surface — their brand guidelines
     allow a dark variant, but light-on-white gives the cleanest logo read. */
  .btn-google { background: #ffffff; color: #1f1f1f; border-color: #dadce0; }
}


/* ─── Bulk image migration ──────────────────────────────────────────── */
.bulk-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.bulk-banner {
  margin-top: 12px;
  padding: 10px 14px;
  border-radius: var(--radius-s);
  font-size: 14px;
  background: linear-gradient(135deg, rgba(45,212,191,.22), rgba(14,165,233,.14));
  border: 1px solid rgba(45,212,191,.45);
  color: var(--text);
}
.bulk-banner code {
  padding: 1px 6px;
  background: rgba(10,15,30,.3);
  border-radius: 4px;
  font-size: 12px;
}
.bulk-list {
  display: grid;
  gap: 8px;
  max-height: 620px;
  overflow-y: auto;
  padding: 4px;
  margin: -4px;
}
.bulk-row {
  padding: 10px 14px;
  border-radius: var(--radius-xs);
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  font-size: 13px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: border-color .15s, background .15s;
}
.bulk-row[data-status="done"]     { border-color: rgba(45,212,191,.35); }
.bulk-row[data-status="error"]    { border-color: rgba(239,68,68,.45); background: rgba(239,68,68,.06); }
.bulk-row[data-status="fetching"],
.bulk-row[data-status="uploading"] { border-color: rgba(14,165,233,.5); }
.bulk-row-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.bulk-row-url a {
  color: var(--text-dim);
  text-decoration: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  word-break: break-all;
}
.bulk-row-url a:hover { color: var(--text); text-decoration: underline; }
.bulk-row-new a {
  color: #2dd4bf;
  text-decoration: none;
  font-size: 12px;
}
.bulk-row-new a:hover { text-decoration: underline; }
.bulk-row-note.bad {
  color: #fca5a5;
  font-size: 12px;
  background: rgba(239,68,68,.08);
  padding: 4px 8px;
  border-radius: 4px;
}
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--muted);
  line-height: 1.4;
}
.pill.ok   { background: linear-gradient(135deg, #2dd4bf, #0ea5e9); color: white; border-color: rgba(255,255,255,.2); }
.pill.bad  { background: rgba(239,68,68,.22); color: #fca5a5; border-color: rgba(239,68,68,.4); cursor: help; }
.pill.busy { background: linear-gradient(135deg, rgba(14,165,233,.3), rgba(45,212,191,.2)); color: #7dd3fc; border-color: rgba(14,165,233,.4); }
@keyframes sv-busy-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(14,165,233,.35); }
  70%  { box-shadow: 0 0 0 6px rgba(14,165,233,0); }
  100% { box-shadow: 0 0 0 0 rgba(14,165,233,0); }
}
.pill.busy { animation: sv-busy-pulse 1.5s ease-out infinite; }
@media (prefers-reduced-motion: reduce) { .pill.busy { animation: none; } }

/* ─── Exam history drill-down ───────────────────────────────────────────
   Each exam row has a "View questions" toggle that expands a detail row
   listing every question with the user's answer and the correct answer.
   Explanations are intentionally omitted so this reads like a quick
   post-mortem, not a re-study of the material. */
.exam-history-table .exam-row > td { vertical-align: middle; }
/* Wrap the table in a horizontal-scroll guard so it can never blow out
   the parent card on narrow screens. */
.exam-history-scroll { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.exam-history-table { min-width: 0; }
.exam-history-table .exam-date { white-space: nowrap; }
.exam-history-table .exam-details-cell { width: 1%; white-space: nowrap; }
.exam-details-toggle {
  padding: 4px 10px;
  font-size: 12px;
  line-height: 1.2;
  border-radius: 999px;
  white-space: nowrap;
}
/* Two labels in the View button — full prose on desktop, single word on
   mobile so it stops blowing out the row. */
.exam-details-toggle-short { display: none; }
@media (max-width: 640px) {
  /* On phones, abandon the table layout entirely and stack each exam as
     a card. The 5-column grid (Date / Score / % / Duration / View) can't
     fit a sub-360px viewport without horizontal scroll, and scrolling a
     summary table feels broken. Stack instead:
        Apr 12, 2026                            [View]
        42/50 · 84% · 47 min
     This way the exam list never overflows regardless of viewport width.
  */
  .exam-history-scroll { overflow-x: visible; }

  .exam-history-table,
  .exam-history-table thead,
  .exam-history-table tbody,
  .exam-history-table td { display: block; width: 100%; }
  /* tr rule excludes [hidden] explicitly — without :not(), the
     `display: block` here would beat the browser's UA stylesheet for
     [hidden]-on-tr (which sets display:none) and force every details
     row open by default. */
  .exam-history-table tr:not([hidden]) { display: block; width: 100%; }
  .exam-history-table tr[hidden] { display: none !important; }
  .exam-history-table thead { display: none; }

  .exam-history-table .exam-row {
    position: relative;
    padding: 12px 14px;
    border-bottom: 1px solid var(--glass-border);
  }
  .exam-history-table .exam-row:last-of-type { border-bottom: 0; }

  .exam-history-table .exam-row > td {
    padding: 0;
    border: 0;
  }

  /* Top line — bold date, with the View button absolute-positioned to
     the top-right so it doesn't fight the date for horizontal space. */
  .exam-history-table .exam-row > .exam-date {
    font-weight: 600;
    font-size: 14px;
    color: var(--text);
    margin-bottom: 2px;
    padding-right: 70px;        /* space for the absolute-positioned View btn */
    text-align: left;
  }

  /* Score / % / Duration collapse into one inline meta line under the
     date, separated by middle-dots. */
  .exam-history-table .exam-row > td:nth-child(2),
  .exam-history-table .exam-row > td:nth-child(3),
  .exam-history-table .exam-row > td:nth-child(4) {
    display: inline;
    color: var(--muted);
    font-size: 13px;
    text-align: left;
  }
  .exam-history-table .exam-row > td:nth-child(3)::before,
  .exam-history-table .exam-row > td:nth-child(4)::before {
    content: " · ";
    color: var(--glass-border-strong);
    margin: 0 2px;
  }

  /* View button pinned to the top-right of the card. */
  .exam-history-table .exam-row > .exam-details-cell {
    position: absolute;
    top: 10px;
    right: 12px;
    width: auto;
    text-align: right;
  }
  .exam-details-toggle { padding: 4px 10px; font-size: 11.5px; }
  .exam-details-toggle-full  { display: none; }
  .exam-details-toggle-short { display: inline; }

  /* The expanded details row — no longer a table cell, just a panel
     under the parent exam card. The :not([hidden]) selector matters: my
     `display: block` would otherwise override the [hidden] attribute and
     leave every details row open by default. Browsers map [hidden] to
     `display: none` via UA stylesheet, but author CSS at the same
     specificity wins. */
  .exam-history-table .exam-details-row:not([hidden]) {
    display: block;
    width: 100%;
  }
  .exam-history-table .exam-details-row > td {
    display: block;
    padding: 0 !important;
  }
}
.exam-details-row > td {
  padding: 0 !important;
  background: rgba(255,255,255,.02);
  border-top: 1px solid var(--glass-border);
}
.exam-q-list {
  list-style: none;
  margin: 0;
  padding: 10px 12px 14px;
  display: grid;
  gap: 10px;
}
.exam-q-item {
  border-radius: var(--radius-s);
  border: 1px solid var(--glass-border);
  background: var(--glass);
  padding: 10px 12px;
}
.exam-q-right   { border-left: 3px solid #10b981; }
.exam-q-wrong   { border-left: 3px solid #ef4444; }
.exam-q-skipped { border-left: 3px solid var(--muted); }
.exam-q-missing { border-left: 3px solid var(--glass-border); }
.exam-q-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}
.exam-q-num {
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
  letter-spacing: .04em;
  text-transform: uppercase;
}
.exam-q-status {
  font-size: 12px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.exam-q-status-right   { color: #10b981; background: rgba(16,185,129,.15); border-color: rgba(16,185,129,.35); }
.exam-q-status-wrong   { color: #f87171; background: rgba(239, 68, 68,.15); border-color: rgba(239, 68, 68,.35); }
.exam-q-status-skipped { color: var(--muted); background: rgba(148,163,184,.12); border-color: var(--glass-border); }
.exam-q-prompt {
  margin: 0 0 8px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
  font-weight: 600;
  /* Guard against an abnormally long unbroken token (URL, identifier)
     forcing the card wider than the viewport. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
.exam-q-line {
  margin: 4px 0;
  font-size: 13.5px;
  line-height: 1.5;
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.exam-q-label {
  font-weight: 700;
  color: var(--muted);
  min-width: 115px;
  flex-shrink: 0;
}
.exam-q-yours    { color: var(--text-dim); }
.exam-q-correct  { color: var(--text); }
.exam-q-correct .exam-q-label { color: #10b981; }

/* On narrow screens the 115px-min-width label crowds short answer text.
   Drop the min-width and shrink the type — the label still bolds clearly
   without forcing every line to be 115px wide. */
@media (max-width: 540px) {
  .exam-q-label { min-width: 0; font-size: 12px; }
  .exam-q-line  { font-size: 13px; }
  .exam-q-list  { padding: 8px; gap: 8px; }
  .exam-q-item  { padding: 8px 10px; }
}

/* ─── Badges & achievements ─────────────────────────────────────────────
   Free-for-all feature. Two surfaces: (a) a compact preview card on the
   dashboard showing the 6 most-recent unlocks, and (b) a full grid at
   /achievements grouped by category. */

/* Dashboard preview */
.achv-preview-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
}
.achv-preview-head h3 { margin: 0; }
.achv-preview-list {
  list-style: none;
  margin: 0 0 10px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.achv-preview-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(16,185,129,.18), rgba(14,165,233,.16));
  border: 1px solid rgba(16,185,129,.45);
  font-size: 13px;
  line-height: 1.2;
  color: var(--text);
}
.achv-preview-icon { font-size: 16px; }
.achv-preview-title { font-weight: 600; }
.achv-preview-foot {
  display: flex;
  justify-content: flex-end;
}
.achv-preview-foot .link { font-size: 13px; font-weight: 600; }

/* Full grid hero */
.achv-hero {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.achv-hero-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: wrap;
}
.achv-hero-title h2 { margin: 0 0 4px; }
.achv-hero-title p { margin: 0; }
.achv-hero-stat {
  text-align: right;
  flex-shrink: 0;
}
.achv-hero-num {
  font-size: 34px;
  font-weight: 800;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.achv-hero-total {
  font-size: 18px;
  color: var(--text-dim);
  font-weight: 600;
}
.achv-hero-lbl {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--muted);
  font-weight: 700;
  margin-top: 2px;
}
.achv-hero-foot { margin: 0; }

/* Shared progress bar */
.achv-bar {
  width: 100%;
  height: 6px;
  border-radius: 999px;
  background: var(--glass-border);
  overflow: hidden;
}
.achv-bar > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #10b981, #0ea5e9);
  transition: width .4s ease;
}

/* ─── Achievements gallery ──────────────────────────────────────────────
 *
 * Per-category color theming via [data-category] selectors. Colors are
 * brand-aligned but distinct so the eye can sort badges by category at
 * a glance. CSS variables `--achv-c1` (light) and `--achv-c2` (dark)
 * are set on each [data-category] root and consumed by every painted
 * surface inside (icon medallion gradient, hover ring, progress bar
 * gradient, group-heading underline).
 */

/* Per-category palette — single source of truth. */
[data-category="streak"]  { --achv-c1: #fde68a; --achv-c2: #d97706; --achv-c3: rgba(217,119,6,.18); }
[data-category="volume"]  { --achv-c1: #bae6fd; --achv-c2: #0284c7; --achv-c3: rgba(2,132,199,.18); }
[data-category="exam"]    { --achv-c1: #ddd6fe; --achv-c2: #7c3aed; --achv-c3: rgba(124,58,237,.18); }
[data-category="subject"] { --achv-c1: #99f6e4; --achv-c2: #0d9488; --achv-c3: rgba(13,148,136,.18); }

/* Group heading — small accent bar in the category color, makes
   each group section feel anchored. */
.achv-group-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--glass-border);
  position: relative;
}
.achv-group-head h3 {
  margin: 0;
  display: inline-flex; align-items: center; gap: 8px;
}
.achv-group-head[data-category]::after {
  content: "";
  position: absolute;
  bottom: -1px;
  left: 0;
  width: 64px;
  height: 2px;
  background: var(--achv-c2, var(--primary));
  border-radius: 2px;
}

.achv-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
@media (min-width: 540px) {
  .achv-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 820px) {
  .achv-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1100px) {
  .achv-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ── Individual badge card — vertical "trophy" layout ────────────────── */
.achv-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  padding: 18px 14px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--glass-border);
  background: var(--glass);
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
  position: relative;
  overflow: hidden;
}

/* Hover lift — only applies when there's something to celebrate. The
   locked-not-started state stays static so it doesn't feel like a CTA. */
.achv-card.unlocked:hover,
.achv-card:not(.locked):hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(15,23,42,.08);
  border-color: var(--achv-c2, var(--glass-border-strong));
}

/* Subtle category-tinted gradient wash visible only on unlocked badges —
   ties the card to its category. */
.achv-card.unlocked {
  background:
    linear-gradient(180deg, var(--achv-c3, rgba(45,212,191,.12)) 0%, transparent 60%),
    var(--glass);
  border-color: color-mix(in srgb, var(--achv-c2, var(--primary)) 45%, transparent);
}

/* Decorative shimmer that runs once per page-mount on unlocked badges —
   draws the eye to recent unlocks without being distracting. */
.achv-card.unlocked::before {
  content: "";
  position: absolute;
  top: 0; left: -120%;
  width: 60%;
  height: 100%;
  background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,.18) 50%, transparent 70%);
  transform: skewX(-20deg);
  animation: achv-shimmer 1.6s ease-out 0.4s 1;
  pointer-events: none;
}
@keyframes achv-shimmer {
  0%   { left: -120%; }
  100% { left: 220%; }
}

.achv-card.locked {
  opacity: .65;
  filter: saturate(0.4);
}

/* ── Icon medallion ─────────────────────────────────────────────────── */
.achv-icon {
  font-size: 36px;
  line-height: 1;
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,.45), transparent 55%),
    linear-gradient(135deg, var(--achv-c1, rgba(148,163,184,.32)) 0%, var(--achv-c2, rgba(148,163,184,.55)) 100%);
  border: 2px solid color-mix(in srgb, var(--achv-c2, var(--glass-border)) 60%, transparent);
  box-shadow:
    0 4px 12px color-mix(in srgb, var(--achv-c2, transparent) 30%, transparent),
    inset 0 -2px 6px rgba(0,0,0,.10),
    inset 0 2px 4px rgba(255,255,255,.30);
  position: relative;
  z-index: 1;
}
/* Locked icons collapse to a flat slate-grey medallion so the unlocked
   ones really pop in comparison. */
.achv-card.locked .achv-icon {
  background: linear-gradient(135deg, rgba(148,163,184,.22), rgba(100,116,139,.32));
  border-color: var(--glass-border);
  box-shadow: inset 0 -2px 6px rgba(0,0,0,.06);
  filter: grayscale(.75);
}

/* Subtle ambient pulse on unlocked icons — slow, ~3s cycle, easy to
   ignore if you're scanning but rewarding when you stop on one. */
.achv-card.unlocked .achv-icon {
  animation: achv-pulse 3s ease-in-out infinite;
}
@keyframes achv-pulse {
  0%, 100% {
    box-shadow:
      0 4px 12px color-mix(in srgb, var(--achv-c2, transparent) 30%, transparent),
      inset 0 -2px 6px rgba(0,0,0,.10),
      inset 0 2px 4px rgba(255,255,255,.30);
  }
  50% {
    box-shadow:
      0 4px 18px color-mix(in srgb, var(--achv-c2, transparent) 55%, transparent),
      inset 0 -2px 6px rgba(0,0,0,.10),
      inset 0 2px 4px rgba(255,255,255,.30);
  }
}

.achv-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
}
.achv-title {
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
  line-height: 1.2;
}
.achv-desc {
  font-size: 12.5px;
  color: var(--text-dim);
  line-height: 1.4;
}

/* ── Footer strip — varies by state ─────────────────────────────────── */
.achv-foot {
  width: 100%;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid var(--glass-border);
  font-size: 11.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.achv-foot-unlocked {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--achv-c2, var(--primary));
  font-weight: 600;
}
.achv-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--achv-c2, var(--primary));
  color: #fff;
  font-size: 10px;
  font-weight: 800;
}
.achv-foot-locked {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-style: italic;
  opacity: .8;
}
.achv-lock { font-size: 11px; opacity: .7; }

/* In-progress footer — bar + percentage + label in one row. */
.achv-foot-progress {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.achv-foot-progress .achv-bar { background: var(--glass-border); }
.achv-foot-progress .achv-bar > span {
  background: linear-gradient(90deg, var(--achv-c1, #5eead4), var(--achv-c2, #14b8a6));
}
.achv-foot-line {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
}
.achv-prog-pct {
  font-weight: 700;
  color: var(--achv-c2, var(--text-dim));
}
.achv-prog-label {
  font-size: 11px;
}

/* ── Hero rails (recent unlocks + closest-to-unlock) ────────────────── */
.achv-rails {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--glass-border);
}
@media (min-width: 720px) {
  .achv-rails { grid-template-columns: 1fr 1fr; }
}
.achv-rail-head { margin-bottom: 8px; }
.achv-rail-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.achv-rail-list {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.achv-rail-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 6px;
  background: var(--glass-weak);
  border: 1px solid color-mix(in srgb, var(--achv-c2, var(--glass-border)) 40%, transparent);
  border-radius: 999px;
  transition: transform .15s ease, box-shadow .15s ease;
}
.achv-rail-chip:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15,23,42,.08);
}
.achv-rail-icon {
  font-size: 16px;
  width: 28px; height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--achv-c1, rgba(148,163,184,.3)), var(--achv-c2, rgba(148,163,184,.5)));
  flex-shrink: 0;
}
.achv-rail-text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}
.achv-rail-title { font-weight: 700; font-size: 12px; color: var(--text); }
.achv-rail-sub   { font-size: 10.5px; color: var(--muted); margin-top: 1px; }

.achv-rail-chip-progress .achv-rail-icon {
  filter: grayscale(.4);
  opacity: .85;
}
.achv-back {
  display: flex;
  justify-content: center;
  margin-top: 8px;
}

/* ─── Avatars (home hero + account picker) ─────────────────────────────
   The top-chip avatar styles live next to .user-chip near the top of the
   file. Everything below is hero + picker UI. */
.home-hero-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; border-radius: 999px;
  font-size: 30px; line-height: 1;
  background: linear-gradient(135deg, rgba(45,212,191,.22), rgba(14,165,233,.18));
  border: 1px solid var(--glass-border-strong);
  text-decoration: none; cursor: pointer;
  transition: transform .15s, border-color .15s;
  margin-right: 4px;
}
.home-hero-avatar:hover { transform: scale(1.05); border-color: rgba(45,212,191,.55); }

.avatar-card .avatar-picker {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 20px;
  align-items: flex-start;
  margin-top: 10px;
}
.avatar-preview {
  display: inline-flex; align-items: center; justify-content: center;
  width: 96px; height: 96px; border-radius: 20px;
  font-size: 58px; line-height: 1;
  background: linear-gradient(135deg, rgba(45,212,191,.22), rgba(14,165,233,.18));
  border: 1px solid var(--glass-border-strong);
  flex-shrink: 0;
}
.avatar-picker-body { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.avatar-picker-category { display: flex; flex-direction: column; gap: 6px; }
.avatar-picker-label {
  font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-dim);
}
.avatar-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: 6px;
}
.avatar-emoji-btn {
  display: inline-flex; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1;
  font-size: 22px; line-height: 1;
  padding: 0;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  cursor: pointer;
  transition: transform .1s, border-color .15s, background .15s;
}
.avatar-emoji-btn:hover {
  transform: translateY(-1px);
  border-color: var(--glass-border-strong);
  background: var(--glass);
}
.avatar-emoji-btn.selected {
  border-color: rgba(45,212,191,.65);
  background: linear-gradient(135deg, rgba(45,212,191,.24), rgba(14,165,233,.18));
  box-shadow: 0 0 0 2px rgba(45,212,191,.2);
}
.avatar-custom {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px;
  padding-top: 6px;
  border-top: 1px dashed var(--glass-border);
}
.avatar-custom label { flex: 1 1 180px; display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-dim); }
.avatar-custom input {
  font-size: 18px; padding: 6px 10px; border-radius: 8px;
  background: var(--glass-weak); border: 1px solid var(--glass-border);
  color: var(--text);
}
.avatar-custom input:focus { outline: none; border-color: rgba(45,212,191,.55); }

@media (max-width: 560px) {
  .avatar-card .avatar-picker { grid-template-columns: 1fr; }
  .avatar-preview { width: 80px; height: 80px; font-size: 48px; border-radius: 18px; }
}

/* ─── Multiplayer ───────────────────────────────────────────────────────
   Lobby (host + join forms), live match (scoreboard, question card, timer),
   and the finished-match recap. Uses the same glass/accent language as the
   rest of the app; reads cleanly in both colour schemes via the light-mode
   overrides at the bottom of this file. */
.mp-lobby { display: flex; flex-direction: column; gap: 18px; }
.mp-lobby-hero { padding: 4px 2px; }
.mp-lobby-hero h1 { font-size: 28px; margin: 0 0 4px; }
.mp-lobby-hero p { margin: 0; max-width: 64ch; }

/* Free-tier quota banner — shown above Quick Match for free users. */
.mp-quota-banner {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 16px;
  background: linear-gradient(135deg, rgba(251,191,36,.16), rgba(251,191,36,.08));
  border-color: rgba(251,191,36,.35);
}
.mp-quota-icon { font-size: 22px; line-height: 1; }
.mp-quota-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mp-quota-text strong { font-size: 15px; }
.mp-quota-text a { color: var(--primary); font-weight: 600; text-decoration: underline; }

/* Quick Match hero card */
.mp-quickmatch {
  display: flex; align-items: center; gap: 16px;
  flex-wrap: wrap;
  padding: 18px 20px;
  background: linear-gradient(135deg, rgba(45,212,191,.16), rgba(14,165,233,.12));
  border-color: rgba(45,212,191,.35);
}
.mp-quickmatch-body {
  display: flex; align-items: center; gap: 14px;
  flex: 1 1 280px;
}
.mp-quickmatch-icon {
  font-size: 34px; line-height: 1;
  width: 56px; height: 56px;
  display: grid; place-items: center;
  background: rgba(45,212,191,.18);
  border: 1px solid rgba(45,212,191,.4);
  border-radius: 14px;
  flex: 0 0 auto;
}
.mp-quickmatch-text h3 { margin: 0 0 4px; font-size: 18px; }
.mp-quickmatch-text p  { margin: 0; font-size: 14px; }
.mp-quickmatch-btn {
  flex: 0 0 auto;
  min-width: 160px;
  font-size: 15px;
}

/* Public-rooms browser */
.mp-browse-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin: 0 0 12px;
}
.mp-browse-head h3 {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: 17px;
}
.mp-browse-list {
  display: flex; flex-direction: column; gap: 8px;
}
.mp-browse-empty { margin: 0; padding: 8px 2px; font-size: 14px; }
.mp-browse-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
}
.mp-browse-player {
  display: flex; align-items: center; gap: 10px;
  min-width: 0;
}
.mp-browse-player .mp-pmeta { gap: 1px; }
.mp-browse-filters {
  display: flex; flex-wrap: wrap; gap: 6px;
  min-width: 0;
}
.mp-filter-tag {
  font-size: 12px; font-weight: 600;
  padding: 3px 8px; border-radius: 8px;
  background: rgba(45,212,191,.14);
  border: 1px solid rgba(45,212,191,.35);
  color: #5eead4;
  white-space: nowrap;
}
.mp-browse-join { min-width: 72px; }

.mp-lobby-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.mp-lobby-card h3 {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 12px; font-size: 17px;
}
.mp-lobby-card .mp-icon { font-size: 22px; line-height: 1; }

/* Public/private toggle on host form */
.mp-visibility {
  flex-direction: row !important; align-items: flex-start;
  gap: 10px !important;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  cursor: pointer;
}
.mp-visibility input[type="checkbox"] {
  margin: 3px 0 0; flex: 0 0 auto;
  width: 16px; height: 16px;
  accent-color: #2dd4bf;
}
.mp-visibility > span {
  display: flex; flex-direction: column; gap: 2px;
  flex: 1 1 auto; min-width: 0;
}
.mp-visibility strong { color: var(--text); font-weight: 600; }
.mp-visibility .small { font-size: 12px; }

.mp-form { display: flex; flex-direction: column; gap: 10px; }
.mp-form label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 13px; color: var(--muted);
}
.mp-form select,
.mp-form input {
  padding: 10px 12px; border-radius: 10px; font-size: 15px;
  background: var(--glass-weak); border: 1px solid var(--glass-border);
  color: var(--text);
}
.mp-form select:focus,
.mp-form input:focus {
  outline: none; border-color: rgba(45,212,191,.55);
  box-shadow: 0 0 0 2px rgba(45,212,191,.18);
}
.mp-form .small { font-size: 12px; margin: 4px 0 0; }
.mp-match-count {
  font-size: 13px; padding: 6px 2px; min-height: 1.2em;
}
.mp-match-warn { color: #fca5a5; }

.mp-code-input {
  text-transform: uppercase; letter-spacing: .3em;
  font-weight: 700; font-size: 20px; text-align: center;
  font-variant-numeric: tabular-nums;
}

.mp-rules ul { margin: 0; padding-left: 20px; }
.mp-rules li { margin: 6px 0; line-height: 1.5; }

/* Waiting room */
.mp-wait { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 28px 20px; }
.mp-wait h1 { margin: 0; font-size: 26px; }
.mp-wait > p.muted { margin: 0; max-width: 46ch; }
.mp-code-display {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 42px; font-weight: 700; letter-spacing: .25em;
  padding: 14px 22px; border-radius: 14px;
  background: linear-gradient(135deg, rgba(16,185,129,.18), rgba(14,165,233,.14));
  border: 1px solid rgba(45,212,191,.35);
  color: #5eead4;
  box-shadow: 0 0 0 3px rgba(45,212,191,.08) inset;
}
.mp-wait-status {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 4px 0 0; color: var(--muted);
}
.mp-wait-pulse {
  width: 10px; height: 10px; border-radius: 50%;
  background: #5eead4;
  animation: mpPulse 1.4s ease-in-out infinite;
}
@keyframes mpPulse {
  0%, 100% { transform: scale(.85); opacity: .45; }
  50%      { transform: scale(1.15); opacity: 1; }
}
.mp-wait-filters { font-size: 14px; color: var(--muted); }
.mp-wait-filters strong { color: var(--text); }
.mp-wait-icon {
  font-size: 56px; line-height: 1;
  width: 96px; height: 96px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: linear-gradient(135deg, rgba(45,212,191,.18), rgba(14,165,233,.12));
  border: 1px solid rgba(45,212,191,.35);
  animation: mpWaitIcon 2.2s ease-in-out infinite;
}
@keyframes mpWaitIcon {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.05); box-shadow: 0 0 0 10px rgba(45,212,191,.05); }
}
.mp-host-sub { margin: -4px 0 10px; }

/* Host "Back to lobby" / "Cancel match" action row on the waiting screen */
.mp-wait-actions {
  display: flex; gap: 8px; justify-content: center; flex-wrap: wrap;
  margin-top: 6px;
}
.mp-wait-actions .btn { min-width: 140px; }

/* Your-match row in the public-rooms browser */
.mp-row-mine {
  background: linear-gradient(135deg, rgba(45,212,191,.12), rgba(14,165,233,.08));
  border: 1px solid rgba(45,212,191,.35) !important;
  border-radius: 12px;
  padding: 10px 12px;
}
.mp-row-ready-row {
  background: linear-gradient(135deg, rgba(249,115,22,.18), rgba(239,68,68,.1));
  border-color: rgba(239,68,68,.45) !important;
  animation: mpRowReady 1.8s ease-in-out infinite;
}
@keyframes mpRowReady {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,.0); }
  50%      { box-shadow: 0 0 0 4px rgba(239,68,68,.18); }
}
.mp-row-ready .mp-wait-pulse {
  display: inline-block;
  width: 8px; height: 8px; border-radius: 50%;
  background: #fff;
  margin-left: 6px; vertical-align: middle;
  animation: mpPulse 1.1s ease-in-out infinite;
}

/* Lobby tabs (Play | Leaderboard) */
.mp-tabs {
  display: flex; gap: 4px;
  padding: 4px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
}
.mp-tab {
  flex: 1; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 10px 12px;
  border-radius: 9px;
  font-weight: 600; font-size: 14px;
  color: var(--muted);
  text-decoration: none;
  transition: background .12s ease, color .12s ease;
}
.mp-tab:hover { color: var(--text); background: rgba(255,255,255,.04); }
.mp-tab.active {
  background: linear-gradient(135deg, rgba(45,212,191,.22), rgba(14,165,233,.16));
  color: var(--text);
  box-shadow: inset 0 0 0 1px rgba(45,212,191,.35);
}

/* Leaderboard table */
.mp-leaderboard { padding: 16px; }
.mp-lb-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin-bottom: 12px;
}
.mp-lb-head h3 { margin: 0; display: inline-flex; align-items: center; gap: 6px; }
.mp-lb-scope { display: inline-flex; gap: 4px; background: rgba(15,23,42,.35); padding: 3px; border-radius: 9px; }
.mp-lb-chip {
  appearance: none; border: 0; cursor: pointer;
  padding: 6px 12px;
  font-size: 13px; font-weight: 600;
  color: var(--muted);
  background: transparent;
  border-radius: 7px;
  transition: background .12s ease, color .12s ease;
}
.mp-lb-chip:hover { color: var(--text); }
.mp-lb-chip.active {
  background: linear-gradient(135deg, rgba(45,212,191,.28), rgba(14,165,233,.18));
  color: var(--text);
}
.mp-lb-mystats { margin: 0 0 12px; }
.mp-lb-me {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 10px 12px;
  background: linear-gradient(135deg, rgba(45,212,191,.10), rgba(14,165,233,.06));
  border: 1px solid rgba(45,212,191,.28);
  border-radius: 12px;
}
.mp-lb-me.empty { background: var(--glass-weak); border-color: var(--glass-border); justify-content: flex-start; }
.mp-lb-me-left { display: flex; align-items: center; gap: 10px; min-width: 0; }
.mp-lb-me-stats { display: flex; gap: 14px; flex-wrap: wrap; }
.mp-lb-stat { display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
.mp-lb-stat-val { font-weight: 700; font-size: 18px; color: var(--text); }
.mp-lb-stat-lbl { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }

.mp-lb-body { overflow-x: auto; }
.mp-lb-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.mp-lb-table th,
.mp-lb-table td {
  padding: 10px 8px;
  border-bottom: 1px solid var(--glass-border);
  text-align: left;
  vertical-align: middle;
}
.mp-lb-table th {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}
.mp-lb-table th.num,
.mp-lb-table td.num { text-align: right; white-space: nowrap; }
.mp-lb-table .mp-lb-rank {
  width: 44px;
  font-weight: 700;
  text-align: center;
  font-size: 15px;
}
.mp-lb-table .mp-lb-player {
  display: flex; align-items: center; gap: 8px;
  min-width: 0;
}
.mp-lb-table .mp-lb-player .mp-avatar {
  width: 30px; height: 30px; font-size: 18px;
}
.mp-lb-table .mp-lb-player .mp-pname {
  font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 180px;
}
.mp-lb-youtag {
  font-size: 11px; font-weight: 700;
  padding: 2px 6px;
  border-radius: 6px;
  background: rgba(45,212,191,.25);
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: .06em;
}
.mp-lb-mine td { background: rgba(45,212,191,.08); }
.mp-lb-mine td:first-child { border-left: 3px solid rgba(45,212,191,.6); padding-left: 5px; }
.mp-lb-empty { margin: 12px 0; text-align: center; padding: 16px; }
.mp-lb-foot { margin: 12px 0 0; }
.mp-lb-about {
  margin: 14px 0 0;
  padding: 10px 14px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
}
.mp-lb-about > summary {
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
  padding: 2px 0;
  display: flex; align-items: center; gap: 6px;
}
.mp-lb-about > summary::before {
  content: "ⓘ";
  color: rgba(45,212,191,.9);
  font-size: 15px;
}
.mp-lb-about[open] > summary { margin-bottom: 8px; }
.mp-lb-about-body p {
  margin: 0 0 8px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text-dim);
}
.mp-lb-about-body p:last-child { margin-bottom: 0; }
.mp-lb-about-body strong { color: var(--text); }

@media (max-width: 560px) {
  .mp-lb-table th:nth-child(5),
  .mp-lb-table td:nth-child(5) { display: none; }
  .mp-lb-table .mp-lb-player .mp-pname { max-width: 120px; }
  .mp-lb-me-stats { gap: 10px; }
  .mp-lb-stat-val { font-size: 16px; }
}

/* Live match */
.mp-play { display: flex; flex-direction: column; gap: 14px; }

.mp-scoreboard {
  display: grid; gap: 10px;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 12px 14px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: 14px;
}
.mp-player {
  display: flex; align-items: center; gap: 10px;
  min-width: 0;
  transition: transform .12s ease, opacity .12s ease;
}
.mp-player.mp-opp { justify-content: flex-end; }
.mp-player.done { opacity: .85; }
.mp-avatar {
  flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 22px; line-height: 1;
  background: linear-gradient(135deg, rgba(16,185,129,.16), rgba(14,165,233,.12));
  border: 1px solid rgba(45,212,191,.3);
}
.mp-pmeta {
  display: flex; flex-direction: column;
  min-width: 0; line-height: 1.15;
}
.mp-pmeta.right { align-items: flex-end; text-align: right; }
.mp-pname {
  font-size: 13px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}
.mp-score {
  font-size: 20px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.mp-lock {
  font-size: 14px; font-weight: 700;
  color: #34d399;
  padding: 2px 6px; border-radius: 6px;
  background: rgba(16,185,129,.16);
  border: 1px solid rgba(16,185,129,.4);
}

.mp-vs {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 72px;
}
.mp-progress { font-size: 12px; color: var(--muted); }
.mp-timer {
  font-size: 22px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 4px 10px; border-radius: 10px;
  background: rgba(15,23,42,.25);
  border: 1px solid var(--glass-border);
  color: var(--text);
  min-width: 60px; text-align: center;
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.mp-timer.mp-timer-low {
  color: #fca5a5;
  background: rgba(239,68,68,.15);
  border-color: rgba(239,68,68,.45);
  animation: mpTimerPulse .9s ease-in-out infinite;
}
@keyframes mpTimerPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}

.mp-qcard { padding: 18px; }

/* Header row that holds the prominent "Bookmark" pill. Right-aligned so
   it floats to the corner away from the question stem, with breathing
   room below so the prompt doesn't crowd it. */
.mp-q-head {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 14px;
}

.mp-qprompt {
  font-size: 17px; line-height: 1.5;
  margin: 0 0 14px;
  color: var(--text);
  white-space: pre-wrap;
}
.mp-choices {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.mp-choice {
  width: 100%;
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  color: var(--text); text-align: left; cursor: pointer;
  font-size: 15px; line-height: 1.4;
  transition: background .12s ease, border-color .12s ease, transform .08s ease;
}
.mp-choice:hover:not(:disabled) {
  background: rgba(45,212,191,.08);
  border-color: rgba(45,212,191,.4);
}
.mp-choice:active:not(:disabled) { transform: scale(.99); }
.mp-choice:disabled { cursor: default; }
.mp-choice.right {
  background: rgba(16,185,129,.16);
  border-color: rgba(16,185,129,.5);
  color: #a7f3d0;
}
.mp-choice.wrong {
  background: rgba(239,68,68,.14);
  border-color: rgba(239,68,68,.48);
  color: #fecaca;
}
.mp-chletter {
  flex: 0 0 auto;
  width: 28px; height: 28px; border-radius: 8px;
  display: grid; place-items: center;
  font-weight: 700; font-size: 13px;
  background: rgba(15,23,42,.25);
  border: 1px solid var(--glass-border);
}
.mp-choice.right .mp-chletter {
  background: rgba(16,185,129,.22);
  border-color: rgba(16,185,129,.5);
}
.mp-choice.wrong .mp-chletter {
  background: rgba(239,68,68,.18);
  border-color: rgba(239,68,68,.5);
}
.mp-chtext { flex: 1 1 auto; min-width: 0; }
.mp-qimg {
  max-width: 100%; margin-top: 12px; border-radius: 10px;
  border: 1px solid var(--glass-border);
}

.mp-play-foot {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px; flex-wrap: wrap;
}

/* Finished screen */
.mp-finish { display: flex; flex-direction: column; gap: 16px; }
.mp-result {
  text-align: center;
  padding: 24px 20px;
  border-radius: 18px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
}
.mp-result h1 { font-size: 30px; margin: 0 0 14px; }
.mp-result-win {
  background: linear-gradient(135deg, rgba(16,185,129,.2), rgba(14,165,233,.14));
  border-color: rgba(16,185,129,.45);
}
.mp-result-loss {
  background: linear-gradient(135deg, rgba(239,68,68,.14), rgba(30,41,59,.12));
  border-color: rgba(239,68,68,.4);
}
.mp-result-tie {
  background: linear-gradient(135deg, rgba(251,191,36,.16), rgba(14,165,233,.12));
  border-color: rgba(251,191,36,.45);
}
.mp-result-scores {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: 14px;
  max-width: 520px; margin: 0 auto;
}
.mp-vs-vs {
  font-size: 14px; font-weight: 700; letter-spacing: .15em;
  color: var(--muted);
  padding: 6px 12px; border-radius: 10px;
  background: rgba(15,23,42,.25);
  border: 1px solid var(--glass-border);
}

.mp-recap { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.mp-recap-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 10px;
  background: rgba(15,23,42,.22);
  border: 1px solid var(--glass-border);
}
.mp-recap-q {
  font-size: 14px; line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis;
}
.mp-recap-picks { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.mp-pick {
  font-size: 12px; font-weight: 600;
  padding: 4px 8px; border-radius: 8px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  color: var(--muted);
  white-space: nowrap;
}
.mp-pick.right  { color: #a7f3d0; background: rgba(16,185,129,.14); border-color: rgba(16,185,129,.4); }
.mp-pick.wrong  { color: #fecaca; background: rgba(239,68,68,.14); border-color: rgba(239,68,68,.4); }
.mp-pick.skip   { color: var(--muted); font-style: italic; }

/* ── Multiplayer bookmark toggles (in-match + recap) ───────────────────
   Two surfaces share the same visual language: a small pill with a
   star icon + a "Bookmark" / "Bookmarked" label. Bigger hit target
   than a bare ☆ icon and the text makes the affordance immediately
   obvious to users who didn't notice the previous icon-only version. */

.mp-bookmark,
.mp-recap-bmk {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--muted, #888780);
  background: var(--glass-weak, rgba(148, 163, 184, 0.08));
  border: 1px solid var(--glass-border, rgba(148, 163, 184, 0.28));
  border-radius: 999px;
  cursor: pointer;
  transition: color 150ms ease, background 150ms ease, border-color 150ms ease, transform 150ms ease;
}
.mp-bookmark:hover,
.mp-recap-bmk:hover {
  color: var(--ink, var(--text));
  background: var(--glass, rgba(148, 163, 184, 0.16));
  transform: translateY(-1px);
}
.mp-bookmark.on,
.mp-recap-bmk.on {
  color: #b45309;
  background: rgba(245, 158, 11, 0.16);
  border-color: rgba(245, 158, 11, 0.55);
}
.mp-bookmark .mp-bookmark-icon,
.mp-recap-bmk .mp-recap-bmk-icon {
  font-size: 15px;
  line-height: 1;
}
.mp-bookmark:disabled,
.mp-recap-bmk:disabled { opacity: 0.6; cursor: wait; transform: none; }

/* In-match button slightly larger so it reads as a clear control at
   the top of the question card. */
.mp-bookmark { padding: 7px 14px; font-size: 13px; }
.mp-bookmark .mp-bookmark-icon { font-size: 17px; }

.mp-finish-actions {
  display: flex; gap: 10px; justify-content: center; flex-wrap: wrap;
}

@media (max-width: 560px) {
  .mp-scoreboard { grid-template-columns: 1fr auto 1fr; padding: 10px; gap: 8px; }
  .mp-avatar { width: 32px; height: 32px; font-size: 18px; }
  .mp-score { font-size: 17px; }
  .mp-timer { font-size: 18px; min-width: 52px; padding: 3px 8px; }
  .mp-vs { min-width: 60px; }
  .mp-code-display { font-size: 30px; letter-spacing: .18em; padding: 12px 16px; }
  .mp-result-scores { grid-template-columns: 1fr; gap: 8px; }
  .mp-result-scores .mp-player.mp-opp { justify-content: flex-start; }
  .mp-result-scores .mp-pmeta.right { align-items: flex-start; text-align: left; }
  .mp-recap-row { grid-template-columns: 1fr; }
  .mp-recap-picks { justify-content: flex-start; }
}

/* ─── Light-mode contrast overrides ─────────────────────────────────────
   Placed at the very end so they out-cascade the base (dark-first) rules
   regardless of where those base rules appear in the stylesheet. The
   pastel teal/amber tones used on dark glass cards wash out against the
   white-ish light-mode background, so we swap in darker shades. */
@media (prefers-color-scheme: light) {
  /* Pro chip (Hi Nanda ✨ Pro) */
  .pro-chip {
    color: #0f766e;
    background: linear-gradient(135deg, rgba(20,184,166,.22), rgba(14,165,233,.22));
    border-color: rgba(15,118,110,.45);
  }
  .pro-chip-free {
    color: #334155;
    background: rgba(15,23,42,.04);
    border-color: rgba(15,23,42,.18);
  }
  .pro-chip-free:hover { color: #0f766e; border-color: rgba(15,118,110,.5); }

  /* Species / subject tags under each question — need strong contrast on
     white/glass cards. Opacity bumped so pastel doesn't wash into card. */
  .tag-species {
    color: #064e3b;
    background: rgba(16,185,129,.28);
    border-color: rgba(6,78,59,.55);
  }
  .tag-subject {
    color: #7c2d12;
    background: rgba(251,146,60,.32);
    border-color: rgba(124,45,18,.55);
  }

  /* Amber "🔒 Pro" lock badge next to gated action titles */
  .lock-badge {
    color: #92400e;
    background: rgba(251,191,36,.22);
    border-color: rgba(180,83,9,.4);
  }

  /* Eyebrow / accent text on paywall, upgrade, and dash-lock cards */
  .paywall-eyebrow,
  .upgrade-eyebrow,
  .dash-lock-eyebrow { color: #0f766e; }

  /* Scattered teal accent links + ticks that also wash out */
  .upgrade-current .link,
  .home-quota-label .link,
  .compare-card .cmp-pro { color: #0f766e; }
  .plan-points li::before { color: #0f766e; }

  /* Question prompt in darker teal so it reads on white */
  .question-prompt { color: #0f766e; }

  /* Badges — teal greens wash out against white, darken them. */
  .achv-hero-num { color: #0f766e; }

  /* The new badge-card design uses per-category color variables driven by
     [data-category] selectors, so no light-mode overrides for unlocked
     cards / icons are needed — they already render correctly against
     light backgrounds.  The only dashboard preview chip that needs help
     is the legacy .achv-preview-chip on the home/dashboard preview rail. */
  .achv-preview-chip {
    background: linear-gradient(135deg, rgba(16,185,129,.22), rgba(14,165,233,.18));
    border-color: rgba(4,120,87,.5);
    color: #0f172a;
  }

  /* Exam-history drill-down status pills and labels — pastel tones wash out
     against white, so darken them. */
  .exam-q-status-right   { color: #047857; background: rgba(16,185,129,.18); border-color: rgba(4,120,87,.45); }
  .exam-q-status-wrong   { color: #b91c1c; background: rgba(239, 68, 68,.15); border-color: rgba(185, 28, 28,.45); }
  .exam-q-correct .exam-q-label { color: #047857; }
  .exam-q-right   { border-left-color: #047857; }
  .exam-q-wrong   { border-left-color: #b91c1c; }
  .exam-details-row > td { background: rgba(15,23,42,.03); }

  /* Avatars — the default teal glow needs more pop on white backgrounds. */
  .user-chip-avatar {
    background: rgba(15,23,42,.04);
    border-color: rgba(15,23,42,.18);
  }
  .home-hero-avatar {
    background: linear-gradient(135deg, rgba(16,185,129,.22), rgba(14,165,233,.18));
    border-color: rgba(4,120,87,.4);
  }
  .avatar-preview {
    background: linear-gradient(135deg, rgba(16,185,129,.22), rgba(14,165,233,.18));
    border-color: rgba(4,120,87,.4);
  }
  .avatar-emoji-btn.selected {
    border-color: rgba(4,120,87,.55);
    background: linear-gradient(135deg, rgba(16,185,129,.28), rgba(14,165,233,.2));
    box-shadow: 0 0 0 2px rgba(16,185,129,.22);
  }

  /* Multiplayer — pastels wash out on white; use darker teals/reds. */
  .mp-code-display {
    color: #0f766e;
    background: linear-gradient(135deg, rgba(16,185,129,.18), rgba(14,165,233,.12));
    border-color: rgba(4,120,87,.45);
    box-shadow: 0 0 0 3px rgba(4,120,87,.08) inset;
  }
  .mp-wait-pulse { background: #0f766e; }
  .mp-match-warn { color: #b91c1c; }
  .mp-avatar {
    background: linear-gradient(135deg, rgba(16,185,129,.22), rgba(14,165,233,.16));
    border-color: rgba(4,120,87,.4);
  }
  .mp-lock {
    color: #047857;
    background: rgba(16,185,129,.18);
    border-color: rgba(4,120,87,.45);
  }
  .mp-timer { background: rgba(15,23,42,.05); }
  .mp-timer.mp-timer-low {
    color: #b91c1c;
    background: rgba(239,68,68,.12);
    border-color: rgba(185,28,28,.45);
  }
  .mp-vs-vs { background: rgba(15,23,42,.05); }
  .mp-choice.right {
    color: #064e3b;
    background: rgba(16,185,129,.18);
    border-color: rgba(4,120,87,.5);
  }
  .mp-choice.right .mp-chletter {
    background: rgba(16,185,129,.28);
    border-color: rgba(4,120,87,.5);
  }
  .mp-choice.wrong {
    color: #7f1d1d;
    background: rgba(239,68,68,.14);
    border-color: rgba(185,28,28,.45);
  }
  .mp-choice.wrong .mp-chletter {
    background: rgba(239,68,68,.2);
    border-color: rgba(185,28,28,.5);
  }
  .mp-chletter { background: rgba(15,23,42,.05); }
  .mp-recap-row { background: rgba(15,23,42,.03); }
  .mp-pick.right  { color: #064e3b; background: rgba(16,185,129,.18); border-color: rgba(4,120,87,.45); }
  .mp-pick.wrong  { color: #7f1d1d; background: rgba(239,68,68,.14); border-color: rgba(185,28,28,.45); }
  .mp-result-win {
    background: linear-gradient(135deg, rgba(16,185,129,.2), rgba(14,165,233,.14));
    border-color: rgba(4,120,87,.5);
  }
  .mp-result-loss {
    background: linear-gradient(135deg, rgba(239,68,68,.14), rgba(15,23,42,.04));
    border-color: rgba(185,28,28,.4);
  }
  .mp-result-tie {
    background: linear-gradient(135deg, rgba(251,191,36,.2), rgba(14,165,233,.12));
    border-color: rgba(180,83,9,.45);
  }

  /* Quick Match + public-rooms browser */
  .mp-quickmatch {
    background: linear-gradient(135deg, rgba(20,184,166,.22), rgba(14,165,233,.16));
    border-color: rgba(15,118,110,.45);
  }
  .mp-quickmatch-icon {
    background: rgba(16,185,129,.22);
    border-color: rgba(4,120,87,.4);
  }
  .mp-filter-tag {
    color: #0f766e;
    background: rgba(16,185,129,.18);
    border-color: rgba(4,120,87,.4);
  }

  /* Lobby tabs + leaderboard */
  .mp-tab:hover { background: rgba(15,23,42,.05); }
  .mp-tab.active {
    background: linear-gradient(135deg, rgba(20,184,166,.22), rgba(14,165,233,.16));
    box-shadow: inset 0 0 0 1px rgba(15,118,110,.45);
  }
  .mp-lb-scope { background: rgba(15,23,42,.06); }
  .mp-lb-chip.active {
    background: linear-gradient(135deg, rgba(20,184,166,.28), rgba(14,165,233,.2));
  }
  .mp-lb-me {
    background: linear-gradient(135deg, rgba(16,185,129,.14), rgba(14,165,233,.08));
    border-color: rgba(15,118,110,.35);
  }
  .mp-lb-mine td { background: rgba(16,185,129,.1); }
  .mp-lb-mine td:first-child { border-left-color: rgba(15,118,110,.55); }
  .mp-lb-youtag {
    background: rgba(16,185,129,.28);
    color: #0f766e;
  }
}

/* ─── Landing page (public marketing) ─────────────────────────────────────
   Scoped under .landing-page so none of these light-marketing rules can
   leak into the dark in-app UI. The renderLanding() view also adds a
   `landing-active` class to <body> while mounted, which we use to hide
   the dark app chrome (topbar, bottom nav, site footer). All CTAs in this
   page route to #/signin so the existing auth flow handles signup. */

body.landing-active .topbar,
body.landing-active #bottomnav,
body.landing-active .site-footer { display: none !important; }

/* Catch-all for any logged-out route (landing, signin, etc.) — the marketing
   nav (or the auth view's own brand header) handles navigation, so the dark
   in-app shell would just be redundant chrome. The #view padding override
   only applies on /landing (where the marketing page owns the viewport);
   /signin keeps the default centered card padding. */
body.signed-out .topbar,
body.signed-out #bottomnav,
body.signed-out .site-footer { display: none !important; }
body.landing-active #view {
  /* Let the marketing page own the full viewport — no card padding,
     no max-width clamp from the in-app shell. */
  max-width: none;
  margin: 0;
  padding: 0;
}
body.landing-active {
  background: #ffffff;
  color: #0f172a;
}

.landing-page {
  /* Calm-clinical landing tokens — aligned with app proper palette
     (slate-tinted teal #0ea5a3 primary, slate neutrals, hairline
     borders). Kept under .landing-page scope so the marketing-only
     surface can evolve independently of the app shell. */
  --lp-bg: #ffffff;
  --lp-bg-soft: #f8fafc;
  --lp-bg-tint: #f0fdfa;          /* teal-50 — calmer than the old #ecfeff */
  --lp-ink: #0f172a;              /* slate-900 */
  --lp-ink-soft: #334155;         /* slate-700 (was #475569 — pulls one shade darker for body authority) */
  --lp-ink-mute: #64748b;         /* slate-500 */
  --lp-line: #e2e8f0;             /* slate-200 hairline */
  --lp-line-strong: #cbd5e1;      /* slate-300 */
  --lp-teal: #0ea5a3;             /* clinical teal — matches app --primary */
  --lp-teal-deep: #0f766e;        /* teal-700 hover */
  --lp-teal-bright: #14b8a6;      /* legacy alias (kept for back-compat) */
  --lp-sky: #0284c7;              /* sky-600 — secondary, used sparingly now */
  --lp-radius: 14px;              /* down from 16 — matches app radius */
  --lp-radius-sm: 10px;
  --lp-radius-lg: 20px;           /* hero card / final CTA / featured plan */
  --lp-shadow-sm: 0 1px 2px rgba(15,23,42,.04), 0 1px 3px rgba(15,23,42,.06);
  --lp-shadow-md: 0 4px 6px rgba(15,23,42,.05), 0 10px 15px rgba(15,23,42,.08);
  --lp-shadow-lg: 0 10px 25px rgba(15,23,42,.10), 0 20px 40px rgba(15,23,42,.06);
  --lp-shadow-teal: 0 4px 12px rgba(14,165,163,.20);
  --lp-ease: cubic-bezier(.2, .8, .2, 1);

  /* Use Inter (already loaded by index.html) for typographic continuity
     with the app — modern marketing sites mostly use a single typeface
     across surfaces, not a system-font marketing wrapper. */
  font: 16px/1.55 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-feature-settings: "cv11", "ss01", "ss03";
  color: var(--lp-ink);
  background: var(--lp-bg);
  -webkit-font-smoothing: antialiased;
}
.landing-page * { box-sizing: border-box; }
.landing-page a { color: inherit; text-decoration: none; }
.landing-page h1, .landing-page h2, .landing-page h3 {
  color: var(--lp-ink);
  letter-spacing: -.01em;
  margin: 0;
}
.landing-page p { margin: 0; color: var(--lp-ink-soft); }
.landing-page strong { color: var(--lp-ink); }
.lp-accent { color: var(--lp-teal-deep); font-weight: 700; }

/* ── Marketing top nav ──────────────────────────────────────────────────
   Sticky on scroll with backdrop-blur — modern marketing pattern. The
   scrolled state (added by JS via IntersectionObserver) tightens
   padding and surfaces a hairline border so the nav reads as elevated
   chrome rather than flat header. */
.lp-nav {
  position: sticky;
  top: 0;
  left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 32px;
  max-width: 1200px;
  margin: 0 auto;
  flex-wrap: wrap;
  background: rgba(255, 255, 255, 0);
  border-bottom: 1px solid transparent;
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  /* Only paint-only transitions here — animating `padding` on a sticky
     nav as the .lp-scrolled class toggles caused the document below
     the nav to shift up/down by a few px every time scrollY crossed
     the threshold (visible as a mild jitter). Padding is now constant
     across both states so the nav height never changes. */
  transition: background var(--lp-ease) 200ms,
              backdrop-filter var(--lp-ease) 200ms,
              border-color var(--lp-ease) 200ms;
}
.landing-page.lp-scrolled .lp-nav {
  background: rgba(255, 255, 255, 0.78);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  border-bottom-color: var(--lp-line);
}
.lp-nav-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 20px;
  font-weight: 800;
  color: var(--lp-ink);
  letter-spacing: -.011em;
}
.lp-nav-brand img { display: block; border-radius: 8px; }
.lp-nav-links {
  display: flex;
  gap: 28px;
  font-size: 15px;
  font-weight: 500;
}
.lp-nav-links a {
  color: var(--lp-ink-soft);
  transition: color var(--lp-ease) 120ms;
  position: relative;
}
.lp-nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 2px;
  background: var(--lp-teal);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--lp-ease) 200ms;
}
.lp-nav-links a:hover { color: var(--lp-teal-deep); }
.lp-nav-links a:hover::after { transform: scaleX(1); }
.lp-nav-cta {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ── Buttons ────────────────────────────────────────────────────────────
   Solid clinical teal primary — gradient was retired (matched the
   app proper, where every gradient text/button has been replaced with
   a single solid). Modern marketing CTAs lean confident-flat over
   glossy-gradient. */
.lp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 20px;
  border-radius: var(--lp-radius-sm);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  transition: transform var(--lp-ease) 100ms,
              box-shadow var(--lp-ease) 200ms,
              background var(--lp-ease) 150ms,
              border-color var(--lp-ease) 150ms,
              color var(--lp-ease) 150ms;
  border: 1px solid transparent;
  white-space: nowrap;
}
.lp-btn:active { transform: translateY(1px); }
.lp-btn-primary {
  background: var(--lp-teal);
  color: #ffffff;
  border-color: var(--lp-teal);
  box-shadow: var(--lp-shadow-teal);
}
.lp-btn-primary:hover {
  background: var(--lp-teal-deep);
  border-color: var(--lp-teal-deep);
  box-shadow: 0 8px 20px rgba(14, 165, 163, .32);
  transform: translateY(-1px);
}
.lp-btn-ghost {
  background: transparent;
  color: var(--lp-ink);
  border-color: var(--lp-line-strong);
}
.lp-btn-ghost:hover {
  background: var(--lp-bg-tint);
  border-color: var(--lp-teal);
  color: var(--lp-teal-deep);
}
.lp-btn-lg { padding: 14px 26px; font-size: 16px; }
.lp-btn-block { display: flex; width: 100%; }

/* ── Hero ───────────────────────────────────────────────────────────────
   Modernized: bigger editorial typography, single subtle teal glow
   instead of the dual-gradient blob mesh, "Pass." accent is now a
   teal underline-highlight (not a gradient text fill — reads more
   confident). The hero art is a real product preview (stat tiles +
   mini heatmap) instead of a giant generic icon — gives visitors a
   60-second feel for what the app actually looks like before they
   click Start free. */
.lp-hero {
  position: relative;
  /* Reduced bottom padding (was 56px) — the trust strip provides a
     visual closer for the hero, and the numbers section below has its
     own top padding, so this generous extra padding was redundant. */
  padding: 32px 32px 20px;
  background: var(--lp-bg);
  overflow: hidden;
  isolation: isolate;
}
.lp-hero::before {
  /* Single very subtle teal glow top-right — calmer than the previous
     two-blob mesh. Sits behind everything else and respects the
     z-index layering. */
  content: "";
  position: absolute;
  top: -240px; right: -160px;
  width: 720px; height: 720px;
  background: radial-gradient(closest-side, rgba(14,165,163,.14), transparent 70%);
  filter: blur(20px);
  pointer-events: none;
  z-index: -1;
}
.lp-hero-inner {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 48px;
  align-items: center;
  max-width: 1200px;
  margin: 24px auto 36px;
}
.lp-hero-copy { display: flex; flex-direction: column; gap: 22px; max-width: 620px; }
.lp-eyebrow {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--lp-bg-tint);
  border: 1px solid rgba(14,165,163,.25);
  color: var(--lp-teal-deep);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.lp-eyebrow::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--lp-teal);
  box-shadow: 0 0 0 3px rgba(14,165,163,.20);
}
.lp-h1 {
  font-size: clamp(40px, 7vw, 72px);
  line-height: 1.02;
  font-weight: 800;
  letter-spacing: -.028em;
  color: var(--lp-ink);
}
.lp-h1-accent {
  /* Calm-clinical accent — solid teal text with a subtle highlight
     swatch behind it. Reads more confident than the previous teal-sky
     gradient text fill, and matches the rest of the app where gradient
     text fills have been retired. */
  position: relative;
  color: var(--lp-teal);
  background: none;
  -webkit-background-clip: initial;
  background-clip: initial;
  display: inline-block;
}
.lp-h1-accent::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 4%;
  height: 18%;
  background: rgba(14,165,163,.14);
  border-radius: 4px;
  z-index: -1;
}
.lp-lede {
  font-size: 19px;
  line-height: 1.55;
  color: var(--lp-ink-soft);
  max-width: 58ch;
}
.lp-hero-ctas {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 4px;
}
.lp-hero-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  color: var(--lp-ink-mute);
  font-size: 14px;
}
.lp-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.lp-meta-item::before {
  content: "✓";
  color: var(--lp-teal);
  font-weight: 700;
  font-size: 13px;
}
.lp-meta-dot { display: none; }   /* Replaced by the inline check marks above */

/* ── Hero art: rotating feature carousel ───────────────────────────────
   Tab-driven crossfade carousel cycling through four real-shape app
   mockups (subject-mastery radar, 12-week heatmap, daily streak card,
   practice question card). Auto-advances every 4s, pauses on hover so
   readers can absorb a slide, click any tab to jump + reset the
   interval. JS in landing.js manages the rotation; CSS handles layout
   and the crossfade. Honors prefers-reduced-motion (auto-advance
   disabled, slide swap is instant rather than animated). */
.lp-hero-art {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  min-height: 480px;
  isolation: isolate;
}
.lp-hero-glow {
  position: absolute;
  inset: 12% 6% 8%;
  background: radial-gradient(closest-side, rgba(14,165,163,.22), transparent 70%);
  filter: blur(40px);
  z-index: 0;
  pointer-events: none;
}

/* Tab pill row sits above the stage — 4 small chips, one filled-teal
   active state. Click handler in JS jumps the carousel + resets the
   auto-advance timer. */
.lp-hero-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  position: relative;
  z-index: 2;
  padding: 4px;
  background: rgba(255,255,255,.65);
  border: 1px solid var(--lp-line);
  border-radius: 999px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.lp-hero-tab {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  background: transparent;
  font: inherit;
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--lp-ink-mute);
  cursor: pointer;
  transition: color var(--lp-ease) 150ms,
              background var(--lp-ease) 150ms,
              box-shadow var(--lp-ease) 150ms;
  white-space: nowrap;
}
.lp-hero-tab:hover {
  color: var(--lp-teal-deep);
}
.lp-hero-tab[aria-selected="true"] {
  background: var(--lp-teal);
  color: #ffffff;
  box-shadow: var(--lp-shadow-teal);
}

/* Stage — fixed-aspect frame the slides crossfade inside. Each slide
   is absolutely positioned and faded via opacity. The active one
   becomes opacity:1, others go opacity:0. We also do a subtle
   translate-Y on the entering slide so it slides up while fading in. */
.lp-hero-stage {
  position: relative;
  width: 100%;
  max-width: 440px;
  /* aspect-ratio: 1 / 1 — square frame sized to fit the tallest slide
     (mastery radar at ~410px) without trailing empty space. Was 4/5
     which left ~110px of dead air below the radar caption. */
  aspect-ratio: 1 / 1;
  z-index: 1;
}
.lp-hero-slide {
  position: absolute;
  inset: 0;
  background: #ffffff;
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  box-shadow: var(--lp-shadow-md);
  padding: 22px 22px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 600ms var(--lp-ease),
              transform 600ms var(--lp-ease);
  pointer-events: none;
}
.lp-hero-slide.is-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .lp-hero-slide {
    transition: opacity 0ms;
    transform: none;
  }
}

/* Slide common bits — header eyebrow + right-aligned meta. */
.lp-slide-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.lp-slide-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--lp-teal-deep);
}
.lp-slide-eyebrow::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--lp-teal);
}
.lp-slide-meta {
  font-size: 11.5px;
  color: var(--lp-ink-mute);
  font-variant-numeric: tabular-nums;
}
.lp-slide-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--lp-ink);
  letter-spacing: -.011em;
  margin: 0;
}
.lp-slide-foot {
  margin-top: auto;
  font-size: 11.5px;
  color: var(--lp-ink-mute);
  line-height: 1.45;
}

/* ── Slide 1: Subject mastery radar ────────────────────────────────── */
.lp-slide-radar {
  align-items: stretch;
}
.lp-slide-radar svg {
  flex: 1 1 auto;
  width: 100%;
  height: auto;
  max-height: 280px;
  display: block;
  margin: 0 auto;
}
.lp-radar-grid { stroke: var(--lp-line); fill: none; stroke-width: 1; }
.lp-radar-grid-mid { stroke: var(--lp-line-strong); }
.lp-radar-axis { stroke: var(--lp-line); stroke-width: 1; stroke-dasharray: 2 4; }
.lp-radar-fill { fill: var(--lp-teal); fill-opacity: .22; stroke: var(--lp-teal); stroke-width: 2; }
.lp-radar-dot { fill: var(--lp-teal); }
.lp-radar-label {
  fill: var(--lp-ink);
  font-size: 9.5px;
  font-weight: 600;
  font-family: inherit;
}
.lp-radar-tick {
  fill: var(--lp-ink-mute);
  font-size: 8.5px;
  font-weight: 500;
  font-family: inherit;
}

/* ── Slide 2: Heatmap ──────────────────────────────────────────────── */
.lp-slide-heatmap-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 4px;
  margin-top: 4px;
}
.lp-slide-heatmap-grid > span {
  display: block;
  aspect-ratio: 1;
  border-radius: 3px;
  background: var(--lp-bg-soft);
}
.lp-slide-heatmap-grid > span.lvl-1 { background: rgba(14,165,163,.18); }
.lp-slide-heatmap-grid > span.lvl-2 { background: rgba(14,165,163,.40); }
.lp-slide-heatmap-grid > span.lvl-3 { background: rgba(14,165,163,.65); }
.lp-slide-heatmap-grid > span.lvl-4 { background: var(--lp-teal); }
.lp-slide-heatmap-legend {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  color: var(--lp-ink-mute);
}
.lp-slide-heatmap-legend-scale {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.lp-slide-heatmap-legend-scale > span {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--lp-bg-soft);
}
.lp-slide-heatmap-legend-scale > span.lvl-1 { background: rgba(14,165,163,.18); }
.lp-slide-heatmap-legend-scale > span.lvl-2 { background: rgba(14,165,163,.40); }
.lp-slide-heatmap-legend-scale > span.lvl-3 { background: rgba(14,165,163,.65); }
.lp-slide-heatmap-legend-scale > span.lvl-4 { background: var(--lp-teal); }

/* ── Slide 3: Streak card ──────────────────────────────────────────── */
.lp-slide-streak-row {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 14px 0 8px;
}
.lp-slide-streak-flame {
  flex: 0 0 auto;
  width: 64px; height: 64px;
  display: grid;
  place-items: center;
  font-size: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, rgba(217,119,6,.18), rgba(220,38,38,.10));
  border: 1px solid rgba(217,119,6,.30);
}
.lp-slide-streak-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.lp-slide-streak-num {
  font-size: 38px;
  font-weight: 800;
  letter-spacing: -.025em;
  color: var(--lp-ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.lp-slide-streak-lbl {
  font-size: 13px;
  color: var(--lp-ink-soft);
  font-weight: 500;
}
.lp-slide-target {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.lp-slide-target-row {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: var(--lp-ink-soft);
}
.lp-slide-target-row strong {
  color: var(--lp-ink);
  font-variant-numeric: tabular-nums;
}
.lp-slide-bar {
  height: 8px;
  border-radius: 999px;
  background: var(--lp-bg-soft);
  overflow: hidden;
  position: relative;
}
.lp-slide-bar-fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  background: var(--lp-teal);
  border-radius: 999px;
}
.lp-slide-streak-mini {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  margin-top: 4px;
}
.lp-slide-streak-mini > span {
  aspect-ratio: 1;
  border-radius: 4px;
  background: var(--lp-bg-soft);
  display: grid;
  place-items: center;
  font-size: 9px;
  font-weight: 600;
  color: var(--lp-ink-mute);
}
.lp-slide-streak-mini > span.done {
  background: var(--lp-teal);
  color: #ffffff;
}
.lp-slide-streak-mini > span.today {
  background: rgba(14,165,163,.18);
  color: var(--lp-teal-deep);
  border: 1.5px solid var(--lp-teal);
}

/* ── Slide 4: Practice question mock ──────────────────────────────── */
.lp-slide-question {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--lp-ink);
  margin: 4px 0 6px;
  font-weight: 500;
}
.lp-slide-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.lp-slide-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  background: var(--lp-bg);
  font-size: 12.5px;
  color: var(--lp-ink);
  transition: border-color var(--lp-ease) 150ms, background var(--lp-ease) 150ms;
}
.lp-slide-option-letter {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--lp-bg-soft);
  border: 1px solid var(--lp-line-strong);
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--lp-ink-mute);
}
.lp-slide-option.is-correct {
  border-color: var(--lp-teal);
  background: rgba(14,165,163,.06);
}
.lp-slide-option.is-correct .lp-slide-option-letter {
  background: var(--lp-teal);
  border-color: var(--lp-teal);
  color: #ffffff;
}
.lp-slide-option.is-correct::after {
  content: "✓";
  margin-left: auto;
  color: var(--lp-teal);
  font-weight: 700;
}

/* ── Slide: Practice question (with flip-to-explanation) ──────────────
   Same 3D-flip mechanism as the flashcard slide — front shows the
   question + 4 options unanswered, back shows the correct answer
   (highlighted) + the "why" + bookmark/review actions. The flip
   demonstrates the core practice loop: read → answer → understand →
   spaced-repetition queue. Auto-flips every 4.5s; honors reduced-
   motion (animation paused, front face shown). */
.lp-slide-pq-stack {
  position: relative;
  flex: 1 1 auto;
  perspective: 1400px;
  margin: 2px 0;
  min-height: 220px;
}
.lp-slide-pq-flipper {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  animation: lp-pq-flip 4.5s ease-in-out infinite;
  z-index: 1;
}
@keyframes lp-pq-flip {
  0%, 38%   { transform: rotateY(0deg); }
  50%, 88%  { transform: rotateY(180deg); }
  100%      { transform: rotateY(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .lp-slide-pq-flipper { animation: none; }
}
/* Hover pause — when the user is reading a slide, freeze the flip
   so they can absorb the front or back face without it rotating
   away. Pairs with the JS rotation-pause already on .lp-hero-art. */
.lp-hero-art:hover .lp-slide-pq-flipper {
  animation-play-state: paused;
}
.lp-slide-pq-front,
.lp-slide-pq-back {
  position: absolute;
  inset: 0;
  border: 1px solid var(--lp-line);
  background: var(--lp-bg);
  border-radius: var(--lp-radius-sm);
  padding: 14px 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
  box-shadow: var(--lp-shadow-sm);
}
.lp-slide-pq-back {
  transform: rotateY(180deg);
  border-color: rgba(14,165,163,.30);
  background:
    linear-gradient(180deg, rgba(14,165,163,.05) 0%, transparent 35%),
    var(--lp-bg);
}
.lp-slide-pq-question {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--lp-ink);
  margin: 0;
  font-weight: 500;
}
.lp-slide-pq-options {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  justify-content: center;
}
.lp-slide-pq-option {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 10px;
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  font-size: 11.5px;
  color: var(--lp-ink);
  background: var(--lp-bg);
}
.lp-slide-pq-option-letter {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--lp-bg-soft);
  border: 1px solid var(--lp-line-strong);
  display: grid;
  place-items: center;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--lp-ink-mute);
}

/* Back-side rules — answer card, explanation, action chips. */
.lp-slide-pq-back-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
}
.lp-slide-pq-correct {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--lp-teal);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  font-size: 10.5px;
}
.lp-slide-pq-correct::before {
  content: "✓";
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--lp-teal);
  color: #ffffff;
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
}
.lp-slide-pq-streak {
  color: var(--lp-ink-mute);
  font-size: 10.5px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.lp-slide-pq-answer-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--lp-teal);
  background: rgba(14,165,163,.08);
  border-radius: var(--lp-radius-sm);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--lp-ink);
}
.lp-slide-pq-answer-letter {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--lp-teal);
  color: #ffffff;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 700;
}
.lp-slide-pq-why {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--lp-ink-soft);
  flex: 1 1 auto;
  overflow: hidden;
}
.lp-slide-pq-why strong {
  color: var(--lp-ink);
}
/* Clinical rule callout on practice back face — same visual language
   as the in-app .clinical-rule highlight: warm amber-tinted background,
   3px solid amber-deep left bar, small RULE eyebrow with 📌 prefix.
   Sits between the explanation paragraph and the action chips. */
.lp-slide-pq-rule {
  font-size: 11px;
  line-height: 1.45;
  color: var(--lp-ink);
  background: rgba(217, 119, 6, .08);
  border: 1px solid rgba(217, 119, 6, .25);
  border-left: 3px solid #d97706;
  border-radius: 6px;
  padding: 7px 9px;
}
.lp-slide-pq-rule-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #92400e;
  margin-bottom: 3px;
}
.lp-slide-pq-rule-tag::before {
  content: "📌";
  font-size: 11px;
  letter-spacing: 0;
}

.lp-slide-pq-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.lp-slide-pq-action {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border: 1px solid var(--lp-line);
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--lp-ink-soft);
  background: var(--lp-bg);
}

/* ── Slide: Flashcard mode ─────────────────────────────────────────────
   Real 3D flip animation — the card rotates on the Y axis showing
   question, then answer, looping every 4.5s. Stacked card shadows
   behind it suggest "you're 1 of many in the deck", which makes the
   spaced-repetition story land visually. The flipper uses
   transform-style: preserve-3d + backface-visibility: hidden so each
   face shows only when it's facing the viewer. Honors
   prefers-reduced-motion: animation paused, both faces visible (the
   front sits on top so reader sees question; back is hidden by
   backface-visibility regardless). */
.lp-slide-fc-stack {
  position: relative;
  flex: 1 1 auto;
  perspective: 1400px;
  margin: 2px 0;
  min-height: 140px;
}
/* Ghost cards stacked behind the flipper — read as a deck. The
   slight rotation + offset makes them look like physical cards
   peeking from underneath. */
.lp-slide-fc-stack-shadow {
  position: absolute;
  inset: 0;
  background: var(--lp-bg-soft);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  transform: translate(4px, 5px) rotate(1.6deg);
  z-index: 0;
  pointer-events: none;
}
.lp-slide-fc-stack-shadow-2 {
  transform: translate(-4px, 9px) rotate(-1.4deg);
  opacity: .65;
}
.lp-slide-fc-flipper {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  animation: lp-fc-flip 4.5s ease-in-out infinite;
  z-index: 1;
}
@keyframes lp-fc-flip {
  0%, 38%   { transform: rotateY(0deg); }
  50%, 88%  { transform: rotateY(180deg); }
  100%      { transform: rotateY(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .lp-slide-fc-flipper { animation: none; }
}
/* Hover pause — same rule as the practice flipper. */
.lp-hero-art:hover .lp-slide-fc-flipper {
  animation-play-state: paused;
}
.lp-slide-fc-front,
.lp-slide-fc-back {
  position: absolute;
  inset: 0;
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  padding: 16px 18px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  box-shadow: var(--lp-shadow-sm);
}
.lp-slide-fc-back {
  transform: rotateY(180deg);
  border-color: rgba(14,165,163,.35);
  background:
    linear-gradient(180deg, rgba(14,165,163,.04) 0%, transparent 40%),
    var(--lp-bg);
}
.lp-slide-fc-face-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--lp-teal);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.lp-slide-fc-face-eyebrow::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--lp-teal);
}
.lp-slide-fc-q {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--lp-ink);
  font-weight: 500;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
}
.lp-slide-fc-hint {
  font-size: 10.5px;
  color: var(--lp-ink-mute);
  text-align: center;
  padding-top: 8px;
  border-top: 1px dashed var(--lp-line);
  letter-spacing: .04em;
  text-transform: uppercase;
  font-weight: 600;
}
.lp-slide-fc-a {
  font-size: 13px;
  line-height: 1.5;
  color: var(--lp-ink-soft);
  flex: 1 1 auto;
}
.lp-slide-fc-a strong {
  display: block;
  font-size: 16px;
  color: var(--lp-teal-deep);
  margin-bottom: 6px;
  font-weight: 700;
  letter-spacing: -.011em;
}
.lp-slide-fc-next {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--lp-teal-deep);
  background: rgba(14,165,163,.08);
  border: 1px solid rgba(14,165,163,.25);
  padding: 4px 10px;
  border-radius: 999px;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  letter-spacing: .02em;
}

/* CLINICAL RULE callout — amber-highlighted takeaway box on the back
   of the flashcard. Same visual language as the in-app .clinical-rule
   span (RTE inline mark): warm amber tint, 3px left bar, small RULE
   eyebrow. Reads as "key takeaway / clinical pearl" without competing
   with the teal answer. */
.lp-slide-fc-rule {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--lp-ink);
  background: rgba(217, 119, 6, .08);
  border: 1px solid rgba(217, 119, 6, .25);
  border-left: 3px solid #d97706;
  border-radius: 6px;
  padding: 8px 10px;
}
.lp-slide-fc-rule-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #92400e;
  margin-bottom: 4px;
}
.lp-slide-fc-rule-tag::before {
  content: "📌";
  font-size: 11px;
  letter-spacing: 0;
}
.lp-slide-fc-grades {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
.lp-slide-fc-grade {
  padding: 9px 6px 8px;
  border-radius: var(--lp-radius-sm);
  border: 1px solid;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: center;
  background: var(--lp-bg);
}
.lp-slide-fc-grade-key {
  display: block;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: -.01em;
  text-transform: none;
  margin-bottom: 1px;
}
.lp-slide-fc-grade.again { color: #dc2626; border-color: rgba(220,38,38,.30); }
.lp-slide-fc-grade.hard  { color: #d97706; border-color: rgba(217,119,6,.30); }
.lp-slide-fc-grade.good  { color: #ffffff; background: var(--lp-teal); border-color: var(--lp-teal); box-shadow: var(--lp-shadow-teal); }
.lp-slide-fc-grade.easy  { color: var(--lp-sky); border-color: rgba(2,132,199,.30); }

/* ── Slide: Multiplayer race + weekly leaderboard ──────────────────────
   Two visual layers: a compact head-to-head live race up top (avatars,
   live scores, twin progress bars, LIVE indicator + speed-bonus chip),
   and a 3-row weekly Elo leaderboard with gold/silver/bronze rank
   medals at the bottom. The user appears at #2 (silver) with a
   teal-tinted row highlight, sitting between Aleksi N. (gold) and
   Maya M. (bronze) — aspirational social-proof positioning that says
   "you're competitive, climbing fast". */

/* ─ Match section ─────────────────────────────────────────────────── */
.lp-slide-mp-match {
  background: var(--lp-bg-soft);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  padding: 12px 14px 10px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.lp-slide-mp-vs {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
}
.lp-slide-mp-side {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.lp-slide-mp-side.you  { justify-content: flex-start; }
.lp-slide-mp-side.opp  { justify-content: flex-end; }
.lp-slide-mp-side-avatar {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 17px;
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
}
.lp-slide-mp-side.you .lp-slide-mp-side-avatar {
  border-color: var(--lp-teal);
  box-shadow: 0 0 0 2px rgba(14,165,163,.16);
}
.lp-slide-mp-side-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.lp-slide-mp-side.opp .lp-slide-mp-side-info { align-items: flex-end; }
.lp-slide-mp-side-name {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--lp-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lp-slide-mp-side-score {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -.025em;
  color: var(--lp-ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.lp-slide-mp-side.you .lp-slide-mp-side-score {
  color: var(--lp-teal-deep);
}
.lp-slide-mp-vs-divider {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .12em;
  color: var(--lp-ink-mute);
  padding: 4px 8px;
  border: 1px solid var(--lp-line);
  border-radius: 999px;
  background: var(--lp-bg);
}

/* Twin progress bars — one per player, side by side. */
.lp-slide-mp-progress-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.lp-slide-mp-progress {
  height: 5px;
  border-radius: 999px;
  background: var(--lp-bg);
  position: relative;
  overflow: hidden;
}
.lp-slide-mp-progress > span {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  border-radius: 999px;
}
.lp-slide-mp-progress.you > span { background: var(--lp-teal); }
.lp-slide-mp-progress.opp > span { background: var(--lp-line-strong); }

.lp-slide-mp-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 11px;
  color: var(--lp-ink-mute);
}
.lp-slide-mp-live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .10em;
  text-transform: uppercase;
  color: var(--lp-teal);
}
.lp-slide-mp-live::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--lp-teal);
  animation: lp-pulse 1.5s ease-in-out infinite;
}
.lp-slide-mp-bonus {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(217,119,6,.10);
  border: 1px solid rgba(217,119,6,.25);
  color: #92400e;
  font-size: 10.5px;
  font-weight: 700;
}
@keyframes lp-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .35; }
}
@media (prefers-reduced-motion: reduce) {
  .lp-slide-mp-live::before { animation: none; }
}

/* ─ Leaderboard section ───────────────────────────────────────────── */
.lp-slide-mp-board {
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  padding: 8px 10px 6px;
  background: var(--lp-bg);
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 auto;
  min-height: 0;
}
.lp-slide-mp-board-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .10em;
  text-transform: uppercase;
  color: var(--lp-teal-deep);
  padding: 2px 2px 6px;
  border-bottom: 1px solid var(--lp-line);
  margin-bottom: 2px;
}
.lp-slide-mp-board-meta {
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: none;
  font-size: 10px;
  color: var(--lp-ink-mute);
}
.lp-slide-mp-board-row {
  display: grid;
  grid-template-columns: 24px 22px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 4px 4px;
  font-size: 12px;
  border-radius: 6px;
  border: 1px solid transparent;
}
.lp-slide-mp-board-row.is-you {
  background: rgba(14,165,163,.10);
  border-color: rgba(14,165,163,.30);
}
.lp-slide-mp-rank {
  width: 22px; height: 22px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 10.5px;
  font-weight: 800;
  background: var(--lp-bg-soft);
  color: var(--lp-ink-mute);
  border: 1px solid var(--lp-line);
}
.lp-slide-mp-board-row.gold .lp-slide-mp-rank {
  background: #f59e0b;
  color: #ffffff;
  border-color: #d97706;
  box-shadow: 0 1px 4px rgba(245, 158, 11, .35);
}
.lp-slide-mp-board-row.silver .lp-slide-mp-rank {
  background: #94a3b8;
  color: #ffffff;
  border-color: #64748b;
  box-shadow: 0 1px 4px rgba(100, 116, 139, .25);
}
.lp-slide-mp-board-row.bronze .lp-slide-mp-rank {
  background: #b45309;
  color: #ffffff;
  border-color: #92400e;
  box-shadow: 0 1px 4px rgba(180, 83, 9, .28);
}
.lp-slide-mp-board-avatar {
  font-size: 16px;
  text-align: center;
  line-height: 1;
}
.lp-slide-mp-board-name {
  font-weight: 600;
  color: var(--lp-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lp-slide-mp-board-row.is-you .lp-slide-mp-board-name {
  color: var(--lp-teal-deep);
}
.lp-slide-mp-board-elo {
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--lp-ink);
}

/* ── Slide 7: Answer explanation ───────────────────────────────────── */
.lp-slide-explain-q {
  font-size: 12px;
  color: var(--lp-ink-mute);
  line-height: 1.45;
  padding: 10px 12px;
  background: var(--lp-bg-soft);
  border-radius: var(--lp-radius-sm);
  margin: 0;
}
.lp-slide-explain-answer {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--lp-teal);
  background: rgba(14,165,163,.08);
  border-radius: var(--lp-radius-sm);
  font-size: 13px;
  font-weight: 600;
  color: var(--lp-ink);
}
.lp-slide-explain-answer-letter {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--lp-teal);
  color: #ffffff;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 700;
}
.lp-slide-explain-check {
  margin-left: auto;
  color: var(--lp-teal);
  font-weight: 700;
}
.lp-slide-explain-why {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--lp-ink-soft);
  padding: 10px 0 0;
  border-top: 1px solid var(--lp-line);
}
.lp-slide-explain-why strong {
  color: var(--lp-ink);
}
.lp-slide-explain-actions {
  display: flex;
  gap: 6px;
  margin-top: auto;
}
.lp-slide-explain-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--lp-line);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  color: var(--lp-ink-soft);
  background: var(--lp-bg);
}
.lp-slide-meta.is-correct {
  color: var(--lp-teal);
  font-weight: 700;
}

/* ── Tab indicator dots (fallback for narrow widths) ───────────────── */
.lp-hero-dots {
  display: none;        /* tabs handle this on desktop; dots only kick in below 540px if needed */
  gap: 6px;
  z-index: 2;
}
.lp-hero-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--lp-line-strong);
  border: none;
  padding: 0;
  cursor: pointer;
  transition: background var(--lp-ease) 150ms, transform var(--lp-ease) 150ms;
}
.lp-hero-dot[aria-selected="true"] {
  background: var(--lp-teal);
  transform: scale(1.4);
}

/* Trust strip — bumped from a faintly muted footnote to a more confident
   social-proof line: ink-soft (not ink-mute), 15px, country names bold,
   leading globe icon. Still under-stated enough to read as a footer
   under the hero, not a headline. Padding tightened so the gap to the
   numbers row below is smaller. */
.lp-trust-strip {
  max-width: 1100px;
  margin: 8px auto 0;
  padding: 12px 24px 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  font-size: 15px;
  line-height: 1.5;
  color: var(--lp-ink-soft);
  border-top: 1px solid var(--lp-line);
  flex-wrap: wrap;
}
.lp-trust-strip strong {
  color: var(--lp-ink);
  font-weight: 600;
}
.lp-trust-icon {
  font-size: 18px;
  line-height: 1;
}

/* ── By-the-numbers stat strip ──────────────────────────────────────────
   Sits between hero and features. Three big-numeral counters that
   communicate scale instantly. Clean grid, restrained shadows, no
   decorative icons — modern marketing pages let the numbers carry
   the moment. */
/* Slate-50 mist background extends edge-to-edge — matches the
   .lp-howitworks treatment so the numbers strip reads as a distinct
   "section break" between the white hero and the white feature
   bento. max-width moved to the inner grid so only the content
   stays centered while the background fills the full viewport. */
.lp-numbers {
  background: var(--lp-bg-soft);
  /* Top padding tightened (was 56px) so the numbers row sits closer to
     the trust strip + hero — they read as one continuous "first pass"
     above the fold rather than two separated sections. */
  padding: 36px 32px 48px;
}
.lp-numbers-grid {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  align-items: stretch;
  text-align: center;
}
.lp-number-cell {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 18px 12px;
  border-left: 1px solid var(--lp-line);
}
.lp-number-cell:first-child { border-left: none; }
.lp-number-cell-num {
  font-size: clamp(32px, 4vw, 44px);
  font-weight: 800;
  letter-spacing: -.025em;
  color: var(--lp-ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.lp-number-cell-num .lp-number-unit {
  font-size: .55em;
  font-weight: 700;
  color: var(--lp-teal);
  letter-spacing: 0;
  margin-left: 2px;
}
.lp-number-cell-lbl {
  font-size: 13px;
  font-weight: 500;
  color: var(--lp-ink-mute);
  margin-top: 8px;
}
@media (max-width: 760px) {
  .lp-numbers { padding: 40px 18px; }
  .lp-numbers-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
  }
  .lp-number-cell {
    border-left: none;
    border-top: 1px solid var(--lp-line);
    padding: 14px 8px;
  }
  .lp-number-cell:first-child,
  .lp-number-cell:nth-child(2) { border-top: none; }
}

/* ── Generic section ──────────────────────────────────────────────────── */
.lp-section {
  padding: 80px 32px;
  max-width: 1200px;
  margin: 0 auto;
}
.lp-section-head {
  text-align: center;
  max-width: 720px;
  margin: 0 auto 40px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.lp-section-head h2 {
  font-size: clamp(28px, 3.5vw, 40px);
  font-weight: 800;
  letter-spacing: -.02em;
}
.lp-section-sub {
  font-size: 17px;
  line-height: 1.55;
  color: var(--lp-ink-soft);
}

/* ── Features (bento) ───────────────────────────────────────────────────
   Modern bento layout — 12-column grid, first card spans 2 cols x 2
   rows for the killer feature (Flashcard mode). Other cards span
   1 col each. Reads as editorial / data-density rather than the
   even-grid tile pattern. Mobile collapses to a single column. */
.lp-feature-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 18px;
  grid-auto-rows: minmax(180px, auto);
}
.lp-feature {
  position: relative;
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  padding: 26px 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: transform var(--lp-ease) 200ms,
              box-shadow var(--lp-ease) 200ms,
              border-color var(--lp-ease) 200ms;
  grid-column: span 4;
  overflow: hidden;
}
.lp-feature:hover {
  transform: translateY(-3px);
  box-shadow: var(--lp-shadow-md);
  border-color: var(--lp-line-strong);
}
/* Featured cell — spans 6 cols on desktop, anchors the bento grid. */
.lp-feature.lp-feature-hero {
  grid-column: span 6;
  grid-row: span 2;
  background:
    linear-gradient(135deg, rgba(14,165,163,.04) 0%, rgba(2,132,199,.04) 100%),
    var(--lp-bg);
  border-color: rgba(14,165,163,.25);
}
.lp-feature.lp-feature-hero::before {
  /* Top-right accent glow for the hero cell only. */
  content: "";
  position: absolute;
  top: -80px; right: -80px;
  width: 260px; height: 260px;
  background: radial-gradient(closest-side, rgba(14,165,163,.16), transparent 70%);
  filter: blur(20px);
  pointer-events: none;
}
.lp-feature.lp-feature-hero h3 {
  font-size: clamp(22px, 2.4vw, 28px);
  letter-spacing: -.018em;
}
.lp-feature.lp-feature-hero p {
  font-size: 16px;
  max-width: 52ch;
}
.lp-feature.lp-feature-hero .lp-feature-icon {
  width: 56px;
  height: 56px;
  border-radius: 14px;
}
/* The two cells immediately following the 6-col-wide hero share the
   right column with it (one in row 1, one in row 2). Bump them to
   span 6 cols each so the right column fills cleanly — otherwise the
   default span-4 leaves 2 dead cols at the far right of those rows. */
.lp-feature-grid > .lp-feature.lp-feature-hero + .lp-feature,
.lp-feature-grid > .lp-feature.lp-feature-hero + .lp-feature + .lp-feature {
  grid-column: span 6;
}
@media (max-width: 980px) {
  .lp-feature-grid { grid-template-columns: repeat(6, 1fr); }
  .lp-feature { grid-column: span 3; }
  .lp-feature.lp-feature-hero { grid-column: span 6; grid-row: auto; }
  /* At the 6-col breakpoint the right-column cells revert to the
     standard 3-col half-row width — the hero has dropped its row-span
     so they no longer need to fill the right side of the bento. */
  .lp-feature-grid > .lp-feature.lp-feature-hero + .lp-feature,
  .lp-feature-grid > .lp-feature.lp-feature-hero + .lp-feature + .lp-feature {
    grid-column: span 3;
  }
}
@media (max-width: 540px) {
  .lp-feature-grid { grid-template-columns: 1fr; gap: 14px; }
  .lp-feature, .lp-feature.lp-feature-hero { grid-column: 1 / -1; }
}
.lp-feature-icon {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--lp-bg-tint);
  color: var(--lp-teal);
  margin-bottom: 4px;
  border: 1px solid rgba(14,165,163,.18);
}
.lp-feature h3 {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -.011em;
  color: var(--lp-ink);
}
.lp-feature p {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--lp-ink-soft);
}

/* ── How it works ─────────────────────────────────────────────────────── */
.lp-howitworks { background: var(--lp-bg-soft); border-radius: 0; max-width: none; }
.lp-howitworks .lp-section-head,
.lp-howitworks .lp-steps {
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}
.lp-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.lp-steps li {
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  padding: 26px 22px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  position: relative;
}
.lp-step-num {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-weight: 800;
  font-size: 16px;
  color: #ffffff;
  background: var(--lp-teal);
  margin-bottom: 4px;
  box-shadow: var(--lp-shadow-teal);
}
.lp-steps h3 { font-size: 17px; font-weight: 700; }
.lp-steps p { font-size: 14.5px; line-height: 1.55; }

/* ── Pricing ──────────────────────────────────────────────────────────── */

/* Intro promo banner — sits above the plan grid, calls out the
   $3.99 first-month deal + the INTRO promo code. Subtle amber-to-teal
   gradient tint so it draws the eye without competing with the plan
   cards below. The 🎉 emoji wiggles every ~2.4s to add a touch of
   movement (honors prefers-reduced-motion). */
.lp-promo-banner {
  max-width: 760px;
  margin: 0 auto 32px;
  display: inline-flex;
  align-items: center;
  /* gap was 14px to space the 🎉 emoji from the text; with the
     emoji removed, drop the gap so the centered text sits flush
     and the pill reads as a single content block. */
  gap: 0;
  padding: 10px 22px;
  border-radius: 999px;
  background: linear-gradient(120deg,
    rgba(217, 119, 6, 0.10) 0%,
    rgba(14, 165, 163, 0.08) 100%);
  border: 1px solid rgba(217, 119, 6, 0.30);
  font-size: 14px;
  color: var(--lp-ink);
  flex-wrap: wrap;
  justify-content: center;
  text-align: center;
}
.lp-promo-banner-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 32px;
}
.lp-promo-banner strong { color: var(--lp-ink); font-weight: 700; }
.lp-promo-pulse {
  font-size: 18px;
  display: inline-block;
  animation: lp-promo-wiggle 2.6s ease-in-out infinite;
  transform-origin: 70% 70%;
}
@keyframes lp-promo-wiggle {
  0%, 60%, 100% { transform: rotate(0deg); }
  68% { transform: rotate(-14deg); }
  76% { transform: rotate(14deg); }
  84% { transform: rotate(-8deg); }
  92% { transform: rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .lp-promo-pulse { animation: none; }
}
.lp-promo-code {
  display: inline-block;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--lp-bg);
  border: 1px solid var(--lp-line-strong);
  padding: 2px 9px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--lp-teal-deep);
}

.lp-plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 20px;
  max-width: 1100px;
  margin: 0 auto;
}
/* Two-card variant (Pro Monthly + Pro Yearly only). The standalone
   Free card was retired in favour of the lp-plan-free-note line below
   the grid, so we tighten max-width so the two cards don't stretch
   uncomfortably wide on desktop. Auto-fit handles the wrap on mobile. */
.lp-plan-grid.lp-plan-grid-2up {
  max-width: 820px;
}

/* Free-plan note — moved above the plan grid (was below it). Sits
   between the section subtitle and the intro promo banner so the
   "no-card free tier" pitch surfaces immediately without the user
   having to scan past two paid cards first. Wrapped in a flex
   container so the pill is true-centered horizontally regardless
   of its content width (replaces margin:auto centering which can
   look offset on wide viewports when paired with the wider plan
   grid below). Calmly muted (ink-soft) so the paid plans stay the
   visual focus, with a teal CTA link at the end. */
.lp-plan-free-note-wrap {
  display: flex;
  justify-content: center;
  margin: 0 auto 24px;
}
.lp-plan-free-note {
  margin: 0;
  max-width: 680px;
  padding: 14px 22px;
  text-align: center;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--lp-ink-soft);
  background: var(--lp-bg-soft);
  border: 1px solid var(--lp-line);
  border-radius: 999px;
}
.lp-plan-free-note strong { color: var(--lp-ink); font-weight: 700; }
.lp-plan-free-note a {
  color: var(--lp-teal-deep);
  font-weight: 600;
  white-space: nowrap;
  margin-left: 4px;
}
.lp-plan-free-note a:hover { color: var(--lp-teal); }
@media (max-width: 540px) {
  .lp-plan-free-note {
    border-radius: var(--lp-radius);
    font-size: 14px;
  }
}
.lp-plan-card {
  position: relative;
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  padding: 32px 26px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-shadow: var(--lp-shadow-sm);
}
.lp-plan-card-featured {
  border: 2px solid var(--lp-teal);
  border-radius: var(--lp-radius-lg);
  box-shadow: var(--lp-shadow-md), 0 0 0 6px rgba(14,165,163,.06);
  transform: translateY(-4px);
}
.lp-plan-ribbon {
  position: absolute;
  top: -12px;
  right: 24px;
  background: var(--lp-teal);
  color: #ffffff;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 6px 14px;
  border-radius: 999px;
  box-shadow: var(--lp-shadow-teal);
}
.lp-plan-name {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--lp-teal-deep);
}
.lp-plan-price {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.lp-plan-amount {
  font-size: 44px;
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--lp-ink);
}
.lp-plan-per {
  font-size: 14px;
  color: var(--lp-ink-mute);
}
.lp-plan-sub {
  font-size: 14px;
  color: var(--lp-ink-soft);
  min-height: 38px;
}
.lp-plan-points {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 14.5px;
  color: var(--lp-ink-soft);
}
.lp-plan-points li {
  position: relative;
  padding-left: 26px;
  line-height: 1.45;
}
.lp-plan-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .35em;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--lp-teal);
  -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M3 8l3.2 3.2L13 4.5" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>') center/contain no-repeat;
          mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M3 8l3.2 3.2L13 4.5" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>') center/contain no-repeat;
}

/* ── Testimonials ─────────────────────────────────────────────────────── */
.lp-testimonials { background: var(--lp-bg-soft); max-width: none; }
.lp-testimonials .lp-section-head,
.lp-testimonials .lp-quote-grid {
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}
.lp-quote-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
}
.lp-quote {
  position: relative;
  margin: 0;
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  padding: 28px 24px 24px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  transition: box-shadow var(--lp-ease) 200ms,
              border-color var(--lp-ease) 200ms,
              transform var(--lp-ease) 200ms;
}
.lp-quote:hover {
  box-shadow: var(--lp-shadow-md);
  border-color: var(--lp-line-strong);
  transform: translateY(-2px);
}
.lp-quote::before {
  /* Decorative open-quote mark — subtle teal mark in the corner. */
  content: """;
  position: absolute;
  top: 4px; left: 16px;
  font-family: Georgia, serif;
  font-size: 64px;
  line-height: 1;
  color: rgba(14,165,163,.20);
  pointer-events: none;
}
.lp-quote blockquote {
  margin: 0;
  font-size: 16px;
  line-height: 1.6;
  color: var(--lp-ink);
  font-weight: 500;
}
.lp-quote figcaption {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 14px;
  border-top: 1px solid var(--lp-line);
  padding-top: 16px;
}
.lp-quote-avatar {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--lp-bg-tint);
  border: 1px solid rgba(14,165,163,.20);
  display: grid;
  place-items: center;
  font-weight: 700;
  color: var(--lp-teal-deep);
  font-size: 14px;
}
.lp-quote-meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.lp-quote-role { color: var(--lp-ink-mute); font-size: 13px; }

/* ── FAQ ──────────────────────────────────────────────────────────────── */
.lp-faq { max-width: 760px; }
.lp-faq-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.lp-faq-item {
  background: var(--lp-bg);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s;
}
.lp-faq-item.open,
.lp-faq-item[open] {
  border-color: rgba(13,148,136,.4);
  box-shadow: var(--lp-shadow-sm);
}
.lp-faq-q {
  list-style: none;
  cursor: pointer;
  padding: 16px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  font-size: 16px;
  font-weight: 600;
  color: var(--lp-ink);
}
.lp-faq-q::-webkit-details-marker { display: none; }
.lp-faq-q::marker { content: ""; }
.lp-faq-chev {
  font-size: 22px;
  font-weight: 400;
  color: var(--lp-teal-deep);
  transition: transform .2s ease;
  line-height: 1;
}
.lp-faq-item.open .lp-faq-chev,
.lp-faq-item[open] .lp-faq-chev {
  transform: rotate(45deg);
}
.lp-faq-a {
  padding: 0 20px 18px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--lp-ink-soft);
}

/* ── Final CTA ──────────────────────────────────────────────────────────
   Solid clinical teal panel — gradient retired. The previous teal→sky
   gradient + radial-glow read as marketing-page; solid teal with a
   single subtle inner highlight reads as confident final ask. */
.lp-final-cta { padding-top: 40px; padding-bottom: 80px; }
.lp-final-card {
  position: relative;
  text-align: center;
  padding: 56px 32px;
  border-radius: var(--lp-radius-lg);
  background: var(--lp-teal);
  color: #ffffff;
  box-shadow: var(--lp-shadow-md), 0 12px 32px rgba(14,165,163,.30);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  overflow: hidden;
  isolation: isolate;
}
.lp-final-card::before {
  /* Subtle inner highlight — adds a single tonal lift instead of a
     candy radial gradient. */
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(800px 240px at 50% -10%, rgba(255,255,255,.16), transparent 70%);
  pointer-events: none;
  z-index: -1;
}
.lp-final-card h2 {
  font-size: clamp(28px, 3.8vw, 40px);
  color: #ffffff;
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.1;
}
.lp-final-card p {
  color: rgba(255,255,255,.92);
  font-size: 17px;
  max-width: 56ch;
}
.lp-final-card .lp-btn-primary {
  background: #ffffff;
  color: var(--lp-teal-deep);
  border-color: #ffffff;
  box-shadow: 0 4px 12px rgba(0,0,0,.10);
}
.lp-final-card .lp-btn-primary:hover {
  background: #f8fafc;
  border-color: #f8fafc;
  color: var(--lp-teal-deep);
  box-shadow: 0 8px 24px rgba(0,0,0,.18);
  transform: translateY(-1px);
}
.lp-final-meta {
  font-size: 14px;
  color: rgba(255,255,255,.85);
}

/* ── Footer ───────────────────────────────────────────────────────────── */
.lp-footer {
  border-top: 1px solid var(--lp-line);
  background: var(--lp-bg-soft);
  padding: 28px 32px;
}
.lp-footer-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.lp-footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 16px;
  font-weight: 700;
  color: var(--lp-ink);
}
.lp-footer-brand img { border-radius: 6px; }
.lp-footer-links {
  display: flex;
  gap: 22px;
  font-size: 14px;
  color: var(--lp-ink-soft);
}
.lp-footer-links a:hover { color: var(--lp-teal-deep); }
.lp-footer-meta { font-size: 13px; color: var(--lp-ink-mute); }

/* ── Scroll-reveal animation ────────────────────────────────────────────
   Sections fade up into view as the user scrolls. JS tags each
   .lp-section / .lp-numbers with .lp-reveal then swaps to .lp-revealed
   when the IntersectionObserver fires. Honors prefers-reduced-motion
   automatically (the @media rule below disables the transform). */
.lp-reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 600ms var(--lp-ease),
              transform 600ms var(--lp-ease);
  will-change: opacity, transform;
}
.lp-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* ── Mobile tuning ────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  .lp-nav { padding: 14px 18px; gap: 10px; }
  .lp-nav-links { display: none; }
  .lp-hero { padding: 16px 18px 32px; }
  .lp-hero-inner {
    grid-template-columns: 1fr;
    gap: 32px;
    margin: 12px auto 20px;
    text-align: center;
  }
  .lp-hero-copy { align-items: center; max-width: none; }
  .lp-eyebrow { align-self: center; }
  .lp-lede { max-width: none; font-size: 17px; }
  .lp-hero-ctas { justify-content: center; }
  .lp-hero-meta { justify-content: center; }
  .lp-hero-art { min-height: 320px; }
  .lp-hero-stack { max-width: 360px; }
  /* Mobile carousel — grid-stack pattern. Drop the desktop
     aspect-ratio: 1/1 entirely (a 360px-wide phone gives a 360px
     square, which can't fit the practice slide's stem + 4 options +
     explain + clinical-rule + actions row), and stack all slides in
     a single 1×1 grid cell. The cell auto-sizes to the tallest slide,
     so the stage grows naturally without anyone having to know the
     longest content's exact pixel height. Slides go from
     position:absolute → grid-area:1/1, which keeps them overlapping
     for the crossfade but lets the parent measure their actual
     intrinsic heights. */
  .lp-hero-stage {
    aspect-ratio: auto;
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
  }
  .lp-hero-slide {
    position: relative;
    inset: auto;
    grid-row: 1;
    grid-column: 1;
    padding: 18px 18px 16px;
  }
  .lp-section { padding: 56px 18px; }
  .lp-howitworks .lp-section-head,
  .lp-howitworks .lp-steps,
  .lp-testimonials .lp-section-head,
  .lp-testimonials .lp-quote-grid { padding: 0 18px; }
  .lp-plan-card-featured { transform: none; }
  .lp-final-card { padding: 40px 22px; }
  .lp-footer-inner { justify-content: center; text-align: center; }
}
@media (max-width: 540px) {
  .lp-h1 { font-size: clamp(34px, 9vw, 46px); }
  .lp-section-head h2 { font-size: clamp(26px, 6vw, 32px); }
}

/* Compact mobile (~360px viewports — Pixel/iPhone SE/Galaxy S/etc).
   Most modern phones live in 360-414px. The 540px tier above catches
   them but its sizing was tuned for ~540px space, so prose, padding,
   and grids that look fine at 540px get cramped at 360px. This tier
   tightens the few surfaces that actually feel pinched at the
   narrow end:
     · numbers row → single column (was 2-up at 760px → cells too
        narrow for "$3.99/1st mo"-style longer values at 360px)
     · hero typography → tighter clamp min so the headline doesn't
        eat half the viewport
     · section padding → 18px → 14px to give content +8px more room
     · plan-free-note pill → tighter padding + smaller font
     · feature cards / quote cards → tighter padding
     · final CTA → tighter padding
*/
@media (max-width: 400px) {
  /* Hero headline — drop the 34px clamp min to 30px so the headline
     stays comfortable on a 360px-wide phone instead of feeling
     overstuffed. */
  .lp-h1 { font-size: clamp(30px, 9vw, 40px); letter-spacing: -.022em; }
  .lp-lede { font-size: 16px; }

  /* Section heads — tighten min so "Everything you need, nothing you
     don't" doesn't wrap to 4 lines on a Pixel. */
  .lp-section-head h2 { font-size: clamp(24px, 6vw, 28px); }
  .lp-section-sub { font-size: 15px; }

  /* All sections — shave 4px off horizontal padding so content has
     more room. */
  .lp-section, .lp-numbers { padding-left: 14px; padding-right: 14px; }
  .lp-hero { padding-left: 14px; padding-right: 14px; }
  .lp-howitworks .lp-section-head,
  .lp-howitworks .lp-steps,
  .lp-testimonials .lp-section-head,
  .lp-testimonials .lp-quote-grid { padding: 0 14px; }

  /* Numbers row — single column so each cell has the full viewport
     width to breathe. The "$3.99/1st mo · with code INTRO · then
     $6.99/mo" promo cell is the longest and was wrapping awkwardly
     at 360px in 2-col layout. */
  .lp-numbers-grid {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .lp-number-cell {
    border-left: none;
    border-top: 1px solid var(--lp-line);
    padding: 16px 8px;
  }
  .lp-number-cell:first-child { border-top: none; }
  .lp-number-cell-num { font-size: clamp(28px, 9vw, 36px); }

  /* Free-plan note pill — was wrapping into 4-5 lines at 360px with
     awkward word breaks. Tighten typography so the pill stays
     readable without overwhelming the section. */
  .lp-plan-free-note {
    padding: 12px 16px;
    font-size: 13.5px;
    line-height: 1.5;
  }

  /* Plan cards — tighten padding so the bullet rows have room. */
  .lp-plan-card { padding: 24px 18px; }
  .lp-plan-amount { font-size: 36px; }

  /* Intro promo banner — keep it pill-shaped but tighten so it
     doesn't eat too much vertical space. */
  .lp-promo-banner { padding: 8px 16px; font-size: 13px; gap: 10px; }
  .lp-promo-pulse { font-size: 16px; }

  /* Feature cards — tighten padding so the dense bento grid (now
     1-up at this width) doesn't feel like an oversized empty box. */
  .lp-feature { padding: 22px 18px; }
  .lp-feature.lp-feature-hero { padding: 22px 18px; }
  .lp-feature.lp-feature-hero h3 { font-size: clamp(20px, 5.5vw, 24px); }

  /* Testimonial cards — tighter padding + slightly smaller quote. */
  .lp-quote { padding: 22px 18px 20px; }
  .lp-quote blockquote { font-size: 15px; }

  /* Final CTA — pull the headline and inner padding down a notch. */
  .lp-final-card { padding: 32px 18px; }
  .lp-final-card h2 { font-size: clamp(24px, 6vw, 30px); }

  /* Trust strip — drop a layer of padding + tighten font. */
  .lp-trust-strip { padding: 12px 14px 4px; font-size: 14px; gap: 8px; }

  /* Carousel tabs — bump down padding so 4 tabs fit one row at 360px
     (was wrapping to 2 rows). */
  .lp-hero-tab { padding: 6px 11px; font-size: 12px; }
  .lp-hero-tabs { gap: 4px; padding: 3px; }

  /* Carousel stage already auto-sizes via the grid-stack pattern in
     the 760px tier; just tighten the slide padding + flex gap so the
     dense practice/explain content has a touch more room at the
     narrowest phones. */
  .lp-hero-slide { padding: 16px 16px 14px; gap: 12px; }
}

/* ── Flashcard-slide grade pills — mobile-thinner ─────────────────────────
 * The Again / Hard / Good / Easy row sits at the bottom of the
 * Flashcard carousel slide. At desktop the four pills with 9px vertical
 * padding + a stacked numeric keycap above the ALL-CAPS label give a
 * tall 2-row tile. At narrow viewports that 2-row tile pushed the
 * whole grades grid past the slide card edge.
 *
 * Mobile fix: hide the numeric keycap entirely (no keyboard on a
 * phone, so "1/2/3/4" isn't useful), drop the pill to a single short
 * row carrying just the label, and tighten padding/font so the row
 * reads as a thin single-line pill bar instead of a 2-row card.
 */
@media (max-width: 760px) {
  .lp-slide-fc-grades { gap: 5px; }
  .lp-slide-fc-grade {
    padding: 6px 4px;
    font-size: 10px;
    letter-spacing: .03em;
    line-height: 1;
  }
  .lp-slide-fc-grade-key {
    /* Numeric keycap is a desktop-only keyboard hint — hide on
       mobile so the pill collapses to a single short row. */
    display: none;
  }
}
@media (max-width: 400px) {
  .lp-slide-fc-grades { gap: 4px; }
  .lp-slide-fc-grade {
    padding: 5px 3px;
    font-size: 9.5px;
  }
}

/* ── Honor reduced motion ─────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .lp-feature, .lp-btn, .lp-faq-chev,
  .lp-quote, .lp-nav, .lp-nav-links a::after { transition: none; }
  .lp-feature:hover, .lp-btn-primary:hover,
  .lp-btn-ghost:hover, .lp-quote:hover { transform: none; }
  .lp-reveal { opacity: 1; transform: none; transition: none; }
}


/* ─── Rich-text editor (admin edit modal) ─────────────────────────────── */
/* The host div replaces the old <textarea> for q + explain. Quill renders
   its toolbar + editor inside; we constrain the editor to a sensible min
   height so the modal doesn't jump on mount. */
.rte-host {
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  overflow: hidden;
  min-height: 180px;
}
.rte-host:focus-within {
  border-color: rgba(45,212,191,.6);
  box-shadow: 0 0 0 3px rgba(45,212,191,.18);
}
.rte-host .ql-toolbar.ql-snow,
.rte-host .ql-container.ql-snow {
  border: none;
}
.rte-host .ql-toolbar.ql-snow {
  border-bottom: 1px solid var(--glass-border);
  background: rgba(255,255,255,.04);
}
.rte-host .ql-editor {
  min-height: 140px;
  font: inherit;
  color: var(--text);
  line-height: 1.5;
}
.rte-host .ql-editor.ql-blank::before {
  color: var(--text-dim);
  font-style: normal;
}
.rte-host .ql-editor h3 { font-size: 1.05em; margin: 0.6em 0 0.3em; }
.rte-host .ql-editor h4 { font-size: 1em;    margin: 0.6em 0 0.3em; }
.rte-host .ql-editor blockquote {
  border-left: 3px solid var(--glass-border);
  padding-left: 12px;
  margin: 0.6em 0;
  color: var(--text-dim);
}
.rte-loading {
  padding: 18px; text-align: center; font-size: 13px;
}
.rte-fallback {
  font: inherit; color: var(--text);
  background: transparent;
  border: none;
  padding: 10px 12px;
  width: 100%; box-sizing: border-box;
  resize: vertical;
  min-height: 140px;
}
.rte-fallback:focus { outline: none; }
.rte-fallback-msg {
  padding: 4px 10px 8px; font-size: 12px;
}

/* Rendered RTE output inside the quiz card — keep block elements aligned
   with the rest of the question/explanation typography. */
.question-block ul,
.question-block ol,
.feedback-explain ul,
.feedback-explain ol {
  margin: 0.4em 0 0.4em 1.4em;
}
.question-block blockquote,
.feedback-explain blockquote {
  border-left: 3px solid var(--glass-border);
  padding-left: 12px;
  margin: 0.6em 0;
  color: var(--text-dim);
}
.question-block h3,
.feedback-explain h3 { font-size: 1.05em; margin: 0.7em 0 0.3em; }
.question-block h4,
.feedback-explain h4 { font-size: 1em;    margin: 0.7em 0 0.3em; }
.question-block a,
.feedback-explain a { color: var(--accent, #2dd4bf); text-decoration: underline; }


/* ─── Explanation callouts: clinical rules + references ───────────────── */
/* Inline highlight for clinical pearls / rules — wraps a phrase mid-sentence
   so it pops out of explanation prose. inline-block lets the border-left
   render correctly while keeping the element flow inline-friendly. The
   block-level treatment further down (.feedback-explain .clinical-rule,
   .question-block .clinical-rule, .rte-editor .clinical-rule, .fc-explain
   .clinical-rule) overrides this for the most common case where the
   highlight stands alone as a takeaway box. Both palettes use the same
   amber tone so inline + block share a visual identity. */
.clinical-rule {
  display: inline-block;
  background: rgba(217, 119, 6, 0.10);
  padding: 2px 8px;
  border-left: 3px solid #d97706;
  font-weight: 600;
  border-radius: 0 4px 4px 0;
  line-height: 1.5;
  color: var(--ink, #0f172a);
}
/* Block-level reference / citation line at the end of an explanation. */
.reference {
  color: #6c757d;
  font-style: italic;
  font-size: 0.9em;
  display: block;
  margin-top: 4px;
}
/* Inline marks INSIDE references — without these explicit overrides, the
   .reference block's italic-gray styling visually masks any bold /
   underline / strike / link the author applied to specific words inside
   the reference (e.g. emphasised journal title, hyperlinked DOI).
   Each mark gets a distinguishing visual cue that punches through the
   gray italic so the author can still see their formatting. */
.reference strong, .reference b {
  font-weight: 800;
  font-style: normal;          /* counter-rotate the parent italic */
  color: var(--text);
}
.reference em, .reference i {
  /* parent is already italic — emphasis-on-italic flips to upright so
     em-marked text stays visually distinct */
  font-style: normal;
  color: var(--text);
}
.reference u {
  text-decoration: underline;
  color: var(--text);
}
.reference s, .reference del {
  text-decoration: line-through;
}
.reference a {
  color: var(--accent, #2dd4bf);
  font-style: normal;
  text-decoration: underline;
}
.reference sup, .reference sub {
  font-style: normal;
}

/* Toolbar buttons for the two custom Quill formats — their built-in icons
   are blank since we provide text labels via Quill's icon registry, but
   the buttons need a sensible width so the labels don't get clipped. */
.ql-toolbar .ql-clinical-rule,
.ql-toolbar .ql-reference {
  width: auto !important;
  min-width: 36px;
  padding: 0 8px !important;
}
.ql-toolbar .ql-clinical-rule.ql-active,
.ql-toolbar .ql-reference.ql-active {
  background: rgba(45,212,191,.18);
  border-radius: 4px;
}


/* RTE-fixes-2026-04-27 */
/* 1. Quill 2.x emits <ol> with <li data-list="bullet"> for unordered lists.
      Outside the editor, the default <ol> styling makes bullets render as
      numbers — override per-li using the data-list attribute. */
.question-block li[data-list="bullet"],
.feedback-explain li[data-list="bullet"],
.rte-host .ql-editor li[data-list="bullet"] {
  list-style-type: disc;
}
.question-block li[data-list="ordered"],
.feedback-explain li[data-list="ordered"],
.rte-host .ql-editor li[data-list="ordered"] {
  list-style-type: decimal;
}

/* 2. Clinical-rule spacing — horizontal padding keeps the highlight off
      surrounding words when it's used inline in prose, and a top margin
      gives it breathing room when it's used at the start of its own line
      or paragraph (the more common case in flashcard explanations). */
.clinical-rule {
  margin: 12px 4px 4px;
}
/* When the clinical-rule starts a paragraph, the inline-block wrapper
   above it adds more visible separation. Make the whole containing
   paragraph snap to a new visual block so the highlight reads as a
   distinct callout instead of crashing into the prose above. */
p > .clinical-rule:only-child,
p > .clinical-rule:first-child {
  margin-top: 14px;
}

/* 3. References get a horizontal rule above them so they sit visually
      separated from the explanation body. The border + padding combine
      to make the rule a proper divider, not just a thin line. */
.reference {
  margin-top: 16px;
  padding-top: 10px;
  border-top: 1px solid rgba(0,0,0,0.12);
}
/* In dark/glass theme contexts, lift the rule contrast slightly. */
.feedback-explain .reference,
.question-block .reference {
  border-top-color: var(--glass-border, rgba(255,255,255,0.18));
}


/* RTE-custom-2026-04-27 */
/* Custom RTE — replaces Quill. Toolbar + contenteditable editor inside .rte-host. */
.rte-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.05);
}
.rte-toolbar button {
  font: 600 12px/1 system-ui, sans-serif;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 5px 9px;
  cursor: pointer;
  color: var(--text);
  min-width: 28px;
  transition: background 80ms, border-color 80ms;
}
.rte-toolbar button:hover {
  background: rgba(255,255,255,0.08);
}
.rte-toolbar button.active {
  background: rgba(45,212,191,.20);
  border-color: rgba(45,212,191,.5);
}
.rte-toolbar button b,
.rte-toolbar button i,
.rte-toolbar button u {
  font-style: normal;
  font-weight: inherit;
}
.rte-toolbar button b { font-weight: 800; }
.rte-toolbar button i { font-style: italic; }
.rte-toolbar button u { text-decoration: underline; }
.rte-toolbar .rte-block-select {
  font: inherit;
  background: transparent;
  border: 1px solid var(--glass-border);
  border-radius: 4px;
  padding: 4px 6px;
  color: var(--text);
  cursor: pointer;
}
.rte-toolbar .rte-sep {
  width: 1px;
  align-self: stretch;
  background: var(--glass-border);
  margin: 2px 4px;
}
.rte-editor {
  min-height: 140px;
  padding: 10px 12px;
  outline: none;
  font: inherit;
  color: var(--text);
  line-height: 1.55;
}
/* Placeholder rendering — Tiptap's Placeholder extension adds
   `data-placeholder` and the `is-editor-empty` class to the empty
   first paragraph. The old `:empty::before` selector never matched
   because Tiptap always keeps a `<p></p>` inside the host (so the
   host is not empty in the DOM sense), which is why the placeholder
   silently failed to render. */
.rte-editor p.is-editor-empty:first-child::before {
  content: attr(data-placeholder);
  color: var(--text-dim);
  pointer-events: none;
  float: left;
  height: 0;
}

/* Sub/sup pairs — bring them visually close to their baseline so
   formulas like H₂O / m² read like real chemistry/exponents. */
.rte-editor sup, .rte-editor sub {
  font-size: 0.78em;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}
.rte-editor sup { top: -0.45em; }
.rte-editor sub { bottom: -0.25em; }

/* Disabled toolbar buttons — used by undo/redo when there's nothing
   to step through. Visually muted so the affordance is clear. */
.rte-toolbar button:disabled {
  opacity: .35;
  cursor: not-allowed;
  background: transparent;
}
.rte-toolbar button:disabled:hover { background: transparent; }
/* Undo/redo glyphs are larger fonts so the arrows render at a
   readable size. */
.rte-toolbar .rte-icon-btn { font-size: 16px; line-height: 1; padding: 4px 8px; }
.rte-editor h3 { font-size: 1.05em; margin: 0.6em 0 0.3em; }
.rte-editor h4 { font-size: 1em;    margin: 0.6em 0 0.3em; }
.rte-editor blockquote {
  border-left: 3px solid var(--glass-border);
  padding-left: 12px;
  margin: 0.6em 0;
  color: var(--text-dim);
}
.rte-editor ul, .rte-editor ol { margin: 0.4em 0 0.4em 1.4em; }
.rte-editor a { color: var(--accent, #2dd4bf); text-decoration: underline; }


/* RTE-editor-feedback-2026-04-27 */
/* Live editor feedback — show clinical-rule + reference styling inside the
   contenteditable so admins can see what they're applying. */
.rte-editor .clinical-rule {
  display: inline-block;
  background: #fff3cd;
  padding: 2px 8px;
  margin: 0 4px;
  border-left: 3px solid #f0ad4e;
  font-weight: 600;
  border-radius: 0 3px 3px 0;
  color: #2b2b2b;
}
.rte-editor .reference,
.rte-editor p.reference,
.rte-editor div.reference {
  color: #6c757d;
  font-style: italic;
  font-size: 0.95em;
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid var(--glass-border, rgba(255,255,255,0.18));
}
/* Editor-side mark overrides inside references — same intent as the
   public-side rules added above, scoped so admins see live exactly what
   the rendered card will show. */
.rte-editor .reference strong, .rte-editor .reference b {
  font-weight: 800;
  font-style: normal;
  color: var(--text);
}
.rte-editor .reference em, .rte-editor .reference i {
  font-style: normal;
  color: var(--text);
}
.rte-editor .reference u {
  text-decoration: underline;
  color: var(--text);
}
.rte-editor .reference s, .rte-editor .reference del {
  text-decoration: line-through;
}
.rte-editor .reference a {
  color: var(--accent, #2dd4bf);
  font-style: normal;
  text-decoration: underline;
}
.rte-editor .reference sup, .rte-editor .reference sub {
  font-style: normal;
}
/* The live `.clinical-rule` callout already has its own background and
   weight, but in case it sits inside a reference we make sure its
   italic-counter-rotate sticks too. */
.rte-editor .reference .clinical-rule {
  font-style: normal;
}
.reference .clinical-rule {
  font-style: normal;
}


/* RTE-reference-divider-2026-04-27 */
/* High-specificity rule for the .reference horizontal divider in the
   rendered card view. Earlier rules used theme-dependent colours (var
   --glass-border) that can fall back to invisible on certain backgrounds.
   Force a neutral mid-grey with !important so the line is reliably visible
   in both light and dark themes. */
.feedback-explain p.reference,
.feedback-explain div.reference,
.feedback-explain .reference,
.question-block p.reference,
.question-block div.reference,
.question-block .reference {
  display: block !important;
  margin-top: 18px !important;
  padding-top: 10px !important;
  border-top: 1px solid rgba(127, 127, 127, 0.45) !important;
  color: #6c757d !important;
  font-style: italic !important;
  font-size: 0.92em !important;
}


/* ─── Editor.js theming (replaces Tiptap RTE) ─────────────────────────
 * Editor.js ships its own light-theme CSS via JS injection. We override
 * the colors so it integrates with the glass/dark theme. Selectors
 * prefixed `.ce-` (codex editor) or `.cdx-` are Editor.js's own
 * classes; `.ce-block__reference` is our custom Reference block.
 */
.rte-editorjs-host {
  /* Editor.js manages its own padding/spacing inside; we just need
     to give it a min-height and let the parent .rte-host border show. */
  min-height: 180px;
  padding: 8px 12px;
}
.rte-editorjs-host .codex-editor {
  font: inherit;
  color: var(--text);
  line-height: 1.55;
}
.rte-editorjs-host .codex-editor__redactor {
  padding-bottom: 80px !important;     /* Editor.js default 300px is too big */
}
.rte-editorjs-host .ce-block {
  margin: 0;
}
.rte-editorjs-host .ce-block__content {
  max-width: 100%;
}
.rte-editorjs-host .ce-paragraph,
.rte-editorjs-host .ce-paragraph[data-placeholder]:empty::before,
.rte-editorjs-host .cdx-block {
  font: inherit;
  color: var(--text);
}
.rte-editorjs-host [contenteditable=true]:empty::before {
  content: attr(data-placeholder);
  color: var(--text-dim);
  pointer-events: none;
}
/* Headers */
.rte-editorjs-host .ce-header {
  font-weight: 700;
  margin: 0.5em 0 0.25em;
  padding: 0;
  color: var(--text);
}
.rte-editorjs-host h3.ce-header { font-size: 1.1em; }
.rte-editorjs-host h4.ce-header { font-size: 1em; }
/* Lists */
.rte-editorjs-host .cdx-list { padding-left: 1.4em; }
.rte-editorjs-host .cdx-list__item { margin: 0.2em 0; }
/* Quote */
.rte-editorjs-host .cdx-quote {
  border-left: 3px solid var(--glass-border);
  padding-left: 12px;
  margin: 0.6em 0;
  color: var(--text-dim);
}
.rte-editorjs-host .cdx-quote__text {
  min-height: 1.5em;
  font-style: italic;
}
.rte-editorjs-host .cdx-quote__caption { display: none; }    /* we don't use captions */

/* Reference block — our custom block renders with the same italic
   gray + top divider treatment as the rendered card so authors see
   the final look while editing. */
.rte-editorjs-host .ce-block__reference {
  color: #9aa0a6;
  font-style: italic;
  font-size: 0.95em;
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid var(--glass-border);
}
/* Inline marks inside a reference still need to read distinctly —
   same treatment as the public-side .reference rules. */
.rte-editorjs-host .ce-block__reference strong,
.rte-editorjs-host .ce-block__reference b { font-weight: 800; font-style: normal; color: var(--text); }
.rte-editorjs-host .ce-block__reference em,
.rte-editorjs-host .ce-block__reference i  { font-style: normal; color: var(--text); }
.rte-editorjs-host .ce-block__reference u  { text-decoration: underline; color: var(--text); }
.rte-editorjs-host .ce-block__reference s  { text-decoration: line-through; }
.rte-editorjs-host .ce-block__reference a  { color: var(--accent, #2dd4bf); font-style: normal; text-decoration: underline; }

/* Toolbar (left + button + right ⋮ menu) — make their backgrounds
   darker so the light icons show against glass. */
.rte-editorjs-host .ce-toolbar__plus,
.rte-editorjs-host .ce-toolbar__settings-btn {
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  color: var(--text);
}
.rte-editorjs-host .ce-toolbar__plus:hover,
.rte-editorjs-host .ce-toolbar__settings-btn:hover {
  background: var(--glass);
  color: var(--text);
}

/* Inline floating toolbar (appears on text selection) */
.rte-editorjs-host .ce-inline-toolbar,
.codex-editor .ce-inline-toolbar {
  background: var(--bg-0);
  border: 1px solid var(--glass-border-strong);
  box-shadow: var(--shadow-2);
  color: var(--text);
}
.codex-editor .ce-inline-tool {
  color: var(--text);
}
.codex-editor .ce-inline-tool:hover {
  background: var(--glass);
}
.codex-editor .ce-inline-tool--active {
  color: rgba(45,212,191,1);
  background: rgba(45,212,191,.15);
}

/* Block-tool popover (the "+" menu listing block types) */
.codex-editor .ce-popover,
.rte-editorjs-host .ce-popover {
  background: var(--bg-0);
  border: 1px solid var(--glass-border-strong);
  color: var(--text);
}
.codex-editor .ce-popover-item__title { color: var(--text); }
.codex-editor .ce-popover-item:hover  { background: var(--glass); }
.codex-editor .ce-popover-item__icon  {
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
}

/* Conversion toolbar (block-type "convert to" submenu) */
.codex-editor .ce-conversion-toolbar {
  background: var(--bg-0);
  border: 1px solid var(--glass-border-strong);
  color: var(--text);
}
.codex-editor .ce-conversion-tool { color: var(--text); }
.codex-editor .ce-conversion-tool:hover { background: var(--glass); }

/* Selected block — Editor.js applies a subtle highlight; tone it down */
.codex-editor .ce-block--selected .ce-block__content {
  background: rgba(45,212,191,.06);
  border-radius: 4px;
}


/* ─── Markdown editor (replaces Tiptap / Editor.js) ───────────────────
 * Side-by-side textarea + live HTML preview, framed by a toolbar with
 * Markdown quick-insert buttons and a one-line cheat sheet under the
 * editor. Stacks vertically below 720px so phones get a usable layout.
 */
.md-editor {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  overflow: hidden;
  background: var(--glass-weak);
  min-height: 280px;
}
.md-editor-fallback { padding: 10px; }
.md-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.05);
}
.md-toolbar button {
  font: 600 12px/1 system-ui, sans-serif;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 5px 9px;
  cursor: pointer;
  color: var(--text);
  min-width: 28px;
  transition: background 80ms, border-color 80ms;
}
.md-toolbar button b { font-weight: 800; }
.md-toolbar button i { font-style: italic; }
.md-toolbar button u { text-decoration: underline; }
.md-toolbar button s { text-decoration: line-through; }
.md-toolbar button:hover {
  background: rgba(255,255,255,0.08);
}
.md-toolbar .md-sep {
  width: 1px;
  align-self: stretch;
  background: var(--glass-border);
  margin: 2px 4px;
}
/* RULE / REF pills get a coloured tint so the custom syntax buttons
   stand out from the standard Markdown ones. */
.md-toolbar .md-pill {
  font-size: 11px; letter-spacing: 0.04em; font-weight: 700;
  padding: 5px 10px;
  border: 1px solid var(--glass-border);
  border-radius: 999px;
}
.md-toolbar .md-pill-rule {
  background: rgba(240,173,78,.18);
  border-color: rgba(240,173,78,.45);
  color: #f6c779;
}
.md-toolbar .md-pill-ref {
  background: rgba(99,102,241,.16);
  border-color: rgba(99,102,241,.45);
  color: #a5b4fc;
  font-style: italic;
}

.md-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;                       /* renders as a single divider line */
  background: var(--glass-border);
  flex: 1;
}
@media (max-width: 720px) {
  .md-cols {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 1fr;
  }
}

.md-input {
  font: 13.5px/1.55 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  padding: 12px 14px;
  background: var(--bg-0);
  color: var(--text);
  border: 0;
  outline: 0;
  resize: vertical;
  min-height: 220px;
  /* Hide spinner outline on focus — the .md-editor border highlights
     when focus-within instead. */
  white-space: pre-wrap;
  word-wrap: break-word;
}
.md-input::placeholder {
  color: var(--text-dim);
}
.md-editor:focus-within {
  border-color: rgba(45,212,191,.5);
  box-shadow: 0 0 0 3px rgba(45,212,191,.16);
}

.md-preview {
  padding: 12px 14px;
  background: var(--bg-0);
  color: var(--text);
  overflow-y: auto;
  max-height: 480px;
  min-height: 220px;
  font: inherit;
  line-height: 1.55;
}
/* Block-level rendering inside the preview, scoped so we don't leak
   into the rest of the page. */
.md-preview > :first-child { margin-top: 0; }
.md-preview > :last-child  { margin-bottom: 0; }
.md-preview h1, .md-preview h2 { font-size: 1.25em; margin: 0.6em 0 0.3em; font-weight: 700; }
.md-preview h3 { font-size: 1.1em; margin: 0.6em 0 0.3em; font-weight: 700; }
.md-preview h4 { font-size: 1em;   margin: 0.6em 0 0.3em; font-weight: 700; }
.md-preview p  { margin: 0 0 0.5em; }
.md-preview ul, .md-preview ol { padding-left: 1.4em; margin: 0.4em 0; }
.md-preview li { margin: 0.15em 0; }
.md-preview blockquote {
  border-left: 3px solid var(--glass-border);
  padding-left: 12px;
  margin: 0.6em 0;
  color: var(--text-dim);
}
.md-preview a {
  color: var(--accent, #2dd4bf);
  text-decoration: underline;
}
.md-preview code {
  background: var(--glass);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 0.9em;
}

.md-help {
  padding: 7px 12px;
  font-size: 11.5px;
  color: var(--muted);
  border-top: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.03);
  white-space: nowrap;
  overflow-x: auto;            /* tiny chip bar that scrolls horizontally on mobile */
}
.md-help code {
  background: var(--glass);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 11px;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  color: var(--text);
}
.md-fallback-msg { padding: 8px 12px; }


/* RTE-clinical-rule-callout-2026-05-10 */
/* Clinical rule callout — matches the landing-page carousel demo:
 * soft amber-tinted background, 3px amber-deep left bar, 1px hairline
 * border on the other 3 sides, "📌 CLINICAL RULE" eyebrow at the top.
 * Reads as a key takeaway / clinical pearl distinct from the body
 * prose around it. Applied in:
 *   - .feedback-explain   — practice / review post-answer explanation
 *   - .question-block     — exam / multiplayer question shell
 *   - .rte-editor         — admin editor live preview
 *   - .fc-explain         — flashcards back-face explanation
 * Inside .reference blocks the inline highlight stays inline (handled
 * separately further down) so we don't get nested callouts.
 */
.feedback-explain .clinical-rule,
.question-block .clinical-rule,
.rte-editor .clinical-rule,
.fc-explain .clinical-rule {
  display: block !important;
  position: relative;
  margin: 16px 0 12px !important;
  padding: 30px 14px 12px 14px !important;
  background: rgba(217, 119, 6, 0.08) !important;
  border: 1px solid rgba(217, 119, 6, 0.25) !important;
  border-left: 3px solid #d97706 !important;
  border-radius: 6px !important;
  color: var(--ink, #0f172a) !important;
  font-weight: 500;
  line-height: 1.55;
}
/* Eyebrow tag — pinned to the top-left corner with the 📌 prefix.
   Pure CSS, no markup change needed (the RTE just emits the inline
   span; the layered selectors above expand it into a block, this
   ::before adds the label). */
.feedback-explain .clinical-rule::before,
.question-block .clinical-rule::before,
.rte-editor .clinical-rule::before,
.fc-explain .clinical-rule::before {
  content: "📌 Clinical rule";
  position: absolute;
  top: 8px;
  left: 12px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #92400e;
  pointer-events: none;
}


/* admin-users-dashboard-2026-04-27 */
/* Admin user dashboard */
.admin-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-top: 12px;
}
.admin-stat {
  background: var(--glass-weak, rgba(255,255,255,0.04));
  border: 1px solid var(--glass-border, rgba(255,255,255,0.10));
  border-radius: 8px;
  padding: 10px 12px;
}
.admin-stat-label { font-size: 12px; color: var(--text-dim); }
.admin-stat-value { font-size: 22px; font-weight: 700; margin-top: 2px; }
.admin-stat-sub   { font-size: 11px; margin-top: 2px; }

.admin-tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  margin: 8px 0 12px;
  border-bottom: 1px solid var(--glass-border, rgba(255,255,255,0.12));
}
.admin-tabs button {
  background: transparent; border: none; cursor: pointer;
  font: inherit; font-size: 13px;
  color: var(--text-dim);
  padding: 8px 12px;
  border-bottom: 2px solid transparent;
}
.admin-tabs button:hover { color: var(--text); }
.admin-tabs button.active {
  color: var(--text);
  border-bottom-color: rgba(45, 212, 191, 0.7);
}

.admin-lb-list {
  list-style: none; padding: 0; margin: 0;
}
.admin-lb-row {
  display: grid;
  grid-template-columns: 28px 32px 1fr auto auto;
  gap: 8px; align-items: center;
  padding: 8px 6px;
  border-radius: 6px;
}
.admin-lb-row:hover { background: rgba(255,255,255,0.04); }
.admin-lb-rank { color: var(--text-dim); font-size: 13px; text-align: center; }
.admin-lb-avatar { font-size: 18px; text-align: center; }
.admin-lb-name { font-weight: 500; }
.admin-lb-tier {
  font-size: 11px; padding: 2px 8px; border-radius: 999px;
  background: rgba(255,255,255,0.06);
  color: var(--text-dim);
}
.admin-lb-tier.pro {
  background: rgba(45, 212, 191, 0.18);
  color: rgba(45, 212, 191, 0.95);
}
.admin-lb-value { font-variant-numeric: tabular-nums; font-weight: 500; }

/* User table */
.admin-table-wrap { overflow-x: auto; margin-top: 12px; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.admin-table th {
  text-align: left; font-weight: 600; padding: 10px 8px;
  border-bottom: 1px solid var(--glass-border, rgba(255,255,255,0.12));
  cursor: pointer; user-select: none;
  white-space: nowrap;
}
.admin-table th:hover { color: rgba(45, 212, 191, 0.95); }
.admin-table td {
  padding: 8px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
}
.admin-table tr:hover td { background: rgba(255,255,255,0.04); }
.admin-row-avatar { font-size: 16px; margin-right: 4px; }
.admin-tier {
  font-size: 11px; padding: 2px 8px; border-radius: 999px;
  background: rgba(255,255,255,0.06);
  color: var(--text-dim);
}
.admin-tier.pro {
  background: rgba(45, 212, 191, 0.18);
  color: rgba(45, 212, 191, 0.95);
}

/* Activity chart */
.admin-chart { display: block; width: 100%; height: auto; max-width: 100%; }
.admin-chart-bar  { fill: rgba(45, 212, 191, 0.55); }
.admin-chart-line { stroke: rgba(255, 200, 90, 0.95); stroke-width: 2; fill: none; }
.admin-chart-axis { stroke: rgba(255,255,255,0.18); }
.admin-chart-yl   { fill: var(--text-dim); font-size: 10px; }
.admin-chart-xl   { fill: var(--text-dim); font-size: 11px; }
.admin-chart-legend {
  display: flex; gap: 14px; font-size: 12px; color: var(--text-dim);
  margin: 4px 0 10px;
}
.admin-chart-swatch {
  display: inline-block; width: 12px; height: 12px;
  vertical-align: middle; margin-right: 4px; border-radius: 2px;
}
.admin-chart-swatch.bar  { background: rgba(45, 212, 191, 0.55); }
.admin-chart-swatch.line { background: rgba(255, 200, 90, 0.95); }

/* Drill-down modal extensions */
.admin-detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 8px;
}
.admin-detail-row {
  background: var(--glass-weak, rgba(255,255,255,0.04));
  border-radius: 6px;
  padding: 8px 10px;
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 13px;
}
.admin-subject-list {
  list-style: none; padding: 0; margin: 0;
}
.admin-subject-list li {
  display: flex; justify-content: space-between;
  padding: 6px 4px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  font-size: 13px;
}


/* admin-presence-2026-04-27 */
/* Live presence indicators on the admin dashboard */
.admin-live-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.3px;
  text-transform: uppercase;
  color: rgba(45, 212, 191, 0.95);
  background: rgba(45, 212, 191, 0.14);
  padding: 3px 8px;
  border-radius: 999px;
  vertical-align: middle;
  margin-left: 8px;
}
.admin-live-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: rgb(45, 212, 191);
  box-shadow: 0 0 0 0 rgba(45, 212, 191, 0.7);
  animation: admin-live-pulse 1.8s infinite;
}
@keyframes admin-live-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(45, 212, 191, 0.6); }
  60%  { box-shadow: 0 0 0 8px rgba(45, 212, 191, 0); }
  100% { box-shadow: 0 0 0 0   rgba(45, 212, 191, 0); }
}

.admin-online-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: rgb(46, 204, 113);
  margin-right: 6px;
  vertical-align: middle;
  box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.6);
  animation: admin-online-pulse 2s infinite;
}
.admin-online-dot.off {
  background: rgba(127, 127, 127, 0.35);
  animation: none;
  box-shadow: none;
}
@keyframes admin-online-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(46, 204, 113, 0.55); }
  70%  { box-shadow: 0 0 0 6px rgba(46, 204, 113, 0); }
  100% { box-shadow: 0 0 0 0   rgba(46, 204, 113, 0); }
}

/* Highlight the "Online now" stat card with a subtle teal accent. */
.admin-stat.admin-stat-live {
  border-color: rgba(45, 212, 191, 0.45);
  box-shadow: inset 0 0 0 1px rgba(45, 212, 191, 0.18);
}
.admin-stat.admin-stat-live .admin-stat-value {
  color: rgba(45, 212, 191, 0.95);
}


/* auth-forgot-2026-04-27 */
/* Forgot-password link sits below the password field, right-aligned, muted. */
.auth-forgot {
  margin: -4px 0 4px;
  text-align: right;
  font-size: 13px;
}
.auth-forgot a {
  color: var(--text-dim);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-dim);
}
.auth-forgot a:hover {
  color: var(--text);
  border-bottom-color: var(--text);
}


/* avatar-dropdown-2026-04-27 */
/* Avatar picker — compact dropdown form. Replaces the old always-open grid.
   The wrap is BLOCK (not inline-block) so it respects its parent card's
   width. Without this, an inline-block wrap sizes to its content, which
   means the trigger pill (avatar + label + chevron) could extend past the
   card's right edge on narrow phones — chevron half-clipped. The trigger
   itself is capped at max-width: 100% so even on the widest content it
   won't break out of the wrap. */
.avatar-dd-wrap {
  position: relative;
  display: block;
  max-width: 100%;
}
.avatar-dd-trigger {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 8px 8px;
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  background: var(--glass-weak);
  cursor: pointer;
  font: inherit;
  color: var(--text);
  transition: border-color 120ms, background 120ms;
  /* Cap so the chevron can never poke past the parent card. */
  max-width: 100%;
}
.avatar-dd-trigger:hover { border-color: rgba(45,212,191,.55); }
.avatar-dd-trigger:focus { outline: none; border-color: rgba(45,212,191,.7); box-shadow: 0 0 0 3px rgba(45,212,191,.18); }
.avatar-dd-wrap.open .avatar-dd-trigger {
  border-color: rgba(45,212,191,.55);
  background: var(--glass-strong, rgba(255,255,255,.06));
}
.avatar-dd-preview {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: rgba(45,212,191,.18);
  font-size: 22px;
  line-height: 1;
}
.avatar-dd-text {
  font-size: 14px;
  color: var(--text);
  /* Truncate-on-overflow universally — without min-width:0 a flex item
     refuses to shrink below its content width and pushes siblings out
     of the parent. With it, the text gracefully ellipses and the
     chevron stays anchored on the right edge of the pill. */
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.avatar-dd-chevron {
  font-size: 12px;
  color: var(--text-dim);
  transition: transform 120ms;
  /* Never shrink — must remain visible inside the trigger pill. */
  flex: 0 0 auto;
}
.avatar-dd-preview { flex: 0 0 auto; }
.avatar-dd-wrap.open .avatar-dd-chevron { transform: rotate(180deg); }

.avatar-dd-pop {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 50;
  width: min(560px, calc(100vw - 32px));
  /* Fully opaque so the cards underneath don't bleed through. The base
     glass --surface variable is intentionally semi-transparent; that works
     for hero/stat cards but not for an overlay popover. */
  background: var(--bg-0);
  color: var(--text);
  border: 1px solid var(--glass-border);
  border-radius: 14px;
  box-shadow: 0 18px 48px rgba(0,0,0,.28), 0 4px 12px rgba(0,0,0,.16);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.avatar-dd-pop[hidden] { display: none; }
.avatar-dd-pop-body {
  padding: 14px;
  max-height: 360px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.avatar-dd-footer {
  border-top: 1px solid var(--glass-border);
  padding: 10px 14px 12px;
  background: rgba(0,0,0,.02);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.avatar-dd-footer label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--text-dim);
}
.avatar-custom-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
}

/* Right-anchor on narrow viewports so the popover doesn't run off-screen. */
@media (max-width: 480px) {
  .avatar-dd-pop {
    left: auto; right: 0;
    width: min(520px, calc(100vw - 32px));
  }
}

/* Mobile: the trigger pill was inline-block + sized to its content, so on
   narrow cards the chevron + label could push past the card's right edge
   (visible as horizontal overflow / a half-clipped chevron). Switching the
   wrap to full-width block and the trigger to a full-width flex with
   space-between keeps everything inside the card and pins the chevron to
   the right where users expect it. The avatar text gets a truncating
   min-width:0 so very long localised labels also stay tidy. */
@media (max-width: 540px) {
  .avatar-dd-wrap { display: block; width: 100%; }
  .avatar-dd-trigger {
    width: 100%;
    justify-content: flex-start;
    padding: 8px 14px 8px 8px;
  }
  .avatar-dd-text {
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .avatar-dd-chevron { flex: 0 0 auto; margin-left: auto; }
  .avatar-dd-pop {
    left: 0; right: 0;
    width: auto;
  }
}


/* avatar-dropdown-zfix-2026-04-27 */
/* Lift the entire avatar card above sibling stacking contexts (other .card
   siblings have backdrop-filter, which spawns their own stacking context).
   Without this, the popover is rendered correctly but obscured by the next
   card down. */
.avatar-card {
  position: relative;
}
.avatar-card:has(.avatar-dd-wrap.open) {
  z-index: 100;
  overflow: visible;
}
.avatar-dd-pop {
  z-index: 1000;
}


/* admin-qid-jump-2026-04-27 */
.qid-jump {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 6px;
}
.qid-jump input[type="number"] {
  /* hide native spinners — they crowd the box */
  appearance: textfield;
  -moz-appearance: textfield;
}
.qid-jump input::-webkit-outer-spin-button,
.qid-jump input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}


/* admin-user-notes-2026-04-28 */
/* User-notes list inside the admin drill-down modal. */
.admin-notes-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex; flex-direction: column; gap: 8px;
  max-height: 280px;
  overflow-y: auto;
}
.admin-note {
  background: var(--glass-weak, rgba(255,255,255,.04));
  border: 1px solid var(--glass-border, rgba(255,255,255,.10));
  border-radius: 8px;
  padding: 8px 10px;
}
.admin-note-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 12px;
  margin-bottom: 4px;
}
.admin-note-qid {
  font-family: monospace;
  font-weight: 600;
  color: var(--text);
}
.admin-note-time { font-size: 11px; }
.admin-note-text {
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text);
}


/* update-banner-2026-04-28 */
/* Update banner — fixed bottom, slides up when a new SW activates. */
.update-banner {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%) translateY(120%);
  width: min(560px, calc(100vw - 24px));
  background: var(--surface, #fff);
  color: var(--text);
  border: 1px solid var(--glass-border, rgba(0,0,0,.08));
  border-radius: 12px;
  padding: 12px 14px 12px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  box-shadow: 0 8px 28px rgba(0,0,0,.15), 0 2px 6px rgba(0,0,0,.08);
  z-index: 9999;
  transition: transform 240ms cubic-bezier(.2,.8,.3,1);
}
.update-banner-shown { transform: translateX(-50%) translateY(0); }
.update-banner-msg {
  flex: 1;
  font-size: 14px;
  line-height: 1.4;
}
.update-banner .btn { padding: 6px 14px; font-size: 13px; }
.update-banner-close {
  background: transparent;
  border: none;
  font: inherit;
  font-size: 22px; line-height: 1;
  color: var(--text-dim);
  cursor: pointer;
  padding: 0 4px;
  border-radius: 4px;
}
.update-banner-close:hover { color: var(--text); background: rgba(0,0,0,.05); }

@media (max-width: 480px) {
  .update-banner {
    bottom: 78px; /* clear the bottom nav */
    flex-wrap: wrap;
    padding: 10px 12px;
  }
  .update-banner-msg { width: 100%; font-size: 13px; }
}


/* theme-toggle-2026-04-28 — refreshed for calm-clinical palette.
   User-chosen theme overrides beat the prefers-color-scheme media query
   by selector specificity. JS sets <html data-theme="..."> on first paint.
   Token values mirror the :root + @media (light) blocks at the top of
   this file — keep them in sync if you change one. */

:root[data-theme="dark"] {
  --bg-0:      #0b1220;
  --blob-1:    rgba(15, 23, 42, 0);
  --blob-2:    rgba(15, 23, 42, 0);
  --blob-3:    rgba(15, 23, 42, 0);
  --blob-4:    rgba(15, 23, 42, 0);

  --surface:    rgba(15, 23, 42, 0.72);
  --surface-2:  rgba(30, 41, 59, 0.55);
  --border:     rgba(148, 163, 184, 0.18);
  --border-strong: rgba(148, 163, 184, 0.32);

  --glass:               rgba(15, 23, 42, 0.72);
  --glass-strong:        rgba(15, 23, 42, 0.85);
  --glass-weak:          rgba(15, 23, 42, 0.50);
  --glass-border:        rgba(148, 163, 184, 0.18);
  --glass-border-strong: rgba(148, 163, 184, 0.30);
  --glass-hi:            rgba(255, 255, 255, 0.04);

  --ink:       #f1f5f9;
  --text:      #e2e8f0;
  --text-dim:  #94a3b8;
  --muted:     #64748b;

  --primary-soft: rgba(14, 165, 163, 0.18);

  --shadow-0: 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-1: 0 1px 3px rgba(15, 23, 42, 0.10), 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-2: 0 4px 12px rgba(15, 23, 42, 0.16), 0 2px 4px rgba(15, 23, 42, 0.08);
  --shadow-3: 0 12px 30px rgba(15, 23, 42, 0.40), 0 4px 8px rgba(15, 23, 42, 0.10);
  --shadow:       var(--shadow-2);
  --shadow-hover: var(--shadow-3);
}

:root[data-theme="light"] {
  --bg-0:      #f4f6fb;
  --blob-1:    rgba(15, 23, 42, 0);
  --blob-2:    rgba(15, 23, 42, 0);
  --blob-3:    rgba(15, 23, 42, 0);
  --blob-4:    rgba(15, 23, 42, 0);

  --surface:    #ffffff;
  --surface-2:  #f8fafc;
  --border:     #e2e8f0;
  --border-strong: #cbd5e1;

  --glass:               rgba(255, 255, 255, 0.85);
  --glass-strong:        rgba(255, 255, 255, 0.95);
  --glass-weak:          rgba(255, 255, 255, 0.65);
  --glass-border:        #e2e8f0;
  --glass-border-strong: #cbd5e1;
  --glass-hi:            rgba(255, 255, 255, 0.70);

  --ink:       #0f172a;
  --text:      #1e293b;
  --text-dim:  #475569;
  --muted:     #64748b;

  --primary-soft: rgba(14, 165, 163, 0.10);

  --shadow-0: 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-1: 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 3px rgba(15, 23, 42, 0.06);
  --shadow-2: 0 4px 6px rgba(15, 23, 42, 0.05), 0 10px 15px rgba(15, 23, 42, 0.08);
  --shadow-3: 0 10px 25px rgba(15, 23, 42, 0.10), 0 20px 40px rgba(15, 23, 42, 0.06);
  --shadow:       var(--shadow-2);
  --shadow-hover: var(--shadow-3);
}

/* Theme-toggle button in the topbar — icon-only round button with a
   sun/moon glyph that swaps based on the data-theme-state attribute the
   JS keeps in sync. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  color: var(--text);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  transition: background 120ms, border-color 120ms;
}
.theme-toggle:hover {
  background: var(--glass-strong);
  border-color: var(--glass-border-strong);
}
.theme-toggle:focus {
  outline: none;
  box-shadow: 0 0 0 3px var(--primary-soft);
}
/* Sun while in dark mode (clicking switches to light), moon while in light. */
.theme-toggle::before {
  content: "🌙";
}
.theme-toggle[data-theme-state="dark"]::before {
  content: "☀️";
}


/* phase1a-engagement-2026-04-28 */
/* Daily Question of the Day card on home — full-width, eye-catching but
   restrained. Click anywhere on the card to open today's question. */
.daily-card {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 14px;
  align-items: center;
  text-decoration: none;
  color: var(--text);
  margin-top: 14px;
  padding: 16px 18px;
  border-left: 3px solid #f0ad4e;
  background: linear-gradient(to right, var(--glass-strong, rgba(255,255,255,.05)), var(--glass-weak, rgba(255,255,255,.02)));
  transition: transform 120ms, box-shadow 120ms;
}
.daily-card:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-hover);
}
.daily-card-done { border-left-color: #2ecc71; }
.daily-icon {
  font-size: 28px;
  text-align: center;
}
.daily-body { min-width: 0; }
.daily-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.daily-label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
}
.daily-pill {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(240, 173, 78, 0.18);
  color: #b47a00;
}
.daily-pill-done {
  background: rgba(46, 204, 113, 0.18);
  color: #1f8c4f;
}
.daily-stem {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.daily-cta {
  margin-top: 6px;
  font-size: 13px;
  font-weight: 600;
  color: rgba(45, 212, 191, 0.95);
}

/* Segmented-dots daily card — replaces the older two-row pill/CTA
   variant. Single-row layout: rounded icon tile, label + N dots
   filling left-to-right + "X of Y" count, then a tight CTA on the
   right edge. The dots match the size/colour of the dashboard mosaic
   so the visual idiom is shared across the app. */
.daily-card-dots {
  grid-template-columns: 44px 1fr auto;
  gap: 12px;
  padding: 12px 16px;
  border-left-width: 3px;
}
.daily-card-dots .daily-icon-tile {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: rgba(240, 173, 78, 0.16);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  line-height: 1;
}
.daily-card-dots .daily-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.daily-card-dots .daily-label {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim, var(--muted));
}
.daily-card-dots .daily-dots {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}
.daily-card-dots .daily-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--glass-weak, rgba(148, 163, 184, 0.18));
  border: 0.5px solid var(--border, rgba(148, 163, 184, 0.35));
  transition: background .15s, border-color .15s, transform .15s;
}
.daily-card-dots .daily-dot.on {
  background: #1D9E75;
  border-color: #0F6E56;
}
.daily-card-dots .daily-count {
  font-size: 12px;
  color: var(--text-dim, var(--muted));
  font-variant-numeric: tabular-nums;
}
.daily-card-dots .daily-cta-arrow {
  font-size: 13px;
  font-weight: 600;
  color: #0F6E56;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}
.daily-card-dots:hover .daily-cta-arrow { color: #04342C; }
@media (max-width: 480px) {
  .daily-card-dots {
    grid-template-columns: 36px 1fr auto;
    padding: 10px 14px;
  }
  .daily-card-dots .daily-icon-tile { width: 36px; height: 36px; font-size: 18px; }
  .daily-card-dots .daily-dot { width: 8px; height: 8px; }
}

/* Daily-view full-page (the /daily route) */
.daily-view-card { padding-top: 14px; }
.daily-view-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 10px;
  flex-wrap: wrap; gap: 10px;
}
.daily-eyebrow {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-dim);
}
.daily-view-foot {
  margin-top: 12px;
  padding: 8px 12px;
  text-align: center;
  font-size: 13px;
  border-top: 1px solid var(--glass-border);
}

/* Activity heatmap */
.hm-card { margin-top: 14px; padding: 10px 14px; }
.hm-card h3 { margin: 0 0 4px; font-size: 14px; }
.hm-summary { font-size: 12px; margin-bottom: 8px; }

/* CSS-grid heatmap. Cells stretch horizontally to fill the card
   (grid-template-columns: repeat(var(--hm-cols), 1fr)) while row
   height stays pinned at 11px — gives the "wide & short" activity
   strip without ballooning the card on desktop.

   Layout:
     .hm-grid-wrap   row-flex container: weekday-label column +
                    main grid column
     .hm-rowlabels   7-row grid showing M / W / F on the right rows
     .hm-grid-main   stacks the month-label strip above the cells
     .hm-month-labels  position: relative bar with absolutely-
                    positioned text spans for each labelled month
     .hm-cells       the actual cell grid — N cols × 7 rows
*/
.hm-grid-wrap {
  display: flex;
  gap: 6px;
  align-items: stretch;
}
.hm-rowlabels {
  display: grid;
  grid-template-rows: repeat(7, 11px);
  row-gap: 2px;
  padding-top: 16px; /* matches .hm-month-labels height so rows align */
  font-size: 10px;
  color: var(--text-dim);
  font-weight: 600;
  width: 14px;
  flex-shrink: 0;
}
.hm-rowlabels > span {
  display: flex;
  align-items: center;
  line-height: 1;
  height: 11px;
}
.hm-grid-main {
  flex: 1;
  min-width: 0;
}
.hm-month-labels {
  position: relative;
  height: 14px;
  margin-bottom: 2px;
  font-size: 10px;
  color: var(--text-dim);
  font-weight: 600;
  letter-spacing: .04em;
}
.hm-month-label {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  white-space: nowrap;
  line-height: 1;
}
.hm-cells {
  display: grid;
  grid-template-columns: repeat(var(--hm-cols, 13), 1fr);
  grid-template-rows: repeat(7, 11px);
  gap: 2px;
}
.hm-cell {
  border-radius: 2px;
  min-width: 0;
}
.hm-cell-pad { background: transparent; }

.hm-legend {
  display: flex; align-items: center; gap: 4px;
  margin-top: 8px;
  font-size: 11px;
  justify-content: flex-end;
}
.hm-swatch {
  display: inline-block;
  width: 12px; height: 11px;
  border-radius: 2px;
}


/* daily-set-actions-2026-04-28 */
.daily-view-actions {
  display: flex;
  gap: 10px;
  margin-top: 12px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.daily-view-actions .btn { padding: 8px 18px; }

/* streak-freeze-2026-04-28 */
.freeze-pill {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink);
  background: linear-gradient(135deg, rgba(125, 211, 252, 0.18), rgba(45, 212, 191, 0.18));
  border: 1px solid rgba(125, 211, 252, 0.35);
  border-radius: 999px;
  padding: 1px 8px;
  margin-left: 4px;
  letter-spacing: .01em;
  cursor: help;
  vertical-align: 1px;
}

/* legal-pages-2026-04-29 */
.legal-page {
  max-width: 760px; margin: 32px auto; padding: 0 18px;
  line-height: 1.6;
}
.legal-head {
  margin-bottom: 24px; padding-bottom: 16px;
  border-bottom: 1px solid var(--glass-border);
}
.legal-head h1 { margin: 8px 0 4px; font-size: 28px; }
.legal-back {
  display: inline-block; margin-bottom: 8px;
  font-size: 13px; color: var(--muted);
  text-decoration: none;
}
.legal-back:hover { color: var(--ink); }
.legal-body h2 {
  font-size: 18px; margin: 28px 0 8px;
  border-top: 1px solid var(--glass-border);
  padding-top: 18px;
}
.legal-body h2:first-of-type { border-top: none; padding-top: 0; }
.legal-body p { margin: 8px 0; }
.legal-body ul { margin: 8px 0; padding-left: 22px; }
.legal-body ul li { margin: 4px 0; }
.legal-body code {
  background: var(--glass-weak);
  padding: 1px 6px; border-radius: 4px;
  font-size: 13px;
}
.legal-body a { color: rgba(45,212,191,.95); }
.legal-body a:hover { text-decoration: underline; }
.legal-foot {
  margin-top: 32px; padding-top: 16px;
  border-top: 1px solid var(--glass-border);
}

/* admin-hub-2026-04-29 */
.admin-hub-grid {
  /* Force three equal columns at desktop width so the nav cards stay
     visually consistent with the cards above and below them. Falls back
     to 2 then 1 columns on narrower viewports. */
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 720px) { .admin-hub-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .admin-hub-grid { grid-template-columns: 1fr; } }
/* Make the hub action-cards a touch taller so their visual weight matches
   the surrounding heading + content cards. */
.admin-hub-grid .action-card { min-height: 92px; }

/* visitor-analytics-2026-04-29 */
.analytics-loading p { margin: 4px 0; }
.analytics-pills {
  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px;
}
.analytics-pill {
  font-size: 12px; padding: 4px 10px; border-radius: 999px;
  background: var(--glass-weak); border: 1px solid var(--glass-border);
  font-weight: 600;
}
.analytics-pill-warn  { border-color: rgba(251,191,36,.55); color: rgba(251,191,36,1); }
.analytics-pill-muted { color: var(--muted); }

.funnel { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; }
.funnel-row {
  display: grid; grid-template-columns: 160px 1fr 140px;
  align-items: center; gap: 12px;
}
.funnel-label { font-weight: 600; font-size: 13px; }
.funnel-bar {
  height: 18px; border-radius: 999px;
  background: rgba(127,127,127,.15);
  overflow: hidden;
}
.funnel-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #2dd4bf, #0ea5e9);
  border-radius: 999px;
  transition: width .4s ease;
}
.funnel-count { font-size: 13px; font-variant-numeric: tabular-nums; text-align: right; }
@media (max-width: 540px) {
  .funnel-row { grid-template-columns: 1fr; gap: 4px; }
  .funnel-count { text-align: left; }
}

.signup-bars {
  display: grid; grid-template-columns: repeat(30, 1fr);
  gap: 3px; height: 80px;
  align-items: end; margin: 8px 0 6px;
}
.signup-bar {
  position: relative; height: 100%;
  display: flex; flex-direction: column; justify-content: end;
}
.signup-bar-fill {
  background: linear-gradient(180deg, #2dd4bf, #0ea5e9);
  border-radius: 2px 2px 0 0;
  min-height: 2px;
}
.signup-bar-label {
  font-size: 9px; color: var(--muted);
  text-align: center; margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 540px) {
  .signup-bar-label { display: none; }
}

.analytics-table { font-size: 13px; }
.analytics-table td { padding: 6px 10px; }
.status-pill {
  display: inline-block; font-size: 11px; padding: 2px 8px;
  border-radius: 999px; font-weight: 600;
  border: 1px solid var(--glass-border);
}
.status-pill-pro  { color: rgba(45,212,191,1); border-color: rgba(45,212,191,.55); }
.status-pill-free { color: var(--muted); }
.status-pill-warn { color: rgba(251,191,36,1); border-color: rgba(251,191,36,.55); }
.status-pill-muted { color: var(--muted); }

.referrer-list { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }
.referrer-row {
  display: grid; grid-template-columns: 180px 1fr 60px;
  align-items: center; gap: 10px;
  font-size: 13px;
}
.referrer-host { font-family: var(--mono, monospace); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.referrer-bar {
  height: 10px; border-radius: 999px;
  background: rgba(127,127,127,.15);
  overflow: hidden;
}
.referrer-bar-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #7dd3fc, #0ea5e9);
}
.referrer-count { font-variant-numeric: tabular-nums; text-align: right; font-weight: 600; }
@media (max-width: 540px) {
  .referrer-row { grid-template-columns: 1fr 60px; }
  .referrer-bar { grid-column: 1 / -1; }
}

/* streak-analysis-2026-05-02 — admin tool: streak summary + 14-day
   activity bar chart. Layout matches the admin analytics chart so the
   visual language is consistent. */
.streak-stats {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  margin: 10px 0;
}
.streak-stat {
  background: var(--surface-2, rgba(0,0,0,.025));
  border: 1px solid var(--border, rgba(0,0,0,.06));
  border-radius: 10px; padding: 10px 12px;
  text-align: center;
}
.streak-stat-num {
  font-size: 22px; font-weight: 700; color: var(--accent, #0ea5e9);
  line-height: 1.1;
}
.streak-stat-lbl {
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted, #777); margin-top: 2px;
}
.streak-chart-wrap { margin-top: 10px; }
.streak-chart {
  display: flex; align-items: flex-end; gap: 4px;
  height: 120px;
  padding: 8px;
  border: 1px solid var(--border, rgba(0,0,0,.06));
  border-radius: 10px;
  background: var(--surface-2, rgba(0,0,0,.02));
}
.streak-bar {
  flex: 1; min-width: 0;
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  height: 100%;
  cursor: default;
}
.streak-bar-fill {
  width: 70%; min-width: 4px;
  background: linear-gradient(180deg, #5eead4, #14b8a6);
  border-radius: 3px 3px 0 0;
  min-height: 1px;
  transition: filter .12s ease;
}
.streak-bar:hover .streak-bar-fill { filter: brightness(1.15); }
.streak-bar-today .streak-bar-fill {
  background: linear-gradient(180deg, #38bdf8, #0ea5e9);
  outline: 1px solid rgba(14,165,233,.6);
}
.streak-bar-laststudy .streak-bar-fill {
  background: linear-gradient(180deg, #fcd34d, #f59e0b);
}
.streak-bar-label {
  font-size: 10px; color: var(--muted, #777);
  margin-top: 2px;
}
.streak-bar-month {
  font-size: 9px; line-height: 1;
}
.streak-chart-foot { margin-top: 6px; }

/* mp-active-banner-2026-05-02 — home page banner that surfaces the
   user's currently-pending multiplayer room (host waiting for opponent,
   opponent just joined, or match in progress). Pulses softly when the
   opponent has arrived so it grabs attention without being aggressive. */
.mp-active-banner {
  display: flex; align-items: center; gap: 14px;
  margin: 0 0 14px 0; padding: 14px 18px;
  text-decoration: none;
  border-radius: 14px;
  border: 1px solid var(--border, rgba(0,0,0,.08));
  background: var(--surface-2, #fff);
  color: var(--ink);
  transition: transform .12s ease, box-shadow .18s ease;
}
.mp-active-banner:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(14,165,233,.10);
}
.mp-active-banner .mp-active-emoji {
  font-size: 28px; line-height: 1; flex: 0 0 auto;
}
.mp-active-banner .mp-active-text { flex: 1; min-width: 0; }
.mp-active-banner .mp-active-title { font-weight: 600; }
.mp-active-banner .mp-active-body  { font-size: 13px; }
.mp-active-banner .mp-active-body code {
  background: rgba(0,0,0,.06); padding: 1px 6px; border-radius: 6px;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
}
.mp-active-banner .mp-active-cta {
  flex: 0 0 auto;
  font-weight: 600; font-size: 14px;
  color: var(--accent, #0ea5e9);
}
/* "Opponent ready" — accented border + soft glow pulse. */
.mp-active-banner.mp-active-ready {
  border-color: rgba(45,212,191,.55);
  background: linear-gradient(135deg, rgba(45,212,191,.10), rgba(14,165,233,.08));
  animation: mp-active-pulse 2.4s ease-in-out infinite;
}
@keyframes mp-active-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(45,212,191,.30); }
  50%      { box-shadow: 0 0 0 8px rgba(45,212,191,0);  }
}
@media (prefers-reduced-motion: reduce) {
  .mp-active-banner.mp-active-ready { animation: none; }
}

/* mp-conn-banner-2026-05-02 — connection-lost banner above the question
   card during a live match. Only visible when navigator.onLine is false
   or the user clicks Re-sync. Soft amber so it's noticed without panic. */
.mp-conn-banner {
  background: rgba(245, 158, 11, 0.10);
  border: 1px solid rgba(245, 158, 11, 0.45);
  color: #92400e;
  padding: 8px 12px;
  border-radius: 10px;
  margin-bottom: 10px;
  font-size: 13px;
  font-weight: 500;
}

/* email-management-2026-05-02 — admin toggles for scheduled email
   types. Custom switch styling so each toggle reads as a row with the
   label + description on the right and the actual switch on the left. */
.email-toggle {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 10px 12px;
  background: var(--surface-2, rgba(0,0,0,.025));
  border: 1px solid var(--border, rgba(0,0,0,.06));
  border-radius: 10px;
  cursor: pointer;
  transition: background .12s ease;
}
.email-toggle:hover { background: var(--surface-2-hover, rgba(0,0,0,.04)); }
.email-toggle input[type="checkbox"] {
  position: absolute; opacity: 0; width: 0; height: 0;
}
.email-toggle .email-toggle-track {
  flex: 0 0 auto;
  width: 38px; height: 22px;
  border-radius: 999px;
  background: rgba(120,120,120,.30);
  position: relative;
  transition: background .15s ease;
  margin-top: 2px;
}
.email-toggle .email-toggle-thumb {
  position: absolute;
  top: 2px; left: 2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.18);
  transition: transform .18s ease;
}
.email-toggle input[type="checkbox"]:checked ~ .email-toggle-track {
  background: #14b8a6;
}
.email-toggle input[type="checkbox"]:checked ~ .email-toggle-track .email-toggle-thumb {
  transform: translateX(16px);
}
.email-toggle .email-toggle-text {
  flex: 1; line-height: 1.4;
}
.email-toggle .email-toggle-text strong { font-size: 14px; }

/* admin-access-panel-2026-05-02 — promote/revoke admins from /admin. */
.admin-add-row {
  display: flex; gap: 10px; align-items: stretch; flex-wrap: wrap;
  margin-top: 10px;
}
.admin-add-row .input {
  flex: 1 1 260px; min-width: 0;
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--border, rgba(0,0,0,.12));
  background: var(--surface-2, #fff);
  color: var(--ink); font: inherit;
}
.admin-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.admin-list .admin-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border-radius: 10px;
  background: var(--surface-2, rgba(0,0,0,.025));
  border: 1px solid var(--border, rgba(0,0,0,.06));
}
.admin-list .admin-email {
  flex: 1; font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 13px; word-break: break-all;
}
.admin-list .admin-row-empty { padding: 10px 0; }
.admin-list .tag-muted {
  background: rgba(120,120,120,.12); color: var(--muted, #777);
  border: 1px solid rgba(120,120,120,.2);
  padding: 2px 8px; border-radius: 999px; font-size: 11px;
}

/* bank-console-2026-05-02 — comprehensive tabbed bank manager. Browse
   + Import + Export + Delete + Activity, with search/filter, multi-
   select bulk operations, and round-trip-safe JSON/Excel I/O. */

.bank-tabs {
  display: flex; gap: 6px; flex-wrap: wrap;
  border-bottom: 1px solid var(--border, rgba(0,0,0,.08));
  margin-bottom: 0;
}
.bank-tabs button {
  appearance: none; background: transparent; border: 0;
  font: inherit; font-weight: 500;
  padding: 10px 16px; cursor: pointer;
  color: var(--muted, #777);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .12s ease, border-color .12s ease;
}
.bank-tabs button:hover { color: var(--ink); }
.bank-tabs button.active {
  color: var(--accent, #0ea5e9);
  border-bottom-color: var(--accent, #0ea5e9);
}

/* Browse toolbar (search + filters). */
.bank-browse-toolbar {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  margin-bottom: 12px;
}
.bank-browse-toolbar .input {
  flex: 1; min-width: 180px;
  padding: 8px 12px; border-radius: 10px;
  border: 1px solid var(--border, rgba(0,0,0,.12));
  background: var(--surface-2, #fff); color: var(--ink); font: inherit;
}
.bank-browse-toolbar select.input { flex: 0 0 auto; min-width: 140px; }

/* Selection bar — appears when rows are checked. */
.bank-selection-bar {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  background: linear-gradient(135deg, rgba(45,212,191,.08), rgba(14,165,233,.06));
  border: 1px solid rgba(45,212,191,.30);
  border-radius: 10px;
  padding: 8px 14px;
  margin-bottom: 10px;
  font-size: 14px;
}
.bank-selection-bar.hidden { display: none; }

/* Browse table. */
.bank-table {
  width: 100%; border-collapse: collapse;
  font-size: 13px;
}
.bank-table th, .bank-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid var(--border, rgba(0,0,0,.06));
  vertical-align: top;
}
.bank-table th {
  font-weight: 600; font-size: 11px;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted, #777);
  background: var(--surface-2, rgba(0,0,0,.025));
  cursor: default;
  user-select: none;
}
.bank-table th[data-sort] { cursor: pointer; }
.bank-table th[data-sort]:hover { color: var(--ink); }
.bank-table tbody tr:hover { background: rgba(0,0,0,.02); }
.bank-col-check  { width: 30px; }
.bank-col-id     { width: 92px; white-space: nowrap; }
.bank-col-id a   { font-family: ui-monospace, Menlo, Consolas, monospace; }
.bank-col-stem   { max-width: 540px; }

/* Per-row "preview as quiz" eye button — sits next to the #ID link.
   Subtle by default, brightens on hover. Clicking opens a modal
   showing the question rendered as a real quiz card. */
.bank-row-preview {
  margin-left: 6px;
  padding: 0 4px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  opacity: .55;
  transition: opacity .12s, transform .1s, background .12s;
  vertical-align: middle;
}
.bank-row-preview:hover { opacity: 1; transform: scale(1.12); background: rgba(45,212,191,.12); }
.bank-row-preview:focus { outline: none; opacity: 1; box-shadow: 0 0 0 2px rgba(45,212,191,.3); }

/* Quiz-format preview modal — wider than the default modal so the
   quiz card has room to breathe (image + 5 choices + explanation can
   be tall). The header puts a close ✕ on the right of the title. */
.bank-preview-card { max-width: 760px; }
.bank-preview-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 4px;
}
.bank-preview-head h2 { margin: 0; }
.bank-preview-slot { margin-top: 12px; }
/* Tame the inner quiz card so it sits naturally inside the modal —
   the .quiz card normally has its own card chrome. */
.bank-preview-slot .card.quiz {
  margin: 0;
}

/* ─── Activity tab (bank console) ─────────────────────────────────────
   Reverse-chronological event log with day-grouped sections. Each row
   shows an icon, the action description, qid chips, and actor + time.
   Tone-coloured left border keys readers to severity — info/ok/warn. */
.bank-activity-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px;
}
.bank-activity-sub { margin: 0; flex: 1 1 320px; }

.bank-activity-day { margin: 14px 0; }
.bank-activity-day:first-child { margin-top: 4px; }
.bank-activity-day-label {
  font-size: 11.5px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 4px 8px;
  margin-bottom: 6px;
  border-bottom: 1px dashed var(--glass-border);
}
.bank-activity-events {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.bank-activity-row {
  display: grid;
  grid-template-columns: 32px 1fr;
  gap: 10px;
  align-items: start;
  padding: 8px 12px;
  border-radius: var(--radius-s);
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-left: 3px solid var(--glass-border-strong);
}
.bank-activity-info { border-left-color: rgba(14,165,233,.55); }
.bank-activity-ok   { border-left-color: rgba(45,212,191,.65); }
.bank-activity-warn { border-left-color: rgba(244,63,94,.55); }
.bank-activity-icon {
  font-size: 16px;
  line-height: 1;
  padding-top: 2px;
}
.bank-activity-body { min-width: 0; }
.bank-activity-title {
  font-size: 14px; font-weight: 600;
  color: var(--text);
  word-break: break-word;
}
.bank-activity-meta {
  margin-top: 2px;
  display: flex; align-items: center; gap: 6px;
  flex-wrap: wrap;
}
.bank-activity-actor {
  font-family: ui-monospace, Menlo, Consolas, monospace;
}

.bank-activity-chips {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 4px;
}
.bank-activity-chip {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11.5px;
  padding: 1px 8px;
  border-radius: 4px;
  background: rgba(45,212,191,.12);
  border: 1px solid rgba(45,212,191,.3);
  color: var(--accent, #2dd4bf);
  text-decoration: none;
}
.bank-activity-chip:hover { background: rgba(45,212,191,.22); }
.bank-activity-chip-more {
  background: var(--glass);
  border-color: var(--glass-border);
  color: var(--muted);
  cursor: default;
}

/* Each affected qid in an event row renders as a pair: the #NNN chip
   (edit modal) and an 👁 button (preview modal). Visually fused with
   shared rounding so the two adjacent buttons read as one capsule. */
.bank-activity-chip-pair {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  border-radius: 4px;
  overflow: hidden;
}
.bank-activity-chip-pair .bank-activity-chip {
  border-radius: 4px 0 0 4px;
  border-right: 0;
}
.bank-activity-chip-eye {
  font-size: 11px;
  padding: 1px 7px;
  background: rgba(45,212,191,.08);
  border: 1px solid rgba(45,212,191,.3);
  border-radius: 0 4px 4px 0;
  cursor: pointer;
  line-height: 1.4;
  color: var(--text-dim);
  transition: background .12s, transform .1s, color .12s;
}
.bank-activity-chip-eye:hover {
  background: rgba(45,212,191,.22);
  color: var(--text);
  transform: none;        /* the chip-pair is already a capsule, no scale */
}
.bank-activity-chip-eye:focus {
  outline: none;
  box-shadow: 0 0 0 2px rgba(45,212,191,.3);
  position: relative;
  z-index: 1;
}

.bank-activity-foot {
  margin-top: 12px;
  display: flex; justify-content: center;
}
.bank-activity-foot.muted { padding: 8px; }


/* Pagination. */
.bank-pagination {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 8px;
  margin-top: 12px; padding-top: 8px;
  border-top: 1px solid var(--border, rgba(0,0,0,.05));
}
.bank-pag-controls { display: flex; gap: 6px; align-items: center; }
.bank-pag-controls span { font-size: 13px; color: var(--muted, #777); margin: 0 8px; }

/* Import mode toggles (radio rows, shared with delete confirmations). */
.bank-mode-row {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--surface-2, rgba(0,0,0,.025));
  border: 1px solid var(--border, rgba(0,0,0,.06));
  border-radius: 10px;
  padding: 10px 12px; margin: 10px 0 6px;
}
.bank-mode-opt {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  font-size: 14px; line-height: 1.4;
}
.bank-mode-opt input[type="radio"] { margin-top: 3px; flex: 0 0 auto; }
.bank-mode-opt strong { color: var(--ink); }
.bank-mode-opt code {
  background: rgba(0,0,0,.06); padding: 1px 6px; border-radius: 6px;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
}

/* Import/Delete shared input affordances. */
.bulk-import-row { margin-top: 10px; }
.bulk-import-textarea {
  width: 100%; min-height: 180px; resize: vertical;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
  line-height: 1.5;
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--border, rgba(0,0,0,.12));
  background: var(--surface-2, #fff); color: var(--ink);
}
.bulk-import-actions {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  margin-top: 10px;
}
.bulk-import-error {
  background: rgba(220,38,38,.08); border: 1px solid rgba(220,38,38,.30);
  color: #b91c1c; padding: 10px 12px; border-radius: 10px;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
}

/* Preview tables (import + delete share the same look). */
.bulk-import-table {
  width: 100%; border-collapse: collapse; font-size: 13px;
  margin-top: 6px;
}
.bulk-import-table th, .bulk-import-table td {
  padding: 6px 10px; text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--border, rgba(0,0,0,.06));
}
.bulk-import-table th {
  font-weight: 600; color: var(--muted, #777);
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
}
.bulk-row-idx     { width: 36px; color: var(--muted, #777); }
.bulk-row-correct { width: 70px; font-weight: 600; }
.bulk-row-tags    { color: var(--muted, #777); font-size: 12px; }
.bulk-row-status  { width: 36%; }
.bulk-row-err     { background: rgba(220,38,38,.04); }
.bulk-status-ok   { color: #047857; font-weight: 600; }
.bulk-status-err  { color: #b91c1c; font-weight: 600; }

/* Tiny button modifier reused for pagination + selection-bar actions. */
.btn-tiny {
  padding: 4px 10px; font-size: 12px; border-radius: 8px;
}

/* admin-reminders-2026-04-29 */
.reminder-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 16px;
  margin-top: 10px;
}
.reminder-prompt {
  background: linear-gradient(135deg, rgba(45,212,191,.12), rgba(14,165,233,.10));
  border: 1px solid rgba(45,212,191,.40);
  margin-top: 16px; padding: 14px 18px;
}
.reminder-prompt-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.reminder-prompt-text { display: flex; flex-direction: column; gap: 2px; }
.reminder-prompt-actions { display: flex; gap: 8px; }

/* push-reminders-2026-04-28 (Account page) */
.badge-pro {
  display: inline-block; vertical-align: 2px;
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 999px;
  background: linear-gradient(135deg, rgba(45,212,191,.20), rgba(14,165,233,.18));
  border: 1px solid rgba(45,212,191,.55);
  color: var(--ink);
  margin-left: 6px;
}
.push-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 16px;
  margin-top: 8px;
}
.switch {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;
}
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch-track {
  position: relative;
  width: 40px; height: 22px; border-radius: 999px;
  background: rgba(127,127,127,0.30);
  transition: background .15s;
}
.switch-thumb {
  position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.25);
  transition: transform .18s;
}
.switch input:checked ~ .switch-track {
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
}
.switch input:checked ~ .switch-track .switch-thumb {
  transform: translateX(18px);
}
.switch input:disabled ~ .switch-track { opacity: .5; cursor: not-allowed; }
.switch-label { font-weight: 600; }
.push-hour {
  display: inline-flex; align-items: center; gap: 6px;
}
.push-hour select {
  padding: 6px 10px; border-radius: 8px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak); color: var(--ink);
  font-size: 14px;
}
.push-status-ok { color: rgba(45,212,191,.95); }
.push-status-warn { color: rgba(251,191,36,.95); }

/* theme-picker-2026-04-28 (Account page) */
.theme-choice {
  display: grid; gap: 10px; margin-top: 10px;
  grid-template-columns: repeat(2, minmax(140px, 220px));
}
.theme-option {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius);
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  cursor: pointer; user-select: none;
  transition: border-color .12s, background .12s;
}
.theme-option input { position: absolute; opacity: 0; pointer-events: none; }
.theme-option:hover { border-color: rgba(45,212,191,.45); }
.theme-option.is-on {
  border-color: rgba(45,212,191,.85);
  background: linear-gradient(135deg, rgba(45,212,191,.12), rgba(14,165,233,.10));
}
.theme-glyph { font-size: 18px; }
.theme-label { font-weight: 600; font-size: 14px; }

/* exam-countdown-2026-04-28 */
.exam-card { margin-top: 18px; padding: 18px; }
.exam-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 10px;
}
.exam-eyebrow {
  font-size: 12px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); font-weight: 700;
}
.btn-tiny { padding: 4px 10px; font-size: 12px; }
.btn-sm   { padding: 6px 12px; font-size: 12.5px; }
.btn-danger { color: rgba(248,113,113,.95); }

/* ─── Admin · Daily content editor ─────────────────────────────────
   Two-section editor for the home carousel's "Today" slide bank
   (terms + facts). The "today preview" header summarises what's
   currently picked plus a 7-day rolling preview; each section then
   lists every entry with inline edit + delete. */
.adc-today {
  background: var(--glass-weak, rgba(148, 163, 184, 0.10));
  border-radius: var(--radius-s, 8px);
  padding: 12px 14px;
  margin-top: 12px;
  font-size: 13px;
}
.adc-today-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  align-items: center;
}
.adc-today-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim, var(--muted));
}
.adc-today-pick strong { font-weight: 600; }
.adc-upcoming { margin-top: 10px; }
.adc-upcoming > summary { cursor: pointer; font-weight: 600; font-size: 12.5px; color: var(--text-dim, var(--muted)); }
.adc-upcoming-table { margin-top: 8px; display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; }
.adc-up-head, .adc-up-row {
  display: grid;
  grid-template-columns: 80px 1fr 1fr;
  gap: 10px;
}
.adc-up-head { font-weight: 600; color: var(--text-dim, var(--muted)); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; padding-bottom: 4px; border-bottom: 0.5px solid var(--border, rgba(148,163,184,0.18)); }

.adc-section { margin-top: 16px; }
.adc-section-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin-bottom: 6px;
}
.adc-section-head h3 { margin: 0; }
.adc-count { font-size: 12px; color: var(--text-dim, var(--muted)); font-variant-numeric: tabular-nums; }

.adc-seed {
  background: rgba(250, 199, 117, 0.14);
  border: 0.5px solid rgba(186, 117, 23, 0.30);
  border-radius: var(--radius-s, 8px);
  padding: 10px 12px;
  margin: 10px 0;
}
.adc-seed p { margin: 0 0 8px; }

.adc-add { margin: 10px 0; border-top: 0.5px dashed var(--border, rgba(148, 163, 184, 0.25)); padding-top: 10px; }
.adc-add > summary { cursor: pointer; font-weight: 600; color: var(--text, var(--ink)); padding: 6px 0; }

.adc-list { list-style: none; padding: 0; margin: 12px 0 0; display: flex; flex-direction: column; gap: 6px; }
.adc-row {
  border: 0.5px solid var(--border, rgba(148, 163, 184, 0.25));
  border-radius: var(--radius-s, 8px);
  padding: 10px 12px;
  background: var(--surface, var(--glass-weak));
}
.adc-row-head { display: flex; align-items: center; gap: 10px; }
.adc-row-idx {
  font-size: 11px; font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums;
  background: var(--glass-weak, rgba(148, 163, 184, 0.18));
  padding: 2px 8px; border-radius: 999px;
}
.adc-row-title { flex: 1; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adc-row-actions { display: inline-flex; gap: 6px; flex-shrink: 0; }
.adc-row-preview { margin: 6px 0 0; padding-left: 40px; }
.adc-row-body { margin-top: 10px; padding-top: 10px; border-top: 0.5px dashed var(--border, rgba(148, 163, 184, 0.25)); }

.adc-form { display: flex; flex-direction: column; gap: 10px; padding: 8px 0; }
.adc-field { display: flex; flex-direction: column; gap: 4px; }
.adc-field-label { font-size: 12px; color: var(--text-dim, var(--muted)); font-weight: 600; }
.adc-field input, .adc-field textarea {
  font: inherit;
  font-size: 13.5px;
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid var(--border, rgba(148, 163, 184, 0.25));
  background: var(--surface, transparent);
  color: var(--text, var(--ink));
  resize: vertical;
}
.adc-form-actions { display: flex; gap: 8px; margin-top: 2px; }

.adc-back { margin-top: 16px; }
.exam-card-row {
  display: grid; gap: 18px;
  grid-template-columns: 1fr 1fr;
  align-items: center;
}
@media (max-width: 600px) {
  .exam-card-row { grid-template-columns: 1fr; }
}
.exam-countdown { text-align: left; }
.exam-big {
  font-size: 32px; font-weight: 800; line-height: 1.1;
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.exam-card.is-past .exam-big {
  background: linear-gradient(135deg, #fbbf24, #f87171);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.exam-sub { margin-top: 2px; font-size: 14px; }
.exam-date { margin-top: 2px; }

.exam-plan-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; font-size: 13px;
}
.exam-plan-label { color: var(--muted); }
.exam-plan-count { font-weight: 700; font-size: 15px; color: var(--ink); font-variant-numeric: tabular-nums; }
.exam-plan-bar {
  margin-top: 6px; height: 8px; border-radius: 999px; overflow: hidden;
  background: rgba(127,127,127,0.18);
}
.exam-plan-bar > span {
  display: block; height: 100%;
  background: linear-gradient(90deg, #2dd4bf, #0ea5e9);
  transition: width .4s ease;
}
.exam-card.is-met .exam-plan-bar > span {
  background: linear-gradient(90deg, #34d399, #10b981);
}
.exam-plan-explain { margin-top: 6px; }
.exam-plan-met { margin-top: 6px; font-size: 13px; color: rgba(45,212,191,.95); font-weight: 600; }

.exam-empty .exam-edit-form { margin-top: 8px; }
.exam-edit-form {
  display: grid; gap: 10px; margin-top: 14px;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  padding-top: 14px;
  border-top: 1px solid var(--glass-border);
}
.exam-field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
.exam-field input {
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak); color: var(--ink);
  font-size: 14px;
}
.exam-edit-actions {
  grid-column: 1 / -1;
  display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap;
}

/* flashcards-2026-04-28 */
.fc-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 8px;
}
.fc-head-actions { display: flex; gap: 6px; align-items: center; }
.fc-eyebrow {
  font-size: 12px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); font-weight: 700;
}
.fc-setup .fc-field {
  border: none; padding: 0; margin: 18px 0 0;
}
.fc-setup .fc-field legend {
  font-size: 12px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin-bottom: 8px; padding: 0;
}
.fc-source-row {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}
.fc-radio {
  display: flex; flex-direction: column; gap: 2px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 10px 14px; cursor: pointer;
  transition: border-color .15s, background .15s, transform .1s;
}
.fc-radio input { position: absolute; opacity: 0; pointer-events: none; }
.fc-radio:hover { border-color: rgba(45,212,191,.45); }
.fc-radio.is-on {
  border-color: rgba(45,212,191,.85);
  background: linear-gradient(135deg, rgba(45,212,191,.12), rgba(14,165,233,.10));
}
.fc-radio.disabled { opacity: .5; cursor: not-allowed; }
.fc-radio-title { font-weight: 600; font-size: 14px; }
.fc-radio-sub { font-size: 12px; color: var(--muted); }
.fc-chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  max-height: 140px; overflow-y: auto; padding: 2px;
}
.fc-chip {
  display: inline-flex; align-items: center;
  font-size: 12px; padding: 4px 10px;
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  background: var(--glass-weak);
  cursor: pointer; user-select: none;
  transition: border-color .12s, background .12s;
}
.fc-chip input { position: absolute; opacity: 0; pointer-events: none; }
.fc-chip:hover { border-color: rgba(45,212,191,.45); }
.fc-chip.is-on {
  border-color: rgba(45,212,191,.85);
  background: rgba(45,212,191,.18);
  color: var(--ink);
}
.fc-row-end {
  display: flex !important; align-items: end; gap: 12px;
  flex-wrap: wrap;
}
.fc-row-end legend { width: 100%; }

/* Deck-size dropdown — custom styled select that matches the glass aesthetic
   of the rest of the form. We strip the native UA chrome and paint our own
   chevron via an inline SVG background-image so the control reads as part of
   the same design system as the chips and buttons around it. */
.fc-limit {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  min-width: 160px;
  padding: 11px 40px 11px 14px;
  font: inherit;
  font-size: 15px;
  color: var(--text);
  background-color: var(--glass-weak);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px 16px;
  backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-s);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.fc-limit:hover {
  border-color: rgba(45,212,191,.55);
  background-color: rgba(45,212,191,.08);
}
.fc-limit:focus {
  outline: none;
  border-color: rgba(45,212,191,.85);
  box-shadow: 0 0 0 3px rgba(45,212,191,.18), inset 0 1px 0 rgba(255,255,255,.08);
}
.fc-limit option {
  /* Native dropdown panel — drive both colors from theme variables so the
     panel stays readable in both dark mode (dark navy bg, near-white text)
     and light mode (light pearl bg, near-black text). Hard-coding either
     side breaks the other theme. */
  background: var(--bg-0);
  color: var(--text);
  padding: 6px 10px;
}

.fc-card .fc-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
/* Flashcard question stem — bumped to 22px desktop / 19px phone for
   easy reading. Grows to fill the card's vertical space (flex:1) and
   centers its content vertically so the question dominates the front
   face the way a physical flashcard does, instead of sitting as a
   small block at the top with empty space below. max-width caps line
   length for prose readability on wide screens. */
.fc-stem {
  font-size: 22px;
  line-height: 1.6;
  letter-spacing: -.005em;
  margin: 0;
  color: var(--ink, var(--text));
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-width: 65ch;
  align-self: center;
  width: 100%;
}
.fc-stem p { margin: 0 0 .8em; font-size: inherit; }
.fc-stem p:last-child { margin-bottom: 0; }
@media (max-width: 540px) {
  .fc-stem { font-size: 19px; line-height: 1.55; }
}
.fc-figure { margin: 8px 0; text-align: center; }
.fc-figure img {
  max-width: 100%; max-height: 360px; border-radius: var(--radius);
  border: 1px solid var(--glass-border);
}

/* Admin-only "Exclude from deck" button on the flashcard page header.
   Subtle red tint on hover so it reads as a destructive-ish action
   without screaming. The default state stays ghost-quiet so it
   doesn't compete with Edit / End session for visual attention. */
.fc-exclude-btn {
  color: var(--text-dim);
}
.fc-exclude-btn:hover {
  color: #dc2626;
  border-color: rgba(220, 38, 38, .35);
  background: rgba(220, 38, 38, .06);
}
.fc-exclude-btn:disabled {
  opacity: .55;
  cursor: not-allowed;
}

/* ── 3D flip card ────────────────────────────────────────────────────
 * Real flashcard mechanic — both faces render in the same DOM and the
 * flipper rotates 180° on the Y-axis to swap which face is visible.
 * CSS Grid is the layout primitive: both faces sit in the same 1×1
 * grid cell so the flipper grows to the height of the taller face.
 * backface-visibility:hidden keeps the rotated-away face from showing
 * through during/after the rotation.
 */
.fc-flip-wrap {
  perspective: 1600px;
  margin: 6px 0 4px;
}
.fc-flipper {
  display: grid;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.65s cubic-bezier(.2, .8, .2, 1);
  cursor: pointer;
  outline: none;
}
.fc-flipper:focus-visible {
  /* Keyboard focus ring on the whole card — matches the global ring style. */
  box-shadow: 0 0 0 3px var(--ring-glow, rgba(14,165,163,.22));
  border-radius: var(--radius);
}
.fc-flipper.is-flipped {
  transform: rotateY(180deg);
}
@media (prefers-reduced-motion: reduce) {
  .fc-flipper { transition: none; }
}
.fc-face {
  /* Both faces stack in the same grid cell — flipper sizes to taller. */
  grid-column: 1;
  grid-row: 1;
  padding: 18px 20px 16px;
  border-radius: var(--radius);
  background: var(--surface, var(--glass-weak));
  border: 1px solid var(--border, var(--glass-border));
  box-shadow: var(--shadow-1);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.fc-face-back {
  /* Pre-rotated 180° on Y so when the flipper rotates, this face is
     the one facing the viewer. */
  transform: rotateY(180deg);
  background:
    linear-gradient(180deg, rgba(14,165,163,.06) 0%, transparent 35%),
    var(--surface, var(--glass-weak));
  border-color: color-mix(in srgb, var(--primary, #0ea5a3) 30%, var(--border, var(--glass-border)));
}
.fc-face-eyebrow {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--primary, #0ea5a3);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.fc-face-eyebrow::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--primary, #0ea5a3);
}
.fc-face-eyebrow-answer {
  /* Slightly different tonal value on the back so eyebrow distinguishes
     "Question" from "Answer" beyond just text alone. */
  color: var(--primary-dark, #0f766e);
}
.fc-face-eyebrow-answer::before {
  background: var(--primary-dark, #0f766e);
}

/* Tap-to-flip hint at the bottom of the front face — dashed top border
   to signal "below this is the action zone", subtle pulsing keyboard
   <kbd> chip to draw the eye on first viewing. */
.fc-flip-hint {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px dashed var(--border, var(--glass-border));
  font-size: 12.5px;
  color: var(--text-dim, var(--muted));
  text-align: center;
  letter-spacing: .02em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-wrap: wrap;
}
.fc-flip-hint kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--surface-2, var(--glass-weak));
  border: 1px solid var(--border, var(--glass-border));
  padding: 1px 7px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink, var(--text));
}
.fc-flip-hint-icon {
  display: inline-block;
  font-size: 13px;
  animation: fc-flip-hint-spin 6s linear infinite;
  transform-origin: center;
}
@keyframes fc-flip-hint-spin {
  0%, 80% { transform: rotate(0); }
  100%    { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .fc-flip-hint-icon { animation: none; }
}

/* Hover lift on the flipper — only when the back is NOT yet revealed,
   to telegraph "this is interactive". Once flipped, the user is in
   grading territory and the lift would distract. */
.fc-flipper:not(.is-flipped):hover .fc-face-front {
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
  transition: transform 200ms var(--ease, cubic-bezier(.2,.8,.2,1)),
              box-shadow 200ms var(--ease, cubic-bezier(.2,.8,.2,1));
}

/* Legacy .fc-back / .fc-actions-flip / .fc-flip-btn rules are no longer
   used by the redesigned flip layout, but we leave the selectors in the
   stylesheet so older bookmarks / saved states render gracefully if a
   user happens to hit the JS while it's mid-deploy. */
.fc-actions-flip { display: flex; justify-content: center; margin-top: 12px; }
.fc-flip-btn { min-width: 220px; }
.fc-back {
  margin-top: 6px; padding: 14px 16px; border-radius: var(--radius);
  background: var(--surface-2, var(--glass-weak));
  border: 1px solid var(--border, var(--glass-border));
}
.fc-answer-row { display: flex; align-items: center; gap: 10px; font-size: 17px; font-weight: 600; }
.fc-answer-letter {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px;
  background: rgba(45,212,191,.85); color: #03263a; font-weight: 800;
}
.fc-answer-text { color: var(--ink); }
.fc-answer-line { margin-top: 8px; color: var(--ink); }
/* Back-face explanation prose — slightly smaller than the question
   stem (which is 22px) since explanations are usually denser and the
   reader has already recalled before flipping, but bumped from the old
   inherited 14-15px so it doesn't read like fine print. */
.fc-explain {
  margin-top: 8px;
  color: var(--ink);
  font-size: 17px;
  line-height: 1.6;
}
.fc-explain p { margin: 0 0 .7em; font-size: inherit; }
.fc-explain p:last-child { margin-bottom: 0; }
@media (max-width: 540px) {
  .fc-explain { font-size: 15.5px; line-height: 1.55; }
}
/* Clinical-rule callouts inside the flashcard explanation now share the
   global block-level treatment (with 📌 eyebrow) defined alongside
   .feedback-explain / .question-block / .rte-editor higher up in this
   stylesheet — see the RTE-clinical-rule-callout-2026-05-10 block. */

.fc-grade-row {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 8px; margin-top: 14px;
}
@media (max-width: 520px) {
  .fc-grade-row { grid-template-columns: repeat(2, 1fr); }
}
.fc-grade {
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  padding: 10px 8px; border-radius: var(--radius);
  font-weight: 700; font-size: 14px; cursor: pointer;
  border: 1px solid var(--glass-border);
  background: var(--glass-weak); color: var(--ink);
  transition: transform .08s, background .12s, border-color .12s;
}
.fc-grade:hover { transform: translateY(-1px); }
.fc-grade-hint { font-size: 11px; font-weight: 500; color: var(--muted); }
.fc-grade-again { border-color: rgba(248,113,113,.55); }
.fc-grade-again:hover { background: rgba(248,113,113,.18); }
.fc-grade-hard  { border-color: rgba(251,191,36,.55); }
.fc-grade-hard:hover  { background: rgba(251,191,36,.18); }
.fc-grade-good  { border-color: rgba(45,212,191,.55); }
.fc-grade-good:hover  { background: rgba(45,212,191,.18); }
.fc-grade-easy  { border-color: rgba(125,211,252,.55); }
.fc-grade-easy:hover  { background: rgba(125,211,252,.18); }

.fc-summary-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  margin: 14px 0;
}
.fc-stat {
  text-align: center; padding: 14px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
}
.fc-stat-num {
  font-size: 22px; font-weight: 700;
  background: linear-gradient(135deg, #2dd4bf, #0ea5e9);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.fc-stat-lbl { font-size: 12px; color: var(--muted); }
.fc-grade-breakdown {
  display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0;
}
.fc-pill {
  font-size: 12px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--glass-border); background: var(--glass-weak);
  font-weight: 600;
}
.fc-summary-actions {
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end;
  margin-top: 8px;
}

/* ─── Welcome diagnostic ──────────────────────────────────────────────────
   First-run skill check-up flow: warm intro card, full-width progress bar
   above each question, and a colored skill-heatmap result. The intro and
   result reuse the .card surface; only the chrome around the question
   loop (the progress bar) is bespoke — the question card itself is the
   shared .quiz block from quiz.js so it feels identical to Practice. */

/* Intro card — single tall surface with a big icon, friendly copy, and
   two CTAs. Centered layout pulls the eye to the start button. */
.diag-intro {
  text-align: center;
  padding: 36px 28px 32px;
  display: flex; flex-direction: column; align-items: center;
  gap: 14px;
}
.diag-intro-icon {
  font-size: 56px; line-height: 1;
  width: 96px; height: 96px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,.28), transparent 55%),
    linear-gradient(135deg, rgba(94,234,212,.45), rgba(20,184,166,.62));
  border: 2px solid rgba(13,148,136,.45);
  box-shadow:
    0 8px 22px rgba(13,148,136,.20),
    inset 0 -3px 6px rgba(0,0,0,.08),
    inset 0 3px 6px rgba(255,255,255,.30);
  margin-bottom: 4px;
}
.diag-intro-title {
  font-size: 24px; font-weight: 700; line-height: 1.25;
  color: var(--text);
  margin: 0;
}
.diag-intro-body {
  font-size: 15px; line-height: 1.55;
  color: var(--text-dim);
  max-width: 38ch;
  margin: 0;
}
.diag-intro-meta {
  font-size: 13px; max-width: 38ch;
  margin: 0;
}
.diag-intro-actions {
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: center;
  margin-top: 10px;
}

/* Top-of-page progress strip during the question loop. Sits above the
   shared .quiz card and replaces the in-card progressText, since the
   user benefits from seeing "I'm 4/10 of the way through the warmup"
   at a glance without hunting the card header. */
.diag-progress {
  margin: 6px 0 14px;
  padding: 0 4px;
}
.diag-progress-label {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 6px;
}
.diag-progress-step {
  font-size: 13px; font-weight: 600; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.diag-progress-pct {
  font-size: 12px; font-variant-numeric: tabular-nums;
}
.diag-progress-bar {
  height: 6px; border-radius: 999px;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  overflow: hidden;
}
.diag-progress-bar > span {
  display: block; height: 100%;
  background: linear-gradient(90deg, #2dd4bf, #14b8a6);
  border-radius: 999px;
  transition: width .35s cubic-bezier(.4,0,.2,1);
}

/* Result screen — overall score + skill heatmap + recommendation. */
.diag-result {
  padding: 28px 24px 24px;
}
.diag-result-head {
  display: flex; align-items: center; gap: 14px;
  margin-bottom: 6px;
}
.diag-result-icon {
  font-size: 40px; line-height: 1;
  width: 64px; height: 64px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 16px;
  background: rgba(45,212,191,.14);
  border: 1px solid rgba(45,212,191,.35);
  flex-shrink: 0;
}
.diag-result-title {
  font-size: 22px; font-weight: 700; line-height: 1.2;
  color: var(--text);
  margin: 0 0 2px;
}
.diag-result-headline {
  font-size: 14px; color: var(--text-dim);
  margin: 0;
}
.diag-result-headline strong {
  color: var(--text); font-weight: 700;
}
.diag-result-sub {
  font-size: 14px; line-height: 1.5;
  margin: 12px 0 18px;
}

/* Skill grid — one cell per subject the user encountered, color-coded
   by accuracy bucket. Cells stretch to fill 2 columns on mobile,
   3 columns on wider screens. */
.diag-skill-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 18px;
}
@media (min-width: 540px) {
  .diag-skill-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.diag-skill-cell {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--glass-border);
  background: var(--glass-weak);
  font-size: 13px;
  /* Cells that wrap their subject name shouldn't blow up vertically. */
  min-height: 44px;
}
.diag-skill-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--muted);
  flex-shrink: 0;
}
.diag-skill-name {
  flex: 1;
  font-weight: 600; color: var(--text);
  /* Long subject names truncate gracefully rather than blow the cell out. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.diag-skill-acc {
  font-size: 12px; font-weight: 600; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
/* Accuracy tiers. RGBA fills work in both light and dark mode without
   per-mode overrides — the alpha keeps contrast against any surface. */
.diag-skill-strong {
  background: rgba(34,197,94,.12);
  border-color: rgba(34,197,94,.40);
}
.diag-skill-strong .diag-skill-dot { background: #22c55e; }
.diag-skill-ok {
  background: rgba(245,158,11,.12);
  border-color: rgba(245,158,11,.40);
}
.diag-skill-ok .diag-skill-dot { background: #f59e0b; }
.diag-skill-weak {
  background: rgba(239,68,68,.12);
  border-color: rgba(239,68,68,.40);
}
.diag-skill-weak .diag-skill-dot { background: #ef4444; }
.diag-skill-untested {
  opacity: .65;
}

/* Recommendation card — the "we'd start you with X" CTA. Lays out as
   icon | text | button on wide screens, stacks under each other on
   narrow ones. The bordered fill matches the recommended subject's
   tier color, so a weak-area recommendation looks distinctly different
   from a strong-area one. */
.diag-recommend {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  border-radius: var(--radius);
  border: 1.5px solid rgba(45,212,191,.45);
  background:
    radial-gradient(ellipse at top left, rgba(45,212,191,.16), transparent 60%),
    var(--glass-weak);
  margin-bottom: 16px;
}
@media (max-width: 520px) {
  .diag-recommend {
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
  }
  .diag-recommend-cta { grid-column: 1 / -1; justify-self: stretch; text-align: center; }
}
.diag-recommend-icon {
  font-size: 32px; line-height: 1;
  width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 12px;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,.30), transparent 55%),
    linear-gradient(135deg, rgba(94,234,212,.45), rgba(20,184,166,.65));
  border: 1.5px solid rgba(13,148,136,.45);
  flex-shrink: 0;
}
.diag-recommend-text {
  min-width: 0;  /* allow ellipsis on long subject names */
}
.diag-recommend-label {
  font-size: 12px; font-weight: 600;
  color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em;
}
.diag-recommend-subject {
  font-size: 18px; font-weight: 700;
  color: var(--text);
  line-height: 1.25;
  margin: 1px 0 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.diag-recommend-rationale {
  font-size: 13px; line-height: 1.4;
}
.diag-recommend-cta { white-space: nowrap; }

/* Tier-specific accent on the recommendation card — matches the cell
   colors so a weak-area recommendation reads as "needs work" and a
   strong-area one as "let's keep it sharp". */
.diag-recommend-weak {
  border-color: rgba(239,68,68,.45);
  background:
    radial-gradient(ellipse at top left, rgba(239,68,68,.14), transparent 60%),
    var(--glass-weak);
}
.diag-recommend-ok {
  border-color: rgba(245,158,11,.45);
  background:
    radial-gradient(ellipse at top left, rgba(245,158,11,.14), transparent 60%),
    var(--glass-weak);
}
.diag-recommend-strong {
  border-color: rgba(34,197,94,.45);
  background:
    radial-gradient(ellipse at top left, rgba(34,197,94,.14), transparent 60%),
    var(--glass-weak);
}

.diag-result-actions {
  display: flex; justify-content: flex-end; gap: 10px;
  margin-top: 4px;
}

/* Diagnostic skill-map card on /dashboard. Reuses the .diag-skill-grid /
   .diag-skill-cell styles from the diagnostic result screen — only the
   surrounding chrome (compact head, small meta line) is bespoke here. */
.diag-skill-card { /* wrapper is .card, no extra layout needed */ }
.diag-skill-card-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 4px;
}
.diag-skill-card-head h3 { margin: 0; }
.diag-skill-card-meta {
  margin: 0 0 12px;
  font-variant-numeric: tabular-nums;
}

/* ─── 404 / unknown-route view ─────────────────────────────────────────────
   Wraps the shared .empty-state pattern in a centered section so the
   medallion + title + actions sit comfortably on what's otherwise a
   blank page. The "Tried: …" footer line is a small muted code chip
   under the actions — surfaces the failed path so a user catching a
   typo can self-correct, and gives the admin a useful breadcrumb if
   someone reports the issue. */
.notfound {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 32px 16px 24px;
}
.notfound .empty-state {
  /* The empty-state already centers itself; cap width so it doesn't
     stretch edge-to-edge on wide viewports. */
  max-width: 480px;
  width: 100%;
}
.notfound-tried {
  margin: 16px 0 0;
  font-variant-numeric: tabular-nums;
}
.notfound-tried code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--glass-weak);
  border: 1px solid var(--glass-border);
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 12px;
  color: var(--text-dim);
}

/* Admin-route auth gate (renderAdminGate from admin.js).
   Same shape as .notfound — empty-state pattern centered with capped
   width so the medallion + actions don't stretch edge-to-edge on
   desktop. Used by admin-hub, admin-users, admin-analytics, admin
   (bank console), bulk-images. */
.admin-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 32px 16px 24px;
}
.admin-gate .empty-state {
  max-width: 480px;
  width: 100%;
}

/* ─── Heartbeat + ECG loader (.sv-loader) ────────────────────────────────
 * Branded loading indicator — pulses a filled red heart with three
 * cool-toned ripple rings (sky → teal → purple, staggered 0.6s) above
 * a scrolling amber ECG waveform with anatomically correct PQRST
 * morphology. Replaces the generic skeleton blocks and three-dot
 * spinners that used to appear during page-load / data fetches.
 *
 * Markup (built by loaderHtml() in app/js/loader.js):
 *   <div class="sv-loader [sv-loader-sm]">
 *     <div class="sv-loader-stage">
 *       <div class="sv-loader-heart-wrap">
 *         <span class="sv-loader-ring"></span> ×3
 *         <svg class="sv-loader-heart">...</svg>
 *       </div>
 *       <svg class="sv-loader-ekg">...</svg>
 *     </div>
 *     <p class="sv-loader-msg">Loading…</p>
 *   </div>
 *
 * Three sizes via modifier classes:
 *   default    — full-page (heart 36px, ECG 220×60)
 *   sv-loader-sm — modal/card (heart 24px, ECG 140×40, no message)
 *   sv-loader-lg — splash (heart 48px, ECG 280×80)
 *
 * Honors prefers-reduced-motion: animations stripped, static heart +
 * full ECG line + accessible "Loading" text remain.
 */
.sv-loader {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px 16px;
  width: 100%;
}
.sv-loader-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.sv-loader-heart-wrap {
  position: relative;
  width: 64px; height: 64px;
  display: flex; align-items: center; justify-content: center;
}
.sv-loader-heart-wrap > svg.sv-loader-heart {
  position: relative;
  z-index: 3;
  width: 36px; height: 36px;
  color: #E24B4A;
  animation: sv-loader-pulse 1.4s ease-in-out infinite;
  transform-origin: center;
}
.sv-loader-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2.5px solid;
  z-index: 2;
  animation: sv-loader-ring 2s ease-out infinite;
  transform-origin: center;
  pointer-events: none;
}
.sv-loader-ring:nth-of-type(1) { border-color: #85B7EB; animation-delay: 0s;   }
.sv-loader-ring:nth-of-type(2) { border-color: #5DCAA5; animation-delay: 0.6s; }
.sv-loader-ring:nth-of-type(3) { border-color: #AFA9EC; animation-delay: 1.2s; }

.sv-loader-ekg {
  width: 220px; height: 60px;
  display: block;
}
.sv-loader-ekg path:not(.sv-loader-baseline) {
  fill: none;
  stroke: #BA7517;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 280;
  animation: sv-loader-ekg 2s linear infinite;
}
.sv-loader-ekg .sv-loader-baseline {
  fill: none;
  stroke: var(--border, var(--lp-line, #e2e8f0));
  stroke-width: 1;
  opacity: 0.6;
}

.sv-loader-msg {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--text-dim, var(--muted));
  text-align: center;
  letter-spacing: 0.01em;
  max-width: 36ch;
  line-height: 1.5;
}

/* Small variant — for inline / card-sized contexts. Heart shrinks to
   24px, ring zone shrinks proportionally, ECG narrows to 140×40, and
   the message is hidden (caller can supply none). */
.sv-loader.sv-loader-sm { padding: 14px 8px; gap: 10px; }
.sv-loader.sv-loader-sm .sv-loader-heart-wrap { width: 44px; height: 44px; }
.sv-loader.sv-loader-sm .sv-loader-heart-wrap > svg.sv-loader-heart { width: 24px; height: 24px; }
.sv-loader.sv-loader-sm .sv-loader-ring { border-width: 2px; }
.sv-loader.sv-loader-sm .sv-loader-ekg { width: 140px; height: 40px; }
.sv-loader.sv-loader-sm .sv-loader-msg { font-size: 12px; }

/* Large variant — for splash / first-paint contexts. */
.sv-loader.sv-loader-lg { padding: 36px 16px; gap: 18px; }
.sv-loader.sv-loader-lg .sv-loader-heart-wrap { width: 80px; height: 80px; }
.sv-loader.sv-loader-lg .sv-loader-heart-wrap > svg.sv-loader-heart { width: 48px; height: 48px; }
.sv-loader.sv-loader-lg .sv-loader-ekg { width: 280px; height: 80px; }
.sv-loader.sv-loader-lg .sv-loader-msg { font-size: 14px; }

@keyframes sv-loader-pulse {
  0%, 100% { transform: scale(1); }
  10%      { transform: scale(1.18); }
  20%      { transform: scale(1); }
  30%      { transform: scale(1.14); }
  40%      { transform: scale(1); }
}
@keyframes sv-loader-ring {
  0%   { transform: scale(0.45); opacity: 0.7; }
  100% { transform: scale(2.4); opacity: 0; }
}
@keyframes sv-loader-ekg {
  0%   { stroke-dashoffset: 280; }
  100% { stroke-dashoffset: -280; }
}

@media (prefers-reduced-motion: reduce) {
  .sv-loader-heart-wrap > svg.sv-loader-heart,
  .sv-loader-ring,
  .sv-loader-ekg path:not(.sv-loader-baseline) {
    animation: none;
  }
  .sv-loader-ekg path:not(.sv-loader-baseline) {
    /* Show the full waveform statically when motion is off. */
    stroke-dasharray: none;
  }
}

/* ─── Practice/Flashcards filter redesign (A+C) ────────────────────────
 * The customize panel was a wall of ~70 chips with equal-weight
 * fieldsets. This block restyles it into a hierarchical, search-first
 * picker:
 *   1. Suggested-for-you row (top)        — weak-areas quick picks
 *   2. "What animal?" pill row             — Species + Group merged
 *   3. Subject section with search input   — primary subjects visible,
 *                                            compound under expander
 *   4. "More options" sub-collapsible      — Images / Deck size / Picker
 *
 * Selectors are scoped to `.filters-redesigned` (practice) and
 * `.fc-setup` (flashcards) so the older surfaces (exam, etc.) keep
 * their existing chip styling unchanged.
 */

/* Section spacing — tighter than the old fieldset rhythm. */
.filters-redesigned fieldset { margin: 0 0 18px; }
.filters-redesigned legend {
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: 10px;
  letter-spacing: .02em;
  font-size: var(--text-base);
}

/* ── Suggested-for-you row ──────────────────────────────────────────── */
.filter-suggested {
  background: var(--primary-soft, rgba(14, 165, 163, 0.10));
  border: 1px solid color-mix(in srgb, var(--primary) 25%, transparent);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  margin-bottom: 18px;
}
.filter-suggested legend {
  color: var(--primary, var(--primary-deep));
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: var(--text-xs);
  margin-bottom: 8px;
}
.suggested-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.suggested-chip {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid color-mix(in srgb, var(--primary) 35%, transparent);
  background: var(--surface);
  color: var(--ink);
  padding: 7px 14px;
  border-radius: 999px;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1)),
              border-color var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1)),
              color var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1)),
              transform var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.suggested-chip:hover {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 8%, var(--surface));
  transform: translateY(-1px);
}
.suggested-chip.is-on {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
  box-shadow: 0 2px 6px rgba(14, 165, 163, .25);
}

/* ── What animal? — pill row ────────────────────────────────────────── */
.filter-animal { /* container */ }
.animal-pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}
.animal-pill {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--border, rgba(148, 163, 184, 0.30));
  background: var(--surface);
  color: var(--text-dim);
  padding: 9px 16px;
  border-radius: 999px;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: all var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.animal-pill:hover {
  color: var(--ink);
  border-color: var(--border-strong, rgba(148, 163, 184, 0.55));
}
.animal-pill.is-on {
  background: var(--primary);
  color: #ffffff;
  border-color: var(--primary);
  box-shadow: 0 2px 6px rgba(14, 165, 163, .22);
}
.hidden-checks { display: none; }

/* ── Filter detail (collapsible "Specific species" / "Show all") ────── */
.filter-detail {
  margin-top: 10px;
}
.filter-detail-summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: var(--text-sm);
  color: var(--text-dim);
  font-weight: 500;
  transition: background var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1)),
              color var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.filter-detail-summary:hover {
  color: var(--ink);
  background: var(--surface-2, rgba(148, 163, 184, 0.10));
}
.filter-detail-summary::-webkit-details-marker { display: none; }
.filter-detail-summary::marker { content: ""; }
.filter-detail[open] > .filter-detail-summary {
  color: var(--ink);
  margin-bottom: 8px;
}
.filter-detail .chips,
.filter-detail .fc-chips {
  margin-top: 6px;
}

/* ── Subject section: search-first picker ───────────────────────────── */
.filter-subject .subject-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  margin-bottom: 12px;
  max-width: 520px;
}
.subject-search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 14px;
  pointer-events: none;
  opacity: .65;
}
.subject-search {
  flex: 1 1 auto;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--border, rgba(148, 163, 184, 0.30));
  background: var(--surface);
  color: var(--ink);
  padding: 10px 38px 10px 38px;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--text-base);
  transition: border-color var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1)),
              box-shadow var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.subject-search:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(14, 165, 163, .20);
}
.subject-search::-webkit-search-cancel-button { display: none; }
.subject-search-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  appearance: none;
  border: none;
  background: var(--surface-2, rgba(148, 163, 184, 0.15));
  color: var(--text-dim);
  width: 24px; height: 24px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  display: grid;
  place-items: center;
  transition: background var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.subject-search-clear:hover {
  background: var(--border, rgba(148, 163, 184, 0.40));
  color: var(--ink);
}
.filter-subject-count {
  margin-left: 8px;
  color: var(--primary-dark, #0f766e);
  font-weight: 600;
}
.subject-empty {
  margin: 12px 0 0;
  padding: 10px 14px;
  background: var(--surface-2, rgba(148, 163, 184, 0.08));
  border: 1px dashed var(--border, rgba(148, 163, 184, 0.30));
  border-radius: var(--radius-sm);
  text-align: center;
}

/* Visibility class used by the subject search to hide non-matching
   chips while keeping their underlying inputs in the form. */
.chip-pick.is-hidden,
.fc-chip.is-hidden { display: none; }

/* ── More options (collapsible secondary settings) ──────────────────── */
.filter-more {
  margin-top: 4px;
  border-top: 1px dashed var(--border, rgba(148, 163, 184, 0.30));
  padding-top: 14px;
}
.filter-more-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  transition: background var(--dur-1, 120ms) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.filter-more-summary:hover {
  background: var(--surface-2, rgba(148, 163, 184, 0.10));
}
.filter-more-summary::-webkit-details-marker { display: none; }
.filter-more-summary::marker { content: ""; }
.filter-more-summary-label {
  font-weight: 600;
  color: var(--ink);
  font-size: var(--text-base);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.filter-more-summary-label::before {
  content: "⌄";
  display: inline-block;
  transition: transform var(--dur-2, 220ms) var(--ease, cubic-bezier(.2,.8,.2,1));
  color: var(--text-dim);
}
.filter-more[open] .filter-more-summary-label::before {
  transform: rotate(180deg);
}
.filter-more-summary-line {
  font-style: normal;
}
.filter-more[open] .filter-more-summary-line {
  display: none;
}
.filter-more > fieldset {
  margin-top: 14px;
  padding-left: 4px;
}

/* ── Flashcards-specific overrides ──────────────────────────────────── */
/* The flashcards setup uses .fc-chip not .chip-pick — same redesign
   applies, just to the fc-* selectors. */
.fc-setup .filter-detail .fc-chips { margin-top: 6px; }
.fc-setup .subject-search-wrap { max-width: 520px; }


/* ────────────────────────────────────────────────────────────────────
 * Swipable "do this next" hero carousel on /home.
 *
 * Sits between the greeting hero and the existing stat-grid as an
 * additive layer; doesn't replace anything. CSS scroll-snap drives the
 * actual swipe (native inertia + snap stops on iOS/Android); home.js
 * just listens for scroll to keep the dot in sync and reacts to dot
 * clicks + arrow keys.
 *
 * All selectors prefixed `.hf-*` so nothing leaks into other surfaces.
 * ──────────────────────────────────────────────────────────────────── */
.hf-hero-wrap {
  position: relative;
  margin: 0;
}
.hf-hero-carousel {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  outline: none;
  padding: 2px;
}
.hf-hero-carousel::-webkit-scrollbar { display: none; }

/* Slide width: 2-up on desktop (≥601px), 1-up + peek on mobile.
   - Desktop: `calc(50% - 6px)` — exactly two tiles fit per scroll
     view (the 12px gap between them is split 6px each side). Snap-
     per-tile still works; the dot count = tile count, and as the
     user swipes the next tile slides into view.
   - Mobile: `calc(100% - 36px)` — one tile + ~24px peek of the next,
     since 2-up at 360px viewports leaves each tile too cramped.
   The mobile width is set in the @media block further down. */
.hf-hero-slide {
  flex: 0 0 calc(50% - 6px);
  scroll-snap-align: start;
  scroll-snap-stop: always;
  background: var(--surface, var(--glass-weak));
  border: 1px solid var(--border, var(--glass-border));
  border-radius: var(--radius-lg, 20px);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  opacity: 0.7;
  transition: opacity var(--dur-2, 220ms) var(--ease, ease);
}
.hf-hero-slide.is-active { opacity: 1; }

.hf-hero-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.hf-hero-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  border-radius: 8px;
  background: var(--glass-weak);
  flex-shrink: 0;
}
.hf-hero-icon i { font-size: 16px; line-height: 1; }
.hf-hero-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim, var(--muted));
}

/* Coach / Today type-tag chip — small label on each slide so the user
   knows whether the slide is a personalised observation (Coach) or
   educational content of the day (Today). Sits on the right edge of
   the slide head, opposite the icon. Colour matches the slide's
   accent ramp so it reads as "part of this card." */
.hf-hero-type-tag {
  margin-left: auto;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 999px;
  line-height: 1.4;
  white-space: nowrap;
  flex-shrink: 0;
}
.hf-type-coach { background: rgba(15, 110, 86, 0.16); color: #04342C; }
.hf-type-today { background: rgba(60, 52, 137, 0.16); color: #26215C; }
.hf-hero-title {
  font-size: 15px;
  font-weight: 600;
  margin: 2px 0 0;
  line-height: 1.25;
  color: var(--ink, var(--text));
  /* Cap title at two lines so a long question (e.g. "Review queue ·
     1,234 cards due") can't make the tile balloon. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hf-hero-sub {
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-dim, var(--muted));
  /* Two-line clamp for the same reason as title. Keeps mobile tile
     height predictable regardless of copy length. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Today slides (term-of-the-day, did-you-know fact) have long bodies
   (120–180 chars) but no CTA — they should use the vertical room the
   action row would have taken and clamp at 5 lines instead of 2.
   Slightly smaller font + tighter leading on mobile so the whole
   definition / fact fits without ellipsis. Coach slides keep the
   tight 2-line clamp since their copy is short and the CTA needs
   room. */
.hf-hero-slide[data-kind="today"] .hf-hero-sub {
  font-size: 11.5px;
  line-height: 1.45;
  -webkit-line-clamp: 5;
}
.hf-hero-slide[data-kind="today"] .hf-hero-title {
  -webkit-line-clamp: 1;
  font-size: 14.5px;
}
.hf-hero-actions {
  margin-top: auto;
  padding-top: 6px;
}
.hf-hero-cta {
  display: inline-flex;
  align-items: center;
  background: var(--primary, #0ea5a3);
  color: #fff;
  font-size: 12.5px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 8px;
  text-decoration: none;
  transition: background var(--dur-1, 150ms) var(--ease, ease), transform var(--dur-1, 150ms) var(--ease, ease);
}
.hf-hero-cta:hover { transform: translateY(-1px); }
.hf-hero-cta:active { transform: translateY(0); }

/* Per-color slide tints. Each picks a faint surface fill + saturated
   border + matching CTA. Falls back to neutral surface if data-color
   is absent or unknown. */
.hf-hero-slide[data-color="teal"]   { background: rgba(20,184,166,0.10);  border-color: rgba(20,184,166,0.32); }
.hf-hero-slide[data-color="teal"]   .hf-hero-icon { background: rgba(20,184,166,0.18); color: #0F6E56; }
.hf-hero-slide[data-color="teal"]   .hf-hero-cta  { background: #0F6E56; }

.hf-hero-slide[data-color="coral"]  { background: rgba(216,90,48,0.10);   border-color: rgba(216,90,48,0.32); }
.hf-hero-slide[data-color="coral"]  .hf-hero-icon { background: rgba(216,90,48,0.18); color: #993C1D; }
.hf-hero-slide[data-color="coral"]  .hf-hero-cta  { background: #993C1D; }

.hf-hero-slide[data-color="blue"]   { background: rgba(55,138,221,0.10);  border-color: rgba(55,138,221,0.32); }
.hf-hero-slide[data-color="blue"]   .hf-hero-icon { background: rgba(55,138,221,0.18); color: #185FA5; }
.hf-hero-slide[data-color="blue"]   .hf-hero-cta  { background: #185FA5; }

.hf-hero-slide[data-color="purple"] { background: rgba(127,119,221,0.12); border-color: rgba(127,119,221,0.32); }
.hf-hero-slide[data-color="purple"] .hf-hero-icon { background: rgba(127,119,221,0.18); color: #3C3489; }
.hf-hero-slide[data-color="purple"] .hf-hero-cta  { background: #534AB7; }

.hf-hero-slide[data-color="amber"]  { background: rgba(239,159,39,0.12);  border-color: rgba(239,159,39,0.40); }
.hf-hero-slide[data-color="amber"]  .hf-hero-icon { background: rgba(239,159,39,0.20); color: #854F0B; }
.hf-hero-slide[data-color="amber"]  .hf-hero-cta  { background: #854F0B; }

/* Dot indicators below the carousel. Active dot widens 8px → 22px. */
.hf-hero-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin: 12px 0 0;
}
.hf-dot {
  width: 8px; height: 4px;
  padding: 0;
  border: none;
  border-radius: 2px;
  background: var(--border-strong, var(--border, rgba(148,163,184,0.45)));
  cursor: pointer;
  transition: width var(--dur-1, 150ms) var(--ease, ease),
              background var(--dur-1, 150ms) var(--ease, ease);
}
.hf-dot.is-on {
  width: 22px;
  background: var(--ink, var(--text));
}
.hf-dot:focus-visible { outline: 2px solid var(--primary, #0ea5a3); outline-offset: 2px; }

/* Mobile tuning. At ≤600px the 2-up width gives each tile <300px which
   is too cramped for the title + description + CTA layout. Drop to 1-up
   with a slight peek of the next tile so the swipeability is still
   visible, and shrink the title size a touch more so two-line titles
   read comfortably on narrow viewports. */
@media (max-width: 600px) {
  .hf-hero-slide {
    flex: 0 0 calc(100% - 36px);
    padding: 10px 12px;
    gap: 4px;
  }
  .hf-hero-title { font-size: 14px; }
  .hf-hero-sub   { font-size: 11.5px; }
  .hf-hero-cta   { font-size: 12px; padding: 6px 11px; }

  /* Today slides on mobile — push the body font down + open up the
     line-clamp so a full term definition / fact body fits without
     ellipsis. Title goes a touch smaller too so long terms like
     "Polyuria/polydipsia" don't wrap. */
  .hf-hero-slide[data-kind="today"] .hf-hero-title { font-size: 13.5px; }
  .hf-hero-slide[data-kind="today"] .hf-hero-sub {
    font-size: 11px;
    line-height: 1.4;
    -webkit-line-clamp: 6;
  }
}

/* ────────────────────────────────────────────────────────────────────
 * Practice page filter tweaks (user request):
 *  - Subject section is now a <details> (collapsed by default).
 *  - More options is flat (no <details> wrapper) — all three fieldsets
 *    visible at all times.
 * ──────────────────────────────────────────────────────────────────── */

/* Subject details summary — clickable row that toggles the chip cloud. */
.filter-subject-collapsed > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  margin: 0 0 8px;
  background: var(--surface-2, var(--glass-weak));
  border: 1px solid var(--border, var(--glass-border));
  border-radius: 10px;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink, var(--text));
  user-select: none;
  transition: background var(--dur-1, 150ms) var(--ease, ease);
}
.filter-subject-collapsed > summary:hover {
  background: var(--surface, var(--glass-weak));
}
.filter-subject-collapsed > summary::-webkit-details-marker { display: none; }
.filter-subject-collapsed > summary::marker { content: ""; }

.filter-subject-summary-label {
  flex: 1;
  min-width: 0;
}
.filter-subject-chev {
  display: inline-flex;
  font-size: 16px;
  color: var(--text-dim, var(--muted));
  transition: transform var(--dur-1, 150ms) var(--ease, ea


/* ────────────────────────────────────────────────────────────────────
 * Dashboard chart upgrades:
 *  - Radar target ring (variant N): dashed 70% pass-line overlay +
 *    callout list of subjects below it.
 *  - Pipeline mosaic card (variant E5r-c): hero stat block + reversed
 *    dot mosaic where coloured progress dots come first.
 * ──────────────────────────────────────────────────────────────────── */

/* Dashed dark-red polygon drawn between the standard rings and the
   value polygon — the 70% pass-line. Same geometry as the rings
   (polygon, not circle) so it shares the radar's grid lines. Was
   amber #BA7517; switched to coral-900 #993C1D to match the mockup
   and to share the same red family as the below-70% labels +
   homework-list "weak" dots. */
.radar-target {
  fill: none !important;
  stroke: #993C1D !important;
  stroke-width: 1.4;
  stroke-dasharray: 4 3;
  pointer-events: none;
}

/* Callout list below the radar — replaces the old foot caption when
   any subject sits below 70%. Each chip pairs a coloured tier dot
   (red = weak <55%, amber = watch 55-70%) with the subject name + %. */
.radar-target-callout {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border, var(--glass-border));
}
.radar-target-callout-head {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim, var(--muted));
  margin: 0 0 8px;
}
.radar-target-callout-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.radar-target-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  background: var(--glass-weak);
  border: 1px solid var(--border, var(--glass-border));
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}
.radar-target-chip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.radar-target-chip-dot[data-tier="weak"]  { background: #E24B4A; }
.radar-target-chip-dot[data-tier="watch"] { background: #EF9F27; }
.radar-target-chip-name {
  color: var(--ink, var(--text));
  font-weight: 600;
}
.radar-target-chip-pct {
  color: var(--text-dim, var(--muted));
  font-variant-numeric: tabular-nums;
  font-size: 11.5px;
}
.radar-foot { /* unchanged when no callout is shown */ }

/* ─── Pipeline mosaic card ────────────────────────────────────────── */
.mosaic-card { display: flex; flex-direction: column; gap: 14px; }
.mosaic-head h3 { margin: 0; }
.mosaic-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: stretch;
  min-width: 0;
}
/* Hero capped to 220px so it doesn't hog horizontal space — the dot
   mosaic is the headline visual and should fill the rest of the card. */
.mosaic-grid > .mosaic-hero { flex: 0 1 200px; max-width: 220px; }
.mosaic-grid > .mosaic-dots { flex: 1 1 320px; min-width: 0; }

/* Hero block (left column) */
.mosaic-hero {
  background: var(--surface, var(--glass-weak));
  border: 1px solid var(--border, var(--glass-border));
  border-radius: 10px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 140px;
}
.mosaic-hero-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim, var(--muted));
  margin: 0 0 4px;
}
.mosaic-hero-num {
  font-size: 32px;
  font-weight: 600;
  margin: 0;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink, var(--text));
}
.mosaic-hero-sub {
  font-size: 11.5px;
  color: var(--text-dim, var(--muted));
  margin: 4px 0 12px;
}
.mosaic-hero-foot {
  font-size: 11px;
  color: var(--text-dim, var(--muted));
  margin: 10px 0 0;
}

/* Thin proportion bar inside the hero block — five horizontal slivers,
   each tier coloured to match the dots. */
.mosaic-proportion {
  display: flex;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
  gap: 1px;
  background: transparent;
}
.mosaic-proportion > span {
  display: block;
  height: 100%;
  min-width: 0;
}

/* Dot grid (right column). 24 columns × ~12 rows = ~288 cells; with
   ~300 dots the grid wraps cleanly. aspect-ratio 1 keeps every dot a
   perfect circle regardless of container width. */
.mosaic-dots {
  display: grid;
  /* 24 columns @ ~14px each fills the dots column when hero is capped
     at 220px on typical desktop widths. The minmax(0, 1fr) variant
     stops grid items from forcing a width floor. */
  grid-template-columns: repeat(24, minmax(0, 1fr));
  gap: 3px;
  padding: 4px;
  align-content: start;
  min-height: 140px;
  min-width: 0;
}
.mosaic-dot {
  /* min-height kept tiny so aspect-ratio:1 doesn't propagate a width
     floor large enough to overflow narrow containers. */
  aspect-ratio: 1;
  min-height: 4px;
  width: 100%;
  min-width: 0;
  border-radius: 50%;
  display: block;
}

/* Legend row below the grid */
.mosaic-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border, var(--glass-border));
  font-size: 11.5px;
  color: var(--text-dim, var(--muted));
}
.mosaic-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-variant-numeric: tabular-nums;
}
.mosaic-legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
}

/* Mosaic mastery-help — collapsible explainer under the legend. Default
   <details> marker is hidden in favour of our own chevron so the open/closed
   affordance lives on the right edge, matching FAQ-style toggles elsewhere. */
.mosaic-help > summary { list-style: none; }
.mosaic-help > summary::-webkit-details-marker { display: none; }
.mosaic-help > summary { outline: none; }
.mosaic-help > summary:focus-visible {
  outline: 2px solid var(--accent, #1D9E75);
  outline-offset: 3px;
  border-radius: 4px;
}
.mosaic-help .mosaic-help-chev {
  transition: transform 0.18s ease;
  display: inline-block;
}
.mosaic-help[open] .mosaic-help-chev { transform: rotate(180deg); }
.mosaic-help-body ul li { margin: 3px 0; }

/* Mobile — flexbox wraps the hero on top of the dots automatically when
   there isn't room for both. The dot grid stays at 20 cols on normal
   phones, drops to 16 on very narrow screens so each dot stays visible
   without forcing a minimum width that overflows. */
@media (max-width: 420px) {
  .mosaic-dots { grid-template-columns: repeat(16, minmax(0, 1fr)) !important; }
}


/* ────────────────────────────────────────────────────────────────────
 * Mastery vs 70% target radar — exact mockup match for variant N.
 *
 *  Layout: 2-column grid; SVG radar on the left, callout "side panel"
 *  on the right with the homework list + a black "Drill weak" CTA.
 *  Below-target axis labels (the names around the radar perimeter)
 *  get a red colour treatment so the homework subjects are also
 *  visually flagged on the chart itself.
 * ──────────────────────────────────────────────────────────────────── */

.radar-card .radar-head h3 {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 600;
}
.radar-card .radar-sub {
  margin: 0 0 12px;
  font-size: 12.5px;
  line-height: 1.4;
}
.radar-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
}
.radar-grid > .radar-svg { flex: 1 1 240px; min-width: 0; }
.radar-grid > .radar-side { flex: 1 1 200px; min-width: 0; }
.radar-card .radar-svg {
  width: 100%;
  max-width: 320px;
  height: auto;
  display: block;
  margin: 0 auto;
}

/* Below-target axis labels — coloured darker red so the names around
   the perimeter call themselves out alongside the side-panel list. */
.radar-label-weak {
  fill: #993C1D;
  font-weight: 600;
}

/* Side panel (right column) */
.radar-side {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 4px;
}
.radar-side-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim, var(--muted));
  margin: 0 0 4px;
}
.radar-side-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.radar-side-list li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink, var(--text));
}
.radar-side-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
}
.radar-side-dot[data-tier="weak"]  { background: #E24B4A; }
.radar


/* Growth-curve projection footer (GC2). Sits below the chart with a
   thin top border. Uses tabular numerals for the milestone count. */
.growth-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border, var(--glass-border));
  font-size: 12.5px;
  color: var(--text-dim, var(--muted));
  font-variant-numeric: tabular-nums;
}
.growth-projection {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.growth-projection strong {
  font-weight: 600;
  color: var(--ink, var(--text));
}
.growth-projection.muted strong { color: var(--text-dim, var(--muted)); }

