/* ===== css/tokens.css ===== */
/* =============================================================================
   Aforé / DermaReverse — Design Tokens (LOCKED)
   Source: plans/research/brand-tokens.md §4 (verbatim :root), extended per
   build-plan.md COO recon #2 + creative-direction.md §2.4.
   3-tier system: brand (--c-*) → semantic → component. Components reference
   semantic/component tokens ONLY — never raw hex/px in .module.css.
   ============================================================================= */

:root {
  /* ---- 13 brand colors ---- */
  --c-black:#13181C; --c-golden-hour:#B8854F; --c-oyster:#C8B89E; --c-parchment:#E4DFD3;
  --c-khaki:#E1D3BA; --c-cadmium:#FFA300; --c-deep-olive:#463B24; --c-umber:#9A5224;
  --c-ochre:#C67E0A; --c-klein-blue:#1D3481; --c-poppy:#D43D01; --c-clay:#803413; --c-claret:#540E09;

  /* ---- semantic: surfaces & ink ---- */
  --bg:var(--c-parchment); --bg-alt:var(--c-khaki); --bg-sand:var(--c-oyster); --surface:#EEEAE0;
  --ink:var(--c-black); --ink-soft:var(--c-deep-olive); --ink-mute:#6B5E45;
  --line:#C7BCA6; --line-strong:var(--c-deep-olive); --line-dark:rgba(228,223,211,.18);

  /* ---- semantic: accents ---- */
  --accent:var(--c-ochre); --accent-warm:var(--c-cadmium); --accent-metal:var(--c-golden-hour);
  --accent-cool:var(--c-klein-blue); --accent-poppy:var(--c-poppy);
  --accent-clay:var(--c-clay); --accent-claret:var(--c-claret);

  /* ---- semantic: dark sections ---- */
  --dark-bg:var(--c-deep-olive); --dark-bg-2:var(--c-black); --dark-bg-claret:var(--c-claret);
  --dark-ink:var(--c-parchment); --dark-ink-soft:var(--c-oyster);

  /* ---- semantic: components ---- */
  --on-accent:var(--c-black); --focus:var(--c-klein-blue);
  --btn-bg:var(--c-black); --btn-fg:var(--c-parchment);
  --btn-accent-bg:var(--c-ochre); --btn-accent-fg:var(--c-black);

  /* ---- fonts ---- */
  --font-display: var(--font-display, "Fraunces"), "Times New Roman", Georgia, serif;
  --font-serif:   var(--font-serif,   "Newsreader"), Georgia, "Times New Roman", serif;
  --font-sans:    var(--font-sans,    "Inter"), system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-mono:    var(--font-mono,    "IBM Plex Mono"), ui-monospace, Menlo, Consolas, monospace;

  /* ---- type scale ---- */
  --fs-display:clamp(3.25rem,1.5rem + 8vw,7.5rem);
  --fs-h1:clamp(2.5rem,1.4rem + 5vw,4.5rem);
  --fs-h2:clamp(2rem,1.3rem + 3.2vw,3.25rem);
  --fs-h3:clamp(1.5rem,1.15rem + 1.6vw,2.25rem);
  --fs-h4:clamp(1.25rem,1.05rem + 0.9vw,1.625rem);
  --fs-lead:clamp(1.125rem,1rem + 0.6vw,1.375rem);
  --fs-body:clamp(1rem,0.96rem + 0.2vw,1.0625rem);
  --fs-sm:0.9375rem; --fs-eyebrow:clamp(0.75rem,0.72rem + 0.15vw,0.8125rem); --fs-meta:0.75rem;
  --lh-display:0.98; --lh-tight:1.08; --lh-head:1.15; --lh-snug:1.4; --lh-body:1.6;
  --tr-eyebrow:0.16em; --tr-tight:-0.01em;

  /* ---- spacing & layout ---- */
  --sp-1:0.25rem; --sp-2:0.5rem; --sp-3:0.75rem; --sp-4:1rem; --sp-5:1.5rem; --sp-6:2rem;
  --sp-7:3rem; --sp-8:4rem; --sp-9:6rem; --sp-10:8rem;
  --section-y:clamp(4rem,8vw,8rem); --gutter:clamp(1.25rem,4vw,4rem);
  --maxw:1440px; --maxw-prose:68ch;

  /* ---- radii ---- */
  --r-pill:9999px; --r-lg:20px; --r-md:12px; --r-sm:8px; --r-image:16px; --r-0:0;

  /* ---- borders ---- */
  --bw-hair:1px; --bw:1.5px; --bw-strong:2px;

  /* ---- shadows / rings ---- */
  --shadow-xs:0 1px 2px rgba(70,59,36,.06);
  --shadow-sm:0 2px 8px rgba(70,59,36,.08);
  --shadow-md:0 8px 24px rgba(70,59,36,.10);
  --shadow-lg:0 18px 48px rgba(19,24,28,.12);
  --shadow-glow:0 0 0 4px rgba(255,163,0,.18);
  --ring-focus:0 0 0 3px rgba(29,52,129,.55);

  /* ---- motion ---- */
  --dur-fast:150ms; --dur:250ms; --dur-slow:400ms; --dur-slower:700ms;
  --ease:cubic-bezier(.22,1,.36,1);
  --ease-in-out:cubic-bezier(.65,0,.35,1);
  --ease-emph:cubic-bezier(.16,1,.3,1);

  /* =========================================================================
     ADDED by FOUNDATION A1 (build-plan §2A · creative-direction §2.4)
     ========================================================================= */

  /* ---- primary CTA tokens (COO recon #2): Cadmium fill + ink label,
         hover warms to Ochre. The Subscribe & Save buttons use these. ---- */
  --cta-bg:var(--c-cadmium);
  --cta-fg:var(--ink);
  --cta-bg-hover:var(--c-ochre);

  /* ---- reveal / mask easings used by the 2 GSAP moments + before/after ---- */
  --ease-reveal:cubic-bezier(.19,1,.22,1);
  --micro-ease-overshoot:cubic-bezier(.25,1.4,.5,1);
  --spring-pop:linear(0,0, 0.3,1.2, 0.5,0.9, 0.7,1.05, 1,1);

  /* ---- z-index scale ---- */
  --z-grain:1;     /* film-grain overlay sits above flat section bg, below content */
  --z-nav:100;     /* sticky top nav */
  --z-sticky:200;  /* sticky mobile CTA bar */
  --z-modal:1000;  /* exit-intent modal */

  /* ---- texture ---- */
  --grain-opacity:0.04;
}

/* ===== css/base.css ===== */
/* =============================================================================
   Aforé / DermaReverse — Base stylesheet (STATIC PORT of app/globals.css)
   Tokens → modern reset → base type → utilities → film grain → reduced-motion,
   PLUS the shared UI atoms (Container/Button/Eyebrow/SectionHeading/Badge/Reveal)
   promoted to GLOBAL classes. Every value references a var(--token).
   tokens.css is imported by site.css BEFORE this file; no @import here.
   ============================================================================= */

/* ---------------------------------------------------------------------------
   1. Modern CSS reset (verbatim from globals.css)
   --------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -moz-tab-size: 4;
  tab-size: 4;
}

html:focus-within {
  scroll-behavior: smooth;
}

body {
  min-height: 100svh;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

img,
picture {
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
  padding: 0;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

#__next,
#root {
  isolation: isolate;
}

/* ---------------------------------------------------------------------------
   2. Base typography & document defaults (verbatim from globals.css)
   --------------------------------------------------------------------------- */

body {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--ink);
  background-color: var(--bg);
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: var(--lh-head);
  letter-spacing: var(--tr-tight);
  text-wrap: balance;
}

h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-tight);
}
h2 {
  font-size: var(--fs-h2);
}
h3 {
  font-size: var(--fs-h3);
}
h4 {
  font-size: var(--fs-h4);
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration: none;
}

strong,
b {
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   3. Accessibility utilities (verbatim from globals.css)
   --------------------------------------------------------------------------- */

/* Visually hidden but available to screen readers. */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link / reduce-motion toggle becomes visible on focus. */
.sr-only-focusable:focus,
.sr-only-focusable:focus-within {
  position: fixed !important;
  top: var(--sp-3);
  left: var(--sp-3);
  z-index: var(--z-modal);
  width: auto;
  height: auto;
  padding: var(--sp-2) var(--sp-4);
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
  color: var(--btn-fg);
  background-color: var(--btn-bg);
  border-radius: var(--r-pill);
}

/* Single focus treatment for keyboard users (Klein Blue ring). */
:focus-visible {
  outline: none;
  box-shadow: var(--ring-focus);
  border-radius: var(--r-sm);
}

::selection {
  background-color: var(--accent-warm);
  color: var(--on-accent);
}

/* ---------------------------------------------------------------------------
   4. Film-grain overlay (the "printed editorial stock" texture)
   ONE static feTurbulence, ~4% soft-light, fixed, full-bleed, pointer-events:none.
   The <filter id="afore-grain"> lives once in index.html as an inline,
   visually-hidden <svg>. The .grain element consumes it.
   --------------------------------------------------------------------------- */

.grain {
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: soft-light;
  filter: url(#afore-grain);
}

/* =============================================================================
   5. SHARED UI ATOMS → GLOBAL CLASSES
   Ported from the components/ui atom CSS modules. Section CSS uses these
   classes directly; do NOT re-declare per section.
   ============================================================================= */

/* ---- Container — centered max-width + responsive gutters --------------------
   Base ".container" + size modifiers ".container--prose" / ".container--wide".
   Default (no modifier) = --maxw. */
.container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--gutter);
  max-width: var(--maxw);
}

/* Reading measure for prose blocks (FAQ, long body). */
.container--prose {
  max-width: var(--maxw-prose);
}

/* Full-width with gutters only — for edge-bleeding editorial spreads. */
.container--wide {
  max-width: none;
}

/* ---- Button — shared CTA vocabulary. Pill radius. ---------------------------
   Base ".btn" + variant (.btn--cta/.btn--ink/.btn--ghost/.btn--outline)
   + size (.btn--sm/.btn--md/.btn--lg) + .btn--full.
   Internal spans: .btn__label, .btn__icon. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  border-radius: var(--r-pill);
  border: var(--bw-hair) solid transparent;
  cursor: pointer;
  user-select: none;
  transition:
    transform var(--dur) var(--micro-ease-overshoot),
    background-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease);
}

.btn__label {
  display: inline-block;
}

.btn__icon {
  display: inline-flex;
  font-size: 1.1em;
  line-height: 0;
}

/* ---- sizes (default applied = md when no size class given) ---- */
.btn--sm {
  font-size: var(--fs-sm);
  padding: var(--sp-2) var(--sp-4);
}
.btn--md {
  font-size: var(--fs-body);
  padding: 0.9rem 1.6rem;
}
.btn--lg {
  font-size: var(--fs-lead);
  padding: var(--sp-4) var(--sp-6);
}

.btn--full {
  width: 100%;
}

/* ---- variant: cta (Cadmium fill + ink label — the one loud element) ---- */
.btn--cta {
  background-color: var(--cta-bg);
  color: var(--cta-fg);
}
.btn--cta:hover {
  background-color: var(--cta-bg-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-glow);
}
.btn--cta:active {
  transform: translateY(0);
  transition-duration: 90ms;
}

/* ---- variant: ink (secondary solid — Black bg / Parchment label) ---- */
.btn--ink {
  background-color: var(--btn-bg);
  color: var(--btn-fg);
}
.btn--ink:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
.btn--ink:active {
  transform: translateY(0);
  transition-duration: 90ms;
}

/* ---- variant: ghost (text + arrow, no fill) ---- */
.btn--ghost {
  background-color: transparent;
  color: var(--ink);
  padding-inline: var(--sp-2);
}
.btn--ghost:hover {
  color: var(--ink-soft);
}
.btn--ghost:hover .btn__icon {
  transform: translateX(2px);
}
.btn--ghost .btn__icon {
  transition: transform var(--dur) var(--ease);
}

/* ---- variant: outline (hairline-bordered ink) ---- */
.btn--outline {
  background-color: transparent;
  color: var(--ink);
  border-color: var(--line-strong);
}
.btn--outline:hover {
  background-color: var(--ink);
  color: var(--btn-fg);
  transform: translateY(-1px);
}
.btn--outline:active {
  transform: translateY(0);
  transition-duration: 90ms;
}

/* Disabled state (form submit guard). */
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  .btn,
  .btn:hover,
  .btn:active {
    transform: none;
  }
}

/* ---- Eyebrow — mono uppercase tracked kicker (the clinical voice) ----------
   Base ".eyebrow" + tone (.eyebrow--metal/.eyebrow--dark/.eyebrow--accent/
   .eyebrow--poppy). Default (no tone) = --ink-soft. */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  margin: 0;
  color: var(--ink-soft);
}

/* Golden-hour metallic — the hero eyebrow. Uses the deeper burnished Clay tone
   rather than raw Golden-Hour: --accent-metal (#B8854F) only hits 2.43:1 on the
   Parchment hero bg and fails WCAG AA for this small (13px) mono text, whereas
   --accent-clay (#803413) reaches 6.53:1 while keeping the warm-metal voice. */
.eyebrow--metal {
  color: var(--accent-clay);
}
/* On dark sections — Parchment. */
.eyebrow--dark {
  color: var(--dark-ink);
}
/* Emphasis on dark — Cadmium. */
.eyebrow--accent {
  color: var(--accent-warm);
}
/* Before/After tabs voice — Poppy. */
.eyebrow--poppy {
  color: var(--accent-poppy);
}

/* ---- SectionHeading — Fraunces head + optional Newsreader-italic emphasis ---
   Base ".section-heading" + level (.section-heading--h1/--h2/--h3 → size)
   + tone (.section-heading--dark) + align (.section-heading--center).
   The inline <em> emphasis is styled via ".section-heading em" (true italic). */
.section-heading {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: var(--lh-head);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
  text-wrap: balance;
  margin: 0;
}

.section-heading--h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-tight);
}
.section-heading--h2 {
  font-size: var(--fs-h2);
}
.section-heading--h3 {
  font-size: var(--fs-h3);
}

/* The italic emphasis — true Newsreader cursive italic. Use <em> inside. */
.section-heading em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0;
}

.section-heading--dark {
  color: var(--dark-ink);
}

.section-heading--center {
  text-align: center;
}

/* ---- Badge — stadium pill chip (the capsule motif). Mono uppercase. --------
   Base ".badge" + tone (.badge--solid/.badge--accent/.badge--dark).
   Default (no tone) = hairline-outlined ink on cream.
   Optional internals: .badge__mark (PillMark svg), .badge__label. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  line-height: 1;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-pill);
  border: var(--bw-hair) solid transparent;
  white-space: nowrap;
  /* default tone: hairline-outlined ink on cream */
  color: var(--ink-soft);
  border-color: var(--line);
  background-color: transparent;
}

.badge__mark {
  font-size: 1.05em;
  flex: none;
}

.badge__label {
  display: inline-block;
}

/* Cadmium fill + ink — the "MOST POPULAR" ribbon */
.badge--solid {
  color: var(--on-accent);
  background-color: var(--accent-warm);
  border-color: transparent;
}

/* Ochre fill + ink — box-matched chips */
.badge--accent {
  color: var(--on-accent);
  background-color: var(--accent);
  border-color: transparent;
}

/* outlined Parchment on dark */
.badge--dark {
  color: var(--dark-ink);
  border-color: var(--line-dark);
  background-color: transparent;
}

/* ---- Reveal — scroll reveal hooks (CSS-driven, NO GSAP) --------------------
   Markup: any element with [data-reveal] paints its from-state. js/main.js adds
   .is-visible on viewport entry to land the final state. Variant chosen via
   data-reveal="fade-up|fade|scale-in|clip-up" (default fade-up). Per-element
   tuning: data-reveal-delay="0.12" (seconds) → inline transition-delay applied
   by JS. Server/no-JS + reduced-motion lands at final state. */
[data-reveal] {
  opacity: 0;
  transition-property: transform, opacity;
  transition-duration: var(--dur-slower);
  transition-timing-function: var(--ease);
  will-change: transform, opacity;
}

[data-reveal="fade-up"] {
  transform: translateY(24px);
}
[data-reveal="fade"] {
  transform: none;
}
[data-reveal="scale-in"] {
  transform: scale(0.96);
}
[data-reveal="clip-up"] {
  transform: translateY(24px) scale(0.98);
}

/* in-view → final state */
[data-reveal].is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ---- Light-beat seam hairline -----------------------------------------------
   The dark beats (product/clinical/founder/finalcta) get crisp hard color edges
   at their seams, so those transitions read instantly. The long Parchment runs
   carry no edge cue and separate by whitespace alone, so consecutive light
   sections read as one floating field. Give the major unruled Parchment beats a
   faint top hairline — the same device Trust already uses — so every light seam
   has a defined edge and the transition language is consistent across the page.
   (These three sections set no border-block-start of their own; the section CSS
   concatenates after base.css, so nothing here is overridden.) */
.s-problem,
.s-howtouse,
.s-beforeafter,
.s-faq {
  border-block-start: var(--bw-hair) solid var(--line);
}

/* ---------------------------------------------------------------------------
   6. Global reduced-motion block (verbatim from globals.css)
   Covers no-JS / pre-hydration. Near-zero durations AND reset
   animation-timeline:auto — the `animation` shorthand does NOT reset the
   timeline, so a scroll-driven element can otherwise freeze half-hidden.
   --------------------------------------------------------------------------- */

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

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

  /* Reveal hooks land at final state when motion is reduced (belt + suspenders;
     JS also short-circuits the observer). */
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ===== css/sections/nav.css ===== */
/* =============================================================================
   Nav (.s-nav) — announcement bar + sticky shrink nav + accessible mobile menu.
   Ported from components/layout/Nav/Nav.module.css. All selectors scoped under
   .s-nav. Behavior wired by js/main.js via data hooks:
     [data-nav]            the <nav> that gains .is-scrolled on scroll
     [data-nav-toggle]     hamburger button (aria-expanded toggled)
     [data-nav-panel]      mobile menu dialog (gains .is-open; [hidden] toggled)
     [data-nav-scrim]      click-to-dismiss backdrop (gains .is-open)
     [data-nav-close]      any element that closes the menu (panel links + scrim)
   ============================================================================= */

.s-nav {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
}

/* ---- announcement bar ---- */
.s-nav__announce {
  background-color: var(--c-black);
  color: var(--accent-warm);
}

.s-nav__announce-inner {
  display: flex;
  justify-content: center;
  padding-block: var(--sp-2);
}

.s-nav__announce-text {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  text-align: center;
}

/* ---- sticky nav ---- */
.s-nav__nav {
  background-color: var(--bg);
  border-bottom: var(--bw-hair) solid var(--line);
  --nav-pad: var(--sp-4);
  transition:
    background-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

.s-nav__nav.is-scrolled {
  --nav-pad: var(--sp-3);
  background-color: var(--surface);
  box-shadow: var(--shadow-sm);
  border-bottom-color: transparent;
}

.s-nav__bar {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  padding-block: var(--nav-pad);
  transition: padding-block var(--dur) var(--ease);
}

.s-nav__wordmark {
  display: inline-flex;
  align-items: center;
  flex: none;
}

.s-nav__wordmark-img {
  width: auto;
  height: 1.4rem;
  transition: height var(--dur) var(--ease);
}

.s-nav__nav.is-scrolled .s-nav__wordmark-img {
  height: 1.2rem;
}

/* desktop links — center-left */
.s-nav__links {
  display: none;
  align-items: center;
  gap: var(--sp-5);
  margin: 0;
  list-style: none;
}

.s-nav__link {
  position: relative;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink);
  padding-block: var(--sp-1);
}

/* ink-draw underline on hover */
.s-nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: var(--bw);
  background-color: var(--ink);
  transform: scaleX(0.1);
  transform-origin: left;
  opacity: 0;
  transition:
    transform var(--dur) var(--ease),
    opacity var(--dur) var(--ease);
}

.s-nav__link:hover::after,
.s-nav__link:focus-visible::after {
  transform: scaleX(1.02);
  opacity: 1;
}

/* right cluster */
.s-nav__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-left: auto;
}

.s-nav__micro-label {
  display: none;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
}

.s-nav__shop-link {
  display: none;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: var(--bw-hair);
}

.s-nav__shop-link:hover {
  color: var(--ink-soft);
}

/* the desktop CTA (global .btn .btn--cta .btn--sm) wrapped to control display */
.s-nav__cta {
  display: none;
}

/* ---- mobile toggle (hamburger) ---- */
.s-nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--r-pill);
}

/* When the menu is open the full-screen panel (z-index var(--z-nav)) would
   otherwise paint over this button, intercepting the tap and making the X
   unclickable. Lift the open toggle above the panel so it can close the menu. */
.s-nav__toggle.is-open {
  position: relative;
  z-index: calc(var(--z-nav) + 1);
}

.s-nav__toggle-bars,
.s-nav__toggle-bars::before,
.s-nav__toggle-bars::after {
  display: block;
  width: 1.25rem;
  height: var(--bw-strong);
  background-color: var(--ink);
  border-radius: var(--r-pill);
  transition:
    transform var(--dur) var(--ease),
    opacity var(--dur-fast) var(--ease);
}

.s-nav__toggle-bars {
  position: relative;
}

.s-nav__toggle-bars::before,
.s-nav__toggle-bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.s-nav__toggle-bars::before {
  top: -0.375rem;
}
.s-nav__toggle-bars::after {
  top: 0.375rem;
}

/* open state — toggled by JS via .is-open on the toggle button */
.s-nav__toggle.is-open .s-nav__toggle-bars {
  background-color: transparent;
}
.s-nav__toggle.is-open .s-nav__toggle-bars::before {
  transform: translateY(0.375rem) rotate(45deg);
}
.s-nav__toggle.is-open .s-nav__toggle-bars::after {
  transform: translateY(-0.375rem) rotate(-45deg);
}

/* ---- mobile menu panel ---- */
/* Anchored to the top and sized to its content (not inset:0) so the opaque
   panel no longer blankets the whole viewport over the scrim. The empty area
   below the menu stays the scrim's, keeping click-to-dismiss working. The
   panel still caps at the viewport height and scrolls if its content is tall. */
.s-nav__panel {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  max-height: 100vh;
  z-index: var(--z-nav);
  background-color: var(--bg);
  padding-top: var(--sp-9);
  overflow-y: auto;
  transform: translateY(-8px);
  opacity: 0;
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.s-nav__panel.is-open {
  transform: translateY(0);
  opacity: 1;
}

.s-nav__panel-inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-7);
  padding-block: var(--sp-7);
}

.s-nav__panel-links {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  margin: 0;
  list-style: none;
}

.s-nav__panel-link {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 500;
  color: var(--ink);
}

.s-nav__panel-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  align-items: stretch;
}

.s-nav__panel-shop {
  text-align: center;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.s-nav__scrim {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-nav) - 1);
  background-color: rgba(19, 24, 28, 0.4);
  cursor: pointer;
  border: 0;
  display: none;
}

.s-nav__scrim.is-open {
  display: block;
}

/* ---- desktop layout (>= 840px / 52.5rem) ---- */
@media (min-width: 52.5rem) {
  .s-nav__links {
    display: flex;
  }
  .s-nav__cta {
    display: inline-flex;
  }
  .s-nav__shop-link {
    display: inline-block;
  }
  .s-nav__toggle {
    display: none;
  }
  .s-nav__panel,
  .s-nav__scrim {
    display: none;
  }
}

@media (min-width: 64rem) {
  .s-nav__micro-label {
    display: inline-block;
  }
}

@media (prefers-reduced-motion: reduce) {
  .s-nav__panel,
  .s-nav__toggle-bars,
  .s-nav__toggle-bars::before,
  .s-nav__toggle-bars::after {
    transition: none;
  }
}

/* ===== css/sections/footer.css ===== */
/* =============================================================================
   Footer (.s-footer) — Black surface, muted Oyster disclaimer. 4 cols → stack.
   Ported from components/layout/Footer/Footer.module.css. Selectors scoped under
   .s-footer. Newsletter is a non-interactive stub (action="#"). Disclaimer block
   is VERBATIM (4 footnotes + trademark + copyright).
   ============================================================================= */

.s-footer {
  background-color: var(--dark-bg-2);
  color: var(--dark-ink);
  /* defined top edge so the FinalCTA→Footer beat reads as two dark sections,
     not one continuous black field (mirrors base.css's light-seam hairline) */
  border-block-start: var(--bw-hair) solid var(--line-dark);
  padding-block: var(--sp-8) var(--sp-7);
}

.s-footer__inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-7);
}

/* ---- column grid ---- */
.s-footer__columns {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-7);
}

.s-footer__brand-col {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.s-footer__wordmark {
  width: auto;
  height: 1.5rem;
  /* pin intrinsic ratio + opt out of column align:stretch so the global img
     reset can't draw the wordmark ~2.7x too wide (native PNG is 1468x390) */
  aspect-ratio: 1468 / 390;
  align-self: flex-start;
  /* the wordmark PNG is dark ink — invert toward Parchment on Black */
  filter: brightness(0) invert(1);
  opacity: 1;
  /* lift the wordmark's optical top onto the SHOP/COMPANY/HELP eyebrow
     cap-line so the four columns share one clean top edge */
  margin-block-start: -0.15rem;
}

.s-footer__domain {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  color: var(--dark-ink-soft);
}

.s-footer__tagline {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-body);
  color: var(--dark-ink-soft);
  max-width: 24ch;
  /* keep wordmark+domain tight as one lockup; set the tagline apart */
  margin-top: var(--sp-2);
}

.s-footer__link-col {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

/* col heading uses the global .eyebrow .eyebrow--dark; this just tones it down */
.s-footer__col-heading {
  color: var(--dark-ink-soft);
}

.s-footer__col-links {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: 0;
  list-style: none;
}

.s-footer__col-link {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--dark-ink);
  transition: color var(--dur-fast) var(--ease);
}

.s-footer__col-link:hover {
  color: var(--accent-warm);
}

/* ---- newsletter ---- */
/* full-width section break: the hairline lives on the wrapper border so it
   spans the full container width like the column grid and disclaimer, while
   the inner form/note stay capped at 36rem below. Border width is 100% (not
   100vw): 100vw includes the vertical scrollbar gutter and is anchored inside
   the container gutter, so it overran the content area and forced a page-wide
   horizontal scrollbar at all widths. */
.s-footer__newsletter {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  width: 100%;
  border-block-start: var(--bw-hair) solid var(--line-dark);
  padding-block-start: var(--sp-6);
}

.s-footer__newsletter-label {
  margin-bottom: var(--sp-1);
}

.s-footer__newsletter-form {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  /* cap only the input row (not the wrapper) so the section-break hairline
     above stays full-width while the controls keep their tight measure */
  max-width: 36rem;
}

.s-footer__newsletter-input {
  flex: 1 1 14rem;
  min-width: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--dark-ink);
  background-color: transparent;
  border: var(--bw-hair) solid var(--line-dark);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
}

.s-footer__newsletter-input::placeholder {
  color: var(--dark-ink-soft);
}

.s-footer__newsletter-button {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-body);
  color: var(--cta-fg);
  background-color: var(--cta-bg);
  border-radius: var(--r-pill);
  /* match the input's sp-3 border-box height so the controls share a centerline */
  padding: var(--sp-2) var(--sp-5);
  transition: background-color var(--dur-fast) var(--ease);
}

.s-footer__newsletter-button:hover {
  background-color: var(--cta-bg-hover);
}

.s-footer__newsletter-note {
  font-family: var(--font-sans);
  font-size: var(--fs-meta);
  color: var(--dark-ink-soft);
  max-width: 36rem;
}

/* ---- disclaimer block (verbatim) — capped measure, muted Oyster ---- */
.s-footer__disclaimer {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  max-width: var(--maxw-prose);
  color: var(--dark-ink-soft);
}

.s-footer__disclaimer-heading {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--dark-ink);
}

.s-footer__footnotes {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.s-footer__footnote {
  display: grid;
  grid-template-columns: 0.75rem 1fr;
  gap: var(--sp-1);
  font-size: var(--fs-meta);
  line-height: var(--lh-snug);
  font-style: italic;
}

.s-footer__footnote-mark {
  font-style: normal;
  color: var(--dark-ink);
}

.s-footer__trademark,
.s-footer__copyright {
  font-size: var(--fs-meta);
  line-height: var(--lh-snug);
}

.s-footer__copyright {
  color: var(--dark-ink);
}

/* ---- responsive columns ---- */
@media (min-width: 40rem) {
  .s-footer__columns {
    grid-template-columns: 1.6fr 1fr 1fr 1fr;
    gap: var(--sp-6);
  }
  .s-footer__footnote {
    grid-template-columns: 0.75rem 1fr;
  }
}

/* ===== css/sections/chrome.css ===== */
/* =============================================================================
   Chrome — StickyCTA (.s-sticky) + ExitIntentModal (.s-modal).
   Ported from components/layout/StickyCTA + ExitIntentModal *.module.css.
   Both are hidden by default and revealed by js/main.js via data hooks:
     [data-sticky-cta]  the mobile bottom bar (gains .is-visible when hero leaves)
     [data-exit-modal]  the exit-intent overlay (gains .is-open on exit intent)
     [data-exit-close]  any dismiss control (backdrop / × / "No thanks" / Esc)
     [data-exit-form]   the email capture form (swaps to the success state)
     [data-exit-default]/[data-exit-success]  the two body states
   ============================================================================= */

/* ---------------------------------------------------------------------------
   StickyCTA — mobile-only sticky bottom Subscribe bar. Hidden on desktop.
   --------------------------------------------------------------------------- */
.s-sticky {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: var(--z-sticky);
  padding: var(--sp-3) var(--gutter)
    calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  background-color: var(--surface);
  border-top: var(--bw-hair) solid var(--line);
  box-shadow: var(--shadow-lg);
  /* hidden state — slid off-screen, transform-safe */
  transform: translateY(110%);
  transition: transform var(--dur-slow) var(--ease);
}

.s-sticky.is-visible {
  transform: translateY(0);
}

/* Desktop: never show the mobile sticky bar. */
@media (min-width: 52.5rem) {
  .s-sticky {
    display: none;
  }
}

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

/* ---------------------------------------------------------------------------
   ExitIntentModal — tasteful fade-in-up email capture. Hidden by default
   ([hidden] removed by JS when opening; .is-open present while shown).
   --------------------------------------------------------------------------- */
.s-modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--gutter);
}

.s-modal[hidden] {
  display: none;
}

.s-modal__backdrop {
  position: absolute;
  inset: 0;
  background-color: rgba(19, 24, 28, 0.55);
  cursor: pointer;
  border: 0;
  /* fade the scrim in */
  animation: aforeBackdropIn var(--dur) var(--ease);
}

@keyframes aforeBackdropIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.s-modal__dialog {
  position: relative;
  width: min(28rem, 100%);
  background-color: var(--surface);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--sp-7) var(--sp-6) var(--sp-6);
}

/* fade-in-up — JS adds .animate only when motion is allowed. */
.s-modal__dialog.animate {
  animation: aforeDialogIn var(--dur-slow) var(--ease);
}

@keyframes aforeDialogIn {
  from {
    opacity: 0;
    transform: translateY(15%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.s-modal__close {
  position: absolute;
  top: var(--sp-3);
  right: var(--sp-3);
  width: 2.25rem;
  height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-h4);
  line-height: 1;
  color: var(--ink-soft);
  border-radius: var(--r-pill);
  transition: background-color var(--dur-fast) var(--ease);
}

.s-modal__close:hover {
  background-color: var(--bg-alt);
}

.s-modal__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  text-align: center;
}

/* hide whichever state is not active (JS toggles [hidden]) */
.s-modal__body[hidden] {
  display: none;
}

.s-modal__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
}

.s-modal__heading {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h3);
  line-height: var(--lh-head);
  color: var(--ink);
}

.s-modal__text {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink-soft);
}

.s-modal__form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
}

.s-modal__input {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--ink);
  background-color: var(--bg);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  text-align: center;
}

.s-modal__input::placeholder {
  color: var(--ink-mute);
}

.s-modal__dismiss {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--ink-mute);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  margin-top: var(--sp-1);
}

.s-modal__dismiss:hover {
  color: var(--ink-soft);
}

@media (prefers-reduced-motion: reduce) {
  .s-modal__backdrop,
  .s-modal__dialog,
  .s-modal__dialog.animate {
    animation: none;
  }
}

/* ===== css/sections/hero.css ===== */
/* =============================================================================
   Hero — golden-hour opener (STATIC PORT of components/sections/Hero/Hero.module.css).
   Parchment + warm light-field, 7/5 broken grid, bottle bleeding off the right,
   cursor-tracked specular highlight, mouse parallax, on-load fade-up stagger.

   Scoping: EVERY selector is nested under .s-hero so the concatenated stylesheet
   never collides with other sections. Keyframes stay global but are prefixed
   `hero-` (hero-golden-drift). All colour/space/type/radius/motion values are
   var(--token) verbatim; grid line numbers, viewport units, percentages and
   unitless transform multipliers are layout math, not design-token values.

   The Next <HeroReveal> client wrapper maps to .s-hero .stage[data-hero-light];
   it owns the --mx/--my/--px/--py vars and the [data-ready] stagger gate, both
   written by js/main.js (fine-pointer + motion-allowed only).
   ============================================================================= */

.s-hero {
  position: relative;
  background-color: var(--bg);
  /* The bottle bleeds off the right edge — clip it to the section. */
  overflow: hidden;
  isolation: isolate;
}

/* The client root from HeroReveal. Holds the pointer/parallax CSS vars and
   carries section vertical rhythm. */
.s-hero .stage {
  position: relative;
  display: block;
  /* parallax + specular var defaults — static (centred / neutral) until the
     fine-pointer effect overrides them in JS. */
  --mx: 0.5;
  --my: 0.5;
  --px: 0;
  --py: 0;
  /* Tighter than a standard section beat so the opener reads as one cohesive
     viewport rather than a tall, sparse band. */
  padding-block: clamp(2.25rem, 4vw, 4.5rem);
  /* lift content above the light-field */
  z-index: var(--z-grain);
}

/* -----------------------------------------------------------------------------
   Golden-hour light-field — 3 low-opacity warm radials over flat Parchment.
   The ONE sanctioned gradient (light, not section colour). Drifts on a 14s loop
   for fine-motion users only. Sits behind everything in the section.
   ----------------------------------------------------------------------------- */
.s-hero .goldenField {
  position: absolute;
  inset: calc(-1 * var(--sp-8));
  z-index: -1;
  pointer-events: none;
  background-image:
    /* Cadmium "sun", top-right */
    radial-gradient(
      42% 46% at 82% 12%,
      color-mix(in srgb, var(--c-cadmium) 34%, transparent),
      transparent 70%
    ),
    /* Golden-Hour, mid-left */
    radial-gradient(
      46% 52% at 14% 46%,
      color-mix(in srgb, var(--c-golden-hour) 28%, transparent),
      transparent 72%
    ),
    /* Ochre "floor", bottom-centre */
    radial-gradient(
      60% 44% at 62% 96%,
      color-mix(in srgb, var(--c-ochre) 22%, transparent),
      transparent 76%
    );
  transform: translate3d(0, 0, 0) scale(1);
  will-change: transform;
}

@media (prefers-reduced-motion: no-preference) {
  .s-hero .goldenField {
    animation: hero-golden-drift 14s var(--ease-in-out) infinite alternate;
  }
}

@keyframes hero-golden-drift {
  from {
    transform: translate3d(-1.5%, -1%, 0) scale(1.02);
  }
  to {
    transform: translate3d(1.5%, 1.5%, 0) scale(1.06);
  }
}

/* -----------------------------------------------------------------------------
   Layout — 12-col editorial grid, 7/5 asymmetry. Copy cols 2–7, media cols 8–13.
   ----------------------------------------------------------------------------- */
.s-hero .inner {
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: center;
  column-gap: var(--gutter);
  row-gap: var(--sp-8);
}

/* ----- Copy cluster: lower-left, cols 2–7 ----- */
.s-hero .copy {
  /* Hug the container's left edge so the copy lines up with the nav wordmark
     (no extra column of indent) and the composition spans edge-to-edge. */
  grid-column: 1 / 7;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* Vertically centered against the bottle so neither column floats with a big
     empty band above or below it. */
  align-self: center;
}

.s-hero .eyebrow {
  margin-bottom: var(--sp-5);
}

/* Scoped under .copy so it wins over .section-heading's own --h1 size regardless
   of stylesheet order — the hero head reads at display scale. */
.s-hero .copy .heading {
  /* Sized so each of the two sentences fits on ONE line — a clean two-line
     headline. (The default --fs-display hit 120px and stacked into 4 lines that
     overflowed; an 80px pass broke mid-sentence as "...body. Support...".) */
  font-size: clamp(2.25rem, 0.5rem + 3vw, 3.25rem);
  line-height: var(--lh-display);
  margin-bottom: var(--sp-4);
}

/* Break the headline at the sentence boundary: the italic 2nd sentence drops to
   its own line rather than wrapping mid-sentence. */
.s-hero .copy .heading em {
  display: block;
  font-style: italic;
}

/* Keep the body copy at a comfortable reading measure even though .copy itself
   is no longer measure-capped. */
.s-hero .subhead,
.s-hero .efficacy {
  max-width: 52ch;
}

.s-hero .subhead {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--ink);
  /* Slightly more breathing room before the small muted efficacy line so it
     doesn't read as crowded against the larger subhead above it. */
  margin: 0 0 var(--sp-5);
  max-width: 56ch;
}

.s-hero .efficacy {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--ink-soft);
  margin: 0 0 var(--sp-6);
  max-width: 56ch;
}

.s-hero .ctas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-5);
}

.s-hero .microcopy {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: 0 0 var(--sp-6);
}

.s-hero .badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ----- Media cluster: cols 7–13, hugging the right ----- */
.s-hero .media {
  position: relative;
  grid-column: 7 / 13;
  grid-row: 1;
  align-self: center;
  display: flex;
  justify-content: flex-end;
  /* Bleed well past the container's right gutter toward the viewport edge so the
     bottle's right side actually runs off-screen (clipped by the section's
     overflow:hidden) instead of floating with an empty parchment band beside it. */
  margin-right: calc(-1 * (var(--gutter) + var(--sp-7)));
  min-height: 0;
}

.s-hero .bottleParallax {
  position: relative;
  /* Shrink-wrap to the bottle's actual box (capped by .bottleFrame) so the
     absolutely-positioned accents (capsule mark, stat card) anchor to the glass
     instead of the much-wider media cell — keeps them hugging the bottle. */
  width: 100%;
  max-width: 35rem;
  /* parallax: bottle moves slow (heavy). Driven by --px/--py from the pointer. */
  transform: translate3d(
    calc(var(--px) * var(--parallax-bottle, 10px)),
    calc(var(--py) * var(--parallax-bottle, 10px)),
    0
  );
  transition: transform var(--dur-slow) var(--ease);
  will-change: transform;
}

.s-hero .bottleFrame {
  position: relative;
  width: 100%;
  /* Sized to fill the media cell and cross the right gutter so the glass reaches
     /bleeds the right edge (with the section's overflow:hidden clipping the
     overshoot) rather than floating inside the cell. */
  max-width: 35rem;
  margin-left: auto;
  /* Reserve headroom under the base cap so ONLY the right side bleeds — the
     bottle's base stays clear of the section's bottom edge instead of clipping. */
  margin-bottom: var(--sp-8);
}

.s-hero .bottle {
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
  /* Background-knockout cutout (transparent PNG) so the bottle sits on the
     parchment on ANY backdrop — no white box, and no backdrop-dependent blend
     (multiply only dissolved the white over warm areas, leaving a box on the
     lighter mobile gradient). A soft shadow grounds it. */
  filter: drop-shadow(0 22px 34px rgba(19, 24, 28, 0.17));
}

/* Cursor-tracked specular highlight raking the glass. soft-light blend so it
   reads as a studio softbox, never a flat overlay. Centred when idle. */
.s-hero .spotlight {
  position: absolute;
  /* Extend the glow layer WELL beyond the bottle box (the bottle occupies the
     centre 25%..75% of this oversized element) so the radial gradient always
     fades to transparent BEFORE the element's own edges. That removes the hard
     rectangular cut-off that traced the frame box, and lets the glow bleed
     smoothly off the glass. No ancestor clips this (frame/parallax have no
     overflow); only the section's far overflow:hidden bounds it. */
  inset: -50%;
  z-index: 1;
  pointer-events: none;
  mix-blend-mode: soft-light;
  opacity: 0;
  /* --mx/--my are 0..1 across the BOTTLE (set by JS from the bottle box); remap
     into this 2x element's centre band. A soft two-stop falloff (bright core ->
     mid tint -> transparent) keeps the edge feathered, never a visible ring. */
  background: radial-gradient(
    17% 14% at calc(25% + var(--mx) * 50%) calc(25% + var(--my) * 50%),
    color-mix(in srgb, var(--c-cadmium) 62%, var(--c-parchment)) 0%,
    color-mix(in srgb, var(--c-cadmium) 30%, var(--c-parchment)) 40%,
    transparent 72%
  );
  /* Fade OUT quickly (dur-fast) the moment the cursor leaves the bottle so the
     glow doesn't linger; fade IN is overridden to the smoother dur on :hover. */
  transition: opacity var(--dur-fast) var(--ease);
}

/* Capsule mark — light/quick parallax layer, floating near the bottle top-left. */
.s-hero .capsuleFloat {
  position: absolute;
  /* Drop onto the flat shoulder glass BELOW the dropper bulb rather than the
     narrow dark dropper neck, so the mark rests cleanly on glass instead of
     colliding with / half-occluded by the dropper. */
  top: var(--sp-10);
  /* The parallax box is the full 35rem frame but the visible glass is narrower
     and right-aligned (margin-left:auto on .bottleFrame), so a left near the
     box's left edge stranded the mark out in the gutter. Push it ~33% in so it
     clears the dropper neck and rests on the broader shoulder glass to the left
     of the bulb instead of overlapping it. */
  left: clamp(30%, 33%, 36%);
  z-index: 2;
  color: var(--accent-metal);
  transform: translate3d(
    calc(var(--px) * var(--parallax-capsule, 26px)),
    calc(var(--py) * var(--parallax-capsule, 26px)),
    0
  );
  transition: transform var(--dur) var(--ease);
  will-change: transform;
}

.s-hero .capsule {
  display: block;
  width: var(--sp-7);
  height: auto;
  opacity: 0.9;
  filter: drop-shadow(var(--shadow-sm));
}

/* Small clinical stat card overlapping the bottle's bottom-left corner. Anchored
   to .bottleParallax (the shrink-wrapped bottle box), so the negative left pulls
   it onto the glass's bottom-left rather than into the dead gutter. The bottom
   offset matches .bottleFrame's headroom margin so the card hugs the bottle base,
   not the reserved space beneath it. */
.s-hero .statCard {
  position: absolute;
  left: calc(-1 * var(--sp-6));
  /* Raise the card so its body overlaps the bottle's lower-left glass corner.
     One step above .bottleFrame's headroom margin so the card's lowest sliver
     (the "P<.0001" line + bottom padding) ends on the glass rather than drifting
     past the silver base onto bare parchment. (A margin-top lift has no effect on
     an absolutely-positioned box anchored by `bottom`, so the offset lives here.) */
  bottom: var(--sp-9);
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-5);
  background-color: var(--surface);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  max-width: 15rem;
}

.s-hero .statValue {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h4);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
}

.s-hero .statLabel {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  /* Cadmium is a fill, never text on cream — use Cadmium-numeral discipline only
     on dark. Here the stat label is a clinical caption in secondary ink. */
  color: var(--ink-soft);
}

/* -----------------------------------------------------------------------------
   On-load staggered fade-up. The fragment markup === pre-animation state
   (opacity:0, translateY). The transition is gated on [data-ready] (set by JS
   after first paint) so it never fires on first paint; the stagger is per-item.
   ----------------------------------------------------------------------------- */
.s-hero .revealItem {
  opacity: 0;
  transform: translateY(var(--sp-5));
  transition:
    opacity var(--dur-slower) var(--ease),
    transform var(--dur-slower) var(--ease);
  will-change: transform, opacity;
}

.s-hero .stage[data-ready="true"] .revealItem {
  opacity: 1;
  transform: none;
}

/* Stagger eyebrow → H1 → sub → efficacy → CTAs → microcopy → badges, plus the
   stat card last. Delays use the motion duration tokens via calc fractions. */
.s-hero .stage[data-ready="true"] .eyebrow {
  transition-delay: 0ms;
}
.s-hero .stage[data-ready="true"] .heading {
  transition-delay: var(--dur-fast);
}
.s-hero .stage[data-ready="true"] .subhead {
  transition-delay: var(--dur);
}
.s-hero .stage[data-ready="true"] .efficacy {
  transition-delay: calc(var(--dur) + var(--dur-fast));
}
.s-hero .stage[data-ready="true"] .ctas {
  transition-delay: var(--dur-slow);
}
.s-hero .stage[data-ready="true"] .microcopy {
  transition-delay: calc(var(--dur-slow) + var(--dur-fast));
}
.s-hero .stage[data-ready="true"] .badges {
  transition-delay: var(--dur-slower);
}
.s-hero .stage[data-ready="true"] .statCard {
  transition-delay: var(--dur-slower);
}

/* The spotlight only fades in once interactive + fine pointer (idle opacity:0).
   Gate the glow to the BOTTLE BOX itself (.bottleFrame) — not the whole media
   column — so the moment the cursor leaves the bottle's border the glow fades
   out (instead of clamping at the edge and lingering across the empty cell).
   Fade IN uses the smoother --dur; fade OUT uses --dur-fast (base rule). */
@media (hover: hover) and (pointer: fine) {
  .s-hero .bottleFrame:hover .spotlight {
    opacity: 1;
    transition: opacity var(--dur) var(--ease);
  }
}

/* -----------------------------------------------------------------------------
   Responsive — collapse the 7/5 grid to a single column; bottle below copy.
   ----------------------------------------------------------------------------- */
@media (max-width: 64rem) {
  .s-hero .copy {
    grid-column: 2 / 12;
    grid-row: 1;
  }
  .s-hero .media {
    /* Stack BELOW the copy (its own row) instead of sharing row 1 — otherwise the
       (now background-free) bottle overlaps the copy text. */
    grid-column: 2 / 12;
    grid-row: 2;
    justify-content: center;
    margin-right: calc(-1 * var(--gutter));
    margin-left: auto;
    max-width: 30rem;
  }
}

@media (max-width: 40rem) {
  .s-hero .inner {
    row-gap: var(--sp-7);
  }
  .s-hero .copy,
  .s-hero .media {
    grid-column: 1 / 13;
  }
  .s-hero .media {
    margin-right: 0;
    margin-left: 0;
    margin-inline: auto;
    max-width: 22rem;
  }
  .s-hero .copy .heading {
    font-size: var(--fs-h1);
  }
  .s-hero .statCard {
    left: 0;
    max-width: 13rem;
    padding: var(--sp-3) var(--sp-4);
  }
  .s-hero .capsuleFloat {
    left: 0;
  }
}

/* -----------------------------------------------------------------------------
   Reduced motion — kill drift / parallax / stagger transitions, land final.
   Reset animation-timeline per build-plan (shorthand doesn't reset it).
   ----------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .s-hero .goldenField {
    animation: none;
    animation-timeline: auto;
    transform: none;
  }
  .s-hero .bottleParallax,
  .s-hero .capsuleFloat {
    transform: none;
    transition: none;
  }
  .s-hero .spotlight {
    opacity: 0;
    transition: none;
  }
  .s-hero .revealItem {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ===== css/sections/trust.css ===== */
/* =============================================================================
   TrustStrip (.s-trust) — Parchment proof strip. Centered, monochrome,
   hairline-ruled. Ported from components/sections/TrustStrip/TrustStrip.module.css.
   ALL selectors scoped under .s-trust. Every color/space/type/radius value is a
   var(--token) — no raw hex/px. The eyebrow uses the GLOBAL .eyebrow atom; the
   reveal uses the GLOBAL [data-reveal]/.is-visible hooks (NOT re-declared here).
   ============================================================================= */

/* .section → the <section> itself. Parchment surface (section 2 in the
   alternation rhythm). Hairline rules top + bottom give the strip its frame.
   Generous halo above + below the single content cluster. */
.s-trust {
  background: var(--bg);
  color: var(--ink);
  border-block: var(--bw-hair) solid var(--line);
  /* Tighter than a full section: this is a quick proof drumbeat, not a beat
     that should open a void under the hero. */
  padding-block: clamp(2.5rem, 5vw, 4.5rem);
}

.s-trust .inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-5);
  /* Wide enough that the five credential chips breathe across 2 tidy rows
     instead of cramming a prose column and orphaning words. */
  max-width: min(64rem, 100%);
  margin-inline: auto;
}

/* Credential wall — centered flex-wrap of discrete chips. Each chip is one
   self-contained unit, so the row can never orphan a word mid-credential. */
.s-trust .row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: center;
  /* Width tuned so the five chips settle into a tidy 1 / 2 / 2 pyramid: the long
     marquee journal chip sits alone up top, then the two mid pairs wrap two-up
     (measured pair widths ~816px and ~981px both fit under this cap, while the
     long chips still can't pair with the marquee). Reads as a credential wall,
     not a tall single-column ladder. */
  max-width: 63rem;
  margin-inline: auto;
  /* Snug the wrapped capsules so the five read as one deliberate centered list
     rather than a tall ladder of wide lone rows; the wider column-gap is kept
     so any two short chips that do share a row read as a deliberate two-up. */
  row-gap: var(--sp-3);
  column-gap: var(--sp-4);
  margin-block: 0;
  padding: 0;
  list-style: none;
}

/* Credential chip = hairline capsule lifted just off the parchment, monochrome
   mono caption inside. The capsule motif rides as a leading mark via ::before. */
.s-trust .credential {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Leading capsule mark — the brand pill motif drawn as a tiny outlined capsule,
   tinted metal so it reads as a quiet credential bullet. */
.s-trust .credential::before {
  content: "";
  flex: none;
  width: 0.6em;
  height: 0.9em;
  border: var(--bw-strong) solid var(--accent-metal);
  /* Metal tint inside the outline so the capsule reads as an intentional brand
     bullet — crisp enough at the eyebrow scale not to be mistaken for a stray
     glyph or a faint vertical sliver before the text. */
  background: color-mix(in oklab, var(--accent-metal) 24%, transparent);
  border-radius: var(--r-pill);
}

/* Chips are self-contained; the inline SVG separators are no longer needed. */
.s-trust .separator {
  display: none;
}

.s-trust .mark {
  display: block;
  width: 1em;
  height: 1em;
}

/* Newsreader-italic sub-line, muted — the editorial register answering the
   mono eyebrow. */
.s-trust .subline {
  margin: 0;
  /* Tighten the subline toward the chip cluster so it reads as the editorial
     caption answering the proof wall rather than a detached line floating
     below it. The .inner gap is --sp-5; this negative offset lands the
     effective row→subline spacing near --sp-4, matching the internal tier
     rhythm without touching the eyebrow→row gap. */
  margin-top: calc(-1 * (var(--sp-5) - var(--sp-4)));
  max-width: var(--maxw-prose);
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-tight);
  color: var(--ink-mute);
  text-wrap: balance;
}

/* On the narrowest screens, hide the inline pill-mark separators so the
   credential row stacks cleanly without orphaned bullets between wrapped lines.
   The credentials themselves remain centered and legible. */
@media (max-width: 36rem) {
  .s-trust .row {
    flex-direction: column;
    gap: var(--sp-3);
  }

  .s-trust .separator {
    display: none;
  }
}

/* ===== css/sections/problem.css ===== */
/* =============================================================================
   ProblemEducation — section 3 (creative-direction §3.3) — STATIC PORT
   Parchment beat. Large-vs-small asymmetry (oversized pull-stat ↔ tight body),
   5 NON-uniform cards on a 12-col grid (baseline-locked via subgrid), and a
   compliant "WHY IT HAPPENS" explainer. Every value references a var(--token).
   Ported from components/sections/ProblemEducation/ProblemEducation.module.css;
   ALL selectors scoped under .s-problem to avoid collisions when concatenated.
   ============================================================================= */

.s-problem {
  background-color: var(--bg);
  color: var(--ink);
  padding-block: var(--section-y);
  /* Anchor offset so the sticky nav doesn't cover the heading on jump. */
  scroll-margin-top: var(--sp-8);
}

.s-problem .inner {
  display: flex;
  flex-direction: column;
  /* --sp-8 (not --sp-9): the feature row's short stat column bottoms out well
     above the tall body column, so an --sp-9 gap on top of that empty zone made
     the band before the cards read as a floating void with the numeral dangling.
     Tightened to pull the cards up under the numeral; the explainer's deliberate
     halo is restored via its own margin-top below. */
  gap: var(--sp-8);
}

/* ---- Heading cluster — constrained measure, lower-left editorial anchor ---- */

.s-problem .head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.s-problem .heading {
  /* Measure set HERE (ch resolves against the 52px display font, ≈ 936px) so the
     long headline reads as a clean ~3-line block — not on .head, where ch would
     resolve against the small body font and throttle it. */
  max-width: 36ch;
  text-wrap: pretty;
  overflow-wrap: normal;
  hyphens: none;
}

/* ---------------------------------------------------------------------------
   Feature row — the large-vs-small asymmetry.
   12-col grid: pull-stat occupies cols 1–7 (the oversized drama, flush to the
   left spine), the tight body block occupies cols 9–13. Each lands in its own
   whitespace halo.
   --------------------------------------------------------------------------- */

.s-problem .feature {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--gutter);
  row-gap: var(--sp-7);
  /* Top-align the columns so the numeral's top meets the body paragraph's top
     instead of sinking to the row's baseline (which left a large empty upper
     quadrant above the short stat block). */
  align-items: start;
}

.s-problem .pullStat {
  /* Start at col 1 so the +5,000% numeral shares the page's left spine with the
     eyebrow, headline, cards and explainer (was 2/9, which floated the section's
     strongest element ~1 track right of every other left-flush element). */
  grid-column: 1 / 8;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.s-problem .pullStatValue {
  font-family: var(--font-display);
  /* Oversized display numeral — sits between --fs-display and a touch larger. */
  font-size: var(--fs-display);
  font-weight: 500;
  line-height: var(--lh-display);
  letter-spacing: var(--tr-tight);
  /* Ink, NOT Cadmium: Cadmium fails as text on cream (1.51:1). The scale is the
     drama; the warmth comes from the section, not an illegible numeral. */
  color: var(--ink);
  /* Tabular figures so the count-up doesn't reflow width as digits change. */
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.s-problem .pullStatCaption {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: var(--tr-eyebrow);
  /* Bumped from --fs-eyebrow and softened ink → full ink so the caption clearly
     anchors the giant numeral instead of nearly vanishing beneath it. */
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--ink);
  max-width: 28ch;
  margin: 0;
}

.s-problem .bodyBlock {
  /* Start at col 8 (was 9) to close the empty col-8 corridor between the
     pull-stat's right edge and the body's left edge; max-width: 42ch on .body
     keeps the measure readable so the asymmetry reads as a deliberate pairing. */
  grid-column: 8 / 13;
  /* Both columns top-align now (.feature align-items:start), so nudge the body
     down slightly to read against the cap height of the giant numeral. */
  padding-top: var(--sp-2);
}

.s-problem .body {
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--ink);
  text-wrap: pretty;
  margin: 0;
  max-width: 42ch;
}

/* ---------------------------------------------------------------------------
   The 5 "what you may be seeing" cards — NON-uniform spans, baseline-locked.
   6-col grid: row 1 = three 2-col cards, row 2 = two 3-col cards. Cards are
   subgrid so icon / label / line rows align across the row (baseline lock).
   --------------------------------------------------------------------------- */

.s-problem .cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  /* Split gap so the row gap (--sp-6 = card interior padding) is at least equal
     to the column gutter; an --sp-5 row gap read tighter than the cards' own
     --sp-6 padding, an inverted rhythm that crowded the two rows vertically. */
  column-gap: var(--sp-5);
  row-gap: var(--sp-6);
}

.s-problem .card {
  /* subgrid the shared rows so the three card "lines" baseline-align. */
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;
  align-content: start;
  gap: var(--sp-3);
  padding: var(--sp-6);
  background-color: var(--surface);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
}

/* Uniform 2-col cards in a centered 3-over-2 pyramid: row 1 = three 2-col cards
   (cols 1/3/5), row 2 = two 2-col cards centered under the trio (cols 2 and 4).
   Equal ~213px width across both rows lets the copy fill each card the way it
   already does in row 1, instead of stranding it in a half-section-wide card. */
.s-problem .card:nth-child(1) {
  grid-column: span 2;
}
.s-problem .card:nth-child(2) {
  grid-column: span 2;
}
.s-problem .card:nth-child(3) {
  grid-column: span 2;
}
.s-problem .card:nth-child(4) {
  grid-column: 2 / span 2;
}
.s-problem .card:nth-child(5) {
  grid-column: 4 / span 2;
}

.s-problem .cardIcon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sp-6);
  height: var(--sp-6);
  /* Glyph (1em SVG) sized to sit with comfortable padding inside the 32px pill;
     --fs-h4 clamped up to ~26px and crowded/clipped the inner diameter. */
  font-size: var(--fs-body);
  color: var(--accent-metal);
  border: var(--bw) solid var(--line);
  border-radius: var(--r-pill);
}

.s-problem .cardLabel {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: var(--tr-eyebrow);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--ink);
  margin: 0;
}

.s-problem .cardLine {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
  margin: 0;
}

/* ---- Staggered scroll-reveal (driven by the [data-problem-reveal] hook) ----
   Server/no-JS HTML === pre-animation from-state, so no FOUC. main.js adds
   .is-ready on mount to gate the transition on, then .is-in once the <ul>
   enters the viewport to land the final state. Stagger via the per-card
   --reveal-i set inline on each <li>. Transform/opacity only. */

.s-problem .card {
  opacity: 0;
  transform: translateY(24px) scale(0.97);
}

.s-problem .cards.is-ready .card {
  transition-property: transform, opacity;
  transition-duration: var(--dur-slower);
  transition-timing-function: var(--ease);
  transition-delay: calc(var(--reveal-i, 0) * 90ms);
  will-change: transform, opacity;
}

.s-problem .cards.is-in .card {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ---------------------------------------------------------------------------
   WHY IT HAPPENS — the compliant educational explainer.
   Sits in its own whitespace halo, narrow reading measure, hairline rule above.
   --------------------------------------------------------------------------- */

.s-problem .explainer {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: var(--maxw-prose);
  /* Bump the explainer's leading whitespace back up after the global .inner gap
     was tightened to --sp-8, preserving this beat's deliberate breathing room. */
  margin-top: var(--sp-5);
  padding-top: var(--sp-7);
  border-top: var(--bw-hair) solid var(--line);
}

.s-problem .explainerEyebrow {
  color: var(--ink-soft);
}

.s-problem .explainerBody {
  font-family: var(--font-sans);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--ink);
  text-wrap: pretty;
  margin: 0;
}

.s-problem .explainerCta {
  margin: 0;
  margin-top: var(--sp-2);
}

/* ---------------------------------------------------------------------------
   Responsive — collapse the asymmetric grids on smaller viewports.
   --------------------------------------------------------------------------- */

@media (max-width: 60rem) {
  .s-problem .feature {
    grid-template-columns: 1fr;
    align-items: start;
  }
  .s-problem .pullStat,
  .s-problem .bodyBlock {
    grid-column: 1 / -1;
  }
  .s-problem .bodyBlock {
    padding-top: 0;
  }
  .s-problem .cards {
    grid-template-columns: repeat(4, 1fr);
  }
  /* Two-up: first four cards span 2, the fifth spans the full row. */
  .s-problem .card:nth-child(1),
  .s-problem .card:nth-child(2),
  .s-problem .card:nth-child(3),
  .s-problem .card:nth-child(4) {
    grid-column: span 2;
  }
  .s-problem .card:nth-child(5) {
    grid-column: span 4;
  }
}

@media (max-width: 38rem) {
  .s-problem .inner {
    gap: var(--sp-8);
  }
  .s-problem .cards {
    grid-template-columns: 1fr;
    gap: var(--sp-4);
  }
  .s-problem .card {
    /* Single column: subgrid row-spanning no longer needed; each card is its own. */
    grid-template-rows: auto auto auto;
    grid-row: auto;
  }
  .s-problem .card:nth-child(1),
  .s-problem .card:nth-child(2),
  .s-problem .card:nth-child(3),
  .s-problem .card:nth-child(4),
  .s-problem .card:nth-child(5) {
    grid-column: 1 / -1;
  }
}

/* ---------------------------------------------------------------------------
   Reduced motion — belt-and-suspenders with the JS guard + global block.
   Land cards at final state; never leave one frozen half-hidden.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .s-problem .card {
    opacity: 1;
    transform: none;
  }
  .s-problem .cards.is-ready .card {
    transition: none;
  }
}

/* ===== css/sections/product.css ===== */
/* =============================================================================
   PRODUCT (.s-product, id="science") — static port of ProductExplainer.module.css
   + folded Ingredients. DARK Deep-Olive beat (dark beat #1). Every selector is
   scoped under .s-product to survive concatenation; keyframes are global but
   prefixed `product-`. Every color/space/type/radius/motion value references a
   var(--token), verbatim from the source module.
   On dark: body = Parchment (--dark-ink); emphasis = Cadmium (--accent-warm,
   5.49:1 on Deep Olive — passes). Ticks on the DermaReverse column = Cadmium.
   ============================================================================= */

.s-product {
  position: relative;
  isolation: isolate;
  overflow: hidden; /* clip the edge-bleeding box image */
  background-color: var(--dark-bg); /* Deep Olive */
  color: var(--dark-ink); /* Parchment */
  padding-block: var(--section-y);
}

/* A hairline top rule (the deck's section-label device, dark variant). */
.s-product::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: var(--bw-hair);
  background-color: var(--line-dark);
}

.s-product .inner {
  position: relative;
  z-index: 1; /* content above the bleed image */
}

/* sr-only — accessible caption / headings hidden visually. */
.s-product .srOnly {
  position: absolute;
  width: var(--bw-hair);
  height: var(--bw-hair);
  padding: 0;
  margin: calc(-1 * var(--bw-hair));
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* -----------------------------------------------------------------------------
   Product shot — bleeds in from the RIGHT edge, mask/clip reveal on enter.
   Decorative (aria-hidden); the box also appears as Ochre, tying to --accent.
   ----------------------------------------------------------------------------- */
.s-product .bleed {
  position: absolute;
  z-index: 0;
  /* Anchor to the TOP-right band — the genuinely empty space beside the intro
     heading + comparison table. (Full-height + centered would drop the box onto
     the actives grid, where the bright box bleeds through the translucent cards
     and collides with the right-column active.) */
  inset-block-start: 0;
  inset-block-end: auto;
  inset-inline-end: 0;
  /* Narrower footprint + a deeper off-edge pull (see boxImg translateX) keep the
     loud baked-in horizontal wordmark out of frame, so only the carton silhouette
     bleeds in as a decorative element rather than a second mid-section brandmark. */
  inline-size: clamp(16rem, 30vw, 26rem);
  pointer-events: none;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
}

.s-product .bleedInner {
  position: relative;
  inline-size: 100%;
  /* Feather ALL exposed edges so the opaque rectangular photo (gold carton on a
     rocky background — not a transparent cut-out) never shows a hard boundary
     against the flat Deep-Olive panel. Left fade dissolves toward the type
     column; the second gradient softens the top + bottom rock edges. The two
     are intersected so the box reads as bleeding into the section, not pasted. */
  -webkit-mask-image: linear-gradient(
      to left,
      rgba(0, 0, 0, 1) 70%,
      rgba(0, 0, 0, 0) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, 1) 12% 86%,
      rgba(0, 0, 0, 0) 100%
    );
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(
      to left,
      rgba(0, 0, 0, 1) 70%,
      rgba(0, 0, 0, 0) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, 1) 12% 86%,
      rgba(0, 0, 0, 0) 100%
    );
  mask-composite: intersect;
}

.s-product .boxImg {
  display: block;
  inline-size: 100%;
  block-size: auto;
  object-fit: contain;
  /* translate off the right edge so it "bleeds in" — pulled deeper so the loud
     baked-in horizontal wordmark clips off-frame and only the carton shows */
  transform: translateX(28%);
  filter: drop-shadow(var(--shadow-lg));
  opacity: 0.92;
}

/* Mask/clip reveal on section enter — CSS scroll-driven, compositor-only.
   @property animation reveals from the right edge as the section scrolls in. */
@property --product-pe-reveal {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .s-product .bleedInner {
      animation: product-box-reveal linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 38%;
      -webkit-mask-image: linear-gradient(
          to left,
          rgba(0, 0, 0, 1) var(--product-pe-reveal),
          rgba(0, 0, 0, 0) 100%
        ),
        linear-gradient(
          to bottom,
          rgba(0, 0, 0, 0) 0%,
          rgba(0, 0, 0, 1) 12% 86%,
          rgba(0, 0, 0, 0) 100%
        );
      -webkit-mask-composite: source-in;
      mask-image: linear-gradient(
          to left,
          rgba(0, 0, 0, 1) var(--product-pe-reveal),
          rgba(0, 0, 0, 0) 100%
        ),
        linear-gradient(
          to bottom,
          rgba(0, 0, 0, 0) 0%,
          rgba(0, 0, 0, 1) 12% 86%,
          rgba(0, 0, 0, 0) 100%
        );
      mask-composite: intersect;
    }
    .s-product .boxImg {
      animation: product-box-drift linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 38%;
    }
  }
}

@keyframes product-box-reveal {
  from {
    --product-pe-reveal: 100%;
  }
  to {
    --product-pe-reveal: 50%;
  }
}

@keyframes product-box-drift {
  from {
    transform: translateX(38%) scale(1.04);
    opacity: 0;
  }
  to {
    transform: translateX(28%) scale(1);
    opacity: 0.92;
  }
}

/* -----------------------------------------------------------------------------
   Intro cluster
   ----------------------------------------------------------------------------- */
.s-product .head {
  /* asymmetric: keep type off the right edge where the box bleeds in */
  max-width: 60ch;
  margin-block-end: var(--sp-9);
}

.s-product .head > * + * {
  margin-block-start: var(--sp-5);
}

.s-product .lead {
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--dark-ink);
  max-width: var(--maxw-prose);
  margin: 0;
}

/* -----------------------------------------------------------------------------
   Comparison table — Typical vs DermaReverse. Cadmium ticks on DermaReverse col.
   ----------------------------------------------------------------------------- */
.s-product .comparisonWrap {
  /* sp-9 (not sp-10): tighten the table into the actives narrative it
     introduces; reserve sp-10 for true major-block breaks (actives → ingredients). */
  margin-block-end: var(--sp-9);
  max-width: 64rem;
}

.s-product .comparison {
  inline-size: 100%;
  border-collapse: collapse;
  text-align: start;
  table-layout: fixed;
}

.s-product .comparison th,
.s-product .comparison td {
  padding: var(--sp-4) var(--sp-5);
  vertical-align: top;
  /* Override the UA default `th { text-align: center }`, which targets each
     <th> directly and beats the table's `text-align: start`. This snaps the
     PROOF/PURPOSE/… row labels flush to the section rail and left-aligns the
     TYPICAL / DERMAREVERSE column heads over their left-aligned columns. */
  text-align: start;
  border-block-end: var(--bw-hair) solid var(--line-dark);
}

/* Flush the table to the section grid: zero the outer cell padding so the
   first column (PROOF/PURPOSE/…) aligns to the same left rail as the heading
   and eyebrows, and the last (DermaReverse) column ends true to the grid.
   Scoped through `.comparison` so these win the cascade over the base
   `.comparison th,td { padding: … }` shorthand — a bare `.dimHead` longhand
   loses to the shorthand on both specificity and shorthand-vs-longhand order,
   which is why the labels were drifting ~24px right of the rail. The explicit
   `padding-inline` shorthand restamps the inline axis outright. */
.s-product .comparison .dimHead,
.s-product .comparison .dimCell {
  padding-inline: 0 var(--sp-5);
}

.s-product .comparison .productHead,
.s-product .comparison .productCell {
  padding-inline: var(--sp-5) 0;
}

/* column heads */
.s-product .dimHead {
  /* Tightened from 22%: the row labels are short single words (PROOF/PURPOSE/
     ORIGIN/ACTIVES), so a narrower label column pulls the comparison columns
     closer to their labels and closes the oversized empty channel. */
  inline-size: 16%;
}

.s-product .typicalHead,
.s-product .productHead {
  inline-size: 42%;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  line-height: var(--lh-snug);
}

.s-product .typicalHead {
  color: var(--dark-ink-soft); /* Oyster — the quieter, lesser column */
}

/* DermaReverse column — emphasized in Cadmium (passes on dark). */
.s-product .productHead {
  color: var(--accent-warm);
}

/* row dimension label (mono clinical voice) */
.s-product .dimCell {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--dark-ink-soft);
  line-height: var(--lh-snug);
}

.s-product .typicalCell {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--dark-ink-soft);
}

/* Center the single-line label + short typical-column cells against the tallest
   cell in each row (the productCell stays top), so when a DermaReverse cell
   wraps to two lines its row no longer opens a hollow band beneath the short
   left cells — keeping PROOF/PURPOSE/ORIGIN/ACTIVES on an even cadence. Scoped
   through `.comparison` to beat the base `th,td { vertical-align: top }`. */
.s-product .comparison .dimCell,
.s-product .comparison .typicalCell {
  vertical-align: middle;
}

.s-product .productCell {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--dark-ink);
  font-weight: 500;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

/* Cadmium tick on the DermaReverse column. */
.s-product .tick {
  flex: none;
  inline-size: 1.15em;
  block-size: 1.15em;
  margin-block-start: 0.1em;
  color: var(--accent-warm);
}

/* -----------------------------------------------------------------------------
   Actives — varied spans (NOT 4 identical icon-circles)
   ----------------------------------------------------------------------------- */
.s-product .actives {
  margin-block-end: var(--sp-10);
}

.s-product .activesEyebrow {
  margin-block-end: var(--sp-6);
}

.s-product .activeGrid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--sp-5);
}

.s-product .activeCard {
  position: relative;
  grid-column: span 3;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  /* Lift fill + border so the panel actually reads as a card on Deep Olive
     (28% fill was imperceptible; line-dark hairline barely registered). */
  border: var(--bw-hair) solid
    color-mix(in srgb, var(--dark-ink) 14%, transparent);
  border-radius: var(--r-lg);
  background-color: color-mix(in srgb, var(--dark-bg-2) 50%, transparent);
  transition: border-color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

/* First card spans wider — varied, asymmetric (the hero active: retinol).
   The 4th card also widens, so the grid reads 6 / 3+3 / 6 — a broken, editorial
   rhythm rather than four identical icon-circles. */
.s-product .activeCard:nth-child(1),
.s-product .activeCard:nth-child(4) {
  grid-column: span 6;
}

.s-product .activeCard:hover {
  border-color: color-mix(in srgb, var(--accent-warm) 40%, var(--line-dark));
  transform: translateY(-2px);
}

.s-product .activeIndex {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  color: var(--accent-warm); /* Cadmium numeral accent */
}

/* active name emphasized in Cadmium per spec ("active-name emphasis uses Cadmium"). */
.s-product .activeName {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h4);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-tight);
  color: var(--accent-warm);
  margin: 0;
  text-wrap: balance;
}

.s-product .activeDesc {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--dark-ink);
  margin: 0;
}

/* Full-width cards (01, 04) span all 6 columns. Give them a two-column internal
   layout so the right half is used: index+name sit in column 1, the description
   fills column 2 — the wide panel reads as populated rather than left-loaded
   with a hollow right band. */
.s-product .activeCard:nth-child(1),
.s-product .activeCard:nth-child(4) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  gap: var(--sp-3) var(--sp-6);
}

.s-product .activeCard:nth-child(1) .activeDesc,
.s-product .activeCard:nth-child(4) .activeDesc {
  /* span both rows of column 2 so it sits beside the index+name stack */
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  /* raise the cap so the description fills column 2 instead of leaving a void */
  max-width: 48ch;
}

/* -----------------------------------------------------------------------------
   Descriptor strip — mono pills
   ----------------------------------------------------------------------------- */
.s-product .descriptors {
  margin-block-start: var(--sp-7);
}

.s-product .descriptorList {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

/* -----------------------------------------------------------------------------
   Ingredients sub-component (folded transparency story)
   ----------------------------------------------------------------------------- */
.s-product .ingredients {
  border-block-start: var(--bw-hair) solid var(--line-dark);
  padding-block-start: var(--sp-9);
  scroll-margin-top: var(--sp-9);
}

.s-product .ingredientsHead {
  max-width: 60ch;
}

.s-product .ingredientsHead > * + * {
  margin-block-start: var(--sp-4);
}

.s-product .ingredientsHeading {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h3);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-tight);
  color: var(--dark-ink);
  text-wrap: balance;
  margin: 0;
}

.s-product .ingredientsIntro {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--dark-ink-soft);
  margin: 0;
}

/* Highlighted actives chips */
.s-product .highlightWrap {
  margin-block-start: var(--sp-7);
}

.s-product .highlightList {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--sp-4);
}

.s-product .highlightChip {
  display: grid;
  grid-template-columns: auto 1fr;
  /* Two rows: the name fills the flexible top track, the benefit pins to the
     auto bottom track. This self-aligns every benefit to a shared baseline
     across the equal-width row regardless of how many lines a name wraps to —
     replacing the fragile chipName min-height reservation, which broke whenever
     a name (e.g. the tetrapeptide one) wrapped past the reserved two lines. */
  grid-template-rows: 1fr auto;
  align-items: start;
  column-gap: var(--sp-3);
  row-gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-5);
  border: var(--bw-hair) solid var(--line-dark);
  border-radius: var(--r-md);
  background-color: color-mix(in srgb, var(--dark-bg-2) 50%, transparent);
}

.s-product .chipMark {
  grid-row: 1 / span 2;
  font-size: var(--fs-h4);
  color: var(--accent-warm);
  flex: none;
}

.s-product .chipName {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  color: var(--dark-ink);
  /* Sits in the flexible top track; the benefit is pinned to the bottom track
     (see .highlightChip grid-template-rows), so no min-height hack is needed. */
}

.s-product .chipBenefit {
  grid-column: 2;
  grid-row: 2;
  align-self: end;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--dark-ink-soft);
}

/* Full INCI — native <details> */
.s-product .inci {
  margin-block-start: var(--sp-6);
  border: var(--bw-hair) solid var(--line-dark);
  border-radius: var(--r-md);
  background-color: color-mix(in srgb, var(--dark-bg-2) 50%, transparent);
}

.s-product .inciSummary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  cursor: pointer;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--dark-ink);
  list-style: none;
}

.s-product .inciSummary::-webkit-details-marker {
  display: none;
}

.s-product .inciSummaryLabel {
  display: inline-block;
}

.s-product .inciChevron {
  flex: none;
  color: var(--accent-warm);
  transition: transform var(--dur) var(--ease);
}

.s-product .inci[open] .inciChevron {
  transform: rotate(180deg);
}

.s-product .inciList {
  margin: 0;
  padding: 0 var(--sp-5) var(--sp-5);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--dark-ink-soft);
}

/* Free-from / format strip — mono pills */
.s-product .freeFrom {
  margin-block-start: var(--sp-6);
}

.s-product .freeFromList {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

/* -----------------------------------------------------------------------------
   Focus visibility (keyboard) — Klein Blue ring on the collapsible summary.
   ----------------------------------------------------------------------------- */
.s-product .inciSummary:focus-visible {
  outline: none;
  box-shadow: var(--ring-focus);
  border-radius: var(--r-md);
}

/* -----------------------------------------------------------------------------
   Responsive — collapse spans + table to a stacked layout on narrow viewports.
   ----------------------------------------------------------------------------- */
@media (max-width: 980px) {
  .s-product .bleed {
    inline-size: clamp(14rem, 48vw, 22rem);
    opacity: 0.5;
  }

  .s-product .head,
  .s-product .ingredientsHead {
    max-width: none;
  }
}

@media (max-width: 720px) {
  .s-product .bleed {
    display: none; /* reclaim the column; box is decorative */
  }

  .s-product .activeCard,
  .s-product .activeCard:nth-child(1),
  .s-product .activeCard:nth-child(4) {
    grid-column: 1 / -1;
  }

  /* Collapse the wide cards' two-column internal layout back to a single
     column so the description doesn't get squeezed on narrow viewports. */
  .s-product .activeCard:nth-child(1),
  .s-product .activeCard:nth-child(4) {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
  }

  .s-product .activeCard:nth-child(1) .activeDesc,
  .s-product .activeCard:nth-child(4) .activeDesc {
    grid-column: auto;
    grid-row: auto;
    align-self: auto;
    max-width: 60ch;
  }

  /* Stack the comparison table into labeled blocks. */
  .s-product .comparison,
  .s-product .comparison thead,
  .s-product .comparison tbody,
  .s-product .comparison tr,
  .s-product .comparison th,
  .s-product .comparison td {
    display: block;
    inline-size: 100%;
  }

  .s-product .comparison thead {
    position: absolute;
    width: var(--bw-hair);
    height: var(--bw-hair);
    overflow: hidden;
    clip-path: inset(50%);
  }

  .s-product .comparison tr {
    padding-block: var(--sp-4);
    border-block-end: var(--bw-hair) solid var(--line-dark);
  }

  .s-product .comparison th,
  .s-product .comparison td {
    border: 0;
    padding: var(--sp-1) 0;
  }

  .s-product .dimCell {
    margin-block-end: var(--sp-2);
    color: var(--accent-warm);
  }

  .s-product .typicalCell::before {
    content: "Typical: ";
    color: var(--dark-ink-soft);
    font-weight: 600;
  }
}

/* -----------------------------------------------------------------------------
   Reduced motion — land the box at its final state; reset scroll timelines.
   Belt-and-suspenders with the global reduce block (animation shorthand does NOT
   reset animation-timeline).
   ----------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .s-product .bleedInner,
  .s-product .boxImg {
    animation: none;
    animation-timeline: auto;
  }
  .s-product .boxImg {
    transform: translateX(28%);
    opacity: 0.92;
  }
  .s-product .inciChevron {
    transition: none;
  }
  .s-product .activeCard {
    transition: none;
  }
}

/* ===== css/sections/howtouse.css ===== */
/* =============================================================================
   HowToUse — "Powerful by day. Restorative by night." (§5 + signature §4.3)
   STATIC PORT of components/sections/HowToUse/HowToUse.module.css.
   ALL selectors scoped under .s-howtouse (prevents collisions when sections are
   concatenated). The keyframe is renamed htu-dusk -> howtouse-dusk. Every
   color/space/type/motion/radius value references a var(--token) verbatim.

   Reveal: [data-reveal] from-state + .is-visible final-state live globally in
   base.css; this file only ports the section's own visual + the CSS-driven
   AM/PM dusk sweep (scroll-driven, gated for reduced-motion).
   ============================================================================= */

.s-howtouse {
  background-color: var(--bg);
  padding-block: var(--section-y);
}

.s-howtouse .inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-9);
}

/* ---------------------------------------------------------------------------
   Header cluster — asymmetric: heading left, science intro offset right.
   --------------------------------------------------------------------------- */

.s-howtouse .head {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-5);
  align-items: end;
}

/* Layers on top of the global .eyebrow atom (margin only). */
.s-howtouse .eyebrow {
  margin-bottom: var(--sp-4);
}

.s-howtouse .intro {
  max-width: var(--maxw-prose);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--ink-soft);
}

@media (min-width: 60rem) {
  .s-howtouse .head {
    grid-template-columns: 7fr 5fr;
    gap: var(--sp-8);
  }
  .s-howtouse .intro {
    padding-bottom: var(--sp-2);
  }
}

/* ---------------------------------------------------------------------------
   3-step mechanism rail: 01 RENEW · 02 SUPPORT · 03 REPLENISH
   Non-uniform editorial feel via a top hairline + oversized Fraunces numerals.
   --------------------------------------------------------------------------- */

.s-howtouse .rail {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6);
}

@media (min-width: 48rem) {
  .s-howtouse .rail {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-7);
  }
}

.s-howtouse .railStep {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding-top: var(--sp-4);
  border-top: var(--bw-strong) solid var(--line-strong);
}

.s-howtouse .stepNum {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--tr-tight);
  color: var(--accent);
}

.s-howtouse .stepName {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink);
}

.s-howtouse .stepBody {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   SIGNATURE — the AM/PM DAY→NIGHT split (§4.3)
   Two panels share a rounded media frame; the divide between them reads as a
   day→night gradient OF THE IMAGERY. A .sweep overlay sweeps the dusk on scroll.
   --------------------------------------------------------------------------- */

.s-howtouse .dayNight {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  border-radius: var(--r-image);
  overflow: clip;
  box-shadow: var(--shadow-lg);
  isolation: isolate;
}

@media (min-width: 52rem) {
  .s-howtouse .dayNight {
    grid-template-columns: 1fr 1fr;
  }
}

.s-howtouse .panel {
  position: relative;
  z-index: 2; /* above the .sweep dusk veil */
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: var(--sp-7) var(--sp-6);
  min-height: 100%;
}

/* AM — warm Parchment with the one sanctioned golden light-field (LIGHT, not
   a color block): low-opacity Cadmium "sun" + Golden-Hour warmth over Khaki. */
.s-howtouse .panelDay {
  color: var(--ink);
  background-color: var(--bg-alt);
  background-image:
    radial-gradient(
      120% 90% at 18% 12%,
      rgba(255, 163, 0, 0.22),
      rgba(255, 163, 0, 0) 60%
    ),
    radial-gradient(
      100% 80% at 85% 100%,
      rgba(184, 133, 79, 0.18),
      rgba(184, 133, 79, 0) 55%
    );
}

/* PM — Deep-Olive night, deepening toward Claret at the far edge. */
.s-howtouse .panelNight {
  color: var(--dark-ink);
  background-color: var(--dark-bg);
  background-image:
    radial-gradient(
      120% 90% at 82% 18%,
      rgba(84, 14, 9, 0.55),
      rgba(84, 14, 9, 0) 60%
    ),
    radial-gradient(
      90% 80% at 10% 100%,
      rgba(19, 24, 28, 0.5),
      rgba(19, 24, 28, 0) 55%
    );
}

.s-howtouse .panelHead {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.s-howtouse .timeMark {
  font-family: var(--font-mono);
  font-size: var(--fs-h4);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  color: var(--accent-warm);
}

.s-howtouse .panelDay .timeMark {
  /* Cadmium/Golden-Hour fail as TEXT on cream (hard color rule) — the AM device
     reads as strong ink instead; the PM (Cadmium on Deep-Olive, 5.49:1) is fine. */
  color: var(--ink);
}

.s-howtouse .dnLabel {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
}

.s-howtouse .panelDay .dnLabel {
  color: var(--ink-soft);
}
.s-howtouse .panelNight .dnLabel {
  color: var(--accent-warm);
}

.s-howtouse .dnBody {
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  font-style: italic;
  line-height: var(--lh-snug);
  max-width: 48ch;
}

.s-howtouse .panelDay .dnBody {
  color: var(--ink);
}
.s-howtouse .panelNight .dnBody {
  color: var(--dark-ink);
}

/* The bottle figure — same asset, lit warm (AM) or cooled (PM). Decorative. */
.s-howtouse .figure {
  display: flex;
  justify-content: center;
  padding-block: var(--sp-5);
}

.s-howtouse .bottle {
  width: auto;
  height: 12rem;
  object-fit: contain;
}

.s-howtouse .bottleDay {
  filter: saturate(1.06) brightness(1.04)
    drop-shadow(0 var(--sp-4) var(--sp-6) rgba(70, 59, 36, 0.28));
}

.s-howtouse .bottleNight {
  filter: saturate(0.82) brightness(0.78) contrast(1.04)
    drop-shadow(0 var(--sp-4) var(--sp-6) rgba(19, 24, 28, 0.5));
}

/* Per-panel ritual list (AM / PM 3-step). */
.s-howtouse .ritual {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.s-howtouse .ritualLabel {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
}

.s-howtouse .panelDay .ritualLabel {
  color: var(--ink-mute);
}
.s-howtouse .panelNight .ritualLabel {
  color: var(--dark-ink-soft);
}

.s-howtouse .ritualSteps {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.s-howtouse .ritualStep {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
}

.s-howtouse .ritualIndex {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sp-6);
  height: var(--sp-6);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  font-weight: 500;
}

.s-howtouse .panelDay .ritualIndex {
  color: var(--on-accent);
  background-color: var(--accent);
}
.s-howtouse .panelNight .ritualIndex {
  color: var(--dark-ink);
  border: var(--bw-hair) solid var(--line-dark);
}

.s-howtouse .ritualTitle {
  font-weight: 600;
}

.s-howtouse .panelDay .ritualText {
  color: var(--ink-soft);
}
.s-howtouse .panelDay .ritualTitle {
  color: var(--ink);
}
.s-howtouse .panelNight .ritualText {
  color: var(--dark-ink-soft);
}
.s-howtouse .panelNight .ritualTitle {
  color: var(--dark-ink);
}

/* The scroll-linked dusk sweep — a warm→night veil that translates across the
   split as the block passes through the viewport. Decorative; transform/opacity
   only (compositor-safe). Static fallback = invisible (the panels already read
   as a day/night split). Gated to motion-OK + browsers with scroll-driven
   animation support; the global reduce block also resets animation-timeline. */
.s-howtouse .sweep {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: soft-light;
  background-image: linear-gradient(
    100deg,
    rgba(255, 163, 0, 0) 0%,
    rgba(184, 133, 79, 0.35) 38%,
    rgba(84, 14, 9, 0.55) 58%,
    rgba(19, 24, 28, 0.6) 100%
  );
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .s-howtouse .sweep {
      will-change: transform, opacity;
      transform: translate3d(-12%, 0, 0);
      animation: howtouse-dusk linear both;
      animation-timeline: view();
      animation-range: cover 8% cover 92%;
    }
  }
}

@keyframes howtouse-dusk {
  0% {
    opacity: 0;
    transform: translate3d(-12%, 0, 0);
  }
  45% {
    opacity: 0.85;
  }
  100% {
    opacity: 0.6;
    transform: translate3d(8%, 0, 0);
  }
}

/* ---------------------------------------------------------------------------
   Ramp-up note + study timeline strip
   --------------------------------------------------------------------------- */

.s-howtouse .notes {
  display: flex;
  flex-direction: column;
  gap: var(--sp-7);
}

.s-howtouse .rampUp {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  max-width: var(--maxw-prose);
  margin-inline: auto;
  padding: var(--sp-5);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  background-color: var(--surface);
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

.s-howtouse .rampMark {
  width: var(--sp-6);
  height: var(--sp-6);
  color: var(--accent);
  margin-top: var(--sp-2);
}

.s-howtouse .timeline {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-5);
}

@media (min-width: 48rem) {
  .s-howtouse .timeline {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-7);
  }
}

.s-howtouse .timelineItem {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-top: var(--sp-4);
  border-top: var(--bw-hair) solid var(--line);
}

.s-howtouse .timelineMarker {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--accent);
}

.s-howtouse .timelineBody {
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  color: var(--ink-soft);
}

.s-howtouse .timelineArrow {
  display: none;
  position: absolute;
  top: var(--sp-4);
  right: 0;
  margin-top: calc(var(--sp-1) * -1);
  transform: translateX(calc(50% + (var(--sp-7) / 2)));
  font-family: var(--font-mono);
  color: var(--ink-mute);
}

@media (min-width: 48rem) {
  .s-howtouse .timelineItem:not(:last-child) .timelineArrow {
    display: inline;
  }
}

/* ---------------------------------------------------------------------------
   Mandatory cosmetic-honesty line — kept prominent, never buried.
   --------------------------------------------------------------------------- */

.s-howtouse .honesty {
  max-width: var(--maxw-prose);
  padding-left: var(--sp-5);
  border-left: var(--bw-strong) solid var(--accent);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

/* ===== css/sections/clinical.css ===== */
/* =============================================================================
   ClinicalProof — §6 dark beat (Deep Olive), the heart of the page.
   STATIC PORT of components/sections/ClinicalProof/ClinicalProof.module.css.
   EVERY selector scoped under .s-clinical (concatenation-safe). Keyframes (none
   here) would be prefixed clinical-. Every color/space/type/radii/motion value
   is a var(--token) — no raw hex/px. prefers-reduced-motion honored at the bottom.
   The pinned GSAP proof reveal + count-up are driven by js/main.js; the
   from-state below is gated on the JS-applied .is-animated class so server/no-JS
   paint stays at the FINAL state (real numbers, visible stats).
   ============================================================================= */

.s-clinical {
  position: relative;
  background-color: var(--dark-bg); /* Deep Olive — primary dark editorial bg */
  color: var(--dark-ink);
  overflow: clip; /* contain the overlapping card + rotated edge caption */
}

/* The pinned WRAPPER (ScrollTrigger pins this element, never a grid item).
   Content-driven height: the static page has no live pin, so a 100vh
   reservation just created a ~2x-tall dark beat with the content floating in
   the middle and an orphaned citation. Sizing to content + one --section-y
   matches the parchment neighbors' rhythm and keeps the dark beats equal-weight. */
.s-clinical .stage {
  position: relative;
  display: flex;
  align-items: center;
  padding-block: var(--section-y);
}

.s-clinical .inner {
  position: relative;
  width: 100%;
  display: grid;
  gap: var(--sp-8);
}

/* --- rotated print-spread edge caption (decorative) ----------------------- */
.s-clinical .edge-caption {
  position: absolute;
  /* Nudge down off the flex-stretched stage center so the rotated label's
     center lands near the section's true content center (between the stat grid
     and footer) instead of floating in the top third of the right gutter. */
  top: calc(50% + var(--sp-8));
  right: calc(-1 * var(--sp-2));
  transform: translateY(-50%) rotate(90deg);
  transform-origin: right center;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--dark-ink-soft);
  opacity: 0.7;
  pointer-events: none;
}

/* --- header --------------------------------------------------------------- */
.s-clinical .head {
  display: grid;
  gap: var(--sp-4);
  max-width: var(--maxw-prose);
}

.s-clinical .intro {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--dark-ink);
  max-width: 60ch;
}

/* --- body grid: stats + overlapping proof card ---------------------------- */
.s-clinical .body {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-7);
  align-items: start;
}

/* --- the four huge stats -------------------------------------------------- */
.s-clinical .stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-7) var(--sp-6);
  margin: 0;
  padding: 0;
  list-style: none;
}

.s-clinical .stat {
  display: grid;
  gap: var(--sp-3);
  align-content: start;
  /* hairline above each stat — the deck's header-rule device, on dark */
  padding-top: var(--sp-4);
  border-top: var(--bw-hair) solid var(--line-dark);
}

/* The hero numeral — Fraunces, Cadmium (5.49:1 on Deep Olive, large-text AA).
   Kept on a single line and stepped down from --fs-display so the widest stat
   ("6 weeks") fits its half-column at desktop; this equalizes all four cells'
   heights so the bottom row shares a baseline (no orphaned "0" cell). */
.s-clinical .stat-number {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(3rem, 1.2rem + 6vw, 5.5rem);
  line-height: var(--lh-display);
  letter-spacing: -0.02em;
  color: var(--accent-warm);
  font-variant-numeric: tabular-nums; /* steady width while counting up */
  white-space: nowrap; /* keep "6 weeks" on one line for a shared baseline */
}

.s-clinical .stat-caption {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--dark-ink-soft);
  max-width: 30ch;
}

/* --- the Parchment proof card overlapping the panel corner (§4.4) --------- */
.s-clinical .proof-card {
  position: relative;
  z-index: 2;
  justify-self: end;
  max-width: 44ch;
  margin-top: calc(-1 * var(--sp-7)); /* overlap the stats' corner */
  padding: var(--sp-6);
  background-color: var(--surface);
  color: var(--ink);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}

.s-clinical .proof-card-kicker {
  margin: 0 0 var(--sp-4);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
}

.s-clinical .bullets {
  display: grid;
  gap: var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.s-clinical .bullet {
  position: relative;
  padding-left: var(--sp-5);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--ink);
}

/* capsule-motif marker — a small Cadmium lozenge */
.s-clinical .bullet::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: var(--sp-3);
  height: var(--sp-2);
  background-color: var(--accent-warm);
  border-radius: var(--r-pill);
}

/* --- citation + study link (in-frame, mandatory) ------------------------- */
.s-clinical .footer {
  display: grid;
  gap: var(--sp-4);
  padding-top: var(--sp-5);
  border-top: var(--bw-hair) solid var(--line-dark);
}

.s-clinical .citation {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  line-height: var(--lh-snug);
  letter-spacing: 0.01em;
  color: var(--dark-ink-soft);
  max-width: 80ch;
}

/* Ghost button defaults to dark ink; force Parchment so it reads on the dark
   panel. Compound selector beats the single-class .btn--ghost regardless of
   bundle order. */
.s-clinical .footer .study-link,
.s-clinical .footer .study-link:hover {
  justify-self: start;
  color: var(--dark-ink);
}

/* =============================================================================
   Desktop layout — stats and the overlapping card share the editorial spread.
   ============================================================================= */
@media (min-width: 64rem) {
  .s-clinical .body {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: var(--sp-8);
  }

  .s-clinical .stats {
    gap: var(--sp-7) var(--sp-7);
  }

  .s-clinical .proof-card {
    margin-top: var(--sp-7); /* let it drop to overlap the stats' lower corner */
    margin-left: calc(-1 * var(--sp-8));
  }
}

/* =============================================================================
   GSAP from-state — only present once main.js marks the stage .is-animated
   (motion allowed + JS live). Keeps server/no-JS paint at the FINAL state (real
   numbers, visible stats); GSAP's own gsap.set then drives opacity/transform.
   The reduce block below resets it.
   ============================================================================= */
.s-clinical .stage.is-animated [data-proof] {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .s-clinical .stage.is-animated [data-proof] {
    opacity: 1 !important;
    transform: none !important;
    animation-timeline: auto !important;
  }
}

/* ===== css/sections/beforeafter.css ===== */
/* =============================================================================
   BeforeAfter — §7 / signature §4.2. Static port of
   components/sections/BeforeAfter/BeforeAfter.module.css.
   ALL selectors scoped under .s-beforeafter. Keyframes kept global but prefixed
   beforeafter- to avoid collisions. Parchment surface, Poppy accents (the ONLY
   Poppy on the page). The real before-after.webp is a single SPLIT-FACE asset
   (one side DermaReverse, one side placebo), framed at --r-image.

   Motion (signature moment #2):
   - js/main.js drives an animated wipe: the AFTER half wipes in over the BEFORE
     as the section enters, by writing the --reveal var on [data-ba-frame]; the
     .afterLayer clips to it via clip-path:inset().
   - A draggable compare handle moves the inspection divider (--split, also
     written by main.js); momentum→spring settle is JS-driven.
   - CSS fallback: if JS never sets data-gsap="on", the wipe still runs once via
     the scroll-driven keyframe below in the no-preference media query.
   - prefers-reduced-motion → static, both halves shown, no wipe.

   Every value is a var(--token) — no raw hex/px.
   ========================================================================== */

.s-beforeafter {
  background-color: var(--bg);
  padding-block: var(--section-y);
  position: relative;
  /* clip the decorative .halo bleed (inset: -sp-6) to the section so its -48px
     right edge can't poke past a narrow (390px) viewport and cause horizontal
     scroll — matches .s-hero/.s-clinical/.s-finalcta which clip their bleeds. */
  overflow: clip;
}

.s-beforeafter .container {
  display: grid;
  gap: var(--sp-7);
}

/* =============================================================================
   Desktop spread — give the empty right gutter a job. Below 64rem the section
   stays a single anchored column (head → stage → caption stacked). At >=64rem
   it becomes a two-column editorial spread: the split-face stage holds the left
   column, the .head + .captionWrap text flank it in the right column, so the
   former all-right void becomes the reading measure beside the graphic.
   The .stage sits in its own [data-reveal] wrapper, so we place that wrapper.
   ============================================================================= */
@media (min-width: 64rem) {
  .s-beforeafter .container {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
    column-gap: var(--sp-9);
    align-items: center;
  }

  /* stage wrapper → left column, spanning both text rows. Target the stage's
     OWN reveal value (clip-up) only — a bare [data-reveal] also matched .head
     (data-reveal="fade-up") at higher specificity and forced the heading into
     column 1 on top of the image. */
  .s-beforeafter .container > [data-reveal="clip-up"] {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  /* header + caption → right column, stacked top-to-bottom */
  .s-beforeafter .head {
    grid-column: 2;
    grid-row: 1;
    align-self: end;
  }

  .s-beforeafter .captionWrap {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    /* the stacking-specific halo-offset nudge (base --sp-2) doesn't apply once
       the caption sits BESIDE (not under) the stage — and an extra margin here
       only stacks on top of the grid row-gap (--sp-7), pushing the caption ~64px
       off the body copy so it reads as an orphaned block. Zero it out and let the
       single row-gap govern the head→caption rhythm. */
    margin-top: 0;
  }
}

/* ---- header cluster (eyebrow + heading + body) ---------------------------- */
.s-beforeafter .head {
  display: grid;
  gap: var(--sp-4);
  max-width: var(--maxw-prose);
}

/* Even out the H2 rag so the brand name doesn't sit alone on a stubby middle
   line — let the browser balance the lines. The heading gets a slightly wider
   measure than the prose body (--maxw-prose on .head) so balance has room to
   step the rag longest→shortest instead of pinching the brand word onto a stubby
   middle line. */
.s-beforeafter .head .section-heading {
  text-wrap: balance;
  max-width: 24ch;
}

.s-beforeafter .eyebrow {
  margin: 0;
}

.s-beforeafter .body {
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  max-width: 60ch;
}

/* ---- the framed compare stage -------------------------------------------- */
.s-beforeafter .stage {
  position: relative;
  width: 100%;
  /* The asset is a self-contained portrait graphic — keep it at a calm editorial
     size rather than letting it sprawl to the full content width. */
  max-width: 46rem;
  /* Left-align the graphic to the same edge as the header cluster so the
     composition reads as one anchored column instead of a left-aligned intro
     followed by a disconnected, centered slab. */
  margin-inline: 0;
}

.s-beforeafter .frame {
  position: relative;
  /* the asset is 1080×1350 = 4:5 portrait */
  aspect-ratio: 4 / 5;
  width: 100%;
  border-radius: var(--r-image);
  overflow: hidden;
  background-color: var(--bg-sand);
  box-shadow: var(--shadow-lg);
  /* sit above the soft Poppy halo behind the frame */
  isolation: isolate;
}

/* The asset is a fully pre-composed 4:5 clinical graphic — keep its native aspect
   at every width. (A landscape cover-crop chopped it into a confusing band that
   was dominated by the anonymization bars.) */

/* Absolutely-positioned image filling the frame. With the frame matched to the
   asset's 4:5 aspect, cover shows the whole graphic with no crop. */
.s-beforeafter .image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* The before-after.webp asset already bakes in its own BEFORE/AFTER labels,
   dashed callout circles, anonymization bars and the study caption. Suppress the
   component's duplicate interactive chrome so the finished graphic reads clean
   instead of double-labelled and cluttered. */
.s-beforeafter .afterLayer,
.s-beforeafter .divider,
.s-beforeafter .handle,
.s-beforeafter .tabs,
.s-beforeafter .callout {
  display: none;
}

/* The BEFORE layer = the image as-is. The AFTER wipe overlay sits on top and is
   clipped from the right by --reveal (0 → 100% as the wipe completes). Because the
   asset is a single split-face frame, the overlay re-renders the SAME image with
   a subtle warm "treated" lift so the wipe reads as a reveal of the result. */
.s-beforeafter .afterLayer {
  position: absolute;
  inset: 0;
  /* clip from the right: at --reveal:0 nothing shows, at 100% the whole frame */
  clip-path: inset(0 calc(100% - var(--reveal, 0%)) 0 0);
  /* a whisper of warmth on the revealed (treated) side — token-driven filter */
  filter: saturate(1.06) brightness(1.03);
  will-change: clip-path;
}

/* The moving inspection divider (the draggable compare handle). --split is the
   handle position 0–100% written by main.js (defaults to mid). */
.s-beforeafter .divider {
  position: absolute;
  inset-block: 0;
  left: var(--split, 50%);
  width: var(--bw-strong);
  margin-left: calc(var(--bw-strong) * -0.5);
  background-color: var(--accent-poppy);
  box-shadow: 0 0 0 var(--bw-hair) var(--bg);
  z-index: 3;
  touch-action: none;
}

.s-beforeafter .handle {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: var(--sp-8);
  height: var(--sp-8);
  border-radius: var(--r-pill);
  background-color: var(--accent-poppy);
  color: var(--bg);
  display: grid;
  place-items: center;
  cursor: ew-resize;
  border: var(--bw) solid var(--bg);
  box-shadow: var(--shadow-md);
  transition: transform var(--dur-fast) var(--micro-ease-overshoot);
}

.s-beforeafter .handle:hover {
  transform: translate(-50%, -50%) scale(1.06);
}

.s-beforeafter .handle:focus-visible {
  outline: none;
  box-shadow: var(--ring-focus), var(--shadow-md);
}

.s-beforeafter .handleIcon {
  display: inline-flex;
  font-size: var(--fs-h4);
  line-height: 0;
}

/* ---- Poppy BEFORE / AFTER tabs (the ONLY Poppy on the page) --------------- */
.s-beforeafter .tabs {
  position: absolute;
  inset-inline: var(--sp-4);
  top: var(--sp-4);
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  z-index: 4;
  pointer-events: none;
}

.s-beforeafter .tab {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: var(--tr-eyebrow);
  font-size: var(--fs-meta);
  font-weight: 500;
  line-height: 1;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-pill);
  background-color: var(--accent-poppy);
  color: var(--bg);
}

/* the week-grade study labels sit under each tab — calm, not hypey */
.s-beforeafter .tabMeta {
  display: block;
  margin-top: var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  color: var(--bg);
  opacity: 0.85;
}

/* ---- dashed-circle callouts ---------------------------------------------- */
.s-beforeafter .callout {
  position: absolute;
  width: var(--sp-9);
  height: var(--sp-9);
  border: var(--bw) dashed var(--accent-poppy);
  border-radius: var(--r-pill);
  z-index: 3;
  pointer-events: none;
}

.s-beforeafter .calloutTop {
  top: 18%;
  right: 14%;
}

.s-beforeafter .calloutBottom {
  bottom: 16%;
  right: 22%;
}

.s-beforeafter .calloutLabel {
  position: absolute;
  bottom: calc(var(--sp-9) * -0.5 + var(--sp-2));
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---- caption (VERBATIM) + microcopy -------------------------------------- */
.s-beforeafter .captionWrap {
  display: grid;
  gap: var(--sp-3);
  max-width: 46rem;
  /* Share the header/stage left edge instead of re-centering, so the whole
     section reads as one left-anchored column. */
  margin-inline: 0;
  /* Equalize the breathing room around the stage: the .halo's negative inset
     eats space above the frame, making the body→image gap read larger than the
     image→caption gap. Nudge the caption down so both gaps read identical. */
  margin-top: var(--sp-2);
  text-align: left;
}

.s-beforeafter .caption {
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--ink);
}

.s-beforeafter .microcopy {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--ink-mute);
}

/* ---- soft Poppy halo behind the frame (decorative) ----------------------- */
.s-beforeafter .halo {
  position: absolute;
  inset: calc(var(--sp-6) * -1);
  z-index: -1;
  border-radius: var(--r-lg);
  /* a faint warm wash, not a section background — uses the sanctioned light idea
     but kept extremely subtle so it doesn't read as a gradient section bg */
  background:
    radial-gradient(
      75% 60% at 50% 50%,
      color-mix(in srgb, var(--accent-poppy) 20%, transparent),
      transparent 70%
    );
  pointer-events: none;
}

/* =============================================================================
   MOTION — gated to no-preference. main.js drives --reveal/--split. This block
   is the CSS-first fallback so the wipe still plays once on enter when JS is
   absent (view-timeline scroll-driven), per §4.2.
   ========================================================================== */

@property --reveal {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@media (prefers-reduced-motion: no-preference) {
  /* CSS fallback: if main.js never sets data-gsap="on", scroll-drive the wipe so
     the AFTER half reveals as the frame scrolls through view. main.js, when it
     mounts, sets data-gsap="on" and takes over (it writes --reveal directly). */
  .s-beforeafter .frame:not([data-gsap="on"]) .afterLayer {
    animation: beforeafter-wipe linear both;
    animation-timeline: view();
    animation-range: entry 15% cover 45%;
  }
}

@keyframes beforeafter-wipe {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

/* Static, honest fallback for reduced motion: show the full revealed frame, no
   wipe, no handle interaction emphasis. The global reduce block already kills
   animations + resets animation-timeline; we additionally pin the layer open. */
@media (prefers-reduced-motion: reduce) {
  .s-beforeafter .afterLayer {
    clip-path: inset(0 0 0 0) !important;
    filter: none;
  }

  .s-beforeafter .divider,
  .s-beforeafter .handle {
    /* divider parks centered as a quiet split marker; drag still works but no
       momentum animation. Keep it visible as the design device. */
    transition: none;
  }
}

/* ===== css/sections/founder.css ===== */
/* =============================================================================
   Founder (.s-founder) — Dr. Julius Few authority beat (creative-direction §9).
   Claret dark beat (#3). Typographic, no photo. Ported from
   components/sections/Founder/Founder.module.css — EVERY selector scoped under
   .s-founder. Every value = var(--token): no raw hex/px. Parchment ink on Claret
   (10.94:1 AAA); Cadmium/Golden-Hour as accents only.
   ============================================================================= */

/* Root — was Founder.module .section. */
.s-founder {
  position: relative;
  background-color: var(--dark-bg-claret);
  color: var(--dark-ink);
  padding-block: var(--section-y);
  /* keep the section above the fixed grain layer's blend yet below modals */
  isolation: isolate;
  overflow: hidden;
}

/* A faint warm halo behind the quote rail — light, not a color-blob section bg.
   Single soft radial of Claret-deepening tone; decorative, pointer-safe. */
.s-founder::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(
      60% 70% at 78% 38%,
      color-mix(in srgb, var(--accent-claret) 60%, var(--c-black)) 0%,
      transparent 70%
    );
  pointer-events: none;
}

/* ---------------------------------------------------------------------------
   Layout — broken editorial grid (7/5-ish asymmetry, never 6/6).
   lede rail leads; the pull-quote floats in its own whitespace halo on the
   wider side. Single column on small screens.
   --------------------------------------------------------------------------- */

.s-founder .inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-8) var(--gutter);
  align-items: start;
}

@media (min-width: 60rem) {
  .s-founder .inner {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: var(--sp-8);
    align-items: start;
  }
}

/* ---------------------------------------------------------------------------
   Left rail — eyebrow / heading / body / credentials / brand mark.
   --------------------------------------------------------------------------- */

.s-founder .lede {
  display: flex;
  flex-direction: column;
  align-items: start;
  /* prose-width measure so the body never runs long on wide viewports */
  max-width: var(--maxw-prose);
}

/* Section override of the global .eyebrow: warm the dark eyebrow toward the
   golden-hour metal so the kicker reads as the clinical-but-warm voice on Claret. */
.s-founder .eyebrow {
  color: var(--accent-metal);
  margin-bottom: var(--sp-5);
}

/* Heading rhythm — more space above than below (brand-tokens §type).
   Eyebrow keeps --sp-5 above; the heading binds tighter (--sp-4) into the body. */
.s-founder .lede h2 {
  margin-bottom: var(--sp-4);
}

.s-founder .body {
  font-family: var(--font-sans);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--dark-ink);
  margin-bottom: var(--sp-7);
}

/* Credential list — tight, hairline-separated, pill-marked. */
.s-founder .credentials {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-7);
  padding: 0;
  width: 100%;
}

.s-founder .credential {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: var(--sp-3);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
  color: var(--dark-ink-soft);
  padding-bottom: var(--sp-3);
  border-bottom: var(--bw-hair) solid var(--line-dark);
}

.s-founder .credential:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.s-founder .credentialMark {
  /* the capsule "A" lozenge as the bullet — quiet pharma nod */
  font-size: 1.25em;
  color: var(--accent-warm);
  margin-top: 0.05em;
  flex: none;
}

/* Typographic portrait stand-in — wordmark + pill mark on Claret. */
.s-founder .signature {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
}

.s-founder .signatureMark {
  font-size: var(--fs-h3);
  color: var(--accent-metal);
  flex: none;
}

.s-founder .wordmark {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h3);
  letter-spacing: var(--tr-tight);
  line-height: 1;
  color: var(--dark-ink);
}

/* ---------------------------------------------------------------------------
   Right rail — the large Newsreader pull-quote in a whitespace halo.
   --------------------------------------------------------------------------- */

.s-founder .quoteWrap {
  position: relative;
  margin: 0;
  padding: var(--sp-7) 0 0;
}

@media (min-width: 60rem) {
  .s-founder .quoteWrap {
    /* Center the quote vertically within the shared grid-row height instead of
       top-anchoring it. The left rail (eyebrow → credentials → wordmark) runs
       nearly the full section height, so a top-anchored short quote stranded a
       lopsided oxblood void in the bottom-right quadrant. Stretch this cell to
       the row height and optically center the quote + attribution against the
       left rail's heading-through-credentials span, distributing the whitespace
       halo above AND below rather than dumping it all beneath the attribution.
       Trim the left pad so the grid gap isn't doubled into an oversized trough,
       and drop the right pad so the quote and its attribution rule terminate on
       a clean right edge mirroring the left margin. */
    align-self: stretch;
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    padding: var(--sp-2) 0 var(--sp-2) var(--sp-5);
  }

  /* Grow the pull-quote a step so the right column carries more vertical
     presence and its block reads against the left rail's heading + body. Held
     at --fs-h3 (not --fs-h2) so the measure keeps "DermaReverse is my answer:"
     on one line rather than stranding "answer:" on its own visual line. */
  .s-founder .quote {
    font-size: var(--fs-h3);
  }
}

/* Oversized opening quotation mark — Fraunces, golden-hour, decorative. */
.s-founder .quoteOpen {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-display);
  line-height: 0.6;
  color: var(--accent-metal);
  opacity: 0.55;
  /* The glyph sits high in a 0.6 line-box, so its own descender space already
     leaves a gap; drop the extra bottom margin so the mark hangs over the
     opening line (~1rem) instead of drifting ~2rem above it. */
  margin-bottom: 0;
  user-select: none;
}

.s-founder .quote {
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: var(--lh-snug);
  letter-spacing: 0;
  color: var(--dark-ink);
  text-wrap: balance;
}

/* Each clause reveals as its own block line (the optional line-by-line reveal).
   Block display so the staggered spans stack like printed quote lines. */
.s-founder .quoteLine {
  display: block;
}

/* Attribution — mono clinical voice, carries "Dr. Julius Few, MD" verbatim. */
.s-founder .attribution {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--accent-warm);
}

.s-founder .attributionRule {
  display: inline-block;
  width: var(--sp-6);
  height: var(--bw-strong);
  background-color: var(--accent-warm);
  flex: none;
}

/* ===== css/sections/pricing.css ===== */
/* =============================================================================
   Pricing (.s-pricing) — SubscriptionValue + PricingCards (the conversion peak).
   Ported from components/sections/SubscriptionValue/SubscriptionValue.module.css.
   EVERY selector scoped under .s-pricing; keyframes kept global but prefixed
   "pricing-" to avoid collisions. Every color/space/type/radius/motion value
   references a var(--token); alpha composed with color-mix so the warm brand
   tokens stay the single source of color truth.

   Behavior wired by js/main.js via data hooks:
     [data-pricing]              the role="radiogroup" wrapper (.cards)
     [data-pricing-tier="…"]     each role="radio" tile (one-time|three-month|six-month)
     [data-pricing-selected]     the preselected (3-month) tile on load
   Selection is a VISUAL state: JS toggles aria-checked + roving tabindex and the
   .tileSelected class (warm ring); the highlighted tile keeps its elevation.
   ============================================================================= */

/* ============================================================================
   Section shell + golden light-field
   ============================================================================ */

.s-pricing {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background-color: var(--bg);
  color: var(--ink);
  padding-block: var(--section-y);
}

/* Calmer golden light-field: warm radials over the flat Parchment base, biased
   toward the middle (where the MOST POPULAR tile sits). Decorative only. */
.s-pricing .lightField {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(
      60% 45% at 50% 22%,
      color-mix(in srgb, var(--c-cadmium) 16%, transparent),
      transparent 70%
    ),
    radial-gradient(
      70% 55% at 50% 64%,
      color-mix(in srgb, var(--c-golden-hour) 18%, transparent),
      transparent 72%
    ),
    radial-gradient(
      90% 60% at 50% 108%,
      color-mix(in srgb, var(--c-ochre) 12%, transparent),
      transparent 70%
    );
  will-change: transform;
}

@media (prefers-reduced-motion: no-preference) {
  .s-pricing .lightField {
    animation: pricing-lightDrift 22s var(--ease-in-out) infinite alternate;
  }
}

@keyframes pricing-lightDrift {
  from {
    transform: translate3d(-1.5%, -1%, 0) scale(1.02);
  }
  to {
    transform: translate3d(1.5%, 1%, 0) scale(1.06);
  }
}

.s-pricing .inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-7);
}

/* ============================================================================
   Heading cluster
   ============================================================================ */

.s-pricing .head {
  max-width: var(--maxw-prose);
  text-align: center;
}

.s-pricing .heading {
  margin-block-start: var(--sp-4);
  text-wrap: balance;
}

/* ============================================================================
   Value props row (3 short items)
   ============================================================================ */

.s-pricing .valueProps {
  width: 100%;
}

.s-pricing .valuePropsList {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.s-pricing .valueProp {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  text-align: start;
}

.s-pricing .valuePropMark {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  inline-size: var(--sp-6);
  block-size: var(--sp-6);
  margin-block-start: var(--sp-1);
  border-radius: var(--r-pill);
  color: var(--on-accent);
  background-color: var(--accent);
  font-size: var(--fs-body);
}

.s-pricing .valuePropText {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.s-pricing .valuePropTitle {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
}

.s-pricing .valuePropBody {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

/* ============================================================================
   Cost-stacking value line (the "$275 engine") — ABOVE the cards
   ============================================================================ */

.s-pricing .costStacking {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  width: 100%;
  padding: var(--sp-4) var(--sp-5);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  background-color: color-mix(in srgb, var(--surface) 78%, transparent);
}

.s-pricing .costStackingMark {
  flex: none;
  font-size: var(--fs-h3);
  line-height: 1;
  color: var(--accent);
  margin-block-start: var(--sp-1);
}

.s-pricing .costStackingText {
  margin: 0;
  max-width: var(--maxw-prose);
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* ============================================================================
   Pricing tiles (NOT three equal cards)
   ============================================================================ */

/* align-items: stretch so every tile fills the row's full height. With equal-height
   tiles, .tileCta { margin-block-start: auto } pushes all three CTAs to a true shared
   bottom baseline regardless of body length or the .tileHighlighted scale — no
   per-tile margin tuning needed. */
.s-pricing .cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-5);
  align-items: stretch;
  inline-size: 100%;
}

/* gap: 0 — the per-element margin-top values (priceRow/cadence/perDay/savings/note)
   are the single source of vertical rhythm inside the tile. Running a flex gap AND
   those margins together doubled the spacing and made the steps uneven. */
.s-pricing .tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--sp-6) var(--sp-5);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  background-color: var(--surface);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  outline: none;
  transition:
    transform var(--dur) var(--ease),
    border-color var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease);
}

/* The quietest tile — the strikethrough anchor. */
.s-pricing .tileAnchor {
  background-color: color-mix(in srgb, var(--surface) 60%, var(--bg));
  box-shadow: none;
}

/* The elevated MOST POPULAR tile: scale, 2px Ochre border, --shadow-md, glow. */
.s-pricing .tileHighlighted {
  border: var(--bw-strong) solid var(--accent);
  box-shadow: var(--shadow-md);
  background-color: var(--surface);
  transform: scale(1.03);
  z-index: 1;
}

/* A calmer golden light-field glow behind the popular tile. */
.s-pricing .tileHighlighted::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--sp-4));
  z-index: -1;
  border-radius: var(--r-lg);
  background: radial-gradient(
    70% 70% at 50% 38%,
    color-mix(in srgb, var(--c-cadmium) 22%, transparent),
    transparent 72%
  );
  pointer-events: none;
}

/* Selected state — Klein-Blue-free, warm ring that doesn't fight the CTA. */
.s-pricing .tileSelected {
  border-color: var(--accent);
  box-shadow: var(--shadow-md);
}

.s-pricing .tileHighlighted.tileSelected {
  box-shadow: var(--shadow-md), var(--shadow-glow);
}

.s-pricing .tile:focus-visible {
  box-shadow: var(--ring-focus);
}

.s-pricing .tileHighlighted:focus-visible {
  box-shadow: var(--shadow-md), var(--ring-focus);
}

/* MOST POPULAR ribbon — springs in on enter (--spring-pop). */
.s-pricing .ribbon {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
}

@media (prefers-reduced-motion: no-preference) {
  .s-pricing .ribbon {
    animation: pricing-ribbonPop var(--dur-slow) var(--spring-pop) both;
  }
}

@keyframes pricing-ribbonPop {
  from {
    transform: translate(-50%, -50%) scale(0.6);
    opacity: 0;
  }
  to {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
  }
}

.s-pricing .tileTop {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
}

.s-pricing .tileName {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-h4);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
}

/* "BEST VALUE" tag on the quiet 6-month tile. */
.s-pricing .tileTag {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}

.s-pricing .priceRow {
  margin: var(--sp-3) 0 0;
  line-height: var(--lh-tight);
}

.s-pricing .price {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h2);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
}

/* One-time price = the quiet value anchor. Muted, NOT struck: $125 is the real
   price you pay for the one-time option, so a strikethrough misreads as "no longer
   charged." The quieter anchor tile + the subscription savings lines ("Save $X/mo
   vs. one-time") already do the anchoring honestly. */
.s-pricing .priceStruck {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-h2);
  letter-spacing: var(--tr-tight);
  color: var(--ink-soft);
}

.s-pricing .cadence {
  margin: var(--sp-1) 0 0;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--ink-soft);
}

.s-pricing .perDay {
  margin: var(--sp-3) 0 0;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--ink-mute);
}

.s-pricing .savings {
  margin: var(--sp-2) 0 0;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--accent-clay);
}

/* min-block-size keeps every tile's note occupying comparable space so the bodies
   read at a consistent height; the shared CTA baseline itself is handled by
   .cards align-items: stretch + .tileCta margin-block-start: auto. */
.s-pricing .note {
  margin: var(--sp-3) 0 var(--sp-5);
  min-block-size: 3.5rem;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

.s-pricing .tileCta {
  margin-block-start: auto;
}

/* ============================================================================
   Guarantee block welded under the CTAs + mono reassurance microcopy
   ============================================================================ */

.s-pricing .guarantee {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  max-width: var(--maxw-prose);
  text-align: center;
}

.s-pricing .guaranteeBody {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  padding: var(--sp-5);
  border: var(--bw-hair) solid var(--line);
  border-radius: var(--r-lg);
  background-color: var(--surface);
}

.s-pricing .guaranteeMark {
  flex: none;
  font-size: var(--fs-h3);
  color: var(--accent);
  margin-block-start: var(--sp-1);
}

.s-pricing .guaranteeText {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
  text-align: start;
}

.s-pricing .guaranteeTitle {
  font-weight: 600;
  color: var(--ink);
}

.s-pricing .microcopy {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  line-height: var(--lh-snug);
  color: var(--ink-mute);
}

/* ============================================================================
   Responsive — collapse the grids; let the popular tile lead on mobile
   ============================================================================ */

@media (max-width: 920px) {
  .s-pricing .valuePropsList {
    grid-template-columns: 1fr;
    gap: var(--sp-4);
    max-width: var(--maxw-prose);
    margin-inline: auto;
  }

  .s-pricing .cards {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
    max-width: var(--maxw-prose);
    margin-inline: auto;
  }

  /* Don't let the scaled popular tile overflow / overlap on a single column. */
  .s-pricing .tileHighlighted {
    transform: none;
    order: -1;
  }
}

/* ============================================================================
   Reduced motion — still every decorative animation here too (belt-and-braces
   with the global reduce block; the shorthand doesn't reset animation-timeline)
   ============================================================================ */

@media (prefers-reduced-motion: reduce) {
  .s-pricing .lightField,
  .s-pricing .ribbon {
    animation: none;
    animation-timeline: auto;
  }

  .s-pricing .tile,
  .s-pricing .tileHighlighted {
    transition: none;
  }
}

/* ===== css/sections/faq.css ===== */
/* =============================================================================
   Faq (.s-faq) — single-column accordion on Parchment (creative-direction §11).
   Ported VERBATIM from components/sections/Faq/Faq.module.css. Every selector
   scoped under .s-faq; all values are var(--token).
   Hairline dividers, 68ch measure, generous row padding. Open/close animates via
   grid-template-rows (0fr→1fr) — never raw height. The header/list reveal via the
   global [data-reveal] hooks; reduced-motion neutralizes the grid-rows/chevron.
   ============================================================================= */

.s-faq {
  background: var(--bg);
  color: var(--ink);
  padding-block: var(--section-y);
}

/* Decouple layout-width from reading-measure. The markup wraps the section in
   .container--prose (68ch), which floats this closing beat as a narrow strip
   left of optical center. Widen the frame to a comfortable centered column so
   the section reads composed; the per-element reading measure is re-capped on
   .question / .answer below. */
.s-faq .container--prose {
  max-width: 52rem;
}

/* Header cluster — whitespace halo above the list. A deeper moat under the
   display heading cleanly separates the header zone from the accordion zone. */
.s-faq .header {
  margin-bottom: var(--sp-8);
}

/* A touch more separation between eyebrow and heading at this section scale. */
.s-faq .heading {
  margin-top: var(--sp-4);
}

/* The accordion list — reset list chrome, hairline top rule opens the stack. */
.s-faq .list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--bw-hair) solid var(--line);
}

.s-faq .item {
  border-bottom: var(--bw-hair) solid var(--line);
}

/* One <details> row. */
.s-faq .details {
  margin: 0;
}

/* The clickable question row. Remove the native marker, lay out as a row with
   the chevron pushed to the end. Generous vertical padding per spec. */
.s-faq .summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  padding-block: var(--sp-6);
  /* Unpin the chevron from the frame edge so it reads as part of the row. */
  padding-right: var(--sp-2);
  cursor: pointer;
  list-style: none;
  color: var(--ink);
  transition: color var(--dur-fast) var(--ease);
}

/* Kill the default disclosure triangle across engines. */
.s-faq .summary::-webkit-details-marker {
  display: none;
}
.s-faq .summary::marker {
  content: "";
}

.s-faq .summary:hover {
  color: var(--ink-soft);
}

/* Keyboard focus — Klein Blue ring (the one cool accent), inset to the row. */
.s-faq .summary:focus-visible {
  outline: none;
  border-radius: var(--r-sm);
  box-shadow: var(--ring-focus);
}

.s-faq .question {
  /* Cap the question's reading measure even though the frame is now wider, but
     keep it wide enough that short, single-line questions don't leave a wide
     empty channel before the chevron. */
  max-width: 44ch;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-tight);
  text-wrap: balance;
}

/* Chevron — a quiet capsule-radius affordance that rotates on open. */
.s-faq .icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sp-6);
  height: var(--sp-6);
  /* Strengthen the resting affordance so the row reads as an interactive toggle:
     a legible border + subtle surface fill, with the chevron in full --ink.
     Hover still brightens the border to --line-strong below. */
  border: var(--bw-hair) solid var(--line-strong);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-h4);
  transition:
    transform var(--dur) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}

.s-faq .summary:hover .icon {
  border-color: var(--line-strong);
  color: var(--ink);
}

/* The answer panel collapses/expands via the grid track, not height.
   Default (closed) = 0fr. overflow:hidden clips the content during collapse. */
.s-faq .panel {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows var(--dur-slow) var(--ease);
}

/* The inner wrapper must be min-height:0 so the 0fr track can fully collapse. */
.s-faq .panel > .answer {
  min-height: 0;
}

/* No-JS / native source of truth: when <details open>, reveal the panel and
   rotate the chevron even before hydration. */
.s-faq .details[open] .panel {
  grid-template-rows: 1fr;
}
.s-faq .details[open] .icon {
  transform: rotate(180deg);
}

/* JS-enhanced state: while a CLOSE animation plays we keep the element [open]
   but flip .isOpen off, so these win and animate the collapse back to 0fr. */
.s-faq .details.isOpen .panel {
  grid-template-rows: 1fr;
}
.s-faq .details.isOpen .icon {
  transform: rotate(180deg);
}
.s-faq .details[open]:not(.isOpen) .panel {
  grid-template-rows: 0fr;
}
.s-faq .details[open]:not(.isOpen) .icon {
  transform: rotate(0deg);
}

.s-faq .answer {
  margin: 0;
  /* No static bottom padding: as the direct child of the 0fr grid track it would
     NOT collapse, leaving a ~24px dead strip under every closed row and stopping
     the close animation short of 0. The row's breathing space is applied only in
     the open state below, so a closed panel resolves to a true 0px. */
  padding-block: 0;
  padding-right: var(--sp-8);
  max-width: var(--maxw-prose);
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}

/* Bottom air only while genuinely open (native [open] no-JS + JS .isOpen). The
   closing rule (.details[open]:not(.isOpen)) below zeroes it so the panel
   animates fully to 0fr → 0px. */
.s-faq .details[open] .answer,
.s-faq .details.isOpen .answer {
  padding-bottom: var(--sp-5);
}
.s-faq .details[open]:not(.isOpen) .answer {
  padding-bottom: 0;
}

/* Reduced motion — no grid-rows or chevron animation; native instant toggle.
   The panel still resolves to its correct final track via the [open] rules
   above (which carry no transition once this block neutralizes it). */
@media (prefers-reduced-motion: reduce) {
  .s-faq .panel,
  .s-faq .icon,
  .s-faq .summary {
    transition: none !important;
  }
}

/* ===== css/sections/finalcta.css ===== */
/* =============================================================================
   FinalCTA (.s-finalcta) — section 12. Black deepest close, centered, big
   whitespace halo, pill mark glowing in a calm Cadmium light-field. Ported from
   components/sections/FinalCTA/FinalCTA.module.css. EVERY selector scoped under
   .s-finalcta; keyframe renamed finalcta-lightDrift. All values tokenized.
   ============================================================================= */

.s-finalcta {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background-color: var(--dark-bg-2);
  color: var(--dark-ink);
  padding-block: var(--section-y);
  text-align: center;
}

/* ---------------------------------------------------------------------------
   Calm Cadmium light-field — the ONLY gradient allowed here, and it's *light*,
   not section color (creative-direction §2.1 rule 5 / §4). Three low-opacity
   warm radials over the flat Black, behind the content. Sits below z-index 0.
   --------------------------------------------------------------------------- */
.s-finalcta .light-field {
  position: absolute;
  inset: -20% -10% auto;
  z-index: -1;
  height: 120%;
  pointer-events: none;
  /* Colors derived from brand tokens via color-mix so no raw hex ships:
     Cadmium "sun" + Golden-Hour mid + Ochre "floor", all fading to transparent. */
  background:
    radial-gradient(
      40% 38% at 50% 32%,
      color-mix(in srgb, var(--c-cadmium) 22%, transparent) 0%,
      color-mix(in srgb, var(--c-cadmium) 0%, transparent) 70%
    ),
    radial-gradient(
      55% 50% at 50% 30%,
      color-mix(in srgb, var(--c-golden-hour) 16%, transparent) 0%,
      color-mix(in srgb, var(--c-golden-hour) 0%, transparent) 72%
    ),
    radial-gradient(
      60% 70% at 50% 86%,
      color-mix(in srgb, var(--c-ochre) 10%, transparent) 0%,
      color-mix(in srgb, var(--c-ochre) 0%, transparent) 75%
    );
  transform: translateZ(0);
}

@media (prefers-reduced-motion: no-preference) {
  .s-finalcta .light-field {
    animation: finalcta-lightDrift 14s var(--ease-in-out) infinite alternate;
    will-change: transform;
  }
}

@keyframes finalcta-lightDrift {
  from {
    transform: translate3d(-1.5%, -1%, 0) scale(1);
  }
  to {
    transform: translate3d(1.5%, 1.5%, 0) scale(1.06);
  }
}

/* ---------------------------------------------------------------------------
   Inner column — centered, narrow measure, generous halo of whitespace.
   --------------------------------------------------------------------------- */
.s-finalcta .inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-6);
  /* rem-based measure so the centered column doesn't collapse against the small
     body font — gives the display-scale heading room for two clean lines. */
  max-width: min(48rem, 92vw);
}

/* The glowing pill mark — the brand's capsule "A" lozenge, the calm focal mote. */
.s-finalcta .mark {
  display: inline-flex;
  margin-bottom: var(--sp-2);
}

.s-finalcta .mark-image {
  width: clamp(3.5rem, 6vw, 5.5rem);
  height: auto;
  /* Cadmium halo — soft glow derived from the brand token (no raw hex). */
  filter: drop-shadow(
      0 0 var(--sp-6) color-mix(in srgb, var(--c-cadmium) 45%, transparent)
    )
    drop-shadow(
      0 0 var(--sp-3) color-mix(in srgb, var(--c-cadmium) 30%, transparent)
    );
}

.s-finalcta .content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-5);
  width: 100%;
}

/* Override the global .eyebrow atom color — warm Cadmium emphasis on Black. */
.s-finalcta .eyebrow {
  color: var(--accent-warm);
}

.s-finalcta .heading {
  /* Sized so each SENTENCE fits on one line (the crescendo: a touch larger than
     the hero's 3.25rem cap). The em below drops "Support your skin." to line 2.
     No per-heading measure cap — it would force "Transform your body." to wrap;
     it reads inside the centered .inner column instead. */
  font-size: clamp(2.5rem, 1rem + 4vw, 4.25rem);
  text-wrap: balance;
}

/* Break the headline at the sentence boundary, mirroring the hero: the italic
   2nd sentence drops to its own line rather than wrapping mid-sentence. */
.s-finalcta .heading em {
  display: block;
  font-style: italic;
}

.s-finalcta .subhead {
  margin: 0;
  max-width: 46ch;
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  color: var(--dark-ink);
  text-wrap: balance;
}

/* ---- CTA cluster ---- */
.s-finalcta .actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-5);
  margin-top: var(--sp-2);
}

.s-finalcta .primary {
  box-shadow: var(--shadow-glow);
}

/* Override the ghost Button (its --ink color is invisible on Black). Descendant
   selector keeps specificity above the atom's .btn--ghost rule reliably. */
.s-finalcta .actions .secondary {
  color: var(--dark-ink);
}
.s-finalcta .actions .secondary:hover {
  color: var(--accent-warm);
}

/* ---- mono reassurance row ---- */
.s-finalcta .reassurance {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2) var(--sp-3);
  margin: var(--sp-2) 0 0;
  padding: 0;
  list-style: none;
  /* Widened from 64ch so the full row stays single-line (or wraps as a clean
     2+2) — narrower than the content, it wrapped mid-row and stranded a leading
     '·' at the start of line 2. The .inner column still caps the true width. */
  max-width: 76ch;
}

.s-finalcta .reassurance-item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--dark-ink-soft);
}

/* Hide the markup-bound inline dots: placed at the START of items 2-4, they
   orphaned a stray '·' at a row's left edge on wrap. Draw the separator with a
   pseudo-element that renders only BETWEEN adjacent items instead, so it can
   never lead a line. */
.s-finalcta .divider {
  display: none;
}

.s-finalcta .reassurance-item + .reassurance-item::before {
  content: "·";
  margin-inline-end: var(--sp-3);
  color: var(--accent-metal);
}

@media (min-width: 48rem) {
  .s-finalcta .inner {
    gap: var(--sp-7);
    max-width: min(52rem, 90vw);
  }
  .s-finalcta .heading {
    /* No measure cap (was 26ch, which clipped "Transform your body." onto two
       lines at display scale); the controlled crescendo size from the base rule
       carries through. Keep the display line-height for the two-line stack. */
    line-height: var(--lh-display);
  }
}

