/* ============================================================================
   PLATFORM DESIGN SYSTEM — the V2 ("path composer v2") aesthetic, rolled out as
   the design language of the WHOLE /app. The V2 system (extracted from
   _proto/path-composer-v2.html) is:
     • a COOL neutral base — cool near-white page, white cards, a cool-slate ink
       ramp, cool hairlines (NO warm cream / beige anywhere)
     • FLAT coral accents only (#DA7756 / #B8553A / #a8472a / #E8A488), ZERO
       gradients — depth comes from refined, cool-tinted layered SHADOWS
     • Plus Jakarta Sans (headings + UI) + JetBrains Mono (eyebrows / ids),
       loaded from Google Fonts
     • the Emil easing tokens (--ease-out / --ease-move; transform + opacity only)
     • reusable card + flat cover-tile primitives, named generically so the rest
       of /app + the future composer reuse them
   WCAG 2.2 AA throughout (small coral text → #a8472a; visible focus rings;
   reduced-motion guards). The existing custom-property NAMES other files depend
   on are PRESERVED — only their VALUES move to V2 (plus net-new V2 tokens).
   ============================================================================ */
/* V2 webfonts: Plus Jakarta Sans (modern geometric) display + UI; JetBrains Mono
   for eyebrows / ids. Loaded here because platform.css is the one CSS every /app
   surface pulls (app.html loads it first); @import keeps the load in the file we
   own without touching the shell HTML. */
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
/* The `hidden` attribute must always win, even over components that set display:flex/grid
   (otherwise a [hidden] panel like the purchase-success banner shows on every page load). */
[hidden] { display: none !important; }

:root {
  /* ── coral family — used as FLAT accents only (no gradients, ever) ── */
  --coral: #DA7756;
  --coral-deep: #B8553A;        /* button fill — AA on white behind white label (4.77:1) */
  --coral-soft: #E8A488;        /* soft coral for dark covers */
  --coral-text: #a8472a;        /* small coral text on white → AA */
  --coral-tint: #fcefe9;        /* faint cool-leaning coral fill */
  --coral-tint2: #f8e2d8;       /* a touch deeper, still flat */
  --coral-light: rgba(218,119,86,0.08);
  --coral-wash: rgba(218,119,86,0.07);
  --coral-line: rgba(218,119,86,0.26);

  /* ── COOL neutral surfaces — near-white + cool grays (NOT cream / beige) ── */
  --ink: #1a1f2e;               /* cool-slate near-black */
  --ink-2: #404a5c;
  --ink-3: #5b6678;
  --ink-4: #8a93a6;             /* faintest cool ink (mono eyebrows / meta) */
  --bg: #ffffff;                /* white card surface */
  --bg-2: #f6f8fb;              /* cool near-white page ground */
  --bg-3: #eef1f6;              /* cool recessed fill (tabs / pills) */
  --card-2: #fbfcfe;            /* faint cool card alt */
  --border: #e7ebf0;            /* cool hairline */
  --border-strong: #dfe3ea;
  /* dark cover tones — flat slate / ink (covers fill flat, never a gradient) */
  --cover-1: #2f3850;
  --cover-2: #232a3a;
  --cover-3: #1a2030;
  /* ── fonts — Plus Jakarta Sans (UI + headings), JetBrains Mono (eyebrows) ── */
  --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  /* --font-serif is RETIRED in look (V2 has no book serif) but kept as a NAME so
     existing rules that reference it don't break; it now resolves to the V2 UI
     font so any heading still using it reads as Plus Jakarta, never a serif. */
  --font-serif: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Consolas, monospace;
  /* refined, COOL-tinted layered shadows — premium depth, no glow, no gradient */
  --shadow-1: 0 1px 2px rgba(20,28,48,0.05), 0 1px 3px rgba(20,28,48,0.07);
  --shadow-2: 0 2px 5px rgba(20,28,48,0.06), 0 6px 16px rgba(20,28,48,0.09);
  --shadow-3: 0 8px 20px rgba(20,28,48,0.10), 0 18px 44px rgba(20,28,48,0.13);
  --shadow-coral: 0 4px 14px rgba(184,85,58,0.22);
  /* ── motion (Emil) — transform + opacity only ── */
  --ease: cubic-bezier(0.23, 1, 0.32, 1);         /* legacy name kept; now the V2 ease-out */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);     /* enter / exit */
  --ease-move: cubic-bezier(0.77, 0, 0.175, 1);   /* moves / reorders */

  /* ════════════════════════════════════════════════════════════════════════
     STYLE ENGINE — the ORTHOGONAL "data-style" axis (Felipe 2026-05-31:
     "it's not only colors… different STYLE, the way buttons are… minimal,
     squary, soft, different vibes"). A STYLE changes the SHAPE / FEEL of every
     component — corner radius, shadow depth, density (padding/gap), and border
     treatment — WITHOUT touching color/ink/accent (those stay on the theme +
     accent layers). Any style × any color theme × any font × any accent.
     The DEFAULT values below ARE the "Default" style (the current V2 look);
     html[data-style="minimal|squary|soft"] override them further down. Every
     /app component routes its shape props through these tokens, so flipping
     data-style re-shapes the whole /app instantly (CSS only, no re-render).
     ──────────────────────────────────────────────────────────────────────── */
  /* RADII — the card/button/container corner ramp (pill radii stay 999px, never
     style-driven). xs→lg are what flex per style. */
  --radius-xs: 7px;             /* tiny chips / small tiles / icon squares */
  --radius-sm: 10px;            /* buttons / inputs / small cards */
  --radius: 14px;               /* the standard card / row / tile */
  --radius-lg: 18px;            /* big cards / panes / modals */
  --radius-xl: 22px;            /* the largest surfaces (composer modal) */
  --radius-pill: 999px;         /* fully-round (bars/chips/dots) — constant */
  /* SHADOW DEPTH — the per-theme shadow values live in :root + each theme bundle
     below (light vs dark tuned). The style layer OVERRIDES --shadow-1/2/3 to go
     flatter (minimal/squary) or softer (soft); dark themes carry a style-scoped
     refinement so a flat/soft style still reads right on a dark surface. */
  /* DENSITY — the card padding + grid gap scale. Default = comfortable; minimal/
     squary tighten, soft loosens. Routed through the highest-impact paddings. */
  --pad-card: 18px;             /* the standard card inner padding */
  --pad-card-sm: 15px;          /* tighter cards (tiles / playlist rows) */
  --pad-card-lg: 22px;          /* roomier cards (path summary / empty states) */
  --gap-card: 12px;             /* the inter-card grid gap */
  /* BORDER TREATMENT — hairline (minimal) ↔ standard ↔ crisp (squary). Components
     that want the style's border weight read --border-weight (default 1px). */
  --border-weight: 1px;

  /* ════════════════════════════════════════════════════════════════════════
     THEME ENGINE — the ACCENT layer. Every coral-derived token is re-expressed
     in terms of an --accent / --accent-deep pair so the ACCENT picker can swap
     the one claim-bearing hue WITHOUT touching surfaces or ink. The default
     accent IS coral; the picker sets --accent / --accent-deep / --accent-text /
     --accent-soft inline on <html> (data-accent) and the families below follow.
     Each theme bundle (html[data-theme=...]) overrides surfaces + ink + accent
     defaults so accent + surface stay AA together. (See APP-THEME-SYSTEM doc.)
     ──────────────────────────────────────────────────────────────────────── */
  /* The accent family holds the LITERAL default-coral values (NOT references to
     --coral*, which would create a cycle once --coral* alias back to --accent*).
     The picker overrides these inline; the themes override them per-bundle. */
  --accent: #DA7756;
  --accent-deep: #B8553A;               /* button fill — AA on the theme surface */
  --accent-text: #a8472a;               /* small accent text on surface — AA */
  --accent-soft: #E8A488;               /* soft accent on dark covers */
  /* Account-menu tokens (account-menu.js reads var(--acct-*, literal) so it
     themes inside /app but keeps its literal look on the R2 book where these are
     undefined). Default = light. */
  --acct-surface: #fff;
  --acct-ink: #1a1a1a;
  --acct-ink-2: #43474f;
  --acct-ink-3: #5a5f67;
  --acct-border: #e6e6ea;
  --acct-tint: #fdf3ee;
}

/* ════════════════════════════════════════════════════════════════════════════
   THE 6 PRESET BUNDLES. Each redefines surfaces + ink + accent defaults; the
   accent FAMILY tokens (--coral* used everywhere) are re-pointed at --accent* so
   one set of overrides re-themes the whole /app. All AA-verified (text ≥4.5:1,
   UI ≥3:1) on the theme's surface. Applied via html[data-theme="..."] set by the
   no-FOUC head script + theme.js BEFORE first paint.
   Re-point the coral family → accent family in EVERY theme (incl. default) so the
   ACCENT picker reaches every coral-named rule across /app.
   ════════════════════════════════════════════════════════════════════════════ */
/* coral family aliases → accent family (so an accent swap re-themes everything
   that still names --coral*). Default accent = coral, so this is a no-op look.
   MUST be :root (not html) — :root has higher specificity than html, so an
   `html` rule here would lose to the literal --coral* defs in the :root above.
   A later :root with equal specificity wins by source order. */
:root {
  --coral: var(--accent);
  --coral-deep: var(--accent-deep);
  --coral-text: var(--accent-text);
  --coral-soft: var(--accent-soft);
}

/* DARK — TRUE NEUTRAL charcoal/gray (R≈G≈B, zero blue cast), light gray ink,
   accent tuned AA on dark. Felipe: night/gray/black, NEVER blue or navy. */
html[data-theme="dark"] {
  --ink: #ededed;            /* near-white neutral ink */
  --ink-2: #b5b5b5;
  --ink-3: #8a8a8a;
  --ink-4: #7d7d7d;          /* faint neutral ink — AA (4.6:1) on the dark page */
  --bg: #1c1c1c;             /* card surface (neutral charcoal) */
  --bg-2: #121212;           /* page ground (darker than cards) */
  --bg-3: #222222;           /* recessed fill (tabs / pills) */
  --card-2: #161616;
  --border: #2c2c2c;
  --border-strong: #333333;
  --cover-1: #3a3a3a;        /* neutral dark cover tiles (no navy) */
  --cover-2: #2a2a2a;
  --cover-3: #202020;
  /* accent on dark: a brighter coral keeps AA on the dark surfaces; deep + text
     lift to clear 4.5:1 on #1c1c1c / #121212. The accent is the ONLY hue. */
  --accent: #e98a67;         /* bright coral for bars / borders / non-text accents */
  --accent-deep: #b85a3c;    /* button fill — white label is AA (4.6:1) */
  --accent-text: #f0a079;    /* accent text on dark surface — AA (7.6:1) */
  --accent-soft: #f0a888;
  --coral-tint: #2e2620;     /* faint warm-dark accent fill */
  --coral-tint2: #3a2c23;
  --coral-light: rgba(233,138,103,0.16);
  --coral-wash: rgba(233,138,103,0.12);
  --coral-line: rgba(233,138,103,0.34);
  --shadow-1: 0 1px 2px rgba(0,0,0,0.30), 0 1px 3px rgba(0,0,0,0.36);
  --shadow-2: 0 2px 6px rgba(0,0,0,0.34), 0 8px 20px rgba(0,0,0,0.42);
  --shadow-3: 0 10px 26px rgba(0,0,0,0.46), 0 20px 50px rgba(0,0,0,0.55);
  --shadow-coral: 0 4px 14px rgba(0,0,0,0.40);
  /* account menu themed for dark (neutral) */
  --acct-surface: #161616;
  --acct-ink: #ededed;
  --acct-ink-2: #b5b5b5;
  --acct-ink-3: #8a8a8a;
  --acct-border: #2c2c2c;
  --acct-tint: #2e2620;
}

/* MIDNIGHT — TRUE BLACK theme: near-pure-black neutral (R≈G≈B, zero blue cast),
   a slightly brighter accent (richer dark). Felipe: black, NEVER indigo/navy. */
html[data-theme="midnight"] {
  --ink: #f0f0f0;
  --ink-2: #b8b8b8;
  --ink-3: #8c8c8c;
  --ink-4: #7e7e7e;
  --bg: #141414;             /* card surface (near-black neutral) */
  --bg-2: #0a0a0a;           /* page ground (true black) */
  --bg-3: #1c1c1c;
  --card-2: #181818;
  --border: #262626;
  --border-strong: #313131;
  --cover-1: #303030;        /* neutral near-black cover tiles (no navy) */
  --cover-2: #1f1f1f;
  --cover-3: #151515;
  --accent: #ef9a78;         /* bright coral for bars / borders / non-text accents */
  --accent-deep: #ba5c3e;    /* button fill — white label is AA (4.5:1) */
  --accent-text: #f3ac8c;    /* accent text on the near-black page — AA (10:1) */
  --accent-soft: #f3b095;
  --coral-tint: #261d2c;
  --coral-tint2: #2f2236;
  --coral-light: rgba(239,154,120,0.16);
  --coral-wash: rgba(239,154,120,0.12);
  --coral-line: rgba(239,154,120,0.36);
  --shadow-1: 0 1px 2px rgba(0,0,0,0.40), 0 1px 3px rgba(0,0,0,0.48);
  --shadow-2: 0 2px 6px rgba(0,0,0,0.44), 0 8px 20px rgba(0,0,0,0.52);
  --shadow-3: 0 10px 26px rgba(0,0,0,0.56), 0 20px 50px rgba(0,0,0,0.64);
  --shadow-coral: 0 4px 14px rgba(0,0,0,0.50);
  --acct-surface: #181818;
  --acct-ink: #f0f0f0;
  --acct-ink-2: #b8b8b8;
  --acct-ink-3: #8c8c8c;
  --acct-border: #262626;
  --acct-tint: #261d2c;
}

/* WARM — light, warm paper/charcoal (echoes the landing + book). Coral accent. */
html[data-theme="warm"] {
  --ink: #2a2422;            /* warm charcoal */
  --ink-2: #574e49;
  --ink-3: #756a63;
  --ink-4: #97897f;
  --bg: #ffffff;             /* warm white card */
  --bg-2: #faf7f1;           /* warm paper page (echoes landing #FBFAF6) */
  --bg-3: #f1ebe1;           /* warm recessed fill */
  --card-2: #fdfbf7;
  --border: #ece3d6;         /* warm hairline */
  --border-strong: #e2d7c6;
  --cover-1: #4a4038;
  --cover-2: #382f29;
  --cover-3: #2a221d;
  --accent: #DA7756;
  --accent-deep: #B8553A;
  --accent-text: #a8472a;
  --accent-soft: #E8A488;
  --coral-tint: #f8ebe1;     /* warm coral fill */
  --coral-tint2: #f3ddcd;
  --coral-light: rgba(218,119,86,0.09);
  --coral-wash: rgba(218,119,86,0.08);
  --coral-line: rgba(218,119,86,0.28);
  --shadow-1: 0 1px 2px rgba(60,40,20,0.05), 0 1px 3px rgba(60,40,20,0.07);
  --shadow-2: 0 2px 5px rgba(60,40,20,0.07), 0 6px 16px rgba(60,40,20,0.10);
  --shadow-3: 0 8px 20px rgba(60,40,20,0.11), 0 18px 44px rgba(60,40,20,0.14);
  --shadow-coral: 0 4px 14px rgba(184,85,58,0.22);
  --acct-surface: #fff;
  --acct-ink: #2a2422;
  --acct-ink-2: #574e49;
  --acct-ink-3: #756a63;
  --acct-border: #ece3d6;
  --acct-tint: #f8ebe1;
}

/* SEPIA — warm low-contrast light, easy on the eyes (reading). */
html[data-theme="sepia"] {
  --ink: #433829;            /* sepia brown ink */
  --ink-2: #5f5238;
  /* darkened to #6f6244 (was #786a4e) so the inactive .dv-tab (--w-ink-3 on the
     sepia page #f1e7cf) hits AA: 4.87:1 (was 4.3:1). 2026-05-31. */
  --ink-3: #6f6244;
  --ink-4: #9a8b6c;
  --bg: #f7efdc;             /* sepia card */
  --bg-2: #f1e7cf;           /* sepia page */
  --bg-3: #e8dcbf;           /* recessed */
  --card-2: #f9f2e1;
  --border: #ddcfac;
  --border-strong: #d2c199;
  --cover-1: #5a4d35;
  --cover-2: #463a27;
  --cover-3: #352b1d;
  --accent: #b9603a;
  --accent-deep: #9c4a28;    /* deep terracotta — AA on the sepia surfaces */
  --accent-text: #8f4322;
  --accent-soft: #cf8254;
  --coral-tint: #ecdcc0;
  --coral-tint2: #e4cda6;
  --coral-light: rgba(156,74,40,0.10);
  --coral-wash: rgba(156,74,40,0.08);
  --coral-line: rgba(156,74,40,0.30);
  --shadow-1: 0 1px 2px rgba(80,60,30,0.07), 0 1px 3px rgba(80,60,30,0.09);
  --shadow-2: 0 2px 5px rgba(80,60,30,0.09), 0 6px 16px rgba(80,60,30,0.12);
  --shadow-3: 0 8px 20px rgba(80,60,30,0.13), 0 18px 44px rgba(80,60,30,0.16);
  --shadow-coral: 0 4px 14px rgba(156,74,40,0.22);
  --acct-surface: #f9f2e1;
  --acct-ink: #433829;
  --acct-ink-2: #5f5238;
  --acct-ink-3: #786a4e;
  --acct-border: #ddcfac;
  --acct-tint: #ecdcc0;
}

/* HIGH CONTRAST — maximal contrast for accessibility (pure black/white). */
html[data-theme="contrast"] {
  --ink: #000000;
  --ink-2: #161616;
  --ink-3: #2a2a2a;
  --ink-4: #3d3d3d;          /* darkest "faint" — still AA on white */
  --bg: #ffffff;
  --bg-2: #ffffff;
  --bg-3: #f0f0f0;
  --card-2: #ffffff;
  --border: #000000;         /* hard 1px black hairlines */
  --border-strong: #000000;
  --cover-1: #1a1a1a;
  --cover-2: #000000;
  --cover-3: #000000;
  --accent: #a8331a;
  --accent-deep: #9a2f17;    /* deep coral — 6.0:1 on white */
  --accent-text: #8f2c15;    /* 7.0:1 on white */
  --accent-soft: #c75a3c;
  --coral-tint: #ffece4;
  --coral-tint2: #ffddcf;
  --coral-light: rgba(154,47,23,0.10);
  --coral-wash: rgba(154,47,23,0.08);
  --coral-line: #9a2f17;
  --shadow-1: 0 0 0 1px #000;
  --shadow-2: 0 0 0 1px #000;
  --shadow-3: 0 0 0 2px #000;
  --shadow-coral: 0 0 0 2px #9a2f17;
  --acct-surface: #ffffff;
  --acct-ink: #000000;
  --acct-ink-2: #161616;
  --acct-ink-3: #2a2a2a;
  --acct-border: #000000;
  --acct-tint: #ffece4;
}

/* ════════════════════════════════════════════════════════════════════════════
   FONT PICKER. data-font swaps the UI --font family across /app; eyebrows keep
   the mono (--font-mono is never touched). Webfonts are loaded in app.html.
   ════════════════════════════════════════════════════════════════════════════ */
html[data-font="inter"]    { --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
html[data-font="serif"]    { --font: 'Source Serif 4', 'EB Garamond', Georgia, 'Times New Roman', serif; }
html[data-font="rounded"]  { --font: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
/* PER-SKIN SIGNATURE FACES (2026-05-31). Each skin offers its OWN font set so a theme
   has its own type, not the same generic four everywhere. These drive the BODY --font
   globally (the skin owns only --font-display for headings — we never pin --font in a
   skin file, so the user's pick wins). grotesk/outfit/mono are @imported in app.html;
   tahoma is a pure SYSTEM stack (Win98's period face, no webfont). */
html[data-font="grotesk"]  { --font: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; }
html[data-font="outfit"]   { --font: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; }
html[data-font="tahoma"]   { --font: Tahoma, 'MS Sans Serif', Geneva, Verdana, sans-serif; }
html[data-font="mono"]     { --font: 'Space Mono', ui-monospace, 'SFMono-Regular', Consolas, monospace; }
/* default (jakarta) inherits the :root --font (Plus Jakarta Sans). */

/* ════════════════════════════════════════════════════════════════════════════
   STYLE PRESETS — the data-style bundles (ORTHOGONAL to theme/font/accent).
   Each bundle is a complete SHAPE/FEEL package: radii + density + border weight,
   plus a shadow override (flatter or softer). Because shadows are color-tuned,
   the flat styles use color-neutral overrides (work on any theme), and the SOFT
   style carries a dark-theme refinement (below) so its generous shadows still
   read on a dark surface. COLOR is never touched here — Squary+Dark = dark+sharp;
   Soft+Light = light+round. (See DASHBOARD-REORG §C / APP-THEME-SYSTEM.)

   The presets:
   • Default — the current V2 (rounded ~14px cards, soft layered shadows, comfy
     padding). It IS the :root defaults; data-style="default" is an explicit no-op
     so the picker can name it.
   • Minimal — flat + editorial: hairline borders, NO shadows (depth from the
     hairline only), modest radius, tighter density, low chrome.
   • Squary — architectural / brutalist-lite: 0–4px radius, crisp 1.5px borders,
     a tight flat shadow, defined edges, compact density.
   • Soft — friendly + rounded: big radius (~20px), generous soft shadows, airy
     padding, light hairlines.
   ════════════════════════════════════════════════════════════════════════════ */

/* DEFAULT — explicit, so the picker has a named target (no-op; matches :root). */
html[data-style="default"] {
  /* radii/density/border = the :root defaults; nothing to override. */
}

/* MINIMAL — flat, hairline, editorial. NO shadows; the hairline carries depth.
   Modest radius (a touch tighter than default), tighter padding, lighter lines. */
html[data-style="minimal"] {
  --radius-xs: 5px;
  --radius-sm: 7px;
  --radius: 9px;
  --radius-lg: 11px;
  --radius-xl: 13px;
  --pad-card: 15px;
  --pad-card-sm: 13px;
  --pad-card-lg: 18px;
  --gap-card: 10px;
  --border-weight: 1px;
  /* depth from the hairline, not a shadow — flatten every elevation to nothing
     (a hairline ring on the heaviest level so popovers/modals still detach). */
  --shadow-1: none;
  --shadow-2: none;
  --shadow-3: 0 0 0 1px var(--border), 0 8px 24px rgba(20,28,48,0.06);
  --shadow-coral: none;
}

/* SQUARY — sharp edges, crisp borders, a tight flat shadow. Architectural. */
html[data-style="squary"] {
  --radius-xs: 0px;
  --radius-sm: 2px;
  --radius: 3px;
  --radius-lg: 4px;
  --radius-xl: 4px;
  --pad-card: 16px;
  --pad-card-sm: 14px;
  --pad-card-lg: 20px;
  --gap-card: 10px;
  --border-weight: 1.5px;            /* crisper, more defined edges */
  /* a single tight, flat shadow (no soft spread) — defined, not floaty. */
  --shadow-1: 0 1px 0 rgba(20,28,48,0.10);
  --shadow-2: 0 2px 0 rgba(20,28,48,0.12), 0 1px 4px rgba(20,28,48,0.08);
  --shadow-3: 0 4px 0 rgba(20,28,48,0.10), 0 8px 22px rgba(20,28,48,0.14);
  --shadow-coral: 0 2px 0 rgba(184,85,58,0.30);
}

/* SOFT — big radius, generous soft shadows, airy density. Friendly + rounded. */
html[data-style="soft"] {
  --radius-xs: 11px;
  --radius-sm: 14px;
  --radius: 20px;
  --radius-lg: 26px;
  --radius-xl: 30px;
  --pad-card: 22px;
  --pad-card-sm: 18px;
  --pad-card-lg: 28px;
  --gap-card: 16px;
  --border-weight: 1px;
  /* softer, more diffuse, slightly larger shadows than default (light tuning). */
  --shadow-1: 0 2px 6px rgba(20,28,48,0.06), 0 4px 12px rgba(20,28,48,0.07);
  --shadow-2: 0 4px 14px rgba(20,28,48,0.08), 0 12px 28px rgba(20,28,48,0.10);
  --shadow-3: 0 14px 32px rgba(20,28,48,0.12), 0 28px 64px rgba(20,28,48,0.16);
  --shadow-coral: 0 6px 20px rgba(184,85,58,0.26);
}

/* SOFT × DARK themes — the soft shadow override above is tuned for light surfaces;
   on dark/midnight a translucent-black soft shadow keeps the generous, diffuse
   feel (a light-tuned shadow would be invisible on a dark page). */
html[data-theme="dark"][data-style="soft"],
html[data-theme="midnight"][data-style="soft"] {
  --shadow-1: 0 2px 8px rgba(0,0,0,0.34), 0 4px 14px rgba(0,0,0,0.40);
  --shadow-2: 0 6px 18px rgba(0,0,0,0.42), 0 14px 34px rgba(0,0,0,0.50);
  --shadow-3: 0 16px 40px rgba(0,0,0,0.52), 0 30px 72px rgba(0,0,0,0.62);
  --shadow-coral: 0 6px 20px rgba(0,0,0,0.46);
}
/* MINIMAL × DARK — the flat-to-nothing override is color-neutral, but the level-3
   hairline ring must use the dark border + a black ambient so popovers still
   detach on a dark page. */
html[data-theme="dark"][data-style="minimal"],
html[data-theme="midnight"][data-style="minimal"] {
  --shadow-3: 0 0 0 1px var(--border), 0 10px 28px rgba(0,0,0,0.45);
}
/* SQUARY × DARK — the flat drop shadows want a darker ambient on a dark surface. */
html[data-theme="dark"][data-style="squary"],
html[data-theme="midnight"][data-style="squary"] {
  --shadow-1: 0 1px 0 rgba(0,0,0,0.40);
  --shadow-2: 0 2px 0 rgba(0,0,0,0.46), 0 1px 5px rgba(0,0,0,0.40);
  --shadow-3: 0 4px 0 rgba(0,0,0,0.40), 0 8px 24px rgba(0,0,0,0.52);
}

/* High-Contrast keeps its own hard 1px-black "shadows" regardless of style (its
   theme bundle already sets --shadow-* to 0 0 0 Npx #000); the style radii still
   apply, so HC can be squary/soft-shaped while staying maximally legible. */

/* STYLE TRANSITION — when the style flips, briefly ease radius/shadow/padding so
   the re-shape glides instead of snapping (theme.js adds .cc-style-anim ~360ms on
   a switch; never on first paint; never under reduced-motion). Transform/opacity
   are untouched; only the shape props transition. */
html.cc-style-anim,
html.cc-style-anim .v2-card, html.cc-style-anim .card, html.cc-style-anim .iax-card,
html.cc-style-anim .jrow, html.cc-style-anim .sec-card, html.cc-style-anim .cw-tile,
html.cc-style-anim .btn, html.cc-style-anim .btn-coral, html.cc-style-anim .btn-ghost-coral,
html.cc-style-anim .hero-card, html.cc-style-anim .iax-bookrow, html.cc-style-anim .iax-modal,
html.cc-style-anim .vpl-row, html.cc-style-anim .overview-card, html.cc-style-anim .pbar,
html.cc-style-anim .ap-tile, html.cc-style-anim .ap-font, html.cc-style-anim .ap-preview {
  transition: border-radius 360ms var(--ease-out), box-shadow 360ms var(--ease-out),
    padding 360ms var(--ease-out), border-width 360ms var(--ease-out) !important;
}
@media (prefers-reduced-motion: reduce) {
  html.cc-style-anim, html.cc-style-anim * { transition: none !important; }
}

/* ════════════════════════════════════════════════════════════════════════════
   THEME COLOR TRANSITION. A subtle cross-fade of color/background/border when
   the theme flips, applied only while the root carries .cc-theme-anim (theme.js
   adds it for ~480ms on a switch). Never on first paint (no flash); never under
   prefers-reduced-motion. Only color props transition — no layout, no transform.
   ════════════════════════════════════════════════════════════════════════════ */
html.cc-theme-anim,
html.cc-theme-anim body,
html.cc-theme-anim .app-sidebar,
html.cc-theme-anim .v2-card,
html.cc-theme-anim .card,
html.cc-theme-anim .iax-card,
html.cc-theme-anim .jrow,
html.cc-theme-anim .sec-card,
html.cc-theme-anim .cw-tile,
html.cc-theme-anim .side-link,
html.cc-theme-anim .btn,
html.cc-theme-anim .btn-coral,
html.cc-theme-anim .btn-ghost-coral {
  transition: background-color 420ms var(--ease-out), color 420ms var(--ease-out),
    border-color 420ms var(--ease-out) !important;
}
@media (prefers-reduced-motion: reduce) {
  html.cc-theme-anim, html.cc-theme-anim * { transition: none !important; }
}

/* SKIN TRANSITION — when the macro THEME (data-skin) flips, briefly ease the
   page/card background + border + color so the re-skin glides instead of snapping
   (theme.js adds .cc-skin-anim ~480ms on a switch; never on first paint; never
   under reduced-motion). A skin file may extend this for its own props (gradients,
   glows). Transform/opacity are untouched. NOTE: setSkin() also runs the color
   (apply) path, so .cc-theme-anim covers most of the cross-fade; this is the
   skin-scoped hook the skin authors can rely on. */
html.cc-skin-anim,
html.cc-skin-anim body,
html.cc-skin-anim .app-shell,
html.cc-skin-anim .app-sidebar,
html.cc-skin-anim .card,
html.cc-skin-anim .jrow,
html.cc-skin-anim .hero-card,
html.cc-skin-anim .btn-coral,
html.cc-skin-anim .btn-ghost-coral {
  transition: background-color 480ms var(--ease-out), background-image 480ms var(--ease-out),
    color 480ms var(--ease-out), border-color 480ms var(--ease-out), box-shadow 480ms var(--ease-out) !important;
}
@media (prefers-reduced-motion: reduce) {
  html.cc-skin-anim, html.cc-skin-anim * { transition: none !important; }
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--coral-text); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible, summary:focus-visible {
  outline: 2px solid var(--coral-deep); outline-offset: 2px; border-radius: 4px;
}

.mono { font-family: var(--font-mono); }

/* V2 headings: Plus Jakarta, tight tracking. Applies app-wide without forcing a
   weight on every existing heading rule (those keep their own font-weight). */
h1, h2, h3, h4 { letter-spacing: -0.02em; }
::selection { background: var(--coral-tint); }

/* ════════════════════════════════════════════════════════════════════════
   V2 REUSABLE PRIMITIVES — generically named so /app + the future composer
   share one card / cover-tile / eyebrow vocabulary. Cool base, flat coral,
   refined shadows, Emil easing. (Surface-specific cards layer on top.)
   ════════════════════════════════════════════════════════════════════════ */
/* The base V2 card: white surface, cool hairline, refined shadow, soft radius.
   Border WIDTH follows the style (--border-weight: hairline ↔ crisp). */
.v2-card {
  background: var(--bg); border: var(--border-weight) solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  transition: transform 200ms var(--ease-out), box-shadow 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
.v2-card.lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-3); }
@media (prefers-reduced-motion: reduce) { .v2-card.lift:hover { transform: none; } }

/* The V2 eyebrow: mono, uppercase, coral-text, wide tracking. */
.v2-eyebrow {
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--coral-text);
}

/* The flat cover TILE — a flat coral / slate motif block (number + title), the
   V2 "rich card" cover. Four flat themes; depth from the shadow on the parent,
   never a gradient on the fill. */
.v2-cover {
  position: relative; overflow: hidden; color: #fff;
  display: flex; flex-direction: column; justify-content: space-between;
}
.v2-cover.t-coral { background: var(--coral-deep); }
.v2-cover.t-soft  { background: var(--coral); }
.v2-cover.t-ink   { background: var(--cover-2); }
.v2-cover.t-slate { background: var(--cover-1); }
.v2-cover .v2-cover-num {
  font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.08em;
  color: rgba(255,255,255,0.85); background: rgba(255,255,255,0.16); border-radius: 6px; padding: 3px 8px;
}

/* A flat coral chip / tag primitive (eyebrow-scale label, AA). */
.v2-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--coral-text);
  background: var(--coral-tint); border: 1px solid var(--coral-line); border-radius: 999px;
  padding: 4px 11px; line-height: 1;
}

/* ── Accessibility primitives (WCAG 2.2 AA) ── */
/* Visually-hidden but available to screen readers. */
.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Skip-to-content link: off-screen until focused, then pinned top-left, coral, AA. */
.skip-link {
  position: absolute; top: 0; left: 0; z-index: 100000; transform: translateY(-120%);
  background: var(--coral-deep); color: #fff; padding: 10px 16px; border-radius: 0 0 8px 0;
  font-weight: 600; font-size: 14px; text-decoration: none; transition: transform 120ms ease;
}
.skip-link:focus { transform: translateY(0); outline: 2px solid #fff; outline-offset: -4px; }
@media (prefers-reduced-motion: reduce) { .skip-link { transition: none; } }
/* Target of a skip link shouldn't show a persistent outline when focused programmatically. */
[tabindex="-1"]:focus { outline: none; }

/* Shared role-aware nav links (built by nav.js) */
.nav-link { font-size: 14px; color: var(--ink-2); text-decoration: none; padding: 6px 2px; border-bottom: 2px solid transparent; }
.nav-link:hover { color: var(--ink); text-decoration: none; }
.nav-link.current { color: var(--coral-text); font-weight: 600; border-bottom-color: var(--coral); }

/* ── Reveal animation (the coral ease) ── */
@keyframes fadeUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
.reveal { animation: fadeUp 640ms var(--ease) both; }
.reveal.d1 { animation-delay: 70ms; }
.reveal.d2 { animation-delay: 150ms; }
.reveal.d3 { animation-delay: 240ms; }
.reveal.d4 { animation-delay: 330ms; }
@media (prefers-reduced-motion: reduce) { .reveal, .reveal.d1, .reveal.d2, .reveal.d3, .reveal.d4 { animation: none; } }

/* ── Brand mark ── */
.mark {
  width: 34px; height: 34px; border-radius: var(--radius-sm); flex-shrink: 0;
  background: var(--coral-deep); color: #fff; font-weight: 700; font-size: 15px;
  display: flex; align-items: center; justify-content: center; letter-spacing: -0.5px;
  box-shadow: var(--shadow-1);
}
.brand { display: inline-flex; align-items: center; gap: 11px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-name { font-size: 15px; font-weight: 600; }
.brand-sub { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; }

/* ════════════════════════════════════════════════════════════════════
   SPLIT AUTH LAYOUT — charcoal particle panel (left) + form panel (right)
   ════════════════════════════════════════════════════════════════════ */
.auth { min-height: 100vh; display: grid; grid-template-columns: 1.05fr 1fr; }

.auth-brand {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 44px clamp(36px, 4vw, 72px);
  color: #fff;
  /* ECHO THE LANDING HERO (Felipe 2026-05-31): the auth band must read as a seamless
     continuation of the marketing landing (public/index.html), not a cool-navy slab.
     The landing hero is a WARM CHARCOAL cover-particles field — local tokens here so
     ONLY .auth-brand changes; the global --cover-2 (#232a3a) and the /app V2 cool-slate
     surfaces (.v2-cover, .dash-hero) are untouched. Values + the coral radial glow +
     the 158deg charcoal gradient are copied verbatim from the landing's .hero so the
     two backgrounds are identical. */
  --auth-cover-1: #2e2e2e; --auth-cover-2: #1c1c1c; --auth-cover-3: #111111;
  background:
    radial-gradient(900px 380px at 50% -60px, rgba(218,119,86,0.30), transparent 72%),
    linear-gradient(158deg, var(--auth-cover-1) 0%, var(--auth-cover-2) 55%, var(--auth-cover-3) 100%);
}
#auth-particles { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.auth-brand .brand-name, .auth-brand .brand-sub { color: #fff; }
.auth-brand .brand-sub { color: var(--coral-soft); }

.auth-pitch { max-width: 30ch; }
.auth-pitch .badge {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.04em;
  color: #fff; background: rgba(255,255,255,0.10); border: 1px solid rgba(255,255,255,0.22);
  padding: 6px 13px; border-radius: 999px; margin-bottom: 22px;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
.auth-pitch .badge .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--coral-soft); }
.auth-pitch h1 {
  font-size: clamp(28px, 3.4vw, 42px); font-weight: 700; line-height: 1.08;
  letter-spacing: -0.025em; margin-bottom: 16px;
}
.auth-pitch h1 em { font-style: normal; color: var(--coral-soft); }
.auth-pitch p { font-size: 16px; line-height: 1.6; color: rgba(255,255,255,0.82); }
.auth-points { list-style: none; margin-top: 26px; display: grid; gap: 13px; }
.auth-points li { display: flex; gap: 11px; align-items: flex-start; font-size: 14.5px; color: rgba(255,255,255,0.88); }
.auth-points svg { width: 19px; height: 19px; flex-shrink: 0; margin-top: 1px; color: var(--coral-soft); }
.auth-foot { font-size: 12.5px; color: rgba(255,255,255,0.55); }

/* form panel */
.auth-main { display: flex; align-items: center; justify-content: center; padding: 40px 28px; background: var(--bg); }
.auth-card { width: 100%; max-width: 404px; }
.auth-card h2 { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; margin-bottom: 5px; }
.auth-card .sub { font-size: 14.5px; color: var(--ink-2); margin-bottom: 22px; }

/* ── Form fields ── */
.field { margin-bottom: 13px; }
.field label { display: block; font-size: 13px; font-weight: 600; color: var(--ink-2); margin-bottom: 5px; }
.field input {
  width: 100%; font-family: var(--font); font-size: 14.5px; color: var(--ink);
  padding: 9px 12px; background: var(--bg); border: var(--border-weight) solid var(--border-strong); border-radius: var(--radius-sm);
  transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}
.field input::placeholder { color: var(--ink-3); }
.field input:focus { outline: none; border-color: var(--coral); box-shadow: 0 0 0 3px var(--coral-light); }
.field input:disabled { background: var(--bg-2); color: var(--ink-3); }
.field.code input {
  font-family: var(--font-mono); font-size: 17px; letter-spacing: 0.18em; text-align: center; text-transform: uppercase;
}
.field-hint { font-size: 12px; color: var(--ink-3); margin-top: 5px; }

/* ── Buttons ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font); font-size: 14px; font-weight: 600; padding: 9px 18px;
  border-radius: var(--radius-sm); cursor: pointer; border: var(--border-weight) solid transparent;
  transition: background 150ms var(--ease), border-color 150ms var(--ease), box-shadow 150ms var(--ease), transform 120ms var(--ease);
}
.btn svg { width: 16px; height: 16px; }
.btn-primary { background: var(--coral-deep); color: #fff; border-color: var(--coral-deep); box-shadow: var(--shadow-1); }
.btn-primary:hover { background: var(--coral-text); border-color: var(--coral-text); box-shadow: var(--shadow-2); text-decoration: none; }
.btn-primary:active { transform: translateY(1px); }
.btn-primary:disabled { background: var(--ink-3); border-color: var(--ink-3); cursor: progress; box-shadow: none; }
.btn-block { width: 100%; }
.btn-ghost { background: var(--bg); color: var(--ink); border-color: var(--border-strong); }
.btn-ghost:hover { border-color: var(--coral); color: var(--coral-text); text-decoration: none; }
@media (prefers-reduced-motion: reduce) { .btn:active { transform: none; } }

.btn .spinner {
  width: 15px; height: 15px; border: 2px solid rgba(255,255,255,0.45); border-top-color: #fff;
  border-radius: 50%; animation: spin 600ms linear infinite; display: none;
}
.btn.loading .spinner { display: inline-block; }
.btn.loading .btn-label { opacity: 0.85; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Inline messages ── */
.msg { font-size: 13.5px; padding: 10px 13px; border-radius: var(--radius-sm); margin-bottom: 14px; display: none; line-height: 1.45; }
.msg.show { display: block; animation: fadeUp 280ms var(--ease) both; }
.msg.error { background: var(--coral-tint); border: 1px solid var(--coral); color: var(--coral-deep); }
.msg.ok { background: #f0faf3; border: 1px solid #b6e0c4; color: #15803d; }

.alt { font-size: 14px; color: var(--ink-2); margin-top: 18px; text-align: center; }
.divider { display: flex; align-items: center; gap: 14px; margin: 18px 0; color: var(--ink-3); font-size: 12px; font-family: var(--font-mono); }
.divider::before, .divider::after { content: ""; height: 1px; background: var(--border); flex: 1; }

@media (max-width: 860px) {
  .auth { grid-template-columns: 1fr; }
  .auth-brand { padding: 32px 24px; min-height: 38vh; }
  .auth-pitch h1 { font-size: 26px; }
  .auth-points { display: none; }
  .auth-main { padding: 36px 22px; }
}

/* ════════════════════════════════════════════════════════════════════
   DASHBOARD / ACCOUNT
   ════════════════════════════════════════════════════════════════════ */
.navbar {
  position: sticky; top: 0; z-index: 100; overflow-x: clip;
  background: rgba(255,255,255,0.85); backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px); border-bottom: 1px solid var(--border);
}
.navbar-inner { max-width: 1080px; margin: 0 auto; padding: 0 28px; height: 56px; display: flex; align-items: center; gap: 12px; }
/* The brand must never shrink; everything to its right shares the remaining space. */
.navbar-inner > .brand { flex-shrink: 0; }
.navbar .nav-right { margin-left: auto; display: flex; align-items: center; gap: 14px; min-width: 0; }
.nav-user { font-size: 13.5px; color: var(--ink-2); }
.nav-user b { color: var(--ink); font-weight: 600; }

/* On narrow screens the role-aware nav (nav.js injects My Courses / Courseware / Admin /
   Settings / View site / Sign out) is wider than the bar. Let the right cluster scroll
   horizontally instead of pushing the whole page sideways, and tighten the gutter so the
   links have more room. Keeps the sticky bar a single 62px row at every width. */
@media (max-width: 640px) {
  .navbar-inner { padding: 0 16px; gap: 8px; }
  .navbar .nav-right {
    gap: 8px; overflow-x: auto; overflow-y: hidden; flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    /* let the scroll edge bleed to the gutter so a partially-hidden link reads as "more here" */
    margin-right: -16px; padding-right: 16px;
  }
  .navbar .nav-right::-webkit-scrollbar { display: none; }
  .navbar .nav-right > * { flex-shrink: 0; }
}

.wrap { max-width: 1080px; margin: 0 auto; padding: 0 28px; }

.dash-hero {
  position: relative; isolation: isolate; overflow: hidden; color: #fff;
  padding: 38px 0 32px;
  /* FLAT cool-slate fill (V2: no gradients). The shell hides .dash-hero inside
     /app anyway; this only governs the standalone account hero. */
  background: var(--cover-2);
  border-bottom: 1px solid var(--border);
}
#dash-particles { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.dash-hero h1 { font-size: clamp(24px, 3vw, 31px); font-weight: 700; letter-spacing: -0.025em; margin-bottom: 6px; }
.dash-hero p { font-size: 15px; color: rgba(255,255,255,0.82); max-width: 60ch; }
.dash-hero .badge {
  display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 12px;
  color: #fff; background: rgba(255,255,255,0.10); border: 1px solid rgba(255,255,255,0.22);
  padding: 5px 12px; border-radius: 999px; margin-bottom: 14px;
}

.section { padding: 28px 0; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.section-head h2 { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; }
.eyebrow { font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; color: var(--coral-text); margin-bottom: 8px; }

.cards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); }
.course-card {
  display: flex; flex-direction: column; gap: 10px;
  background: var(--bg); border: var(--border-weight) solid var(--border); border-radius: var(--radius); padding: var(--pad-card-sm);
  box-shadow: var(--shadow-1); transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease), transform 150ms var(--ease);
}
.course-card:hover { border-color: var(--coral); box-shadow: var(--shadow-3); transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) { .course-card:hover { transform: none; } }
.course-card .ct-top { display: flex; align-items: center; gap: 13px; }
.course-card .ct-icon { width: 42px; height: 42px; border-radius: var(--radius-sm); background: var(--coral-tint); border: 1px solid var(--border); color: var(--coral-deep); display: flex; align-items: center; justify-content: center; }
.course-card .ct-icon svg { width: 22px; height: 22px; }
.course-card h3 { font-size: 16.5px; font-weight: 600; letter-spacing: -0.01em; }
.course-card .ct-meta { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.course-card .ct-foot { display: flex; align-items: center; gap: 10px; margin-top: auto; }

.pill {
  display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em; padding: 4px 9px; border-radius: 6px; border: 1px solid;
}
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill.active { color: #15803d; border-color: #b6e0c4; background: #fff; }
.pill.expired { color: var(--ink-3); border-color: var(--border); background: var(--bg-2); }

.empty {
  text-align: center; padding: 32px 20px; background: var(--bg-2);
  border: 1px dashed var(--border-strong); border-radius: var(--radius);
}
.empty h3 { font-size: 16.5px; font-weight: 600; margin-bottom: 5px; }
.empty p { font-size: 14px; color: var(--ink-2); max-width: 46ch; margin: 0 auto 14px; }

footer { border-top: 1px solid var(--border); background: var(--bg-2); padding: 24px 0 32px; text-align: center; }
footer p { font-size: 13px; color: var(--ink-3); }

/* ════════════════════════════════════════════════════════════════════
   FLAT-SHEET SETTINGS PATTERN — reusable primitives (the claude.ai model).
   A flat sheet (no card boxes), split by a left sub-nav into sections; each
   setting is a ROW with the label on the left (~40%) and the control on the
   right, separated by 1px hairlines. Named generically so any account-style
   surface (admin, instructor, billing) can adopt the same pattern.

   Anatomy:
     .set-shell   — the two-column grid: sub-nav | content sheet
     .set-nav     — the left sub-nav (vertical list of section links)
     .set-navlink — one sub-nav item (aria-current="page" = active)
     .set-sheet   — the right content area (flat, no border)
     .set-section — one panel of rows (one per sub-nav item; toggled)
     .set-section-head — the section's title + optional one-line description
     .set-row     — a single setting: label-left / control-right, full width
     .set-label   — the left label column (~40%): a strong label + helper
     .set-help    — the small helper line under a label
     .set-control — the right control column (input / button / toggle), right-aligned
     .set-divider — an explicit 1px hairline (rows divide themselves; use for groups)
     .set-stack   — a vertical group of controls inside one .set-control (e.g. a form)
   ════════════════════════════════════════════════════════════════════ */
/* The page wrapper for the standalone /settings view. Inside the /app dashboard the shell
   normalizes .set-wrap (padding/margin/max-width → 0/100%), so this only governs the
   standalone route; both paths then share the .set-shell two-column grid. */
.set-wrap { max-width: 880px; margin: 0 auto; padding-left: 28px; padding-right: 28px; }
.set-shell {
  display: grid;
  grid-template-columns: 196px minmax(0, 1fr);
  gap: 40px;
  align-items: start;
  max-width: 880px;
}
.set-pagehead { margin-bottom: 22px; }
.set-pagehead h1 { font-size: 23px; font-weight: 700; letter-spacing: -0.02em; }
.set-pagehead .eyebrow { margin-bottom: 6px; }

/* ── Left sub-nav ── */
.set-nav { position: sticky; top: 76px; display: flex; flex-direction: column; gap: 2px; }
.set-navlink {
  display: block; font-size: 14px; font-weight: 500; color: var(--ink-2);
  padding: 8px 12px; border-radius: 8px; text-decoration: none; cursor: pointer;
  border: 1px solid transparent; text-align: left; background: none; width: 100%;
  transition: background 130ms var(--ease), color 130ms var(--ease);
}
.set-navlink:hover { background: var(--bg-2); color: var(--ink); text-decoration: none; }
.set-navlink[aria-current="page"] { background: var(--coral-tint); color: var(--coral-text); font-weight: 600; }
.set-navlink:focus-visible { outline: 2px solid var(--coral-deep); outline-offset: 2px; }

/* ── Content sheet (flat — no box) ── */
.set-sheet { min-width: 0; }
.set-section { display: none; }
.set-section.active { display: block; animation: fadeUp 320ms var(--ease) both; }
@media (prefers-reduced-motion: reduce) { .set-section.active { animation: none; } }
.set-section-head { margin-bottom: 4px; }
.set-section-head h2 { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
.set-section-head p { font-size: 13.5px; color: var(--ink-2); line-height: 1.5; margin-top: 4px; max-width: 60ch; }

/* ── The ROW — the heart of the pattern ──
   Label column left (~40%), control column right; a hairline below each row.
   align-items:start so a tall control (a stacked form) doesn't drag the label
   to the vertical centre. */
.set-row {
  display: grid; grid-template-columns: minmax(0, 40%) minmax(0, 1fr);
  gap: 28px; align-items: start;
  padding: 18px 0; border-bottom: 1px solid var(--border);
}
.set-row:last-child { border-bottom: 0; }
/* A row that owns a danger action reads in coral-tint via its label color only;
   no box — the flat sheet stays flat. */
.set-row.danger .set-label .set-label-title { color: var(--coral-text); }

.set-label { min-width: 0; }
.set-label-title { display: block; font-size: 14.5px; font-weight: 600; color: var(--ink); line-height: 1.35; }
.set-help { display: block; font-size: 13px; color: var(--ink-2); line-height: 1.5; margin-top: 4px; }
.set-help b { color: var(--ink); font-weight: 600; }

/* The control column sits to the right of the label and right-aligns its content
   so a lone button or input hugs the right edge (claude.ai). A multi-field form
   uses .set-stack to lay its fields out left-aligned at a sensible width. */
.set-control { min-width: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.set-control > * { max-width: 100%; }
/* Inputs in a row are sized to the control column, not full-bleed across the sheet. */
.set-control .field { margin-bottom: 0; width: 100%; max-width: 320px; }
.set-control .field input { width: 100%; }
.set-control .field input { font-size: 14px; padding: 8px 11px; }
.set-control .field label { font-size: 12.5px; }
.set-control .btn { white-space: nowrap; }
/* A stacked control = a small form (a few fields + a submit) laid out vertically,
   left-aligned, capped width, living in the right column. */
.set-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; width: 100%; max-width: 320px; }
.set-stack .field { width: 100%; margin-bottom: 0; }
.set-stack .btn { align-self: flex-start; }
/* Inline status messages inside a control don't need the form-card's bottom margin. */
.set-control .msg, .set-stack .msg { margin-bottom: 0; width: 100%; }
/* A read-only value shown in the control column (e.g. the signed-in email). */
.set-value { font-size: 14px; color: var(--ink); padding-top: 7px; word-break: break-word; }
.set-value.mono { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-2); }

/* An explicit hairline for grouping inside a control (e.g. between session rows). */
.set-divider { height: 1px; background: var(--border); border: 0; margin: 0; width: 100%; }

/* Session list rendered inside a control column: dense mono rows, wrap long UA. */
.set-sesslist { width: 100%; display: flex; flex-direction: column; }
.set-sesslist .sess {
  font-family: var(--font-mono); font-size: 12px; color: var(--ink-2);
  padding: 8px 0; border-bottom: 1px solid var(--border); line-height: 1.5;
  word-break: break-word; overflow-wrap: anywhere;
}
.set-sesslist .sess:last-child { border-bottom: 0; }

/* ── Mobile (≤640px): rows STACK (label over control), the sub-nav becomes a
   horizontal scroll-row of tabs, controls go full-width + thumb-reachable. ── */
@media (max-width: 640px) {
  .set-wrap { padding-left: 16px; padding-right: 16px; }
  .set-shell { grid-template-columns: 1fr; gap: 18px; max-width: 100%; }
  /* Sub-nav → a horizontal row of pill tabs that scrolls if it overflows
     (no horizontal page scroll at 320/390). The negative margin lets the scroll
     edge bleed to the gutter; the matching padding keeps the first pill aligned. */
  .set-nav {
    position: static; flex-direction: row; gap: 8px; overflow-x: auto;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    margin: 0 -16px; padding: 0 16px 6px; border-bottom: 1px solid var(--border);
  }
  .set-nav::-webkit-scrollbar { display: none; }
  /* Compact pills sit side-by-side (override the desktop width:100%, which would
     stretch each pill to the full row). */
  .set-navlink {
    flex: 0 0 auto; width: auto; white-space: nowrap; min-height: 40px;
    display: inline-flex; align-items: center; border-radius: 999px; padding: 8px 15px;
  }
  /* Rows stack: label on top, control underneath, both full width. */
  .set-row { grid-template-columns: 1fr; gap: 12px; padding: 16px 0; }
  .set-control { align-items: stretch; }
  .set-control .field, .set-control .btn, .set-stack, .set-stack .btn,
  .set-control > a.btn, .set-control > button.btn {
    max-width: none; width: 100%;
  }
  .set-control .btn { justify-content: center; min-height: 44px; }
  .set-stack .btn { align-self: stretch; }
  /* 16px inputs stop the iOS focus-zoom; comfortable tap height. */
  .set-control .field input { font-size: 16px; padding: 12px 13px; min-height: 46px; }
  .set-value { padding-top: 0; }
}

/* ════════════════════════════════════════════════════════════════════
   MOBILE-UX PASS — the signed-in /app shell + dashboard (≤640px).
   Felipe's note: mobile felt cramped + bloated. The goals here are room to
   breathe, comfortable type, ≥44px tap targets, a sensible materials grid
   (never a tiny 2-up crush nor an endless 1-col wall), and no doubled
   padding / floated-to-the-edge controls. These rules OVERRIDE the desktop
   defaults above + the injected /account page styles on narrow screens.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  /* ── Cards: stop the icon floating to the vertical centre of a 2-line
     title; keep it pinned to the first line and give cards calmer padding. ── */
  .course-card { padding: var(--pad-card); border-radius: var(--radius); gap: 14px; }
  .course-card .ct-top { align-items: flex-start; gap: 12px; }
  .course-card .ct-icon { width: 40px; height: 40px; }
  .course-card h3 { font-size: 16px; line-height: 1.3; }
  /* Card hover-lift is a desktop pointer affordance; on touch it just causes
     jitter. Flatten the transform so taps feel solid. */
  .course-card:hover { transform: none; box-shadow: var(--shadow-2); }

  /* ── Section rhythm: a touch less vertical air than desktop's 40px so the
     dashboard isn't an endless scroll, but still room to breathe. ── */
  .section { padding: 28px 0; }
  .section-head { margin-bottom: 16px; }

  /* The empty-state block was sized for a wide column; tighten on phones. */
  .empty { padding: 34px 20px; }
}

/* ── Materials grid (Courseware tiles): the core fix. On phones a single
   forced column became an "endless wall". Below the 2-up threshold we keep
   ONE comfortable column with roomier tiles + ≥16px-feel copy; from ~480px
   up we allow a clean 2-up so the wall halves. The injected /account styles
   set minmax(238px) which never goes 2-up on a phone — override it. ── */
@media (max-width: 640px) {
  .cw-tiles { gap: var(--gap-card); grid-template-columns: 1fr; }
  .cw-tile { padding: var(--pad-card-sm); border-radius: var(--radius); }
  .cw-tile:hover { transform: none !important; }
  .cw-tile-title { font-size: 15.5px; }
  .cw-tile-blurb { font-size: 14px; line-height: 1.5; }
  .cw-tile-icon { width: 36px; height: 36px; }
  /* The group header "N / M ready" count can crowd the title on a phone; let
     it sit under the heading instead of fighting for the same row. */
  .cw-group-head { flex-wrap: wrap; gap: 6px 14px; align-items: baseline; }
  .cw-group { margin-bottom: 24px; }
}
@media (min-width: 481px) and (max-width: 640px) {
  /* Tablet-ish / large phones: a clean 2-up materials grid (no tiny crush —
     each tile keeps a comfortable min width before it wraps). */
  .cw-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ── Self-buyer tier picker + coverage cards: make prices/CTAs stack cleanly
   instead of the price floating to a far edge with dead space beside it. ── */
@media (max-width: 640px) {
  .tier-grid { grid-template-columns: 1fr; gap: 14px; }
  .tier-card { padding: 18px; }
  .coverage-card { flex-direction: column; align-items: stretch; gap: 12px; padding: 16px 18px; }
  .coverage-card .cv-body { min-width: 0; }
  .coverage-card .cv-price { margin-left: 0; font-size: 24px; }
  .coverage-card .btn { width: 100%; }
  /* Buy summary in the empty state: stack the price under the name + make the
     CTA full width + thumb-reachable. */
  .buy-summary { flex-direction: column; align-items: stretch; gap: 10px; }
  .buy-summary .buy-price { margin-left: 0; }

  /* Find-your-class + join rows: full-width inputs/buttons, ≥44px tall, no
     awkward half-width search field beside a floated button. */
  .find-form { flex-direction: column; gap: 10px; }
  .find-form input { min-width: 0; width: 100%; }
  .find-form .btn { width: 100%; }
  .find-row { flex-direction: column; align-items: stretch; gap: 12px; }
  .find-row .fr-body { min-width: 0; }
  .find-row .btn { width: 100%; }

  /* Order rows: keep the amount on its own line rather than colliding with a
     long product name on a narrow screen. */
  .order-row { flex-wrap: wrap; gap: 6px 12px; }
  .order-row .o-amt { margin-left: 0; }
}

/* ── Instructor "Sections you teach" + Create-a-course: the densest staff
   surface. On desktop the join code + "Preview as a student" button use
   margin-left:auto and float to the right edge; on a phone that left a big
   empty gutter. Lay the section header out as a calm vertical stack and make
   the controls full-width + tappable. ── */
@media (max-width: 640px) {
  .teach-card { padding: 18px; }
  .teach-card .row { gap: 10px; }
  .teach-card .row .field { min-width: 0; flex: 1 1 100%; }

  /* The flex header row inside a .sec-item (name · roster · pack · join code ·
     preview) — let everything stack and align left, no margin-left:auto float. */
  .sec-item > div:first-child { flex-direction: column; align-items: stretch !important; gap: 8px !important; }
  .sec-item .jc,
  .sec-item .sec-preview { margin-left: 0 !important; }
  .sec-item .sec-preview { width: 100%; justify-content: center; box-sizing: border-box; }
  .sec-item .jc { font-size: 18px; letter-spacing: 0.14em; }

  /* The edition / chapters / save control bar wraps to its own column. */
  .cur { gap: 12px; padding: 14px; }
  .cur-ed { width: 100%; }
  .cur-ed select { flex: 1; }
  .ch-details { min-width: 0; flex: 1 1 100%; }
  .cur-save { width: 100%; }
  .ch-grid { grid-template-columns: 1fr; max-height: 260px; }

  .ros { gap: 12px; }
  .ros-details, .email-details { min-width: 0; flex: 1 1 100%; }
  .ros-row { flex-wrap: wrap; }
  .ros-row .em { flex-basis: 100%; }

  /* Pack picker grids → single column on a phone (no half-width crush). */
  .preset-grid { grid-template-columns: 1fr; }
  .byo-summary { gap: 10px; }
}

/* ── Class-detail dialog (#37): on a phone it should read as a sheet, not a
   tiny centred card. Edge-to-edge with comfortable padding + a stacked
   coverage row so the upgrade CTA is full-width and thumb-reachable. ── */
@media (max-width: 640px) {
  .cd-overlay { padding: 0; align-items: flex-end; }
  .cd-dialog { max-width: 100%; max-height: 94vh; border-radius: 18px 18px 0 0; }
  .cd-head { padding: 20px 18px 16px; border-radius: 18px 18px 0 0; }
  .cd-head h2 { font-size: 19px; }
  .cd-body { padding: 18px; }
  .cd-cov { flex-wrap: wrap; }
  .cd-cov .cd-cov-up { margin-left: 0; width: 100%; }
  .cd-info dt { min-width: 84px; }
}
