/* ============================================================
   overtly · design system
   Brand System v1.0 (Aug 2026): Warm Ivory canvas, Pastel Mint /
   Deep Evergreen / Soft Coral palette, rounded editorial surfaces,
   Inter typeface. See Overtly Brand Guidelines for the full system.
   ============================================================ */

:root {
  /* ---- Core palette (Overtly Brand Guidelines v1.0) ---- */
  --mint: #A3E4C8;          /* Pastel Mint - primary brand field */
  --mint-accent: #86DDBA;   /* Mint Accent - highlights and data */
  --mint-soft: #E2F5EC;     /* Pale Mint - cards and soft sections */
  --evergreen: #0B4638;     /* Deep Evergreen - primary contrast */
  --evergreen-deep: #176F58;/* Deep Accent - secondary dark green */
  --ink: #173B33;           /* Brand Ink - headlines and body emphasis */
  --coral: #F28A78;         /* Soft Coral - warm accent */
  /* Deep Coral. The "small emphasis only" note was exactly backwards: at
     3.48:1 on Warm Ivory it is the one size it must NOT be used at. It is
     a display-size and surface colour. Every small-text use moved to
     --coral-ink below on 28 September. */
  --coral-deep: #D96454;    /* Deep Coral - display size and surfaces only */
  /* Coral Ink. The legible coral, and the reason it exists is that the
     brand had none: Soft Coral is 2.36:1 and Deep Coral 3.48:1 on ivory,
     so every coral label, error and citation marker on the site was below
     the 4.5:1 floor. #AB4036 is 5.83:1 on ivory, 5.97 on white, 5.22 on
     pale, 5.33 on the soft panel and 4.87 on pale coral.

     Decision 61 proposed #C4553F for this and put it at "about 4.3 to 1".
     Measured, it is 4.35:1 and would not have passed. This supersedes it.

     Never on mint (4.12) or yolk (3.69). Text on a coloured tone is ink.
     Kept in step with --ov-coral-ink in the design system tokens. */
  --coral-ink: #AB4036;     /* Coral Ink - small coral text */
  --coral-soft: #FBE3DD;    /* Pale Coral - soft accent surface */
  --ivory: #FFFCF7;         /* Warm Ivory - primary canvas */
  --body-gray: #4B5752;     /* Body Gray - long-form text */
  /* Was #7B857F, which is 3.73:1 on Warm Ivory and fails WCAG AA for body
     text at every size the site uses it at. It is the colour behind
     .text-gray-500 and .text-gray-400, so it was setting 105 pieces of
     metadata across 29 pages below the legibility floor.

     #5d6c64 is 5.41:1 and is the same value the design system settled on
     as --ov-text-muted, so the legacy variable and the token now agree
     rather than quietly disagreeing on two halves of the same page.

     Safe as a single-line change because --muted is only ever used as a
     text colour: 47 occurrences across styles.css and app.js, every one
     of them a `color` declaration and not one a border, rule or dot. */
  --muted: #5d6c64;         /* Muted Gray - metadata */
  --line: #D9E0DC;          /* Neutral Line - borders and dividers */
  --bg-soft: #F4F2EC;       /* warm neutral surface for hover/soft blocks */

  /* ---- Legacy aliases (kept so existing "pink"/"mint" hooks in
     markup and JS pick up the new palette without touching every
     call site) ---- */
  --pink: var(--coral);
  --pink-soft: var(--coral-soft);

  /* ---- Spacing + radius tokens ---- */
  --radius-sm: 12px;   /* inputs, compact cards, tags */
  --radius-lg: 20px;   /* feature cards, illustration panels, hero modules */
  --radius-pill: 999px;/* status chips and compact labels only */
}

html, body {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  color: var(--body-gray);
  background: var(--ivory);
}

h1, h2, h3, h4, strong,
.heading-xl, .heading-lg, .heading-md, .heading-sm {
  color: var(--ink);
}

/* Baseline heading scale for bare h1-h6 tags that carry no .heading-*
   class and no Tailwind text-size utility (e.g. card titles built as
   `<h3 style="font-weight:700">...</h3>` in app.js, or `<h4
   class="font-bold">` in index.html's feature grid). Tailwind's preflight
   resets every heading to font-size:inherit, so without this those
   titles silently render at the surrounding body copy's size instead of
   reading as a title - this was reported as "titles too small, body text
   too big" on mobile card lists (Updates, dashboard). A type selector has
   lower specificity than any class, so `.heading-sm`, `text-sm`, etc.
   still win here as before; this only fills in the cases nothing else
   claims. See project memory "overtly-site-rebrand-2026-08". */
h1 { font-size: 2rem;    font-weight: var(--ov-title-weight, 500); letter-spacing: var(--ov-track-title, -0.035em); }
h2 { font-size: 1.5rem;  font-weight: 600; letter-spacing: var(--ov-track-card, -0.025em); }
h3 { font-size: 1.15rem; font-weight: 600; letter-spacing: var(--ov-track-card, -0.025em); }
h4 { font-size: 1rem; font-weight: 700; }
h5 { font-size: .95rem; font-weight: 700; }
h6 { font-size: .875rem; font-weight: 700; }

/* -------- Rounded surfaces across the system -------- */
.rounded, .rounded-md, .rounded-lg, .rounded-xl, .rounded-2xl,
button, input, .btn { border-radius: var(--radius-sm) !important; }
.rounded-sm { border-radius: 8px !important; }
/* Full circles for dots, avatars, progress bars, pills */
.rounded-full, .progress-bar, .progress-fill, .pill { border-radius: var(--radius-pill) !important; }

/* -------- Logo -------- */
/* Real brand lockup PNGs (mark + wordmark baked in), swapped per background
   in Overtly.renderLogo() -- evergreen on light, white on dark. No color
   styling needed here since the color lives in the image itself. */
a.logo, a.logo:link, a.logo:visited { text-decoration: none; }
.logo { display: inline-flex; align-items: center; line-height: 1; }

/* -------- Site chrome -------- */
.site-header {
  position: sticky; top: 0; z-index: 40;
  background: white; border-bottom: 1px solid var(--line);
  padding: 1rem 2rem;
  display: flex; align-items: center; justify-content: space-between;
}
.site-header .header-nav { display: flex; gap: .25rem; align-items: center; }
.site-header .header-nav a {
  font-size: .875rem; color: var(--body-gray); font-weight: 500;
  padding: .5rem .9rem;
  text-decoration: none;
  display: inline-flex; align-items: center; gap: .35rem;
  border-radius: var(--radius-sm);
}
/* "My dashboard" nav label: full text by default (desktop/tablet);
   swapped for the shorter "Dashboard" under the ≤767px header
   compaction below. */
.nav-label-short { display: none; }
.site-header .header-nav a:hover { background: var(--bg-soft); color: var(--ink); }
.site-header .header-nav a.active { color: var(--ink); font-weight: 700; background: var(--mint-soft); }

/* Creator Studio nav entry. Until 25 September this was a filled coral
   button, and because "a.nav-cta" outranked ".header-auth .nav-start" the
   Start learning button inherited the same coral: two identical filled
   buttons sitting side by side, neither of them clearly the primary.
   One filled action per header. Start learning is it, in evergreen.
   Creator Studio is the other audience's door, so it reads as a quiet
   outlined pill set apart by a rule rather than as a competing CTA. */
.site-header .header-nav a.nav-creator {
  position: relative;
  margin-left: .85rem;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--evergreen);
  font-weight: 600;
}
.site-header .header-nav a.nav-creator::before {
  content: ''; position: absolute; left: -.6rem; top: 50%;
  transform: translateY(-50%);
  width: 1px; height: 20px; background: var(--line);
}
.site-header .header-nav a.nav-creator:hover {
  background: var(--mint-soft); color: var(--evergreen); border-color: var(--mint-accent);
}
.site-header .header-nav a.nav-creator.active {
  background: var(--evergreen); border-color: var(--evergreen); color: #fff; font-weight: 700;
}
.site-header .learner-avatar {
  width: 32px; height: 32px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  color: white; font-weight: 700; font-size: .8rem;
  margin-left: .5rem;
}

.site-footer {
  background: var(--ink); color: rgba(255,255,255,0.65);
  padding: 2.5rem 2rem;
  margin-top: 4rem;
  display: flex; justify-content: space-between; align-items: center;
  gap: 1rem 2rem; flex-wrap: wrap;
  font-size: .75rem;
}
.site-footer__nav { display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; justify-content: center; }
.site-footer__nav a {
  color: rgba(255,255,255,0.75); font-weight: 500; text-decoration: none;
  padding: .5rem 0;
}
.site-footer__nav a:hover { color: white; }

/* -------- Course page: Related content, under the introduction -------- */
.ov-related { margin: var(--ov-space-4) 0 var(--ov-space-5); padding-left: var(--ov-space-4); border-left: 3px solid var(--ov-mint); }
.ov-related__label { display: block; font-size: var(--ov-size-meta); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ov-text-muted); margin-bottom: var(--ov-space-1); }
.ov-related ul { list-style: none; margin: 0; padding: 0; }
.ov-related li { margin: 0; line-height: 1.5; }
.ov-related a { color: var(--ov-forest); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.ov-related small { display: block; font-size: var(--ov-size-label); color: var(--ov-text-muted); }

/* -------- Reading pages: /about/, /contact/ and the legal pages --------
   One reading column. Tables scroll inside their own box on a phone so the
   page never scrolls sideways. */
.legal-doc { max-width: var(--ov-reading-width); margin: 0 auto; padding-block: var(--ov-space-9) var(--ov-space-10); }
.legal-doc h1 { font-size: var(--ov-size-section); line-height: var(--ov-leading-title); letter-spacing: var(--ov-track-title); font-weight: 600; margin: 0 0 var(--ov-space-2); }
.legal-doc .legal-meta { color: var(--ov-text-muted); font-size: var(--ov-size-label); margin: 0 0 var(--ov-space-7); }
.legal-doc h2 { font-size: var(--ov-size-card); line-height: 1.25; font-weight: 600; margin: var(--ov-space-8) 0 var(--ov-space-3); }
.legal-doc p, .legal-doc ul { margin: 0 0 var(--ov-space-4); }
.legal-doc ul { padding-left: 1.25rem; list-style: disc; }
.legal-doc ol { padding-left: 1.25rem; list-style: decimal; margin: 0 0 var(--ov-space-4); }
.legal-doc .legal-lead { font-size: var(--ov-size-lead); margin-bottom: var(--ov-space-6); }
.legal-doc .legal-actions { display: flex; flex-wrap: wrap; gap: var(--ov-space-3); margin-top: var(--ov-space-8); }
.legal-doc .legal-actions a { text-decoration: none; }
.legal-doc .legal-actions .btn-primary { color: var(--ov-action-text); }
.legal-doc li { margin-bottom: var(--ov-space-2); }
.legal-doc a { color: var(--ov-forest); text-decoration: underline; text-underline-offset: 2px; }
.legal-doc code { font-size: .875em; overflow-wrap: anywhere; }
.legal-doc .legal-table { overflow-x: auto; margin: 0 0 var(--ov-space-5); border: 1px solid var(--ov-divider); border-radius: var(--ov-radius-control); background: var(--ov-surface); }
.legal-doc .legal-table:focus-visible { outline: var(--ov-focus-width) solid var(--ov-focus); outline-offset: var(--ov-focus-offset); }
.legal-doc table { width: 100%; border-collapse: collapse; font-size: var(--ov-size-label); line-height: 1.5; }
.legal-doc th, .legal-doc td { text-align: left; vertical-align: top; padding: var(--ov-space-3) var(--ov-space-4); border-bottom: 1px solid var(--ov-divider); }
.legal-doc .legal-table--wide table { min-width: 40rem; }
.legal-doc tr:last-child > * { border-bottom: 0; }
.legal-doc thead th, .legal-doc tbody th { font-weight: 600; }
.legal-doc thead th { background: var(--ov-surface-soft); }
.site-footer__nav a:focus-visible { outline: 2px solid white; outline-offset: 2px; }

/* -------- Illustration bands (dividers) -------- */
.illustration-band {
  width: 100%;
  display: block;
  margin: 0;
  background: var(--mint-soft);
}
.illustration-band img {
  width: 100%; height: auto; display: block;
  max-height: 320px; object-fit: cover;
}

/* -------- Pills -------- */
.pill {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .3rem .7rem;
  font-size: .7rem; font-weight: 600; line-height: 1;
  white-space: nowrap;
}
.pill-mint { background: var(--mint-soft); color: var(--ink); }
.pill-pink { background: var(--coral-soft); color: var(--coral-ink); }
.pill-soft { background: white; border: 1px solid var(--line); color: var(--body-gray); }
.pill-verified { background: var(--mint-soft); color: var(--evergreen); }
.pill-free { background: var(--mint); color: var(--ink); }
.pill-paid { background: var(--coral-soft); color: var(--coral-ink); }
.pill-static { background: var(--bg-soft); color: var(--body-gray); }
.pill-ink { background: var(--ink); color: white; }

/* Creator Studio: compact "Studio preview" status pill, used across the
   catalogue, course workspace, and module edit/re-ingest pages in place
   of a full-paragraph banner. Each page keeps its own short caveat line
   underneath in muted text - this is just the pill itself. */
.studio-preview-pill{
  display:inline-flex; align-items:center; gap:.4rem;
  font-size:.72rem; font-weight:600; color: var(--body-gray);
  background: white; border:1px solid var(--line); border-radius: var(--radius-pill);
  padding:.35rem .75rem;
}
.studio-preview-dot{ width:6px; height:6px; border-radius:999px; background: var(--coral); flex-shrink:0; }
.studio-preview-note{ font-size:.75rem; color: var(--muted); margin-top:.5rem; line-height:1.5; }

/* -------- Frames -------- */
.frame {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: white;
  box-shadow: 0 1px 2px rgba(11,70,56,0.04);
}

/* -------- Walkthrough collapsed row (video/slides entry point) --------
   The play icon + "Watch ..." label already state the action, so the row
   itself is the whole affordance: no separate "Expand" text. Hover/focus
   give an unmistakable lift + tint so it doesn't read as inert. */
.walkthrough-collapsed {
  all: unset; box-sizing: border-box; width: 100%; cursor: pointer;
  display: flex; align-items: center; gap: .9rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: white;
  box-shadow: 0 1px 2px rgba(11,70,56,0.04);
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.walkthrough-collapsed:hover, .walkthrough-collapsed:focus-visible {
  border-color: var(--mint-accent);
  background: var(--mint-soft);
  box-shadow: 0 12px 30px rgba(11,70,56,0.10);
}
.walkthrough-collapsed:focus-visible { outline: 2px solid var(--evergreen); outline-offset: 2px; }
.walkthrough-play-icon {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 999px;
  background: var(--evergreen); color: white;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .85rem;
  transition: transform .15s, background-color .15s;
}
.walkthrough-collapsed:hover .walkthrough-play-icon,
.walkthrough-collapsed:focus-visible .walkthrough-play-icon {
  background: var(--evergreen-deep); transform: scale(1.08);
}
.walkthrough-collapsed-text { flex: 1; min-width: 0; text-align: left; }
.walkthrough-collapsed-title { display: block; font-weight: 700; color: var(--ink); font-size: .9rem; }
.walkthrough-collapsed-sub { display: block; font-size: .75rem; color: var(--muted); margin-top: .15rem; }
.walkthrough-chevron {
  flex-shrink: 0; font-size: 1.1rem; line-height: 1; color: var(--muted);
  transition: transform .15s, color .15s;
}
.walkthrough-collapsed:hover .walkthrough-chevron,
.walkthrough-collapsed:focus-visible .walkthrough-chevron {
  color: var(--evergreen); transform: translateY(2px);
}

/* -------- Progress -------- */
.progress-bar { height: 6px; background: var(--line); overflow: hidden; }
.progress-fill { height: 100%; background: var(--mint-accent); }
.glow-mint { box-shadow: 0 0 0 3px rgba(163,228,200,0.28); border-color: var(--mint); }

/* -------- Headings -------- */
/* Weight 500 and tight tracking, from the reference Orlando pointed at.
   The reference loads no webfont: what reads as a different typeface is
   the setting. Tracking scales with size, because -0.055em is right at
   60px and closes the counters on a 20px title. The values come from
   design-system/tokens.css so the face stays a one-line swap; the
   fallbacks keep these rules working on a page that has not loaded the
   token sheet yet. */
.heading-xl { font-size: 3.75rem; line-height: var(--ov-leading-display, 1.03);
  font-weight: var(--ov-title-weight, 500); letter-spacing: var(--ov-track-display, -0.045em); }
.heading-lg { font-size: 2.5rem;  line-height: var(--ov-leading-title, 1.1);
  font-weight: var(--ov-title-weight, 500); letter-spacing: var(--ov-track-title, -0.035em); }
.heading-md { font-size: 1.75rem; line-height: 1.18;
  font-weight: var(--ov-title-weight, 500); letter-spacing: var(--ov-track-title, -0.035em); }
.heading-sm { font-size: 1.25rem; line-height: 1.28;
  font-weight: 600; letter-spacing: var(--ov-track-card, -0.025em); }
/* Soft Coral is 2.36:1 on ivory, so this class could never be used on text
   legibly. Nothing references it; it points at the legible coral now rather
   than sitting here as a trap for the next person who finds it. */
.accent-pink { color: var(--coral-ink); }

/* -------- Layout -------- */
.container-x { max-width: 1280px; margin: 0 auto; padding: 0 2rem; }
.container-narrow { max-width: 960px; margin: 0 auto; padding: 0 2rem; }
/* padding-block on anything that can sit on a .container-x element.
   `padding: 4rem 0` sets padding-left and padding-right to 0, and where
   both classes are on one element that silently removes the page gutter.
   Found on 29 September with the whole creators page running edge to
   edge on a phone. tools/check-gutters.mjs now fails the build on it. */
.section-pad { padding-block: 4rem; }
.section-pad-lg { padding-block: 6rem; }

/* -------- Buttons (defaults) -------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .65rem 1.1rem;
  font-size: .9rem; font-weight: 700;
  cursor: pointer;
  border: 1px solid transparent;
  background: white; color: var(--ink);
  text-decoration: none;
}
.btn-primary { background: var(--evergreen); color: white; }
.btn-primary:hover { background: var(--evergreen-deep); }
.btn-mint { background: var(--mint-soft); color: var(--ink); }
.btn-mint:hover { background: var(--mint); }
/* The hero's primary action. The reference gives it noticeably more weight
   than a button in a form does, which is the point: it is the only object
   in the row now that the secondary action is a text link. */
.btn-lg { padding: 1rem 1.6rem; font-size: 1rem; border-radius: var(--radius-pill); }
.btn-ghost { background: white; border-color: var(--line); }
.btn-ghost:hover { background: var(--bg-soft); }
.btn-ink { background: var(--ink); color: white; }
.btn-block { width: 100%; }

/* -------- Inputs -------- */
.input {
  border: 1px solid var(--line);
  padding: .65rem .9rem;
  background: white;
  font-size: .9rem;
  color: var(--ink);
  border-radius: var(--radius-sm);
  outline: none;
}
.input:focus { border-color: var(--mint); box-shadow: 0 0 0 3px rgba(163,228,200,0.35); }

/* -------- Discover toolbar --------
   The search field used to carry Tailwind's flex-1 with a 280px floor,
   so it absorbed every spare pixel of the row and pushed "Recently
   updated" past the right edge of the viewport at 1280. It now grows
   from a 320px basis and stops at 520px, which is wider than any query
   anyone types and leaves the pills their own space. min-width:0 is
   what lets a flex item shrink below its content width at all.
   The mobile rules further down stack the two onto their own rows. */
#search-frame { flex: 1 1 320px; min-width: 0; max-width: 520px; }

/* -------- Course cards --------
   Superseded on 28 September by .ov-card in the design system, which is
   what renderCourseCard now emits. These rules are kept only because
   .course-card markup may still exist in a page this pass did not reach;
   grep before deleting them. */
.course-card {
  display: flex; flex-direction: column; gap: .75rem;
  padding: 1.25rem;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: white;
  transition: border-color .15s, box-shadow .15s;
  text-decoration: none;
  color: inherit;
}
.course-card:hover { border-color: var(--mint); box-shadow: 0 12px 30px rgba(11,70,56,0.10); }
.course-card .meta { font-size: .75rem; color: var(--muted); display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.course-card .creator-row { display: inline-flex; align-items: center; gap: .35rem; font-size: .75rem; color: var(--muted); }

/* -------- Avatar -------- */
.avatar { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-pill); color: white; font-weight: 700; }
.avatar-sm { width: 24px; height: 24px; font-size: .65rem; }
.avatar-md { width: 32px; height: 32px; font-size: .75rem; }
.avatar-lg { width: 56px; height: 56px; font-size: 1.1rem; }
.avatar-xl { width: 128px; height: 128px; font-size: 2.5rem; }

/* Brand-safe gradient set (avatar/initial badges) - coral, evergreen,
   and mint only, no neon or out-of-palette hues. */
/* An avatar initial has to clear 4.5:1 against EVERY point of its own
   gradient, not against one end of it.

   `.avatar` sets `color: white`, and white fails on three of the four
   brand stops these ramps were built from: coral 2.42:1, mint accent
   1.61:1, deep coral 3.56:1. Only Deep Evergreen carries white, at
   10.78:1. Ink is the mirror image: fine on coral and mint, 1.14:1 on
   Deep Evergreen. So a ramp that runs from Deep Evergreen to mint has no
   text colour that works along its whole length, and the initial fades
   out partway across whichever one you pick.

   `.gradient-pink-emerald` was corrected for this earlier and its four
   siblings were not. Measured off the rendered pixels of the UNICEF WASH
   avatar, a white initial on `.gradient-blue-emerald` sat at about
   3.58:1, and 1.61:1 where it crossed the mint end.

   Every sweep we run missed it for the same reason: a contrast check
   reads `backgroundColor`, and a gradient is `backgroundImage`, so these
   elements reported a transparent background and were measured against
   whatever was behind them. See the assertion in
   tools/check-design-tokens.mjs, which now measures every stop of every
   ramp against the text colour the ramp actually sets.

   The rule the set now follows: a ramp is either LIGHT and takes ink, or
   DARK and takes white. It never crosses the middle.

   Deep Coral #D96454 is in neither camp, at 3.56:1 for white and 3.45:1
   for ink, so `.gradient-orange-red` takes #C03D2B instead: the same hue
   and saturation carried down to where white clears 5.32:1. */
.gradient-pink-emerald { background: linear-gradient(135deg, var(--coral) 0%, var(--mint-accent) 100%);
  color: var(--ink); }
/* Light ramps, ink. Worst stop: coral at 5.08:1. */
.gradient-pink-purple-emerald { background: linear-gradient(135deg, var(--coral) 0%, var(--mint) 50%, var(--mint-accent) 100%);
  color: var(--ink); }
/* Dark ramps, white. Worst stops: Deep Accent 6.08:1, Coral Ink 5.97:1, #C03D2B 5.32:1. */
.gradient-orange-red { background: linear-gradient(135deg, var(--coral-ink) 0%, #C03D2B 100%);
  color: #fff; }
/* #176F58 is Deep Accent, spelled out rather than referenced: it lives in
   the design system as --ov-forest-accent, and tokens.css is not loaded on
   every page that renders an avatar. A var() that resolves nowhere would
   drop the stop and leave a flat block. Same trap as the .ov-icon sizing. */
.gradient-blue-emerald { background: linear-gradient(135deg, var(--evergreen) 0%, #176F58 100%);
  color: #fff; }
.gradient-purple-pink { background: linear-gradient(135deg, var(--evergreen) 0%, var(--coral-ink) 100%);
  color: #fff; }

/* -------- Lesson body typography -------- */
/* Brand Ink, not Body Gray, and 1.80 rather than 1.65.
   Changed 29 September 2026. A course was set in #4B5752 at 1.65 across an
   84-character measure. Body Gray is for long-form text by its own comment,
   and it passes contrast, but the reading surface is the one place on the
   site that should take the strongest value the palette has: 12:1 rather
   than 8:1, for the text people spend forty minutes with. Leading follows
   the measure, and at 84 characters 1.65 is tight. Both from Orlando's
   lesson reference. */
.lesson-p { margin-top: 1rem; font-size: 1rem; line-height: 1.8; color: var(--ink); }
.lesson-p strong { color: var(--ink); }
.lesson-section { padding: 2rem 0; border-top: 1px solid var(--line); }
.lesson-section:first-child { border-top: none; padding-top: 0; }
.lesson-h2 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.01em; line-height: 1.2; }
.lesson-meta { font-size: .8rem; color: var(--muted); margin-top: .35rem; }
.try-it-now { margin-top: 1.5rem; padding: 1rem 1.25rem; background: var(--mint-soft); border-left: 3px solid var(--mint); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.try-it-now-label { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--evergreen); font-weight: 700; }
.try-it-now-body { margin-top: .35rem; font-size: .95rem; line-height: 1.55; color: var(--ink); }
.cite-list { margin-top: 1.5rem; padding: 1rem; background: var(--bg-soft); border-radius: var(--radius-sm); font-size: .75rem; }
.cite-list .label { text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; font-size: .7rem; }
.cite-list ul { margin-top: .5rem; }
.cite-list li { padding: .15rem 0; color: var(--body-gray); }
/* Was var(--coral), Soft Coral, at 2.42:1 on white. The marker is the
   visible proof of the thing Overtly sells and it was the least legible
   text on the page. */
.cite-list .marker { color: var(--evergreen); font-weight: 700; margin-right: .25rem; }

/* -------- Lesson subheads and notes. Added 1 October 2026 --------
   Subheads were bold paragraphs because the renderer had no heading rule
   and every assembler downgraded `## ` to a bold line to fit. They are h3
   now, under the lesson's h2, so a screen reader can move between them.
   20px at 600: one clear step above 16px body text at 400, and below the
   27px lesson title. The colour stays Brand Ink, as it was. */
.lesson-h3 { margin-top: 1.75rem; font-size: 1.25rem; font-weight: 600; line-height: 1.35;
  letter-spacing: -0.01em; color: var(--ink); }
.lesson-body > .lesson-h3:first-child { margin-top: .75rem; }

/* A note marker is a bare letter, never a bracketed number: [2] on this
   page already means a source, and "we computed this" must not read as
   "a source said this". Same evergreen as the citation marker, because
   both are pointers to something below, at 10.54:1 on paper. */
.note-marker { margin-left: 1px; line-height: 0; }
.note-marker a { color: var(--evergreen); font-weight: 700; text-decoration: none; }
.note-marker a:hover, .note-marker a:focus-visible { text-decoration: underline; }

/* Notes print above the sources: notes, then references. Plain rather than
   boxed, so the two blocks read as two kinds of thing rather than as one
   list split in half. Ink on paper, 12:1; the label shares the sources
   label's treatment so the pair reads as one apparatus. */
.lesson-notes { margin-top: 1.5rem; padding: 0 1rem; font-size: .8125rem; }
.lesson-notes .label { text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
  font-weight: 700; font-size: .7rem; }
.lesson-notes ol { list-style: none; margin: .4rem 0 0; padding: 0; }
.lesson-notes li { display: flex; gap: .5rem; padding: .2rem 0; color: var(--ink); line-height: 1.55; }
.lesson-notes .note-back { flex: none; min-width: 1ch; color: var(--evergreen); font-weight: 700;
  text-decoration: none; }
.lesson-notes .note-back:hover, .lesson-notes .note-back:focus-visible { text-decoration: underline; }
/* Jumping to a note lands it under the sticky header otherwise. */
.lesson-notes li, .note-marker a { scroll-margin-top: 96px; }

/* -------- Deep-track callouts (case study / exercise) -------- */
.deep-callout { margin-top: 1.5rem; padding: 1rem 1.25rem; background: var(--coral-soft); border-left: 3px solid var(--coral); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.deep-callout-label { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--coral-ink); font-weight: 700; }
.deep-callout-heading { margin-top: .35rem; font-size: 1rem; font-weight: 700; color: var(--ink); }
.deep-callout-body { margin-top: .35rem; font-size: .95rem; line-height: 1.55; color: var(--ink); }
.deep-callout + .deep-callout { margin-top: 1rem; }

/* -------- Resources panel (module page) -------- */
.resources-panel .resources-list { display: flex; flex-direction: column; gap: .5rem; }
.resource-item {
  display: flex; align-items: center; gap: .75rem; padding: .7rem .85rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  text-decoration: none; color: inherit; background: white; transition: border-color .15s;
}
a.resource-item:hover { border-color: var(--mint-accent); }
.resource-item-pending { background: var(--bg-soft); }
.resource-icon {
  flex-shrink: 0; width: 32px; height: 32px; border-radius: var(--radius-sm);
  background: var(--mint-soft); color: var(--evergreen); display: inline-flex;
  align-items: center; justify-content: center; font-size: .9rem;
}
.resource-body { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.resource-title { font-size: .875rem; font-weight: 600; color: var(--ink); }
.resource-meta { font-size: .7rem; color: var(--muted); margin-top: .1rem; }
.resource-go { flex-shrink: 0; font-size: .75rem; font-weight: 600; color: var(--evergreen); white-space: nowrap; }
.resource-pending-tag {
  flex-shrink: 0; font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); background: var(--line); padding: .2rem .5rem; border-radius: var(--radius-pill); white-space: nowrap;
}

/* -------- Quiz -------- */
.quiz-progress { font-size: .7rem; font-weight: 700; color: var(--evergreen); background: var(--mint-soft); padding: .3rem .7rem; border-radius: var(--radius-pill); white-space: nowrap; }
.quiz-card { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 1.25rem; background: white; transition: border-color .15s; }
.quiz-card.answered { border-color: var(--line); }
.quiz-kind { display: inline-block; font-size: .65rem; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }
.quiz-prompt { margin-top: .5rem; font-size: 1rem; font-weight: 600; color: var(--ink); line-height: 1.45; }

/* Legacy reveal-answer fallback (only used if a quiz item can't be
   parsed into clean multiple choice) */
.quiz-answer { margin-top: .75rem; padding-top: .75rem; border-top: 1px dashed var(--line); font-size: .85rem; color: var(--body-gray); line-height: 1.5; display: none; }
.quiz-card.show-answer .quiz-answer { display: block; }
.quiz-toggle { margin-top: .75rem; font-size: .75rem; color: var(--coral-ink); font-weight: 600; cursor: pointer; background: none; border: none; padding: 0; }

/* Interactive multiple-choice options */
.quiz-options { margin-top: .9rem; display: flex; flex-direction: column; gap: .5rem; }
.quiz-option {
  display: flex; align-items: center; gap: .7rem;
  width: 100%; text-align: left;
  padding: .7rem .9rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: white; cursor: pointer;
  font-family: inherit; font-size: .9rem; color: var(--body-gray);
  transition: border-color .15s, background .15s;
}
.quiz-option:hover { border-color: var(--mint); background: var(--mint-soft); }
.quiz-option-letter {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: var(--bg-soft); color: var(--ink);
  font-weight: 700; font-size: .72rem;
  transition: background .15s, color .15s;
}
.quiz-option-text { line-height: 1.4; }
.quiz-option.selected { border-color: var(--ink); }
.quiz-option.correct { border-color: var(--evergreen); background: var(--mint-soft); }
.quiz-option.correct .quiz-option-letter { background: var(--evergreen); color: white; }
.quiz-option.incorrect { border-color: var(--coral); background: var(--coral-soft); }
/* White on Deep Coral is 3.56:1 and ink on it is 3.46:1, so neither
   foreground works on that ground. Coral Ink takes white at 5.97:1. Only
   visible after a wrong answer, which is why no page sweep caught it. */
.quiz-option.incorrect .quiz-option-letter { background: var(--coral-ink); color: white; }
.quiz-card.answered .quiz-option:not(.correct):not(.incorrect) { opacity: .55; }
.quiz-feedback { margin-top: .7rem; font-size: .85rem; font-weight: 600; display: none; }
.quiz-feedback.show { display: block; }
.quiz-feedback.right { color: var(--evergreen); }
.quiz-feedback.wrong { color: var(--coral-ink); }

/* -------- Lesson sidebar (module page) -------- */
.lesson-list { display: flex; flex-direction: column; gap: .35rem; font-size: .875rem; }
.lesson-list .lesson-item {
  padding: .55rem .65rem;
  color: var(--body-gray);
  cursor: pointer;
  border-radius: var(--radius-sm);
  display: flex; justify-content: space-between; align-items: center;
}
.lesson-list .lesson-item:hover { background: var(--bg-soft); color: var(--ink); }
.lesson-list .lesson-item.current { background: var(--mint-soft); border: 1px solid var(--mint); color: var(--ink); font-weight: 600; }
.lesson-list .lesson-item.completed { color: var(--body-gray); }

/* -------- Collapsible side panels (course landing page) --------
   Course overview / Features / Sources / Version history, wired up
   by Overtly.initCollapsibles() (see app.js). Collapsed is the CSS
   default everywhere (.collapsible-body starts display:none); JS
   adds .is-open on load for wider viewports so desktop keeps
   showing this content the way it always did, while mobile starts
   collapsed - "compact and collapsible, not everyone wants to read
   it" per the brief. */
.collapsible-toggle {
  display: flex; width: 100%;
  align-items: center; justify-content: space-between;
  gap: .5rem;
  background: none; border: none; padding: 0; margin: 0;
  font: inherit; text-align: left; cursor: pointer;
}
.collapsible-toggle h4 { margin: 0; }
.collapsible-caret {
  flex-shrink: 0;
  color: var(--muted);
  transition: transform .15s ease;
  font-size: .85rem;
}
.collapsible-panel.is-open .collapsible-caret { transform: rotate(180deg); }
.collapsible-body { display: none; }
.collapsible-panel.is-open .collapsible-body { display: block; }

/* -------- Anchor offset for sticky header -------- */
:target { scroll-margin-top: 80px; }

/* -------- Utilities -------- */
.text-muted { color: var(--muted); }
.divider { height: 1px; background: var(--line); }
.bg-mint-soft { background: var(--mint-soft); }
.bg-pink-soft { background: var(--pink-soft); }
.border-mint { border-color: var(--mint) !important; }
.border-pink { border-color: var(--pink) !important; }
/* Visually-hidden but screen-reader-accessible: used to keep a logical
   heading order (e.g. a section that has no visible heading in the
   design but still needs an h2 between the page h1 and its h4 items). */
/* Skip link: first stop for a keyboard, hidden until it takes focus. */
.ov-skip {
  position: absolute; left: .75rem; top: -5rem; z-index: 1000;
  background: var(--evergreen); color: #fff; font-weight: 600; font-size: .9rem;
  padding: .6rem 1rem; border-radius: var(--radius-sm); text-decoration: none;
}
.ov-skip:focus { top: .75rem; outline: 2px solid var(--mint-accent); outline-offset: 2px; }
main:focus { outline: none; }
.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;
}

/* ============================================================
   BRAND ALIGNMENT - Tailwind utility color overrides

   Page templates (catalogue, dashboard, creator profile, course
   and module pages) use Tailwind's CDN color utilities directly
   (text-gray-500, text-pink-600, border-emerald-500, etc). Rather
   than hand-edit every static course/module HTML file, override
   those utility classes here so the whole site - including every
   per-course page generated from the same template - stays on
   the Overtly palette from this one file.
   ============================================================ */
.text-gray-400 { color: var(--muted) !important; }
.text-gray-500 { color: var(--muted) !important; }
.text-gray-600 { color: var(--body-gray) !important; }
.text-gray-700 { color: var(--body-gray) !important; }
.text-gray-900 { color: var(--ink) !important; }
.text-pink-600, .text-pink-700 { color: var(--coral-ink) !important; }
.text-emerald-500, .text-emerald-600, .text-emerald-700 { color: var(--evergreen) !important; }
.border-emerald-500 { border-color: var(--evergreen) !important; }
.border-pink-300 { border-color: var(--coral) !important; }
a.hover\:text-gray-900:hover, .hover\:text-gray-900:hover { color: var(--ink) !important; }
.hover\:border-emerald-500:hover { border-color: var(--evergreen) !important; }

/* Literal inline colors baked into per-course template pages at
   generation time (course/module pages are static per course  - 
   fix centrally via attribute selectors rather than editing every
   course's HTML). */
[style*="#FBCFE8"] { border-color: var(--coral-soft) !important; }
[style*="background:#F3F4F6"], [style*="background: #F3F4F6"] { background: var(--bg-soft) !important; }
[style*="color: #4B5563"], [style*="color:#4B5563"] { color: var(--body-gray) !important; }
[style*="color: #1F2937"], [style*="color:#1F2937"] { color: var(--body-gray) !important; }
/* Course-page title is set inline to var(--mint) per the page template  - 
   too pale for a large headline on the ivory canvas; use Deep Evergreen
   for proper contrast (this ID is consistent across every course page). */
#course-title { color: var(--evergreen) !important; }

/* ============================================================
   LANDING PAGE v2 (2026-08-14): approved "Concept A visuals +
   Concept C product narrative" redesign. Scoped to index.html
   only - hero, product-principles row, "How knowledge stays
   current" process section, and the relocated learning-journey
   section. Course-discovery cards are untouched (still the
   shared, text-only Overtly.renderCourseCard used everywhere on
   the platform - see app.js). Design tokens above already match
   the brief's palette/radius spec 1:1 from the earlier rebrand
   pass, so nothing in :root changed for this pass. See project
   memory "overtly-site-rebrand-2026-08" for the full writeup.
   ============================================================ */

/* ---- Hero: 5/7 column split, illustration + 3 floating proof
   cards on the right. Top padding matches section-pad-lg (6rem);
   bottom is intentionally much smaller than top, because the row
   below used to overlap up into the hero's bottom edge.

   That row is now the flat .ov-tiles in the design system, which
   overlaps nothing and carries its own top gap in .ov-section--tiles.
   This padding stays as it is because the Creator Studio hero uses
   .hero-section too. See project memory
   "overtly-site-rebrand-2026-08" for the original reasoning. */
.hero-section { padding-top: 6rem; padding-bottom: 1.5rem; }
.hero-grid {
  display: grid;
  grid-template-columns: 5.5fr 6.5fr;
  gap: 2.5rem;
  align-items: center;
}
.hero-art-wrap { position: relative; }
.hero-art-wrap .hero-img { width: 100%; height: auto; display: block; }
/* The .principles-band rules that lived here are gone. The white
   panel they styled was replaced on 28 September by the coloured
   .ov-tiles row in the design system, which is deliberately flat
   and unelevated, so the overlap and shadow they existed to
   produce no longer have anything to apply to. */
.hero-proof-card {
  position: absolute;
  background: white;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: 0 12px 30px rgba(11,70,56,0.10);
  padding: .7rem .85rem;
  font-size: .75rem;
  width: 172px;
}
/* Positioned to clear the illustration's face/hand/tablet area
   (confirmed against the actual asset, not guessed) rather than
   overlapping the figure. */
.hero-proof-card--expert   { top: 2%;  left: 0; }
.hero-proof-card--flow     { top: 0;   right: 0; }
.hero-proof-card--progress { bottom: 6%; right: 2%; }
.hero-proof-avatar {
  width: 34px; height: 34px; border-radius: var(--radius-pill);
  object-fit: cover; display: block; flex-shrink: 0;
}
.hero-proof-title { font-weight: 700; color: var(--ink); font-size: .8rem; line-height: 1.25; }
.hero-proof-sub { color: var(--muted); font-size: .68rem; margin-top: .15rem; line-height: 1.3; }
.hero-flow-row { display: flex; align-items: center; gap: .45rem; font-weight: 600; color: var(--ink); }
.hero-flow-arrow { text-align: center; color: var(--muted); font-size: .8rem; margin: .2rem 0; padding-left: 2px; }
/* padding-bottom is deliberately modest (not the requested 80-96px on
   its own): the site-wide `.site-footer` rule below already adds
   `margin-top: 4rem` (64px) after any content, so this section's own
   1.5rem (24px) combines with that to land the total Warm-Ivory gap
   before the footer at 88px - inside the requested 80-96px range -
   without double-counting the footer's existing global spacing rule. */

/* ============================================================
   SLIDE PLAYER - MOTION PILOT (opt-in via renderSlidePlayer's
   opts.motion, see assets/app.js). Adds a slow Ken Burns drift
   behind the slide, a staggered fade/slide-up reveal on the
   text, and a large background stat treatment for data-heavy
   captions. Everything here is scoped under .slide-player-motion
   so it never touches a player that didn't opt in.
   ============================================================ */
@keyframes overtly-kenburns {
  from { transform: scale(1) translate(0, 0); }
  to   { transform: scale(1.06) translate(-1.5%, -1%); }
}
@keyframes overtly-drift {
  from { transform: translate(0, 0); }
  to   { transform: translate(-4%, 3%); }
}
.slide-player-motion .slide-bg-layer {
  animation-name: overtly-kenburns;
  animation-timing-function: ease-out;
  animation-fill-mode: forwards;
  animation-duration: 10s;
}
.slide-player-motion .slide-art-motif {
  position: absolute;
  inset: -12%;
  background-image: radial-gradient(circle, rgba(255,255,255,0.12) 1.5px, transparent 1.5px);
  background-size: 26px 26px;
  opacity: .55;
  animation: overtly-drift 16s ease-in-out infinite alternate;
  pointer-events: none;
}
.slide-player-motion .slide-kicker,
.slide-player-motion .slide-num,
.slide-player-motion .slide-heading,
.slide-player-motion .slide-caption,
.slide-player-motion .slide-stat {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .55s ease, transform .55s ease;
}
.slide-player-motion .slide-kicker.reveal,
.slide-player-motion .slide-num.reveal,
.slide-player-motion .slide-heading.reveal,
.slide-player-motion .slide-caption.reveal,
.slide-player-motion .slide-stat.reveal {
  opacity: 1;
  transform: translateY(0);
}
.slide-player-motion .slide-kicker.reveal { transition-delay: 0s; }
.slide-player-motion .slide-num.reveal    { transition-delay: .02s; }
.slide-player-motion .slide-heading.reveal { transition-delay: .09s; }
.slide-player-motion .slide-caption.reveal { transition-delay: .17s; }
.slide-player-motion .slide-stat.reveal    { transition-delay: .03s; }
.slide-player-motion .slide-stat {
  position: absolute;
  right: 48px;
  top: 40px;
  text-align: right;
  pointer-events: none;
}
.slide-player-motion .slide-stat-num {
  display: block;
  font-size: 4.25rem;
  font-weight: 800;
  color: rgba(255,255,255,0.16);
  line-height: 1;
  letter-spacing: -0.02em;
}
.slide-player-motion .slide-stat-sub {
  display: block;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.24);
  margin-top: .25rem;
}
/* Respect reduced-motion preferences: drop the animated drift, keep the
   fade/slide-up reveal (it's brief and one-shot, not a looping motion). */
@media (prefers-reduced-motion: reduce) {
  .slide-player-motion .slide-bg-layer,
  .slide-player-motion .slide-art-motif {
    animation: none !important;
  }
}

/* ============================================================
   RESPONSIVE: mobile and tablet

   Applies to every current and future page without requiring
   HTML changes. Future course / module pages get mobile
   responsiveness automatically because the rules target
   Tailwind utility classes, custom site-chrome classes, and
   the slide-player class hooks centrally.

   Three breakpoints:
   - 1199px and below: tablet and phones together. Only the
     landing-page v2 hero and learning-journey grids stack here
     (per that design brief's explicit tablet behavior) - nothing
     else in the site defines a distinct tablet tier, everything
     else only changes at 767px and below.
   - 767px and below: phones and small tablets. Stack all
     multi-column layouts. Wrap the header nav. Reduce
     headings, paddings, and slide-player chrome.
   - 479px and below: small phones. Further reduce headings
     and container paddings.

   Authoring rule for new pages: do not add bespoke media
   queries per page. If a layout looks wrong on mobile,
   extend this block.
   ============================================================ */

@media (max-width: 1199px) {
  /* Landing page v2: hero and learning-journey stack to a single
     column at tablet width and below (copy above illustration/
     dashboard, per the design brief's tablet spec) - not just at
     the 767px phone breakpoint. hero-art-wrap and hero-proof-card
     flip out of absolute positioning together, in the same
     breakpoint, so a card can never end up absolutely positioned
     against a parent that's already gone static (which would throw
     it to the wrong containing block instead of just stacking). */
  .hero-grid { grid-template-columns: 1fr; gap: 2rem; }
  .hero-art-wrap { position: static; }
  .hero-proof-card {
    position: static;
    width: 100%;
    margin-top: .6rem;
    box-shadow: none;
  }
  /* Tablet/mobile stacking order (2026-08-14 no-boundary correction):
     copy+actions, then the illustration, then the dashboard preview -
     same order at both tiers now (previously tablet put the dashboard
     second; the brief's current spec has the illustration in that
     slot at every width below desktop). Resets the desktop 2-column
     named areas and row-stretch/bottom-alignment, which don't apply
     once grid-template-columns above collapses to a single 1fr track. */
  /* No gutter to bridge into at a single column, and the brief calls
     for a centered (not lower-left-anchored) illustration at tablet -
     "remove any overlap if space becomes constrained." Resets the
     desktop translateX/justify-self bridging trick. Mobile further
     overrides max-width to full-width in the 767px block below. */

  /* The desktop-only "principles row overlaps the hero" treatment
     depends on the hero being a short, wide two-column strip. Once
     the hero stacks (this same breakpoint), it's a much taller
     single column ending in a stacked proof card - pulling the
     principles row up -3rem here would overlap that last card
     instead of just the illustration's bottom edge. Fall back to a
     normal, non-overlapping gap instead. */
  .hero-section { padding-bottom: 2.5rem; }

  /* Process-section subtitle: the desktop no-wrap treatment assumes
     the wide, unconstrained container width above 1199px. Below
     that, let it wrap normally rather than overflowing or forcing
     the section wider than the viewport. */

  /* Structural rail is desktop-only per the brief - tablet gets a
     2x2 grid (no rail bent around rows) and mobile relies on the
     numbered/titled sequence alone. Covers both tiers in one rule
     since this block already spans everything ≤1199px. */
}

@media (max-width: 1199px) and (min-width: 768px) {
  /* Tablet only (768-1199px): course-discovery cards and the new
     4-item principles/process rows go two-per-row rather than
     collapsing all the way to one column like they do at 767px
     and below - matches the design brief's "principles and
     narrative become 2x2 grids; course cards become two columns"
     tablet spec. Scoped to this range only so it doesn't affect
     the existing 767px-and-below single-column behavior. */
  .grid.grid-cols-3,
  .grid.grid-cols-4 {
    grid-template-columns: repeat(2, 1fr) !important;
  }
  /* Same grid-item blowout guard as the 767px block below (see its
     comment for the underlying min-width:auto issue), needed here
     too now that grid-cols-4 rows (principles, process stages) hold
     denser content like the process section's course/journey rows. */
  .grid.grid-cols-3 > *,
  .grid.grid-cols-4 > * {
    min-width: 0;
  }

  /* The stacked hero illustration had no ceiling between 768 and 1199.
     The ≤767 block below caps it at 200px, and above 1200 it sits in its
     own grid column, but in this range it kept width:100%/height:auto in
     a single column, so at 1024 it rendered 960 by 881 and pushed
     everything under it off the first screen. Measured against the live
     site before the design work: identical, so this is an old defect
     rather than something the conversion introduced.

     Same treatment as the phone tier, with more room: a band rather than
     a page. `center 35%` is copied deliberately and is tuned to where the
     subject sits in this particular illustration, not a generic default.
     If the image is replaced, re-check it here and in the ≤767 block. */
  .hero-art-wrap .hero-img {
    max-height: 360px;
    object-fit: cover;
    object-position: center 35%;
    border-radius: var(--radius-lg);
  }
}

@media (max-width: 767px) {
  /* Container padding: reduce.
     Horizontal-only, deliberately: this shares elements with classes
     like .hero-section/.section-pad that set their
     own top/bottom padding. The old `padding: 0 1rem` shorthand set
     padding-top/bottom to 0 on every one of those, and because this
     rule sits later in the file it silently won the cascade over
     e.g. .hero-section's padding-top: 6rem - the actual cause of
     "no air above the hero/page title" on mobile (confirmed via
     computed-style measurement: 0px instead of the intended rem
     value on every affected section). Longhand left/right keeps this
     rule scoped to what it's meant to control. See project memory
     "overtly-site-rebrand-2026-08". */
  .container-x,
  .container-narrow {
    padding-left: 1.25rem;
    padding-right: 1.25rem;
  }

  /* Section padding: reduce */
  .section-pad    { padding-block: 2rem; }
  .section-pad-lg { padding-block: 2.5rem; }

  /* Headings: reduce */
  .heading-xl { font-size: 2.5rem !important; line-height: 1.1; }
  .heading-lg { font-size: 2rem    !important; line-height: 1.15; }
  .heading-md { font-size: 1.5rem  !important; }
  .heading-sm { font-size: 1.2rem  !important; }

  /* Site header: stay on one line, shrunk down.
     Previously this wrapped to two lines (logo on its own row, nav
     below) because flex-wrap:wrap let the row grow taller instead of
     the contents shrinking to fit - reported as "top bar split in two
     lines" on every page. Fixed by shrinking the logo, the nav item
     padding/font, and the "My dashboard" label (see .nav-label-short
     below) enough that logo + nav + avatar fit in one row down to a
     320px viewport (confirmed via Playwright measurement), then
     switching to nowrap so a rendering variance can't silently
     reintroduce the two-line wrap. */
  .site-header {
    padding: 0.5rem 0.65rem;
    flex-wrap: nowrap;
    gap: 0.35rem;
  }
  .site-header .logo img { height: 16px !important; }
  .site-header .header-nav { gap: 0.05rem; flex-wrap: nowrap; }
  .site-header .header-nav a {
    padding: 0.32rem 0.4rem;
    font-size: 0.72rem;
  }
  .site-header .learner-avatar { margin-left: 0.2rem; width: 24px; height: 24px; font-size: 0.65rem; }

  /* "My dashboard" -> "Dashboard": one word shorter, enough on its
     own to help the header fit one line at this width. Both spans
     are written once in app.js's renderHeader(); default (desktop)
     CSS above the ≤767 breakpoint keeps .nav-label-short hidden. */
  .nav-label-full { display: none; }
  .nav-label-short { display: inline; }

  /* Site footer: stack */
  .site-footer {
    flex-direction: column;
    gap: 0.5rem;
    text-align: center;
    padding: 2rem 1rem;
  }

  /* Illustration bands: shorter on mobile */
  .illustration-band img { max-height: 160px; }

  /* ---- Hero art + proof cards: de-emphasize on mobile ----
     Reported: "hero section image takes too much space and breaks
     the flow"; "sample tiles make the landing too crowded... keep
     as a small thumbnail instead". At ≤1199px the three proof cards
     already leave absolute positioning and stack full-width under
     the hero illustration (see the ≤1199 block above) - each one
     still rendered at full detail (avatar photo, sub-label, progress
     bar), so three stacked full-size cards plus a tall illustration
     added well over 900px of scroll before any real content. Two
     changes: cap the illustration's height so it reads as a supporting
     visual instead of the dominant element, and shrink the three
     proof cards into a single compact row of small thumbnail chips -
     icon/eyebrow only, detail rows (avatar, sub-label, progress bar)
     hidden - rather than three full-detail cards stacked vertically.

     object-position was "top center" (2026-08-20 first pass) on the
     assumption that "top" would keep the face in frame - wrong on
     this specific asset: the source PNG (1116x1024) has ~19% of pure
     empty background above the illustration's head before any of her
     hair/face starts, so cropping from the image's literal top edge
     mostly showed that empty space plus a sliver of her hair, cutting
     off her face, hands, and the tablet entirely below the 200px
     window - reported back as "a floating head, not well placed."
     "center 35%" (not the default 50%) is calibrated against this
     specific image's content distribution (checked directly): it
     skips past the empty top margin and centers the crop on the
     head-through-tablet region instead. If this image is ever
     replaced, re-check this value against the new asset - it's
     tuned to where the subject sits in *this* PNG, not a generic
     safe default. */
  .hero-art-wrap .hero-img {
    max-height: 200px;
    object-fit: cover;
    object-position: center 35%;
    border-radius: var(--radius-lg);
  }
  /* .hero-proof-row (not .hero-art-wrap itself): .hero-art-wrap's
     direct children are the <img> AND the three cards side by side
     (see index.html), so flexing it directly pulled the image into
     the same row as the cards instead of stacking above them. The
     cards are wrapped in their own .hero-proof-row for exactly this
     reason - confirmed via bounding-box measurement that without it,
     the image ate most of the row and squeezed the three cards into
     ~10px slivers. */
  .hero-proof-row {
    display: flex;
    gap: .35rem;
    margin-top: .5rem;
  }
  .hero-proof-card {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    margin-top: 0;
    padding: .55rem .35rem;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }
  /* white-space: normal (not nowrap) - at ~110px per card, "Verified
     expert"/"Cited & current" need to wrap onto two lines rather than
     forcing the card wider than its flex share, which was overflowing
     the viewport (confirmed via Playwright bounding-box scan). */
  .hero-proof-card .pill { font-size: .55rem !important; padding: .25rem .4rem; white-space: normal; line-height: 1.2; }

  /* Each of the three cards has a different internal structure (see
     index.html), so the "keep just the headline, drop the detail
     row" trim is written per card rather than one generic selector:
     --expert's detail is a sibling <div> after the pill; --flow has
     no wrapping pill at all (its first .hero-flow-row *is* the
     headline); --progress's pill is nested one level inside its
     first <div> alongside the "35%" figure. !important throughout
     this trim: every element being hidden also carries its own
     inline style="..." (margin-top, display:flex, etc. - see
     index.html), which otherwise beats a plain class selector
     regardless of specificity or source order. */
  .hero-proof-card--expert > div { display: none !important; }

  /* align-items: stretch overrides the base card's align-items:center
     (inherited, now the cross-axis since flex-direction flips to
     column here) - centered items size to their own fit-content width
     and never wrap, which was pushing "Source document" past the
     card's edge instead of wrapping within it. */
  .hero-proof-card--flow { flex-direction: column; align-items: stretch; }
  .hero-proof-card--flow .hero-flow-arrow,
  .hero-proof-card--flow .hero-flow-row:last-child { display: none !important; }
  .hero-proof-card--flow .hero-flow-row {
    font-size: .65rem;
    justify-content: center;
  }

  .hero-proof-card--progress > div:not(:first-child) { display: none !important; }
  .hero-proof-card--progress > div:first-child span[style*="font-weight:700"] { display: none !important; }

  /* ---- "Choose your depth" selector: compact, stays in one row ----
     Reported: "should be much more compact, takes too much space,
     and the three options should be in a single row." The site-wide
     .grid.grid-cols-3 rule further up forces a single stacked column
     on mobile - right for content grids, wrong for this specific
     3-option control. A more specific selector (#depth-grid) restores
     the row and shrinks padding/type so all three still fit at
     320-390px; the "Only the Deep track..." note below it is
     tightened the same way so the whole control reads as one compact
     block instead of the tallest thing on the page. */
  #depth-grid {
    grid-template-columns: repeat(3, 1fr) !important;
    gap: .4rem !important;
  }
  #depth-grid button { padding: .65rem .55rem; }
  #depth-grid .font-semibold { font-size: .7rem !important; flex-wrap: wrap; }
  #depth-grid .text-xs { font-size: .62rem !important; line-height: 1.3; }
  #depth-grid .pill { font-size: .55rem !important; padding: .1rem .3rem !important; }

  /* Depth selector frame itself + the certification note below it:
     tighter padding/type than desktop, matching the "as compact as
     possible" ask for the pink note box specifically - but not
     zero-padding tight (see 2026-08-20 follow-up: "zero breathing
     room between titles and boxes and edges" - the first pass on
     this went too far). */
  .bg-mint-soft.border-mint.frame,
  div[class*="frame p-5 bg-mint-soft"] { padding: 1.1rem 1.15rem !important; }

  /* ---- Right-column panel type scale: compact ----
     Reported: "Course overview should be more compact in font -
     takes too much space." Applies to all four collapsible panels
     (Course overview, Features, Sources, Version history), open or
     collapsed. */
  .collapsible-panel { padding: 1rem 1.1rem !important; }
  .collapsible-toggle h4 { font-size: .8rem !important; }
  .collapsible-body { font-size: .78rem; }
  .collapsible-body p,
  .collapsible-body li { font-size: .78rem !important; line-height: 1.45; }

  /* ---- Course-detail page title/subtitle: less stretched ----
     Reported (applies site-wide, called out again here): "text below
     title too stretched, not compact enough." The h1 already scales
     down via .heading-* rules; this targets the specific 5xl course
     title (a literal Tailwind class on <h1 id="course-title">, not
     one of the owned .heading-* classes) and the creator-line row
     beneath it, which otherwise stayed at desktop's wide gap/type. */
  #course-title.text-5xl { font-size: 1.75rem !important; line-height: 1.25 !important; }
  #creator-line { font-size: .78rem; gap: .5rem !important; margin-top: .6rem !important; }

  /* ---- More breathing room between titles and the box right below
     them ----
     Reported (2026-08-20 follow-up): "zero breathing room between
     titles and boxes and edges" - several of the gaps above were
     compacted enough in the first mobile pass that they read as
     cramped rather than tidy. These three are plain Tailwind margin
     utilities in the page markup (`mt-3`, `mt-3`), too small once
     everything else on the page also got tighter. */
  #module-card { margin-top: 1rem !important; }
  #module-list { margin-top: 1rem !important; }

  /* Tailwind grid utilities: force single column on mobile.
     Targets the most common multi-column layouts across
     landing, catalogue, course-overview, dashboard, creator,
     and module pages. */
  .grid.grid-cols-2,
  .grid.grid-cols-3,
  .grid.grid-cols-4 {
    grid-template-columns: 1fr !important;
  }

  /* Tailwind col-span-2 (used as half of 3-col grids): full width */
  .col-span-2 { grid-column: span 1 / span 1 !important; }

  /* Tailwind big gaps: reduce */
  .gap-16 { gap: 1.5rem !important; }
  .gap-12 { gap: 1.5rem !important; }
  .gap-10 { gap: 1.25rem !important; }
  .gap-8  { gap: 1rem    !important; }
  .gap-7  { gap: 1rem    !important; }

  /* Custom CSS grids (e.g., module page sidebar + content,
     written inline as grid-template-columns: 220px 1fr or
     240px 1fr): stack on mobile. The attribute-selector
     match covers all inline grid definitions. */
  [style*="grid-template-columns: 240px"],
  [style*="grid-template-columns:240px"],
  [style*="grid-template-columns: 220px"],
  [style*="grid-template-columns:220px"] {
    grid-template-columns: 1fr !important;
  }

  /* Grid item blowout guard: forcing grid-template-columns to 1fr above
     is not enough on its own. Grid items default to min-width:auto, so a
     1fr track still can't shrink below its item's min-content width - if
     any child inside (e.g. the module page's <article> lesson content)
     has an unwrappable min-content wider than the viewport, the single
     column (and the whole page) still blows out horizontally. This
     mirrors the same fix already applied to .course-card. Confirmed via
     Playwright measurement: without this, the module page's sidebar+
     content grid rendered its article at ~1287px wide inside a 390px
     viewport. See project memory "overtly-site-rebrand-2026-08". */
  .grid.grid-cols-2 > *,
  .grid.grid-cols-3 > *,
  .grid.grid-cols-4 > *,
  [style*="grid-template-columns: 240px"] > *,
  [style*="grid-template-columns:240px"] > *,
  [style*="grid-template-columns: 220px"] > *,
  [style*="grid-template-columns:220px"] > * {
    min-width: 0;
  }

  /* Sticky module-page sidebar: unstick the aside itself on mobile (the
     "back to course" link + module title/duration card scroll away
     normally with the page) - only #lesson-list below gets its own
     sticky treatment, turned into a horizontal jump bar. */
  aside[style*="sticky"],
  aside[style*="position: sticky"] {
    position: static !important;
    top: auto !important;
  }

  /* Tailwind arbitrary-value classes that fight narrow viewports */
  .min-w-\[280px\] { min-width: 0 !important; flex-basis: 100%; }

  /* Discover page search + filter toolbar: the search box and filter
     pills were reported colliding/overlapping on mobile. Rather than
     leaning on overriding a Tailwind-CDN-generated arbitrary-value class
     (fragile: depends on the CDN's runtime JIT output matching this
     selector exactly), these ids are owned CSS so the stacking behavior
     doesn't depend on that match. Stack unconditionally on mobile: search
     full-width on its own row, filter pills wrap onto their own row(s)
     below rather than fighting for space on one line. See project memory
     "overtly-site-rebrand-2026-08". */
  #discover-toolbar { flex-direction: column; align-items: stretch; }
  #search-frame { width: 100%; min-width: 0; flex: 1 1 auto; }
  #filter-row { width: 100%; flex-wrap: wrap; }

  /* Frame and course-card padding: tighter */
  .frame { padding-left: 1rem; padding-right: 1rem; }
  .course-card {
    padding: 1rem;
    /* Grid items default to min-width:auto, which lets long unbreakable
       content (e.g. a long tag pill next to the Enroll button in a
       non-wrapping row) force the card wider than its 1fr track,
       overflowing the viewport ("grid blowout"). Without this, cards on
       narrow phones (~320-360px) pushed the whole page into horizontal
       scroll. */
    min-width: 0;
  }
  /* Course-card description: clamp to 4 lines.
     Reported: "WASH summary too long - keep it more compact, 4 lines
     top." Some course descriptions run to 5-6 lines on a narrow
     card; -webkit-line-clamp (supported in every mobile browser that
     matters here) truncates with an ellipsis instead of letting the
     card grow to fit the longest description in the catalogue. */
  .course-card-desc {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* Lesson body typography: scale */
  .lesson-h2 { font-size: 1.35rem; }
  .lesson-p  { font-size: 0.95rem; }

  /* Lesson sidebar -> mobile jump bar. On desktop the aside's
     #lesson-list is a normal sticky vertical sidebar and this whole
     block does nothing. On mobile the aside was being fully unstuck
     (rule above), which meant #lesson-list scrolled away with the page
     like everything else: once you were a screen or two into a module
     there was no way to jump to another section short of scrolling all
     the way back up - reported as "just one long page, no sense of
     structure." Fixed by reshaping #lesson-list into a compact
     horizontal, swipeable strip of section chips pinned under the
     header, instead of leaving the whole vertical sidebar either fully
     visible (too tall, would eat most of the viewport) or fully gone.
     Reuses the exact same markup/ids/hrefs as the desktop sidebar and
     the existing per-page IntersectionObserver that toggles .current as
     you scroll - no HTML or JS changes needed, this is a pure CSS
     reshape.

     position:fixed, not sticky: #lesson-list's DOM parent is <aside>,
     which on mobile only contains the "back to course" link + the
     module-card (~150-200px total) - much shorter than the page. A
     position:sticky element can only remain stuck while its own parent's
     box is still on screen; once that short <aside> scrolls past, the
     "sticky" bar unsticks and scrolls away with it, same as if it had no
     sticky rule at all (confirmed via Playwright: bar's top tracked
     scrollY 1:1 instead of holding at 75px). position:fixed is anchored
     to the viewport directly and has no such containing-block limit, so
     it stays pinned for the entire page. Fixed removes it from layout
     flow, so #module-card below gets a mobile-only margin-bottom (see
     below) to reserve the room it used to occupy, keeping the "back to
     course" link + module card from rendering underneath the bar on
     initial load. See project memory "overtly-site-rebrand-2026-08". */
  #lesson-list {
    position: fixed;
    top: 75px; /* mobile .site-header rendered height */
    left: 0;
    right: 0;
    /* The element also carries Tailwind's .mt-4 (margin-top: 1rem) from
       the desktop markup. For a fixed box that margin still adds to the
       "top" offset (border-box top = top + margin-top), which pushed the
       bar 16px lower than intended - override it to 0 here. */
    margin-top: 0;
    z-index: 30;
    background: var(--ivory);
    border-bottom: 1px solid var(--line);
    padding: 0.55rem 1rem;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    gap: 0.5rem;
  }
  /* Reserve the vertical space #lesson-list used to occupy in normal
     flow now that it's position:fixed (see comment above). The fixed
     bar covers y:75px-126px on screen; without this, aside's first two
     children ("back to course" link, then #module-card) render starting
     right at the top of the page (~y:75px) and are hidden underneath
     it. padding-top on aside pushes both down below the bar together.
     Scoped with :has(#lesson-list) rather than a blanket `aside` rule -
     other pages (e.g. the creator profile page) also use a plain
     <aside> for an unrelated sidebar with no fixed bar above it, and
     would get an unwanted empty gap if this applied there too. */
  aside:has(#lesson-list) { padding-top: 4.6rem; }
  /* ---- Lesson nav bar: full boxes, not pills; current section
     painted solid green; scroll affordance ----
     Reported: "module scroll should not be pills, but full boxes,
     painting in green the scrolled section, and an arrows signaling
     it can be scrolled sideways." This bar already exists (built for
     the Aug 13 mobile pass as a horizontal, swipeable jump strip -
     see the fixed-position block above) - what's changing here is
     its visual style, not the underlying scroll/jump mechanic. */
  .lesson-list .lesson-item {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 0.65rem 0.95rem;
    font-size: 0.75rem;
    background: white;
    border: 1px solid var(--line);
    /* radius-sm (12px) reads as a pill at this chip height - a
       smaller radius keeps a touch of softness (matching the rest of
       the brand system's rounded-corner language) while still
       reading as a "box" rather than a capsule. */
    border-radius: 6px;
  }
  /* Current section: solid evergreen fill (not the pale mint-soft
     tint used elsewhere for "selected" states) so it's unambiguous
     which box you're in while scrolling, at a glance and without
     stopping to read. */
  #lesson-list .lesson-item.current {
    background: var(--evergreen);
    border-color: var(--evergreen);
    color: white;
  }
  /* Duration ("12m") is useful in the full vertical sidebar but just
     clutters a compact chip - hide it there specifically, not text-xs
     generally (that class is used all over these pages for citations,
     timestamps, etc. and must stay untouched). */
  #lesson-list .lesson-item > span:last-child { display: none; }

  /* Scroll-sideways affordance: a fixed (viewport-anchored, not
     scroll-anchored) chevron + fade at the bar's trailing edge, so it
     reads as "more to scroll" rather than "that's the whole list."
     position:fixed on the pseudo-element (not absolute) is what keeps
     it pinned to the screen edge instead of scrolling away with
     #lesson-list's own horizontally-scrolling content - an absolutely
     positioned pseudo-element would still be part of that scrollable
     region and drift off with the rest of the chips. Leading-edge
     arrow is intentionally omitted: once you've scrolled right at
     all, the leading chips being cut off already signals "more this
     way," and this keeps the bar from needing JS to track scroll
     position and show/hide either arrow. */
  #lesson-list::after {
    content: '\203A';
    position: fixed;
    top: 75px;
    right: 0;
    bottom: auto;
    height: 62px;
    width: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--evergreen);
    background: linear-gradient(to right, transparent, var(--ivory) 60%);
    pointer-events: none;
    z-index: 31;
  }

  /* The lesson jump bar is now sticky at ~120px (header + bar), so a
     jumped-to section needs more top clearance than the site-wide
     80px default (set for the header alone) or its heading would land
     partly hidden underneath the bar. */
  :target { scroll-margin-top: 140px; }

  /* Pills: smaller */
  .pill { font-size: 0.65rem; padding: 0.2rem 0.5rem; }

  /* Buttons: scale */
  .btn { padding: 0.55rem 0.85rem; font-size: 0.85rem; }

  /* Quiz: tighten option padding/typography */
  .quiz-card { padding: 1rem; }
  .quiz-option { padding: 0.6rem 0.75rem; font-size: 0.85rem; }
  .quiz-progress { font-size: 0.65rem; }

  /* Slide player: tighten internal padding and typography
     so the slide content fits in a 16/9 frame on a 343px
     content width. Targets the .slide-content class directly
     rather than "> div" so it can't accidentally catch the
     motion-pilot's background/motif/stat layers, which are
     also direct children of .slide-player-bg. */
  .slide-content {
    padding: 18px 18px 60px !important;
  }
  .slide-player-motion .slide-stat-num { font-size: 2.75rem !important; }
  .slide-heading {
    font-size: 1.25rem !important;
    line-height: 1.2 !important;
  }
  .slide-caption {
    font-size: 0.75rem !important;
    margin-top: 0.4rem !important;
  }
  .slide-num {
    font-size: 0.65rem !important;
  }
  .slide-cc {
    font-size: 0.7rem !important;
    padding: 0.35rem 0.6rem !important;
    left: 12px !important;
    right: 12px !important;
    bottom: 52px !important;
    line-height: 1.35 !important;
  }
  .slide-controls {
    padding: 0.4rem 0.55rem !important;
    gap: 0.4rem !important;
    font-size: 0.65rem !important;
  }
  .slide-controls .speed-sel {
    font-size: 0.6rem !important;
    padding: 0.1rem 0.2rem !important;
  }
  .slide-controls .time {
    font-size: 0.6rem !important;
  }
  .play-overlay {
    width: 52px !important;
    height: 52px !important;
  }
  .play-overlay-icon {
    font-size: 1.2rem !important;
  }

  /* Hero video frame inside module page: ensure it still hits
     16/9 even with reduced parent padding. */
  #video-frame {
    margin-left: 0 !important;
    margin-right: 0 !important;
  }
}

@media (max-width: 479px) {
  .heading-xl { font-size: 2rem    !important; }
  .heading-lg { font-size: 1.5rem  !important; }
  /* Horizontal-only, same reasoning as the ≤767px rule above. */
  .container-x, .container-narrow { padding-left: 1.1rem; padding-right: 1.1rem; }
  .site-header { padding: 0.45rem 0.6rem; gap: 0.3rem; }
  .site-header .logo img { height: 14px !important; }
  .site-header .header-nav { gap: 0.02rem; }
  .site-header .header-nav a { font-size: 0.68rem; padding: 0.28rem 0.32rem; gap: 0; }
  .site-header .learner-avatar { width: 20px; height: 20px; font-size: 0.6rem; margin-left: 0.15rem; }
  .lesson-h2 { font-size: 1.2rem; }
  .lesson-p  { font-size: 0.9rem; }
  .slide-heading { font-size: 1.05rem !important; }
  .slide-caption { font-size: 0.7rem !important; }
}

/* ============================================================
   Learner session: header auth area and the course enroll card
   (added with learner accounts, Sep 2026)
   ============================================================ */
.header-auth { display: inline-flex; align-items: center; gap: .5rem; }
.header-auth .nav-signin {
  font-size: .8rem; font-weight: 600; color: var(--body-gray);
  padding: .4rem .6rem; border-radius: var(--radius-sm); text-decoration: none;
}
.header-auth .nav-signin:hover { background: var(--bg-soft); color: var(--ink); }
/* Specificity deliberate: this sits inside .header-nav, whose own
   a-rules would otherwise win and repaint the one primary action. */
.site-header .header-nav .header-auth .nav-start {
  font-size: .8rem; font-weight: 700; padding: .45rem .8rem;
  background: var(--evergreen); color: #fff; border-radius: var(--radius-sm); text-decoration: none;
}
.site-header .header-nav .header-auth .nav-start:hover { background: var(--evergreen-deep); color: #fff; }
.header-auth .learner-link {
  display: inline-flex; align-items: center; gap: .45rem;
  text-decoration: none; color: var(--ink); font-weight: 600; font-size: .85rem;
}
.header-auth .nav-signout {
  font: inherit; font-size: .78rem; font-weight: 600; color: var(--muted);
  background: none; border: 0; cursor: pointer; padding: .35rem .5rem; border-radius: var(--radius-sm);
}
.header-auth .nav-signout:hover { background: var(--bg-soft); color: var(--ink); }
.header-auth .nav-signout:disabled { opacity: .6; cursor: progress; }

.enroll-card { background: var(--mint-soft); border-color: var(--mint); }
.enroll-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.enroll-title { font-weight: 700; color: var(--ink); }
.enroll-sub { font-size: .8rem; color: var(--body-gray); margin-top: .15rem; }
.enroll-error { font-size: .8rem; font-weight: 600; color: var(--coral-ink); margin-top: .5rem; }
@media (max-width: 479px) {
  /* Specificity has to clear ".site-header .header-nav a", which otherwise
     keeps the sign-in link visible and the button at desktop size, and the
     header then scrolls sideways on a phone. */
  .site-header .header-nav .header-auth .nav-signin { display: none; }
  .site-header .header-nav .header-auth .nav-start { padding: .4rem .6rem; font-size: .72rem; white-space: nowrap; }
  .site-header .header-nav a.nav-creator { margin-left: .55rem; padding: .4rem .6rem; }
  .site-header .header-nav a.nav-creator::before { left: -.35rem; height: 16px; }
  .enroll-row .btn { width: 100%; }
}
.module-complete-card { background: var(--mint-soft); border-color: var(--mint); }

/* Coming soon: a listed course whose page is not built yet. The card keeps
   its place in the catalogue but is not a link and does not invite a click. */
.pill-soon { background: var(--bg-soft); border: 1px solid var(--line); color: var(--muted); }
.course-card-soon { cursor: default; }
.course-card-soon:hover { border-color: var(--line); box-shadow: none; }


/* ============================================================
   Hero word flip. See claude/overtly-language-standard.md.
   Runs once on first load, never loops. Three rules that are not
   optional: the word and its comma live in one no-wrap span so
   the line never breaks before the comma; widths are measured
   after document.fonts.ready or the word clips; the landing mark
   sits outside the animation mask so it cannot clip a descender.
   ============================================================ */
.ovt-headline { line-height: 1.25; word-break: normal; overflow-wrap: normal; }
.ovt-headline .nb { white-space: nowrap; }

.ovt-headline .rotwrap {
  position: relative;
  display: inline-block;
  vertical-align: top;
  height: 1.25em;
  transition: width 300ms cubic-bezier(.22,.61,.36,1);
}
.ovt-headline .rotwrap.nomotion { transition: none; }

.ovt-headline .rot {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
  z-index: 1;
}
.ovt-headline .rot span {
  position: absolute; left: 0; top: 0;
  display: block;
  line-height: 1.25em;
  white-space: nowrap;
  color: var(--evergreen);
  will-change: transform, opacity;
  transition: transform var(--ovt-dur, 430ms) cubic-bezier(.22,.61,.36,1),
              opacity   var(--ovt-dur, 430ms) ease,
              color     var(--ovt-dur, 430ms) ease;
}
.ovt-headline .rot span.enter { transform: translateY(102%); opacity: 0; }
.ovt-headline .rot span.here  { transform: translateY(0);     opacity: 1; }
.ovt-headline .rot span.leave { transform: translateY(-102%); opacity: 0; }

.ovt-headline .ovt-hl {
  position: absolute;
  left: -.07em; right: -.07em; top: .14em; bottom: .12em;
  background: var(--mint-soft);
  border-radius: 8px;
  z-index: 0;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 460ms cubic-bezier(.22,.61,.36,1);
}
.ovt-headline .ovt-hl.on { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  .ovt-headline .rotwrap,
  .ovt-headline .rot span,
  .ovt-headline .ovt-hl { transition: none !important; }
}

/* ---- review statement and sensitive-topic notice (course and module pages) ---- */
.ovt-review { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); display: grid; gap: 10px; }
.ovt-review-statement { font-size: 13px; line-height: 1.5; font-weight: 600; color: var(--evergreen); }
/* The composed line for a course with sanitized cases. Quieter than the
   review sentence: it is a fact about the cases, not a claim about the check. */
.ovt-case-notice { font-size: 13px; line-height: 1.5; color: var(--body-gray); margin-top: 6px; }
.ovt-sensitive-notice { font-size: 13px; line-height: 1.55; color: var(--ink); background: var(--coral-soft); border-left: 3px solid var(--coral); border-radius: 8px; padding: 10px 12px; }
.lesson-section .ovt-sensitive-notice { margin-top: 12px; }

/* -------- Exhibits (lesson visuals) --------
   Drawn from the exhibit's own data rather than shipped as an image, so the
   numbers stay selectable and checkable, the type scales with the page, and
   every form collapses to one card per row on a phone. */
.exhibits { margin-top: 1.5rem; }
.exhibit { margin: 1.5rem 0 0; padding: 1.15rem 1.25rem; background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.exhibit-title { font-size: .95rem; font-weight: 700; color: var(--ink); line-height: 1.4; margin-bottom: .9rem; }
.exhibit-alt { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.exhibit-caption { margin-top: .85rem; font-size: .78rem; line-height: 1.5; color: var(--body-gray); }
.exhibit-source { margin-top: .35rem; font-size: .72rem; line-height: 1.5; color: var(--muted); }
/* The inline [1] [6] markers in lesson prose. Was var(--coral) at 2.36:1
   on ivory and 2.16:1 on the soft panel, 69 failing instances on a single
   Blind Spots lesson page and every one of them a citation. */
.exhibit-markers { color: var(--coral-ink); font-weight: 700; font-size: .72em; white-space: nowrap; }
/* The superscript citation marker app.js inserts for every [n] in a lesson
   body. It used to carry its colour in an inline style, which no
   stylesheet can override, so it survived the first pass at this fix. The
   inline style is gone and the styling lives here. */
/* Deep Evergreen, not Coral Ink.
   Changed 29 September 2026. A module page carries up to 58 of these. In
   Coral Ink the page read as annotated with problems, because red means
   WRONG everywhere else in this product: the quiz feedback, the form error
   line, the "tested and failed" grade. A citation is a reference, not a
   fault. Deep Evergreen is 10.54:1 on paper and reads as a link to the
   source list rather than a correction. */
.cite-marker { color: var(--evergreen); font-weight: 700; margin-left: 1px; }

/* Bars: chart and comparison */
/* One grid for the whole chart, not one per row.
   CORRECTED 29 September 2026. The track and the value used to be flex
   siblings inside each row, so a value label that needed more room
   flex-shrank its own bar. Only the bars that overflowed shrank, and the
   bar that overflows is always the longest one, so every chart quietly
   compressed its own maximum: the live m1 exhibit drew 1.24 against 1.96,
   a ratio of 0.63, as 437px against 580px, a ratio of 0.75.

   Putting the grid on the container rather than the row gives every bar
   the same measure, because the `max-content` value column is sized once
   across all rows. That is the only arrangement in which two bars in one
   chart are comparable, and it lines the values up as a side effect. */
.exhibit-bars { display: grid; grid-template-columns: minmax(0, 1fr) max-content;
  column-gap: .5rem; align-items: center; }
.exhibit-bar-label { grid-column: 1 / -1; font-size: .8rem; color: var(--body-gray);
  margin: .5rem 0 .3rem; }
.exhibit-bars > .exhibit-bar-label:first-child { margin-top: 0; }
.exhibit-bar-track { position: relative; min-width: 0; }
.exhibit-bar-fill { height: 1.15rem; background: var(--evergreen-deep); border-radius: 3px; min-width: 2px; }
.exhibit-bar-value { font-size: .82rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
/* A fact is a row of the same exhibit that has no number to draw, so it
   spans both columns and keeps its own label-and-value split. */
.exhibit-fact { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 1rem; padding: .4rem 0; margin-top: .8rem; border-top: 1px solid var(--line); font-size: .8rem; }
.exhibit-fact-label { color: var(--body-gray); }
.exhibit-fact-value { color: var(--ink); font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }

/* Table */
.exhibit-table-wrap { overflow-x: auto; }
.exhibit-table { width: 100%; border-collapse: collapse; font-size: .8rem; }
.exhibit-table th { text-align: left; padding: .5rem .6rem; border-bottom: 2px solid var(--line); color: var(--muted); font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; }
.exhibit-table td { padding: .55rem .6rem; border-bottom: 1px solid var(--line); color: var(--body-gray); vertical-align: top; line-height: 1.5; }
.exhibit-table td:first-child { color: var(--ink); font-weight: 600; }

/* Matrix */
.exhibit-matrix { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.exhibit-matrix-heading { font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; color: var(--evergreen); font-weight: 700; margin-bottom: .5rem; }

/* Evidence grades.
   Added 29 September 2026. A matrix row carries a `grade`, and the four
   grades are a course-wide vocabulary the content declares in its own
   opening lesson: tested and works, tested and mixed, tested and failed,
   untested. The renderer already grouped by that field; it drew all four
   groups identically, so "tested and works" and "tested and failed"
   looked the same until you read the heading.

   The tone comes from the field, never from the position in the list and
   never assigned by hand. That is the test decisions 255 and 256 set: a
   colour that encodes nothing is worse than no colour, because a reader
   who works out that it means nothing has learned to ignore the loudest
   channel on the page. Here it means something the data already knows.

   Colour is never the only cue: the grade is written out as the group's
   heading above every card, and the heading is what a screen reader and
   a monochrome printout get. An unrecognised grade takes no tone at all
   rather than a guess, and tools/build-module-content.mjs fails the
   build on one, so an unknown grade is caught before it is rendered.

   Every pairing is ink on a brand tint, all asserted in
   check-design-tokens: mint 8.47, pale yolk 10.69, pale coral 10.02. */
.exhibit-matrix--grades { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.exhibit-grade { border-radius: var(--radius-sm); padding: .55rem .7rem .1rem; }
.exhibit-grade .exhibit-matrix-heading { color: var(--ink); }
.exhibit-grade .exhibit-card { background: rgb(255 255 255 / 0.62); }
.exhibit-grade--works  { background: var(--ov-mint); }
.exhibit-grade--mixed  { background: var(--ov-yolk-pale); }
.exhibit-grade--failed { background: var(--ov-coral-pale); }
/* Untested is the absence of a grade, so it is drawn as the absence of a
   tone: a bordered group rather than a fifth colour. */
.exhibit-grade--untested { background: transparent; border: 1px solid var(--ov-divider); }
.exhibit-grade--untested .exhibit-card { background: var(--bg-soft); }
.exhibit-card { padding: .65rem .75rem; background: var(--bg-soft); border-radius: var(--radius-sm); margin-bottom: .6rem; }
.exhibit-card-title { font-size: .82rem; font-weight: 700; color: var(--ink); line-height: 1.35; }
.exhibit-card-line { margin-top: .3rem; font-size: .75rem; line-height: 1.45; color: var(--body-gray); }
.exhibit-card-key { text-transform: uppercase; letter-spacing: .05em; font-size: .62rem; color: var(--muted); font-weight: 700; display: block; }

/* -------- Takeaways (the exportable tool) -------- */
.takeaways { margin-top: 1.5rem; }
.takeaway { padding: 1.15rem 1.25rem; background: var(--mint-soft); border: 1px solid var(--mint); border-radius: var(--radius-sm); }
.takeaway + .takeaway { margin-top: 1rem; }
.takeaway-head { display: flex; justify-content: space-between; align-items: center; gap: .5rem; }
.takeaway-label { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--evergreen); font-weight: 700; }
.takeaway-version { font-size: .68rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.takeaway-name { margin-top: .4rem; font-size: 1rem; font-weight: 700; color: var(--ink); }
.takeaway-summary { margin-top: .3rem; font-size: .85rem; line-height: 1.55; color: var(--ink); }
.takeaway-files { margin-top: .75rem; display: flex; flex-wrap: wrap; gap: .5rem; }
.takeaway-file { display: inline-flex; align-items: baseline; gap: .4rem; padding: .4rem .7rem; background: #fff; border: 1px solid var(--mint); border-radius: var(--radius-sm); font-size: .78rem; font-weight: 600; color: var(--evergreen); text-decoration: none; }
.takeaway-file:hover { background: var(--mint); color: var(--evergreen); }
.takeaway-size { font-size: .68rem; color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.takeaway-disclaimer { margin-top: .6rem; font-size: .75rem; line-height: 1.5; color: var(--coral-ink); }
.takeaway-meta { margin-top: .8rem; display: grid; grid-template-columns: auto 1fr; gap: .2rem .7rem; font-size: .73rem; line-height: 1.5; }
.takeaway-meta dt { text-transform: uppercase; letter-spacing: .05em; font-size: .62rem; color: var(--muted); font-weight: 700; padding-top: .15rem; }
.takeaway-meta dd { color: var(--body-gray); }

@media (max-width: 640px) {
  .exhibit { padding: 1rem; }
  .exhibit-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .exhibit-table, .exhibit-table tbody, .exhibit-table tr, .exhibit-table td { display: block; width: 100%; }
  .exhibit-table tr { padding: .6rem 0; border-bottom: 1px solid var(--line); }
  .exhibit-table td { border: 0; padding: .2rem 0; }
  .exhibit-table td::before { content: attr(data-label); display: block; text-transform: uppercase; letter-spacing: .05em; font-size: .62rem; color: var(--muted); font-weight: 700; }
  .exhibit-matrix { grid-template-columns: 1fr; }
  .takeaway-meta { grid-template-columns: 1fr; gap: .1rem; }
  .takeaway-meta dd { margin-bottom: .45rem; }
}
.exhibit-none { color: var(--muted); font-style: italic; }
.exhibit-note { margin-top: .6rem; font-size: .75rem; line-height: 1.5; color: var(--body-gray); }

/* ============================================================
   Apply it exercise (module assessment)
   Short courses end each content module with one hands-on exercise
   instead of a multiple-choice quiz. Rendered by Overtly.renderExercise
   into the module page's #quiz slot.
   ============================================================ */

.ovt-ex [hidden] { display: none !important; }
.ovt-ex-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.ovt-ex-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--coral-ink); margin: 0 0 2px; }
.ovt-ex-count { font-size: 13px; color: var(--muted); white-space: nowrap; margin: 0; font-variant-numeric: tabular-nums; }
.ovt-ex-objective { margin: 10px 0 0; font-size: 14px; color: var(--body-gray); max-width: 62ch; }
.ovt-ex-bar { height: 5px; border-radius: 999px; background: var(--bg-soft); overflow: hidden; margin: 14px 0 0; }
.ovt-ex-bar i { display: block; height: 100%; background: var(--evergreen-deep); border-radius: 999px; transition: width .2s ease; }
.ovt-ex-intro { margin-top: 14px; font-size: 14px; line-height: 1.6; }
.ovt-ex-intro p { margin: 0 0 8px; }

.ovt-ex-steps { list-style: none; margin: 18px 0 0; padding: 0; display: flex; flex-direction: column; gap: 18px; }
.ovt-ex-step { border-top: 1px solid var(--line); padding-top: 16px; }
.ovt-ex-step[data-state="done"] { opacity: .92; }
.ovt-ex-stepnum { font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); margin: 0 0 6px; }
.ovt-ex-prompt { font-size: 15.5px; font-weight: 600; color: var(--ink); line-height: 1.45; margin: 0; }
.ovt-ex-marker { font-size: 10px; font-weight: 600; color: var(--evergreen-deep); vertical-align: super; }
.ovt-ex-controls { margin-top: 12px; }

.ovt-ex-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.ovt-ex-item { background: var(--bg-soft); border-radius: 12px; padding: 12px 14px; }
.ovt-ex-excerpt { margin: 0 0 10px; font-size: 14px; line-height: 1.55; color: var(--ink); }

.ovt-ex-choices { border: 0; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.ovt-ex-choices-stack { flex-direction: column; }
.ovt-ex-pick { display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--line); background: white; border-radius: 999px; padding: 7px 13px; font-size: 13.5px; color: var(--ink); cursor: pointer; }
.ovt-ex-pick-wide { border-radius: 12px; align-items: flex-start; line-height: 1.45; }
.ovt-ex-pick input { accent-color: var(--evergreen-deep); margin: 0; flex: none; }
.ovt-ex-pick:hover { border-color: var(--mint-accent); }
.ovt-ex-pick:focus-within { outline: 2px solid var(--mint-accent); outline-offset: 2px; }
.ovt-ex-pick:has(input:checked) { border-color: var(--evergreen-deep); background: var(--mint-soft); font-weight: 600; }
.ovt-ex-pick:has(input:disabled) { cursor: default; opacity: .85; }

.ovt-ex-field { display: flex; flex-direction: column; gap: 6px; max-width: 320px; }
.ovt-ex-field label { font-size: 13px; color: var(--muted); }
.ovt-ex-input { font: inherit; font-size: 15px; color: var(--ink); background: white; border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; font-variant-numeric: tabular-nums; }
.ovt-ex-input:focus { outline: 2px solid var(--mint-accent); outline-offset: 1px; border-color: var(--mint-accent); }
.ovt-ex-hint { font-size: 12px; color: var(--muted); margin: 0; }

.ovt-ex-actions { margin-top: 14px; display: flex; gap: 10px; flex-wrap: wrap; }
.ovt-ex-feedback { margin: 12px 0 0; font-size: 14px; line-height: 1.5; }
.ovt-ex-feedback:empty { display: none; }
.ovt-ex-feedback.is-right { color: var(--evergreen); font-weight: 600; }
.ovt-ex-feedback.is-right::before { content: "\2713  "; }
.ovt-ex-feedback.is-wrong { color: var(--coral-ink); font-weight: 600; }
.ovt-ex-feedback.is-wrong::before { content: "\2715  "; }
.ovt-ex-feedback.is-note { color: var(--muted); }

.ovt-ex-working { margin-top: 12px; background: var(--mint-soft); border-radius: 12px; padding: 12px 14px; }
.ovt-ex-working-label { font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--evergreen); margin: 0 0 6px; }
.ovt-ex-working-body { font-size: 14px; line-height: 1.6; color: var(--ink); }
.ovt-ex-working-body p { margin: 0 0 8px; }
.ovt-ex-working-body p:last-child { margin-bottom: 0; }

.ovt-ex-field-wide { max-width: none; }
.ovt-ex-text { width: 100%; min-height: 96px; line-height: 1.55; resize: vertical; font-variant-numeric: normal; }
.ovt-ex-answers { margin: 18px 0 0; border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; background: white; }
.ovt-ex-answers-title { margin: 0 0 10px; font-size: 15px; font-weight: 600; color: var(--ink); }
.ovt-ex-answers-list { margin: 0; display: flex; flex-direction: column; gap: 12px; }
.ovt-ex-answer dt { font-size: 13px; color: var(--muted); margin: 0 0 3px; }
.ovt-ex-answer dd { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }
#ovt-print-sheet { display: none; }
@media print {
  body.ovt-print-answers > *:not(#ovt-print-sheet) { display: none !important; }
  body.ovt-print-answers #ovt-print-sheet { display: block; color: #000; font-size: 12pt; line-height: 1.5; }
  #ovt-print-sheet h1 { font-size: 16pt; margin: 0 0 14pt; }
  #ovt-print-sheet h2 { font-size: 11pt; font-weight: 600; margin: 12pt 0 3pt; break-after: avoid; }
  #ovt-print-sheet p { margin: 0; white-space: pre-wrap; }
}

.ovt-ex-done { margin: 18px 0 0; padding: 12px 14px; border-radius: 12px; background: var(--evergreen); color: var(--ivory); font-weight: 600; font-size: 14.5px; }
.ovt-ex-privacy { margin: 14px 0 0; font-size: 12px; color: var(--muted); }

@media (max-width: 560px) {
  .ovt-ex-count { white-space: normal; }
  .ovt-ex-field { max-width: 100%; }
  .ovt-ex-pick { width: 100%; }
}

/* Apply it: calculator step.
   Embeds the course takeaway with the case's numbers preset. Preset fields
   are read only, the learner's fields are not, and the figures recompute as
   they type. The graded output carries the evergreen weight. */
.ovt-ex-calc { display: grid; gap: 14px; max-width: 520px; }
.ovt-ex-calc-inputs { display: grid; gap: 10px; }
.ovt-ex-calc-row { display: grid; grid-template-columns: 1fr 180px; gap: 12px; align-items: center; }
.ovt-ex-calc-row label { font-size: 13.5px; color: var(--ink); line-height: 1.35; }
.ovt-ex-calc-row .ovt-ex-unit { display: block; font-size: 12px; color: var(--muted); font-weight: 400; }
.ovt-ex-calc-row .ovt-ex-input { width: 100%; text-align: right; }
.ovt-ex-calc-row .ovt-ex-input[readonly] { background: var(--bg-soft); color: var(--muted); border-style: dashed; }
.ovt-ex-calc-outputs { margin: 0; padding: 12px 0 0; border-top: 1px solid var(--line); display: grid; gap: 8px; }
.ovt-ex-calc-out { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.ovt-ex-calc-out dt { margin: 0; font-size: 13.5px; color: var(--muted); }
.ovt-ex-calc-out dd { margin: 0; font-size: 15.5px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.ovt-ex-calc-out.is-checked dt { color: var(--ink); font-weight: 600; }
.ovt-ex-calc-out.is-checked dd { color: var(--evergreen-deep); }

/* The step is a labelled group that takes focus when the learner moves on,
   so the prompt is read before the fields. Programmatic focus stays quiet;
   a keyboard visit still shows a ring. */
.ovt-ex-step:focus { outline: none; }
.ovt-ex-step:focus-visible { outline: 2px solid var(--mint-accent); outline-offset: 4px; border-radius: 6px; }

@media (max-width: 560px) {
  .ovt-ex-calc-row { grid-template-columns: 1fr; gap: 4px; }
  .ovt-ex-calc-row .ovt-ex-input { text-align: left; }
}

/* ============================================================
   Account menu in the header, and the review badge
   (Orlando's review, 25 September 2026)
   ============================================================ */

/* Sign out used to sit at the top level beside the learner's own name, which
   gave the least frequent action in the product the same weight as the
   catalogue. It lives under the avatar now, with Account and, until creator
   accounts exist, the Creator Studio entry that was a coral call to action in
   every learner's header. */
/* The nav sets display on its anchors, which beats the browser's own rule for
   the hidden attribute, so hiding the Creator Studio link needs saying twice.
   Same trap as the exercise buttons earlier today. */
.site-header .header-nav a[hidden] { display: none !important; }

.header-auth .nav-menu { position: relative; }
.header-auth .nav-menu-btn {
  font: inherit; font-size: .85rem; font-weight: 600; color: var(--ink);
  background: none; border: 0; cursor: pointer;
  padding: .25rem .45rem .25rem .25rem; border-radius: var(--radius-pill);
}
.header-auth .nav-menu-btn:hover { background: var(--bg-soft); }
.header-auth .nav-menu-btn:focus-visible { outline: 2px solid var(--mint-accent); outline-offset: 2px; }
.nav-menu-caret { font-size: .7rem; color: var(--muted); line-height: 1; }
.nav-menu-panel {
  position: absolute; right: 0; top: calc(100% + .5rem); z-index: 50;
  min-width: 210px; padding: .4rem;
  background: white; border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: 0 12px 28px rgba(23, 59, 51, 0.12);
  display: flex; flex-direction: column;
}
.nav-menu-panel[hidden] { display: none; }
.nav-menu-email {
  font-size: .72rem; color: var(--muted); margin: 0 0 .3rem;
  padding: .4rem .6rem .5rem; border-bottom: 1px solid var(--line);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nav-menu-item {
  font: inherit; font-size: .82rem; font-weight: 500; color: var(--ink);
  text-align: left; text-decoration: none;
  background: none; border: 0; cursor: pointer;
  padding: .5rem .6rem; border-radius: var(--radius-sm);
}
.nav-menu-item:hover { background: var(--bg-soft); color: var(--ink); }
.nav-menu-item:focus-visible { outline: 2px solid var(--mint-accent); outline-offset: -2px; }
.nav-menu-signout {
  color: var(--muted); border-top: 1px solid var(--line);
  margin-top: .3rem; padding-top: .55rem;
}
.nav-menu-signout:hover { color: var(--ink); }
.nav-menu-signout:disabled { opacity: .6; cursor: progress; }

/* The review claim reads as a badge, with the composed sentence under it at a
   smaller size than the overview prose it sits inside. This deliberately
   overrides the earlier .ovt-review-statement rule. */
.ovt-review-badge { margin: 0; }
.ovt-review-statement { font-size: 12px; font-weight: 500; color: var(--body-gray); }

/* ============================================================
   Course bar, sources list, module rail and the heading scale
   (Orlando's review, 25 September 2026)
   ============================================================ */

/* One row for progress and the action. They were a full-width frame each,
   which gave the thinnest information on the page the most space. */
.course-bar { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; padding: .85rem 1.1rem !important; }
.course-bar-progress { flex: 1 1 260px; min-width: 0; }
.course-bar-progress > .flex { margin-bottom: .4rem !important; }
.course-bar .progress-bar { height: 3px; border-radius: 999px; }
/* Capped, so the enrolment copy cannot push the action onto a second row.
   The sub line wraps inside its own column instead. */
.enroll-inline { flex: 0 1 auto; max-width: 54%; min-width: 0; }
.enroll-inline .enroll-row { display: flex; align-items: center; gap: 1rem; flex-wrap: nowrap; }
.enroll-inline .enroll-row > div { flex: 1 1 auto; min-width: 0; }
.enroll-inline .enroll-row > .btn, .enroll-inline .enroll-row > a.btn { flex: 0 0 auto; }
.enroll-inline .enroll-title { font-size: .8rem; font-weight: 700; color: var(--ink); margin: 0; }
.enroll-inline .enroll-sub { font-size: .7rem; line-height: 1.35; color: var(--muted); margin: .1rem 0 0; }
.enroll-inline .btn { white-space: nowrap; }
.enroll-inline .enroll-error { font-size: .72rem; margin: .35rem 0 0; }

@media (max-width: 767px) {
  .course-bar { flex-direction: column; align-items: stretch; gap: .9rem; }
  /* flex-basis follows the main axis, so the 260px basis that sets the
     minimum WIDTH in a row became a 260px minimum HEIGHT once the bar
     stacked. Reset it. */
  .course-bar-progress { flex: 0 0 auto; }
  /* The cap is for the side-by-side row. Stacked, it would squeeze the copy
     into a narrow column and make the block taller than the two frames it
     replaced. */
  .enroll-inline { max-width: 100%; }
  /* nowrap is for the side-by-side row. On a phone the button takes its own
     line at full width rather than squeezing the copy to one word per line. */
  .enroll-inline .enroll-row { flex-wrap: wrap; gap: .7rem; }
  .enroll-inline .enroll-row > div { flex: 1 1 100%; }
  .enroll-inline .enroll-row > .btn, .enroll-inline .enroll-row > a.btn { flex: 1 1 100%; text-align: center; }
}

/* The sources panel keeps its own show-four-then-all toggle; what it lacked
   was a ceiling, so "View all 85 sources" filled the page. The list now grows
   into a scroll area instead. On a phone the cap is a share of the viewport,
   so the toggle that closes it again is always still on screen. */
#sources-list { max-height: 320px; overflow-y: auto; padding-right: .4rem; }
@media (max-width: 767px) {
  #sources-list { max-height: 50vh; }
}

/* The module progress rail. It sticks under the header so a learner can see
   where they are without scrolling back, and it carries a label, because a
   bar with no number reads as a horizontal rule. */
.ovt-rail {
  position: sticky; top: 64px; z-index: 30;
  background: var(--ivory); padding: .7rem 0 .75rem;
  border-bottom: 1px solid var(--line); margin-bottom: 1.4rem !important;
}
.ovt-rail-track { flex: 1; display: flex; align-items: center; gap: .8rem; margin-right: 1rem; }
.ovt-rail .progress-bar { height: 4px; border-radius: 999px; flex: 1; margin-right: 0 !important; }
.ovt-rail-label { font-size: .72rem; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 767px) {
  .ovt-rail { top: 56px; }
  .ovt-rail-label { font-size: .68rem; }
}

/* The heading scale on a module page.
   First pass fixed a real inversion: the module title and the lesson
   heading were both 1.75rem and the lesson was the heavier, so the child
   outranked the parent. That put roughly 1.6 between them, 40px against
   24px, which reads as a poster headline followed by a drop.

   Revised 29 September 2026 to the reference's ramp: 32, 27, and weight
   500 on both. The module title is read once and the lesson headings are
   the landmarks someone scrolling is actually looking for, so the gap
   between them should be small. 500 rather than 700 is the title weight
   already chosen from the specimen. This supersedes the sizing in backlog
   15.7, not its premise: the parent still outranks the child. */
#module-h1 { font-size: 2rem; line-height: 1.15; font-weight: 500; letter-spacing: -0.02em; }
.lesson-h2 { font-size: 1.6875rem; font-weight: 500; letter-spacing: -0.01em; line-height: 1.25; }
#module-card p, #module-card h2, #module-card h3 { font-size: 1rem; line-height: 1.3; }
@media (max-width: 767px) {
  #module-h1 { font-size: 1.75rem; }
  .lesson-h2 { font-size: 1.375rem; }
}

/* The lesson's one-line argument. Published copy, not an internal note: a
   standfirst with a rule, deliberately not a filled box, so it reads as the
   lead rather than competing with the Try it now block below it. */
.lesson-spine { margin-top: 1rem; padding-left: .9rem; border-left: 3px solid var(--evergreen); }
.lesson-spine-label { display: block; font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }
.lesson-spine-text { margin-top: .3rem; font-size: 1.0625rem; line-height: 1.5; color: var(--ink); font-weight: 500; }
@media (max-width: 480px) { .lesson-spine { padding-left: .75rem; } .lesson-spine-text { font-size: 1rem; } }

/* A .btn that is not a control: a label saying why the next step is not
   available yet. It used inline opacity: .55, which put informative text
   at 2.27:1. WCAG's exemption covers a disabled CONTROL, and this is a
   span, so the exemption does not apply and the text has to be legible.
   Full-strength muted is 5.41:1 on white; the dashed border says
   unavailable without dimming the words. */
.btn-inert { cursor: not-allowed; color: var(--muted);
  border-style: dashed; background: transparent; }

/* ============================================================
   ICONS
   Added 29 September 2026. The site used Unicode glyphs as icons: a
   watch for durations, a shaded square for documents, a speaker for the
   mute button, a black diamond for the deep callout. Whether a glyph
   renders as line art, as a colour emoji, or not at all is decided by
   the reader's operating system, and a colour emoji ignores `color`, so
   it is the one thing on the page no stylesheet reaches and no contrast
   check can measure. There is already a comment in app.js about U+2317
   falling back to a plain "#", which was the same problem caught once
   and patched with a different glyph.

   Drawn now: 24 by 24, stroke 1.75, currentColor, emitted by
   `Overtly.icon(name)`. This rule lives here rather than in the design
   system because only three of the seven pages that use an icon load
   components.css, and an <svg> with no width renders at 300 by 150.

   Sized in em so an icon always matches the text beside it, and nudged
   down a sixth of an em to sit on the text's optical centre rather than
   its baseline.
   ============================================================ */
.ov-icon { display: inline-block; width: 1.05em; height: 1.05em;
  flex: none; vertical-align: -0.16em; }
/* Where the icon is a flex child in its own right rather than part of a
   line of text, the baseline nudge is wrong. */
.resource-icon .ov-icon, .nf-check-icon .ov-icon, .nf-icon-chip .ov-icon { vertical-align: 0; }

/* -------- Print. Added 1 October 2026 --------
   Until today only the capex calculator had print rules, scoped to itself,
   so every other page printed the sticky site header and the dark ink
   footer: a block of solid colour and a navigation bar on the first and
   last sheet of a lesson someone wanted on paper.

   Kept deliberately small. It removes chrome that means nothing on paper
   (navigation, the progress rail, the lesson rail and its toggles, the
   previous and next links) and leaves every piece of content alone,
   including the notes and the citations, which are the part of a lesson
   most worth printing. The calculator's own print block still runs on its
   page and does not conflict with this. */
@media print {
  .site-header, .site-footer,
  .ovt-rail, .ov-lesson__rail, .ov-lesson__nav-toggle, .ov-lesson__foot,
  .tool-subhead { display: none !important; }
  body { background: #fff !important; }
  /* Links print as their text; a learner cannot click paper. */
  .lesson-p a { color: inherit; text-decoration: underline; }
  /* Keep a heading with the paragraph it introduces, and a note with its list. */
  .lesson-h3, .lesson-h2 { break-after: avoid; }
  .lesson-notes, .cite-list { break-inside: avoid; }
}
