/* =========================
   Exam Study Aid — Dark Theme (Full Site)
   Cleaned + No Duplicates
========================= */

/* ---------- Theme Variables ---------- */
:root {
  /* Backgrounds — deep ink/navy, lifted from near-black */
  --bg: #0F1013;
  --bg-2: #191B20;
  --bg-3: #181e30;
  --surface: #191B20;
  --surface-soft: #141519;
  --surface-elevated: #1E2027;

  /* Text — crisper hierarchy */
  --text: #F0EFEC;
  --text-muted: #B3B0A6;
  --text-faint: #89867D;
  --muted: #B3B0A6;
  --faint: #89867D;

  /* Accents — unified violet/indigo */
  --accent: #789FF2;
  --accent-hover: #78AEFF;
  --accent-soft: rgba(120, 159, 242, 0.16);
  --accent-border: rgba(169, 193, 238, 0.28);

  /* Premium / locked states */
  --premium-surface: linear-gradient(180deg, rgba(77, 110, 248, 0.13), rgba(77, 110, 248, 0.06));
  --premium-border: rgba(132, 182, 255, 0.28);
  --premium-pill-bg: rgba(91, 140, 255, 0.16);
  --premium-pill-text: #BECDFF; /* PT-11: lavender -> pale blue */

  /* Secondary accent — teal */
  --accent-2: #2DD4BF;
  --teal: #2DD4BF;
  --teal-soft: rgba(45, 212, 191, 0.13);

  /* Semantic */
  --danger: #ef4444;
  --success: #22c55e;
  /* state borders (account-retheme: status badges need a tinted border role) */
  --success-border: rgba(34, 197, 94, 0.30);
  --danger-border: rgba(239, 68, 68, 0.26);
  --warning-border: rgba(251, 191, 36, 0.30);

  /* Borders + shadows — slightly more defined */
  --border: rgba(240, 239, 236, 0.10);
  --border-2: rgba(255, 255, 255, 0.15);
  --border-strong: rgba(255, 255, 255, 0.15);
  --shadow: 0 8px 32px rgba(0,0,0,0.4);
  --shadow-sm: 0 2px 8px rgba(0,0,0,0.3);

  /* Radius */
  --r-lg: 16px;
  --r-md: 12px;
  --r-sm: 8px;

  /* ---- Semantic token extensions (light-mode audit) ----
     Dark values mirror current rendering verbatim. Every token here must
     also be defined in theme-light.css :root — both themes in the same diff. */
  --bg-elevated: var(--surface-elevated);
  --bg-overlay: rgba(4, 6, 16, 0.62);
  --text-inverse: #0b0d1e;
  --text-link: #84B6FF; /* PT-06: dark link blue (was purple via --accent) */
  --text-link-hover: #a9beff;
  --border-subtle: var(--border);
  --border-default: var(--border-2);
  --border-control: rgba(185, 196, 230, 0.30);
  --border-focus: rgba(91, 140, 255, 0.82);
  --focus-ring: rgba(91, 140, 255, 0.82);
  --accent-active: var(--accent-hover);
  --accent-subtle-bg: var(--accent-soft);
  --warning: #fbbf24;
  --info: #22c1ff;
  --danger-subtle-bg: rgba(239, 68, 68, 0.14);
  --success-subtle-bg: rgba(34, 197, 94, 0.14);
  --warning-subtle-bg: rgba(251, 191, 36, 0.14);
  --info-subtle-bg: rgba(34, 193, 255, 0.14);
  --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.35);
  --shadow-lg: var(--shadow);
  --shadow-hover: 0 12px 36px rgba(0, 0, 0, 0.45);
  /* Shared hover/press micro-interaction tokens (see commit A) */
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --hover-ease: var(--ease-expo);
  --hover-dur: 0.2s;
  --press-dur: 100ms;
  --lift-sm: -1px;
  --hover-lift: -3px;
  --lift-lg: -6px;
  --card-hover-shadow: 0 22px 58px rgba(0, 0, 0, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  --press-scale: 0.97;
  --glow-accent: 0 6px 22px rgba(42, 64, 188, 0.38);
  --selection-bg: rgba(91, 140, 255, 0.40);
  --scrollbar-thumb: rgba(148, 163, 184, 0.35);
  --scrollbar-track: transparent;
  --placeholder: rgba(190, 202, 230, 0.46);
  --autofill-bg: #0c1020;
  --autofill-text: rgba(255, 255, 255, 0.96);
  /* Declare the dark scheme so the browser paints native controls and Chrome/
     Brave autofill dark (counterpart of color-scheme:light in theme-light.css).
     Without this, dark-mode autofilled inputs render with a light background. */
  color-scheme: dark;
  --code-bg: rgba(0, 0, 0, 0.35);
  --code-text: rgba(255, 255, 255, 0.90);
  /* Dark counterparts of light-skin tokens (values = current dark rendering) */
  --note-link-hover: #8fe6ff;
  --pg-hover-igcse: #34d399;
  --pg-hover-alevel: #84B6FF; /* PT-13: violet -> periwinkle blue */
  --pg-hover-ap: #fbbf24;
  --pg-hover-sat: #22d3ee;
  --pg-hover-cie: #2e9e6e;     /* Cambridge / CIE — emerald (board-keyed, was blue) */
  --pg-hover-edexcel: #60a5fa; /* Edexcel — blue (board-keyed) */
  --cta-grad-1: #4d6ef8;
  --cta-grad-2: #3855e0;
  --cta-grad-3: #2c46cc;
  --cta-grad-hover-1: #5d7eff;
  --cta-grad-hover-2: #4464f0;
  --cta-grad-hover-3: #3552d8;
}

/* ---------- Base / Reset ---------- */
* {
  box-sizing: border-box;
}

/* Theme switch is INSTANT. While the user flips dark<->light, every transition
   is suppressed so the new theme applies all at once — no per-element colour
   fade and no staggered, one-element-after-another sweep. theme-toggle.js adds
   this class only for the duration of the swap; first paint is never affected
   (the class is never set on load). Replaces the old animated-fade rule. */
html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after {
  transition: none !important;
}

html {
  scroll-padding-top: 108px;
}

html, body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  background: linear-gradient(165deg, #0e1128 0%, #0a0c1a 52%, #070810 100%);
  color: var(--text);
}

body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Links */
a { color: var(--text-link); } /* PT-07 */
a:hover { color: #a9beff; }

/* Typography */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 0.6rem 0;
  color: rgba(255,255,255,0.92);
  letter-spacing: 0.2px;
}

p { color: var(--text); line-height: 1.6; }
small { color: var(--muted); }

hr{
  border: none;
  border-top: 1px solid var(--border);
  margin: 18px 0;
}

/* Lists (global) */
ul { padding-left: 1.3rem; }
li { margin-bottom: 0.55rem; color: var(--text); }

/* ---------- Layout Helpers ---------- */
.container{
  width: min(1100px, calc(100% - 48px));
  margin: 0 auto;
}

/* Main content wrapper you already use */
.content {
  width: min(1100px, calc(100% - 48px));
  margin: 22px auto;
  padding: 24px;

  background: linear-gradient(180deg, rgba(255,255,255,0.035), rgba(255,255,255,0.02));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: 0 14px 35px rgba(0,0,0,0.35);
}

/* =========================
   Buttons (general)
========================= */
button,
.btn{
  background: rgba(255,255,255,0.06);
  color: #fff;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 14px;
  cursor: pointer;
  font: inherit;
  font-weight: 600;
  transition: background 0.18s ease, transform 0.18s ease, border 0.18s ease;
}

button:hover,
.btn:hover{
  background: rgba(255,255,255,0.10);
  border-color: var(--border-2);
}

button:active,
.btn:active{
  transform: translateY(0);
}

/* ── Hover-lift + press micro-interactions (touch-safe) ──────────────────────
   Lift is gated to hover-capable pointers so it never sticks on touch; press
   (a scale-down composed with the lift) is ungated for tactile tap feedback.
   Card grids share one lift token; .nav-cta/buttons keep their small inline
   lift (--lift-sm/--hover-lift). CSS-owned now that the
   theme-transition clobber is scoped to toggles (commit 0). */
/* Global reduced-motion safety net. Zeroes motion DURATION for any
   token-driven transition/animation that lacks its own scoped block.
   Deliberately does NOT reset transform — the landing subject-viewer's
   reduced-motion blocks hold a *resting* transform (e.g. translateY(-92px))
   that a blanket reset would destroy; those per-component blocks stay
   authoritative and remove their own hover transforms. */
@media (prefers-reduced-motion: reduce) {
  /* Nodes rest at their placed position. Explicit transform, not just
     `animation: none` — an infinite keyframe is not reliably a no-op and the
     resting transform is what positions the node. */
  .lp-ai-node {
    animation: none;
  }


  /* The band rests EXPANDED with no animation. Explicit rather than inherited:
     zeroing a duration does not reliably no-op a keyframe, and `animation:none`
     alone would leave whatever clip-path the last frame applied. */
  .lp-ai {
    animation: none;
    clip-path: none;
  }

  /* Constellation only. Below 960 the node is a static flex row with no
     transform of its own, so applying the resting transform there would drag
     every list row up and left by half its own box. */
  @media (min-width: 1100px) {
    .lp-ai-node {
      transform: translate(-50%, -50%);
    }
  }

  /* Rest in the RESOLVED state, not the unresolved start: `animation: none` on a
     `backwards`-filled animation would otherwise leave the from-values showing. */
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--incorrect,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--incorrect .lp-sv-mcq-badge,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--incorrect .lp-sv-mcq-text,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--correct,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--correct .lp-sv-mcq-badge,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--correct .lp-sv-mcq-text,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-mark,
  .lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-feedback {
    animation: none;
    opacity: 1;
  }

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

@media (hover: hover) {
  .pg-bcard:hover,
  .si-card:hover,
  .sr-card:hover { transform: translateY(var(--hover-lift)); }
  .nav-cta:hover,
  button:hover,
  .btn:hover { transform: translateY(var(--lift-sm)); }
}
.pg-bcard:active,
.si-card:active,
.sr-card:active { transform: translateY(var(--hover-lift)) scale(var(--press-scale)); }
.nav-cta:active { transform: translateY(var(--lift-sm)) scale(var(--press-scale)); }

/* primary button */
.btn-primary{
  background: rgba(91,140,255,0.14);
  border-color: rgba(91,140,255,0.28);
  color: #d4deff;
}

.btn-primary:hover{
  background: rgba(91,140,255,0.22);
}

/* =========================
   Inputs
========================= */
input, select, textarea{
  width: 100%;
  padding: 12px 12px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
  color: var(--text);
  outline: none;
}

input:focus, select:focus, textarea:focus{
  border-color: rgba(91,140,255,0.45);
  box-shadow: 0 0 0 4px rgba(91,140,255,0.12);
}

/* =========================
   Cards / Panels
========================= */
.card{
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 18px;
  box-shadow: 0 12px 30px rgba(0,0,0,0.35);
}

.card-title{
  font-weight: 800;
  letter-spacing: 0.2px;
}

.muted{ color: var(--muted); }

/* =========================
   Footer
========================= */
.footer {
  position: relative;
  z-index: 2;
  margin-top: auto;
  padding: 22px 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 18px;
}

.footer-quote{
  font-weight: 600;
  color: rgba(255,255,255,0.72);
  letter-spacing: 0.2px;
}

.footer-credit{
  font-weight: 600;
  color: rgba(255,255,255,0.55);
  letter-spacing: 0.35px;
  font-size: 13px;
}

/* =========================
   Account Page / Menu
========================= */
.account-container{
  max-width: 460px;
  margin: 70px auto;
  padding: 26px;

  background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: 0 18px 45px rgba(0,0,0,0.45);

  color: #fff;
}

.account-container h1{
  text-align: center;
  margin-bottom: 16px;
  font-size: 1.7rem;
}

.account-username,
.account-note{
  text-align: center;
  margin-bottom: 16px;
  color: var(--muted);
}

/* Account menu list (overrides global UL styling) */
.account-menu{
  list-style: none;
  padding: 0;
  margin: 0;
}

.account-menu li{
  margin: 0 0 12px 0;
}

/* remove default form spacing */
.account-menu form{ margin: 0; }

/* menu items */
.account-menu a,
.account-menu button{
  width: 100%;
  display: block;
  padding: 12px 14px;
  text-align: center;

  border-radius: 14px;
  border: 1px solid var(--border);

  background: rgba(255,255,255,0.05);
  color: rgba(255,255,255,0.88);

  text-decoration: none;
  cursor: pointer;
  font: inherit;
  font-weight: 700;

  transition: background 0.18s ease, transform 0.16s ease, border 0.18s ease;
}

.account-menu a:hover,
.account-menu button:hover{
  background: rgba(255,255,255,0.10);
  border-color: var(--border-2);
  transform: translateY(var(--lift-sm));
}

.account-menu a:active,
.account-menu button:active{
  transform: translateY(0);
}

/* Premium button */
.account-menu .premium-btn{
  background: rgba(91,140,255,0.14);
  border-color: rgba(91,140,255,0.28);
  color: #d4deff;
}

.account-menu .premium-btn:hover{
  background: rgba(91,140,255,0.22);
}

/* Logout button */
.account-menu .logout-btn{
  background: rgba(255,90,95,0.14);
  border-color: rgba(255,90,95,0.25);
  color: rgba(255,255,255,0.92);
}

.account-menu .logout-btn:hover{
  background: rgba(255,90,95,0.20);
}

/* =========================
   Utility
========================= */
.highlight{
  color: var(--text-link); /* PT-07 */
  font-weight: 800;
}

.badge{
  display:inline-flex;
  align-items:center;
  gap:8px;
  padding: 6px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.04);
  color: var(--muted);
  font-weight: 700;
  font-size: 12px;
}

@media (max-width: 520px){
  .ft-link,
  .ft-legal-link{
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* ── Crowned upgrade CTAs — shared /pricing stroked crown. Sized in `em` so it
   scales with each button; vertical-align covers inline <a> CTAs, flex-shrink
   covers inline-flex CTAs (.nav-cta). ── */
.upgrade-crown {
  width: 1.05em;
  height: 1.05em;
  flex-shrink: 0;
  margin-right: 0.5em;
  vertical-align: -0.14em;
}

/* =========================
   Subject Index Pages
   (IGCSE / Edexcel, IGCSE / CIE, etc.)
========================= */

.subject-index-page {
  padding: 96px 56px;
  max-width: 1400px;
  margin: 0 auto;
  position: relative;
}

.subject-index-page::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 1200px;
  height: 680px;
  background: radial-gradient(ellipse at 50% 0%, rgba(91,140,255,0.26) 0%, rgba(91,140,255,0.06) 52%, transparent 72%);
  pointer-events: none;
  z-index: 0;
}

.subject-index-card {
  max-width: 1120px;
  margin: 0 auto;
  position: relative;
  z-index: 1;
}

.subject-index-card h1 {
  font-size: 3.75rem;
  font-weight: 800;
  letter-spacing: -0.035em;
  margin-bottom: 32px;
  background: linear-gradient(120deg, #ffffff 0%, #b8c8ff 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.subject-index-subtitle {
  font-size: 1.0625rem;
  color: rgba(255,255,255,0.64);
  margin-bottom: 56px;
  font-weight: 400;
}

.subjects-section-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(169,190,255,0.55);
  margin-bottom: 22px;
}

.subjects-grid {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.subjects-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 20px;
  row-gap: 0;
}

.subjects-row--single {
  grid-template-columns: 1fr;
}

@media (max-width: 560px) {
  .subjects-row {
    grid-template-columns: 1fr;
  }
}

.subject-card {
  background: linear-gradient(160deg, rgba(30, 38, 72, 0.88) 0%, rgba(18, 22, 50, 0.82) 100%);
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 2px 16px rgba(0,0,0,0.24);
  transition: border-color 0.18s, box-shadow 0.18s, background 0.18s;
}

.subject-card:hover {
  border-color: rgba(169,190,255,0.28);
  background: linear-gradient(160deg, rgba(36, 44, 82, 0.92) 0%, rgba(22, 27, 60, 0.88) 100%);
  box-shadow: 0 4px 28px rgba(0,0,0,0.32), 0 0 0 0 transparent;
}

.subject-btn {
  width: 100%;
  padding: 30px 32px;
  background: transparent;
  border: none;
  text-decoration: none;
  color: var(--text);
  font-size: 1.1875rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 16px;
  letter-spacing: -0.01em;
  transition: background 0.15s;
}

.subject-btn:hover {
  background: rgba(91,140,255,0.12);
  transform: none;
  box-shadow: none;
}

.subject-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  color: rgba(255,255,255,0.44);
  transition: color 0.18s, filter 0.18s;
}

.subject-icon svg {
  width: 22px;
  height: 22px;
  stroke-width: 1.75;
}

/* Per-subject icon accent colors */
.subject-btn[data-subject="biology"] .subject-icon    { color: rgba(74, 222, 128, 0.90); }
.subject-btn[data-subject="physics"] .subject-icon    { color: rgba(91, 140, 255, 0.96); }
.subject-btn[data-subject="chemistry"] .subject-icon  { color: rgba(34, 211, 238, 0.88); }
.subject-btn[data-subject="maths"] .subject-icon      { color: rgba(251, 191, 36, 0.92); }
.subject-btn[data-subject="math"] .subject-icon       { color: rgba(251, 191, 36, 0.92); }
.subject-btn[data-subject="calculus"] .subject-icon   { color: rgba(251, 191, 36, 0.92); }
.subject-btn[data-subject="english"] .subject-icon    { color: rgba(132, 182, 255, 0.92); }
.subject-btn[data-subject="reading"] .subject-icon    { color: rgba(132, 182, 255, 0.92); }
.subject-btn[data-subject="business"] .subject-icon   { color: rgba(52, 211, 153, 0.88); }
.subject-btn[data-subject="writing"] .subject-icon    { color: rgba(251, 146, 60, 0.92); }
.subject-btn[data-subject="economics"] .subject-icon  { color: rgba(163, 230, 53, 0.84); }
.subject-btn[data-subject="psychology"] .subject-icon { color: rgba(251, 113, 133, 0.90); }

/* Brighten on hover */
.subject-btn:hover .subject-icon {
  filter: brightness(1.25) saturate(1.15);
}

.subject-name {
  flex: 1;
}

.subject-chevron {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  color: rgba(255,255,255,0.36);
  transition: transform 0.22s ease, color 0.15s;
}

.subject-feature-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
  margin-top: 60px;
}

.subject-feature-item {
  padding: 28px 32px;
  border: 1px solid rgba(91,140,255,0.16);
  border-radius: 14px;
  background: linear-gradient(145deg, rgba(28, 34, 66, 0.72) 0%, rgba(14, 18, 44, 0.64) 100%);
  transition: border-color 0.18s;
}

.subject-feature-item:hover {
  border-color: rgba(91,140,255,0.30);
}

.subject-feature-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: rgba(255,255,255,0.78);
  margin: 0 0 8px;
  letter-spacing: 0.005em;
}

.subject-feature-desc {
  font-size: 0.8125rem;
  color: rgba(255,255,255,0.60);
  margin: 0;
  line-height: 1.65;
}

/* =========================
   Auth Pages (login, signup, etc.)
========================= */

/* Outer centering wrapper */
.auth-page{
  min-height: 70vh;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 3rem 1rem 6rem;
}

/* Card */
.auth-card{
  width: 100%;
  max-width: 420px;
  background:
    radial-gradient(circle at 88% -8%, rgba(95,115,230,0.095) 0%, rgba(70,90,190,0.032) 35%, transparent 56%),
    radial-gradient(ellipse 72% 38% at 50% -10%, rgba(150,168,225,0.048) 0%, rgba(95,115,170,0.018) 52%, transparent 100%),
    linear-gradient(180deg, rgba(14,17,30,0.97) 0%, rgba(10,13,24,0.98) 58%, rgba(7,9,18,0.99) 100%);
  border: 1px solid rgba(125,142,198,0.25);
  border-top-color: rgba(165,182,230,0.32);
  border-radius: 18px;
  padding: 2.5rem 2rem;
  box-shadow:
    0 24px 66px rgba(0,0,0,0.38),
    0 0 0 1px rgba(105,125,200,0.048),
    inset 0 1px 0 rgba(255,255,255,0.048),
    inset 0 -1px 0 rgba(0,0,0,0.22);
}

/* Larger card variant — used on standalone auth pages (e.g. change password) */
.auth-card--lg {
  max-width: 520px;
  padding: 3.25rem 3rem;
  background:
    radial-gradient(circle at 88% -8%, rgba(95,115,230,0.095) 0%, rgba(70,90,190,0.032) 35%, transparent 56%),
    radial-gradient(ellipse 72% 38% at 50% -10%, rgba(150,168,225,0.048) 0%, rgba(95,115,170,0.018) 52%, transparent 100%),
    linear-gradient(180deg, rgba(14,17,30,0.98) 0%, rgba(10,13,24,0.99) 58%, rgba(7,9,18,1) 100%);
  border: 1px solid rgba(125,142,198,0.25);
  border-top-color: rgba(165,182,230,0.32);
  border-radius: 20px;
  box-shadow:
    0 28px 76px rgba(0, 0, 0, 0.40),
    0 0 0 1px rgba(105,125,200,0.048),
    inset 0 1px 0 rgba(255, 255, 255, 0.048),
    inset 0 -1px 0 rgba(0,0,0,0.22);
}

/* =========================
   Change Password Settings Page
========================= */

.pwd-page {
  padding: 72px 56px 80px;
  position: relative;
  overflow: hidden;
}

.pwd-page::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 1100px;
  height: 600px;
  background: radial-gradient(ellipse at 50% 0%, rgba(91,140,255,0.22) 0%, rgba(91,140,255,0.06) 50%, transparent 72%);
  pointer-events: none;
  z-index: 0;
}

.pwd-inner {
  max-width: 1080px;
  margin: 0 auto;
  position: relative;
  z-index: 1;
}

/* ── Page header ── */
.pwd-header {
  margin-bottom: 36px;
}

.pwd-eyebrow {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(169, 190, 255, 0.72);
  margin: 0 0 14px;
}

.pwd-title {
  font-size: 3.25rem;
  font-weight: 800;
  letter-spacing: -0.035em;
  margin: 0 0 12px;
  background: linear-gradient(120deg, #ffffff 0%, #a8bcff 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.pwd-subtitle {
  font-size: 1.0625rem;
  color: rgba(255, 255, 255, 0.64);
  margin: 0;
}

/* ── Two-column body ── */
.pwd-body {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 28px;
  align-items: start;
}

/* ── Form panel ── */
.pwd-form-panel {
  background: linear-gradient(160deg, rgba(18,22,46,0.988) 0%, rgba(10,13,30,0.994) 100%);
  border: 1px solid rgba(155,170,215,0.18);
  border-top-color: rgba(200,212,248,0.24);
  border-radius: 22px;
  padding: 2.5rem 3.5rem;
  box-shadow:
    0 24px 72px rgba(0, 0, 0, 0.56),
    0 0 0 1px rgba(130, 155, 255, 0.06),
    inset 0 1px 0 rgba(200, 212, 255, 0.06);
}

/* Richer button treatment inside form panel */
.pwd-form-panel .auth-btn {
  background: linear-gradient(180deg, #4d6ef8 0%, #3855e0 52%, #2c46cc 100%);
  border-color: rgba(170, 185, 255, 0.34);
  box-shadow: 0 14px 32px rgba(42, 64, 188, 0.24), inset 0 1px 0 rgba(255,255,255,0.12), inset 0 -1px 0 rgba(0,0,0,0.16);
}

.pwd-form-panel .auth-btn:hover {
  background: linear-gradient(180deg, #5d7eff 0%, #4464f0 52%, #3552d8 100%);
  border-color: rgba(190, 202, 255, 0.46);
  box-shadow: 0 16px 36px rgba(42, 64, 188, 0.28), inset 0 1px 0 rgba(255,255,255,0.15), inset 0 -1px 0 rgba(0,0,0,0.16);
  transform: translateY(var(--lift-sm));
}

.pwd-form-error {
  font-size: 0.875rem;
  padding: 11px 16px;
  border-radius: 10px;
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.24);
  color: rgba(252, 165, 165, 0.92);
  margin-bottom: 1.5rem;
  line-height: 1.5;
}

/* ── Footer links ── */
.pwd-footer-links {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 1.375rem;
  padding-top: 1.125rem;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.pwd-footer-link {
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.58);
  text-decoration: none;
  letter-spacing: 0.01em;
  transition: color 0.18s ease, text-decoration-color 0.18s ease;
  text-decoration-color: transparent;
}

.pwd-footer-link:hover {
  color: rgba(255, 255, 255, 0.86);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(255, 255, 255, 0.32);
}

.pwd-footer-sep {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.20);
  user-select: none;
}

/* ── Recovery page eyebrow: slightly more luminous than default ── */
.pwr-body .pwd-eyebrow {
  color: rgba(169, 190, 255, 0.82);
}

/* ── Reset password single-column body ── */
.pwr-body {
  max-width: 620px;
  margin: 0 auto;
}

.pwr-body .pwd-header {
  margin-bottom: 20px;
}

.pwr-body .pwd-form-panel {
  padding: 3rem 4rem;
  /* slightly richer top-edge presence for recovery card */
  border-top-color: rgba(169, 190, 255, 0.22);
  box-shadow:
    0 24px 72px rgba(0, 0, 0, 0.65),
    0 0 0 1px rgba(91, 140, 255, 0.14),
    0 -1px 0 0 rgba(169, 190, 255, 0.16),
    inset 0 1px 0 rgba(169, 190, 255, 0.10);
}

/* ── "Check your email" confirmation ── */
.pwd-done-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  margin: 0 auto 1.625rem;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 30%, rgba(91, 140, 255, 0.28) 0%, rgba(56, 85, 224, 0.14) 100%);
  border: 1px solid rgba(169, 190, 255, 0.38);
  box-shadow:
    0 0 0 6px rgba(91, 140, 255, 0.07),
    0 4px 20px rgba(91, 140, 255, 0.22);
  color: rgba(180, 188, 255, 0.95);
}

.pwd-done-body {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.64);
  text-align: center;
  line-height: 1.65;
  margin-bottom: 0.25rem;
  max-width: 38ch;
  margin-left: auto;
  margin-right: auto;
}

/* Footer links richer indigo hover on recovery pages */
.pwr-body .pwd-footer-link:hover {
  color: rgba(180, 188, 255, 0.92);
  text-decoration-color: rgba(169, 190, 255, 0.40);
}

/* ── Security aside ── */
.pwd-aside {
  background: linear-gradient(145deg, rgba(91, 140, 255, 0.13) 0%, rgba(56, 85, 224, 0.07) 100%);
  border: 1px solid rgba(91, 140, 255, 0.28);
  border-radius: 20px;
  padding: 1.75rem 2.25rem;
  box-shadow: 0 8px 32px rgba(91, 140, 255, 0.10), inset 0 1px 0 rgba(169, 190, 255, 0.09);
}

.pwd-aside-label {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(169, 190, 255, 0.76);
  margin: 0 0 14px;
}

.pwd-aside-list {
  list-style: none;
  padding: 0;
  margin: 0 0 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pwd-aside-list li {
  position: relative;
  padding-left: 18px;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.70);
  line-height: 1.55;
}

.pwd-aside-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 8px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(169, 190, 255, 0.70);
}

.pwd-aside-divider {
  height: 1px;
  background: rgba(91, 140, 255, 0.28);
  margin: 0 0 14px;
}

.pwd-aside-help {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.52);
  line-height: 1.65;
  margin: 0;
}

.pwd-aside-link {
  color: rgba(169, 190, 255, 0.88);
  text-decoration: none;
  transition: color 0.15s ease;
}

.pwd-aside-link:hover {
  color: rgba(169, 190, 255, 1.0);
}

/* ── Responsive ── */
@media (max-width: 768px) {
  .pwd-body {
    grid-template-columns: 1fr;
  }

  .pwd-aside {
    order: -1; /* show above form on mobile? No, keep below */
  }
}

@media (max-width: 560px) {
  .pwd-page {
    padding: 60px 20px 88px;
  }

  .pwd-title {
    font-size: 2.25rem;
  }

  .pwd-form-panel {
    padding: 2.25rem 1.75rem;
    border-radius: 18px;
  }

  .pwr-body .pwd-form-panel {
    padding-block: clamp(28px, 2.25rem, 48px);
    padding-inline: clamp(20px, 1.75rem, 32px);
  }
}

/* Heading */
.auth-title{
  text-align: center;
  font-size: 1.75rem;
  font-weight: 800;
  color: #ffffff;
  margin: 0 0 1.5rem;
  letter-spacing: -0.02em;
}

/* Block-level non-field error banner */
.auth-error--block {
  padding: 11px 16px;
  border-radius: 10px;
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.24);
  color: rgba(252, 165, 165, 0.92);
  margin-bottom: 1.25rem;
  font-size: 0.875rem;
  line-height: 1.5;
}

/* Select field */
.auth-field select {
  padding: 0.6rem 0.85rem;
  background: linear-gradient(180deg, rgba(10,13,28,0.94), rgba(7,10,20,0.96));
  border: 1px solid rgba(125,142,198,0.27);
  border-radius: 8px;
  color: rgba(255,255,255,0.95);
  font-size: 0.95rem;
  outline: none;
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.auth-field select option {
  background: #0b1118;
  color: rgba(255,255,255,0.9);
}

.auth-field select + select {
  margin-top: 0;
}

.auth-field .date-select {
  flex: 1;
  min-width: 0;
}

.auth-field:has(select[name*='date']) {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.auth-field:has(select[name*='date']) label {
  width: 100%;
  margin-bottom: 4px;
}

.auth-field:has(select[name*='date']) select {
  flex: 1;
  min-width: 80px;
}

.date-row {
  display: flex;
  gap: 10px;
}

.date-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
}

.date-label {
  font-size: 0.78rem;
  color: rgba(255,255,255,0.5);
  font-weight: 500;
}

/* Error message */
.auth-error{
  font-size: 13px;
  color: var(--danger);
  margin: -0.25rem 0 0.75rem;
}

/* Inline banner for Django messages on password-change page */
.auth-change-msg {
  font-size: 0.875rem;
  padding: 11px 16px;
  border-radius: 10px;
  margin-bottom: 1.25rem;
  line-height: 1.5;
}

.auth-change-msg--success {
  background: rgba(48, 152, 116, 0.11);
  border: 1px solid rgba(88, 188, 145, 0.25);
  color: rgba(144, 218, 178, 0.92);
}

.auth-change-msg--error,
.auth-change-msg--warning {
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.24);
  color: rgba(252, 165, 165, 0.92);
}

.auth-change-msg--info {
  background: rgba(125, 145, 210, 0.070);
  border: 1px solid rgba(125, 145, 210, 0.20);
  color: rgba(200, 212, 250, 0.92);
}

/* Bottom links row */
.auth-links{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 1.25rem;
  font-size: 14px;
  color: rgba(225,232,255,0.68);
}

.auth-links a{
  color: rgba(178,196,255,0.90);
  text-decoration: none;
  font-weight: 600;
}

.auth-links a:hover{
  color: rgba(210,220,255,0.98);
}

.auth-subtitle{
  color: rgba(220,228,255,0.62);
  font-size: 0.9rem;
  text-align: center;
  margin: -0.5rem 0 1.5rem;
  line-height: 1.5;
}

.auth-help{
  font-size: 0.78rem;
  color: rgba(255,255,255,0.4);
  line-height: 1.4;
}

.account-subscription-status {
  list-style: none;
}

.account-subscription-status a,
.account-subscription-status span,
.account-subscription-status {
  display: block;
  width: 100%;
  padding: 0.6rem 1.2rem;
  border-radius: 10px;
  border: 1px solid rgba(74, 222, 128, 0.3);
  background: rgba(74, 222, 128, 0.08);
  color: #4ade80;
  font-weight: 600;
  font-size: 0.95rem;
  text-align: center;
}

/* =========================
   Date of Birth Row
========================= */
.date-birth-field .date-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.date-birth-field .date-row select {
  width: 100%;
}

/* ── Landing Page ─────────────────────────────────────── */

.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 96px 24px 72px;
  text-align: center;
  position: relative;
  overflow: hidden;
}

.hero::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 700px;
  height: 400px;
  background: radial-gradient(ellipse, rgba(91,140,255,0.10), transparent 70%);
  filter: blur(60px);
  z-index: 0;
  pointer-events: none;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(2,6,23,0) 0%,
    rgba(2,6,23,0.3) 100%
  );
  z-index: 0;
  pointer-events: none;
}

.hero > * {
  position: relative;
  z-index: 1;
}

.hero-inner {
  max-width: 680px;
}

.hero-headline,
.hero-title {
  font-size: 3.5rem;
  font-weight: 700;
  line-height: 1.15;
  margin-bottom: 20px;
  letter-spacing: -0.02em;
  background: linear-gradient(to right, #ffffff, #cbd5f5);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.hero-sub,
.hero-subtext {
  font-size: 1.125rem;
  color: #94a3b8;
  max-width: 640px;
  margin: 0 auto 36px;
  line-height: 1.6;
}

.hero-cta,
.primary-btn {
  display: inline-block;
  background-color: #5b8cff;
  color: #fff;
  padding: 12px 28px;
  border-radius: 12px;
  font-weight: 500;
  font-size: 1rem;
  text-decoration: none;
  transition: all 0.2s ease;
  box-shadow: 0 10px 30px rgba(91, 140, 255, 0.2);
}

.hero-cta:hover,
.primary-btn:hover {
  background-color: #78aeff;
  color: #fff;
  transform: translateY(-2px);
  box-shadow: 0 15px 40px rgba(91, 140, 255, 0.35);
}

.hero-cta:active,
.primary-btn:active {
  transform: translateY(0);
  box-shadow: 0 5px 15px rgba(91, 140, 255, 0.25);
}

.landing-section,
.section {
  padding: 80px 24px;
  text-align: center;
}

.landing-section-inner {
  max-width: 640px;
  margin: 0 auto;
}

.landing-section h2,
.value-title {
  font-size: 2.25rem;
  font-weight: 600;
  max-width: 600px;
  margin: 0 auto 16px;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.landing-section p,
.value-subtext {
  font-size: 1.0625rem;
  color: #94a3b8;
  line-height: 1.7;
  margin-top: 1rem;
  max-width: 500px;
  margin-left: auto;
  margin-right: auto;
}

.landing-features {
  padding: 80px 24px;
}

.landing-features-inner {
  max-width: 960px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 24px;
}

.feature-card {
  background: rgba(15, 23, 42, 0.6);
  backdrop-filter: blur(10px);
  border: 1px solid #1e293b;
  border-radius: 16px;
  padding: 28px 24px;
  text-align: center;
  transition: all 0.25s ease;
}

.feature-card:nth-child(2) {
  transform: translateY(-4px);
}

.feature-card:nth-child(3) {
  transform: translateY(-2px);
}

.feature-card:hover {
  transform: translateY(var(--lift-lg));
  background: rgba(15, 23, 42, 0.85);
  border-color: rgba(91, 140, 255, 0.4);
  box-shadow:
    0 10px 30px rgba(91, 140, 255, 0.15),
    0 0 0 1px rgba(91, 140, 255, 0.2);
}

.feature-icon,
.icon-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  background: rgba(91, 140, 255, 0.1);
  border-radius: 12px;
  margin: 0 auto 16px;
  color: #5b8cff;
  padding: 12px;
}

.feature-card h3 {
  font-size: 1.125rem;
  font-weight: 600;
  margin-bottom: 8px;
}

.feature-card p {
  font-size: 0.9375rem;
  color: var(--text-muted, #aaa);
  line-height: 1.6;
}

.landing-cta {
  padding: 64px 24px 80px;
  text-align: center;
}

.landing-cta-inner {
  max-width: 480px;
  margin: 0 auto;
}

.landing-cta-note {
  font-size: 0.9375rem;
  color: var(--text-muted, #aaa);
  margin-bottom: 20px;
}

/* ── Footer ───────────────────────────────────────────── */

/* ======================
   Global Site Footer
====================== */
.site-footer {
  position: relative;
  background: rgba(2,4,18,0.96);
  border-top: 1px solid rgba(130,148,215,0.10);
}

/* Subtle cool blue glow along the top separation line */
.site-footer::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 50%;
  transform: translateX(-50%);
  width: 48%;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(140,162,240,0.22) 28%,
    rgba(155,178,248,0.32) 50%,
    rgba(140,162,240,0.22) 72%,
    transparent 100%
  );
}

/* Legacy .footer class kept for safety */
.footer {
  padding: 1.75rem 48px;
  font-size: 0.8125rem;
  color: rgba(255,255,255,0.30);
  background: transparent;
  border-top: 1px solid rgba(255,255,255,0.08);
}

/* ── Coming Soon Page ─────────────────────────────────── */

.coming-soon-page {
  padding: 80px 40px;
  max-width: 680px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.coming-soon-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.coming-soon-exam {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.28);
  margin: 0 0 18px;
}

.coming-soon-title {
  font-size: 2.25rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  margin: 0 0 32px;
  background: linear-gradient(to right, #ffffff, #cbd5f5);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.coming-soon-message {
  font-size: 1rem;
  line-height: 1.7;
  color: rgba(255,255,255,0.52);
  margin: 0 0 10px;
  max-width: 480px;
}

.coming-soon-submessage {
  font-size: 0.9375rem;
  color: rgba(255,255,255,0.35);
  margin: 0 0 40px;
}

.coming-soon-btn {
  display: inline-block;
  padding: 12px 28px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 10px;
  font-size: 0.9375rem;
  font-weight: 600;
  color: rgba(255,255,255,0.88);
  text-decoration: none;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
  margin-bottom: 24px;
}

.coming-soon-btn:hover {
  background: rgba(255,255,255,0.11);
  border-color: rgba(255,255,255,0.22);
  color: #fff;
}

.coming-soon-note {
  font-size: 0.8125rem;
  color: rgba(255,255,255,0.22);
  margin: 0;
}

.site-footer-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 52px 60px 0;
}

/* ── Main 3-column grid ── */
.ft-main {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 52px;
  padding-bottom: 40px;
}

/* ── Brand column ── */
.ft-brand {
  display: flex;
  flex-direction: column;
}

.ft-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: rgba(255,255,255,0.92);
  font-weight: 700;
  font-size: 18.5px;
  letter-spacing: -0.35px;
  margin-bottom: 13px;
  transition: opacity 0.18s ease;
}

.ft-logo:hover {
  opacity: 0.74;
}

.ft-logo-img {
  height: 30px;
  width: auto;
  display: block;
  object-fit: contain;
}

.ft-logo-text {
  line-height: 1;
}

.ft-tagline {
  font-size: 14px;
  line-height: 1.65;
  color: rgba(210,218,240,0.56);
  max-width: 310px;
  margin: 0;
}

/* ── Link columns ── */
/* 12px, the floor of the size ladder (was 11px, mobile audit 2026-09-25).
   The line box stays 17.6px (12 x 1.4667, it was 11 x the inherited 1.6), so
   the footer keeps its height and only the headings' letters change. Same
   change in site-footer.css. */
.ft-col-heading {
  font-size: var(--nb-text-xs, 12px);
  line-height: 1.4667;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: rgba(190,205,240,0.64);
  margin: 0 0 16px;
}

.ft-contact-intro {
  font-size: 13.5px;
  color: rgba(200,210,240,0.44);
  margin: -6px 0 11px;
  line-height: 1;
}

.ft-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ft-link {
  font-size: 14.5px;
  font-weight: 400;
  color: rgba(210,220,255,0.62);
  text-decoration: none;
  letter-spacing: 0em;
  transition: color 0.18s ease;
}

.ft-link:hover {
  color: rgba(190,215,255,0.92);
}

/* ── Legal row ── */
.ft-legal {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid rgba(130,148,215,0.12);
  padding: 18px 0 24px;
}

.ft-legal-copy {
  font-size: 13px;
  color: rgba(200,212,240,0.52);
}

.ft-legal-links {
  display: flex;
  align-items: center;
  gap: 10px;
}

.ft-legal-link {
  font-size: 13px;
  color: rgba(205,215,245,0.50);
  text-decoration: none;
  transition: color 0.18s ease;
}

.ft-legal-link:hover {
  color: rgba(180,205,255,0.78);
}

.ft-legal-sep {
  font-size: 13px;
  color: rgba(190,200,235,0.24);
  user-select: none;
}

/* ── Responsive ── */
@media (max-width: 768px) {
  .site-footer-inner {
    padding: 44px 32px 0;
  }
  /* minmax(0, 1fr): a 1fr track never shrinks below its min-content (the
     logo row and the email address), which at 200% zoom on a small phone
     held the page 26px wider than the window. */
  .ft-main {
    grid-template-columns: minmax(0, 1fr);
    gap: 30px;
    padding-bottom: 32px;
  }
  .ft-tagline {
    max-width: 100%;
  }
}

@media (max-width: 520px) {
  .site-footer-inner {
    padding: 36px 20px 0;
  }
  .ft-legal {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding-bottom: 28px;
  }
  /* Rows that could not break: only a column narrower than the words uses
     these, so a phone at its normal text size lays out exactly as before.
     The name is never cut (under 176px of layout it steps down with the
     window, the mark above it); the legal links wrap as whole links. */
  .ft-logo {
    flex-wrap: wrap;
    max-width: 100%;
    font-size: min(18.5px, 10.5vw);
  }
  .ft-legal-links {
    flex-wrap: wrap;
  }
  .ft-link,
  .ft-legal-link {
    overflow-wrap: anywhere;
  }
}
/* Footer tap targets on every touch screen (mobile audit 2026-09-25). The
   520px tap-target block in the Utility section reached only phones held
   upright, so tablets and a phone on its side got 19 to 20px links and a 30px
   logo, and Log In stayed 40px wide.
   44 by 44 on a coarse pointer; the list's gap and the global li margin fold
   into the rows, so a column steps one 44px row at a time. A fine pointer
   never matches. It sits after the footer's own rules because .ft-links sets
   its gap here too. Same block in site-footer.css (two copies, one component). */
@media (pointer: coarse) {
  .ft-logo {
    min-height: 44px;
  }
  .ft-links {
    gap: 0;
  }
  .ft-links li {
    margin-bottom: 0;
  }
  .ft-link,
  .ft-legal-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    min-width: 44px;
  }
}

/* =============================================================
   Landing Page (lp-* namespace)
   All classes here are scoped to index.html via lp- prefix.
   No conflict with existing .hero, .feature-card, .section, etc.
============================================================= */

/* ── Atmosphere overlay ──────────────────────────────────── */
.lp-atmosphere {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    /* Crisp white crown — editorial light source */
    radial-gradient(ellipse 90% 44% at 50% 0%, rgba(255,255,255,0.17) 0%, transparent 50%),
    /* Indigo focal accent — deeper, richer sky */
    radial-gradient(ellipse 76% 54% at 50% 0%, rgba(72,84,210,0.30) 0%, transparent 58%),
    /* Indigo right shoulder accent */
    radial-gradient(ellipse 48% 36% at 84% 8%, rgba(56,85,224,0.12) 0%, transparent 42%),
    /* Deep navy lower-left counterpoint */
    radial-gradient(ellipse 40% 26% at 14% 68%, rgba(44,70,204,0.08) 0%, transparent 42%),
    /* Deep neutral midnight base */
    linear-gradient(180deg, #0b0d1e 0%, #080a18 100%);
}

/* Blurred indigo-navy hero glow — richer, more premium focal depth */
.lp-atmosphere::before {
  content: "";
  position: fixed;
  top: -12vh;
  left: 50%;
  transform: translateX(-50%);
  width: 72%;
  height: 66vh;
  background: radial-gradient(ellipse at center, rgba(64,80,200,0.26) 0%, transparent 58%);
  filter: blur(80px);
  pointer-events: none;
}

/* Blurred deep-navy undertone — very subtle lower warmth */
.lp-atmosphere::after {
  content: "";
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translateX(-50%);
  width: 65%;
  height: 55vh;
  background: radial-gradient(ellipse at center, rgba(44,70,204,0.09) 0%, transparent 65%);
  filter: blur(90px);
  pointer-events: none;
}

/* ── Scroll animations ───────────────────────────────────── */
/* Default: visible. JS adds html.lp-animations-ready once it has stripped
   .lp-animate from already-visible elements, so only below-fold elements are
   hidden for entrance. The reveal transition is scoped under
   html.lp-animations-ready so its specificity (0,2,1) beats per-card
   transition: rules like .lp-step-card / .lp-proof (0,1,0),
   which would otherwise win the cascade and kill the opacity/transform fade.
   JS removes .lp-animate from each element once it has finished revealing,
   so per-card hover transitions resume at their natural speed. */
html.lp-animations-ready .lp-animate {
  transition:
    opacity 760ms cubic-bezier(0.22, 1, 0.36, 1),
    transform 760ms cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: var(--lp-reveal-delay, 0ms);
  will-change: opacity, transform;
}

html.lp-animations-ready .lp-animate:not(.lp-animate--visible) {
  opacity: 0;
  transform: translateY(20px);
}

html.lp-animations-ready .lp-animate.lp-animate--visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html.lp-animations-ready .lp-animate,
  html.lp-animations-ready .lp-animate:not(.lp-animate--visible),
  html.lp-animations-ready .lp-animate.lp-animate--visible {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0ms;
    will-change: auto;
  }
}

/* ════ Homepage motion language ═══════════════════════════
   Tokens + grouped reveal + hero choreography. The uniform
   .lp-animate fade-up no longer appears on the homepage; other
   pages keep it untouched. Everything below is gated on the
   JS-added html.lp-animations-ready class: no JS, no hiding. */
:root {
  --m-fast: 140ms;
  --m-state: 220ms;
  --m-enter: 560ms;
  --m-hero: 700ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-hero: var(--ease-expo);
  --rise: 12px;
}

/* Grouped reveal — stagger within a group only (cards, lists) */
html.lp-animations-ready .lp-reveal {
  transition:
    opacity var(--m-enter) var(--ease-out),
    transform var(--m-enter) var(--ease-out);
  transition-delay: var(--lp-reveal-delay, 0ms);
  will-change: opacity, transform;
}

html.lp-animations-ready .lp-reveal:not(.lp-reveal--visible) {
  opacity: 0;
  transform: translateY(var(--rise));
}

html.lp-animations-ready .lp-reveal.lp-reveal--visible {
  opacity: 1;
  transform: none;
}

/* Hero choreography — the page's one orchestrated load moment */
@keyframes lp-hero-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@keyframes lp-hero-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

html.lp-animations-ready .lp-hero .lp-headline {
  animation: lp-hero-in var(--m-hero) var(--ease-hero) both;
}

html.lp-animations-ready .lp-hero .lp-subline {
  animation: lp-hero-in var(--m-hero) var(--ease-hero) 90ms both;
}

html.lp-animations-ready .lp-hero .lp-hero-ctas,
html.lp-animations-ready .lp-hero .lp-free-note {
  animation: lp-hero-in var(--m-hero) var(--ease-hero) 180ms both;
}

html.lp-animations-ready .lp-hero .lp-showcase-wrap {
  animation: lp-hero-fade var(--m-hero) var(--ease-out) 280ms both;
}

html.lp-animations-ready .lp-hero .lp-eyebrow {
  animation: lp-hero-fade var(--m-hero) var(--ease-out) 360ms both;
}

/* Hero sheen: the (now one-shot) sweep waits for the JS-gated choreography,
   then fires once. Both rules out-rank the base .lp-eyebrow::after shorthand
   on specificity — they must stay (0,2,1)+ or the base 2s delay wins. */
.lp-hero .lp-eyebrow::after {
  animation-play-state: paused;
}

html.lp-animations-ready .lp-hero .lp-eyebrow::after {
  animation-play-state: running;
  animation-delay: 1.2s;
}

/* Homepage pricing panel: the shared include only renders .lp-animate when
   passed pricing_card_animated (homepage). Neutralized so the panel simply
   exists; id="pricing" is unique to index.html. */
html.lp-animations-ready #pricing .lp-animate,
html.lp-animations-ready #pricing .lp-animate:not(.lp-animate--visible) {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Focus rings that were missing entirely (chrome + homepage links) */
.logo:focus-visible,
.ft-logo:focus-visible,
.ft-link:focus-visible,
.ft-legal-link:focus-visible,
.lp-pricing-secondary-cta:focus-visible,
.google-btn:focus-visible,
.auth-modal-footer-link:focus-visible,
.welcome-btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html.lp-animations-ready .lp-reveal,
  html.lp-animations-ready .lp-reveal:not(.lp-reveal--visible),
  html.lp-animations-ready .lp-reveal.lp-reveal--visible {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0ms;
    will-change: auto;
  }

  html.lp-animations-ready .lp-hero .lp-headline,
  html.lp-animations-ready .lp-hero .lp-subline,
  html.lp-animations-ready .lp-hero .lp-hero-ctas,
  html.lp-animations-ready .lp-hero .lp-free-note,
  html.lp-animations-ready .lp-hero .lp-showcase-wrap,
  html.lp-animations-ready .lp-hero .lp-eyebrow {
    animation: none;
  }

  .lp-cta-primary:active,
  .lp-plan-btn:active {
    transform: none;
    transition: none;
  }
}

/* ── Hero ─────────────────────────────────────────────────── */
.lp-hero {
  padding: clamp(44px,4vw,68px) 48px 40px;
  position: relative;
}

.lp-hero-inner {
  max-width: 1360px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1.18fr;
  gap: 52px;
  align-items: center;
}

.lp-hero-inner > * {
  min-width: 0;
}

.lp-hero-content {
  max-width: none;
  margin: 0;
}

.lp-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 5px 14px 5px 5px;
  border-radius: var(--r-sm);
  background: rgba(255,255,255,0.052);
  border: 1px solid rgba(185,196,230,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.052);
  font-size: 0.8125rem;
  font-weight: 620;
  color: rgba(240,244,255,0.90);
  margin-bottom: 28px;
  letter-spacing: 0.01em;
  /* Sheen animation setup */
  position: relative;
  overflow: hidden;
}

@keyframes lp-pill-sheen {
  0%    { transform: translateX(-160%); }
  22%   { transform: translateX(260%); }
  100%  { transform: translateX(260%); }
}

/* Soft left-to-right glass sheen sweep */
.lp-eyebrow::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 45%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255,255,255,0.07) 30%,
    rgba(255,255,255,0.13) 50%,
    rgba(255,255,255,0.07) 70%,
    transparent 100%
  );
  transform: translateX(-160%);
  animation: lp-pill-sheen 6.5s ease-in-out 2s 1 forwards;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .lp-eyebrow::after {
    animation: none;
  }
}

/* Leading state tile — miniature of the site's icon-tile anatomy (pg-bcard
   tiles, cn-badge). Free: the chapter numeral "1" (the mark IS the copy);
   premium: the gem. Tokens resolve per theme; light only overrides the
   premium tile surface. */
.lp-eyebrow-tile {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  color: var(--text-link);
  font-size: 11px;
  font-weight: 750;
  line-height: 1;
}

.lp-eyebrow-tile svg {
  display: block;
}

/* Premium: the named premium tokens (:root above) — same dialect as the
   paywall gate badge and the pricing-card label */
.lp-eyebrow--premium {
  background: var(--premium-pill-bg);
  border-color: var(--premium-border);
  color: var(--premium-pill-text);
}

.lp-eyebrow--premium .lp-eyebrow-tile {
  background: var(--premium-pill-bg);
  border-color: var(--premium-border);
  color: var(--premium-pill-text);
}

.lp-headline {
  font-size: clamp(3.25rem, 6.2vw, 5.75rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.044em;
  color: #ffffff;
  margin: 0 0 26px;
  overflow: visible;
}

.lp-headline-line {
  display: block;
  white-space: nowrap;
}

.lp-headline-accent {
  display: block;
  background: linear-gradient(to right, #f0f4ff 0%, #b8cfff 32%, #78aeff 68%, #4e96f8 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  padding-bottom: 0.1em;
}

.lp-subline {
  font-size: 1.0625rem;
  color: rgba(230,236,255,0.84);
  line-height: 1.70;
  margin: 0 0 36px;
  max-width: 500px;
}

.lp-hero-ctas {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

/* Hero-scoped CTA overrides — calibrated for hero context */
.lp-hero-ctas .lp-cta-primary {
  padding: 15px 44px;
  min-width: 220px;
  font-size: 0.9375rem;
}

.lp-hero-ctas .lp-cta-ghost {
  padding: 13px 22px;
  font-size: 0.9375rem;
}

/* ── Buttons ─────────────────────────────────────────────── */
.lp-cta-primary {
  display: inline-block;
  background: linear-gradient(165deg, #4d6ef8 0%, #3855e0 46%, #2840c8 100%);
  border: 1px solid rgba(110,138,248,0.32);
  color: #fff;
  padding: 17px 56px;
  min-width: 260px;
  text-align: center;
  border-radius: 11px;
  font-weight: 700;
  font-size: 1.0625rem;
  text-decoration: none;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  box-shadow:
    0 6px 22px rgba(42,64,188,0.38),
    0 1px 4px rgba(0,0,0,0.24),
    inset 0 1px 0 rgba(255,255,255,0.20),
    inset 0 -1px 0 rgba(0,0,0,0.14);
  letter-spacing: 0.01em;
}

.lp-cta-primary:hover {
  color: #fff;
  transform: translateY(var(--lift-sm));
  border-color: rgba(130,158,255,0.44);
  box-shadow:
    0 10px 28px rgba(42,64,188,0.46),
    0 2px 6px rgba(0,0,0,0.24),
    inset 0 1px 0 rgba(255,255,255,0.22),
    inset 0 -1px 0 rgba(0,0,0,0.14);
}

.lp-cta-primary:active {
  transform: translateY(0) scale(0.985);
  transition: transform var(--m-fast) var(--ease-out);
}

.lp-cta-primary:focus-visible {
  outline: 2px solid rgba(120,158,255,0.80);
  outline-offset: 3px;
}

.lp-cta-block {
  display: block;
  width: 100%;
  text-align: center;
}

.lp-cta-ghost {
  display: inline-block;
  color: rgba(255,255,255,0.76);
  padding: 15px 28px;
  border-radius: 12px;
  font-weight: 500;
  font-size: 1rem;
  text-decoration: none;
  border: 1px solid rgba(100,128,242,0.28);
  transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease;
}

.lp-cta-ghost:hover {
  color: rgba(255,255,255,0.88);
  border-color: rgba(255,255,255,0.22);
  background: rgba(255,255,255,0.05);
}

.lp-cta-ghost:focus-visible {
  outline: 2px solid rgba(150,160,255,0.80);
  outline-offset: 3px;
}

.lp-free-note {
  font-size: 0.875rem;
  color: rgba(220,228,255,0.54);
  margin: 0;
}

.lp-hero-content .lp-free-note {
  text-align: left;
}

.lp-free-note--spaced {
  margin-top: 14px;
}

/* ── Product Preview ─────────────────────────────────────── */
.lp-product-preview {
  max-width: none;
  margin: 0;
  position: relative;
}

/* In hero two-column: hide sidebar so main content fills the full card width */
.lp-hero-inner .lp-preview-sidebar {
  display: none;
}

.lp-product-preview::before {
  content: "";
  position: absolute;
  inset: -90px -60px;
  background: radial-gradient(ellipse at 50% 50%, rgba(68,78,185,0.12) 0%, transparent 62%);
  filter: blur(80px);
  z-index: 0;
  pointer-events: none;
}

.lp-preview-card {
  display: flex;
  background: rgba(11,11,13,0.97);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 20px;
  overflow: hidden;
  box-shadow:
    0 52px 120px rgba(0,0,0,0.72),
    0 0 0 1px rgba(255,255,255,0.07) inset,
    0 0 140px rgba(68,78,185,0.16);
  min-height: 480px;
  position: relative;
  z-index: 1;
}

.lp-preview-sidebar {
  width: 240px;
  flex-shrink: 0;
  background: rgba(7,7,8,0.99);
  border-right: 1px solid rgba(255,255,255,0.08);
  padding: 22px 16px;
  display: flex;
  flex-direction: column;
}

.lp-preview-subject {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid rgba(255,255,255,0.05);
}

.lp-preview-subject-icon {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: linear-gradient(135deg, #10b981, #059669);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: white;
  flex-shrink: 0;
}

.lp-preview-subject-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: rgba(255,255,255,0.88);
  line-height: 1.2;
}

.lp-preview-subject-board {
  font-size: 0.6875rem;
  color: rgba(255,255,255,0.32);
  margin-top: 2px;
}

.lp-preview-chapters {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
}

.lp-chapter-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border-radius: 7px;
  font-size: 0.8rem;
  color: rgba(255,255,255,0.52);
  border: 1px solid transparent;
}

.lp-chapter-item.lp-chapter-active {
  background: rgba(91,140,255,0.14);
  border-color: rgba(91,140,255,0.30);
  color: rgba(255,255,255,0.94);
}

.lp-chapter-item.lp-chapter-done {
  color: rgba(255,255,255,0.32);
}

.lp-chapter-check {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(34,197,94,0.15);
  color: #22c55e;
  font-size: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.lp-chapter-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid #5b8cff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  position: relative;
}

.lp-chapter-dot::after {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #5b8cff;
  position: absolute;
}

.lp-chapter-circle {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.14);
  flex-shrink: 0;
  display: inline-block;
}

.lp-preview-progress {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.05);
}

.lp-progress-label {
  font-size: 0.6875rem;
  color: rgba(255,255,255,0.32);
  margin-bottom: 8px;
}

.lp-progress-bar {
  height: 5px;
  background: rgba(255,255,255,0.08);
  border-radius: 99px;
  overflow: hidden;
  margin-bottom: 6px;
}

.lp-progress-fill {
  height: 100%;
  width: 18%;
  background: linear-gradient(to right, #5b8cff, #5b8cff);
  border-radius: 99px;
}

.lp-progress-text {
  font-size: 0.6875rem;
  color: rgba(255,255,255,0.28);
}

/* Preview main area */
.lp-preview-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.lp-panel-title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: rgba(255,255,255,0.95);
  margin: 0 0 12px;
}

.lp-panel-body {
  font-size: 0.9rem;
  color: rgba(255,255,255,0.68);
  line-height: 1.65;
  margin: 0 0 18px;
}

.lp-particle-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 16px;
}

.lp-particle-card {
  background: rgba(255,255,255,0.055);
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 8px;
  padding: 14px 12px;
}

.lp-particle-name {
  font-size: 0.875rem;
  font-weight: 700;
  color: #a9beff;
  margin-bottom: 4px;
}

.lp-particle-detail {
  font-size: 0.75rem;
  color: rgba(255,255,255,0.54);
}

.lp-exam-tip {
  padding: 14px 16px;
  background: rgba(251,191,36,0.10);
  border: 1px solid rgba(251,191,36,0.25);
  border-radius: 8px;
}

.lp-exam-tip-label {
  font-size: 0.75rem;
  font-weight: 700;
  color: #fbbf24;
  margin-bottom: 6px;
  letter-spacing: 0.02em;
}

.lp-exam-tip p {
  font-size: 0.875rem;
  color: rgba(255,255,255,0.72);
  line-height: 1.55;
  margin: 0;
}

/* Questions panel */
.lp-question-block {
  background: rgba(255,255,255,0.025);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 10px;
  padding: 16px;
}

.lp-question-text {
  font-size: 0.875rem;
  color: rgba(255,255,255,0.62);
  margin: 0 0 12px;
  line-height: 1.55;
}

.lp-answer-area {
  background: rgba(0,0,0,0.25);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 8px;
  padding: 12px;
  font-size: 0.8125rem;
  color: rgba(255,255,255,0.22);
  min-height: 72px;
}

/* Video panel */
.lp-video-placeholder {
  background: rgba(255,255,255,0.02);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 160px;
  gap: 14px;
}

.lp-play-btn {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: #5b8cff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.2s ease, opacity 0.2s ease;
  border: none;
}

.lp-play-btn:hover {
  transform: scale(1.08);
  opacity: 0.88;
}

.lp-play-btn svg {
  margin-left: 3px;
}

.lp-video-label {
  font-size: 0.8125rem;
  color: rgba(255,255,255,0.32);
  margin: 0;
}

/* Summary panel */
.lp-summary-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.lp-summary-list li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 0.9rem;
  color: rgba(255,255,255,0.72);
  margin: 0;
  line-height: 1.5;
}

.lp-summary-list li::before {
  content: "\2713";
  color: #22c55e;
  font-weight: 700;
  font-size: 0.875rem;
  flex-shrink: 0;
  margin-top: 1px;
}

/* ── Hero Showcase — 4-step exam prep method ─────────────── */
/* ─────────────────────────────────────────────────────────────
   Per-accent CSS vars — one palette token per resource type.
   Stages and inline cards inherit via `data-accent` attribute.
───────────────────────────────────────────────────────────── */
.lp-showcase-wrap,
.lp-showcase-wrap [data-accent] {
  --sv-accent-rgb: 148,163,184;
}
.lp-showcase-wrap [data-accent="notes"]      { --sv-accent-rgb: 91,140,255;  }
.lp-showcase-wrap [data-accent="flashcards"] { --sv-accent-rgb: 120,160,255; }
.lp-showcase-wrap [data-accent="questions"]  { --sv-accent-rgb: 56,189,248;  }
.lp-showcase-wrap [data-accent="summary"]    { --sv-accent-rgb: 45,212,191;  }
.lp-showcase-wrap [data-accent="overview"]   { --sv-accent-rgb: 165,180,255; }

/* ── Showcase shell ─────────────────────────────────────── */
.lp-showcase-wrap {
  /* Optical alignment: the hero grid is align-items:center, so a margin-top on
     this centred item shifts its BORDER box down by half the margin. The H1's
     leading measures 9.0px at 1440/1280 and 7.3px at 1100, so 9px here lands
     the top edge ~half a leading closer to the cap-height while keeping both
     edges near-balanced. Deliberately NOT align-items:start, which would move
     the whole overhang to the bottom. */
  margin-top: 9px;
  position: relative;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  height: 486px;
  overflow: hidden;
  border-radius: 20px;
  border: 1px solid rgba(148,163,232,0.18);
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(91,140,255,0.07) 0%, transparent 58%),
    linear-gradient(180deg, rgba(15,18,38,0.99) 0%, rgba(9,11,24,0.99) 100%);
  box-shadow:
    0 44px 96px rgba(0,0,0,0.66),
    0 2px 12px rgba(0,0,0,0.36),
    inset 0 1px 0 rgba(255,255,255,0.06),
    inset 0 0 0 1px rgba(255,255,255,0.025);
  display: flex;
  flex-direction: column;
}

/* ── Top system banner ───────────────────────────────────── */
/* ─────────────────────────────────────────────────────────────
   THE DEVICE — one border on the panel, two surfaces inside it.
   BEZEL  (--nb-paper-raised): title + board crumb, then the tabs.
   SCREEN (--nb-paper): darker, runs to the panel's bottom edge and
   inherits its radius. Content sits DIRECTLY on it — no inner card,
   no second border. The tonal step is what makes it read as a
   device; the geometry is identical on all four tabs because the
   stages are absolutely positioned inside the screen and never
   size it.

   Tabs are deliberately NOT focusable: they live inside the panel's
   aria-hidden subtree. The .lp-skip-inline link before the panel is
   the keyboard/AT route.
───────────────────────────────────────────────────────────── */
.lp-sv-bezel {
  display: flex;
  flex-direction: column;
  gap: 20px;
  flex-shrink: 0;
  padding: 15px 22px 0;
  min-width: 0;
}

.lp-sv-bezel-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  min-width: 0;
}

/* Calibrated to the old .lp-sv-method, the one header treatment that read
   as a product label rather than body copy. */
.lp-sv-bezel-title {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.115em;
  text-transform: uppercase;
  color: var(--nb-ink);
  white-space: nowrap;
}


.lp-sv-tabs {
  display: flex;
  align-items: flex-end;
  gap: 24px;
  padding-bottom: 10px;
  min-width: 0;
}

.lp-sv-tab {
  padding-bottom: 8px;
  font: var(--nb-type-label);
  /* F19. --nb-ink-3 is banned inside the panel. The skin overrides this at
     higher specificity, so the rendered colour is unaffected either way; this
     removes a dead reference rather than changing an appearance. */
  color: var(--nb-ink-2);
  white-space: nowrap;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color var(--m-state, 220ms) ease;
}

.lp-sv-tab--active {
  color: var(--nb-ink);
  border-bottom-color: var(--lp-role);
}

/* The screen. One hairline divides it from the bezel; that hairline is the
   hard top edge the notes pan slides under — no mask, a mask reads unfinished. */
.lp-sv-screen {
  flex: 1;
  min-height: 0;
  /* A flex column, because .lp-sv-viewport sizes itself with flex:1. As a plain
     block parent the viewport collapsed to 0 and every stage centred on a
     zero-height line. */
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  background: var(--nb-paper);
  border-top: 1px solid var(--nb-border);
  border-radius: 0 0 17px 17px;
}

/* ── Visually-hidden route into the content the panel advertises ──
   The panel itself is aria-hidden (it is a mock full of fabricated
   exam material). This link is the real, announced way in. It
   becomes visible on focus so sighted keyboard users can see it. */
.lp-skip-inline {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.lp-skip-inline:focus-visible {
  position: static;
  width: auto;
  height: auto;
  clip: auto;
  clip-path: none;
  display: inline-block;
  margin-bottom: 12px;
  padding: 8px 14px;
  border: 2px solid var(--nb-blue);
  border-radius: 8px;
  color: var(--nb-ink);
  font-size: var(--nb-text-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: normal;
}

/* ── Stage viewport — fixed window, stages stack absolutely ── */
.lp-sv-viewport {
  flex: 1;
  position: relative;
  overflow: hidden;
  min-height: 0;
}

.lp-sv-stage {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-rows: 1fr;
  padding: 22px 26px;
  opacity: 0;
  transform: translateY(10px);
  /* Sequenced, not crossfaded: the outgoing stage clears in 160ms, then the
     incoming enters. Only one stage is substantially visible at a time, so a
     tab switch reads as a screen changing rather than two images dissolving.
     Transform snaps back after the fade so the next entrance starts at 10px. */
  transition: opacity 160ms ease, transform 0ms linear 160ms;
  pointer-events: none;
}

.lp-sv-stage--active {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 260ms cubic-bezier(0.22, 1, 0.36, 1) 160ms,
    transform 260ms cubic-bezier(0.22, 1, 0.36, 1) 160ms;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .lp-sv-stage {
    transition: none;
    transform: none;
  }
}

/* ── Unified head block: pill + title + sub ───────────── */
.lp-sv-head {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ── Canvas: centered preview area ───────────────────────── */
.lp-sv-canvas {
  position: relative;
  display: flex;
  align-items: center;
  overflow: hidden;
  justify-content: center;
  min-height: 0;
}

/* The canvas clip is load-bearing for the NOTES stage only, where the note body
   deliberately overruns by 153-525px and pans under it. For the other two it was
   cutting content that has room to spare:
     - the MCQ group is 3.1px taller than its canvas at each end, which removed
       the "QUESTION n OF m" pill's top edge and the top of both 999px radii;
     - the flashcard card is rotated under a 1600px perspective, so its PROJECTED
       box grows to 339.8px against a 293.3px layout box, and up to 18.7px of it
       was clipped at 84 degrees - the blue top accent vanishing mid-flip.
   Containment is not removed, it moves out one level: .lp-sv-viewport and
   .lp-sv-screen both still clip, 22.5px further out. .lp-sv-stage carries a
   transform but no overflow, so it does not capture anything on the way. */
.lp-sv-stage--flashcards .lp-sv-canvas,
.lp-sv-stage--questions .lp-sv-canvas {
  overflow: visible;
}

.lp-sv-canvas > * {
  width: 100%;
}

/* ─────────────────────────────────────────────────────────────
   STAGE 0 · OVERVIEW — vertical 4-row product flow
───────────────────────────────────────────────────────────── */
/* ─────────────────────────────────────────────────────────────
   STAGE 1 · NOTES — live scrolling note preview
───────────────────────────────────────────────────────────── */
/* No overflow, no mask, no pan: the stage now holds everything it shows,
   so nothing is ever clipped at either edge. */
/* The notes excerpt is taller than the screen and pans once, upward, sliding
   under the bezel hairline. Hard edge, no mask: .lp-sv-screen clips it. */
.lp-sv-note-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  will-change: transform;
}

.lp-sv-note-qs {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.lp-sv-note-q {
  margin: 0;
  font-size: var(--nb-text-sm);
  font-weight: 600;
  line-height: 1.5;
  color: var(--nb-ink);
}

.lp-sv-note-a {
  margin: 4px 0 0;
  font-size: var(--nb-text-sm);
  line-height: 1.5;
  color: var(--nb-ink);
}

.lp-sv-note-a span {
  font-weight: 600;
  color: var(--nb-ink);
}

.lp-sv-note-h2 {
  margin: 0;
  font-size: var(--nb-text-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--nb-ink);
}

/* Masked viewport — content scrolls inside; top + bottom fade for polish */
.lp-sv-note-h1 {
  font-size: 1.1875rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.18;
  margin: 0 0 4px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(var(--sv-accent-rgb), 0.16);
  background: linear-gradient(135deg, rgba(255,255,255,0.97) 0%, rgba(200,218,255,0.88) 55%, rgba(155,195,255,0.82) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.lp-sv-note-p {
  font-size: var(--nb-text-sm);
  color: var(--nb-ink);
  line-height: 1.62;
  margin: 0;
}

.lp-sv-note-p strong {
  color: var(--nb-ink);
  font-weight: 600;
}

/* ── Note callouts — mirrors real callout-key-point / -examiner / -misconception ── */
.lp-sv-co {
  --co-rgb: var(--sv-accent-rgb);
  position: relative;
  display: flex;
  gap: 12px;
  padding: 12px 14px;
  background:
    linear-gradient(110deg, rgba(var(--co-rgb), 0.12) 0%, rgba(var(--co-rgb), 0.04) 50%, transparent 100%);
  border: 1px solid rgba(var(--co-rgb), 0.20);
  border-left: 3px solid rgba(var(--co-rgb), 0.86);
  border-radius: 10px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}

/* Two callouts: Misconception and Examiner Insight. Two admonition types show
   the note apparatus; four competing colours in one small frame was the defect. */
.lp-sv-co--misconception { --co-rgb: 251,191,36; }   /* skin remaps to --nb-adm-warn */
.lp-sv-co--examiner      { --co-rgb: 132,182,255; }  /* skin remaps to --nb-adm-insight */

/* A leading glyph, not a badge. The plate put an accent on an accent-tinted
   surface, which measured 3.46:1 (warn) and 3.33:1 (insight) in light. Dropping
   it puts the glyph on the callout tint at 4.73:1 — the same surface its label
   already uses, so icon and label share one treatment. */
.lp-sv-co-icon {
  flex-shrink: 0;
  width: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.45;
}

.lp-sv-co-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.lp-sv-co-label {
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--co-rgb), 0.95);
}

.lp-sv-co-p {
  font-size: 0.75rem;
  color: rgba(232,238,255,0.84);
  line-height: 1.55;
  margin: 0;
}

/* ─────────────────────────────────────────────────────────────
   STAGE 2 · FLASHCARDS — calm flip; cool-blue front, teal back
───────────────────────────────────────────────────────────── */
.lp-sv-fc {
  /* Content-sized and centred by .lp-sv-canvas (align-items:center) — the same
     mechanism .lp-sv-mcq uses. No height and no max-height: this column is
     justify-content:normal, so a clamp would pack from the top and push the
     controls row out of the bottom, cutting the one row that must stay visible.
     The guard is measurement, not a clamp; overflow stays visible so a spill is
     loud rather than silent. */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: 100%;
}

.lp-sv-fc-scene {
  perspective: 1600px;
  width: 100%;
  /* G7. Content-derived, not chosen: 320px text measure + 32px face padding
     each side + 1px face border each side = 386. Above this the surplus is dead
     side padding — .lp-sv-fc-text carries its own max-width: 320px, so a wider
     scene never reaches the text and cannot change a line count or a height.
     Measured surplus at 460/440/420/400 was +74/+54/+34/+14.
     The (max-width: 700px) override stays at 360, which is 6px UNDER its own
     derived figure of 366 (320 + 22 + 22 + 2) and so clips the measure to 314.
     Left alone deliberately: raising it re-wraps text where 320 is already
     tight. */
  /* Derived, not chosen. With aspect-ratio 3/2 the card's height is width x 2/3,
     and the group must also fit a 30px controls row plus an 18px gap. The
     binding width is 1440/1280, canvas 350: (350 - 48) x 1.5 = 453, the largest
     value that clamps nowhere. Set BELOW it at 440 deliberately: 453 leaves 0px
     headroom at 1440/1280 and 1px at 960, and the answer text this card is
     sized to is due for replacement. 13px of width buys ~10px of slack. Do not
     raise it past 453. */
  max-width: 440px;
  /* Sized by its content plus the face's own padding. A flashcard is a small
     object; the previous 320px floor held 96.8px of ink and left 223px empty,
     and consumed the clearance the controls row needed. */
}

/* Both faces occupy one grid cell, so the card sizes to the TALLER of the two.
   Measured before this change: the back's content exceeded the card's box by
   41-86px at every width, spilling outside the card's own border whenever the
   flip showed it. height:100% is dropped with it — it resolved to auto against a
   content-sized scene. preserve-3d and backface-visibility stay on this element
   and the faces, so grid does not flatten the 3D subtree. */
.lp-sv-fc-card {
  position: relative;
  width: 100%;
  display: grid;
  /* A flashcard has a shape: the text sits in it rather than defining it.
     max-height keeps it inside the canvas if content exceeds the ratio — at 320
     it does, and the card falls back to content height. */
  aspect-ratio: 3 / 2;
  max-height: 100%;
  transform-style: preserve-3d;
  transform: rotateY(0deg);
}

.lp-sv-fc-face {
  grid-area: 1 / 1;
}

/* Cycle: front hold → flip → back hold → flip forward to front.
   Forward rotation only; runs once per stage activation (JS restarts it each cycle). */
@keyframes lp-sv-fc-flip {
  0%, 22%    { transform: rotateY(0deg); }
  37%        { transform: rotateY(180deg); }
  72%        { transform: rotateY(180deg); }
  87%, 100%  { transform: rotateY(360deg); }
}

.lp-sv-stage--active.lp-sv-stage--flashcards .lp-sv-fc-card {
  animation: lp-sv-fc-flip 6.4s cubic-bezier(0.6, 0, 0.4, 1) 0.3s forwards;
}

@media (prefers-reduced-motion: reduce) {
  .lp-sv-stage--active.lp-sv-stage--flashcards .lp-sv-fc-card {
    animation: none;
    transform: rotateY(0deg);
  }
}

/* Each face owns its own --fc-rgb so front/back read as related-but-distinct */
.lp-sv-fc-face {
  --fc-rgb: var(--sv-accent-rgb);
  /* The FRONT face stays in flow so the scene takes its height from real
     content; the back is overlaid on top of it. With both absolute there was
     nothing to size the scene, which is why it needed an invented min-height. */
  position: relative;
  width: 100%;
  /* Three rows in flow: fixed header, flexing body, fixed footer. No child is
     absolutely positioned — 2D-i removed exactly that, and it is why the face
     self-sizes. grid-template-columns: 100% is load-bearing: without it the
     column is content-sized and `justify-self: start` on the label would align
     to the widest row item rather than to the face's padding edge. */
  display: grid;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 100%;
  justify-items: center;
  padding: 28px 32px;
  border-radius: 18px;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  text-align: center;
  background:
    linear-gradient(148deg,
      rgba(var(--fc-rgb), 0.18) 0%,
      rgba(var(--fc-rgb), 0.06) 46%,
      rgba(10,13,28,0.96) 100%);
  border: 1px solid rgba(var(--fc-rgb), 0.30);
  border-top: 2px solid rgba(var(--fc-rgb), 0.68);
  box-shadow:
    0 24px 56px rgba(0,0,0,0.46),
    0 4px 14px rgba(0,0,0,0.30),
    inset 0 1px 0 rgba(255,255,255,0.07);
}

/* Front — cool blue / "question / active recall" */
/* The flexing middle row. It exists because grid's 1fr needs a single target
   and the back has two paragraphs; centring here turns the row's spare height
   into breathing room rather than a top-anchored block. */
.lp-sv-fc-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: 0;
}

.lp-sv-fc-face--front {
  --fc-rgb: 120,160,255;
}

/* Back — calm teal / "answer / confirmation" — siblings, not twins */
.lp-sv-fc-face--back {
  --fc-rgb: 56,205,180;
  transform: rotateY(180deg);
  background:
    linear-gradient(148deg,
      rgba(var(--fc-rgb), 0.22) 0%,
      rgba(var(--fc-rgb), 0.08) 48%,
      rgba(10,16,26,0.96) 100%);
  border-color: rgba(var(--fc-rgb), 0.36);
  border-top-color: rgba(var(--fc-rgb), 0.82);
  box-shadow:
    0 24px 56px rgba(0,0,0,0.46),
    0 4px 14px rgba(0,0,0,0.30),
    inset 0 1px 0 rgba(255,255,255,0.085);
}



.lp-sv-fc-label {
  /* Colour is var(--nb-blue), not the per-face --fc-rgb it used to take: the
     accent reduction retired the back's teal for TEXT, and the skin has
     overridden all four text sites to ink for some time, so the --fc-rgb form
     here declared an intent nothing honoured. --fc-rgb stays defined and still
     drives the faces' surfaces (gradient, border, border-top) — surface carries
     face identity, text carries one accent. Same change at
     .lp-sv-fc-label--answer and .lp-sv-fc-hint. */
  /* Header row. The kicker centres with the other two children — the face's
     justify-items: center places it and nothing overrides that. It was
     justify-self: start for one pass; on a 386x164 box with three children a
     top-left label stranded ~336px of empty header beside it, which read as
     stray rather than as structure. The 2D-ii 6px bottom margin is gone: the
     grid row sets the gap. */
  margin: 0;
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--nb-blue);
}

.lp-sv-fc-label--answer {
  color: var(--nb-blue);
}

.lp-sv-fc-text {
  font-size: 1.3125rem;
  font-weight: 500;
  color: rgba(255,255,255,0.96);
  /* SHORTHAND IS LOAD-BEARING. Must stay a shorthand, not longhand. The back's
     override below wins on specificity alone (2 classes against this rule's 1);
     rewriting the BACK rule to match this one's specificity would make the
     cascade source-order dependent. The 2D-ii 22px is gone: the front's text is
     the only child of .lp-sv-fc-body, so a bottom margin here is trailing space
     that shifts the flexing body off its own centre. Twin comment at
     .lp-sv-fc-face--back .lp-sv-fc-text. */
  margin: 0;
  line-height: 1.48;
  letter-spacing: -0.005em;
  /* J2. Fills the face's content box; a 320px cap would reintroduce the dead
     side padding J1 just paid for. */
  max-width: 100%;
  /* Balances the last line against the ones above it; max-width stays 320px, so
     the measure is unchanged and this only redistributes within it. Unsupported
     browsers fall back to today's greedy wrapping. */
  text-wrap: balance;
}

/* Back rhythm. Both rules are longhand and out-specify the base
   `.lp-sv-fc-text` shorthand (2 and 3 classes against 1), so they do not depend
   on source order. Keep it that way: see the twin comment on .lp-sv-fc-text. */
.lp-sv-fc-face--back .lp-sv-fc-text {
  margin-bottom: 10px;
  font-weight: 600;
  color: #ffffff;
}


.lp-sv-fc-hint {
  /* Footer row. text-transform removed together with the string change: the
     source now reads "Tap to reveal" and renders that way. A sentence-case
     source that renders uppercase is a source that lies about its output. */
  font-size: 0.625rem;
  font-weight: 500;
  /* 0.04em was set for the uppercase string; with the
     uppercase gone the two footer elements should read as one slot. */
  letter-spacing: 0.005em;
  color: var(--nb-blue);
}


.lp-sv-fc-controls {
  display: flex;
  align-items: center;
  gap: 10px;
}

.lp-sv-fc-btn {
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 8px;
  color: rgba(225,232,250,0.62);
}

.lp-sv-fc-counter {
  font-size: 0.75rem;
  font-weight: 600;
  color: rgba(215,225,250,0.62);
  letter-spacing: 0.01em;
  padding: 0 8px;
  font-variant-numeric: tabular-nums;
}

/* ─────────────────────────────────────────────────────────────
   STAGE 3 · MCQS - mini version of the real MCQ resource UI
───────────────────────────────────────────────────────────── */
/* The card wrapper is gone, so this element now holds the question, the four
   options and the explanation directly — it must stack them. */
.lp-sv-mcq {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
}

/* No fixed height, no overflow, no mask: the card is shown whole. The 316px
   masked window was correct at a ~300px canvas; at 445px it sliced option C. */
.lp-sv-mcq-card {
  width: 100%;
}

.lp-sv-mcq-count {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--nb-ink);
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.09);
  padding: 4px 9px;
}

.lp-sv-mcq-stem {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
  margin-bottom: 13px;
}

.lp-sv-mcq-question {
  flex: 1;
  min-width: 0;
  margin: 0;
  color: rgba(226,232,240,0.92);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.52;
  letter-spacing: -0.005em;
  max-width: 56ch;
}

.lp-sv-mcq-options {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.lp-sv-mcq-option {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 38px;
  padding: 7px 13px;
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.030);
  color: rgba(226,232,240,0.82);
}

.lp-sv-mcq-badge {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 7px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.10);
  color: rgba(200,210,230,0.72);
  font-size: 0.71875rem;
  font-weight: 700;
}

.lp-sv-mcq-text {
  flex: 1;
  min-width: 0;
  font-size: 0.90625rem;
  font-weight: 500;
  line-height: 1.45;
}

.lp-sv-mcq-option--incorrect {
  background: rgba(239,68,68,0.07);
  border-color: rgba(239,68,68,0.26);
  color: rgba(254,202,202,0.88);
}

.lp-sv-mcq-option--incorrect .lp-sv-mcq-badge {
  background: rgba(239,68,68,0.14);
  border-color: rgba(239,68,68,0.34);
  color: rgba(252,165,165,1);
}

.lp-sv-mcq-option--correct {
  background: rgba(34,197,94,0.07);
  border-color: rgba(34,197,94,0.26);
  color: rgba(220,252,231,0.90);
}

.lp-sv-mcq-option--correct .lp-sv-mcq-badge {
  background: rgba(34,197,94,0.14);
  border-color: rgba(34,197,94,0.34);
  color: rgba(134,239,172,1);
}

.lp-sv-mcq-option--dimmed {
  background: rgba(255,255,255,0.016);
  border-color: rgba(255,255,255,0.05);
  color: rgba(226,232,240,0.72); /* legible neutral; hierarchy via colour not opacity */
}

.lp-sv-mcq-option--dimmed .lp-sv-mcq-badge {
  background: rgba(255,255,255,0.03);
  border-color: rgba(255,255,255,0.06);
  color: rgba(200,210,230,0.72);
}

.lp-sv-mcq-mark {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.lp-sv-mcq-option--correct .lp-sv-mcq-mark {
  color: rgba(134,239,172,0.96);
  background: rgba(34,197,94,0.10);
  border: 1px solid rgba(34,197,94,0.22);
}

.lp-sv-mcq-option--incorrect .lp-sv-mcq-mark {
  color: rgba(252,165,165,0.96);
  background: rgba(239,68,68,0.10);
  border: 1px solid rgba(239,68,68,0.22);
}

.lp-sv-mcq-mark svg {
  width: 11px;
  height: 11px;
}

/* De-carded (F9). The surface is gone — no background, border, radius or
   overflow — so the explanation reads as a continuation of the option list
   rather than a second nested card. margin-top stays: it is the only thing
   separating it from the last option. The 1px border it used to carry was also
   load-bearing for alignment; its removal is compensated in
   .lp-sv-mcq-explanation's horizontal padding below (see A5 arithmetic). */
/* Reveal, opacity only — the marks and the explanation already occupy their
   space and keep occupying it: no height, margin, display or position is
   animated, so nothing reflows. Sequenced after the two rows resolve. */
@keyframes lp-sv-mcq-fade-in {
  from { opacity: 0; }
}

.lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--incorrect .lp-sv-mcq-mark {
  animation: lp-sv-mcq-fade-in 0.30s ease 0.38s backwards;
}
.lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-option--correct .lp-sv-mcq-mark {
  animation: lp-sv-mcq-fade-in 0.30s ease 0.70s backwards;
}
.lp-sv-stage--active.lp-sv-stage--questions .lp-sv-mcq-feedback {
  animation: lp-sv-mcq-fade-in 0.36s ease 0.94s backwards;
}

.lp-sv-mcq-feedback {
  margin-top: 11px;
}

.lp-sv-mcq-verdict {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  font-size: 0.875rem;
  font-weight: 600;
  border-bottom: 1px solid rgba(255,255,255,0.07);
}

.lp-sv-mcq-verdict--incorrect {
  color: rgba(252,165,165,0.96);
  background: rgba(239,68,68,0.08);
  border-bottom-color: rgba(239,68,68,0.12);
}

.lp-sv-mcq-verdict svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.lp-sv-mcq-answer-ref {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 7px 10px;
  padding: 11px 16px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  background: rgba(34,197,94,0.04);
}

.lp-sv-mcq-answer-label {
  font-size: 0.59375rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: rgba(34,197,94,0.62);
  white-space: nowrap;
}

.lp-sv-mcq-answer-value {
  font-size: 0.8125rem;
  color: rgba(220,252,231,0.86);
  font-weight: 500;
  line-height: 1.45;
}

/* One explanation, flowing: the label sits inline ahead of the sentence rather
   than on its own row, so the block costs ~2 lines instead of ~70px. */
.lp-sv-mcq-explanation {
  margin: 0;
  /* G1. Aligns to the option rows' BORDER-BOX left edge, not their content
     edge. The earlier A5 target was wrong: matching the option's inner inset
     put this text on the badge's left edge, which reads as an indent against
     the four rows' border line. The option's border box is offsetLeft 0, so
     this rule carries no horizontal padding at all. Right padding goes with it
     — an asymmetric inset would reintroduce the same lie on the other edge, and
     since F9 de-carded this element there is no surface left to inset from.
     Both narrower breakpoints below carry the same target. */
  padding: 9px 0 10px;
  line-height: 1.45;
}

.lp-sv-mcq-explanation .lp-sv-mcq-explanation-label {
  margin-right: 8px;
}

.lp-sv-mcq-explanation + .lp-sv-mcq-explanation {
  border-top: 1px solid rgba(255,255,255,0.06);
}

/* J4. Stays INLINE. The product puts this label on its own line, but the
   product's MCQ is a full page; this stage has +2px of headroom at 700 and -3
   at 960, and an extra line box costs ~17px it does not have — measured, it
   pushed 960 to -20 and opened a new overflow at 700. What DID carry across is
   the colour: the product has no red incorrect label at all, so the red was a
   landing-only invention and it is gone. Size, weight, tracking and case remain
   the differentiation, which is how the product differentiates too. */
.lp-sv-mcq-explanation-label {
  /* Close to the explanation's own 15px without matching it. Full inherit
     widened this label enough to wrap the sentence at 1100 — the one width where
     the questions stage had only 15px of headroom — taking it to -6. 12px is the
     largest step measured that keeps 1100 positive and moves no other cell.
     Weight, tracking and case still carry the differentiation. */
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Re-added: the red incorrect label was removed when the label took --nb-ink-2,
   and is being restored deliberately. */
.lp-sv-mcq-explanation--incorrect .lp-sv-mcq-explanation-label {
  color: rgba(248,113,113,0.95);
}

.lp-sv-mcq-explanation--correct .lp-sv-mcq-explanation-label {
  color: rgba(134,239,172,0.95);
}

/* ─────────────────────────────────────────────────────────────
   STAGE 4 · YOUR TUTOR — the study loop
   Four nodes on a landscape oval, arrows flowing clockwise, the
   fourth closing back to the first. Colour is all var(--nb-*) so
   the diagram follows the theme toggle with no light-mode fork.

   Two variants, one idea. The wide oval's <text> scales with its
   viewBox, so below a measured canvas width its 13px labels drop
   under an 11px legibility floor; a vertical chain takes over
   there. The crossover bands are measured, not assumed — the
   hero is two-column above 960px, so the panel is *narrowest*
   between 961px and 1280px, not on a phone.
───────────────────────────────────────────────────────────── */
.lp-sv-loop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  max-height: 100%;
  /* The canvas is a flex item with default min-width:auto. Without this the
     diagram's min-content width pushes the panel past its own frame on very
     narrow viewports, exactly as the old summary list does today. */
  min-width: 0;
  min-height: 0;
}

.lp-sv-loop-svg {
  display: block;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
}

/* Never scale past 1:1. The collapsed chrome gave the canvas ~120px more room,
   which let the tall variant scale to 1.41 and render its 15px labels at 21px —
   a 64% jump across the 1280/1281 crossover. Capping at the viewBox's own
   height keeps both variants within one step of each other. */
/* Cap derived from the label, not the other way round: labels are fixed at
   --nb-text-base (15px) and render at 15 x scale, so scale must be exactly 1.0
   and the cap must equal the viewBox height. To fill more screen the viewBox
   grew (280->320 wide, 268->300 tall) rather than the scale rising. */
.lp-sv-loop-svg--wide { max-height: 320px; }
.lp-sv-loop-svg--tall { max-height: 300px; }

.lp-sv-loop-svg--tall { display: none; }

/* The arrows carry the meaning — which way the loop runs — so they sit on
   ink-3. The border hairline measures 1.3:1 against this panel, which is
   fine for a container edge and far too faint for information. */
.lp-sv-loop-link { color: var(--nb-ink-2); }

.lp-sv-loop-node rect {
  fill: none;
  stroke: var(--nb-border);
  stroke-width: 1;
}

.lp-sv-loop-node text {
  font-family: var(--nb-sans);
  font-weight: 600;
  font-size: var(--nb-text-base);
  fill: var(--nb-ink-2);
}

.lp-sv-loop-caption {
  margin: 0;
  max-width: 54ch;
  text-align: center;
  /* One step up the token ladder from --nb-text-sm. The loop SVG is
     flex: 1 1 auto with min-height: 0, so it shrinks to absorb the growth and
     the stage's full-fill headroom of 0 is preserved — max-height caps growth,
     it does not prevent shrink. */
  font-size: var(--nb-text-base);
  font-weight: 400;
  line-height: 1.5;
  color: var(--nb-ink);
}

/* The loop draws itself once, clockwise, from "Read the notes". Each node
   appears, then the arc leaving it strokes on and its arrowhead lands. Settles
   at 2.64s. pathLength="1" normalises every arc so one dash pair fits all four.

   RECONSTRUCTED FROM RECORD in pass F, not recovered from git: passes A-E were
   never committed, so these 17 selectors existed only in the working tree.
   Timings are the values logged when it was built and again when it was deleted.

   stroke-dashoffset is not GPU-compositable — it repaints the path. It runs
   ONCE per stage activation (forwards, no iteration count), restarted by the
   reflow poke in landing.js. That cost was known and accepted: this is the best
   motion in the panel, and deleting it in pass E was my error. */
.lp-sv-loop-node { opacity: 0; }
.lp-sv-loop-tip  { opacity: 0; }
.lp-sv-loop-arc  { stroke-dasharray: 1; stroke-dashoffset: 1; }

@keyframes lp-sv-loop-draw { to { stroke-dashoffset: 0; } }
@keyframes lp-sv-loop-in   { to { opacity: 1; } }

.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-node:nth-child(5) {
  animation: lp-sv-loop-in 0.30s ease 0.10s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(1) .lp-sv-loop-arc {
  animation: lp-sv-loop-draw 0.42s ease 0.34s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(1) .lp-sv-loop-tip {
  animation: lp-sv-loop-in 0.18s ease 0.66s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-node:nth-child(6) {
  animation: lp-sv-loop-in 0.30s ease 0.70s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(2) .lp-sv-loop-arc {
  animation: lp-sv-loop-draw 0.42s ease 0.94s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(2) .lp-sv-loop-tip {
  animation: lp-sv-loop-in 0.18s ease 1.26s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-node:nth-child(7) {
  animation: lp-sv-loop-in 0.30s ease 1.30s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(3) .lp-sv-loop-arc {
  animation: lp-sv-loop-draw 0.42s ease 1.54s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(3) .lp-sv-loop-tip {
  animation: lp-sv-loop-in 0.18s ease 1.86s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-node:nth-child(8) {
  animation: lp-sv-loop-in 0.30s ease 1.90s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(4) .lp-sv-loop-arc {
  animation: lp-sv-loop-draw 0.42s ease 2.14s forwards;
}
.lp-sv-stage--active.lp-sv-stage--summary .lp-sv-loop-link:nth-child(4) .lp-sv-loop-tip {
  animation: lp-sv-loop-in 0.18s ease 2.46s forwards;
}

/* Resting state: a complete, correct loop — never a mid-draw frame. */
@media (prefers-reduced-motion: reduce) {
  .lp-sv-loop-node,
  .lp-sv-loop-tip {
    opacity: 1;
    animation: none;
  }
  .lp-sv-loop-arc {
    stroke-dashoffset: 0;
    animation: none;
  }
}

/* Measured crossover: the wide oval needs >= 541.5px of canvas to hold an
   11px label. Canvas width is 540.0px at 630px viewport and 539.9px at
   1260px — both just under — so the chain covers both bands. */
@media (max-width: 640px), (min-width: 961px) and (max-width: 1280px) {
  .lp-sv-loop-svg--wide { display: none; }
  .lp-sv-loop-svg--tall { display: block; }
}

/* ─────────────────────────────────────────────────────────────
   Bottom chrome — "Up next" + progress bars
───────────────────────────────────────────────────────────── */

/* ─────────────────────────────────────────────────────────────
   Responsive — keep miniatures readable across all widths
───────────────────────────────────────────────────────────── */
/* ── The notes pan: one move, then it rests on a complete frame ──────────
   Distance is set from a custom property so the media blocks can retune it
   per breakpoint without duplicating the keyframes. */
.lp-sv-stage--notes .lp-sv-canvas {
  align-items: flex-start;
  /* measured: notes content minus the screen's inner height, per breakpoint */
}

/* Query container for the pan below. Scoped to notes so no other stage acquires
   size containment. The canvas's overflow: hidden is untouched and still
   load-bearing for the overrun. */
.lp-sv-stage--notes .lp-sv-canvas {
  container-type: size;
}

@keyframes lp-sv-note-pan {
  0%, 12%   { transform: translateY(0); }
  /* Derived, not tuned. 100% of a translateY is the note body's OWN height and
     100cqh is the canvas height (the canvas is the query container below), so
     -100% + 100cqh is exactly the overrun — the pan ends with the last line of
     content on the canvas floor at every width, whatever the wrapping does.
     The seven hand-set --lp-note-pan values it replaces fell short by
     19/19/59/18/19/193/108/169/308px, which is why 360 stopped mid-callout. */
  88%, 100% { transform: translateY(calc(-100% + 100cqh)); }
}

.lp-sv-stage--active.lp-sv-stage--notes .lp-sv-note-body {
  animation: lp-sv-note-pan 8s cubic-bezier(0.45, 0.05, 0.55, 0.95) forwards;
}

/* Reduced motion parks at the TOP, not the end: a viewer who sees one static
   frame should see the beginning of the note, not a frame with the heading
   already scrolled past. The legacy guard at the top of this file deliberately
   does not reset transform, so this holds. */
@media (prefers-reduced-motion: reduce) {
  .lp-sv-stage--active.lp-sv-stage--notes .lp-sv-note-body {
    animation: none;
    transform: translateY(0);
  }
}

@media (max-width: 1280px) {
  .lp-sv-stage--notes .lp-sv-canvas {
  }
  .lp-showcase-wrap {
    height: 486px;
  }
}

@media (max-width: 1100px) {
  .lp-showcase-wrap {
    margin-top: 7px;
  }
  .lp-sv-stage--notes .lp-sv-canvas {
    /* capped at 0.6x the screen's inner height (390.4), like the narrow
       breakpoints: 1100 is the tightest two-column width on every axis */
  }
  .lp-showcase-wrap {
    height: 508px;
  }
}

@media (max-width: 960px) {
  .lp-sv-stage--notes .lp-sv-canvas {
  }
  .lp-showcase-wrap {
    height: 483px;
  }
  .lp-sv-stage {
    padding: 22px 22px 18px;
  }
  .lp-sv-fc-face {
    padding: 30px 32px;
  }
  .lp-sv-mcq-question {
    font-size: 0.9375rem;
  }
}

@media (max-width: 700px) {
  /* A5 at this breakpoint: option is 1px border + 12px padding = 13px, one less
     than base, so the explanation re-derives rather than inheriting base's 14. */
  .lp-sv-mcq-explanation {
    padding: 9px 0 10px;
  }

  .lp-sv-stage--notes .lp-sv-canvas {
  }
  .lp-showcase-wrap {
    height: 492px;
  }
  .lp-sv-stage {
    padding: 20px 20px 16px;
  }
  .lp-sv-fc-face {
    padding: 26px 22px;
  }
  .lp-sv-fc-text {
    font-size: 0.9375rem;
  }
  .lp-sv-mcq-stem {
    gap: 6px;
    margin-bottom: 11px;
  }
  .lp-sv-mcq-question {
    font-size: 0.875rem;
    line-height: 1.48;
  }
  .lp-sv-mcq-option {
    min-height: 40px;
    padding: 9px 12px;
    gap: 11px;
  }
  .lp-sv-mcq-text {
    font-size: 0.8125rem;
  }
  .lp-sv-note-h1 {
    font-size: 1.0625rem;
  }
}

@media (max-width: 480px) {
  .lp-sv-stage--notes .lp-sv-canvas {
    /* capped at 0.6x the screen's inner height: a full-screen travel
       reads as a long scroll, not a slow reveal */
  }
  .lp-showcase-wrap {
    height: 443px;
  }
  .lp-sv-stage {
    grid-template-rows: minmax(0, 1fr);
    padding: 16px 14px 14px;
  }
  .lp-sv-head {
    gap: 8px;
  }
  /* On the smallest screens, keep note preview static at top so it stays
     readable without needing to play through the scroll cycle. */
  .lp-sv-stage--questions .lp-sv-canvas {
    padding-top: 0;
  }
  .lp-sv-mcq-count {
    display: none;
  }
  .lp-sv-mcq-stem {
    gap: 5px;
    margin-bottom: 9px;
  }
  .lp-sv-mcq-question {
    font-size: 0.8125rem;
    line-height: 1.42;
  }
  .lp-sv-mcq-options {
    gap: 5px;
  }
  .lp-sv-mcq-option {
    min-height: 34px;
    padding: 6px 8px;
    gap: 9px;
  }
  .lp-sv-mcq-badge {
    width: 23px;
    height: 23px;
    border-radius: 7px;
  }
  .lp-sv-mcq-feedback {
    margin-top: 10px;
  }
  .lp-sv-mcq-verdict {
    padding: 8px 10px;
  }
  .lp-sv-mcq-answer-ref {
    padding: 8px 10px;
  }
  .lp-sv-mcq-explanation {
    padding: 8px 0;
  }
}

/* 360px needs a little more than 480px does: the panel is narrow enough that
   the MCQ question and explanation both wrap further. 480 stays as it was. */
@media (max-width: 400px) {
  .lp-sv-tabs {
    gap: 12px;
  }
  .lp-sv-stage--notes .lp-sv-canvas {
    /* capped at 0.6x the screen's inner height: a full-screen travel
       reads as a long scroll, not a slow reveal */
  }
  .lp-showcase-wrap {
    height: 465px;
  }

  /* Both callouts fit everywhere the panel grew; below 400px they do not.
     Showing one complete beats showing two clipped. */
  .lp-sv-stage--notes .lp-sv-co--examiner {
    display: none;
  }
}

/* ── Section divider ─────────────────────────────────────── */
.lp-divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(130,148,215,0.28) 32%, rgba(155,175,240,0.32) 50%, rgba(130,148,215,0.28) 68%, transparent);
  max-width: 840px;
  margin: 0 auto;
  box-shadow: 0 0 12px rgba(100,120,215,0.10);
}

/* ── Section header ──────────────────────────────────────── */
.lp-section-header {
  text-align: center;
  margin-bottom: 56px;
}

/* .lp-mark-title verbatim. The gradient text-clip this replaced had NO real
   colour -- it painted through -webkit-text-fill-color: transparent, and four
   separate rules existed elsewhere only to undo it in light mode. That is the
   mechanism behind this project's two shipped invisible-text incidents, so the
   headline now carries an ordinary colour like every other headline.
   overflow-wrap and min-width are load-bearing: tests_notebook.py:3292 pins
   overflow-wrap: anywhere as a mobile intrinsic-width trap guard. */
.lp-section-title {
  margin: 0 0 12px;
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
  font-size: clamp(2rem, 3.4vw, 3rem);
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: normal;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* .lp-mark-sub verbatim. Colour comes from the skin's var(--nb-ink), the same
   ink as the headline -- ONE ink, matching the two sections above. */
.lp-section-sub {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.6;
  max-width: 40rem;
}

/* ── Features ────────────────────────────────────────────── */
.lp-features {
  padding: 96px 48px 96px;
}

.lp-features .lp-section-header {
  text-align: left;
  max-width: 960px;
  margin: 0 auto 52px;
}

.lp-features .lp-section-sub {
  margin: 0;
  max-width: 480px;
}

.lp-features-grid {
  max-width: 960px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 2px;
  row-gap: 16px;
}

.lp-feat {
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.07);
  box-shadow: none;
  border-radius: 14px;
  padding: 32px 28px;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.lp-feat:hover {
  background: rgba(255,255,255,0.07);
  border-color: rgba(255,255,255,0.12);
  transform: none;
  box-shadow: none;
}

/* Top row — primary value props: slightly elevated surface */
.lp-feat:nth-child(-n+2) {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.10);
}

.lp-feat:nth-child(-n+2):hover {
  background: rgba(255,255,255,0.09);
  border-color: rgba(255,255,255,0.15);
}

/* Bottom row — supporting features: slightly recessed */
.lp-feat:nth-child(n+3) .lp-feat-title {
  color: rgba(255,255,255,0.88);
}

.lp-feat:nth-child(n+3) .lp-feat-desc {
  color: rgba(255,255,255,0.50);
}

.lp-feat:nth-child(n+3) .lp-feat-icon {
  color: rgba(169,190,255,0.60);
}

.lp-feat-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: auto;
  background: none;
  border: none;
  border-radius: 0;
  margin-bottom: 16px;
  color: #a9beff;
}

.lp-feat-title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: rgba(255,255,255,0.96);
  margin: 0 0 10px;
}

.lp-feat-desc {
  font-size: 0.9rem;
  color: rgba(255,255,255,0.58);
  line-height: 1.65;
  margin: 0;
}

/* ── Board / Subjects ────────────────────────────────────── */
.lp-boards {
  padding: 96px 48px;
  text-align: center;
  background: rgba(255,255,255,0.03);
  border-top: 1px solid rgba(255,255,255,0.07);
  border-bottom: 1px solid rgba(255,255,255,0.07);
}

.lp-boards-inner {
  max-width: 860px;
  margin: 0 auto;
}

.lp-programme-groups {
  display: flex;
  justify-content: center;
  margin-bottom: 52px;
}

.lp-programme-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 24px 44px;
  border-right: 1px solid rgba(255,255,255,0.07);
}

.lp-programme-group:last-child {
  border-right: none;
}

.lp-programme-group-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.30);
}

.lp-programme-links {
  display: flex;
  gap: 8px;
}

.lp-chip {
  display: inline-block;
  padding: 10px 22px;
  border: 1px solid rgba(91,140,255,0.30);
  border-radius: 9px;
  background: rgba(91,140,255,0.07);
  color: rgba(255,255,255,0.85);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
  transition: border-color 0.18s ease, background 0.18s ease, color 0.18s ease;
}

.lp-chip:hover {
  border-color: rgba(91,140,255,0.60);
  background: rgba(91,140,255,0.15);
  color: #ffffff;
}

.lp-chip:focus-visible {
  outline: 2px solid #5b8cff;
  outline-offset: 3px;
}

.lp-subjects-label {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.26);
  margin: 0 0 14px;
  text-align: center;
}

.lp-subject-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}

.lp-subject-tile {
  padding: 14px 12px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 9px;
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(255,255,255,0.60);
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.lp-subject-tile:not(.lp-subject-tile--more):hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.14);
  color: rgba(255,255,255,0.90);
}

.lp-subject-tile--more {
  color: rgba(255,255,255,0.28);
  font-style: italic;
  border-style: dashed;
}


/* ── Persuasion / Editorial ──────────────────────────────── */
/* ═══ ExamStudyAid AI band ══════════════════════════════════════════════
   A FIXED dark surface in both themes: a dark band on a light page is the
   intended look, so nothing here reads --nb-ink / --nb-ink-2 / --nb-border —
   in light theme --nb-ink is near-black and would be invisible on navy. The
   scoped set below is sampled from the approved mock and is identical in both
   themes by construction, which is why there is no theme-light twin.
   Two ink levels only, matching the hero panel's rule. */
.lp-ai {
  /* Sampled from the mock, not derived. The previous #051228 came from a
     constrained delta-E search and was never checked against the mock's own
     ground: it carried 15 more blue (B 40 vs 25), which read as a mid navy
     where the mock is a near-neutral near-black. */
  --lp-ai-bg: #090F19;
  --lp-ai-ink: #F6E6D1;
  /* T3. The mock's own subhead is #8B8E94 (L* 58.9) and the render was already
     a shade brighter at #8E9196 (L* 60.1), so the recession is in the mock, not
     a render defect. Raised deliberately: L* 66.2, 7.41:1 on the band, which
     leaves a 25.9 L* gap to the headline against the mock's 29.7 -- still
     clearly subordinate, and the 60px serif against 17px sans carries the
     hierarchy regardless of ink. STEP 2: re-hued warm. #9EA1A7 was the only
     cold element left on a band of cream, tan and warm border -- B>G>R by 9.
     #A5A09C is the exact mirror, R>G>B by 9, at the same L* 66.17 and the same
     7.41:1, so nothing about the contrast or the hierarchy moves. */
  --lp-ai-ink-2: #A5A09C;
  --lp-ai-edge: #1A2432;
  --lp-ai-line: #2A292D;
  --lp-ai-joint: #C2B5A8;
  /* N2. The collapsed edges land on the NUMBERS BAND's content width, so the
     section starts aligned with the page and then breaks out of it. That band
     caps its section at 1200px and pads it 24px, so its content's left offset
     is max(0, (W - 1200) / 2) + 24 -- which is exactly this. 100% rather than
     100vw: percentages inside inset() resolve against the border box, so a
     scrollbar cannot skew it. */
  /* Clamped to the band's own gutter. Un-clamped, the numbers band's content
     offset overtakes the AI band's 7.42% text gutter at about 1353px wide, and
     the collapsed edge then lands 37px inside the eyebrow. Below that the two
     align exactly; above it the collapsed edge sits just outside the text
     gutter. The 6px is not decoration: clamping to exactly 7.42% put the edge
     ON the gutter, and subpixel rounding then shaved 0.2px off the eyebrow. */
  --lp-ai-inset: min(calc(max(0px, (100% - 1200px) / 2) + 24px), calc(7.42% - 6px));
  --lp-ai-radius: 1.5rem;
  position: relative;
  padding: clamp(52px, 4.2vw, 72px) 48px clamp(48px, 4vw, 68px);
  background: var(--lp-ai-bg);
}

/* Scroll expand. THE DEFAULT STATE IS EXPANDED: no clip-path is declared on
   .lp-ai itself, so a browser with no scroll-timeline support renders a correct
   full-bleed band rather than a permanently inset one. The inset exists only
   inside the keyframe, and only a live view() timeline can apply it.
   clip-path, not transform: scale — scale resamples and blurs text. Not width
   or margin — those are layout properties and would reflow the page. */
@keyframes lp-ai-expand {
  from {
    clip-path: inset(0 var(--lp-ai-inset) 0 var(--lp-ai-inset)
                     round var(--lp-ai-radius));
  }
  to {
    clip-path: inset(0 0 0 0 round 0);
  }
}

@supports (animation-timeline: view()) {
  .lp-ai {
    animation: lp-ai-expand linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 35%;
  }
}

.lp-ai-inner {
  max-width: 1100px;
  margin: 0 auto;
}

/* Two columns at wide widths; 2C replaces the figure entirely below 960. */
/* Constellation from 1100 up, not 960. The overlay moved .lp-ai-figure out of
   .lp-ai-inner so the network could span the band, and a sibling cannot be a
   grid column of the inner — the 960-1100 two-column tier had no remaining
   implementation and rendered stacked at 1117px tall. Below 1100 the list is
   the layout. The composition would not have survived there anyway: the mock's
   own proportion yields a 44.0ch measure at 1100 and less below it. */
@media (min-width: 1100px) {
  .lp-ai-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(300px, 30vw, 420px);
    gap: 40px;
    align-items: center;
  }

  .lp-ai-text {
    max-width: 40rem;
  }
}

/* Stroke set in CSS, not as a presentation attribute: var() is not valid in an
   SVG presentation attribute, so stroke="var(--lp-ai-line)" resolved to none
   and the entire network painted nothing. */
.lp-ai-net-line,
.lp-ai-net-curve,
.lp-ai-net-joint {
  fill: none;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* Literals, not var(). The custom properties resolve on .lp-ai but come back
   EMPTY on the <g> inside the SVG in this engine, so var() here was invalid at
   computed-value time and stroke inherited `none` — the network painted
   nothing. styles.css permits raw hex (it is in none of the seven CSS
   ratchets), and these two values are the same ones .lp-ai declares. */
/* The mock's own two tiers, sampled from it: the chevron and the connectors
   are one value, the long curves a fainter one. The previous #3A4457 was raised
   for visibility against a background that was 15 units too blue; on #090F19
   the mock's values carry themselves. */
.lp-ai-net-line { stroke: #2D2E32; }

.lp-ai-net-curve { stroke: #1F2228; }

.lp-ai-net-joint { stroke: #C2B5A8; }

/* The numbers band drops its section padding from 24px to 16px between 740 and
   720, so the inset follows it there or the two edges disagree by 8px in that
   range. */
@media (max-width: 720px) {
  .lp-ai {
    --lp-ai-inset: min(calc(max(0px, (100% - 1200px) / 2) + 16px), calc(7.42% - 6px));
  }
}

/* MOBILE-FIRST. Below 960 the constellation is REPLACED, not scaled: a plain
   vertical list, one row per capability, tile beside its question with a
   hairline between rows. The SVG network, the absolute placement, --x/--y and
   the drift all belong to the constellation, so they are switched ON at the
   breakpoint rather than unwound here. */
.lp-ai-figure {
  min-width: 0;
  /* Stacked, the text block and the list are plain siblings with nothing
     between them. 40px is the two-column grid's own gap reused in the stacked
     direction, not a separate number for this layout. */
  margin-top: 40px;
}

.lp-ai-net {
  display: none;
}

/* The list tier has no column to constrain it, so the text needs its own cap:
   without one the measure reached 92.8ch at 1024, well past readable. The
   overlay tier overrides this with the mock's 47%. */
.lp-ai-text {
  max-width: 40rem;
}

.lp-ai-node {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* Separator BETWEEN rows only. Adjacent-sibling form, so the list neither
   opens nor closes on a rule and no :first-child reset is needed — the SVG is
   the figure's first child, which would have made :first-child wrong anyway. */
.lp-ai-node + .lp-ai-node {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--lp-ai-edge);
}

/* 64px is the constellation clamp's OWN floor, not a new number: the tiles
   already render at exactly 64 from 960 down, so the list keeps the size the
   design had reached. Against the 192px source that is 3x, and at the 320
   content box it still leaves 194px of measure for the question. */
.lp-ai-tile {
  flex: none;
  width: 64px;
  height: auto;
  border-radius: 10px;
  /* No filter. The per-tile treatment is BAKED into the delivery WebPs: the
     same brightness/saturate pair, applied to the 320px masters at generation
     time. A live filter promoted each tile to a composited layer once the
     entrance animated its opacity, and the filter resampled differently there
     -- 2.6% of the band's pixels differed between the settled entrance and no
     entrance at all. Baking removes that, and a per-frame paint on five
     composited images with it. */
}

.lp-ai-q {
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
  font-size: clamp(0.9375rem, 1.15vw, 1.125rem);
  line-height: 1.25;
  color: var(--lp-ai-ink);
}

/* Drift. Five durations sharing no common factor, so the five never resync:
   17 / 19 / 23 / 29 / 31 seconds are consecutive primes. The diagonals run
   0.295vw per axis on the diagonals, not 0.417: the excursion is the
   HYPOTENUSE, so 0.295 x root-2 is 0.417vw, the same span the two single-axis
   drifts get -- 6px at 1440. In vw so it scales with the tiles.
   The binding constraint is NOT the joint radius: the rings sit at the QUESTION
   end of each connector, so a drifting tile cannot pull away from one. It pulls
   away from its connector's tile-side endpoint, and those gaps are the limit.
   6px leaves the tightest of them (schedule) at 1.8px; 8px closed it to 0.3px,
   at which the joint stops reading as a joint.
   Transform only — no layout property is animated. */
/* M3 ENTRANCE. Opacity and a small lift only -- no scale, which would resample
   the tile texture and soften it. The lift is in vw so it scales with the tile,
   and both keyframes carry the -50% centring so the animation composes with the
   resting transform instead of replacing it. */
@keyframes lp-ai-net-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes lp-ai-tile-in {
  from { opacity: 0; transform: translate(-50%, calc(-50% + 0.55vw)); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}

@keyframes lp-ai-q-in {
  from { opacity: 0; transform: translateY(calc(-50% + 0.55vw)); }
  to   { opacity: 1; transform: translateY(-50%); }
}

@keyframes lp-ai-drift-a { 50% { transform: translate(-50%, calc(-50% - 0.556vw)); } }
@keyframes lp-ai-drift-b { 50% { transform: translate(calc(-50% + 0.556vw), -50%); } }
@keyframes lp-ai-drift-c { 50% { transform: translate(calc(-50% - 0.393vw), calc(-50% + 0.393vw)); } }
@keyframes lp-ai-drift-d { 50% { transform: translate(calc(-50% + 0.393vw), calc(-50% - 0.393vw)); } }
@keyframes lp-ai-drift-e { 50% { transform: translate(calc(-50% - 0.393vw), calc(-50% - 0.393vw)); } }

/* CONSTELLATION — 1100 up, matching the overlay breakpoint above. Below this
   the list is the layout; there is no intermediate tier. */
@media (min-width: 1100px) {
  .lp-ai-figure {
    position: relative;
    aspect-ratio: 420 / 384;
    /* The grid gap separates the columns here. */
    margin-top: 0;
  }

  /* A ZERO-SIZE anchor placed on the TILE's centre, which is what the mock's
     fractional centres measure. An earlier version centred the whole node —
     tile plus question — so a right-hand question pushed its tile left, by up
     to 63px at 1440, and two tiles ended up outside the figure box. */
  .lp-ai-node {
    display: block;
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: 0;
    height: 0;
    will-change: transform;
  }

  .lp-ai-node + .lp-ai-node {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }

  .lp-ai-tile {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: clamp(64px, 6.4vw, 96px);
    border-radius: 12px;
  }

  /* Question sits beside its tile, outside the tile's half-width plus a gap. */
  .lp-ai-q {
    position: absolute;
    top: 50%;
    width: max-content;
    max-width: 9.5em;
    transform: translateY(-50%);
  }

  .lp-ai-node--qright .lp-ai-q {
    left: calc(50% + clamp(64px, 6.4vw, 96px) / 2 + 14px);
  }

  .lp-ai-node--qleft .lp-ai-q {
    right: calc(50% + clamp(64px, 6.4vw, 96px) / 2 + 14px);
    text-align: right;
  }

  /* F1. NEGATIVE delays, so each tile starts already advanced into its cycle
     rather than waiting to begin -- a positive delay would hold a tile still
     for up to 31s before it first moved. Each is a distinct fraction of its own
     duration (0.10 / 0.30 / 0.50 / 0.70 / 0.90), so at t=0 the five are spread
     across the cycle instead of all leaving rest together. */
  .lp-ai-node--plan     { animation: lp-ai-drift-a 17s ease-in-out -1.70s infinite; }
  .lp-ai-node--weakness { animation: lp-ai-drift-b 19s ease-in-out -5.70s infinite; }
  .lp-ai-node--quiz     { animation: lp-ai-drift-c 23s ease-in-out -11.50s infinite; }
  .lp-ai-node--schedule { animation: lp-ai-drift-d 29s ease-in-out -26.10s infinite; }
  .lp-ai-node--teach    { animation: lp-ai-drift-e 31s ease-in-out -21.70s infinite; }
}

/* THE OVERLAY, 1100 up. The band is pinned to the mock's 1672 x 941 so every
   --x/--y in the markup is the mock's own fraction, measured from it. A grid
   cannot express this composition: the mock's leftmost tile sits at x 0.433
   while the text runs to 0.475, so tiles and text overlap horizontally and
   clear each other vertically instead. */
@media (min-width: 1100px) {
  .lp-ai {
    aspect-ratio: 1672 / 941;
    /* The mock's own gutter. Its text block starts at x 0.0742 of the band;
       with the inner capped at 1100 and centred, the text's left edge drifted
       from 0.044 at 1100 to 0.118 at 1440 -- the last part of the composition
       still set by my numbers instead of the mock's. */
    padding-left: 7.42%;
    padding-right: 7.42%;
  }

  /* STEP 4. Centred, not offset. The block's height is no longer stable --
     four corrections have changed it -- so any fixed top offset drifts: the
     shift needed to centre was 2.698vw at 1440 but 0.761vw at 1100, because
     the block shrinks faster than the band does. Flex centring is width-
     independent and needs no number. */
  /* M2. Half the gutter, as it always was -- but the gutter stopped being 48px
     when the band took the mock's 7.42%, so a fixed 24px inset had drifted to
     0.225 of the gutter at 1440 while still reading 0.500 below 1100. */
  .lp-ai {
    /* Named so the tiles hang off the SAME timeline as the expand and the two
       read as one gesture. The expand keeps its anonymous view(). */
    view-timeline-name: --lp-ai-view;
  }

  /* The network arrives first and the tiles land on it, rather than everything
     fading up together. */
  .lp-ai-net {
    animation: lp-ai-net-in linear both;
    animation-timeline: --lp-ai-view;
    animation-range: entry 5% entry 30%;
  }

  .lp-ai-tile {
    animation: lp-ai-tile-in linear both;
    animation-timeline: --lp-ai-view;
  }

  .lp-ai-q {
    animation: lp-ai-q-in linear both;
    animation-timeline: --lp-ai-view;
  }

  /* Stagger. 6% of the entry phase between tiles, in the reading order of the
     constellation rather than DOM order. */
  .lp-ai-node--plan     .lp-ai-tile,
  .lp-ai-node--plan     .lp-ai-q { animation-range: entry 26% entry 56%; }
  .lp-ai-node--weakness .lp-ai-tile,
  .lp-ai-node--weakness .lp-ai-q { animation-range: entry 32% entry 62%; }
  .lp-ai-node--quiz     .lp-ai-tile,
  .lp-ai-node--quiz     .lp-ai-q { animation-range: entry 38% entry 68%; }
  .lp-ai-node--teach    .lp-ai-tile,
  .lp-ai-node--teach    .lp-ai-q { animation-range: entry 44% entry 74%; }
  .lp-ai-node--schedule .lp-ai-tile,
  .lp-ai-node--schedule .lp-ai-q { animation-range: entry 50% entry 80%; }

  .lp-ai-inner {
    display: flex;
    align-items: center;
    min-height: 100%;
    max-width: none;
  }

  /* T1. The block sat at 0.0746 of band height where the mock puts it at
     0.2391, which ran the headline's second line under the plan tile at 1440
     (-25.2px). vw because a percentage margin resolves against WIDTH, and
     these are fractions of band HEIGHT: band aspect is 1.7768, so 1% of height
     is 0.5628vw. The two internal gaps are the mock's own. */
  .lp-ai-text {
    position: relative;
    z-index: 1;
    max-width: 47%;
  }


  /* Absolute against .lp-ai, NOT .lp-ai-inner. The inner is inset by the band
     padding, and the mock's coordinates are fractions of the whole band, so
     the inner deliberately stays static and this resolves against the section. */
  .lp-ai-figure {
    position: absolute;
    inset: 0;
    margin-top: 0;
    aspect-ratio: auto;
  }

  .lp-ai-net {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }

  /* vw, not %: the node is a zero-size anchor, so a percentage width would
     resolve against 0. The band is full-bleed, so 1vw is 1% of band width and
     these are the mock's own per-tile fractions. */
  .lp-ai-tile {
    width: var(--tile-w, 5.26vw);
  }

  /* The questions are placed from the mock too, not derived from the tile edge.
     The old tile.right + 14px formula put three of them on top of their own
     connector rings, and it could not express weakness, whose question sits
     7.81% of band height BELOW its tile rather than level with it. vw because
     the node is zero-size: a percentage would resolve against 0. */
  .lp-ai-q {
    top: var(--qdy, 0px);
  }

  .lp-ai-node--qright .lp-ai-q {
    left: var(--qdx, 8.5vw);
  }

  .lp-ai-node--qleft .lp-ai-q {
    right: var(--qdx, 5.2vw);
  }
}

/* M4. Placed AFTER every rule it has to beat: media queries add no specificity,
   so a reduced-motion block earlier in the file loses to a later @media
   (min-width) block on the same selector. That exact mistake was made once
   already this session. Explicit resting states, not just `animation: none` --
   an infinite keyframe at 0ms is not reliably a no-op, and `none` alone strands
   whatever the last frame applied. */
@media (prefers-reduced-motion: reduce) {
  .lp-ai {
    animation: none;
    clip-path: none;
  }

  .lp-ai-net {
    animation: none;
    opacity: 1;
  }

  /* .lp-ai-node belongs here too, not only in the early block: the overlay's
     drift rule is later in the file, so an `animation: none` up there loses the
     cascade and the drift keeps running under reduced motion. */
  .lp-ai-node {
    animation: none;
  }

  .lp-ai-tile,
  .lp-ai-q {
    animation: none;
    opacity: 1;
  }

  /* Transforms only where the overlay actually sets them. Below 1100 the tile
     is a static flex child with no transform of its own, and forcing one here
     would drag every list row up and left by half its own box. */
  @media (min-width: 1100px) {
    .lp-ai-tile { transform: translate(-50%, -50%); }
    .lp-ai-q { transform: translateY(-50%); }
  }
}

/* A plain label, on the same metrics as the page's other kickers --
   .nb-home-eyebrow (--nb-type-label, 600 at 0.8125rem, 0.08em) and
   .lp-mark-kicker (0.8125rem / 600 / 0.08em). The pill it replaced was the one
   templated-looking thing on the page: a bordered capsule with a tan dot,
   generic AI-product chrome rather than this page's voice.
   Literal values, not var(--nb-type-label): the band is deliberately
   self-contained in styles.css because the --nb-* layer is gated on
   NOTEBOOK_PROOF and vanishes in a flag-off build -- the same reason
   .lp-mark-kicker writes its metrics out. */
.lp-ai-eyebrow {
  margin: 0 0 26px;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--lp-ai-ink);
}

.lp-ai-title {
  margin: 0 0 22px;
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
  font-size: clamp(2.25rem, 4.4vw, 3.75rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: var(--lp-ai-ink);
}

.lp-ai-sub {
  margin: 0;
  max-width: 34rem;
  /* STEP 1. One step up from 17px. The subhead was carrying too little weight
     against a 60px headline; 18px keeps the ratio at 3.33:1, still unambiguously
     subordinate, and does not change the line count at any overlay width. */
  font-size: 1.125rem;
  line-height: 1.6;
  color: var(--lp-ai-ink-2);
}

/* These three have to sit AFTER the base .lp-ai-eyebrow / .lp-ai-title rules
   above, not in the overlay block further up: same specificity, and the base
   rules are later in the file, so an override up there loses the cascade and
   silently does nothing. It did -- the two gaps below were reported as applied
   in the previous pass and were not.
   The headline's pitch is a TYPE decision, not a band-geometry one. Matching
   the mock's 0.110521-of-band-height pitch gave 5.20vw = 74.9px on a 60px font
   -- a 1.25 ratio, loose enough on display type that the lines read as
   separate. The mock's 1.49 ratio came off a canvas whose font-size-to-band
   relationship is not ours, so it was the wrong target to chase. 1.15 is the
   display-appropriate value: 69px at 1440, and unitless so it tracks the
   font-size at every width rather than the band. */
@media (min-width: 1100px) {
  .lp-ai-eyebrow {
    margin-bottom: 2.40vw;
  }

  .lp-ai-title {
    /* C1 set this ink-to-ink against the mock's 0.0531. STEP 3 then reset it
       on RHYTHM rather than on the mock: the eyebrow is a bordered pill, so
       the gap the eye reads runs from its BORDER, not its text ink -- 44px,
       against 41px below the headline, a ratio of 1.07:1. Near-equal spacing
       makes the eyebrow, headline and subhead read as three peers. They are
       not: the eyebrow is a label and the subhead is the headline's
       continuation, so the gap below the headline should be the smaller one.
       0.67vw gives 31.3px, a 1.40:1 ratio. Beyond about 1.6:1 the eyebrow
       starts to detach from the block entirely. */
    margin-bottom: 0.67vw;
    line-height: 1.15;
  }
}

/* ── Mark scheme artifact ─────────────────────────────────────
   PAGE background, not the band's navy: the AI band stays the page's only
   full-bleed dark break. No card -- a single hairline between the columns,
   following the numbers band's hairlines-over-cards precedent and the MCQ
   de-carding. Padding matches .lp-persuade, NOT the band's 7.42% gutter,
   which is specific to the band's mock coordinate space. */
.lp-mark {
  /* Scoped set, mirroring the AI band's --lp-ai-* naming so the two read as
     siblings in the source. Self-contained in styles.css for the same reason
     the band is: notebook-public-skin.css and its --nb-* tokens are gated on
     NOTEBOOK_PROOF and vanish in a flag-off build. --text/--muted are NOT used
     -- theme-light.css declares them on an unscoped :root, so they hold the
     same value in both themes. */
  /* C1. ONE ink. #B3B0A6 is the same warm grey as --nb-ink-2 and --muted, and
     it reads sage against near-black -- its third appearance on this page. The
     cross and the [0] already say "no mark", so dimming the withheld row made
     the row carrying the most information the quietest thing in the column. */
  --lp-mark-ink: #F0EFEC;
  --lp-mark-edge: rgba(255,255,255,0.10);
  --lp-mark-award: rgb(111,191,143);
  --lp-mark-withheld: rgb(232,106,90);
  padding: clamp(52px,4.2vw,72px) 48px clamp(48px,4vw,68px);
}

.lp-mark-inner {
  max-width: 1100px;
  margin: 0 auto;
}

.lp-mark-head {
  max-width: 40rem;
  margin: 0 auto clamp(34px, 3vw, 48px);
  text-align: center;
}

.lp-mark-title {
  margin: 0 0 12px;
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
  font-size: clamp(2rem, 3.4vw, 3rem);
  line-height: 1.15;
  font-weight: 500;
  color: var(--lp-mark-ink);
}

.lp-mark-sub {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.6;
  color: var(--lp-mark-ink);
}

/* Stacked below 1100. Two columns need a 45ch measure and a half column falls
   to 43.1ch at 1024, so 1100 is the last width that holds -- the same floor the
   AI band reaches from its own direction. */
.lp-mark-artifact {
  display: grid;
  gap: 32px;
}

/* Kicker follows .nb-home-eyebrow's metrics -- plain uppercase, no pill, no
   dot. The band's eyebrow is a pill; reusing it would read as a second band.
   Colour is a page-safe rgba, not var(--nb-ink): the notebook token layer is
   dropped when NOTEBOOK_PROOF is False and --nb-* would resolve to nothing. */
.lp-mark-kicker {
  margin: 0 0 14px;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--lp-mark-ink);
}

.lp-mark-quote {
  margin: 0;
  border: 0;
  padding: 0;
}

.lp-mark-quote p {
  margin: 0;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--lp-mark-ink);
}

.lp-mark-rows {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* L1. The mark sits in the SAME inline flow as its point, so it follows the
   text immediately and wraps with it -- which is what the mock shows on the
   four-line row, where [0] trails "ribosome." rather than sitting in a column.
   A grid put the marks ~700px from their text at 1440, reading as a column of
   numbers instead of that point's score.
   L2. No separators: the mock has none, and this section has no card, so a rule
   between rows would reintroduce the chrome the no-card call removed. The rows
   are separated by space and by their icons.
   The icon is absolutely placed so it stays on the FIRST line when a point
   wraps, which a baseline-aligned flex item would not do. */
.lp-mark-row {
  position: relative;
  padding: 9px 0 9px 32px;
}

.lp-mark-icon {
  position: absolute;
  left: 0;
  top: 11px;
  width: 20px;
  height: 20px;
}

.lp-mark-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* The two semantic accents are the MCQ stage's own correct/incorrect tokens.
   Award and no-award map onto them exactly, so no new accent enters the
   four-accent budget. currentColor carries them into the inline SVG -- var()
   is invalid in an SVG presentation attribute. */
.lp-mark-row--award .lp-mark-icon { color: var(--lp-mark-award); }
.lp-mark-row--withheld .lp-mark-icon { color: var(--lp-mark-withheld); }

.lp-mark-point,
.lp-mark-score {
  font-size: 1rem;
  line-height: 1.55;
  color: var(--lp-mark-ink);
}

.lp-mark-score {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* THE ONE ANIMATION. The row text is present from the first frame; only the
   icon and the mark arrive. A row that faded in whole would read as content
   loading -- this reads as the point being marked, which is the artifact's
   whole argument. Default state is RESOLVED and the unresolved state lives
   only inside the keyframe, so a browser without scroll-timeline shows a
   finished artifact rather than an empty one. */
@keyframes lp-mark-resolve {
  from {
    opacity: 0;
    transform: translateY(-3px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.lp-mark {
  view-timeline-name: --lp-mark-view;
}

.lp-mark-icon,
.lp-mark-score {
  animation: lp-mark-resolve linear both;
  animation-timeline: --lp-mark-view;
}

/* Staggered by 8% of the entry phase. Scroll ranges, not seconds -- a
   scroll-driven timeline has no wall-clock duration. */
.lp-mark-row:nth-child(1) .lp-mark-icon,
.lp-mark-row:nth-child(1) .lp-mark-score { animation-range: entry 30% entry 45%; }
.lp-mark-row:nth-child(2) .lp-mark-icon,
.lp-mark-row:nth-child(2) .lp-mark-score { animation-range: entry 38% entry 53%; }
.lp-mark-row:nth-child(3) .lp-mark-icon,
.lp-mark-row:nth-child(3) .lp-mark-score { animation-range: entry 46% entry 61%; }
.lp-mark-row:nth-child(4) .lp-mark-icon,
.lp-mark-row:nth-child(4) .lp-mark-score { animation-range: entry 54% entry 69%; }

@media (min-width: 1100px) {
  .lp-mark-artifact {
    grid-template-columns: 1fr 1fr;
    gap: 0;
    align-items: start;
  }

  .lp-mark-col--answer {
    padding-right: 32px;
  }

  /* The hairline. 32px either side puts it on the inner's midpoint, which is
     where the mock's divider sits (393px / 394px columns). */
  .lp-mark-col--eval {
    padding-left: 32px;
    border-left: 1px solid var(--lp-mark-edge);
  }
}

/* Stacked below 1100: the divider turns from a vertical rule between columns
   into a horizontal one between blocks, so the two still read as one artifact
   rather than two sections. */
@media (max-width: 1099.98px) {
  .lp-mark-col--eval {
    padding-top: 28px;
    border-top: 1px solid var(--lp-mark-edge);
  }
}

/* Reduced motion: the artifact renders fully resolved. Explicit resting state,
   not just `animation: none` -- that strands whatever the last frame applied,
   and an infinite keyframe at 0ms is not reliably a no-op. */
@media (prefers-reduced-motion: reduce) {
  .lp-mark-icon,
  .lp-mark-score {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* ── A clearer way to revise ───────────────────────────────────
   Restyled to the mark-scheme artifact's terms, because the two sit adjacent
   and two adjacent sections should not run two conventions: the same serif
   headline, the same plain kicker, ONE ink, a single hairline, and the PAGE
   background.
   No section background of its own -- the page's paper shows through, as it
   does behind .lp-mark.
   ONE rule per boundary, never zero and never two. border-top STAYS: .lp-mark
   sits directly above (the AI band is two sections up, behind it) and .lp-mark
   draws no edge of its own, so without this the two would meet with nothing
   between them -- measured as a 0.00 luminance step at all nine widths in both
   themes. An unmarked boundary is fine between two visually distinct sections;
   these two share a background AND a typographic language.
   border-bottom is GONE: it sat 0px above .lp-divider, which draws that seam
   itself, so it was the genuinely doubled one. */
.lp-persuade {
  padding: clamp(52px,4.2vw,72px) 48px clamp(48px,4vw,68px);
  position: relative;
  border-top: 1px solid rgba(130,148,215,0.10);
  /* Mirrors --lp-mark-edge, which is declared ON .lp-mark (and on
     html.theme-light .lp-mark) and so cannot be inherited here. Same two
     values, so both sections draw the identical hairline. */
  --lp-persuade-edge: rgba(255,255,255,0.10);
}

/* The light value lives here rather than in theme-light.css: that file's HEAD
   blob has corrupt mixed line endings, so any edit to it diffs as one
   whole-file hunk and cannot be staged by hunk. */
html.theme-light .lp-persuade {
  --lp-persuade-edge: rgba(21,26,45,0.14);
}

.lp-persuade-inner {
  position: relative;
  z-index: 1;
  max-width: 1100px;
  margin: 0 auto;
}

/* .lp-mark-kicker's metrics exactly -- plain uppercase, no pill, no border.
   The pill was the last card-shaped thing above the proofs.
   It inherits the lede's alignment rather than setting its own. f41bbcf5
   centred it here to stop it starting 230px left of the heading it
   introduces; the split keeps that fix by a different route -- eyebrow,
   heading and body are now siblings in one left-aligned column, so they share
   an edge because they share a parent, not because three rules agree. */
.lp-persuade-eyebrow {
  display: block;
  margin: 0 0 14px;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The LEFT column of the split, and the whole lede when stacked. Left-aligned
   at every width: the section had three left edges before f41bbcf5 and one
   after, and keeping one axis is that fix, not the particular axis it chose.
   Centring it again above the breakpoint would put the heading on a different
   line from the features it introduces.
   No max-width of its own -- the grid track is the measure now, and it is
   sized so the heading keeps its two-line break (see the track note below). */
.lp-persuade-content {
  margin: 0 0 clamp(34px, 3vw, 48px);
  text-align: left;
}

/* .lp-mark-title's family, weight and leading. The serif lives HERE, not in
   notebook-public-skin.css, on purpose: that file sits inside the
   notebook-*.css glob whose typography ratchet freezes a count and a SHA over
   every font-family declaration. .lp-mark-title sets the precedent.
   The clamp MAXIMUM is the one thing that is no longer verbatim -- 2.7rem
   against .lp-mark-title's 3rem, so the two headlines differ by 4.8px from
   1412px up, where both reach their cap. That is the price of equal columns:
   the heading's binding line is "IGCSE, A-Level, AP & SAT", and in the 518px
   an even track leaves it, 2.75rem breaks to three lines with "SAT" alone.
   2.7rem holds the two-line break at 1412, 1440, 1920 and 2560 -- measured by
   line text, not by counting lines, because a count of 2 says nothing about
   where the break fell. Headroom is under one 0.05rem step, so treat this
   number as load-bearing: raising it re-orphans "SAT" only above 1412px,
   which is invisible at the widths most people test at. */
.lp-persuade-title {
  margin: 0 0 12px;
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
  font-size: clamp(2rem, 3.4vw, 2.7rem);
  line-height: 1.15;
  font-weight: 500;
}

/* .lp-mark-sub verbatim. Colour comes from the skin's var(--nb-ink) -- the
   same ink as the title, matching the artifact's ONE-ink rule. */
.lp-persuade-body {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.6;
}

/* The RIGHT column of the split, and the second block when stacked. The three
   proofs are ROWS, each a label ABOVE its sentence -- never label-left /
   sentence-right again. That two-column row is what left a 388.5px gap
   between a 161.5px label and its own rule, which f41bbcf5 closed; the split
   moves the vertical hairline out to the column boundary, where a rule
   between two blocks of different kinds belongs, instead of down the middle
   of one row. */
.lp-persuade-proofs {
  display: grid;
  gap: 0;
  align-content: start;
}

/* The separator is now BETWEEN rows and horizontal -- three features reading
   as one list, which is what the hairline in .lp-mark-artifact does for two
   columns. The earlier note here argued a rule between rows would reintroduce
   card chrome; that held while each row already carried its own vertical rule
   and a second one would have boxed it. With the vertical rule moved to the
   column edge these are the only separators the list has, and without them
   three unpadded blocks run together. Adjacent-sibling, so no rule hangs off
   the last row and none sits above the first. */
.lp-proof {
  display: grid;
  gap: 0;
  padding: 18px 0;
  text-align: left;
}

/* The descendant part of this selector is LOAD-BEARING, not tidiness.
   notebook-public-skin.css carries `html .lp-persuade .lp-proof { border: 0 }`
   -- (0,2,1) -- to neutralise the white card theme-light.css would otherwise
   paint here. A bare `.lp-proof + .lp-proof` is (0,2,0) and loses to it, so
   the separators measured 0px in BOTH themes with the notebook flag on, which
   is every production build. Adding .lp-persuade-proofs makes this (0,3,0),
   which wins on class count. Fixed here rather than by relaxing the skin: that
   rule still has a white card to suppress. */
.lp-persuade-proofs .lp-proof + .lp-proof {
  border-top: 1px solid var(--lp-persuade-edge);
}

/* Flush with the column's top and bottom so the vertical rule, which spans
   the whole grid row, starts and ends level with the text beside it rather
   than 18px proud of it. */
.lp-proof:first-child {
  padding-top: 0;
}

.lp-proof:last-child {
  padding-bottom: 0;
}

.lp-proof-title {
  margin: 0 0 4px;
  font-size: 1rem;
  line-height: 1.55;
  font-weight: 600;
}

.lp-proof-body {
  margin: 0;
  font-size: 1rem;
  line-height: 1.55;
}

/* THE SPLIT. Lede left, features right, one vertical hairline between them --
   .lp-mark-artifact's own shape, one section up, down to the 32px either side
   and the 1px rule. The section was 607.3px tall at 1440 holding a 640px
   column of text inside an 1100px cap; side by side the same words measure
   462.2px, and the 1100 cap is filled rather than straddled.
   The rule rides the RIGHT column's border-left, exactly as
   .lp-mark-col--eval's does. Not the left column's border-right: the lede is
   the shorter of the two at every width measured (242.3 against 343.2 at
   1440), and align-items defaults to stretch, so a border on the taller
   element spans the row either way -- but only the right one keeps spanning it
   if the lede ever grows past the features.

   960, not 1100. Above it the heading keeps the two-line break it has always
   had and every feature sentence stays two lines; at 900 the sentences go to
   three at a 39ch measure, and by 820 the heading breaks to three with "SAT"
   alone on the last line. 960 is the narrowest width measured where neither
   happens.

   EQUAL tracks. The first cut ran 1.3fr against 1fr so the heading could keep
   its break at 3rem, which left the lede 143.4px more content width than the
   features and set all three sentences to two lines while the heading had
   slack. Evening the tracks moves that width to the side that was short; the
   heading pays for it with a smaller cap (see .lp-persuade-title).

   TWO ROWS, and the eyebrow owns the first one. It used to sit inside the
   lede, which put the features' first label at exactly the eyebrow's y --
   measured at 0.0px apart, and 48.1px ABOVE the heading's cap. Nothing about
   a kicker and a feature label makes them peers. Row 2 holds the heading and
   the features, so the two columns start together on the content that
   matters, and the kicker reads as a label above the pair.
   1fr on row 2 lets it take the leftover height, so the rule spans the whole
   of it rather than stopping at whichever column is shorter. */
@media (min-width: 960px) {
  .lp-persuade-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    gap: 0;
  }

  .lp-persuade-eyebrow {
    grid-column: 1;
    grid-row: 1;
  }

  /* The bottom margin is the stacked gap between lede and features; side by
     side there is nothing below it to clear. */
  .lp-persuade-content {
    grid-column: 1;
    grid-row: 2;
    margin-bottom: 0;
    padding-right: 32px;
  }

  .lp-persuade-proofs {
    grid-column: 2;
    grid-row: 2;
    padding-left: 32px;
    border-left: 1px solid var(--lp-persuade-edge);
  }
}

/* THE ONE ANIMATION, on the artifact's own mechanism. Only the SENTENCE
   arrives; its label and every hairline are present from the first frame, so a
   row reads as a point being completed rather than as content loading -- which
   is exactly why .lp-mark-row animates its icon and score instead of the whole
   row. Default state is RESOLVED and the unresolved state lives only inside
   the keyframe, so a browser without scroll-timeline shows a finished
   section.
   It stays on .lp-proof-body and NOT on .lp-proof: the row now carries the
   border-top separating it from the one above, and animating the row would
   fade that rule in with it. Both hairlines -- the column rule and the row
   separators -- are on elements nothing animates. */
@keyframes lp-persuade-resolve {
  from {
    opacity: 0;
    transform: translateY(-3px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.lp-persuade {
  view-timeline-name: --lp-persuade-view;
}

.lp-proof-body {
  animation: lp-persuade-resolve linear both;
  animation-timeline: --lp-persuade-view;
}

/* Staggered by 8% of the entry phase -- the artifact's own step. Scroll
   ranges, not seconds: a scroll-driven timeline has no wall-clock duration. */
.lp-proof:nth-child(1) .lp-proof-body { animation-range: entry 30% entry 45%; }
.lp-proof:nth-child(2) .lp-proof-body { animation-range: entry 38% entry 53%; }
.lp-proof:nth-child(3) .lp-proof-body { animation-range: entry 46% entry 61%; }

/* Reduced motion: the section renders fully resolved. Explicit resting state,
   not just `animation: none` -- that strands whatever the last frame applied. */
@media (prefers-reduced-motion: reduce) {
  .lp-proof-body {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* ── Pricing ─────────────────────────────────────────────── */
.lp-pricing,
.lp-pricing--page {
  --lp-price-card-bg:
    radial-gradient(circle at 18% 0%, rgba(91, 140, 255, 0.055), transparent 34%),
    linear-gradient(180deg, rgba(18, 25, 46, 0.96) 0%, rgba(8, 12, 24, 0.99) 100%);
  --lp-price-card-border: rgba(148, 163, 184, 0.20);
  --lp-price-card-shadow: 0 30px 90px rgba(0, 0, 0, 0.36), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  --lp-price-divider: rgba(129, 143, 186, 0.14);
  --lp-price-surface: rgba(255,255,255,0.04);
  --lp-price-surface-2: rgba(255,255,255,0.03);
  --lp-price-text: rgba(245, 248, 255, 0.96);
  --lp-price-muted: rgba(199, 210, 235, 0.74);
  --lp-price-faint: rgba(185, 196, 224, 0.58);
  --lp-price-accent: #6b83f5;
  --lp-price-accent-border: rgba(107, 131, 245, 0.30);
  --lp-price-accent-surface: rgba(64, 96, 220, 0.13);
  --lp-price-accent-soft: rgba(107, 131, 245, 0.14);
  --lp-price-accent-strong: #4060e0;
  --lp-price-accent-shadow: 0 16px 28px rgba(40, 64, 188, 0.22);
  --lp-price-success: rgba(94, 234, 212, 0.94);
  --lp-price-success-bg: rgba(20, 184, 166, 0.14);
}

/* Padding matched to .lp-mark, not kept at this section's old
   clamp(72px,6vw,96px) -- three consecutive sections on one rhythm. */
.lp-pricing {
  padding: clamp(52px,4.2vw,72px) 48px clamp(48px,4vw,68px);
  /* Mirrors --lp-mark-edge, which is scoped to .lp-mark and so cannot be
     inherited here. Same two values, so all three sections draw one hairline. */
  --lp-pricing-edge: rgba(255,255,255,0.10);
}

/* Light value here rather than in theme-light.css: that file's HEAD blob has
   corrupt mixed line endings and cannot be staged by hunk. */
html.theme-light .lp-pricing {
  --lp-pricing-edge: rgba(21,26,45,0.14);
}

.lp-pricing-inner {
  max-width: 1100px;
  margin: 0 auto;
}

/* .lp-mark-head's block: same 40rem measure, same centred stack. */
.lp-pricing .lp-section-header {
  max-width: 40rem;
  margin: 0 auto clamp(34px, 3vw, 48px);
  text-align: center;
}

/* The card is now an UNSTYLED WRAPPER and the div must stay: pricing_panel.html
   renders `lp-animate` on it and landing.js:7 queries '.lp-animate, .lp-reveal',
   adding and removing lp-animate--visible at :12/:21/:57/:83/:85. Moving that
   class to another element is a change landing.js cannot see and no test would
   catch, so the element keeps it and simply stops painting.
   Two columns, one hairline, 32px either side -- .lp-mark-artifact's own shape,
   so the last three sections of the page share one column structure. */
.lp-pricing-card {
  max-width: 1100px;
  margin: 0 auto;
  display: grid;
  gap: 0;
  padding: 0;
  text-align: left;
}

.lp-pricing-badge {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  align-self: flex-start;
  margin-bottom: 24px;
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* .lp-pricing-badge-icon is gone with its markup: the gem glyph read as
   generic product chrome, and "Premium Access" says it without decoration. */

.lp-pricing-amount {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-start;
  gap: 8px;
  margin-bottom: 4px;
}

.lp-pricing-price {
  font-size: clamp(4.25rem, 7vw, 6.0rem);
  font-weight: 900;
  color: var(--lp-price-text);
  letter-spacing: -0.07em;
  line-height: 0.9;
}

.lp-pricing-period {
  font-size: clamp(1rem, 1.4vw, 1.2rem);
  font-weight: 500;
  color: rgba(203, 213, 225, 0.72);
}

.lp-pricing-tagline {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.97rem;
  color: var(--lp-price-muted);
  margin: 0;
}

.lp-pricing-list {
  list-style: none;
  padding: 0;
  margin: 0 0 32px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-align: left;
}

.lp-pricing-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1rem;
  color: rgba(255,255,255,0.76);
  margin: 0;
}

.lp-pricing-list li::before {
  content: "\2713";
  color: #22c55e;
  font-weight: 700;
  flex-shrink: 0;
}

.lp-pricing-note {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--lp-price-faint);
  margin: 0;
}

/* ── CTA footer group (button + view-link + note) ─────────── */
.lp-pricing-cta-footer {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 14px;
}

.lp-pricing-cta-footer .lp-pricing-note {
  margin: 0;
}

.lp-pricing-cta-footer .lp-pricing-secondary-cta {
  margin-top: 0;
}

.lp-pricing-secondary-cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-align: center;
  justify-content: center;
  margin-top: 2px;
  font-size: 0.95rem;
  font-weight: 600;
  color: rgba(198, 207, 255, 0.78);
  text-decoration: none;
  letter-spacing: -0.01em;
  transition: color 0.18s ease, transform 0.18s ease;
}

.lp-pricing-secondary-cta:hover {
  color: rgba(226, 231, 255, 0.96);
  transform: translateY(var(--lift-sm));
}

.lp-pricing-card-left .lp-pricing-secondary-cta {
  justify-content: flex-start;
}

/* ── Plan selector ───────────────────────────────────────── */
.lp-plan-selector {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* 24px, not the old 10px: with no boxes, the gap is the only thing separating
     one option from the next. */
  gap: 24px;
  margin-bottom: 26px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}

/* THE SELECTION LANGUAGE, copied from .lp-sv-tab rather than approximated:
   padding-bottom 8px, a 2px bottom border transparent at rest, --nb-blue when
   active. Same treatment, same role -- persistent selection -- so the page
   speaks one selection language instead of two. The transparent border at rest
   is what stops the row shifting when the choice moves.
   min-height stays 82px: the chrome goes, the hit area does not. */
.lp-plan-btn {
  display: flex;
  min-width: 0;
  max-width: 100%;
  box-sizing: border-box;
  overflow-wrap: anywhere;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 4px;
  min-height: 82px;
  padding: 0 0 8px;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  box-shadow: none;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

/* transform:none is NOT decorative. styles.css:293-300 gives every button a
   translateY(var(--lift-sm)) on hover site-wide; without this the options would
   bob. Hover reads as an ink lift instead, which the skin supplies. */
.lp-plan-btn:hover {
  transform: none;
}

.lp-plan-btn--active {
  border-bottom-color: var(--nb-blue);
  font-weight: 600;
}

.lp-plan-btn--active:hover {
  transform: none;
}

.lp-plan-btn:active {
  transform: scale(0.985);
  transition: transform var(--m-fast) var(--ease-out);
}

.lp-plan-btn:focus-visible {
  outline: 2px solid rgba(169, 190, 255, 0.62);
  outline-offset: 2px;
}

/* Plain micro-text, not a pill. Two filled pills inside a section whose whole
   point is that nothing is filled would have been the one surviving piece of
   chrome, and on the two most important options. The words do the work. */
.lp-plan-micro {
  display: block;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-transform: uppercase;
}

/* The per-option price. Each period shows its own figure so yearly can be read
   as good value against something, rather than against a blank. */
.lp-plan-price {
  display: block;
  font-size: 1rem;
  font-weight: 600;
}

.lp-plan-micro--featured {
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  line-height: inherit;
  text-transform: inherit;
}

.lp-plan-main {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.1;
  color: currentColor;
}

.lp-plan-check {
  display: none;
}

.lp-plan-btn--active .lp-plan-micro {
  background: transparent;
  border-color: transparent;
  color: rgba(160, 182, 255, 0.90);
}

.lp-plan-best-value {
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(160,182,255,0.72);
  line-height: 1.4;
}

/* Muted helper label for 3-month / monthly plan buttons */
.lp-plan-tag {
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.26);
  line-height: 1.4;
}

.lp-plan-btn--active .lp-plan-tag {
  color: rgba(160,182,255,0.55);
}

/* ── Pricing page variant ────────────────────────────────── */
.lp-pricing--page {
  padding-top: 80px;
}

/* Billing subline below the large price */
.lp-pricing-billing {
  font-size: 1rem;
  color: var(--lp-price-muted);
  margin: 0;
}

/* ── Wide two-column pricing card ────────────────────────── */
.lp-pricing-card--wide {
  display: grid;
  grid-template-columns: minmax(0, 0.96fr) minmax(0, 1.04fr);
  align-items: stretch;
  text-align: left;
  padding: 0;
}

.lp-pricing-card-left {
  padding: 0;
  display: flex;
  flex-direction: column;
}

.lp-pricing-card-right {
  padding: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

/* .lp-mark-kicker's metrics -- plain uppercase, no pill, no border, and the
   section's ink rather than the premium pill colour it used to borrow. */
.lp-pricing-card-right-label {
  margin: 0 0 14px;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.lp-pricing-card-right-sub {
  font-size: 1rem;
  color: var(--lp-price-muted);
  margin: 0 0 22px;
  line-height: 1.6;
}

/* .lp-pricing-divider is gone with its markup: the section's only hairline is
   the column rule, as in .lp-mark and .lp-persuade. A second horizontal rule
   inside one half would be the chrome this pass removed everywhere else. */

.lp-pricing-meta-icon,
.lp-pricing-note-icon {
  width: 30px;
  height: 30px;
  min-width: 30px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: rgba(190, 210, 255, 0.92);
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.06);
}

/* ── Premium benefit rows (right panel) ──────────────────── */
.lp-pricing-benefits {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0;
}

/* THE hairline -- the section's only one, and the same rule .lp-mark-col--eval
   and .lp-proof-title already draw: 1100 breakpoint, 32px either side, 1px.
   Three consecutive sections on one column structure. */
@media (min-width: 1100px) {
  .lp-pricing-card {
    grid-template-columns: 1fr 1fr;
  }

  .lp-pricing-card-left {
    padding-right: 32px;
  }

  .lp-pricing-card-right {
    padding-left: 32px;
    border-left: 1px solid var(--lp-pricing-edge);
  }
}

/* Stacked below 1100: the divider turns from a vertical rule between the halves
   into a horizontal one between them, exactly as .lp-mark-col--eval does. */
@media (max-width: 1099.98px) {
  .lp-pricing-card-right {
    padding-top: 28px;
    border-top: 1px solid var(--lp-pricing-edge);
  }
}

/* Rows, not boxes. Same 9px vertical rhythm as .lp-mark-row and .lp-proof.
   margin:0 is load-bearing -- styles.css has a generic `li { margin-bottom:
   0.55rem }` and these rows are <li>, so without the reset every row carries an
   extra 8.8px and the rhythm stops matching the two sections above. */
.lp-pricing-benefit {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  padding: 9px 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  font-size: 1rem;
  line-height: 1.55;
}

/* INK, not an accent, and no plate behind it. This tick is punctuation
   confirming inclusion -- nothing on this list can be "not awarded", so there
   is no judgment for it to carry. The identical glyph in .lp-mark-row IS
   semantic (award vs no-award) and correctly takes --lp-mark-award /
   --lp-mark-withheld. Same glyph, different job: do NOT unify these two. */
.lp-pricing-benefit-icon {
  width: 20px;
  height: 20px;
  min-width: 20px;
  margin-top: 1px;
  background: none;
  border: 0;
  border-radius: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.lp-pricing-benefit-text {
  display: block;
  color: inherit;
}

.lp-pricing-cta-primary {
  display: inline-flex;
  max-width: 100%;
  box-sizing: border-box;
  flex-wrap: wrap;
  overflow-wrap: anywhere;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-width: 0;
  min-height: 58px;
  padding: 18px 28px;
  border-radius: 18px;
  background: linear-gradient(135deg, #5b6cff 0%, #3d5afe 48%, #243fd6 100%);
  border: 1px solid rgba(107, 131, 245, 0.40);
  box-shadow: 0 18px 42px rgba(61, 90, 254, 0.26), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  font-size: 1.08rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.lp-pricing-cta-primary:hover {
  transform: translateY(var(--lift-sm));
  box-shadow: 0 22px 54px rgba(61, 90, 254, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.22);
  border-color: rgba(130, 158, 255, 0.48);
}

.lp-pricing-cta-primary:focus-visible {
  outline-color: rgba(150, 175, 255, 0.88);
}

/* Scroll anchor offset — keep section below sticky nav */
#pricing-card,
#pricing {
  scroll-margin-top: 108px;
}

/* button element using .lp-cta-primary */
button.lp-cta-primary {
  font-family: inherit;
  border: none;
  cursor: pointer;
}

button.lp-cta-primary:hover {
  transform: translateY(var(--lift-sm));
}

/* ── Final CTA ───────────────────────────────────────────── */
.lp-final-cta {
  padding: clamp(52px,4.5vw,68px) 48px clamp(56px,4.5vw,72px);
  border-top: 1px solid rgba(130,148,215,0.14);
  position: relative;
}

/* Subtle ambient top-glow — connects the close to the page atmosphere */
.lp-final-cta::before {
  content: '';
  position: absolute;
  top: 0;
  left: 15%;
  right: 15%;
  height: 200px;
  background: radial-gradient(ellipse at 50% 0%, rgba(60,80,200,0.06) 0%, transparent 70%);
  pointer-events: none;
}

.lp-final-cta-inner {
  max-width: 580px;
  margin: 0 auto;
  text-align: center;
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
  border-radius: 0;
  position: relative;
}

.lp-final-cta-title {
  font-size: clamp(2.5rem, 5vw, 3.75rem);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1.1;
  padding-bottom: 0.08em;
  margin: 0 0 20px;
  background: linear-gradient(to bottom, #ffffff 20%, rgba(176,200,255,0.82));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.lp-final-cta-sub {
  font-size: 1.0625rem;
  color: rgba(220,228,255,0.76);
  margin: 0 0 36px;
  line-height: 1.68;
  max-width: 420px;
  margin-left: auto;
  margin-right: auto;
}

.lp-final-cta .lp-free-note {
  color: rgba(210,220,255,0.56);
}

/* ── Responsive ──────────────────────────────────────────── */
@media (max-width: 960px) {
  /* Collapse hero to single column and re-center */
  .lp-hero {
    padding: 48px 36px 36px;
    text-align: center;
  }

  .lp-hero-inner {
    grid-template-columns: 1fr;
    gap: 48px;
  }

  .lp-hero-ctas {
    justify-content: center;
  }

  .lp-hero-content .lp-free-note {
    text-align: center;
  }

  .lp-subline {
    margin: 0 auto 40px;
    max-width: 560px;
  }

  /* In single-column context restore preview sidebar */
  .lp-hero-inner .lp-preview-sidebar {
    display: flex;
  }

  /* features grid stays 2-col until 700px */
  .lp-subject-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .lp-programme-group {
    padding: 20px 28px;
  }

  .lp-features .lp-section-header {
    text-align: center;
  }

  .lp-features .lp-section-sub {
    margin: 0 auto;
  }

  .lp-pricing-card--wide {
    grid-template-columns: 1fr;
  }

  .lp-pricing-card-left {
    padding: 38px 32px;
    border-right: none;
    border-bottom: 1px solid var(--lp-price-divider);
  }

  .lp-pricing-card-right {
    padding: 34px 32px 36px;
  }
}

@media (max-width: 700px) {
  .lp-hero {
    padding: 40px 24px 32px;
  }

  .lp-headline {
    font-size: clamp(2.25rem, 11vw, 3.25rem);
  }

  .lp-headline-line {
    white-space: normal;
  }

  .lp-cta-primary:not(.lp-cta-block) {
    min-width: 0;
    width: 100%;
    padding-left: 32px;
    padding-right: 32px;
  }

  .lp-features,
  .lp-boards,
  .lp-persuade,
  .lp-mark,
  .lp-pricing,
  .lp-final-cta {
    padding: 64px 24px;
  }

  /* Same 24px gutter the neighbouring sections already step down to, rather
     than a value chosen for this band. The clip inset is derived from that
     gutter — half of it — so it has to move with it: at the desktop 48px the
     inset is 24px, here it is 12px. An inset larger than the gutter would cut
     the content it is supposed to frame. */
  .lp-ai {
    padding: 64px 24px;
  }

  .lp-features-grid {
    grid-template-columns: 1fr;
  }

  /* On small screens collapse the programme groups to a stack */
  .lp-programme-groups {
    flex-direction: column;
    align-items: center;
    gap: 0;
  }

  .lp-programme-group {
    width: 100%;
    padding: 16px 24px;
    border-right: none;
    border-bottom: 1px solid rgba(255,255,255,0.07);
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }

  .lp-programme-group:last-child {
    border-bottom: none;
  }

  .lp-programme-group-label {
    width: 100px;
    text-align: left;
  }


  .lp-subject-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .lp-final-cta-sub {
    margin-left: 0;
    margin-right: 0;
    max-width: none;
  }

  .lp-pricing-card {
    padding: 0;
  }

  .lp-pricing-card-left {
    padding: 30px 22px;
  }

  .lp-pricing-card-right {
    padding: 28px 22px 30px;
  }

  .lp-pricing-benefit {
    border-radius: 14px;
    padding: 12px 13px;
    font-size: 0.9rem;
  }

  /* Plan selector: stack vertically on small screens */
  .lp-plan-selector {
    grid-template-columns: 1fr;
  }

  .lp-plan-btn {
    min-height: 0;
    flex-wrap: wrap;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: 11px 16px;
  }

  .lp-plan-micro {
    order: 2;
  }

  .lp-plan-main {
    order: 1;
    width: auto;
  }

  .lp-pricing-amount {
    gap: 6px;
  }

  .lp-pricing-price {
    font-size: clamp(3.35rem, 18vw, 4.1rem);
  }

  .lp-pricing-secondary-cta,
  .lp-pricing-card-left .lp-pricing-secondary-cta {
    justify-content: center;
  }

  .lp-particle-grid {
    grid-template-columns: 1fr;
    gap: 8px;
  }
}

/* =============================================================
   Programme Gateway Page (pg-* namespace)
   Used by subject_index.html and board-selector pages.
============================================================= */

/* ── Page-specific focal glow (subject_index.html only) ─── */
.pg-page-glow {
  position: fixed;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 920px;
  height: 68vh;
  background: radial-gradient(ellipse 70% 65% at 50% 5%, rgba(91,140,255,0.09) 0%, transparent 65%);
  filter: blur(64px);
  pointer-events: none;
  z-index: -1;
}

/* ── Inner wrapper ───────────────────────────────────────── */
.pg-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 40px;
}

/* ── Hero ────────────────────────────────────────────────── */
.pg-hero {
  padding: 80px 0 56px;
}

.pg-hero--sub {
  padding: clamp(48px, 6.5vh, 80px) 0 clamp(28px, 3.8vh, 56px);
}

.pg-hero-title {
  font-size: clamp(2.25rem, 5vw, 3.25rem);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.04em;
  color: #ffffff;
  margin: 0 0 20px;
  overflow-wrap: anywhere;
}

.pg-hero-body {
  font-size: 1.0625rem;
  color: rgba(255,255,255,0.62);
  line-height: 1.65;
  margin: 0;
  max-width: 500px;
}

/* ── Back link (ghost underline) ─────────────────────────── */
.pg-back {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 0 2px 9px 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-size: 0.9375rem;
  font-weight: 800;
  letter-spacing: -0.015em;
  color: #8fb2ff;
  text-decoration: none;
  margin-bottom: clamp(24px, 3.5vh, 44px);
  transition: color 0.18s ease, transform 0.18s ease;
}

/* Animated accent underline, starting after the chevron */
.pg-back::after {
  content: "";
  position: absolute;
  left: 25px;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, rgba(95,150,255,0.62), rgba(95,150,255,0.05));
  transform-origin: left;
  transform: scaleX(0.72);
  opacity: 0.6;
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.pg-back:hover {
  color: #b9ccff;
  transform: translateX(-1px);
}

.pg-back:hover::after {
  transform: scaleX(1);
  opacity: 0.9;
}

.pg-back:focus-visible {
  outline: 2px solid rgba(91,140,255,0.70);
  outline-offset: 4px;
  border-radius: 6px;
}

.pg-back-icon {
  flex-shrink: 0;
  opacity: 0.92;
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.pg-back:hover .pg-back-icon {
  opacity: 1;
  transform: translateX(-2px);
}

/* ── Programme context line (subject pages) ──────────────────── */
.pg-board-context {
  margin: 0 0 16px;
  font-size: 1rem;
  font-weight: 650;
  letter-spacing: 0.01em;
  color: rgba(203,213,225,0.70);
}

/* ── Board selector shell ────────────────────────────────── */
.pg-board-shell {
  /* Top-anchored: no forced viewport-centering (it left a dead gap above the
     cards). Content flows from the top with bounded padding; the sections
     below the cards fill the page. */
  /* Short-page treatment, same as .acg-page and .si-page: fill the screen
     below the topbar so the footer starts at the fold instead of surfacing
     mid-screen. The board pickers are one row of two cards, so without this
     they end ~340px above the fold and the footer reads as page content.
     Top-anchored, NOT centred -- the slack lands below the cards, where the
     body's own 1fr row already puts some of it today.
     e5165c83 reserved 96px less so the footer's wordmark peeked above the
     fold. Owner call 2026-09-03: no footer visible without scrolling, on any
     route, at any viewport. The peek is gone; the whole screen is reserved
     again. Only the media-query reorder from that commit survives -- see the
     block after .si-page (styles.css:7968). */
  min-height: calc(100svh - 72px);          /* topbar (chrome-navbar.css:20) */
  padding: clamp(16px, 2.4vh, 32px) 20px clamp(36px, 5vh, 60px);
  /* decorative card-column glow bleeds past the inner column; clip it so it
     never widens the scrollable area on narrow viewports */
  overflow-x: clip;
}

.pg-board-inner {
  width: min(100%, 1160px);
  /* horizontal centering only — vertical centering removed (it left a dead gap
     above the cards; content now flows from the top). */
  margin: 0 auto;
}

.pg-board-inner > .pg-back {
  margin-bottom: clamp(28px, 4.5vh, 42px);
}

/* ── Programme/board picker: stacked, centered hero + 2×2 card grid ─────── */
.pg-board-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: start;
  padding-top: clamp(8px, 2.5vh, 28px);
}

/* ── Page header (gateway / board pickers) — open, centred masthead ────── */
.pg-board-head {
  margin: 0 auto;
  text-align: center;
}

/* Board-uncertainty reassurance (P0): a calm aside under the card grid that
   answers "am I on the right board?" — the page's highest-stakes question.
   Token-driven so it themes itself (no light override needed). */
.pg-board-help {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  max-width: 64ch;
  margin: clamp(22px, 3.2vh, 34px) auto 0;
  padding: 13px 17px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-soft);
  color: var(--text-muted);
  font-size: 0.9375rem;
  line-height: 1.55;
  text-align: left;
}

.pg-board-help-icon {
  flex-shrink: 0;
  margin-top: 1px;
  color: var(--accent);
}

.pg-board-title {
  margin: 0 0 18px;
  font-size: clamp(2.4rem, 5vw, 3.4rem);
  font-weight: 900;
  line-height: 1.04;
  letter-spacing: -0.035em;
  color: rgba(248,250,252,0.98);
  text-wrap: balance;
}

.pg-board-lede {
  margin: 0 auto;
  max-width: 54ch;
  font-size: 1.1875rem;
  line-height: 1.6;
  color: rgba(206,216,230,0.80);
}

/* Visible section heading above the picker cards ("Choose your …") */
.pg-board-cards-heading {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-align: left;
  color: var(--text);
}

/* Card column — per-programme atmospheric tint sits behind the stack */
.pg-board-cards {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

.pg-board-cards::before {
  content: "";
  position: absolute;
  inset: -48px -56px;
  pointer-events: none;
  background: radial-gradient(closest-side at 50% 28%, var(--pg-board-tint, rgba(91,140,255,0.07)), transparent);
}

.pg-board-shell--igcse   { --pg-board-tint: rgba(52,211,153,0.05); }
.pg-board-shell--alevel  { --pg-board-tint: rgba(132,182,255,0.05); }
.pg-board-shell--gateway { --pg-board-tint: rgba(91,140,255,0.05); }

.pg-board-cards > * {
  position: relative;
}

/* ── Board card ──────────────────────────────────────────── */
.pg-bcard {
  --bcard-accent: var(--pg-hover-alevel);
  --bcard-soft: color-mix(in srgb, var(--bcard-accent) 13%, transparent);
  --bcard-border: color-mix(in srgb, var(--bcard-accent) 26%, transparent);
  --bcard-ring: color-mix(in srgb, var(--bcard-accent) 42%, transparent);
  --bcard-glow: color-mix(in srgb, var(--bcard-accent) 15%, transparent);
  display: flex;
  flex-direction: column;
  padding: 22px 26px 20px;
  border-radius: 20px;
  border: 1px solid color-mix(in srgb, var(--bcard-accent) 30%, rgba(148,163,184,0.16));
  background:
    radial-gradient(460px 220px at 14% 0%, color-mix(in srgb, var(--bcard-accent) 8%, transparent), transparent 70%),
    radial-gradient(480px 250px at 100% 0%, color-mix(in srgb, var(--bcard-accent) 4%, transparent), transparent 72%),
    linear-gradient(180deg, rgba(18,25,46,0.97) 0%, rgba(11,16,31,0.99) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.055),
    0 18px 50px rgba(0,0,0,0.30);
  text-decoration: none;
  transition:
    border-color var(--hover-dur) var(--hover-ease),
    background var(--hover-dur) var(--hover-ease),
    box-shadow var(--hover-dur) var(--hover-ease),
    transform var(--hover-dur) var(--hover-ease);
}

/* Per-board accent — one token each; soft/border/ring/glow derive via
   color-mix in the shared rule above, so both themes stay correct and
   adding a board is a single line. */
.pg-bcard--igcse   { --bcard-accent: var(--pg-hover-igcse); }
.pg-bcard--edexcel { --bcard-accent: var(--pg-hover-edexcel); }
.pg-bcard--cie     { --bcard-accent: var(--pg-hover-cie); }
.pg-bcard--alevel { --bcard-accent: var(--pg-hover-alevel); }
.pg-bcard--ap     { --bcard-accent: var(--pg-hover-ap); }
.pg-bcard--sat    { --bcard-accent: var(--pg-hover-sat); }

.pg-bcard:hover {
  border-color: color-mix(in srgb, var(--bcard-accent) 60%, transparent);
  background:
    radial-gradient(460px 220px at 14% 0%, color-mix(in srgb, var(--bcard-accent) 12%, transparent), transparent 70%),
    radial-gradient(480px 250px at 100% 0%, color-mix(in srgb, var(--bcard-accent) 6%, transparent), transparent 72%),
    linear-gradient(180deg, rgba(22,30,54,0.98) 0%, rgba(12,18,34,0.99) 100%);
  box-shadow: var(--card-hover-shadow);
  transform: translateY(-2px);
}

.pg-bcard:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

.pg-bcard-top {
  display: flex;
  align-items: center;
  gap: 16px;
}

.pg-bcard-tile {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 14px;
  background:
    radial-gradient(circle at 38% 26%, rgba(255,255,255,0.12), transparent 38%),
    radial-gradient(120% 120% at 30% 24%,
      color-mix(in srgb, var(--bcard-accent) 80%, #ffffff) 0%,
      var(--bcard-accent) 48%,
      color-mix(in srgb, var(--bcard-accent) 68%, #0b0d1e) 100%);
  border: 1px solid color-mix(in srgb, var(--bcard-accent) 58%, transparent);
  color: #ffffff;
  box-shadow:
    0 8px 18px var(--bcard-glow),
    inset 0 1px 0 rgba(255,255,255,0.20),
    inset 0 -3px 8px rgba(0,0,0,0.20);
  transition:
    box-shadow var(--hover-dur) var(--hover-ease),
    transform var(--hover-dur) var(--hover-ease);
}

.pg-bcard-tile svg {
  width: 24px;
  height: 24px;
}

.pg-bcard:hover .pg-bcard-tile {
  box-shadow:
    0 8px 16px var(--bcard-glow),
    inset 0 1px 0 rgba(255,255,255,0.22),
    inset 0 -2px 6px rgba(0,0,0,0.20);
  transform: translateY(var(--lift-sm));
}

.pg-bcard-main {
  min-width: 0;
}

.pg-bcard-name {
  display: block;
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.15;
  color: rgba(255,255,255,0.96);
}

.pg-bcard-qual {
  display: block;
  margin-top: 3px;
  font-size: 0.9375rem;
  line-height: 1.35;
  color: rgba(212,221,237,0.82);
}

.pg-bcard-subjects {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 0 0;
}

/* Narrow screens: centre the wrapped chip rows so a short trailing row balances
   under a full one instead of hanging left (the picker-critique wrap nit). Only
   below the width where all chips fit one line, so the desktop left-alignment
   with the card name/count is preserved. */
@media (max-width: 500px) {
  .pg-bcard-subjects {
    justify-content: center;
  }
}

/* Subject tags — static, scannable subject-preview labels (NOT interactive;
   the whole card is the single link). Quiet neutral border, no per-chip hover
   or transition, so they read as metadata rather than tappable pills. */
.pg-bcard-chip {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 11px;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.01em;
  color: rgba(237,245,255,0.92);
  background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.018));
  border: 1px solid var(--border-2);
  border-radius: 9px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}

.pg-bcard-rule {
  height: 1px;
  margin: 16px 0 0;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255,255,255,0.09) 20%,
    rgba(255,255,255,0.09) 80%,
    transparent 100%
  );
}

.pg-bcard-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 14px;
}

.pg-bcard-count {
  min-width: 0;
  font-size: 0.9375rem;
  font-weight: 750;
  color: var(--bcard-accent);
}

.pg-bcard-go {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  gap: 9px;
  font-size: 0.9375rem;
  font-weight: 550;
  color: rgba(225,232,245,0.92);
  overflow-wrap: anywhere;
  transition: color 0.22s ease;
}

.pg-bcard-arrow {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  color: var(--bcard-accent);
  transition: color 0.22s ease, transform 0.22s var(--ease-expo);
}

.pg-bcard:hover .pg-bcard-go,
.pg-bcard:hover .pg-bcard-arrow {
  color: var(--bcard-accent);
}

.pg-bcard:hover .pg-bcard-arrow {
  transform: translateX(4px);
}

/* Two-pane composition with a structural hairline from 920px up */
@media (min-width: 920px) {
  /* Stacked composition: head on top, cards as a full-width 2×2 grid below.
     (Reverts the board-page-revamp two-pane, which laid the cards in a single
     tall column that scrolled. The 2×2 grid lives on .pg-board-cards.) */
  .pg-board-layout {
    gap: clamp(14px, 2vh, 22px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pg-bcard,
  .pg-bcard-go,
  .pg-bcard-arrow,
  .pg-bcard-tile {
    transition: none;
  }

  .pg-bcard:hover,
  .pg-bcard:hover .pg-bcard-arrow,
  .pg-bcard:hover .pg-bcard-tile {
    transform: none;
  }
}

/* ── Board rows: the A Level and IGCSE board pickers ─────────
   Owner mockup 2026-09-30: one left-aligned column, a headline and one
   paragraph, a letter-spaced label over a hairline, then one row per
   board -- icon tile, name, qualification, the subjects it offers, and a
   "View N subjects" link behind a divider. One ink for every word (no grey
   text); blue for the links; the board hue only on the icon tile. Hover
   and keyboard focus lift the row and draw the blue edge on its left.
   Tokens carry legacy fallbacks so the un-flagged build still reads; the
   board hue on the tile comes from notebook-pickers-skin.css, the one sheet
   allowed to carry the notebook board tokens (tests_notebook confines them).

   SIZES FOLLOW THE MONITOR (owner, same day: "bigger, more comfortable,
   decide how big based on pc monitor res"). Each --bp-* is a straight line
   from its value on a 1280px-wide screen to its value on a 1920px one
   (a + b*vw), clamped at both ends: 1280 and below get the 1280 size, a
   1536 laptop at 125% sits between, 1920 gets the full size and 2560 grows
   a little further before the caps. Phones set their own values below.
   .sr-page shares the scale: every subject hub draws its resources as
   these same rows (hub-rows.css, owner 2026-09-30). */
.pg-board-shell--rows,
.sr-page {
  --bp-col: clamp(45rem, 400px + 25vw, 64rem);      /* 720 -> 880 */
  --bp-h1: clamp(2.25rem, 20px + 1.25vw, 3.25rem);  /* 36 -> 44 */
  --bp-lede: clamp(18px, 14px + 0.3125vw, 22px);    /* 18 -> 20 */
  --bp-eyebrow: clamp(11.5px, 9.5px + 0.156vw, 13px);
  --bp-name: clamp(19px, 9px + 0.78vw, 26px);       /* 19 -> 24 */
  --bp-qual: clamp(14px, 8px + 0.47vw, 18px);       /* 14 -> 17 */
  --bp-subj: clamp(13px, 8px + 0.39vw, 16px);       /* 13 -> 15.5 */
  --bp-go: clamp(14px, 8px + 0.47vw, 18px);         /* 14 -> 17 */
  --bp-tile: clamp(56px, 32px + 1.875vw, 76px);     /* 56 -> 68 */
  --bp-icon: clamp(24px, 12px + 0.94vw, 32px);      /* 24 -> 30 */
  --bp-arrow: clamp(18px, 10px + 0.625vw, 23px);
  --bp-pad-y: clamp(20px, 1.5625vw, 34px);          /* 20 -> 30 */
  --bp-pad-l: clamp(18px, 1.5625vw - 2px, 32px);
  --bp-pad-r: clamp(12px, 1.25vw - 4px, 24px);
  --bp-gap: clamp(23px, 5px + 1.4vw, 36px);         /* 23 -> 32 */
  --bp-list-gap: clamp(16px, 4px + 0.94vw, 26px);
  --bp-dot: clamp(26px, 14px + 0.94vw, 34px);
  --bp-eyebrow-top: clamp(28px, 4px + 1.875vw, 48px);
}

.pg-board-shell--rows .pg-bpick {
  width: min(100%, var(--bp-col));
  margin: 0 auto;
  padding-top: clamp(16px, 5vh, 48px);
}

.pg-bpick-head {
  text-align: left;
}

/* (0,3,0): beats notebook-pickers.css's --alevel/--igcse title margin and
   the typography bridge's headline size, both of which load later. */
.pg-board-shell--rows .pg-bpick-head .pg-board-title {
  margin: 0 0 clamp(6px, 0.625vw - 2px, 12px);
  font-size: var(--bp-h1);
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.pg-board-shell--rows .pg-bpick-head .pg-board-lede {
  margin: 0;
  max-width: none;
  font-size: var(--bp-lede);
  color: var(--nb-ink, var(--text));
}

.pg-bpick-eyebrow {
  margin: var(--bp-eyebrow-top) 0 var(--bp-list-gap);
  padding-bottom: clamp(8px, 0.625vw, 14px);
  border-bottom: 1px solid var(--nb-border, var(--border));
  font-family: var(--nb-sans, inherit);
  font-size: var(--bp-eyebrow);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--nb-ink, var(--text));
}

.pg-bpick-list {
  display: grid;
  gap: var(--bp-list-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

.pg-brow {
  --brow-accent: var(--pg-hover-edexcel);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--bp-gap);
  padding: var(--bp-pad-y) var(--bp-pad-r) var(--bp-pad-y) var(--bp-pad-l);
  border-top: 1px solid transparent;
  border-bottom: 1px solid var(--nb-border, var(--border));
  color: var(--nb-ink, var(--text));
  text-decoration: none;
  transition-property: background-color, box-shadow, border-color;
  transition-duration: var(--hover-dur, 0.18s);
  transition-timing-function: var(--hover-ease, ease);
}

.pg-brow--cie {
  --brow-accent: var(--pg-hover-cie);
}

.pg-brow:hover,
.pg-brow:focus-visible {
  background-color: color-mix(in srgb, var(--nb-blue, var(--accent)) 5%, var(--nb-paper, var(--bg)));
  border-top-color: color-mix(in srgb, var(--nb-border, var(--border)) 55%, transparent);
  box-shadow: inset 2px 0 0 var(--nb-blue, var(--accent));
}

.pg-brow:focus-visible {
  outline: 2px solid var(--nb-blue, var(--focus-ring));
  outline-offset: 3px;
}

.pg-brow-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--bp-tile);
  height: var(--bp-tile);
  border-radius: var(--nb-r-lg, 12px);
  border: 1px solid color-mix(in srgb, var(--brow-accent) 34%, var(--nb-border, var(--border)));
  background: color-mix(in srgb, var(--brow-accent) 10%, transparent);
  color: var(--brow-accent);
}

.pg-brow-tile svg {
  width: var(--bp-icon);
  height: var(--bp-icon);
}

/* The ink is set here, not inherited from the link: a site-wide a:hover
   colour would otherwise turn every word in a hovered row blue. */
.pg-brow-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  color: var(--nb-ink, var(--text));
}

.pg-brow-name {
  font-family: var(--nb-sans, inherit);
  font-size: var(--bp-name);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.pg-brow-qual {
  margin-top: clamp(2px, 0.31vw - 2px, 5px);
  font-family: var(--nb-sans, inherit);
  font-size: var(--bp-qual);
  font-weight: 400;
  line-height: 1.4;
}

/* Every subject carries its dot in front, and the list is pulled left by
   one dot's width inside a clipping box: the dot before the first word of
   each line falls outside the box, so a wrapped line never starts "· ". */
.pg-brow-subjects {
  display: block;
  overflow: hidden;
  margin-top: clamp(10px, 2px + 0.625vw, 16px);
  font-family: var(--nb-sans, inherit);
  font-size: var(--bp-subj);
  font-weight: 400;
  line-height: 1.4;
}

.pg-brow-subjects-in {
  display: flex;
  flex-wrap: wrap;
  row-gap: 2px;
  margin-left: calc(-1 * var(--bp-dot));
}

.pg-brow-subject::before {
  content: "\00B7";
  display: inline-block;
  width: var(--bp-dot);
  font-weight: 700;
  text-align: center;
}

.pg-brow-go {
  display: inline-flex;
  align-items: center;
  gap: clamp(11px, 3px + 0.625vw, 16px);
  align-self: stretch;
  padding-left: var(--bp-gap);
  border-left: 1px solid var(--nb-border, var(--border));
  font-family: var(--nb-sans, inherit);
  font-size: var(--bp-go);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--nb-blue, var(--accent));
}

.pg-brow-arrow {
  flex-shrink: 0;
  width: var(--bp-arrow);
  height: var(--bp-arrow);
  transition: transform 0.22s var(--ease-expo, ease);
}

.pg-brow:hover .pg-brow-arrow,
.pg-brow:focus-visible .pg-brow-arrow {
  transform: translateX(3px);
}

/* Phones: the link drops under the text, the divider becomes a hairline
   above it, and the tile stays level with the name. Sizes are the phone's
   own, not the 1280 floor above. */
@media (max-width: 560px) {
  .pg-board-shell--rows,
  .sr-page {
    --bp-h1: 2rem;
    --bp-lede: 17px;
    --bp-eyebrow: 11px;
    --bp-name: 17px;
    --bp-qual: 13px;
    --bp-subj: 12px;
    --bp-go: 13px;
    --bp-tile: 46px;
    --bp-icon: 22px;
    --bp-arrow: 18px;
    --bp-list-gap: 16px;
    --bp-dot: 26px;
    --bp-eyebrow-top: 28px;
  }

  .pg-brow {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    column-gap: 16px;
    padding: 18px 12px 16px 14px;
  }

  .pg-brow-go {
    grid-column: 2;
    justify-content: space-between;
    margin-top: 14px;
    padding: 12px 0 0;
    border-left: 0;
    border-top: 1px solid var(--nb-border, var(--border));
  }
}

@media (prefers-reduced-motion: reduce) {
  .pg-brow,
  .pg-brow-arrow {
    transition: none;
  }

  .pg-brow:hover .pg-brow-arrow,
  .pg-brow:focus-visible .pg-brow-arrow {
    transform: none;
  }
}

/* ── Screen-reader heading ───────────────────────────────── */
.pg-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* ── Bottom CTA ──────────────────────────────────────────── */
.pg-cta-section {
  padding: 64px 0 80px;
  position: relative;
  /* Dim structural border */
  border-top: 1px solid rgba(255,255,255,0.05);
}

/* Centered luminous accent over the divider */
.pg-cta-section::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 50%;
  transform: translateX(-50%);
  width: 220px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(91,140,255,0.55) 50%,
    transparent 100%
  );
}

.pg-cta-inner {
  text-align: center;
  max-width: 480px;
  margin: 0 auto;
}

.pg-cta-title {
  font-size: clamp(1.5rem, 3vw, 1.875rem);
  font-weight: 700;
  color: rgba(255,255,255,0.90);
  letter-spacing: -0.03em;
  margin: 0 0 10px;
}

.pg-cta-body {
  font-size: 0.9375rem;
  color: rgba(255,255,255,0.60);
  margin: 0 0 28px;
  line-height: 1.6;
}

/* Right-size the CTA button for this secondary context */
.pg-cta-section .lp-cta-primary {
  padding: 14px 40px;
  min-width: 0;
  font-size: 1rem;
}

/* The phone override for BOTH picker shells now lives after .si-page's own
   rule instead of here -- see styles.css:7968. This copy sat ahead of it and
   carried the same (0,1,0) specificity, so .si-page ignored it on source
   order and kept subtracting 72 at phone widths. */

/* ── Board shell responsive ────────────────────────── */
@media (max-width: 760px) {
  .pg-board-shell {
    padding: 30px 16px 72px;
  }

  .pg-board-layout {
    gap: 30px;
    padding-top: 4px;
  }

  /* Single column on phones */
  .pg-board-cards {
    grid-template-columns: 1fr;
  }

  .pg-board-title {
    font-size: clamp(2.1rem, 8.5vw, 2.7rem);
  }

  .pg-board-cards::before {
    inset: -32px -24px;
  }

  .pg-bcard {
    padding: 22px 20px 18px;
  }

  .pg-bcard-tile {
    width: 46px;
    height: 46px;
    border-radius: 12px;
  }

  .pg-bcard-tile svg {
    width: 23px;
    height: 23px;
  }

  .pg-bcard-name {
    font-size: 1.35rem;
  }
}

/* ── Responsive ──────────────────────────────────────────── */
@media (max-width: 700px) {
  .pg-inner {
    padding: 0 20px;
  }

  .pg-hero {
    padding: 60px 0 44px;
  }

  .pg-hero--sub {
    padding: 52px 0 36px;
  }

  .pg-cta-section {
    padding: 48px 0 60px;
  }
}

/* =========================
   Account Hub — premium full-page layout
   Two-column card: profile bar (full width) + membership | actions columns.
   The existing .acct-* classes (used in the navbar modal) are NOT touched here.
========================= */

/* ── Page chrome ── */
.acct-hub-hero {
  padding: 100px 0 36px;
  text-align: center;
}

/* Centre the subtitle to match the centred card composition */
.acct-hub-hero .pg-hero-body {
  margin: 0 auto;
}

.acct-hub-content {
  padding: 0 0 120px;
}

/* ── Main card — wide premium surface ── */
.acct-hub-card {
  max-width: 860px;
  margin: 0 auto;
  /* AP-1/AD-1: flat token surface (replaces the old off-theme tinted card),
     matching the reference .tlo-card in both themes. */
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  min-width: 0;
}

/* ── Profile header bar (full-width stripe) ── */
.acct-hub-profile {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 30px 40px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-soft);
  min-width: 0;
}

.acct-hub-profile > :last-child {
  flex: 1 1 0;
  min-width: 0;
  max-width: 100%;
}

/* Avatar circle */
.acct-hub-avatar {
  width: 50px;
  height: 50px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent-soft);
  border: 1.5px solid var(--accent-border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
}

/* Username */
.acct-hub-name {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.02em;
  margin: 0 0 3px;
  overflow-wrap: anywhere;
}

/* Email */
.acct-hub-email {
  font-size: 0.875rem;
  color: var(--muted);
  margin: 0;
  overflow-wrap: anywhere;
}

/* ── Two-column body ── */
.acct-hub-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-width: 0;
}

/* Column */
.acct-hub-col {
  padding: 36px 40px;
  min-width: 0;
}

.acct-hub-col + .acct-hub-col {
  border-left: 1px solid var(--border);
}

/* Section label — small uppercase eyebrow above each col */
.acct-hub-section-label {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: #aab4c7; /* AA on dark account card (was --faint 3.22:1) */
  margin: 0 0 18px;
  overflow-wrap: anywhere;
}

/* ── Membership: Premium active ── */
.acct-hub-premium-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px 16px;
  border-radius: 12px;
  background: var(--success-subtle-bg);
  border: 1px solid var(--success-border);
  color: var(--success);
  font-size: 0.9375rem;
  font-weight: 600;
  margin-bottom: 16px;
}

.acct-hub-premium-note {
  font-size: 0.875rem;
  color: var(--muted);
  line-height: 1.65;
  margin: 0;
}

/* ── Membership: Free / upgrade ── */
.acct-hub-free-name {
  font-size: 1rem;
  font-weight: 700;
  color: var(--accent);
  margin: 0 0 8px;
}

.acct-hub-free-desc {
  font-size: 0.875rem;
  color: var(--muted);
  line-height: 1.65;
  margin: 0 0 22px;
}

.acct-hub-upgrade-form {
  margin: 0;
}

.acct-hub-upgrade-btn {
  display: block;
  width: 100%;
  padding: 13px 0;
  background: linear-gradient(135deg, var(--cta-grad-1) 0%, var(--cta-grad-2) 55%, var(--cta-grad-3) 100%);
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 700;
  text-align: center;
  border-radius: 11px;
  border: none;
  cursor: pointer;
  font-family: inherit;
  box-shadow: var(--glow-accent);
  transition: opacity 0.15s ease, box-shadow 0.15s ease;
  overflow-wrap: anywhere;
}

.acct-hub-upgrade-btn:hover {
  opacity: 0.90;
  box-shadow: var(--shadow-hover);
}

/* ── Action links (Edit Profile, Change Password) ── */
.acct-hub-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 0;
}

.acct-hub-action-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px 18px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface-soft);
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.acct-hub-action-link:hover {
  background: var(--surface-elevated);
  border-color: var(--border-2);
  color: var(--text);
}

.acct-hub-action-arrow {
  color: var(--faint);
  flex-shrink: 0;
  transition: color 0.18s ease, transform 0.18s var(--ease-expo);
}

.acct-hub-action-link:hover .acct-hub-action-arrow {
  color: var(--muted);
  transform: translateX(3px);
}

/* ── Account state (2026-08-30) ──────────────────────────────────────
   The hub stopped repeating the navbar dropdown's shortcuts and started
   showing what the dropdown cannot hold: real membership dates, the study
   setup, and subject targets. Layout + dark ink live here; theme-light.css
   carries the light values and notebook-account-skin.css the nb skin. */

/* Key/value rows. A row is only ever rendered when it HAS a value, so there
   is no empty-state styling to write -- an empty row never reaches the DOM. */
.acct-hub-meta {
  margin: 14px 0 0;
  display: grid;
  gap: 8px;
}

.acct-hub-meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  min-width: 0;
}

.acct-hub-meta-k {
  font-size: 0.8125rem;
  color: #aab4c7; /* AA on dark account card, matching the section label */
  min-width: 0;
}

.acct-hub-meta-v {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text);
  text-align: right;
  overflow-wrap: anywhere;
  min-width: 0;
}

/* Subject targets */
.acct-hub-subjects {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.acct-hub-subject {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 11px;
  border: 1px solid var(--border);
  min-width: 0;
}

.acct-hub-subject-name {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text);
  overflow-wrap: anywhere;
  min-width: 0;
}

.acct-hub-subject-grades {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.acct-hub-grade {
  font-size: 0.75rem;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: #aab4c7;
  white-space: nowrap;
}

.acct-hub-grade--target {
  border-color: var(--success-border);
  background: var(--success-subtle-bg);
  color: var(--success);
}

.acct-hub-empty {
  margin: 0 0 18px;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: #aab4c7;
}

/* ── Card footer: completeness, the one non-duplicated errand, sign out ── */
.acct-hub-foot {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--border);
  min-width: 0;
}

.acct-hub-progress,
.acct-hub-foot-actions {
  padding: 30px 40px;
  min-width: 0;
}

.acct-hub-foot-actions {
  border-left: 1px solid var(--border);
}

.acct-hub-progress-track {
  height: 6px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.acct-hub-progress-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--success);
}

.acct-hub-checklist {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: grid;
  gap: 9px;
}

.acct-hub-check {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 0.8125rem;
  color: #aab4c7;
  overflow-wrap: anywhere;
  min-width: 0;
}

.acct-hub-check--done {
  color: var(--success);
}

.acct-hub-check-dot {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  flex: none;
}

/* ── Sign-out area — separated destructive action ── */
.acct-hub-signout {
  margin-top: 24px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
}

.acct-hub-signout-label {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: #aab4c7; /* AA on dark account card */
  margin: 0 0 10px;
}

.acct-hub-logout-form {
  margin: 0;
}

.acct-hub-logout-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 13px 18px;
  border-radius: 11px;
  border: 1px solid var(--danger-border);
  background: var(--danger-subtle-bg);
  color: var(--danger);
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.acct-hub-logout-btn:hover {
  background: var(--danger-subtle-bg);
  border-color: var(--danger-border);
  color: var(--danger);
}

/* ── Guest card (unauthenticated state) ── */
.acct-hub-card--guest {
  max-width: 480px;
  padding: 48px 44px;
  text-align: center;
}

.acct-hub-guest-title {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 8px;
}

.acct-hub-guest-body {
  font-size: 0.9375rem;
  color: var(--muted);
  margin: 0 0 28px;
  line-height: 1.6;
}

.acct-hub-guest-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.acct-hub-guest-primary {
  display: block;
  padding: 14px 0;
  border-radius: 12px;
  background: linear-gradient(135deg, var(--cta-grad-1) 0%, var(--cta-grad-2) 55%, var(--cta-grad-3) 100%);
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  box-shadow: var(--glow-accent);
  transition: opacity 0.15s ease, box-shadow 0.15s ease;
}

.acct-hub-guest-primary:hover {
  opacity: 0.90;
  box-shadow: var(--shadow-hover);
  color: #fff;
}

.acct-hub-guest-secondary {
  display: block;
  padding: 13px 0;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface-soft);
  color: var(--text);
  font-size: 1rem;
  font-weight: 600;
  text-align: center;
  text-decoration: none;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.acct-hub-guest-secondary:hover {
  background: var(--surface-elevated);
  border-color: var(--border-2);
  color: var(--text);
}

.acct-hub-guest-forgot {
  font-size: 0.875rem;
  color: var(--faint);
  text-decoration: none;
  transition: color 0.18s ease;
}

.acct-hub-guest-forgot:hover {
  color: var(--muted);
}

/* ── Responsive ── */
@media (max-width: 800px) {
  .acct-hub-body,
  .acct-hub-foot {
    grid-template-columns: 1fr;
  }

  .acct-hub-col + .acct-hub-col {
    border-left: none;
    border-top: 1px solid var(--border);
  }

  /* The footer's second cell stacks under the first, so its divider has to
     move from the inline edge to the block edge exactly like the columns. */
  .acct-hub-foot-actions {
    border-left: none;
    border-top: 1px solid var(--border);
  }
}

@media (max-width: 700px) {
  .acct-hub-hero {
    padding: 64px 0 28px;
  }

  .acct-hub-content {
    padding: 0 0 72px;
  }

  .acct-hub-profile {
    padding: 22px 24px;
  }

  .acct-hub-col {
    padding: 28px 24px;
  }

  .acct-hub-card--guest {
    padding: 32px 24px;
  }
}

/* =========================
   Logged-out Account Gateway (.acg-* namespace)
   Scoped to the unauthenticated /account/ view. Mirrors the coming-soon
   design language (.cs-panel + .lp-cta-primary system): near-black surface,
   electric-blue CTA, subtle periwinkle accents -- no purple gradients.
   ========================= */

.acg-page {
  background: transparent;                  /* global body gradient shows through */
  min-height: calc(100svh - 72px);          /* topbar height (styles.css:140) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(40px, 5.5vh, 76px) clamp(20px, 3vw, 40px);
  position: relative;
}

.acg-inner {
  width: 100%;
  max-width: 1120px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 460px;
  gap: 36px;
  align-items: center;
}

/* ── Left content ── */
.acg-content {
  min-width: 0;
}

/* Status pill -- same anatomy as .cs-status / .lp-eyebrow */
.acg-pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 24px;
  padding: 10px 20px;
  border-radius: 999px;
  background: var(--surface-soft);
  border: 1px solid var(--border-control);
  /* flat at rest — a status eyebrow, not a tappable pill (matches .lp-eyebrow) */
  color: var(--text);
  font-size: 0.96875rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  line-height: 1;
}

.acg-pill-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow:
    0 0 6px var(--accent-soft),
    0 0 0 3px var(--accent-soft);
  flex-shrink: 0;
}

/* Heading -- mirrors .cs-heading / .lp-headline. Sized so the wrap
   ("Keep your revision" / "organised.") sits as a deliberate two-line
   statement at desktop widths. */
.acg-heading {
  margin: 0 0 14px;
  font-size: clamp(2.25rem, 3.6vw, 3rem);
  font-weight: 800;
  letter-spacing: -0.034em;
  line-height: 1.05;
  color: var(--text);
  max-width: 20ch;
}

.acg-body {
  margin: 0 0 28px;
  font-size: 1.0875rem;
  line-height: 1.65;
  color: var(--muted);
  max-width: 54ch;
}

/* Benefit rows -- subtle dark surface + periwinkle status dot.
   Capped width so they read as a tight stack rather than long flat bars. */
.acg-benefits {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.acg-benefit {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 19px 24px;
  border-radius: 14px;
  background: var(--surface-soft);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

/* Periwinkle hairline rail on the left edge -- echoes the homepage
   .cs-proof-item / .lp-stats-item rail. Visible enough to read as a
   premium structural accent paired with the periwinkle dot marker. */
.acg-benefit::before {
  content: '';
  position: absolute;
  left: 0;
  top: 14px;
  bottom: 14px;
  width: 2px;
  border-radius: 999px;
  background: var(--accent);
  opacity: 0.55;
}

.acg-benefit-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin-top: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow:
    0 0 0 3px var(--accent-soft),
    0 0 8px var(--accent-soft);
}

.acg-benefit-text {
  min-width: 0;
}

.acg-benefit-text strong {
  display: block;
  font-size: 1rem;
  font-weight: 620;
  color: var(--text);
  line-height: 1.3;
  letter-spacing: -0.004em;
}

.acg-benefit-text span {
  display: block;
  margin-top: 4px;
  font-size: 0.9125rem;
  line-height: 1.55;
  color: var(--muted);
}

/* ── Right auth card -- same surface as .cs-panel ── */
.acg-card {
  position: relative;
  padding: clamp(36px, 3.4vw, 44px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

/* Top accent rail -- periwinkle. Reads as the clear "top of card"
   anchor so the auth card feels like the action centre of the page. */
.acg-card::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 2px;
  border-radius: 999px;
  background: var(--accent);
  opacity: 0.55;
}

.acg-card-eyebrow {
  margin: 0 0 12px;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-link);
  line-height: 1.1;
}

.acg-card-title {
  margin: 0 0 14px;
  font-size: 1.625rem;
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.22;
  color: var(--text);
}

.acg-card-body {
  margin: 0 0 28px;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--muted);
}

.acg-card-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 26px;
}

/* Primary CTA -- mirrors .lp-cta-primary (styles.css:2776) exactly,
   adjusted only in width so the card stacks well */
a.acg-btn-primary,
a.acg-btn-primary:link,
a.acg-btn-primary:visited {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  background: linear-gradient(165deg, var(--cta-grad-1) 0%, var(--cta-grad-2) 46%, var(--cta-grad-3) 100%);
  border: 1px solid var(--accent-border);
  color: #fff; /* allowlisted: white-on-accent CTA text, same as site .lp-cta-primary */
  padding: 18px 30px;
  text-align: center;
  border-radius: 12px;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1;
  text-decoration: none;
  box-shadow: var(--glow-accent);
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

a.acg-btn-primary:hover,
a.acg-btn-primary:focus-visible {
  color: #fff;
  text-decoration: none;
  transform: translateY(var(--lift-sm));
  border-color: var(--accent-border);
  box-shadow: var(--shadow-hover);
}

a.acg-btn-primary:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

/* Secondary -- refined dark outlined button, no purple. Strong enough that
   "Create free account" supports conversion without competing with the
   primary Log In CTA. */
a.acg-btn-secondary,
a.acg-btn-secondary:link,
a.acg-btn-secondary:visited {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 54px;
  padding: 17px 30px;
  border-radius: 12px;
  background: var(--surface-soft);
  border: 1px solid var(--border-2);
  color: var(--text);
  font-size: 1.03125rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  line-height: 1;
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

a.acg-btn-secondary:hover,
a.acg-btn-secondary:focus-visible {
  background: var(--surface-elevated);
  border-color: var(--border-2);
  color: var(--text);
  text-decoration: none;
  transform: translateY(var(--lift-sm));
}

a.acg-btn-secondary:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

/* Forgot link -- subtle, low-emphasis */
.acg-forgot {
  display: inline-block;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.18s ease;
}

.acg-forgot:hover,
.acg-forgot:focus-visible {
  color: var(--text);
  text-decoration: none;
}

/* ── Responsive ── */

/* Tablet -- stack into single column */
@media (max-width: 1080px) {
  .acg-page {
    justify-content: flex-start;
    padding: clamp(32px, 4vh, 56px) clamp(20px, 3vw, 32px) clamp(36px, 4.5vh, 60px);
  }
  .acg-inner {
    grid-template-columns: 1fr;
    max-width: 600px;
    gap: 30px;
  }
  .acg-heading {
    max-width: none;
  }
  .acg-benefits {
    max-width: none;
  }
}

/* Mobile */
@media (max-width: 640px) {
  .acg-page {
    padding: 28px 16px 44px;
  }
  .acg-inner {
    gap: 26px;
  }
  .acg-pill {
    padding: 9px 16px;
    font-size: 0.9rem;
    margin-bottom: 18px;
  }
  .acg-heading {
    font-size: clamp(1.85rem, 6.2vw, 2.25rem);
    max-width: none;
    margin-bottom: 14px;
  }
  .acg-body {
    font-size: 0.9875rem;
    margin-bottom: 24px;
    max-width: none;
  }
  .acg-benefits {
    gap: 10px;
  }
  .acg-benefit {
    padding: 14px 16px;
    border-radius: 12px;
    gap: 13px;
  }
  .acg-benefit-text strong {
    font-size: 0.9625rem;
  }
  .acg-benefit-text span {
    font-size: 0.85rem;
  }
  .acg-card {
    padding: 26px 22px;
    border-radius: 18px;
  }
  .acg-card-title {
    font-size: 1.375rem;
  }
  .acg-card-body {
    font-size: 0.9625rem;
    margin-bottom: 22px;
  }
  a.acg-btn-primary,
  a.acg-btn-primary:link,
  a.acg-btn-primary:visited,
  a.acg-btn-secondary,
  a.acg-btn-secondary:link,
  a.acg-btn-secondary:visited {
    min-height: 52px;
    padding: 16px 24px;
  }
}

/* ── Billing & Subscription manage page ───────────────────────────────── */

/* Notices container (Django messages) — sits between profile bar and body */
.bm-notices {
  padding: 20px 40px 0;
}

/* Individual message notice — error style (the only tag currently emitted) */
.bm-notice {
  padding: 12px 16px;
  border-radius: 10px;
  font-size: 0.875rem;
  line-height: 1.55;
  margin-bottom: 10px;
  background: var(--danger-subtle-bg);
  border: 1px solid var(--danger-border);
  color: var(--danger);
}

.bm-notice:last-child {
  margin-bottom: 0;
}

/* Status badge pill — warning (past_due) and ended (cancelled) variants */
.bm-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 15px;
  border-radius: 12px;
  font-size: 0.9375rem;
  font-weight: 600;
  margin-bottom: 16px;
}

.bm-status-badge--warning {
  background: var(--warning-subtle-bg);
  border: 1px solid var(--warning-border);
  color: var(--warning);
}

.bm-status-badge--ended {
  background: var(--surface-soft);
  border: 1px solid var(--border);
  color: var(--faint);
}

/* Form wrapper for portal session submit buttons */
.bm-manage-form {
  margin: 0;
}

/* Secondary outlined button — "View Billing History" in cancelled state */
.bm-secondary-btn {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 12px 0;
  background: var(--surface-soft);
  border: 1px solid var(--border);
  border-radius: 11px;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.bm-secondary-btn:hover {
  background: var(--surface-elevated);
  border-color: var(--border-2);
  color: var(--text);
}

/* Footer bar — back-to-account link at the bottom of the card */
.bm-footer {
  padding: 22px 40px;
  border-top: 1px solid var(--border);
}

.bm-footer-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.875rem;
  color: var(--faint);
  text-decoration: none;
  transition: color 0.18s ease;
}

.bm-footer-link:hover {
  color: var(--muted);
}

@media (max-width: 700px) {
  .bm-notices {
    padding: 16px 24px 0;
  }

  .bm-footer {
    padding: 18px 24px;
  }
}

/* =========================
   Profile edit (.pe-* namespace)
   Reuses the .acct-hub-card shell + .auth-field form primitives. Only the
   form-specific tweaks live here: select chevron, control sizing, the action
   footer, and a success notice variant. Token-based -> themes automatically.
========================= */

/* Success variant of the in-card notice (default .bm-notice is danger-tinted) */
.bm-notice--success {
  background: var(--success-subtle-bg);
  border-color: var(--success-border);
  color: var(--success);
}

/* Even bottom padding inside each column regardless of field count */
.pe-form .acct-hub-col .auth-field:last-child {
  margin-bottom: 0;
}

/* Bring selects in line with the date input (radius/padding/size) and leave
   room on the right for the custom chevron. */
.pe-form .auth-field input,
.pe-form .auth-field select {
  font-size: 16px; /* 16px avoids iOS zoom-on-focus */
}

.pe-form .auth-field select {
  padding: 13px 42px 13px 16px;
  border-radius: 11px;
}

/* Dark calendar-picker glyph is invisible on the dark control — lighten it.
   Reset to native in light mode (see theme-light.css). */
.pe-form .auth-field input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(0.7);
  opacity: 0.75;
  cursor: pointer;
}

/* Custom dropdown chevron (the selects use appearance:none) */
.pe-select {
  position: relative;
}

.pe-select::after {
  content: "";
  position: absolute;
  right: 17px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: translateY(-65%) rotate(45deg);
  pointer-events: none;
}

/* Action footer: back link (left) + save (right) */
.pe-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 24px 40px;
  border-top: 1px solid var(--border);
}

.pe-actions .pe-save {
  width: auto;
  min-width: 200px;
  margin-top: 0;
}

@media (max-width: 700px) {
  .pe-actions {
    flex-direction: column-reverse;
    align-items: stretch;
    gap: 14px;
    padding: 20px 24px;
  }

  .pe-actions .pe-save {
    width: 100%;
    min-width: 0;
  }

  .pe-actions .pe-back {
    justify-content: center;
  }
}

/* =========================
   Billing confirmation pages (.bc-* namespace)
   Stripe checkout success / cancel landings. Token-only -> themes for free.
========================= */

.bc-page {
  min-height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(48px, 9vh, 96px) 20px;
}

.bc-card {
  width: 100%;
  max-width: 460px;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: var(--shadow-lg);
  padding: clamp(36px, 5vw, 52px) clamp(28px, 4vw, 44px);
}

.bc-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 24px;
}

.bc-icon--success {
  background: var(--success-subtle-bg);
  border: 1.5px solid var(--success-border);
  color: var(--success);
}

.bc-icon--cancel {
  background: var(--surface-soft);
  border: 1.5px solid var(--border-2);
  color: var(--faint);
}

.bc-title {
  font-size: clamp(1.5rem, 3.5vw, 1.9rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.15;
  color: var(--text);
  margin: 0 0 12px;
  text-wrap: balance;
}

.bc-body {
  font-size: 1rem;
  color: var(--muted);
  line-height: 1.65;
  margin: 0 auto 20px;
  max-width: 42ch;
}

.bc-note {
  font-size: 0.875rem;
  color: var(--faint);
  line-height: 1.6;
  margin: 0 0 28px;
}

.bc-note-link {
  color: var(--text-link);
  text-decoration: none;
  font-weight: 600;
}

.bc-note-link:hover {
  color: var(--text-link-hover);
  text-decoration: underline;
}

.bc-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

.bc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 28px;
  border-radius: 11px;
  font-size: 0.9375rem;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: opacity 0.15s ease, background 0.18s ease,
    border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}

.bc-btn--primary {
  background: linear-gradient(135deg, var(--cta-grad-1) 0%, var(--cta-grad-2) 55%, var(--cta-grad-3) 100%);
  color: #fff;
  border: 1px solid var(--accent-border);
  box-shadow: var(--glow-accent);
}

.bc-btn--primary:hover {
  opacity: 0.92;
  box-shadow: var(--shadow-hover);
  transform: translateY(var(--lift-sm));
}

.bc-btn--secondary {
  background: var(--surface-soft);
  color: var(--text);
  border: 1px solid var(--border-2);
}

.bc-btn--secondary:hover {
  background: var(--surface-elevated);
  border-color: var(--border-2);
}

.bc-btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

@media (max-width: 480px) {
  .bc-actions {
    flex-direction: column;
  }

  .bc-btn {
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bc-btn,
  .bc-btn--primary:hover {
    transform: none;
    transition: none;
  }
}

/* ── CSP-hardening utility classes ─────────────────────────────────────── */

/* Generic: hide an element */
.btn-hidden {
  display: none;
}

/* Generic: inline form (wraps a submit button alongside other elements) */
.form-inline {
  display: inline;
}

/* auth-btn link variant: ensure anchors styled as auth-btn look correct */
.auth-btn {
  text-align: center;
  text-decoration: none;
}

/* ── Status/confirmation pages (email verify, oauth, etc.) ─────────────── */
.status-page {
  min-height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.status-card {
  max-width: 480px;
  width: 100%;
  text-align: center;
  padding: 48px 24px;
}

.status-icon {
  font-size: 48px;
  margin-bottom: 24px;
}

.status-title {
  font-size: 24px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 16px;
}

.status-body {
  font-size: 15px;
  color: var(--muted);
  line-height: 1.6;
  margin-bottom: 32px;
}

.status-body--sm {
  font-size: 13px;
  color: var(--muted);
}

.status-body--sm a {
  color: var(--text-link);
}

.status-btn {
  display: inline-block;
  background-color: #ffffff;
  color: #0f0f0f;
  font-size: 15px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  padding: 14px 32px;
  border-radius: 8px;
  text-decoration: none;
  font-family: inherit;
}

/* ── Welcome overlay ────────────────────────────────────────────────────── */
.welcome-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.3s ease;
}

/* Animated dismiss: welcome.js adds .is-closing, then display:none after the fade */
.welcome-overlay.is-closing {
  opacity: 0;
  pointer-events: none;
}

/* Reduced motion: welcome appears and dismisses instantly. */
@media (prefers-reduced-motion: reduce) {
  .welcome-overlay { transition: none; }
}

.welcome-card {
  background: #1a1a1a;
  border-radius: 16px;
  padding: 56px 48px;
  max-width: 480px;
  width: 90%;
  text-align: center;
}

.welcome-icon {
  font-size: 48px;
  margin-bottom: 24px;
}

.welcome-title {
  font-size: 28px;
  font-weight: 700;
  color: #ffffff;
  margin-bottom: 16px;
  letter-spacing: -0.5px;
}

.welcome-body {
  font-size: 16px;
  color: #a0a0a0;
  line-height: 1.6;
  margin-bottom: 36px;
}

.welcome-btn {
  background: #ffffff;
  color: #0f0f0f;
  font-size: 15px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  padding: 16px 40px;
  border-radius: 8px;
  width: 100%;
  font-family: inherit;
}

.welcome-btn:hover {
  background: #f8f9fa;
  color: #0f0f0f;
}

/* =======================================================
   Subject Index Leaf Pages  (si-*)
   ap / sat / igcse/cie / igcse/edexcel / alevel/cie / alevel/edexcel
   ======================================================= */

.si-page {
  /* 72px is the topbar (chrome-navbar.css:20). This subtracted 84 and so
     stopped 12px above the fold, leaving a 12px strip of footer showing on
     /ap/, /sat/ and the four board subject grids at every viewport height.
     e5165c83 subtracted a further 96px so the footer peeked; that peek was
     reverted 2026-09-03 on the owner's call. */
  min-height: calc(100svh - 72px);
  padding-bottom: 56px;
}

/* The topbar is 64px on phones, not 72 (chrome-navbar.css:1290), so the
   desktop subtraction undershoots by 8px there and leaks a sliver of footer
   at tall phone viewports. This block must stay AFTER .si-page's own rule:
   the copy that used to live at styles.css:6469 carried the same (0,1,0)
   specificity and lost to it on source order, so .si-page kept subtracting
   72 at 390 and 320 -- measured as an 8px strip of footer on /sat/ at 390.
   The reorder is the one part of e5165c83 that survives its revert.
   Breakpoint matches the topbar's own, not the 760px board-shell one. */
@media (max-width: 767px) {
  .pg-board-shell,
  .si-page {
    min-height: calc(100svh - 64px);
  }
}

/* ── Subject grid section ─────────────────────────────────── */
.si-grid-section {
  padding: 0 0 48px;
}

.si-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(10px, 1.2vw, 14px);
}

/* ── Subject-card accent palette (bounded, brand-anchored) ──────────────
   amber = homepage "Check what sticks"; green = subject green; teal = --accent-2;
   blue = --accent. Brighter on dark; theme-light.css swaps these 6 channel
   tokens for deeper, AA-safe light variants. Each card sets ONE channel
   (--subject-rgb) and accent/soft/border derive below — config-only. */
:root {
  --subj-amber: 192, 154, 128;
  --subj-green: 52, 211, 153;
  --subj-teal:  34, 211, 238;
  --subj-blue:  132, 182, 255;
  --subj-coral: 245, 138, 106;
  --subj-rose:  238, 123, 168;
}

/* ── Subject card ─────────────────────────────────────────── */
.si-card {
  --subject-rgb: 106, 160, 255; /* default blue; per-subject blocks override */
  --subject-accent: rgb(var(--subject-rgb));
  --subject-soft: rgba(var(--subject-rgb), 0.16);
  --subject-border: rgba(var(--subject-rgb), 0.30);
  --subject-soft-hover: rgba(var(--subject-rgb), 0.20);
  --subject-border-hover: rgba(var(--subject-rgb), 0.46);
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 22px 26px;
  border-radius: 18px;
  border: 1px solid rgba(148,163,184,0.15);
  background: linear-gradient(180deg,
    rgba(18,25,46,0.96) 0%,
    rgba(10,15,30,0.98) 100%
  );
  box-shadow:
    0 18px 48px rgba(0,0,0,0.24),
    inset 0 1px 0 rgba(255,255,255,0.045);
  text-decoration: none;
  color: var(--text);
  transition:
    border-color var(--hover-dur) var(--hover-ease),
    background var(--hover-dur) var(--hover-ease),
    box-shadow var(--hover-dur) var(--hover-ease),
    transform var(--hover-dur) var(--hover-ease);
  position: relative;
  overflow: hidden;
}

.si-card[data-ui-disabled="true"] {
  cursor: default;
  pointer-events: none;
}

/* Subtle neutral top hairline */
.si-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.14) 50%, transparent 100%);
  border-radius: 18px 18px 0 0;
  opacity: 0.48;
  transition: background 0.22s ease, opacity 0.22s ease;
}

.si-card:hover::before {
  background: linear-gradient(90deg, transparent 0%, var(--subject-border) 50%, transparent 100%);
  opacity: 0.85;
}

.si-card:hover {
  border-color: var(--subject-border);
  background: linear-gradient(180deg,
    rgba(21,29,52,0.98) 0%,
    rgba(11,17,34,0.99) 100%
  );
  box-shadow: var(--card-hover-shadow);
}

.si-card:focus-visible {
  outline: 2px solid var(--subject-accent);
  outline-offset: 3px;
}

/* ── Icon container ───────────────────────────────────────── */
.si-card-icon-wrap {
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: radial-gradient(120% 120% at 30% 24%,
    var(--subject-soft-hover) 0%,
    var(--subject-soft) 55%,
    rgba(15,23,42,0.42) 100%);
  border: 1px solid var(--subject-border);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.06),
    0 8px 20px color-mix(in srgb, var(--subject-accent) 18%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    background 0.22s ease,
    border-color 0.22s ease,
    box-shadow 0.22s ease,
    transform 0.22s var(--ease-expo);
}

.si-card-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--subject-accent);
  transition: color 0.22s ease, filter 0.22s ease;
}

.si-card-icon svg {
  width: 26px;
  height: 26px;
  stroke-width: 1.75;
}

/* Per-subject identity tokens. Colour stays concentrated in the icon and hover border. */
/* Per-subject accent — one channel token each (accent/soft/border derive above).
   CONSTRAINT: subjects that can appear on the SAME page must NOT share a hue
   (current pages verified distinct). Adding a subject = one line here. */
.si-card[data-subject="biology"] { --subject-rgb: var(--subj-green); }

.si-card[data-subject="chemistry"] { --subject-rgb: var(--subj-teal); }

.si-card[data-subject="physics"] { --subject-rgb: var(--subj-blue); }

.si-card[data-subject="calculus"],
.si-card[data-subject^="calculus-"],
.si-card[data-subject="math"],
.si-card[data-subject="maths"],
.si-card[data-subject="mathematics"],
.si-card[data-subject^="mathematics-"],
.si-card[data-subject="further-mathematics"],
.si-card[data-subject="pure-mathematics"] { --subject-rgb: var(--subj-rose); }

/* The Subjects28 maths slugs on the legacy skin in the light theme. theme-light.css
   is never edited; it carries these two rules only for the old slugs. */
html.theme-light .si-card:is([data-subject="mathematics"], [data-subject^="mathematics-"], [data-subject="further-mathematics"], [data-subject="pure-mathematics"], [data-subject^="calculus-"]) .si-card-icon { color: var(--subject-accent); }
html.theme-light .si-card:is([data-subject="mathematics"], [data-subject^="mathematics-"], [data-subject="further-mathematics"], [data-subject="pure-mathematics"], [data-subject^="calculus-"]) .si-card-icon-wrap { background: var(--subject-soft); border-color: var(--subject-border); }

.si-card[data-subject="english"] { --subject-rgb: var(--subj-coral); }
.si-card[data-subject="reading"] { --subject-rgb: var(--subj-blue); }

.si-card[data-subject="business"] { --subject-rgb: var(--subj-amber); }

.si-card[data-subject="economics"] { --subject-rgb: var(--subj-amber); }

.si-card[data-subject="computer-science"],
.si-card[data-subject="computer_science"],
.si-card[data-subject="computerscience"] { --subject-rgb: var(--subj-teal); }

.si-card[data-subject="psychology"] { --subject-rgb: var(--subj-coral); }

.si-card[data-subject="writing"] { --subject-rgb: var(--subj-coral); }

.si-card:hover .si-card-icon-wrap {
  background: linear-gradient(180deg, var(--subject-soft-hover), rgba(15,23,42,0.42));
  border-color: var(--subject-border-hover);
  transform: translateY(var(--lift-sm));
}

.si-card:hover .si-card-icon {
  filter: brightness(1.12) saturate(1.08);
}

/* ── Card body text ───────────────────────────────────────── */
.si-card-body {
  flex: 1;
  min-width: 0;
}

.si-card-name {
  display: block;
  font-size: 1.25rem;
  font-weight: 700;
  color: rgba(255,255,255,0.92);
  letter-spacing: -0.022em;
  line-height: 1.25;
  transition: color 0.22s ease;
}

.si-card:hover .si-card-name {
  color: #ffffff;
}

.si-card-meta {
  display: block;
  font-size: 0.875rem;
  color: rgba(255,255,255,0.40);
  margin-top: 3px;
  letter-spacing: 0.005em;
  transition: color 0.22s ease;
}

.si-card:hover .si-card-meta {
  color: rgba(255,255,255,0.58);
}

/* ── Trailing chevron ── */
.si-card-arrow {
  flex-shrink: 0;
  color: rgba(255,255,255,0.26);
  opacity: 1;
  transition: color 0.22s ease, opacity 0.22s ease, transform 0.22s var(--ease-expo);
}

.si-card:hover .si-card-arrow {
  color: var(--subject-accent);
  opacity: 0.85;
  transform: translateX(3px);
}

/* Right-aligned affordance arrow (matches the board-card arrow shape). Quiet
   neutral tint that brightens + nudges right on hover. */

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 860px) {
  .si-grid {
    grid-template-columns: 1fr;
  }

}

@media (max-width: 560px) {
  .si-card {
    padding: 16px 18px;
    gap: 14px;
  }

  .si-card-icon-wrap {
    width: 50px;
    height: 50px;
    border-radius: 50%;
  }

  .si-card-name {
    font-size: 1.125rem;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Dedicated auth pages — two-column premium shell (scale + polish pass)
   ──────────────────────────────────────────────────────────────────────
   Scoped strictly under .auth-page--login / .auth-page--signup so the auth
   modal (.auth-modal-panel … in base.html) and password-reset pages
   (.auth-page + .auth-card only) keep their existing visuals untouched.

   Composition:
     [ context panel — eyebrow / headline / sub / feature list ]
     [ form card — title / subtitle / Google / OR / form / links ]

   Sizing targets (≥ 1100 px):
     shell  max-width clamp(1060, 74vw, 1220)
     gap    clamp(56, 6vw, 88)
     login  card max 540 px
     signup card max 580 px
     card padding clamp(40, 4vw, 56)
     card title clamp(2rem, 1.7rem + 0.9vw, 2.35rem)
     headline clamp(2.4rem, 1.2rem + 3.4vw, 3.35rem)
     inputs min-height 54, buttons min-height 56
   ═══════════════════════════════════════════════════════════════════════════ */

.auth-page--login,
.auth-page--signup {
  align-items: center;
  min-height: calc(100dvh - 96px);
  padding: clamp(20px, 3vw, 40px) 32px clamp(56px, 5.5vw, 88px);
  position: relative;
  overflow: hidden;
}

/* Subtle indigo atmosphere — never reaches the modal */
.auth-page--login::before,
.auth-page--signup::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(1080px 540px at 50% -8%, rgba(91, 140, 255, 0.10), transparent 64%),
    radial-gradient(780px 460px at 88% 84%, rgba(59, 130, 246, 0.060), transparent 62%),
    radial-gradient(640px 360px at 8% 92%, rgba(91, 140, 255, 0.045), transparent 64%);
}

/* ── Two-column shell ─────────────────────────────────────────────── */
.auth-shell {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: clamp(1060px, 74vw, 1220px);
  display: grid;
  grid-template-columns: minmax(360px, 0.9fr) minmax(0, 540px);
  align-items: center;
  gap: clamp(56px, 6vw, 88px);
}

.auth-page--signup .auth-shell {
  grid-template-columns: minmax(360px, 0.86fr) minmax(0, 600px);
}

/* ── Left context / value panel — editorial premium block ─────────── */
.auth-context-panel {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 0;
  max-width: 560px;
  position: relative;
}

/* Subtle editorial accent — a short indigo bar above the eyebrow that
   anchors the panel without competing with the form card. */
.auth-context-eyebrow {
  margin: 0;
  position: relative;
  padding-top: 18px;
  font-size: 0.8125rem;       /* 13px */
  font-weight: 800;
  letter-spacing: 0.26em;
  color: rgba(190, 204, 255, 0.92);
  text-transform: uppercase;
}

.auth-context-eyebrow::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 44px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(
    90deg,
    rgba(140, 158, 255, 0.95) 0%,
    rgba(118, 138, 240, 0.55) 60%,
    rgba(118, 138, 240, 0) 100%
  );
}

.auth-context-title {
  margin: 0;
  /* Slightly larger presence for the editorial headline */
  font-size: clamp(2.55rem, 1.25rem + 3.55vw, 3.5rem);   /* ~41–56 px */
  font-weight: 800;
  letter-spacing: -0.028em;
  /* Loosened from 1.05 so gradient-text descenders (y, g, p) render in full
     without being clipped by the line-box. */
  line-height: 1.14;
  /* Belt-and-braces: a sliver of bottom space absorbs any residual paint
     clipping that some browsers apply to background-clip:text descenders. */
  padding-bottom: 0.08em;
  color: #ffffff;
  background: linear-gradient(
    135deg,
    #ffffff 0%,
    rgba(225, 232, 255, 0.98) 48%,
    rgba(188, 204, 255, 0.92) 100%
  );
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.auth-context-sub {
  margin: 6px 0 8px;
  font-size: clamp(1.0625rem, 1rem + 0.28vw, 1.25rem);   /* ~17–20 px */
  font-weight: 450;
  line-height: 1.65;
  color: rgba(232, 238, 255, 0.86);
  max-width: 44ch;
}

.auth-context-list {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.auth-context-list li {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: clamp(1.0625rem, 0.98rem + 0.18vw, 1.125rem);  /* ~17–18 px */
  font-weight: 600;
  color: rgba(240, 244, 255, 0.94);
  letter-spacing: 0.01em;
}

.auth-context-dot {
  flex-shrink: 0;
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: radial-gradient(
    circle at 32% 28%,
    #c2cdff 0%,
    #8c9eff 42%,
    #5e72e8 100%
  );
  box-shadow:
    0 0 0 1px rgba(140, 158, 255, 0.55),
    0 0 0 5px rgba(91, 140, 255, 0.14),
    0 0 14px rgba(91, 140, 255, 0.42);
}

/* ── Right form card — scoped overrides of the base .auth-card ──── */
.auth-page--login .auth-card,
.auth-page--signup .auth-card {
  max-width: none;                              /* grid column caps width */
  padding: clamp(36px, 3.6vw, 52px) clamp(32px, 3.6vw, 52px);
  margin: 0;
  border-color: rgba(150, 168, 225, 0.38);
  border-top-color: rgba(192, 208, 248, 0.46);
  box-shadow:
    0 44px 110px rgba(0, 0, 0, 0.54),
    0 18px 36px rgba(0, 0, 0, 0.28),
    0 0 0 1px rgba(120, 140, 215, 0.10),
    inset 0 1px 0 rgba(255, 255, 255, 0.072),
    inset 0 -1px 0 rgba(0, 0, 0, 0.24);
}

.auth-page--signup .auth-card {
  padding: clamp(28px, 3vw, 40px) clamp(30px, 3.2vw, 44px);
}

/* Title + subtitle — left-aligned, premium hierarchy */
.auth-page--login .auth-title,
.auth-page--signup .auth-title {
  text-align: left;
  font-size: clamp(2rem, 1.7rem + 0.9vw, 2.35rem);  /* ~32–37 px */
  font-weight: 800;
  letter-spacing: -0.026em;
  line-height: 1.12;
  margin: 0 0 10px;
}

.auth-page--login .auth-subtitle,
.auth-page--signup .auth-subtitle {
  text-align: left;
  margin: 0 0 28px;
  font-size: clamp(0.9375rem, 0.9rem + 0.15vw, 1.0625rem);  /* ~15–17 px */
  color: rgba(220, 228, 255, 0.68);
  line-height: 1.55;
}

.auth-page--signup .auth-subtitle {
  margin: 0 0 22px;
}

/* ── Google + primary CTA buttons — uniform premium sizing ─────── */
.auth-page--login .google-btn,
.auth-page--signup .google-btn {
  min-height: 56px;
  padding: 14px 22px;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.2px;
}

.auth-page--login .auth-btn,
.auth-page--signup .auth-btn {
  min-height: 56px;
  padding: 14px 22px;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.2px;
  margin-top: 6px;
}

/* OR divider — refined spacing and contrast */
.auth-page--login .auth-divider,
.auth-page--signup .auth-divider {
  margin: 24px 0 20px;
  gap: 14px;
}

.auth-page--signup .auth-divider {
  margin: 20px 0 16px;
}

.auth-page--login .auth-divider::before,
.auth-page--login .auth-divider::after,
.auth-page--signup .auth-divider::before,
.auth-page--signup .auth-divider::after {
  background: linear-gradient(90deg, transparent, rgba(150, 168, 225, 0.32), transparent);
}

.auth-page--login .auth-divider span,
.auth-page--signup .auth-divider span {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: rgba(220, 228, 255, 0.78);
}

/* ── Fields — taller inputs, clearer labels ─────────────────────── */
.auth-page--login .auth-field,
.auth-page--signup .auth-field {
  margin-bottom: 18px;
  gap: 9px;
}

.auth-page--login .auth-field label,
.auth-page--signup .auth-field label {
  font-size: 14px;
  font-weight: 600;
  color: rgba(245, 248, 255, 0.94);
  letter-spacing: 0.2px;
}

.auth-page--login .auth-field input,
.auth-page--signup .auth-field input {
  min-height: 54px;
  padding: 15px 18px;
  font-size: 1rem;        /* 16px */
  border-radius: 12px;
}

/* Signup density: slightly tighter rhythm so the 5-field card fits the
   viewport without feeling cramped. Input height stays premium. */
.auth-page--signup .auth-field {
  margin-bottom: 13px;
  gap: 7px;
}

.auth-page--signup .auth-field input {
  min-height: 52px;
  padding: 13px 18px;
}

.auth-page--signup .auth-btn {
  margin-top: 10px;
}

.auth-page--login .auth-field-hint,
.auth-page--signup .auth-field-hint {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.45;
}

/* Note: input focus styles use the base .auth-field input:focus rules
   which are already theme-aware (dark in styles.css, light in
   theme-light.css). No scoped focus override here to avoid bleeding
   the dark ring into light mode. */

/* ── Bottom links — readable, more prominent, premium ─────────────── */
.auth-page--login .auth-links,
.auth-page--signup .auth-links {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid rgba(150, 168, 225, 0.14);
  gap: 12px;
  font-size: 0.9875rem;       /* ~15.8px */
  color: rgba(232, 238, 255, 0.86);
  letter-spacing: 0.005em;
}

.auth-page--signup .auth-links {
  margin-top: 24px;
  padding-top: 18px;
}

.auth-page--login .auth-links span,
.auth-page--signup .auth-links span {
  color: var(--text-muted);
}

.auth-page--login .auth-links a,
.auth-page--signup .auth-links a {
  font-weight: 600;
  color: rgba(200, 214, 255, 0.96);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 4px;
  text-decoration-thickness: 1.5px;
  text-shadow: 0 0 0 transparent;
  transition:
    color 0.18s ease,
    text-decoration-color 0.18s ease,
    text-shadow 0.22s ease;
}

.auth-page--login .auth-links a:hover,
.auth-page--signup .auth-links a:hover,
.auth-page--login .auth-links a:focus-visible,
.auth-page--signup .auth-links a:focus-visible {
  color: #ffffff;
  text-decoration-color: rgba(205, 218, 255, 0.85);
  text-shadow: 0 0 14px rgba(150, 175, 255, 0.42);
  outline: none;
}

.auth-page--login .auth-links a:focus-visible,
.auth-page--signup .auth-links a:focus-visible {
  border-radius: 4px;
  box-shadow: 0 0 0 3px rgba(130, 160, 255, 0.28);
}

/* ── Responsive ─────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .auth-shell {
    grid-template-columns: minmax(320px, 1fr) minmax(0, 500px);
    gap: 48px;
  }

  .auth-page--signup .auth-shell {
    grid-template-columns: minmax(320px, 1fr) minmax(0, 540px);
  }
}

@media (max-width: 880px) {
  .auth-page--login,
  .auth-page--signup {
    padding: 48px 24px 72px;
  }

  .auth-shell,
  .auth-page--signup .auth-shell {
    max-width: 560px;
    grid-template-columns: 1fr;
    gap: 36px;
  }

  .auth-context-panel {
    max-width: none;
    text-align: center;
    align-items: center;
    gap: 18px;
  }

  /* Centre the editorial accent bar when the panel is centre-aligned */
  .auth-context-eyebrow::before {
    left: 50%;
    transform: translateX(-50%);
  }

  /* On tablet, login and signup share the same headline scale so the two
     dedicated auth pages stay visually consistent in the single-column
     stack. */

  .auth-context-sub {
    max-width: 54ch;
    font-size: 1.0625rem;
  }

  /* Collapse feature list on tablet — eyebrow + headline + sub are enough */
  .auth-context-list {
    display: none;
  }

  .auth-page--login .auth-card,
  .auth-page--signup .auth-card {
    padding: 36px 32px 32px;
  }
}

@media (max-width: 520px) {
  .auth-page--login,
  .auth-page--signup {
    padding: 28px 16px 96px;
  }

  .auth-page--login .auth-card,
  .auth-page--signup .auth-card {
    padding: 30px 22px 26px;
    border-radius: 16px;
  }

  /* Hide the context panel entirely on phones — the form is the focus */
  .auth-context-panel {
    display: none;
  }

  .auth-page--login .auth-title,
  .auth-page--signup .auth-title {
    font-size: 1.625rem;
  }

  .auth-page--login .auth-subtitle,
  .auth-page--signup .auth-subtitle {
    margin-bottom: 22px;
  }

  .auth-page--login .auth-field input,
  .auth-page--signup .auth-field input {
    min-height: 50px;
    padding: 13px 16px;
  }

  .auth-page--login .google-btn,
  .auth-page--signup .google-btn,
  .auth-page--login .auth-btn,
  .auth-page--signup .auth-btn {
    min-height: 52px;
  }
}

/* ═══════════════════════════════════════════════════════════════════
   Final polish pass — placeholder contrast, refined focus, premium
   hover lift, balanced signup left headline. All scoped to dedicated
   auth pages so the modal and password pages are unaffected.
   ═══════════════════════════════════════════════════════════════════ */

/* Signup left panel uses the same base headline + supporting copy sizing
   as login so the two dedicated auth pages feel like true siblings. */

/* Placeholder contrast — readable, still subtle */
.auth-page--login .auth-field input::placeholder,
.auth-page--signup .auth-field input::placeholder {
  color: rgba(190, 202, 230, 0.46);
  opacity: 1;
}

/* Slightly clearer input borders against the dominant card surface */
.auth-page--login .auth-field input,
.auth-page--signup .auth-field input {
  border-color: rgba(150, 168, 225, 0.34);
}

.auth-page--login .auth-field input:hover,
.auth-page--signup .auth-field input:hover {
  border-color: rgba(170, 188, 240, 0.46);
}

/* Refined focus ring — confident indigo, not loud */
.auth-page--login .auth-field input:focus,
.auth-page--signup .auth-field input:focus {
  border-color: rgba(130, 165, 255, 0.74);
  box-shadow:
    0 0 0 4px rgba(98, 132, 240, 0.17),
    inset 0 1px 0 rgba(255, 255, 255, 0.052),
    inset 0 -1px 0 rgba(0, 0, 0, 0.18);
}

/* Primary CTA — premium hover lift and richer gradient */
.auth-page--login .auth-btn,
.auth-page--signup .auth-btn {
  background: linear-gradient(180deg, #5474ff 0%, #3a59e8 52%, #2c47d2 100%);
  box-shadow:
    0 16px 38px rgba(42, 64, 188, 0.32),
    0 1px 3px rgba(0, 0, 0, 0.28),
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 -1px 0 rgba(0, 0, 0, 0.16);
}

.auth-page--login .auth-btn:hover,
.auth-page--signup .auth-btn:hover {
  background: linear-gradient(180deg, #6485ff 0%, #4566f4 52%, #3654dc 100%);
  box-shadow:
    0 20px 44px rgba(42, 64, 188, 0.38),
    0 2px 6px rgba(0, 0, 0, 0.32),
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    inset 0 -1px 0 rgba(0, 0, 0, 0.16);
  transform: translateY(-1.5px);
}

/* Google button — subtle border/background polish on hover */
.auth-page--login .google-btn,
.auth-page--signup .google-btn {
  border-color: rgba(228, 231, 238, 0.98);
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.14),
    0 6px 18px rgba(0, 0, 0, 0.14),
    inset 0 -1px 0 rgba(0, 0, 0, 0.04);
}

.auth-page--login .google-btn:hover,
.auth-page--signup .google-btn:hover {
  background: #fafbfc;
  border-color: rgba(212, 218, 232, 1);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.10),
    0 10px 24px rgba(0, 0, 0, 0.18),
    inset 0 -1px 0 rgba(0, 0, 0, 0.04);
  transform: translateY(var(--lift-sm));
}

/* ── Legal + error pages (audit hardening) ───────────────────────────── */
.legal-page,
.error-page {
  min-height: calc(100vh - 88px);
  padding: clamp(72px, 10vw, 120px) max(18px, env(safe-area-inset-left)) clamp(80px, 9vw, 112px) max(18px, env(safe-area-inset-right));
  color: var(--text);
  background:
    radial-gradient(circle at 50% 0%, rgba(197, 160, 40, 0.12), transparent 46%),
    var(--bg);
}

.legal-shell,
.error-card {
  width: min(100%, 880px);
  margin-inline: auto;
}

.legal-eyebrow,
.error-eyebrow {
  margin: 0 0 12px;
  color: var(--text-link); /* PT-07 */
  font-size: 0.76rem;
  font-weight: 760;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.legal-title,
.error-title {
  margin: 0;
  font-size: clamp(2rem, 7vw, 4.25rem);
  line-height: 1.04;
  letter-spacing: -0.045em;
  color: var(--text);
}

.legal-lede,
.error-lede {
  margin: 18px 0 0;
  max-width: 64ch;
  color: var(--muted);
  font-size: clamp(1rem, 2.5vw, 1.16rem);
  line-height: 1.7;
}

.legal-card,
.error-card {
  margin-top: 32px;
  padding: clamp(22px, 4vw, 38px);
  border: 1px solid var(--border);
  border-radius: 26px;
  background: var(--surface);
  box-shadow: var(--shadow-soft);
}

.error-card { text-align: center; }
.error-actions,
.video-unavailable-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 24px;
}

.legal-section + .legal-section {
  margin-top: 24px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
}

.legal-section h2 {
  margin: 0 0 8px;
  font-size: clamp(1.12rem, 3vw, 1.45rem);
  color: var(--text);
}

.legal-section p {
  margin: 0;
  color: var(--muted);
  line-height: 1.75;
}

.legal-section a {
  color: var(--text-link);
  overflow-wrap: anywhere;
} /* PT-07 */

.pwd-page .auth-field input,
.pwd-page .auth-btn,
.pwd-page .pwd-footer-link,
.error-page .auth-btn,
.error-page .pwd-footer-link {
  min-height: 44px;
}

@media (max-width: 520px) {
  .legal-page,
  .error-page { padding-top: 56px; }
  .legal-card,
  .error-card { border-radius: 20px; }
  .error-actions { flex-direction: column; align-items: stretch; }
}
