/* STILLFORM — shared site stylesheet
   Palette ported (2026-08-30) from STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md
   section 5 — the homepage-rebuild reference — replacing the six
   2026-08-24 tokens below role-for-role (see CLAUDE.md for that history
   and for the sections still awaiting their own rebuild phase). */

:root {
  --ink:        #111915; /* navigation, final CTA and footer backgrounds */
  --forest:     #173226; /* primary buttons, bundle bar, modal footer */
  --bone:       #F4F0E8; /* page background */
  --paper:      #FAF8F3; /* routine and standard section backgrounds */
  --white:      #FFFFFF; /* proof strip, text on dark, nav CTA */
  --text:       #151D18; /* all headings and body text on light */
  --muted:      #4D5B52; /* secondary text on light */
  --clay:       #C66535; /* marks only — never text */
  --clay-text:  #A34D1F; /* step numbers and clay text on light */
  --clay-light: #E28C59; /* step numbers on ink or forest */
  --line:       rgba(21, 29, 24, 0.17); /* decorative rules only — measured
    contrast for every pair above lives in the instructions file section 5 */

  /* ---- Legacy tokens below: not part of the closed 11 above. Each one
     still drives a homepage section that hasn't reached its own rebuild
     phase yet (see STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md section 11).
     Phase 6 reconciles or removes them once every section has migrated. ---- */

  /* The compliant version of --line (~3.5:1) — kept for cases where a
     border is functional, not decorative, e.g. a field someone needs to
     see the edges of to use. */
  --line-strong: rgba(26, 40, 32, 0.55);

  /* Amber accent for the not-yet-rebuilt hero eyebrow/rule. See CLAUDE.md's
     design-bar section for the full history. */
  --amber: #B8763A;

  /* Motion. Strong ease-out for UI entrances/state changes: starts fast,
     settles gently - feels more responsive than the browser's built-in
     `ease`. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);

  --font-head: "Archivo", Arial, sans-serif;
  --font-body: "DM Sans", Arial, sans-serif;

  /* Old fluid type scale. --display, --h1, --h2 and --lede were the hero's
     and quote-break's only users; Phase 2 rebuilt the hero onto the
     sitewide h1 rule instead, and Phase 5 removed quote-break along with
     the rest of the pre-rebuild homepage content, so all four are unused
     now. Left declared rather than removed — Phase 6 reconciles/removes
     unused legacy tokens across the board, not piecemeal per section. The
     sitewide h1/h2/h3 base rule further down no longer reads any of these
     tokens; see the new type scale below it for the current foundation
     values. */
  --display: clamp(2.5rem, 1.85rem + 3.1vw, 4.25rem); /* 40px -> 68px, unused since Phase 2 */
  --h1:    clamp(2.25rem, 1.6rem + 2.9vw, 3.75rem);   /* 36px -> 60px, unused since Phase 2 */
  --h2:    clamp(1.75rem, 1.47rem + 1.35vw, 2.5rem);  /* 28px -> 40px, already unused */
  --h3:    1.375rem;                                   /* 22px, fixed */
  --body:  1rem;                                       /* 16px minimum */
  --lede:  1.125rem;                                   /* 18px, unused since Phase 2 */
  --small: 0.875rem;                                   /* 14px, fixed */
  --label: 0.6875rem; /* 11px, uppercase eyebrows/step numbers only, never paragraphs */

  /* 8px spacing system. */
  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 32px;
  --space-6: 48px;
  --space-8: 64px;
  --space-10: 80px;
  --space-12: 96px;
  --space-16: 128px;
}

/* ---------- Reset / base ---------- */

* { box-sizing: border-box; }

/* Author display rules (for example `.link-underline { display: inline-flex }`)
   otherwise override the browser's low-specificity [hidden] rule. Keep hidden
   UI out of both the visual layout and the keyboard order. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bone);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--body);
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--font-head);
  font-weight: 500;
  color: var(--text);
  margin: 0 0 var(--space-2);
}

/* Base sizes are mobile-first (CLAUDE.md section 8); 900px is the
   project's one real breakpoint. The type-scale table gives the homepage
   hero its own oversized h1 and every other page's h1 the same size as
   h2 — so the bare h1 rule below matches h2, and only `.hero h1` (the
   homepage) gets the larger clamp. Before Phase 1 this rule was unscoped,
   so every future subpage h1 would have inherited the homepage hero's
   huge size; this split is required infrastructure for those pages, not
   a homepage change — `.hero h1` keeps the exact values the bare rule
   used to carry. */
h1 { font-size: 40px; line-height: 1.01; letter-spacing: -0.045em; }
h2 { font-size: 40px; line-height: 1.01; letter-spacing: -0.045em; }
h3 { font-size: 24px; line-height: 1.04; letter-spacing: -0.03em; }

.hero h1 { font-size: 48px; line-height: 0.98; }

@media (min-width: 900px) {
  h1 { font-size: clamp(2.75rem, 4.8vw, 4.5rem); line-height: 0.98; }
  h2 { font-size: clamp(2.75rem, 4.8vw, 4.5rem); line-height: 0.98; }
  h3 { font-size: 28px; line-height: 1.04; }

  .hero h1 { font-size: clamp(4rem, 7vw, 6.5rem); max-width: 928px; line-height: 0.93; }
}

em { font-style: normal; }

p {
  margin: 0 0 var(--space-2);
  max-width: 66ch; /* keeps body copy within the 50-75 character target */
}

a { color: inherit; }

img { max-width: 100%; display: block; }

a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 3px solid var(--text);
  outline-offset: 3px;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--space-3);
}

/* ---------- Structural marks ---------- */

.eyebrow {
  display: block;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 11px;
  line-height: 1.3;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--space-2);
}

@media (min-width: 900px) {
  .eyebrow { font-size: 12px; }
}

/* The "half rule" from the Round 1 system (direction.html): a short,
   never-full-width mark that sits above an eyebrow label - a small pause
   before something begins. It's a mark, not type, so it only needs to
   clear the 3:1 non-text minimum, not 4.5:1. */
.rule {
  width: 24px;
  height: 2px;
  background: var(--amber);
  border: 0;
  margin: 0 0 var(--space-2);
}

.media-caption {
  font-size: var(--small);
  color: var(--muted);
  margin: var(--space-1) 0 0;
  max-width: 40ch;
}

/* ---------- Actions ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  background: var(--forest);
  color: var(--white);
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--body);
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  padding: 14px 24px; /* section 6 control-size table: 24px side padding */
  min-height: 44px;
  border-radius: 9999px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: opacity 0.16s var(--ease-out), background 0.16s var(--ease-out), transform 0.16s var(--ease-out);
}

.btn:hover { opacity: 0.85; }
.btn:active { transform: scale(0.97); }

.btn--outline {
  background: transparent;
  color: var(--white);
  border-color: rgba(245,241,235,0.6);
}

.btn--outline:hover { background: rgba(245,241,235,0.12); opacity: 1; }

/* Plain underlined text action — STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md
   section 6's "text-link actions" (Explore the routine, View the bundle):
   sentence case, underlined, 5px offset. A different pattern from
   `.text-link` above (uppercase/tracked/arrow), which stays as-is for its
   existing uses elsewhere on the page. Default color suits a light
   background (the hero); a dark-background use (the Phase 3 bundle bar)
   will need its own color there. */
.link-underline {
  display: inline-flex;
  align-items: center;
  min-height: 48px; /* spec's "text-link actions" control size: 48px hit area */
  color: var(--text);
  font-family: inherit;
  font-size: var(--body);
  text-decoration: underline;
  text-underline-offset: 5px;
  /* Button reset: "View the bundle" (Phase 3) is a <button> that opens a
     modal rather than a link that navigates, so this class now has to
     look identical on both elements. Harmless on the existing anchor use
     (Explore the routine) — anchors have none of these by default anyway. */
  background: none;
  border: 0;
  padding: 0;
  appearance: none;
  cursor: pointer;
}

.link-underline:hover { opacity: 0.75; }

/* Dark-background use: the Phase 3 bundle bar sits on --forest, where the
   default --text colour would fail contrast. */
.link-underline--dark { color: var(--white); }

.skip-link {
  position: absolute;
  left: var(--space-2);
  top: -100px;
  background: var(--ink);
  color: var(--white);
  padding: var(--space-1) var(--space-2);
  border-radius: 4px;
  z-index: 100;
  transition: top 0.15s var(--ease-out);
}

.skip-link:focus {
  top: var(--space-2);
}

/* ---------- Header ---------- */
/* Rebuilt for STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md section 7.1: a
   solid --ink bar (no more transparent-over-hero/scroll-to-solid — that
   was tied to the old video hero, which its own rebuild phase retires),
   72px tall at 900px+/64px below it, with three real columns at 900px+
   (brand / desktop nav / AU + CTA) that collapse to brand + a text "Menu"
   button below 900px. Position is `sticky`, not `fixed` — matching this
   section's own spec — so the bar reserves its own height in the page
   flow instead of floating over whatever comes after it. Phase 1 built it
   as `fixed`, which worked only because the old video hero was designed to
   sit underneath it; Phase 2's plain-image hero needs the nav to actually
   occupy the top of the viewport, since "nav + hero fill one 900px
   viewport" is unmeasurable otherwise. */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--ink);
}

.site-header__inner {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 64px;
}

@media (min-width: 900px) {
  .site-header__inner {
    min-height: 72px;
    padding-left: var(--space-6);
    padding-right: var(--space-6);
  }
}

/* Default focus outline (--text) is invisible on this dark bar, so it
   swaps to white here — same reasoning as the .final-cta override below. */
.site-header a:focus-visible,
.site-header button:focus-visible {
  outline-color: var(--white);
}

.site-logo {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--small);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--white);
  text-decoration: none;
}

/* Nav-only wordmark size/tracking correction, measured against the live
   reference at 543px (font-weight already matched at 500): reference is
   17px/0.22em tracking, the base .site-logo rule above is 14px/0.28em.
   Scoped to .site-header rather than changed on the base class, since
   .site-logo is also the footer's brand mark and the footer hasn't reached
   its own rebuild phase yet — this shouldn't resize it too. */
.site-header .site-logo {
  font-size: 17px;
  letter-spacing: 0.22em;
}

/* ---------- Desktop nav + actions (900px and up only) ---------- */

.site-nav-desktop,
.site-header__actions {
  display: none;
}

.site-nav-desktop ul {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--space-6);
  margin: 0;
  padding: 0;
}

/* Measured against the live reference: its desktop nav links declare
   13px (confirmed real — no zoom/transform anywhere in the ancestor
   chain, not a measurement artifact). Not applied here: section 6's
   body-text floor is 16px minimum everywhere, with three named
   exceptions (eyebrows, modal step labels, mobile routine-card text)
   that don't include nav links, and the file states the reference was
   already brought into compliance with that rule. Left at the inherited
   16px body size pending Patrik's call — see the phase report. */
.site-nav-desktop a {
  display: flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
  color: var(--white);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: opacity 0.2s var(--ease-out), border-color 0.2s var(--ease-out);
}

.site-nav-desktop a:hover { opacity: 0.75; border-color: var(--white); }

/* Was styled like a tracked eyebrow label (Archivo 500, uppercase,
   tracked); measured against the live reference, the AU marker is plain
   body text — DM Sans 400, 13px, no tracking, no transform. */
.site-header__region {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 13px;
  color: var(--white);
}

.btn--white {
  background: var(--white);
  color: var(--text);
}

.btn--white:hover { opacity: 0.85; }

@media (min-width: 900px) {
  .site-nav-desktop { display: block; }
  .site-header__actions { display: flex; align-items: center; gap: var(--space-3); }
}

/* ---------- "Menu" button (below 900px only) ---------- */

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 88px;
  height: 44px;
  padding: 0 var(--space-2);
  background: transparent;
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 9999px;
  color: var(--white);
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--body);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
}

.nav-toggle:hover { background: rgba(255,255,255,0.1); }

@media (min-width: 900px) {
  .nav-toggle { display: none; }
}

/* ---------- Nav panel: full-width dropdown, below 900px only ---------- */

.site-nav {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--bone);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 12px 24px rgba(21,29,24,0.12);
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 0.3s var(--ease-out), opacity 0.25s var(--ease-out);
}

.site-nav.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
}

.site-nav__inner {
  overflow: hidden;
  min-height: 0;
}

.site-nav ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: var(--space-2) var(--space-3) 0;
}

.site-nav li { border-top: 1px solid var(--line); }
.site-nav li:first-child { border-top: 0; }

.site-nav a {
  display: flex;
  align-items: center;
  min-height: 48px;
  text-decoration: none;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--body);
  color: var(--muted);
  transition: color 0.2s var(--ease-out);
}

.site-nav a:hover { color: var(--forest); }

/* .site-nav a's color would otherwise win over .btn's here (class+element
   beats a single class) and paint the button's label the muted nav-link
   colour instead of white. */
.site-nav .btn {
  display: flex;
  margin: var(--space-3);
  color: var(--white);
}

.site-nav .btn:hover { color: var(--white); }

@media (min-width: 900px) {
  .site-nav { display: none; }
}

/* ---------- Hero ---------- */
/* Rebuilt for STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md section 7.2: the copy
   sits below the media in normal page flow rather than overlaid on top of
   it, so none of the old scrim/legibility machinery is needed. Two stacked
   rows (media, then copy). `.hero h1` needs no size override: the sitewide
   h1 rule above (48px mobile -> clamp(4rem,7vw,6.5rem) at 900px+) already
   matches this section's hero sizing exactly. At 900px+ the section is
   pinned to fill exactly what's left of the viewport after the sticky nav
   (`calc(100svh - 72px)`), so nav + hero together fill one screen with no
   scroll. The media row is full viewport width, edge to edge — the one
   deliberately unboxed element on the page, in contrast to the copy row
   below it, which sits in a normal content column.

   The media itself is a static photo below 900px and an autoplaying muted
   video at 900px+ (Patrik's 2026-09-07 request) — see .hero__video below.
   Both share the same absolute-inset/object-fit-cover treatment so the slot
   looks identical regardless of which is showing. */

.hero {
  display: flex;
  flex-direction: column;
}

.hero__media {
  position: relative;
  min-height: 272px;
  overflow: hidden;
  background: var(--paper);
}

/* Absolutely positioned rather than `height: 100%` — .hero__media is a flex
   item sized by min-height/flex-grow, not an explicit height, and a
   percentage-height child doesn't reliably resolve against that (measured:
   it was rendering at the image's own intrinsic aspect ratio instead of
   filling the slot). Positioning it against the box directly sidesteps the
   dependency. */
.hero__image {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Video is desktop-only (see hero__actions media queries below) — mobile
   keeps the static image both for data weight and because the source's
   min-width: 900px media query means it never has a source to play below
   that width anyway. */
.hero__video { display: none; }

@media (min-width: 900px) {
  .hero__video {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .hero__media .hero__image { display: none; }
}

.hero__copy {
  width: min(100% - 40px, 760px);
  margin-inline: auto;
  padding: var(--space-4) 0;
}

.hero__copy-main { margin-bottom: var(--space-4); }

/* The shared .eyebrow class defaults to --muted (secondary text), but the
   reference's hero eyebrow measures at full --text color (rgb(21,29,24),
   confirmed via computed styles against the live reference at 543px) —
   font-weight already matched at 500. Scoped to the hero only: .eyebrow's
   other current uses are all in not-yet-rebuilt sections further down the
   page, which keep their existing look until their own rebuild phase. */
.hero .eyebrow { color: var(--text); }

.hero__lede {
  font-size: var(--body);
  line-height: 1.6;
  color: var(--muted);
  max-width: 40ch;
  margin: 0 0 var(--space-3);
}

.hero__actions {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.hero__note {
  font-size: var(--body);
  line-height: 1.5;
  color: var(--muted);
  margin: 0;
}

@media (min-width: 420px) {
  .hero__copy { width: min(100% - 48px, 760px); }
}

@media (min-width: 900px) {
  .hero {
    min-height: calc(100svh - 72px);
  }

  .hero__media {
    flex: 1 1 auto;
    min-height: 360px;
  }

  .hero__copy {
    width: min(100% - 96px, 1440px);
    display: grid;
    grid-template-columns: 8fr 4fr;
    align-items: end;
    column-gap: 7%;
    padding: 56px 0 48px;
  }

  .hero__copy-main { margin-bottom: 0; }
}

/* ---------- Proof strip ---------- */
/* STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md section 7.3. Replaces the old
   .signal-bar marquee below the hero — that section isn't part of the
   target 8-section homepage at all, so it's removed rather than kept
   alongside this one. Four short statements on a plain white band, with
   --line dividers: 2x2 on mobile, one row of 4 at 900px+. */

.proof-strip {
  background: var(--white);
}

.proof-strip__inner {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

.proof-strip__item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  padding: 0 var(--space-2);
  text-align: center;
}

.proof-strip__item:nth-child(odd) { border-right: 1px solid var(--line); }
.proof-strip__item:nth-child(n+3) { border-top: 1px solid var(--line); }

.proof-strip__item p {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
}

@media (min-width: 900px) {
  .proof-strip__inner { grid-template-columns: repeat(4, 1fr); }

  .proof-strip__item {
    height: 72px;
    border-top: 0;
    border-right: 1px solid var(--line);
  }
  .proof-strip__item:last-child { border-right: 0; }
  .proof-strip__item p { font-size: 12px; }
}

/* ---------- Evening routine ---------- */
/* STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md section 7.4. Replaces the old
   "Three steps" section (shared .card-grid, animated .step-icon SVGs,
   .step-card--dark/--amber) wholesale: real product photography instead
   of line-icon animation, so none of that machinery is reused. Section
   padding here (56/64) is its own value from the spec's spacing table,
   deliberately different from the other sections' own padding values. */

.routine {
  background: var(--paper);
  padding: var(--space-8) 0; /* 64px, mobile */
  scroll-margin-top: 64px;
}

.routine__head {
  margin: 0 0 var(--space-4); /* 32px on every width — the spec's routine-
    specific override of the general 56px/32px heading-block margin */
}

/* Direct child only: the eyebrow is a <p> too, but it now lives one level
   deeper inside .routine__head-main, so this no longer zeroes its own
   margin-bottom the way a plain ".routine__head p" descendant selector did. */
.routine__head > p { color: var(--muted); margin: 0; max-width: 46ch; }

/* Reference measured: at 900px+ this becomes a two-column row — heading
   left, supporting paragraph right — the same 8fr/4fr, 7%-gap, bottom-
   aligned proportion the hero copy row already uses. Below 900 it stays
   the plain stacked block it always was; wrapping the eyebrow+h2 pair in
   .routine__head-main only matters at this breakpoint. Removing the old
   max-width: 640px fixes a real bug it caused: at 1440px the h2's ~69px
   clamp size wrapped to 3 lines inside 640px, making the whole routine
   section far taller than the "fits in one 1440x900 viewport" spec. */
@media (min-width: 900px) {
  .routine__head {
    display: grid;
    grid-template-columns: 8fr 4fr;
    column-gap: 7%;
    align-items: end;
    margin-bottom: var(--space-4);
  }

  /* A grid item is its own formatting context, so the h2's own trailing
     margin-bottom doesn't collapse away — left in, it pads out the bottom
     of this column with 16px nothing needs, taller than the reference's
     matching heading-row measures. */
  .routine__head-main h2 { margin-bottom: 0; }
}

.routine__grid {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

.routine-card {
  background: var(--bone);
  border-bottom: 1px solid var(--forest);
  display: flex;
}

.routine-card__media { flex: 0 0 36%; min-height: 264px; }
.routine-card__media img { width: 100%; height: 100%; object-fit: cover; }

.routine-card__copy {
  flex: 1 1 auto;
  min-height: 264px;
  padding: var(--space-2);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.routine-card__num {
  display: block;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--label);
  letter-spacing: 0.16em;
  color: var(--clay-text);
  margin-bottom: var(--space-1);
}

.routine-card__copy h3 { margin: 0 0 var(--space-1); }

/* 15px/14px: the spec's one named mobile exception to the 16px body
   floor, because this card is a narrow two-column row at 375px. The 44px
   tap target is kept via .btn's own min-height. */
.routine-card__copy p { font-size: 15px; color: var(--muted); margin: 0 0 var(--space-2); }

.routine-card__btn { width: 100%; min-height: 48px; font-size: 14px; padding: 0 10px; }

@media (max-width: 419px) {
  .routine-card__media, .routine-card__copy { min-height: 248px; }
}

@media (min-width: 900px) {
  .routine { padding: 56px 0; }

  .routine__grid { grid-template-columns: repeat(3, 1fr); }

  .routine-card { flex-direction: column; }
  /* height, not min-height: in a column-direction flex item, min-height
     alone leaves the box's height indefinite, so the <img>'s height:100%
     can't resolve — it falls back to the photo's intrinsic aspect ratio
     (600x600, so it renders square, ~373px on a 1440px row) instead of the
     spec's 240px. Same fix as .product-modal__media below. The mobile rule's
     min-height: 264px must be reset here too — min-height always wins over
     height, so it would otherwise force this box back up to 264px. */
  .routine-card__media { flex: none; min-height: 0; height: 240px; }
  .routine-card__copy {
    min-height: 200px;
    padding: 16px 24px 24px;
    justify-content: flex-start;
  }
  .routine-card__copy p { font-size: var(--body); }
  .routine-card__btn { width: auto; font-size: var(--body); padding: 0 20px; }
}

/* ---------- Bundle bar ---------- */
/* Section 7.5. Sits 12px below the routine cards, inside the same
   section — not its own full section with the routine's 56/64px padding
   above and below it. */

.bundle-bar {
  margin-top: 12px;
  background: var(--forest);
  color: var(--white);
  padding: var(--space-3);
  display: grid;
  gap: var(--space-2);
}

.bundle-bar__tag {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay-light);
}

.bundle-bar__name {
  margin: 0 0 4px;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 24px;
  color: var(--white);
}

.bundle-bar__text p { color: rgba(245, 241, 235, 0.82); margin: 0; }

.bundle-bar__action {
  justify-self: start;
  color: var(--white);
}

@media (min-width: 900px) {
  .bundle-bar {
    padding: 24px 32px;
    grid-template-columns: 1fr 2fr auto;
    align-items: center;
    gap: var(--space-4);
  }
  .bundle-bar__action { justify-self: end; }
}

/* Default focus outline (--text) is invisible on this bar's forest
   background — same reasoning as the .site-header/.final-cta overrides. */
.bundle-bar :focus-visible { outline-color: var(--white); }

/* ---------- Product modal ---------- */
/* Section 8. One <dialog> serves all four opening actions (the three
   routine buttons above plus "View the bundle"). showModal()/close() give
   focus containment, Escape-to-close and focus restoration for free — see
   js/main.js. Mobile-first: fills the screen and scrolls internally below
   900px, becomes a centred card at 900px+. */

body:has(#productModal[open]) { overflow: hidden; }

.product-modal {
  padding: 0;
  border: 0;
  background: var(--bone);
  color: var(--text);
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  border-radius: 0;
}

/* [open] in the selector matters: an unconditional `.product-modal{display:
   flex}` would beat the UA stylesheet's `dialog:not([open]){display:none}`
   even while closed, since author rules always win over user-agent rules
   regardless of specificity. Scoping to [open] means the rule only exists
   while the attribute is present, so the UA's closed-state display:none
   goes uncontested. */
.product-modal[open] {
  display: flex;
  flex-direction: column;
}

.product-modal::backdrop {
  background: rgba(17, 25, 21, 0.72);
}

.product-modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 24px;
  border-bottom: 1px solid var(--line);
}

.product-modal__title {
  font-size: 28px;
  line-height: 1.1;
  letter-spacing: -0.03em;
  margin: 0 0 8px;
}

.product-modal__desc {
  color: var(--muted);
  margin: 0;
  max-width: 48ch;
}

.product-modal__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 var(--space-3);
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: 9999px;
  color: var(--text);
  font-family: var(--font-head);
  font-weight: 500;
  font-size: var(--body);
  cursor: pointer;
}

.product-modal__close:hover { background: var(--paper); }

.product-modal__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

.product-modal__grid {
  list-style: none;
  margin: 0;
  padding: var(--space-2);
  display: grid;
  gap: var(--space-2);
}

.product-modal__item {
  display: flex;
  background: var(--paper);
}

.product-modal__media {
  flex: 0 0 38%;
  min-height: 160px;
  position: relative;
}

.product-modal__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Outline, not box-shadow: an inset shadow paints under the <img> and
   disappears. outline-offset: -4px pulls it inward so it reads as a frame
   on the photo rather than sitting outside the card edge. */
.product-modal__item[aria-current="true"] .product-modal__media {
  outline: 4px solid var(--clay);
  outline-offset: -4px;
}

.product-modal__copy {
  flex: 1 1 auto;
  padding: 24px;
  min-width: 0;
}

.product-modal__step {
  margin: 0 0 4px;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--clay-text);
}

.product-modal__copy h3 { font-size: 18px; margin: 0 0 4px; }
.product-modal__copy p { color: var(--muted); margin: 0; }

/* Mobile is a deliberate stacked layout (not a row that happens to wrap):
   text block above, button below, tight leading — a plain row here left
   the button wrapping onto its own line with paragraph-width line-height
   on two short label lines, both eating vertical space unnecessarily.
   Restored to the original row/space-between look at 900px+ below. */
.product-modal__footer {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: 16px 24px;
  background: var(--forest);
  color: var(--white);
}

.product-modal__footer-line { font-family: var(--font-head); font-weight: 500; line-height: 1.3; margin: 0; }
/* font-size bumped to --body (was --small/14px): 14px was under the
   sitewide 16px body-text minimum — this line isn't a step label or
   eyebrow, the only two exceptions section 6 allows. */
.product-modal__footer-note { color: rgba(245,241,235,0.82); font-size: var(--body); line-height: 1.3; margin: 0; }
.product-modal__footer .btn { background: var(--white); color: var(--forest); }

/* Default focus outline (--text) is invisible on these dark surfaces —
   same reasoning as the .site-header/.final-cta/.bundle-bar overrides. */
.product-modal__footer :focus-visible { outline-color: var(--white); }

@media (min-width: 900px) {
  .product-modal {
    border-radius: 8px;
    width: min(920px, calc(100% - 48px));
    height: auto;
    max-height: min(760px, calc(100% - 64px));
  }

  .product-modal__header { padding: 32px 40px; }
  .product-modal__title { font-size: 32px; }

  .product-modal__grid {
    grid-template-columns: repeat(3, 1fr);
    padding: var(--space-3);
  }

  .product-modal__item { flex-direction: column; }
  /* height, not min-height: in a column-direction flex item, min-height
     alone leaves the box's height indefinite, so the <img>'s height:100%
     can't resolve — it falls back to the photo's intrinsic aspect ratio
     and blows the card out to ~500px+ tall, which is what was overflowing
     into the footer. An explicit height gives object-fit:cover a real box
     to crop against, the same way .routine-card__media relies on flex
     row-stretch (mobile) and .hero__image relies on inset:0 for the same
     definite-size requirement. */
  .product-modal__media { flex: none; height: 180px; }
  .product-modal__copy { padding: 24px 32px 32px; }

  .product-modal__footer {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 32px 40px;
  }
}

/* ---------- Our standard ---------- */
/* Section 7.6. Media stays inside the content column at every width — the
   spec is explicit it must not become a full-width band, unlike the hero
   image above it, so this reuses .container rather than bleeding edge to
   edge the way .hero__media does. */

.standard {
  background: var(--paper);
}

.standard__grid {
  display: grid;
  gap: var(--space-2);
}

.standard__media { min-height: 328px; overflow: hidden; }
.standard__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.standard__copy { padding: var(--space-8) var(--space-3); }
.standard__copy p { color: var(--muted); }

.standard__list {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
}

.standard__list-item {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line);
  font-family: var(--font-head);
  font-weight: 500;
}

.standard__list-num {
  color: var(--clay-text);
  font-size: var(--label);
  letter-spacing: 0.1em;
}

@media (min-width: 900px) {
  .standard__grid {
    grid-template-columns: 7fr 5fr;
    align-items: stretch;
    min-height: 704px;
  }

  .standard__media { min-height: 360px; height: 100%; }

  .standard__copy {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 80px 12%;
  }
}

/* ---------- Final CTA ---------- */
/* Section 7.7. The only signup form on the page — the hero has none
   (STILLFORM-CLAUDE-CODE-INSTRUCTIONS.md section 4, decision #3). id is
   what the hero action, nav CTA and modal CTA already link to. */

.final-cta {
  background: var(--ink);
  color: var(--white);
  padding: var(--space-8) 0;
  scroll-margin-top: 64px;
}

.final-cta .eyebrow { color: var(--white); }
.final-cta h2 { color: var(--white); }

.final-cta__grid {
  display: grid;
  gap: var(--space-4);
}

.final-cta__intro {
  color: rgba(245,241,235,0.82);
  margin: 0 0 var(--space-3);
}

.final-cta .btn { background: var(--white); color: var(--forest); }

.final-cta a:focus-visible,
.final-cta button:focus-visible,
.final-cta input:focus-visible {
  outline-color: var(--white);
}

@media (min-width: 900px) {
  .final-cta {
    /* 104px: section 6's exact value for this section, not one of the
       named 8px-grid tokens (which skip from 96 to 128) but still on the
       grid (104 = 13 x 8). */
    padding: 104px 0;
    scroll-margin-top: 72px;
  }

  .final-cta__grid {
    grid-template-columns: 7fr 5fr;
    gap: var(--space-8);
    align-items: center;
  }

  /* First name and email stack on mobile (already correct — narrow column,
     each needs its own full-width row) but sit side by side at 900px+.
     Without this, the two-row form column ends up markedly taller than the
     heading column beside it, which combined with the 104px padding above
     (an exact match to the reference's own value, confirmed by measuring
     it directly) reads as far more empty space below the button than the
     reference has. The reference's own form is shorter still — a single
     email field with a placeholder, no visible label — but section 7.7 and
     brief.md §9 require a real optional first-name field and a visible
     label on every field, so it can't be shrunk to match exactly. */
  .final-cta .signup-form__row {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---------- Signup form ---------- */

.signup-form__honeypot {
  display: none; /* honeypot: hidden from everyone, including assistive tech, by design */
}

.signup-form__row {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
  text-align: left;
}

.field label {
  display: block;
  font-size: var(--small);
  letter-spacing: 0.02em;
  margin-bottom: var(--space-1);
}

.field__optional {
  font-weight: 400;
  opacity: 0.8;
}

.field input {
  width: 100%;
  min-height: 48px;
  padding: 10px var(--space-2);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--body);
  color: var(--text);
  background: var(--bone);
  /* --line-strong, not --line: someone needs to see this edge to use the
     field, unlike the decorative dividers elsewhere on the page. */
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  transition: border-color 0.16s var(--ease-out);
}

.field input:focus-visible { border-color: var(--forest); }

/* Final CTA is the only remaining .signup-form--dark consumer, and it sits
   on --ink, not the old cta-band's --forest — the border and label go to
   full white per section 7.7 ("a white 16px 'Email address' label", "1px
   solid white border on --ink"). White on --ink already measures 17.9:1
   (section 5 table), miles past both the 3:1 non-text and 4.5:1 text
   floors, so the literal spec value needs no extra tuning. */
.signup-form--dark .field input {
  background: var(--ink);
  color: var(--white);
  border-color: var(--white);
}

/* A white border is indistinguishable from the field's own white-on-focus
   state, so focus gets its own colour — clay-light measures 6.9:1 on --ink
   (section 5 table), comfortably past the 3:1 non-text floor. */
.signup-form--dark .field input:focus-visible { border-color: var(--clay-light); }

.signup-form--dark .field label { color: var(--white); }

.signup-form__note {
  font-size: var(--small);
  margin: var(--space-2) 0 0;
  color: inherit;
  opacity: 0.8;
}

/* ---------- Signup form width (contact.html) ---------- */
/* On the homepage this form only ever appears inside `.final-cta__grid`'s
   5fr column, which already caps its width. contact.html's form sits
   directly in a plain `.page-section` with no such grid, so without a cap
   here its two fields would stretch to the full 1440px content column.
   Scoped to this page's section id, same pattern as `#featured` above. */
#signup .signup-form { max-width: 480px; }

/* Contact uses the existing light form with the current type and palette. */
[data-page="contact"] .field label,
[data-page="contact"] .signup-form__note { font-size: var(--body); }
[data-page="contact"] .field input { border-color: var(--muted); }
[data-page="contact"] .field input::placeholder { color: var(--muted); opacity: 1; }
[data-page="contact"] .faq-item .link-underline { display: flex; width: fit-content; }

/* ---------- Footer ---------- */
/* Section 7.8. White at 62% opacity on --ink measures ~7.4:1 (calculated
   via the WCAG relative-luminance formula, matching the spec's own worked
   example of ~7.5:1 for this exact pair) — comfortably past the 4.5:1 text
   floor, and the spec's stated floor ("do not go lighter than that"), so
   it's used as-is for footer link and legal text. */

.site-footer {
  background: var(--ink);
  min-height: 96px;
  border-top: 1px solid rgba(255,255,255,0.12);
}

.site-footer__inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.site-footer__logo { color: var(--white); margin: 0; }

.site-footer nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-3);
}

.site-footer nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--small);
  text-decoration: none;
  color: rgba(255,255,255,0.62);
  transition: color 0.2s var(--ease-out);
}

.site-footer nav a:hover { color: var(--white); }
.site-footer nav a:focus-visible { outline-color: var(--white); }

.site-footer__legal {
  font-size: var(--small);
  color: rgba(255,255,255,0.62);
  margin: 0;
}

@media (min-width: 900px) {
  .site-footer__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-6);
  }
}

/* ---------- Scroll reveal ---------- */
/* Progressive enhancement: these rules only apply once js/main.js's reveal
   IIFE confirms IntersectionObserver support and reduced motion is not
   requested, and adds .js-reveal to <html> as its first action. With JS
   disabled, unsupported, or reduced motion, .js-reveal is never added, so
   every .reveal element renders at normal opacity/position immediately. */

.js-reveal .reveal {
  opacity: 0;
  transform: translateY(var(--space-2));
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
  transition-delay: var(--reveal-delay, 0s);
}

.js-reveal .reveal.reveal--visible {
  opacity: 1;
  transform: none;
}

/* Never let a keyboard user tab onto something still invisible. */
.js-reveal .reveal:focus-within {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .js-reveal .reveal { transition: none; }
}

/* ---------- Subpage page header ---------- */
/* First component built for the non-homepage pages (CLAUDE.md Phase 1):
   the homepage's `.hero` is full-bleed and fills a viewport, which the
   spec's type scale and section 8 both say is homepage-only — subpages
   get a plain eyebrow + h1 + intro paragraph inside the normal content
   column instead. */

.page-header { padding: var(--space-8) 0; }

.page-header h1 { max-width: 800px; margin-bottom: var(--space-3); }

.page-header__intro {
  color: var(--muted);
  max-width: 56ch;
  margin: 0;
}

@media (min-width: 900px) {
  .page-header { padding: 112px 0 64px; }
}

/* ---------- Subpage content sections ---------- */

.page-section { padding: var(--space-8) 0; }
.page-section--paper { background: var(--paper); }

.page-section__head { max-width: 720px; margin: 0 0 var(--space-4); }
.page-section__head p:last-child { color: var(--muted); max-width: 60ch; margin: 0; }

@media (min-width: 900px) {
  .page-section { padding: 112px 0; }
  .page-section__head { margin-bottom: var(--space-6); }
}

/* Opt-in desktop spacing for approach, product and journal only. */
@media (min-width: 900px) {
  .page--compact .page-section { padding: 72px 0; }
  .page--compact .page-section__head { margin-bottom: var(--space-4); }
  .page--compact .page-section h2 { font-size: 32px; line-height: 1.1; }
  .page--compact[data-page="product"] .product-media { margin-left: 0; }
}

/* ---------- Shop card (rituals.html) ---------- */
/* A new grid card for the five-item range page. Not a reuse of
   `.routine-card`: that component is a numbered three-step sequence tied
   to the homepage's fixed Mix/Mist/Mask copy, not a general product card. */

.shop-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

@media (min-width: 900px) {
  .shop-grid--products { grid-template-columns: repeat(3, 1fr); }
  .shop-grid--bundles { grid-template-columns: repeat(2, 1fr); }
}

.shop-card {
  background: var(--paper);
  border-bottom: 1px solid var(--forest);
  display: flex;
  flex-direction: column;
}

/* Paper-background sections invert the card fill so it still reads
   against its section, the same paper/bone pairing `.routine-card` uses
   on the homepage. */
.page-section--paper .shop-card { background: var(--bone); }

.shop-card__media {
  aspect-ratio: 2 / 3; /* matches the 400x600 product photography */
  overflow: hidden;
  background: var(--line);
}

.shop-card__media img { width: 100%; height: 100%; object-fit: cover; }

/* Deliberate flat colour fill for an image slot with no photograph yet —
   CLAUDE.md section 10. Never carries text, so it only needs to read as
   an intentional choice, not clear a text-contrast ratio. */
.image-placeholder { width: 100%; height: 100%; background: var(--forest); }

.shop-card__copy {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-2) var(--space-3);
}

.shop-card__copy .eyebrow { margin-bottom: 0; }
.shop-card__copy h3 { margin: 0; }

.shop-card__copy p {
  flex: 1 1 auto;
  color: var(--muted);
  font-size: var(--body);
  line-height: 1.5;
  margin: 0;
}

.shop-card__link { margin-top: var(--space-1); }

/* ---------- CTA band (subpage early-access routing) ---------- */
/* Section 12: rituals.html and product.html route buy-style actions to
   the homepage's signup rather than repeating the form inline. This is a
   plain dark banner with no form — not `.final-cta`, which is built
   two-column around a form field and would leave an empty column here. */

.cta-band {
  background: var(--ink);
  color: var(--white);
  padding: var(--space-8) 0;
}

.cta-band__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.cta-band .eyebrow { color: var(--white); }
.cta-band h2 { color: var(--white); margin-bottom: var(--space-2); }

.cta-band__text p {
  color: rgba(245, 241, 235, 0.82);
  max-width: 56ch;
  margin: 0;
}

.cta-band a:focus-visible,
.cta-band button:focus-visible {
  outline-color: var(--white);
}

@media (min-width: 900px) {
  .cta-band { padding: 104px 0; }

  .cta-band__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-8);
  }

  /* Without a width cap the heading grows to fill the row and leaves the
     button too little space, wrapping its label onto two lines. */
  .cta-band__text { max-width: 640px; }
  .cta-band__inner > .btn { flex-shrink: 0; white-space: nowrap; }
}

/* ---------- Plain text list (product.html) ---------- */
/* Scoped to its own class rather than a bare `ul, ol` reset: nav lists,
   `.shop-grid` and `.faq-list` are also plain <ul>s with no class of their
   own, and a global `li + li` margin broke their flex/grid row alignment
   (first item sat higher than the rest — the footer nav, for example). */

.text-list { margin: 0; padding-left: var(--space-3); }
.text-list li + li { margin-top: var(--space-1); }

/* ---------- Product media (product.html) ---------- */
/* `.shop-card__media`'s aspect-ratio is fixed at 2/3 for 400x600 card
   crops and doesn't fit the 800x900 product hero image. Single column at
   every width, sizing only — not a grid system. */

.product-media {
  max-width: 480px;
  margin: 0 auto var(--space-4);
  aspect-ratio: 800 / 900;
  overflow: hidden;
}

.product-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- Product media — wide modifier (approach.html) ---------- */
/* Full content-column width for a landscape 1600x900 slot, instead of the
   narrow centred 800x900 box `.product-media` uses on product.html. A
   modifier on top of that class, not a change to it, so product.html's
   box is unaffected. */

.product-media--wide {
  max-width: none;
  aspect-ratio: 1600 / 900;
}

/* ---------- FAQ (product.html) ---------- */
/* No accordion/disclosure component exists elsewhere in the codebase.
   Built on native <details>/<summary> — keyboard support and toggling are
   built into the element, so no JS is needed. */

.faq-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.faq-item { border-bottom: 1px solid var(--line); }

.faq-item summary {
  padding: var(--space-2) 0;
  font-family: var(--font-head);
  font-weight: 500;
  cursor: pointer;
}

.faq-item summary:focus-visible {
  outline: 3px solid var(--text);
  outline-offset: 3px;
}

.faq-item p {
  color: var(--muted);
  max-width: 60ch;
  margin: 0 0 var(--space-2);
}

/* ---------- Belief list (approach.html) ---------- */
/* A vertical list of short belief statements — a heading and one sentence
   per item. Reuses the divided-list rhythm `.faq-list` already established,
   without the <details> disclosure: these are static statements, not
   answers to reveal on demand. */

.belief-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.belief-item {
  border-bottom: 1px solid var(--line);
  padding: var(--space-3) 0;
}

.belief-item h3 { margin: 0 0 var(--space-1); }
.belief-item p { color: var(--muted); max-width: 60ch; margin: 0; }

/* ---------- Featured journal teaser (journal.html) ---------- */
/* `.page-section__head`'s own bottom margin (32/48px) is sized to separate
   a heading from a content block like a list or grid below it. Here the
   only thing below is a single CTA link, so that much space read as a
   dead gap rather than section rhythm — scoped down to this one instance
   rather than changing the shared rule everywhere it's used. */
#featured .page-section__head { margin-bottom: var(--space-3); }

/* Same reasoning for the space after the link: the standard section
   padding-bottom (64/112px) is sized for a section that ends on a full
   content block, not one line of text, so it read as an oversized gap
   before the paper background hands off to the next section. */
#featured { padding-bottom: var(--space-4); }

/* Larger, medium-weight variant for a link that should carry more visual
   weight than the default 16px underline — same family/weight the brand
   already uses for buttons and headings, just applied to a text link. */
.link-underline--emphasis {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 18px;
}

/* ---------- Build your ritual quiz (quiz.html) ---------- */

.quiz-header { padding-bottom: var(--space-4); }

.quiz-section { padding-top: var(--space-4); }

.quiz-shell { max-width: 800px; }

.quiz-progress { margin-bottom: var(--space-6); }

.quiz-progress .eyebrow { margin-bottom: var(--space-1); }

.quiz-progress__track {
  width: 100%;
  height: 8px;
  background: var(--line);
}

.quiz-progress__bar {
  width: 20%;
  height: 100%;
  background: var(--forest);
  transition: width 0.16s var(--ease-out);
}

.quiz-question {
  border: 0;
  margin: 0;
  padding: 0;
}

.quiz-question legend,
.quiz-result h2 {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 32px;
  line-height: 1.04;
  letter-spacing: -0.03em;
  max-width: 22ch;
  padding: 0;
}

.quiz-question__intro,
.quiz-result > p {
  color: var(--muted);
  max-width: 56ch;
  margin: var(--space-2) 0 0;
}

.quiz-options {
  display: grid;
  gap: var(--space-1);
  margin-top: var(--space-4);
}

.quiz-option {
  display: block;
  position: relative;
  min-height: 64px;
  cursor: pointer;
}

.quiz-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.quiz-option span {
  display: flex;
  align-items: center;
  min-height: 64px;
  padding: var(--space-2);
  border: 1px solid var(--muted);
  background: var(--paper);
  color: var(--text);
  line-height: 1.5;
  transition: background 0.16s var(--ease-out), border-color 0.16s var(--ease-out);
}

.quiz-option:hover span { background: var(--bone); }

.quiz-option input:checked + span {
  background: var(--bone);
  border: 3px solid var(--forest);
  padding: 14px;
  font-family: var(--font-head);
  font-weight: 500;
}

.quiz-option input:focus-visible + span {
  outline: 3px solid var(--text);
  outline-offset: 3px;
}

.quiz-error {
  color: var(--clay-text);
  margin: var(--space-2) 0 0;
}

.quiz-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.quiz-actions .btn,
.quiz-result .btn,
.quiz-signup .btn {
  min-height: 48px;
}

.quiz-actions .btn { min-width: 136px; }

.quiz-next:disabled {
  background: var(--muted);
  cursor: not-allowed;
  opacity: 1;
}

.quiz-result { max-width: 640px; }

.quiz-result__note { font-size: var(--body); }

.quiz-result .btn { margin-top: var(--space-4); }

.quiz-restart { display: flex; margin-top: var(--space-2); }

.quiz-signup { scroll-margin-top: 64px; }

@media (min-width: 900px) {
  .quiz-header { padding-bottom: var(--space-6); }
  .quiz-section { padding-top: var(--space-6); }
  .quiz-question legend,
  .quiz-result h2 { font-size: 40px; }
  .quiz-signup { scroll-margin-top: 72px; }
}

/* ---------- Responsive ---------- */

@media (min-width: 1440px) {
  .container { max-width: 1200px; }
}
