/** Shopify CDN: Minification failed

Line 2635:10 Expected identifier but found whitespace
Line 2635:15 Unexpected ";"
Line 2689:15 Expected identifier but found whitespace
Line 2689:16 Unexpected "4"
Line 2817:11 Expected identifier but found whitespace
Line 2817:20 Unexpected ";"
Line 2975:6 Expected identifier but found whitespace
Line 2975:7 Unexpected "clamp("
Line 3021:13 Expected identifier but found whitespace
Line 3021:14 Unexpected "clamp("
... and 4 more hidden warnings

**/
/* ============================================================================
   FSK ROUGH MARQUEE · fsk-design.css
   Ported 2026-07-13 from content-drafts/asset-packs/master-pack/{tokens,components}.css
   and content-drafts/website-preplan/homepage-comp.html (the CORRECTED reference).
   Layered ON TOP of Horizon base.css to render the FSK design language:
   living-gradient haze, seamless waves, per-block color, product-card crest,
   pre-paint dark/light. The ONLY FSK file allowed raw hex (TL-1 grep gate).
   Corrections baked in: primary CTA = Citrus + Ink Navy (comp override, 2026-07-12);
   no button grain-hover (#4); plain text links (#3); centered wrapped rows (#2).
   ========================================================================== */

/* ============================================================================
   MOTION / NAMESPACE / Z-INDEX CONTRACT
   (Phase 5 scrollytelling-readiness gate, written 2026-07-22. Reflects the ACTUAL
   current architecture, NOT the audit-time native-scroll-timeline one, which was
   removed 2026-07-21/22.)  READ BEFORE ADDING ANY SCROLLYTELLING / GSAP / RIVE /
   LOTTIE / NEW MOTION.

   1. SCROLL MOTION IS JS-DRIVEN, not native CSS scroll-timeline.
      Driver: assets/fsk-scroll-motion.js (mirrors fsk-haze.js). Native
      `animation-timeline: view()` was removed because it failed in a real
      supporting browser and gives zero motion on iOS Safari / Firefox
      (reference_native_scroll_timeline_unreliable, PF-37). The `--fsktl` /
      `--fsknat` / anonymous view() timelines no longer exist.
      Per-scene contract:
        - scene root carries `data-fsk-scroll`
        - each animated element carries `data-r="<start> <end>"` (0..1 of the
          scene view-progress); optional `data-follow="<selector>"` rides a path tip
        - CSS sets `animation-name` ONLY under `.fsk-motion-js` (added after the
          first frame). The base rule (outside `.fsk-motion-js`) MUST be the
          FINISHED / visible frame, so no-JS and reduced-motion fall through to it.
      The driver runs a CONTINUOUS requestAnimationFrame loop reading the real
      scroller (`.page-wrapper` when it is the scroll container, i.e. Horizon
      desktop; otherwise the document). A bare `window` scroll listener does NOT
      fire on Horizon desktop, so any new scroll motion MUST read the scroller
      this same way, never window scroll events, and MUST key to scroll DISTANCE /
      view-progress, never page fraction.

   2. RESERVED @keyframes (do not redefine or collide):
        haze:     fsk-drift-blue|teal|teal2|citrus|amber
        benefit:  fsk-bhead-rise, fsk-bline-draw
        marquee:  fsk-marq*
        refill:   fsk-loop-draw, fsk-perk-in
        bio:      fsk-bio-blob, fsk-bio-drop, fsk-ves-form
        nature:   fsknat-bloom|gust|settle|spill
        timeline: fsk-tl-draw|rise|pop
      Gate class: `.fsk-motion-js`. Scene owners (data-fsk-scroll): fsk-bioavailability
      (.fsk-bio__win), fsk-benefit-cards (.fsk-head-reveal), fsk-subscribe-education +
      fsk-bundle-cta (.fsk-refill-loop), fsk-timeline, and the nature scene (fsknat-*).

   3. Z-INDEX CEILING = 30 for all FSK content and motion. The 2147482000 /
      2147483000 values are top-layer overlay sentinels (drawers / popovers) only;
      do NOT reuse them for scene motion.

   4. RULE for incoming GSAP / Rive / Lottie / new motion:
        - It MUST REPLACE a CSS/JS driver on an element, or target DISJOINT elements.
          Never double-drive (two systems animating the same element).
        - Every new animation MUST ship a `prefers-reduced-motion: reduce` fallback
          AND a no-JS finished-frame base state.
        - No `gsap` / `ScrollTrigger` / `Rive` globals exist today (clean namespace,
          verified 2026-07-22). Keep new libraries scoped; do not leak colliding globals.
        - R-9 gate: run Lighthouse before/after on the SAME template when a scrolly
          library lands, to catch motion/JS perf regressions.
   ========================================================================== */

/* ------------------------------ TOKENS ---------------------------------- */
:root {
  --mint-air: #F0FFFE;
  --mint-surface: #E3F8F4;
  --reef-teal: #2FE7E1;
  --deep-blue: #0062E3;
  --ink-navy: #0A2540;
  --citrus: #F2EE54;
  --amber: #F6C445;
  --white: #FFFFFF;
  --night-base: #0C0D10;
  --night-surface: #15171C;

  --ink-04: rgba(10,37,64,0.04);
  --ink-08: rgba(10,37,64,0.08);
  --ink-13: rgba(10,37,64,0.13);
  --ink-16: rgba(10,37,64,0.16);
  --ink-22: rgba(10,37,64,0.22);
  --ink-25: rgba(10,37,64,0.25);
  --ink-40: rgba(10,37,64,0.40);
  --ink-60: rgba(10,37,64,0.60);
  --ink-67: rgba(10,37,64,0.67);
  --mintair-06: rgba(240,255,254,0.06);
  --mintair-10: rgba(240,255,254,0.10);
  --mintair-16: rgba(240,255,254,0.16);
  --mintair-28: rgba(240,255,254,0.28);
  --mintair-55: rgba(240,255,254,0.55);
  --mintair-72: rgba(240,255,254,0.72);
  --teal-12: rgba(47,231,225,0.12);
  --teal-18: rgba(47,231,225,0.18);
  --teal-35: rgba(47,231,225,0.35);
  --amber-12: rgba(246,196,69,0.12);
  --amber-16: rgba(246,196,69,0.16);
  --amber-35: rgba(246,196,69,0.35);
  --citrus-16: rgba(242,238,84,0.16);
  --citrus-30: rgba(242,238,84,0.30);
  --blue-08: rgba(0,98,227,0.08);
  --blue-14: rgba(0,98,227,0.14);
  --blue-30: rgba(0,98,227,0.30);

  color-scheme: light;
  --color-bg: var(--mint-air);
  --color-surface: var(--mint-surface);
  --color-surface-raised: var(--white);
  --color-text: var(--ink-navy);
  --color-text-muted: var(--ink-67);
  --color-heading: var(--ink-navy);
  --color-link: var(--deep-blue);
  --color-accent: var(--deep-blue);
  --color-brand: var(--reef-teal);
  --color-highlight: var(--citrus);
  --color-border: var(--ink-13);
  --color-border-strong: var(--ink-25);
  /* corrected reference (homepage-comp.html, Andrew 2026-07-12): primary CTA goes
     yellow (Citrus) + Ink Navy label; Deep Blue keeps links only */
  --color-cta-fill: var(--citrus);
  --color-cta-label: var(--ink-navy);
  --color-cta-value-fill: var(--amber);
  --color-cta-value-label: var(--ink-navy);
  --color-inverse-bg: var(--ink-navy);
  --color-inverse-text: var(--white);
  --color-inverse-cta-fill: var(--citrus);
  --color-inverse-cta-label: var(--ink-navy);

  --color-star-fill: var(--amber);
  --color-star-outline: var(--ink-navy);

  --color-card-plate: var(--reef-teal);
  --plate-rim: 7px;

  --color-focus-ring: var(--deep-blue);
  --focus-ring: 0 0 0 3px var(--color-bg), 0 0 0 6px var(--color-focus-ring);

  --veil-hover: var(--ink-16);
  --veil-pressed: var(--ink-22);
  --veil-hover-on-amber: rgba(10,37,64,0.14);
  --veil-pressed-on-amber: var(--ink-16);

  --radius-xs: 6px;  --radius-sm: 10px; --radius-md: 16px;
  --radius-lg: 24px; --radius-xl: 44px; --radius-dot: 50%;
  --radius-seed-s: 22px 22px 22px 8px;
  --radius-seed-m: 26px 26px 26px 10px;
  --radius-seed-l: 30px 30px 30px 12px;
  --radius-seed-input: 16px 16px 16px 6px;
  --radius-seed-card: 24px 24px 24px 10px;
  --radius-seed-feature: 44px 44px 44px 16px;
  --radius-seed-badge: 16px 16px 16px 6px;

  --space-1: 4px;  --space-2: 8px;   --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px;  --space-7: 48px; --space-8: 64px;
  --space-9: 96px;

  --shadow-rest: 0 6px 16px -6px rgba(10,37,64,0.28);
  --shadow-settle: 0 3px 8px -4px rgba(10,37,64,0.30);
  --shadow-raised: 0 14px 40px -10px rgba(10,37,64,0.20);
  --shadow-card: 0 6px 24px -8px rgba(10,37,64,0.15);
  --shadow-amber-rest: 0 6px 18px -6px rgba(246,196,69,0.35);
  --shadow-amber-settle: 0 3px 9px -4px rgba(246,196,69,0.40);

  --border-hairline: 1.5px;
  --border-stroke: 2.5px;

  --motion-quick: 120ms;
  --motion-settle: 180ms;
  --motion-slow: 260ms;
  --ease-settle: cubic-bezier(0.34, 0.80, 0.40, 1);
  --ease-out: cubic-bezier(0.20, 0.70, 0.30, 1);

  --font-display: 'Fraunces', Georgia, serif;
  --font-display-settings: 'SOFT' 100;
  --font-body: 'Nunito Sans', -apple-system, 'Segoe UI', sans-serif;
  --text-body: 16px;
  --text-small: 14px;
  --text-micro: 12px;
  --leading-body: 1.65;
  --tracking-eyebrow: 0.14em;
  --tracking-badge: 0.06em;

  --scrim-hero: linear-gradient(180deg, rgba(10,37,64,0) 42%, rgba(10,37,64,0.55) 100%);
}

[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: var(--night-base);
  --color-surface: var(--night-surface);
  --color-surface-raised: var(--night-surface);
  --color-text: var(--mint-air);
  --color-text-muted: var(--mintair-72);
  --color-heading: var(--mint-air);
  --color-link: var(--amber);
  --color-accent: var(--amber);
  --color-brand: var(--reef-teal);
  --color-highlight: var(--citrus);
  --color-border: var(--mintair-16);
  --color-border-strong: var(--mintair-28);
  --color-cta-fill: var(--amber);
  --color-cta-label: var(--ink-navy);
  --color-cta-value-fill: var(--amber);
  --color-cta-value-label: var(--ink-navy);
  --color-inverse-bg: var(--night-surface);
  --color-inverse-text: var(--mint-air);
  --color-inverse-cta-fill: var(--amber);
  --color-inverse-cta-label: var(--ink-navy);
  --color-star-fill: var(--amber);
  --color-star-outline: transparent;
  --color-focus-ring: var(--amber);
  /* HORIZON SCHEME TOKENS -- the root cause of the "black text in dark mode" defect.
     snippets/color-palette.liquid emits --color-foreground / --color-background from
     settings_data.json's color_palette, which is foreground #000000 / background #ffffff,
     and those NEVER remap with [data-theme]. 64 rules in base.css consume them, so every
     Horizon-owned element renders literal black: measured 1.08:1 on night-base, 1.17:1 on
     night-surface, 1.14:1 on the dark glass buy-box panel (gate 4.5). This was previously
     mitigated by a 4-selector allowlist on .product-information, which left every other
     Horizon surface black. Remapped here at the token level so all 64 inherit the fix.
     Both are remapped together: flipping only the foreground would strand light text on
     the still-white --color-background pairings. */
  --color-foreground: var(--mint-air);
  --color-foreground-rgb: 240 255 254;
  --color-background: var(--night-surface);
  --veil-hover: var(--veil-hover-on-amber);
  --veil-pressed: var(--veil-pressed-on-amber);
  --shadow-card: 0 6px 24px -8px rgba(12,13,16,0.60);
  --scrim-hero: linear-gradient(180deg, rgba(12,13,16,0) 42%, rgba(12,13,16,0.72) 100%);
}

@media (prefers-reduced-motion: reduce) {
  :root { --motion-quick: 0ms; --motion-settle: 0ms; --motion-slow: 0ms; }
}

/* --------- let the fixed haze show through the page (Horizon paints an
             opaque page background otherwise) --------- */
html, body { background-color: transparent !important; }
.page-wrapper,
#MainContent,
.content-for-layout,
main { background: transparent !important; }
/* FSK section wrappers must not carry an opaque Horizon color-scheme fill */
.shopify-section:has(.fsk-sec) { background: transparent !important; }

/* ------------------------- LIVING-GRADIENT HAZE -------------------------- */
.fsk-haze {
  position: fixed; inset: 0; z-index: -1; overflow: hidden;
  background: var(--color-bg); pointer-events: none;
  --haze: 1.60; --grain-o: 0.06;
  /* Motion amplitude dial read by fsk-haze.js (HAZE-RECIPE §2a). 1 = the timid
     original, 2 = ruled default. Commerce-critical templates can dial down. */
  --haze-motion: 2;
}
.fsk-haze .fog { position: absolute; opacity: var(--haze); will-change: transform; }
.fsk-haze .fog-blue   { width: 95vmax; height: 78vmax; top: -34vmax; right: -28vmax; background: radial-gradient(closest-side, rgb(0 98 227/.22), rgb(0 98 227/.09) 48%, rgb(0 98 227/0) 74%); }
.fsk-haze .fog-teal   { width: 82vmax; height: 64vmax; top: 12vh; left: -30vmax; background: radial-gradient(closest-side, rgb(47 231 225/.20), rgb(47 231 225/.08) 50%, rgb(47 231 225/0) 75%); }
.fsk-haze .fog-teal2  { width: 56vmax; height: 48vmax; bottom: -22vmax; right: -14vmax; background: radial-gradient(closest-side, rgb(47 231 225/.12), rgb(47 231 225/.05) 50%, rgb(47 231 225/0) 75%); }
.fsk-haze .fog-citrus { width: 88vmax; height: 42vmax; bottom: -14vmax; left: 10vw; transform: rotate(-7deg); background: radial-gradient(closest-side, rgb(242 238 84/.30), rgb(242 238 84/.12) 48%, rgb(242 238 84/0) 74%); }
.fsk-haze .fog-amber  { width: 62vmax; height: 52vmax; top: -24vmax; left: -18vmax; background: radial-gradient(closest-side, rgb(246 196 69/.20), rgb(246 196 69/.08) 50%, rgb(246 196 69/0) 75%); }
.fsk-haze .grain {
  position: absolute; inset: 0; opacity: var(--grain-o); mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
}
/* NOTE: the CSS scroll-timeline drift was removed 2026-07-17 — Horizon scrolls
   .page-wrapper, not the root, so scroll(root) never advanced (static haze bug)
   AND it pinned transforms so the JS fallback was ignored. assets/fsk-haze.js
   now drives the drift from the real scroller in all browsers.
   2026-07-19: that JS keyed its sway to scroll FRACTION, so motion silently
   slowed as a page got longer — on a 10-screen homepage the field shifted only
   ~1.7/255 per screenful and read as a static repeating backdrop. The sway is
   now keyed to scroll DISTANCE (viewport heights), which is page-length neutral.
   The keyframes below are dead (JS owns the drift); kept only as the documented
   reference for the original per-layer drift vectors. */
@keyframes fsk-drift-blue   { to { transform: translate3d(-6vw,10vh,0) scale(1.06); } }
@keyframes fsk-drift-teal   { to { transform: translate3d(7vw,-7vh,0) scale(1.10) rotate(2deg); } }
@keyframes fsk-drift-teal2  { to { transform: translate3d(-5vw,-9vh,0) scale(1.05); } }
@keyframes fsk-drift-citrus { to { transform: translate3d(9vw,-4vh,0) rotate(-9deg) scale(1.12); } }
@keyframes fsk-drift-amber  { to { transform: translate3d(4vw,7vh,0) scale(0.94); } }

/* ------------------------------ WAVES ----------------------------------- */
/* currentColor set to the DESTINATION band's color; the wave's straight bottom
   butts flush to the band top → seamless, no gap (correction #8). */
/* A wave is a two-color seam: the div BACKGROUND = the block ABOVE (top-*), the
   path FILL (currentColor) = the block BELOW. That's what makes it seamless with
   no gap. A flipped wave puts the fill on top (a solid band sinking into haze). */
.fsk-wave { display: block; width: 100%; height: clamp(66px, 10vw, 150px); line-height: 0; }
.fsk-wave svg { display: block; width: 100%; height: 100%; }
/* WAVES LOCKED 2026-07-17: single family (draft-C character), 6 per-seam variants
   baked in markup. Mobile (<750px) swaps to the 4-swell paths. */
.fsk-wave .fw-m { display: none; }
@media (max-width: 749px) {
  .fsk-wave .fw { display: none; }
  .fsk-wave .fw-m { display: inline; }
}
/* path fill = block below */
.fsk-wave--surface  { color: var(--color-surface); }
.fsk-wave--navy     { color: var(--color-inverse-bg); }
.fsk-wave--citrus   { color: var(--fsk-citrus-ground); }
.fsk-wave--amber    { color: var(--amber); }
.fsk-wave--teal     { color: var(--reef-teal); }
.fsk-wave--deepblue { color: var(--deep-blue); }
/* div background = block above (default transparent = haze shows through) */
.fsk-wave--top-haze     { background: transparent; }
.fsk-wave--top-surface  { background: var(--color-surface); }
.fsk-wave--top-navy     { background: var(--color-inverse-bg); }
.fsk-wave--top-citrus   { background: var(--fsk-citrus-ground); }
.fsk-wave--top-amber    { background: var(--amber); }
.fsk-wave--top-teal     { background: var(--reef-teal); }
.fsk-wave--top-deepblue { background: var(--deep-blue); }
.fsk-wave--flip svg { transform: scaleY(-1); }

/* SEAM SEAL -- LAUNCH DESIGN CORRECTION #8 ("no gap visible at the seam").
   The wave SVG uses preserveAspectRatio="none", so its solid edge is rasterised at a
   fractional device pixel. At fractional device-pixel ratios (measured failing at 1.25x,
   1.5x and 1.75x; clean at 1x and 2x) a 1px row of page ground survives between the wave
   and the band it flows into. It is only PERCEPTIBLE on the high-contrast seams -- the
   Deep Blue subscribe band and the teal sourcing band, where the bleed measures delta 246
   against the band; on Mint Surface -> haze seams the same rounding is delta 30 and
   invisible. Confirmed by pixel render, not by layout: getBoundingClientRect reports
   gap = 0 at every seam and every width, so geometry alone cannot see this.
   The previous remedy was margin-bottom/-top: -1px scoped to .fsk-src alone. That is
   removed below: it did not survive fractional DPR (fsk-sourcing still hairlined at 1.5x
   and 1.75x while carrying it) and it only ever covered one section.
   This seals it at the wave component instead, so every seam inherits the fix and no
   future band re-solves it. currentColor is already the destination band's colour (it is
   what fills the SVG path), so a 2px bleed strip on the solid edge is exactly the colour
   the seam should be: it overlaps 1px into the band, invisibly, and covers any rounding. */
.fsk-wave { position: relative; }
.fsk-wave::after {
  content: ""; position: absolute; left: 0; right: 0; height: 2px;
  background: currentColor; pointer-events: none;
}
.fsk-wave:not(.fsk-wave--flip)::after { bottom: -1px; }
/* a flipped wave carries its solid edge at the TOP (the svg is scaleY(-1)) */
.fsk-wave--flip::after { top: -1px; }

/* ------------------------------ BANDS ----------------------------------- */
.fsk-sec { margin: 0; position: relative; }
.fsk-band { padding-block: clamp(48px, 8vw, 96px); position: relative; }
/* X-01 (2026-07-29, Andrew): "we can tighten up between the wave banners and the top of the
   text ... the goal is a lot of negative space, but we're going a little too far and now we're
   making worthless space." A wave is already 66-150px tall, and the band then added its full
   48-96px top padding underneath it, so a wave-to-heading gap could reach ~246px of nothing.
   Scoped to the wave-adjacent case ONLY, via the adjacent sibling: bands that are NOT preceded
   by a wave keep the original rhythm untouched, so this cannot flatten the whole site. Andrew's
   brief was explicit that a small cut is enough, so this is roughly a third off the top padding
   and nothing else. The trailing side (band bottom padding stacking under a flipped wave) has
   the same shape and is deliberately LEFT ALONE pending his eye on this one first. */
/* Second selector catches the one wave in the theme that is WRAPPED rather than being a
   direct sibling of its band: fsk-fresh-booth.liquid puts its wave inside a
   <div data-block="teal"> so the wave picks up the PF-16 softened teal. Without this the
   adjacent-sibling rule silently skipped that band and it alone kept the old wider gap.
   Found by the DeepSeek red-team pass on 1A (it flagged the selector as brittle) and then
   measured: 1 wrapped wave out of 65. :only-child keeps it to wrapper-around-a-wave and
   cannot catch an unrelated element that merely contains a wave somewhere inside it. */
.fsk-wave + .fsk-band,
:has(> .fsk-wave:only-child) + .fsk-band { padding-top: clamp(32px, 5vw, 64px); }
.fsk-band--haze { background: transparent; }

/* Apple-style frosted glass. Horizon's #MainContent carries view-transition-name,
   which isolates the fixed page-haze out of a nested panel's backdrop — so the panel
   read as a flat box. Fix: the panel sits over its OWN local colour glow
   (.fsk-glass-scene__glow) in the same stacking context, which backdrop-filter frosts.
   isolation:isolate pins that glow as the definitive backdrop. */
.fsk-glass-scene { position: relative; overflow: hidden; isolation: isolate; }
.fsk-glass-scene__glow {
  position: absolute; inset: -14%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(48% 66% at 32% 38%, var(--teal-35), transparent 70%),
    radial-gradient(50% 66% at 72% 32%, var(--blue-30), transparent 72%),
    radial-gradient(58% 68% at 55% 90%, var(--citrus-30), transparent 72%),
    radial-gradient(44% 54% at 88% 74%, var(--amber-35), transparent 72%);
  filter: blur(20px);
  /* The glow is inset -14%, so it is 128% of the section's height and the parent's
     overflow:hidden clips it at 10.9%/89.1% of its own box. A mask that only
     reached zero at 0%/100% was therefore still ~50% opaque exactly where it got
     clipped — which painted a hard horizontal line across the page (the "solid
     cut-off", 2026-07-19). Stops now reach zero INSIDE the clip box. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 10%, #000 34%, #000 66%, transparent 90%);
  mask-image: linear-gradient(to bottom, transparent 10%, #000 34%, #000 66%, transparent 90%);
}
.fsk-glass {
  position: relative; z-index: 1;
  background: rgba(255,255,255,0.14);
  -webkit-backdrop-filter: blur(24px) saturate(1.7);
  backdrop-filter: blur(24px) saturate(1.7);
  border: 1px solid rgba(255,255,255,0.5);
  border-radius: var(--radius-seed-feature);
  box-shadow: var(--shadow-raised), inset 0 1px 0 rgba(255,255,255,0.65);
}
[data-theme="dark"] .fsk-glass {
  background: rgba(18,20,25,0.34);
  border-color: rgba(240,255,254,0.16);
  box-shadow: var(--shadow-raised), inset 0 1px 0 rgba(240,255,254,0.14);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .fsk-glass { background: rgba(255,255,255,0.62); }
  [data-theme="dark"] .fsk-glass { background: rgba(18,20,25,0.68); }
}
.fsk-band--surface { background: var(--color-surface); }
.fsk-band--raised  { background: var(--color-surface-raised); }

/* PF-23 CARD LIFT, APPLIED AT THE TOKEN LEVEL (not per band).
   In dark mode --color-surface and --color-surface-raised BOTH resolve to --night-surface
   (see the [data-theme="dark"] block above), so any raised card sitting on a
   .fsk-band--surface measures exactly 1.000:1 against its own ground and is visible only
   by its drop shadow. Measured on 10 cards across the PDP, homepage and collection:
   fsk-extraction-highlights (.fsk-outcomes__item, .fsk-media), fsk-how-to-take
   (.fsk-step__ico), fsk-also-try (.fsk-scard, .fsk-scard__media, .fsk-panel),
   home/fsk-benefit-cards (.fsk-scard, .fsk-scard__media), collection/fsk-shop-by-goal
   (.fsk-scard) and collection/fsk-reviews-placeholder (.fsk-panel).
   PF-23 ruled the remedy as color-mix(in srgb, var(--mint-air) 7%, var(--night-surface))
   and it shipped on the comparison matrix only (.fsk-cmp__scroll et al), which is exactly
   why every other band still carried the defect. Redefining --color-surface-raised itself
   inside a surface band lifts every raised component at once -- current and future -- so
   no future band has to re-solve it. Resolves to #24272C: 1.20:1 against the band it sits
   on (the ruled separation) and 14.58:1 for Mint Air text on it. */
[data-theme="dark"] .fsk-band--surface {
  --color-surface-raised: color-mix(in srgb, var(--mint-air) 7%, var(--night-surface));
}
/* PF-54 (ruled 2026-07-26): dark mode softens the Citrus band the same way PF-16
   softened Teal -- full-strength Citrus against the near-black page reads as a
   neon slab. ONE composed value drives the band AND its wave seams (.fsk-wave--citrus /
   .fsk-wave--top-citrus below, which are SIBLINGS of the band inside .fsk-sec, not
   children); composing them separately produced a hard straight edge at the seam,
   the same PF-16 lesson. Light mode is unchanged (resolves to --citrus).

   PF-58 (ruled 2026-07-27, Andrew, candidate B -- AMENDS PF-54's mix, not its mechanism):
   PF-54 mixed --citrus into the dark, which resolved to #3d3e26 = rgb(61,62,38). Citrus is
   a yellow with a very high green channel, so any citrus-into-near-black mix lands on
   OLIVE. Andrew rejected it on sight ("no olive, no green, that is so off from our brand
   kit"). Mixing --amber instead resolves to #3e3623 = rgb(62,54,35): red channel highest,
   warm gold-brown, zero green cast. Amber is already the dark-mode CTA fill here, so the
   band and its button now come from the same hue family.
   Contrast IMPROVES: Mint Air on the new ground is 10.88:1 (was 9.98:1), against a >=7:1
   G4 dark gate. The Mint Air text pin from PF-54 must STAY -- Ink Navy on this ground is
   1.3:1. Light mode still untouched. */
:root               { --fsk-citrus-ground: var(--citrus); }
[data-theme="dark"] { --fsk-citrus-ground: color-mix(in srgb, var(--citrus) 85%, var(--night-surface)); }
/* --fsk-glyph-knockout: duotone spot-glyph cutout ground (benefit-focus-clarity,
   benefit-stress-balance, usage-coffee -- the 6 master-pack files carrying this role,
   see snippets/fsk-svg-defs.liquid header). Tracks --color-inverse-bg live so it stays
   correct across Ink Navy (default), Deep Blue-adjacent, and [data-block="warm"] bands;
   [data-block="teal"] below overrides this with a hard pin per PF-15. */
.fsk-band--dark    { background: var(--color-inverse-bg); color: var(--color-inverse-text); --fsk-glyph-knockout: var(--color-inverse-bg); }
/* Light-side completion of the PF-28(b) fixed-ground pin (P-04): Deep Blue on Citrus measures
   4.44:1 (fails the 4.5 text gate), and palette law G4 rules labels on Citrus are Ink Navy.
   (PF-54, 2026-07-26: dark mode no longer shares this Ink Navy pin -- its softened ground
   reverses it to Mint Air below -- but this unscoped rule still governs light mode, and
   dark mode's own [data-theme="dark"] .fsk-band--citrus override still wins there.) */
/* PF-59 (2026-07-27): --color-text / --color-heading / --color-text-muted are pinned HERE,
   in the base rule, not in a dark-mode override. Light mode masked the gap because those
   globals are already Ink Navy there; in dark they invert to Mint Air, so .fsk-p rendered
   light-on-yellow (caught in a render, not by any gate). Pinning at band level is the rule
   this file already states, and it makes the band theme-independent. */
.fsk-band--citrus  { background: var(--fsk-citrus-ground); color: var(--ink-navy); --color-link: var(--ink-navy); --color-accent: var(--ink-navy); --color-brand: var(--ink-navy); --color-text: var(--ink-navy); --color-heading: var(--ink-navy); --color-text-muted: var(--ink-67); }
.fsk-band--deepblue{ background: var(--deep-blue); color: var(--white); }
.fsk-band--dark :is(.fsk-h, .fsk-eyebrow, .fsk-lede),
.fsk-band--deepblue :is(.fsk-h, .fsk-eyebrow, .fsk-lede) { color: inherit; }

.fsk-wrap { width: 100%; max-width: 1180px; margin-inline: auto; padding-inline: clamp(16px, 4vw, 40px); }
.fsk-wrap--narrow { max-width: 820px; }

/* ---------------------- per-block color override ------------------------ */
/* Default = Navy dark bands (base). Live control cycles teal / warm. */
/* --fsk-glyph-knockout pinned to Mint Air (PF-15): a knockout-carrying duotone icon on a
   teal band sits on its own light disc/chip plate, not raw Reef Teal -- --color-surface-raised
   resolves to night-surface (near-black) in dark mode and would punch dark holes into a plate
   meant to stay light in both themes (same defect PF-15 fixed for .fsk-src__step-icon). Real
   discs-on-teal go translucent (--mintair-10) in dark mode (see .fsk-src__step-icon); this flat
   value is an approximation -- no current call site combines a knockout icon with a teal band,
   revisit if Track B places one. */
[data-block="teal"] { --color-inverse-bg: var(--reef-teal); --color-inverse-text: var(--ink-navy); --fsk-glyph-knockout: var(--mint-air); }
/* PF-16 (ruled 2026-07-20): a full Reef Teal slab in dark mode reads as a neon cyan panel
   carrying dark text -- the same "black text in dark mode" defect Andrew flagged. Softened
   wash instead; ONE composed value drives the band AND its wave seams so the seam stays
   exact (composing them separately produced a hard straight edge). Binding on every teal
   band, not just the section that introduced it. */
[data-theme="dark"] [data-block="teal"] {
  --color-inverse-bg: color-mix(in srgb, var(--reef-teal) 18%, var(--night-surface));
  --color-inverse-text: var(--mint-air);
}
[data-block="teal"] .fsk-wave--teal     { color: var(--color-inverse-bg); }
[data-block="teal"] .fsk-wave--top-teal { background: var(--color-inverse-bg); }
/* the shared .fsk-band--dark .fsk-eyebrow rule paints the eyebrow --color-brand (Reef Teal) --
   on a teal band that's the band's own background, so the eyebrow disappears (1.0:1). Element
   selector added only to out-specificity that same-specificity rule regardless of source order. */
/* 2026-08-07 audit: this was scoped to [data-block="teal"] alone, but that attribute lives on
   <html>, so it matched EVERY p.fsk-eyebrow on the site and out-specified the per-band rules
   below. On the Deep Blue FMS band it forced 72% alpha white (3.55:1, measured). Now scoped to
   the dark band it was written for, which still beats .fsk-band--dark .fsk-eyebrow (0,3,1 vs 0,2,0). */
[data-block="teal"] .fsk-band--dark p.fsk-eyebrow { color: inherit; opacity: 0.72; }
[data-block="warm"] { --color-inverse-bg: var(--amber); --color-inverse-text: var(--ink-navy); }

/* FIXED-GROUND BANDS (Citrus, Amber, Deep Blue) -- these keep the same background in BOTH
   themes, so they must not inherit dark mode's inverted text tokens. In dark, --color-link
   and --color-accent flip to Amber; on the Citrus band that rendered the fsk-markets
   "See all our markets" secondary button as Amber-on-Citrus at 1.33:1 (measured, and
   visibly illegible in the render). Same class of defect as PF-15/PF-16: a token that
   inverts landing on a ground that does not. Pinned at band level, not per component, so
   every current and future element inside these bands inherits the correct pairing.
   Measured on Amber: Ink Navy 9.54:1. On Deep Blue: white 5.45:1 (Amber 3.35:1, Reef
   Teal 3.54:1 and Citrus 4.44:1 all fail the 4.5 text gate).
   Citrus split out below (PF-54, ruled 2026-07-26): its ground now softens in dark mode
   too (--fsk-citrus-ground above), so the Ink Navy pin this block used to share with
   Amber/warm would measure only 1.42:1 there -- the exact "black text in dark mode"
   defect this file exists to prevent. Reversed to Mint Air. [data-block="warm"] (Amber)
   is NOT softened and keeps the original Ink Navy pin unchanged.
   `color` (not just the custom properties) is reversed too: .fsk-band--citrus sets its
   own plain `color: var(--ink-navy)` (not a custom-property read) for ordinary inherited
   text -- .fsk-h reads it via `color: inherit` (a higher-specificity rule a few lines
   down), and un-classed/plain-inherited text (.fsk-list li, .fsk-farmersign, etc.) reads
   it via normal CSS inheritance with no rule of its own. Neither would see the custom-
   property reversal above without this.

   PF-59 (2026-07-27, Andrew): the whole Mint Air reversal that used to live here is GONE.
   It only existed because PF-54/PF-58 darkened the ground. The band is now Citrus at 85%
   (#d1ce4c) in dark, where Ink Navy measures 9.36:1 and Mint Air would be 1.62:1 -- the
   reversal would now CAUSE the defect it was written to prevent. Deleting it lets the base
   .fsk-band--citrus rule govern both themes, so light and dark read identically here. */
[data-theme="dark"] .fsk-band--dark[data-block="warm"] {
  --color-link: var(--ink-navy);
  --color-accent: var(--ink-navy);
  --color-text: var(--ink-navy);
  --color-text-muted: var(--ink-67);
  --color-heading: var(--ink-navy);
}
[data-theme="dark"] .fsk-band--deepblue {
  --color-link: var(--white);
  --color-accent: var(--white);
  --color-text: var(--white);
  --color-heading: var(--white);
}
/* PF-55 (ruled 2026-07-26): Andrew ruled verbatim "citrus + ink Navy text is the CTA
   button color" -- the :root tokens (--color-cta-fill/--color-cta-label) already say
   that and are unchanged. But that ruled fill is invisible (1.0:1) on a Citrus-GROUND
   band itself, and Amber was already ruled out there (PF-28(b): Amber-on-Citrus 1.33:1,
   visibly illegible). So the exception is pinned at band level, matching the
   PF-15/PF-16/PF-28(b) pattern. Light: Deep Blue edge 4.44:1 / white label 5.45:1.
   Dark: the softened Citrus ground drops Deep Blue to 2.01:1, so Amber takes over --
   edge 6.73:1 / Ink Navy label 9.54:1. */
.fsk-band--citrus                     { --color-cta-fill: var(--deep-blue); --color-cta-label: var(--white); }
/* PF-59 (2026-07-27, Andrew, candidate F): the dark ground is Citrus at 85% (#d1ce4c), not a
   dark surface, so the Amber fill this used to carry would be Amber-on-yellow. Ink Navy fill
   with a Citrus label instead: 12.68:1 label-on-fill, 9.36:1 fill-against-band. */
[data-theme="dark"] .fsk-band--citrus { --color-cta-fill: var(--ink-navy);  --color-cta-label: var(--citrus); }

/* P-02: extraction-highlights LM video honors reduced motion without JS: the loop hides and
   its poster image shows. Both elements ship in the markup; this query does the swap. */
@media (prefers-reduced-motion: reduce) {
  .fsk-exh-vid { display: none !important; }
  .fsk-exh-poster { display: block !important; }
}
/* P-05 (Andrew, launch audit): "it's kind of like having a big show for small features."
   The how-to-take band shrinks until real images or the scrollytelling asset exist: heading
   drops a size in the Liquid, icons drop from 56px to 44px here. Scoped to this section. */
/* 2026-08-07 final audit · PF-6 accent floor. The plate under these step glyphs consumes
   --color-surface and the band it sits on IS Mint Surface, so the plate is invisible by
   design (ruled: same-plane plates are edgeless in light too). That makes the GLYPH the only
   accent this band has, and it was rendering at 22px against PF-6's "accents must read at
   44px" — the band read as the pale flat minimalism PF-6 calls a defect. The 2026-07 shrink
   noted above was a build decision; PF-6 is a §15 ruling and outranks it. Glyph now meets the
   floor exactly at 44px, plate sized to hold it. */
.fsk-howto .fsk-step__ico { width: 64px; height: 64px; }
.fsk-howto .fsk-step__ico svg { width: 44px; height: 44px; }

/* ------------------------------ TYPE ------------------------------------ */
.fsk-eyebrow {
  font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--color-link); margin: 0 0 var(--space-3);
}
.fsk-band--dark .fsk-eyebrow { color: var(--color-brand); }
/* Deep Blue split off from the Ink Navy dark band: --color-brand (Reef Teal) measures
   10.1:1 on Ink Navy but only 3.54:1 on Deep Blue, failing the 4.5 text gate -- and §0.2
   bars Reef Teal as text regardless. Takes §0.2's dark-band eyebrow colour, Mint Surface,
   at 4.93:1. Not dark-scoped: the Deep Blue band is the same ground in both themes, so
   this failed in light mode too. */
.fsk-band--deepblue .fsk-eyebrow { color: var(--mint-surface); }
.fsk-h {
  font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 600; line-height: 1.12; color: var(--color-heading); margin: 0;
}
.fsk-band--dark .fsk-h, .fsk-band--deepblue .fsk-h,
.fsk-band--citrus .fsk-h { color: inherit; }
/* PF-54: .fsk-h reads the BAND's own `color` via the rule above (not --color-heading),
   so the dark reversal on .fsk-band--citrus's own `color` property (a few rules up)
   covers headings automatically -- no extra rule needed here. */
.fsk-h--xl { font-size: clamp(2.2rem, 5vw, 3.6rem); }
.fsk-h--lg { font-size: clamp(1.8rem, 4vw, 2.7rem); }
.fsk-h--md { font-size: clamp(1.4rem, 3vw, 2rem); }
.fsk-lede {
  font-family: var(--font-body); font-size: clamp(1rem, 1.4vw, 1.18rem);
  line-height: var(--leading-body); color: var(--color-text-muted);
  max-width: 62ch; margin: var(--space-4) 0 0;
}
.fsk-lede p { margin: 0; }
/* was rgba(255,255,255,0.85) = 4.35:1 on Deep Blue, just under the 4.5 gate in BOTH
   themes; full white measures 5.45:1. The alpha was buying a softness the Deep Blue
   ground already provides. */
.fsk-band--deepblue .fsk-lede { color: var(--white); }
/* dark band follows the block color: white on Navy, Ink Navy on Teal/Warm (readable either way) */
.fsk-band--dark .fsk-lede { color: var(--color-inverse-text); opacity: 0.85; }
.fsk-band--citrus .fsk-lede { color: rgba(10,37,64,0.75); }
/* PF-59 (2026-07-27): the dark-mode Mint Air lede override that PF-54 added here is REMOVED.
   The dark ground is Citrus at 85% now, so the light rule above (Ink Navy at 75%) is correct
   in both themes and a Mint Air lede would be illegible on it. */
.fsk-p { font-family: var(--font-body); font-size: var(--text-body); line-height: var(--leading-body); color: var(--color-text); }
.fsk-section-head { max-width: 46rem; margin: 0 auto clamp(28px,4vw,48px); text-align: center; }

/* Benefit-cards reveal (PF-41, candidate B, ruled 2026-07-22): the money band's cards stay
   STATIC (no motion on any Add-to-cart control) — only the heading rises and a hairline draws
   under it. Scoped to .fsk-head-reveal so the shared .fsk-section-head is untouched. JS-driven
   via the shared scaffold; base = finished frame (heading visible, line solid). */
.fsk-head-reveal__line { display: block; width: min(280px, 55%); height: 6px; margin: 0 auto 18px; }
@keyframes fsk-bhead-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes fsk-bline-draw { to { stroke-dashoffset: 0; } }
.fsk-motion-js .fsk-head-reveal .fsk-h { opacity: 0; animation-name: fsk-bhead-rise; }
.fsk-motion-js .fsk-head-reveal__line path { stroke-dasharray: 100; stroke-dashoffset: 100; animation-name: fsk-bline-draw; }

/* plain text link — NO decorative teal/blue underline (correction #3) */
.fsk-link { color: var(--color-link); text-decoration: none; font-weight: 700; font-family: var(--font-body); }
.fsk-link:hover { opacity: 0.75; }
/* PF-15 link affordance: these bands pin --color-link to Ink Navy, and .fsk-link above
   strips the underline (correction #3) -- so an inline link becomes pixel-identical to
   the bold body copy beside it (WCAG 1.4.1, non-color distinction required). Ink Navy +
   underline is the ruled fix; namespaced so the base .fsk-link (plain prose links
   elsewhere) stays untouched. */
.fsk-band--citrus .fsk-link,
[data-block="teal"] .fsk-link { text-decoration: underline; text-underline-offset: 3px; }

/* ----------------------------- BUTTONS ---------------------------------- */
/* NO grain-dot hover texture (correction #4) — veil only. */
.fsk-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-3);
  font-family: var(--font-body); font-weight: 700; font-size: var(--text-body); line-height: 1.2;
  border: 0; border-radius: var(--radius-seed-m); min-height: 52px; min-width: 44px;
  padding: 0 34px; cursor: pointer; text-decoration: none;
  transition: box-shadow var(--motion-settle) var(--ease-settle),
              transform var(--motion-settle) var(--ease-settle),
              background-color var(--motion-quick) var(--ease-out);
}
.fsk-btn svg { width: 20px; height: 20px; flex: 0 0 auto; }
.fsk-btn--primary { background: var(--color-cta-fill); color: var(--color-cta-label); box-shadow: var(--shadow-rest); }
.fsk-btn--primary:hover { transform: translateY(1px); box-shadow: var(--shadow-settle); background-image: linear-gradient(var(--veil-hover), var(--veil-hover)); }
.fsk-btn--primary:active { transform: translateY(2px); box-shadow: none; background-image: linear-gradient(var(--veil-pressed), var(--veil-pressed)); }
.fsk-btn--value { background: var(--color-cta-value-fill); color: var(--color-cta-value-label); box-shadow: var(--shadow-amber-rest); }
.fsk-btn--value:hover { transform: translateY(1px); box-shadow: var(--shadow-amber-settle); background-image: linear-gradient(var(--veil-hover-on-amber), var(--veil-hover-on-amber)); }
.fsk-btn--secondary { background: transparent; color: var(--color-accent); border: var(--border-stroke) solid var(--color-accent); }
.fsk-btn--secondary:hover { background: var(--blue-08); transform: translateY(1px); }
.fsk-band--dark .fsk-btn--secondary, .fsk-band--deepblue .fsk-btn--secondary { color: var(--color-inverse-text); border-color: var(--color-inverse-text); }
.fsk-btn--inverse { background: var(--color-inverse-cta-fill); color: var(--color-inverse-cta-label); box-shadow: var(--shadow-rest); }
.fsk-btn--inverse:hover { transform: translateY(1px); background-image: linear-gradient(var(--veil-hover-on-amber), var(--veil-hover-on-amber)); }
/* Deep-Blue solid — the correct primary on light/citrus bands (palette law: Blue + white) */
.fsk-btn--blue { background: var(--deep-blue); color: var(--white); box-shadow: var(--shadow-rest); }
.fsk-btn--blue:hover { transform: translateY(1px); box-shadow: var(--shadow-settle); background-image: linear-gradient(var(--veil-hover), var(--veil-hover)); }
/* Secondary CTA for dark full-bleed media (hero): solid Ink Navy fill, Amber hairline, Mint Air label —
   deterministic contrast that never depends on the photo behind it. */
/* teal CTA: differentiates subscription entry points from the amber build-stack CTA
   (Andrew 2026-07-19); Reef Teal fill carries Ink Navy text per palette law */
.fsk-btn--teal { background: var(--reef-teal); color: var(--ink-navy); box-shadow: var(--shadow-rest); }
.fsk-btn--teal:hover { transform: translateY(1px); box-shadow: var(--shadow-settle); background-image: linear-gradient(var(--veil-hover), var(--veil-hover)); }
.fsk-btn--secondary-inverse { background: var(--ink-navy); color: var(--mint-air); border: var(--border-stroke) solid var(--amber); box-shadow: var(--shadow-rest); }
.fsk-btn--secondary-inverse:hover { transform: translateY(1px); background-image: linear-gradient(var(--veil-hover), var(--veil-hover)); }
.fsk-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.fsk-btn-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }

/* ------------------------------ CHIPS ----------------------------------- */
.fsk-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  letter-spacing: var(--tracking-badge); text-transform: uppercase;
  color: var(--color-text); background: var(--color-surface);
  border-radius: var(--radius-seed-badge); padding: 6px 14px; text-decoration: none;
  /* chips shrink-wrap their text — never stretch to the grid/flex track
     (Andrew 2026-07-19: citrus bubbles ran the full card width) */
  width: fit-content; justify-self: start;
  /* white/light chip plate -- own opaque ground for a knockout-carrying duotone icon
     (see .fsk-band--dark above for the ambient-band default this overrides) */
  --fsk-glyph-knockout: var(--color-surface-raised);
}
/* 24px legibility floor for duotone spot glyphs (benefit, usage, origin families -- filled,
   not stroke, per MANIFEST.md ruling D1); was 16px.
   FIX 2026-07-20: an earlier version of this comment closed itself early mid-sentence,
   which pushed the rest of that sentence out as live top-level CSS and silently swallowed
   the .fsk-chip svg rule below (confirmed via render-verify: every primary .fsk-chip icon
   sitewide was rendering at unstyled browser-default SVG size instead of 24px). Kept plain
   prose in this comment on purpose so it can never do that again. */
.fsk-chip svg { width: 24px; height: 24px; flex: 0 0 auto; }
.fsk-chip--citrus { background: var(--citrus-30); color: var(--color-text); }
.fsk-chip--amber  { background: var(--color-cta-value-fill); color: var(--color-cta-value-label); }
.fsk-chip--outline { background: transparent; border: var(--border-hairline) solid var(--color-border-strong); }
.fsk-chip-row { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: center; }

/* trust chips (hero + bands) */
.fsk-trustrow { display: flex; flex-wrap: wrap; gap: var(--space-5); justify-content: center; align-items: center; --fsk-glyph-knockout: var(--color-surface-raised); }
/* 24px legibility floor (was 18px) -- .fsk-trustrow__item mixes Tier-1 chrome (check/leaf/
   mushroom) with Tier-2 spot glyphs (usage-dropper); floor applies to the whole class per
   the migration plan rather than splitting chrome vs spot-glyph instances */
.fsk-trustrow__item { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-body); font-size: var(--text-small); font-weight: 700; color: inherit; }
.fsk-trustrow__item svg { width: 24px; height: 24px; color: var(--color-brand); }

/* --------------------- MEDIA + PHOTO PLACEHOLDERS ----------------------- */
/* Every image slot renders the merchant photo if set, else a neutral placeholder.
   Drop real photos in the theme editor and they replace the placeholders. */
.fsk-media { position: relative; overflow: hidden; border-radius: var(--radius-seed-card); background: var(--color-surface); }
.fsk-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.fsk-ph { display: block; width: 100%; height: 100%; min-height: 220px; background:
  radial-gradient(120% 120% at 30% 20%, var(--teal-18), transparent 60%),
  var(--color-surface); }
.fsk-ph svg { display: block; width: 100%; height: 100%; opacity: 0.35; }
.fsk-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 4vw, 56px); align-items: center; }
.fsk-split .fsk-media { aspect-ratio: 4 / 3; }
@media (max-width: 749px) { .fsk-split { grid-template-columns: 1fr; } }

/* --------------------------- HERO (A1-dark) ----------------------------- */
/* Full-bleed living media (poster <img> = LCP, optional deferred <video>), content
   bottom-left, AMD-2 trust strip pinned to the lower edge. Bottom-left composition +
   directional scrim keep the dappled fruiting body visible upper-right while giving the
   Amber CTA a deterministically dark glare-trap zone (R-5). */
.fsk-hero { position: relative; overflow: hidden; min-height: 86vh; display: flex; flex-direction: column; justify-content: flex-end; background: var(--ink-navy); color: var(--white); }
@media (min-width: 750px) { .fsk-hero { min-height: 92vh; } }
/* 2026-08-07 final audit · hero height unit. `vh` on iOS Safari is the LARGE viewport: it measures
   the window with the address bar and toolbar hidden, which is not the state a page loads in. On
   first paint the visible area is ~85-88% of that, so an 86vh hero is taller than the screen it is
   sitting on, and the amount it overshoots grows as the phone gets smaller. The hero's own CTAs sit
   at its bottom edge, so on the smaller iPhones they start below the fold and the first screen is
   photo and headline with nothing to act on. `svh` is the small viewport — the same measurement with
   the browser chrome SHOWN — which is what the visitor actually has at load. Declared after the `vh`
   line, so a browser without svh support keeps the old value and nothing regresses. Chromium reports
   svh == vh on desktop, so this cannot be verified by a headless render; it needs a real iOS device. */
.fsk-hero { min-height: 86svh; }
@media (min-width: 750px) { .fsk-hero { min-height: 92svh; } }
.fsk-hero__media { position: absolute; inset: 0; z-index: 0; background: linear-gradient(135deg, #0a2540, #123a63 60%, #0a2540); }
.fsk-hero__media > img, .fsk-hero__media > video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fsk-hero__video { opacity: 0; transition: opacity 900ms var(--ease-settle, ease); }
.fsk-hero__video.is-playing { opacity: 1; }
.fsk-hero__media::after { content: ""; position: absolute; inset: 0; z-index: 1; background:
  linear-gradient(115deg, rgba(10,37,64,0.86) 0%, rgba(10,37,64,0.60) 34%, rgba(10,37,64,0.12) 62%, rgba(10,37,64,0) 82%),
  linear-gradient(0deg, rgba(10,37,64,0.55) 0%, rgba(10,37,64,0) 42%); }
.fsk-hero__inner { position: relative; z-index: 2; width: 100%; padding-block: clamp(48px, 8vw, 96px) clamp(20px, 3vw, 32px); }
.fsk-hero__content { max-width: 560px; text-align: left; }
.fsk-hero__eyebrow { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800; letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--mint-air); opacity: 0.92; margin: 0 0 var(--space-3); }
.fsk-hero__title { color: var(--white); font-size: clamp(2.4rem, 5.2vw, 4rem); }
.fsk-hero__lede { color: rgba(255,255,255,0.88); margin-top: var(--space-4); max-width: 46ch; }
.fsk-hero .fsk-btn-row { justify-content: flex-start; margin-top: var(--space-6); }
/* AMD-2 trust strip — solid Ink-Navy band, legible independent of the photo. */
.fsk-hero__trust { position: relative; z-index: 2; background: var(--ink-navy); border-top: var(--border-hairline) solid rgba(255,255,255,0.10); }
[data-theme="dark"] .fsk-hero__trust { background: var(--night-surface); }
.fsk-hero__trust-inner { display: flex; flex-wrap: wrap; gap: clamp(14px, 2.4vw, 32px); align-items: center; justify-content: flex-start; padding-block: clamp(12px, 1.8vw, 18px); color: rgba(255,255,255,0.92); }
/* 2026-08-07 final audit · the strip became a real <ul> in fsk-hero.liquid (four claims that were
   four bare spans, invisible as a list to assistive tech). These three declarations undo what the
   UA adds for a list and nothing else, so the rendered strip is pixel-identical to before:
   list-style kills the bullet, margin-block kills the 1em above/below, and padding-inline-start is
   zeroed because .fsk-wrap's own padding-inline is the shorthand-equivalent longhand and cascade
   order — not specificity — decides which wins. Setting it here explicitly removes that
   dependency. display:flex already stops the <li>s from generating markers in most engines, but
   list-style is stated anyway rather than relied on. */
.fsk-hero__trust-inner { list-style: none; margin-block: 0; padding-inline-start: clamp(16px, 4vw, 40px); }
.fsk-hero__trust-inner .fsk-trustrow__item { font-size: var(--text-small); font-weight: 700; }
/* 24px floor -- this row includes usage-dropper (Tier-2 spot glyph) alongside chrome */
.fsk-hero__trust-inner .fsk-trustrow__item svg { width: 24px; height: 24px; color: var(--reef-teal); }
@media (max-width: 749px) {
  .fsk-hero__media::after { background: linear-gradient(0deg, rgba(10,37,64,0.92) 8%, rgba(10,37,64,0.55) 36%, rgba(10,37,64,0.10) 68%, rgba(10,37,64,0) 90%); }
  .fsk-hero__content { max-width: 100%; }
  .fsk-hero__lede { max-width: 100%; }
  .fsk-hero .fsk-btn-row { width: 100%; }
  .fsk-hero .fsk-btn-row .fsk-btn { flex: 1 1 auto; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) { .fsk-hero__video { display: none; } }

/* header brand-mark fallback (blocks/_header-logo.liquid) — block-level
   {% stylesheet %} proved unreliable here, so the sizing lives in this always-loaded
   sheet; !important outranks base.css `img { width: 100% }` */
.fsk-logo-fb { height: 36px !important; width: auto !important; display: block; }
@media (max-width: 749px) { .fsk-logo-fb { height: 28px !important; } }

/* ---- Hero · glass-right variant (RULED 2026-07-19: B mint-glass — bake-off log
   content-drafts/website-preplan/hero-video-banner/DECISION-NOTE.md).
   LM footage owns the left; copy sits right in a Mint Air glass panel with Ink-Navy
   text (avoids big navy-block + yellow pairings per Andrew's 2026-07-19 ruling). ---- */
.fsk-hero--glass { background: var(--mint-surface); } /* never a navy flash pre-media */
.fsk-hero--glass .fsk-hero__inner { flex: 1; display: flex; align-items: center; }
@media (min-width: 750px) {
  .fsk-hero--glass .fsk-hero__media > img,
  .fsk-hero--glass .fsk-hero__media > video {
    width: 134%; max-width: none; /* Horizon base.css clamps video/img to 100% —
      without this the 134% collapses, the -34% shift still applies, and a hard-edged
      strip of bare media background is exposed on the right (2026-07-19 incident) */
    left: -34%; right: auto; inset-block: 0;
    object-position: 50% 22%; /* crown-biased crop for the left-shift zoom */
  }
}
/* media fallback behind the footage: never navy on the glass hero — mint→teal haze
   (Andrew 2026-07-19), so any pre-load / edge exposure reads brand-light */
.fsk-hero--glass .fsk-hero__media { background:
  linear-gradient(120deg, var(--mint-surface), #9FF2ED 45%, var(--reef-teal)); }
.fsk-hero--glass .fsk-hero__media::after { background:
  linear-gradient(90deg, rgba(10,74,71,0) 55%, rgba(10,74,71,0.20) 100%); }
.fsk-hero--glass .fsk-hero__scene { position: relative; isolation: isolate; margin-left: auto; max-width: 648px; }
/* desktop: panel rides the right edge and narrows so it stops covering the LM
   (Andrew 2026-07-19: "half of that window is covering up lions mane") */
@media (min-width: 750px) {
  .fsk-hero--glass .fsk-hero__inner .fsk-wrap { max-width: none; }
  .fsk-hero--glass .fsk-hero__scene { max-width: min(600px, 46vw); }
}
.fsk-hero--glass .fsk-hero__panel {
  position: relative; z-index: 1;
  /* Mint Surface tone at higher alpha — the 0.60 Mint Air frost read WHITE over the
     bright footage (Andrew 2026-07-19); this holds the ruled mint */
  /* 2026-08-07 final audit · the ruled mint-glass panel was rendering NEUTRAL GREY-BLUE.
     Measured off the render (desktop hero capture): #C2D0D9 / #B3C6C9 — no mint left in it.
     Cause: at 0.72 the desaturated grey-green LM footage still owns ~28% of every pixel and
     saturate(1.4) cannot invent a hue the backdrop does not have, so the panel drifted off
     PF-5's "candidate B mint-glass panel". Raised to 0.88 of the SAME Mint Surface token, so
     the panel reads mint again while staying glass (the footage still shows through and the
     blur still runs). Written as color-mix on --mint-surface rather than a second rgba()
     literal of the same colour, so the panel tracks the token if the palette ever moves. */
  background: color-mix(in srgb, var(--mint-surface) 88%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(1.4);
  backdrop-filter: blur(22px) saturate(1.4);
  border: 1px solid rgba(255,255,255,0.75);
  border-radius: 28px;
  padding: clamp(28px, 3.4vw, 44px);
  box-shadow: 0 24px 60px rgba(10,37,64,0.22);
}
.fsk-hero--glass .fsk-hero__eyebrow { color: var(--deep-blue); opacity: 1; }
.fsk-hero--glass .fsk-hero__title { color: var(--ink-navy); }
.fsk-hero--glass .fsk-hero__lede { color: rgba(10,37,64,0.88); }
[data-theme="dark"] .fsk-hero--glass .fsk-hero__panel {
  background: rgba(18,20,25,0.55); border-color: rgba(255,255,255,0.14);
  box-shadow: 0 24px 60px rgba(0,0,0,0.45);
}
[data-theme="dark"] .fsk-hero--glass .fsk-hero__eyebrow { color: var(--mint-air); }
[data-theme="dark"] .fsk-hero--glass .fsk-hero__title { color: var(--white); }
[data-theme="dark"] .fsk-hero--glass .fsk-hero__lede { color: rgba(255,255,255,0.88); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .fsk-hero--glass .fsk-hero__panel { background: rgba(240,255,254,0.92); }
  [data-theme="dark"] .fsk-hero--glass .fsk-hero__panel { background: rgba(18,20,25,0.9); }
}
@media (max-width: 749px) {
  .fsk-hero--glass .fsk-hero__inner { align-items: flex-end; }
  .fsk-hero--glass .fsk-hero__scene { margin-left: 0; }
  .fsk-hero--glass .fsk-hero__panel { border-radius: 22px; padding: 22px; }
  .fsk-hero--glass .fsk-hero__media::after { background:
    linear-gradient(0deg, rgba(10,37,64,0.55) 0%, rgba(10,37,64,0.18) 40%, rgba(10,37,64,0) 70%); }
}
/* Trust strip under the glass hero: mint→teal gradient instead of the solid navy
   block (Andrew 2026-07-19; consistent with the ruled teal-farm-band / no big navy
   blocks direction). Teal never carries light text → chips flip to Ink Navy. */
.fsk-hero--glass .fsk-hero__trust {
  background: linear-gradient(100deg, var(--mint-surface) 0%, var(--reef-teal) 78%);
  border-top: var(--border-hairline) solid rgba(10,37,64,0.10);
}
.fsk-hero--glass .fsk-hero__trust-inner { color: var(--ink-navy); }
.fsk-hero--glass .fsk-hero__trust-inner .fsk-trustrow__item svg { color: var(--ink-navy); }
[data-theme="dark"] .fsk-hero--glass .fsk-hero__trust { background: var(--night-surface); border-top-color: rgba(255,255,255,0.10); }
[data-theme="dark"] .fsk-hero--glass .fsk-hero__trust-inner { color: rgba(255,255,255,0.92); }
[data-theme="dark"] .fsk-hero--glass .fsk-hero__trust-inner .fsk-trustrow__item svg { color: var(--reef-teal); }

/* --------------------------- CARDS (generic) ---------------------------- */
.fsk-cardgrid { display: flex; flex-wrap: wrap; gap: var(--space-5); justify-content: center; }
/* 5 cards wrap 3 on top + 2 centered on the bottom (not 4 + 1) */
.fsk-cardgrid > * { flex: 1 1 300px; max-width: 360px; min-width: 240px; }
@media (min-width: 900px) { .fsk-cardgrid > * { flex-basis: calc(33.333% - var(--space-5)); } }

/* species / benefit card */
.fsk-scard {
  display: flex; flex-direction: column; background: var(--color-surface-raised); color: var(--color-text);
  border-radius: var(--radius-seed-card); overflow: hidden; box-shadow: var(--shadow-card);
  text-decoration: none; transition: transform var(--motion-settle) var(--ease-settle), box-shadow var(--motion-settle) var(--ease-settle);
}
.fsk-scard:hover { transform: translateY(1px); box-shadow: var(--shadow-settle); }
/* ── 2026-08-07 final audit · stretched-link card ────────────────────────────────
   The card used to be <a class="fsk-scard"> wrapping everything, with popover <button>s and
   the CTA inside it. That is invalid HTML (interactive inside interactive) and it broke keyboard
   and screen-reader use on the buy path: 267 nested-button instances across all 58 pages, from
   this class plus fsk-also-try and fsk-shop-by-goal.
   The card is now a <div> with one absolutely-positioned link covering it, so the whole card
   stays clickable while the buttons above it are real, focusable controls. */
.fsk-scard { position: relative; }
.fsk-scard__link { position: absolute; inset: 0; z-index: 1; text-decoration: none; border-radius: inherit; }
.fsk-scard__link:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Only genuinely interactive children are raised above the stretched link. NOT .fsk-scard__cta:
   its "Add to cart" is currently a non-interactive <span>, so raising it would cover the link and
   the control would do nothing at all — worse than today, where the click at least reaches the
   product page. It stays under the link until that control is either made real or renamed
   (open decision for Andrew). Raising it is a one-line change once that is settled. */
.fsk-scard .fsk-gwrap,
.fsk-scard .fsk-pop { position: relative; z-index: 2; }
/* 2026-08-11 (Andrew): "you put the 'grown on our farm' / 'wildcrafted' / 'wild-foraged' on
   the wrong side ... it's currently on the left side, it would look better on the right."
   The pill was never authored to sit on the left. .fsk-opill declares position:absolute with
   right:12px, and this raise-above-the-stretched-link rule used to include .fsk-opill and
   reset it to position:relative. Against a relative box, right:12px is not an anchor — it is
   a 12px LEFT shift of the in-flow position, which is why the computed left came out -12px
   and the pill hung 12px outside the card's left wall (the same overhang as the "text too
   close to the edge" note in his message). z-index applies to an absolutely positioned box
   on its own, so the pill only ever needed the raise, never the position reset. .fsk-gwrap
   and .fsk-pop do still need position:relative and keep it above. */
.fsk-scard .fsk-opill { z-index: 2; }
/* FINAL card (ported from final-product-card/card.html 2026-07-17): 4/5 media for
   the 2:3 packshots (4/3 beheads the droppers) + crest C deep belly. */
.fsk-scard__hero { position: relative; }
.fsk-scard__media { aspect-ratio: 4/5; background: var(--color-surface); border-radius: 18px 18px 56% 56% / 18px 18px 33% 33%; overflow: hidden; box-shadow: 0 11px 0 0 var(--color-card-plate); margin-bottom: 16px; }
.fsk-scard__media > span {
  display: block; width: 100%; height: 100%;
  background-color: var(--color-surface);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A2540' stroke-opacity='0.16' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.4 12C3.4 6.5 7.3 3 12 3 16.7 3 20.6 6.5 20.6 12 20.6 13.1 16.9 13.7 12 13.7 7.1 13.7 3.4 13.1 3.4 12Z'/%3E%3Cpath d='M8.8 13.5C8.8 15.5 8.5 17.8 9 19 10 19.7 14 19.7 15 19 15.5 17.8 15.2 15.5 15.2 13.5'/%3E%3C/svg%3E"),
    radial-gradient(120% 120% at 50% 22%, var(--teal-12), transparent 60%);
  background-repeat: no-repeat, no-repeat;
  background-position: center 38%, center;
  background-size: 40%, cover;
}
.fsk-scard__media img { width: 100%; height: 100%; object-fit: cover; }

/* checklist (Always / Never) with icons */
.fsk-checklist { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-3); font-family: var(--font-body); }
.fsk-checklist li { display: flex; align-items: flex-start; gap: 10px; line-height: 1.5; }
.fsk-checklist__i { width: 22px; height: 22px; flex: 0 0 auto; margin-top: 1px; }
.fsk-checklist--yes .fsk-checklist__i { color: var(--reef-teal); }
.fsk-checklist--no .fsk-checklist__i { color: var(--color-text-muted); }
[data-crest="flat"] .fsk-scard__media { border-radius: 16px 16px 8px 8px; box-shadow: 0 7px 0 0 var(--color-card-plate); }
.fsk-scard__body { padding: var(--space-5); display: grid; gap: var(--space-2); }
.fsk-scard__eyebrow { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-link); }
/* CONVERGED origin pill (final-product-card ruling): glyph + frozen label riding
   the crest belly, bottom-right, own opaque ground — never text on the teal. */
.fsk-opill {
  position: absolute; right: 12px; bottom: 2px; z-index: 2;
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--color-surface-raised); color: var(--ink-navy);
  border: 1.5px solid var(--color-border-strong);
  font-family: var(--font-body); font-size: 10.5px; font-weight: 800;
  letter-spacing: var(--tracking-badge); text-transform: uppercase; line-height: 1;
  border-radius: var(--radius-seed-badge); padding: 7px 12px 7px 9px;
  box-shadow: var(--shadow-settle); white-space: nowrap;
  /* own opaque plate -- already theme-aware (white light / night-surface dark, see the
     [data-theme="dark"] override below), so the knockout token can just track it */
  --fsk-glyph-knockout: var(--color-surface-raised);
}
/* 24px legibility floor for duotone spot glyphs (was 19px) */
.fsk-opill svg { width: 24px; height: 24px; flex: 0 0 auto; }
/* H-13: the pill becomes a real <button> when it carries a hover description, so it needs the
   UA button defaults knocked back. Every visual property it relies on is already set in
   .fsk-opill above; this only removes what the UA adds on top and restores the pointer. */
button.fsk-opill { appearance: none; -webkit-appearance: none; cursor: help; text-align: left; }
/* Making the pill focusable without giving it a focus style would have been an accessibility
   regression I introduced: .fsk-opill had no focus rule because a <span> never receives focus.
   Matches the convention already used by .fsk-btn and .fsk-bicon in this file. */
button.fsk-opill:focus-visible { outline: none; box-shadow: var(--focus-ring); }
[data-theme="dark"] .fsk-opill { background: var(--night-surface); color: var(--mint-air); border-color: var(--mintair-28); }

/* RULED I3 per-card glow (2026-07-18): amber bloom, each card its own aura.
   Hover keeps the bloom (base hover would drop it); dark scales down to lantern. */
.fsk-scard { box-shadow: var(--shadow-card), 0 10px 58px -4px rgba(246,196,69,0.60); }
.fsk-scard:hover { box-shadow: var(--shadow-settle), 0 10px 58px -4px rgba(246,196,69,0.60); }
[data-theme="dark"] .fsk-scard { box-shadow: var(--shadow-card), 0 10px 52px -4px rgba(246,196,69,0.36); }
[data-theme="dark"] .fsk-scard:hover { box-shadow: var(--shadow-settle), 0 10px 52px -4px rgba(246,196,69,0.36); }

/* mobile = 2-up cardgrid with the scaled pill (verified at 412px in the ruled mock).
   First card = full-width FEATURED lead (Andrew 2026-07-19: large card leads and it's
   Lion's Mane; the remaining 4 pair up 2x2 so no odd card balloons at the bottom). */
@media (max-width: 640px) {
  .fsk-cardgrid { gap: 14px; }
  .fsk-cardgrid > * { flex: 1 1 calc(50% - 14px); min-width: 0; max-width: none; }
  .fsk-cardgrid > :first-child { flex-basis: 100%; }
  .fsk-cardgrid > :first-child .fsk-opill { font-size: 11px; padding: 6px 12px 6px 9px; }
  .fsk-cardgrid > :first-child .fsk-opill svg { width: 18px; height: 18px; }
  .fsk-cardgrid > :first-child .fsk-scard__title { font-size: 1.5rem; }
  .fsk-opill { font-size: 8.5px; padding: 5px 8px 5px 6px; gap: 5px; right: 8px; }
  .fsk-opill svg { width: 14px; height: 14px; }
  .fsk-scard__body { padding: var(--space-4); }
  .fsk-scard__title { font-size: 1.2rem; }
  /* 2026-08-07 final audit · at 390px the Chaga card's "Antioxidants" chip ran into and past
     the card wall while the Trifecta chip beside it wrapped to two lines happily. The chip is
     inline-flex with width:fit-content and its label is one unbreakable 12-character word, so
     its min-content width (icon + word + padding, ~158px) is wider than the half-width card's
     content box (~136px at 390px). A grid item cannot shrink below min-content, so the card
     body laid itself out at the wider size and .fsk-scard's overflow:hidden clipped it —
     which is why the sub-line under it lost its last word too. overflow-wrap:anywhere is the
     one property that lowers the min-content contribution, so the track can shrink back to the
     card; hyphens:auto means the break lands at a hyphenation point rather than mid-syllable
     where the language allows. Label stays at the 12px micro floor — no shrinking type. */
  .fsk-scard .fsk-chip { max-width: 100%; overflow-wrap: anywhere; hyphens: auto; }
}
/* Also-Try 2x2 pairs variant (PF-34 Task D -- Andrew ruled 2x2, 2026-07-21). The
   Also-Try grid renders 4 sibling cards (5 minus the current product); base .fsk-cardgrid
   is tuned for the homepage 5-card grid (3 + 2 centered) and is SHARED across 7 sections,
   so the fix is a scoped modifier, never a base-rule change. Cards keep their ruled 360px
   cap; the lever is the CONTAINER width, capped to exactly two-cards-wide and centered, so
   4 cards wrap 2+2 with no orphan. (A flex-basis change alone can't force 2-up because the
   360px card max-width lets a third 360px card fit on a wide row.) The >=641px basis pins
   two-per-row down through the narrow-tablet band, and on mobile the full-width featured-
   lead treatment -- which belongs to the homepage grid, not here -- is dropped so all four
   pair up 2x2 there too. Double-classed so it wins on specificity, not source order. */
.fsk-cardgrid.fsk-cardgrid--pairs { max-width: calc(360px * 2 + var(--space-5)); margin-inline: auto; }
@media (min-width: 641px) {
  .fsk-cardgrid.fsk-cardgrid--pairs > * { flex-basis: calc(50% - var(--space-5)); }
}
@media (max-width: 640px) {
  .fsk-cardgrid.fsk-cardgrid--pairs > :first-child { flex-basis: calc(50% - 14px); }
  .fsk-cardgrid.fsk-cardgrid--pairs > :first-child .fsk-opill { font-size: 8.5px; padding: 5px 8px 5px 6px; }
  .fsk-cardgrid.fsk-cardgrid--pairs > :first-child .fsk-opill svg { width: 14px; height: 14px; }
  .fsk-cardgrid.fsk-cardgrid--pairs > :first-child .fsk-scard__title { font-size: 1.2rem; }
}
.fsk-scard__price { font-family: var(--font-body); font-weight: 800; font-size: var(--text-body); margin-top: var(--space-2); }
.fsk-scard__price .unit { font-weight: 400; font-size: var(--text-small); color: var(--color-text-muted); }
.fsk-scard__cta { margin-top: var(--space-3); }
/* 2026-08-07 final audit (content-fresh 7) · card CTA baseline.
   .fsk-cardgrid already stretches every card in a row to the same height, and .fsk-scard is a
   column flex, but .fsk-scard__body was sized by its own content — so the leftover height piled
   up as dead space UNDER the last thing in the card instead of above the button. Any two cards
   whose sub-line wrapped to a different number of lines put their buttons at different heights.
   The fresh grid is the worst case, because its per-cultivar texture and flavour lines are
   deliberately different lengths, but it hits every .fsk-scard grid on the site.
   The body now grows into the card and the CTA is pushed to its floor, so a row of buttons lands
   on one line. Grid to flex is not a layout change here: every child is already a full-width
   block in source order and `gap` behaves the same in both. `margin-top: auto` only ever eats
   space that was empty anyway, and the padding keeps the old minimum separation for the case
   where there is none. */
.fsk-scard__body { flex: 1 1 auto; display: flex; flex-direction: column; }
.fsk-scard__cta { margin-top: auto; padding-top: var(--space-3); }
.fsk-scard__cta .fsk-btn { width: 100%; min-height: 44px; padding: 0 22px; border-radius: var(--radius-seed-s); font-size: var(--text-small); }
/* 2026-08-07 final audit · card CTA type size. This button was set at --text-small (14px) against
   the ruled 16px floor for CTA labels. It is the last thing read before the click on the homepage's
   money row, and 14px uppercase-adjacent label text at arm's length on a phone is exactly where the
   floor exists to help. Raised to --text-body. The horizontal padding comes down at the 2-up
   breakpoint to pay for it: at 390px the card's content box is about 140px wide, and "View product"
   at 16px is about 106px, so the old 22px sides would have pushed the label onto two lines inside a
   44px-tall button. 10px sides keep it on one line with room to spare. Vertical size is unaffected —
   min-height 44px already exceeds what 16px/1.2 needs, so no card gets taller. */
.fsk-scard__cta .fsk-btn { font-size: var(--text-body); }
@media (max-width: 640px) {
  .fsk-scard__cta .fsk-btn { padding: 0 10px; }
}
.fsk-scard__title { font-family: var(--font-display); font-variation-settings: var(--font-display-settings); font-size: 1.4rem; font-weight: 600; line-height: 1.2; }
.fsk-scard__sub { font-family: var(--font-body); font-size: var(--text-small); color: var(--color-text-muted); line-height: 1.5; }

/* ── 2026-08-07 final audit · benefit-row baseline, part 2 ────────────────────────────────
   The 2lh reservation on the "Also supports" label (further down) fixed one of the three things
   knocking this row out of alignment. These fix the other two.

   PRICE AND CTA. The five cards hold different amounts of content, so every card's price and
   button sat wherever its own stack happened to end. .fsk-cardgrid is a wrapping flex row and its
   items already stretch to equal height, so the card boxes were level while everything inside them
   was not — the row read as five separate cards rather than one row, and the eye had to hunt for
   the price on each. The body now fills the card (flex: 1) and the price takes margin-top:auto, so
   the free space collects in one place, above the price, and price + button land on a shared line
   across the whole row. This is why the body switches from grid to flex: `margin-top: auto` moves an
   item within its flex line, but in grid it only moves an item inside its own auto-sized track,
   which has no free space to give. The children are all full-width blocks either way, so nothing
   else about the layout changes. padding-top replaces the margin the price used to carry, so the
   gap above it is the same as before on the tallest card (where auto resolves to zero).

   SUB-LINE. Four of the five sub-lines set on one line at desktop; Chaga's runs to two. That one
   extra line pushed its chip, icon row and timing down a step. Reserving two lines on all five
   equalises the block wherever the wrap falls, exactly as the 2lh label reservation does. 2lh is
   the element's own line box, so it tracks the type scale instead of hard-coding a pixel height.

   NOT fixed here: Trifecta carries an eyebrow the other four do not, so its title starts one line
   lower. That is a real content difference, not a layout bug — equalising it means adding an
   eyebrow to the other four or dropping Trifecta's, and both are copy decisions.
   No change to base .fsk-cardgrid (PF-40): everything here is scoped to .fsk-scard's interior. */
.fsk-scard__body { flex: 1 1 auto; display: flex; flex-direction: column; }
.fsk-scard__body > .fsk-chip { align-self: start; }
.fsk-scard__sub { min-height: 2lh; }
.fsk-scard__price { margin-top: auto; padding-top: var(--space-2); }

/* ----------------- SECONDARY-BENEFIT ICON ROW (product card, Candidate A) ----------------
   Ported verbatim from the approved mock (content-drafts/website-preplan/benefit-icon-system/
   mock-candidates.html, Candidate A: grid card only, benefit icons only). Sits right after
   the existing .fsk-chip.fsk-chip--citrus primary chip, before price. Native `popover`
   attribute + CSS anchor positioning (anchor-name/position-anchor set inline per-instance in
   Liquid) gives tap-to-open for free; assets/fsk-bicon-popover.js layers hover/focus intent
   on top -- the same lighter mechanism cart-disclosure-tooltip.liquid's anchored-popover-
   component uses, without that custom element. */
/* H-09 (2026-07-29, Andrew): "Also Supports is on the left side, on the right side next to it
   should be When to Take." The eyebrow inside .fsk-bicon-row is width:100%, so the row already
   stacks its own label above its icons; putting a second labelled block beside it needs a
   two-column wrapper, which is what .fsk-cardmeta is. Second column is auto-width so the icon
   row keeps the space it needs, and the whole thing collapses to one column on narrow cards
   rather than squeezing the timing text to two words per line. Homepage cards only for now:
   .fsk-bicon-row is shared with fsk-also-try and fsk-shop-by-goal, and those are the smaller
   PDP/collection cards where Andrew has not asked for this and it would crowd them. */
/* 2026-08-11 (Andrew): "those SVG icons ... are all supposed to be horizontal. Now there are
   two on top and one on the bottom." Measured cause, not a guess: the left track was
   minmax(0, 1fr) and the right track was `auto`, so "When to take" took its max-content
   (230px on the cards reading "Morning or pre-workout") and left the icon track 61px — one
   44px icon per line. The middle card got 140px, which fits two of its three. Sizing the
   icon track to exactly what three icons need (3 x 44 + 2 gaps = 148px) and giving the
   remainder to the text flips it: 303 - 148 - 12 = 143px, and the longest value measures
   140px, so it still sets on one line. Written as a calc so it tracks .fsk-bicon's own
   width and .fsk-bicon-row's gap if either moves. */
.fsk-cardmeta { display: grid; grid-template-columns: calc(44px * 3 + var(--space-2) * 2) minmax(0, 1fr); gap: var(--space-3); align-items: start; }
/* 2026-08-07 final audit · the benefit row lost its horizontal baseline: the middle card's
   price and Add-to-cart sat 17px above its neighbours. The cause is one wrapped word inside
   this two-column meta block. The right track is auto-sized off its own content, so a card
   with a SHORT "when to take" value (Reishi: "Night time") leaves the left track wide enough
   to set "Also supports" on one line, while the cards with a long value ("Morning or
   pre-workout") squeeze it onto two. That single extra line pushes the icons, the price and
   the Add-to-cart under it down by a line on two cards out of three, and the row stops reading
   as a row. Reserving two label lines on every card equalises the block wherever the wrap
   happens to fall. Deliberately NOT solved with white-space:nowrap: the left track is
   minmax(0, 1fr), which is allowed to size below its own min-content, so a nowrap label would
   have overflowed the track instead of widening it. 2lh tracks the label's own line box, so
   the reservation stays correct if the type scale moves. Scoped to the "Also supports" label
   (the direct child of .fsk-bicon-row) and not to the "When to take" one, which sets on one
   line on every card and would only gain a dead line above its value. */
.fsk-cardmeta .fsk-bicon-row > .fsk-bicon-row__eyebrow { min-height: 2lh; }
/* Collapse to one column where the card is genuinely narrow. This was written as a
   @container query first, which was WRONG: nothing in this stylesheet declares
   container-type, so the query could never match and the columns would have stayed
   squeezed on phones with no visible reason. Uses the file's own 640px card breakpoint
   instead, and follows its existing logic that below 640px the FIRST card goes full width
   (flex-basis 100%) while the rest go half — so only the half-width ones need collapsing. */
@media (max-width: 640px) {
  .fsk-cardgrid > :not(:first-child) .fsk-cardmeta { grid-template-columns: 1fr; }
}
.fsk-whentake { display: flex; flex-wrap: wrap; align-items: center; margin-top: var(--space-3); }
.fsk-whentake__val {
  width: 100%; font-family: var(--font-body); font-size: 12.5px; font-weight: 700;
  line-height: 1.25; color: var(--color-text); text-wrap: balance;
}
.fsk-bicon-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-3); }
.fsk-bicon-row__eyebrow {
  width: 100%; font-family: var(--font-body); font-size: 10.5px; font-weight: 800;
  letter-spacing: var(--tracking-badge); text-transform: uppercase; color: var(--color-text-muted);
  margin-bottom: 1px;
}
.fsk-gwrap { position: relative; display: inline-flex; }
.fsk-bicon {
  width: 44px; height: 44px; padding: 0; flex: 0 0 auto; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-dot); border: 1.5px solid var(--color-border-strong);
  background: var(--color-surface); color: var(--color-text); cursor: pointer;
  transition: background-color var(--motion-quick) var(--ease-out),
              transform var(--motion-settle) var(--ease-settle),
              border-color var(--motion-quick) var(--ease-out);
  /* own opaque plate for a knockout-carrying duotone icon (benefit-focus-clarity used as a
     Trifecta secondary, benefit-stress-balance used as a Reishi secondary) -- ground matches
     this button's own background, same convention as .fsk-chip/.fsk-opill above. */
  --fsk-glyph-knockout: var(--color-surface);
}
.fsk-bicon svg { width: 24px; height: 24px; }
.fsk-bicon:hover { background: var(--teal-12); border-color: var(--color-brand); transform: translateY(1px); }
[data-theme="dark"] .fsk-bicon:hover { background: var(--amber-12); border-color: var(--color-accent); }
.fsk-bicon:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* base popover component -- ported verbatim from master-pack components.css H7 (not
   previously present in this theme; the mock's .fsk-pop below extends it). */
.popover {
  max-width: 300px; background: var(--color-inverse-bg); color: var(--color-inverse-text);
  border-radius: var(--radius-seed-input); padding: var(--space-3) var(--space-4);
  font-family: var(--font-body); font-size: 13px; line-height: 1.55;
  box-shadow: var(--shadow-raised); position: relative;
}
.popover::before {
  content: ""; position: absolute; top: -6px; left: 22px;
  width: 14px; height: 14px; background: var(--color-inverse-bg);
  border-radius: 3px 3px 3px 1px; transform: rotate(45deg);
}
.popover--light {
  background: var(--color-surface-raised); color: var(--color-text);
  border: var(--border-hairline) solid var(--color-border-strong);
}
.popover--light::before {
  background: var(--color-surface-raised);
  border-top: var(--border-hairline) solid var(--color-border-strong);
  border-left: var(--border-hairline) solid var(--color-border-strong);
}
/* repositioned via native CSS anchor positioning (anchor-name/position-anchor set inline
   per-instance in Liquid); drops the corner-tab ::before for a centered ::after pointer. */
.fsk-pop {
  inset: auto; margin: 0; position: fixed; overflow: visible;
  top: anchor(top); left: anchor(center);
  translate: -50% calc(-100% - 12px);
  z-index: 30; width: max-content; max-width: 220px;
}
.fsk-pop::before { content: none; }
.fsk-pop::after {
  content: ""; position: absolute; left: 50%; bottom: -6px; width: 12px; height: 12px; margin-left: -6px;
  background: var(--color-surface-raised);
  border-right: var(--border-hairline) solid var(--color-border-strong);
  border-bottom: var(--border-hairline) solid var(--color-border-strong);
  transform: rotate(45deg); border-radius: 0 0 3px 0;
}
.fsk-pop__text { margin: 0; font-size: 13px; line-height: 1.5; }
/* Popover API support gate (red-team finding, 2026-07-27). .fsk-pop carries no display
   rule of its own -- visibility relied ENTIRELY on the UA stylesheet's
   `[popover]:not(:popover-open) { display: none }`. That UA rule does not exist in
   browsers without Popover API support (pre-Safari 17), so all 31 .fsk-pop panels across
   fsk-shop-by-goal / fsk-benefit-cards / fsk-also-try rendered at once, and the
   anchor-position fallback below then stacked them all at the viewport centre.
   Hide them there instead: the tooltips carry supplementary benefit copy, so absence is
   the correct degrade and the cards still read fully without them.
   Written as `@supports not selector(...)` deliberately -- a plain
   `.fsk-pop:not(:popover-open)` rule would itself be an INVALID selector in exactly the
   browsers that need it, and would be dropped. `@supports selector()` predates the
   Popover API in every engine, so this block evaluates correctly where it matters. */
@supports not selector(:popover-open) {
  .fsk-pop { display: none; }
}
/* fallback for browsers without CSS anchor positioning support */
@supports not (anchor-name: --fsk-a) {
  .fsk-pop { position: fixed; top: 50%; left: 50%; translate: -50% -50%; }
}

/* two-column trust panel (Always / Never) */
.fsk-cols2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-5); }
.fsk-panel { background: var(--color-surface-raised); border-radius: var(--radius-seed-feature); padding: var(--space-6); box-shadow: var(--shadow-card); }
.fsk-panel h3 { font-family: var(--font-display); font-variation-settings: var(--font-display-settings); font-size: 1.3rem; margin: 0 0 var(--space-4); }
.fsk-list { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-3); font-family: var(--font-body); }
.fsk-list li { position: relative; padding-left: 28px; line-height: 1.5; }
.fsk-list li::before { content: ""; position: absolute; left: 4px; top: 0.5em; width: 10px; height: 10px; border-radius: 50% 50% 50% 22%; background: var(--color-brand); }
.fsk-list--never li::before { background: transparent; border: 2.5px solid var(--color-border-strong); width: 9px; height: 9px; }

/* step / how-to row */
.fsk-steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-5); }
.fsk-step { display: grid; gap: var(--space-3); text-align: center; }
.fsk-step__ico { width: 56px; height: 56px; margin: 0 auto; border-radius: 50% 50% 50% 22%; background: var(--color-surface); display: grid; place-items: center; color: var(--color-accent); }
.fsk-step__ico svg { width: 28px; height: 28px; }
.fsk-step__n { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800; letter-spacing: var(--tracking-badge); text-transform: uppercase; color: var(--color-text-muted); }

/* ------------------------ PRODUCT-CARD CREST ---------------------------- */
/* The crest is a Reef-Teal band ONLY under the photo's rounded bottom edge —
   NOT a frame around the whole photo (correction #10, ruled ROUNDED). Applied to
   Horizon's .card-gallery (which already has overflow:hidden). An inset box-shadow
   gives a constant-width band that follows the rounded corners with no claw pinch,
   reliably (independent of the slideshow's internal positioning). */
/* Organic belly crest (biophilic): the photo's bottom is a rounded swell, and the
   teal is a drop-shadow COPY of that shape offset straight down — so it traces the
   belly curve, thickest where the swell dips at centre, easing up the sides. The
   photo clips to the belly (overflow) while the shadow shows outside it. */
.fsk-card .card-gallery {
  border-radius: 18px 18px 56% 56% / 18px 18px 33% 33%;   /* C · deep belly (ruled) */
  overflow: hidden;
  box-shadow: 0 11px 0 0 var(--color-card-plate);
  margin-bottom: 16px;                /* room for the crest below the photo */
}
[data-crest="flat"] .fsk-card .card-gallery {
  border-radius: 16px 16px 8px 8px;
  box-shadow: 0 7px 0 0 var(--color-card-plate);
}
.fsk-card .product-grid-view-zoom-out--details { text-align: left; }

/* ----------------------------- ACCORDION -------------------------------- */
.fsk-accordion { border-bottom: var(--border-hairline) solid var(--color-border); font-family: var(--font-body); }
/* 2026-08-07 final audit · the chevron sat low on every accordion row, and at 390px it crowded
   the longest question. Both come from the same geometry: the marker is a 14px box carrying
   only its right + bottom borders, rotated 45deg about the box centre. align-items:center
   centres the BOX, but the visible ink is the corner where those two borders meet, which the
   rotation throws ~5px BELOW that centre — so the chevron always reads low, and its rotated
   footprint (about 19.8px) overhangs its 14px layout box and eats ~3px of the gap on each
   side. Fixed by translating the ink back to the optical centre in each state (the shift has
   to flip with the rotation, or opening the row would double the error) and by widening the
   summary gap so the overhang can no longer close on the text. */
.fsk-accordion > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-5); min-height: 56px; padding: var(--space-4) var(--space-2);
  font-size: var(--text-body); font-weight: 700; color: var(--color-text);
}
.fsk-accordion > summary::-webkit-details-marker { display: none; }
.fsk-accordion > summary::after { content: ""; width: 14px; height: 14px; flex: 0 0 auto; border-right: 2.5px solid var(--color-accent); border-bottom: 2.5px solid var(--color-accent); transform: translateY(-4px) rotate(45deg); transition: transform var(--motion-settle) var(--ease-settle); }
.fsk-accordion[open] > summary::after { transform: translateY(4px) rotate(-135deg); }
.fsk-accordion__panel { padding: 0 var(--space-2) var(--space-5); font-size: 15px; line-height: var(--leading-body); color: var(--color-text); }

/* ------------------------------ FDA ------------------------------------- */
.fsk-fda {
  background: var(--color-surface); color: var(--color-text-muted);
  border-left: 4px solid var(--color-brand);
  border-radius: 0 var(--radius-md) var(--radius-md) var(--radius-xs);
  padding: var(--space-4) var(--space-5); font-family: var(--font-body);
  font-size: var(--text-small); line-height: 1.6; max-width: 680px; margin-inline: auto;
}
.fsk-fda__label { display: block; font-size: var(--text-micro); font-weight: 800; letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; margin-bottom: var(--space-1); }

/* --------------------------- ANNOUNCEMENT ------------------------------- */
/* Horizon announcement bar, defaulted to Amber (label Ink Navy per palette law). */
.announcement-bar,
.announcement-bar .section-background { background: var(--amber) !important; }
.announcement-bar { color: var(--ink-navy) !important; }
.announcement-bar :is(.announcement-bar__text, a, p, span) { color: var(--ink-navy) !important; }
.announcement-bar.fsk-annbar--teal,
.announcement-bar.fsk-annbar--teal .section-background { background: var(--reef-teal) !important; }
.announcement-bar.fsk-annbar--citrus,
.announcement-bar.fsk-annbar--citrus .section-background { background: var(--citrus) !important; }

/* --------------------------- MARQUEE ------------------------------------ */
/* H-16 (2026-07-29, Andrew): "the scrolling banner is displaying very close to the Start a
   Subscription button. It should be right in the middle ... the negative space on this banner
   is also a bit too much, it's taking up way too much space, condense it."
   Two separate causes, so two changes.
   (a) The band ABOVE is the real reason the row looks glued to the button. On the homepage the
       Build-your-stack band ends with .fsk-band's full bottom padding, up to 96px, while the
       row sits only ~25px above the button. So the gap above the row was roughly four times
       the gap below it. The rule further down cuts that bottom padding when a marquee follows.
   (b) The marquee's own padding is trimmed slightly, and the row-to-button gap is brought into
       line with it, so the row reads centred inside the band instead of bottom-weighted.
   NOT render-verified: nothing is pushed and the storefront preview is blocked from this
   container, so these numbers are reasoned from the cascade, not measured. Andrew should eyeball
   the homepage before this is treated as settled. */
.fsk-marq { overflow: hidden; padding-block: clamp(12px, 1.6vw, 18px); display: grid; gap: 5px; }
.fsk-marq--dark { background: var(--color-inverse-bg); color: var(--color-inverse-text); }
.fsk-marq--citrus { background: var(--citrus); color: var(--ink-navy); }
.fsk-marq--surface { background: var(--color-surface); color: var(--color-text); }
.fsk-marq--deepblue { background: var(--deep-blue); color: var(--white); }
.fsk-marq__row { display: flex; overflow: hidden; }
.fsk-marq__track { display: inline-flex; align-items: center; flex: 0 0 auto; white-space: nowrap; animation: fsk-marq 34s linear infinite; will-change: transform; }
.fsk-marq__row--rev .fsk-marq__track { animation-direction: reverse; }
.fsk-marq__item { display: inline-flex; align-items: center; gap: clamp(16px,2.4vw,32px); padding-right: clamp(16px,2.4vw,32px);
  font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-size: clamp(17px, 2.6vw, 32px); font-weight: 600; line-height: 1.1; }
/* H-04 (Andrew: "maybe the SVGs could be a little bit bigger on this part"). Raised from
   clamp(16px,2vw,26px). The rule is shared by both marquees and the marquee only mounts on the
   homepage, so the blast radius is the two homepage bands and nothing else. */
.fsk-marq__sep { width: clamp(20px,2.6vw,34px); height: clamp(20px,2.6vw,34px); flex: 0 0 auto; }
/* H-03, corrected after rendering the band rather than reading the stylesheet.
   Andrew: "the icons are washed out, you can't see them, the orange and yellow are too close."

   There are two separate failures here and the first one is the big one:
   (a) The glyph BODY was pinned to Citrus while `.fsk-marq--dark` does NOT resolve to a dark
       ground on this site. `--color-inverse-bg` is overridden to Reef Teal in the teal-block
       context, so both homepage marquees actually paint Citrus glyphs on a bright teal band:
       **1.26:1**. Effectively invisible, which is exactly what he described. Measuring against the
       navy the token nominally holds is how this stayed hidden.
   (b) The duotone accent fell back to amber-gold, 1.33:1 against a Citrus body, so even where the
       body did show, the two-tone detail collapsed into one blob.

   Fix keys both colours off the band's own tokens instead of hardcoding, so it stays correct
   whether the band resolves to Reef Teal or to a true dark ground:
     body   = --color-inverse-text, i.e. exactly the colour of the marquee text beside it, which is
              already proven legible on that band (Ink Navy on teal = 10.09:1).
     accent = --color-inverse-bg, i.e. the band itself, so the duotone detail reads as clean
              cutouts. That is this stylesheet's existing --fsk-glyph-knockout treatment, and its
              contrast equals the body's, so it can never collapse again.
   Safe for the five species glyphs because every accent path in them is drawn ON TOP of the
   currentColor body, never against bare background (verified path-order on all five). */
.fsk-marq--dark .fsk-marq__sep, .fsk-marq--deepblue .fsk-marq__sep {
  color: var(--color-inverse-text);
  --fsk-glyph-accent: var(--color-inverse-bg);
}
.fsk-marq--citrus .fsk-marq__sep { color: var(--deep-blue); }
.fsk-marq--surface .fsk-marq__sep { color: var(--reef-teal); }
.fsk-marq__cta { text-align: center; margin-top: clamp(12px,1.6vw,18px); }
/* H-16 (a): pull the band above up off the marquee. Scoped so it only fires where a marquee
   actually follows, which today is the homepage's Build-your-stack band and nothing else, so
   no other band's rhythm moves. Roughly halves that band's bottom padding. */
.fsk-sec:has(+ .fsk-sec > .fsk-marq) > .fsk-band { padding-bottom: clamp(28px, 4.5vw, 52px); }
@keyframes fsk-marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .fsk-marq__track { animation: none; } }

/* FSK review-controls panel (crest / light-dark toggles + its floating buttons)
   removed 2026-08-06: all three constants are ruled and now stamped on <html>
   in layout/theme.liquid. The [data-theme="dark"] rules below stay put for the
   post-launch dark-mode fast-follow. */

/* ============================================================
   PDP BUY BOX — pdp-mock.html port (2026-07-18)
   Scope: .product-information only. Type + hierarchy per the
   approved mock (.buybox__* spec): Fraunces display title/price,
   18px benefit line, micro-labels, seed-radius pills, value CTA.
   All colors via existing vars — dark mode inherits.
   ============================================================ */
.product-information .text-block h1 {
  font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 600; font-size: clamp(28px, 4vw, 38px); line-height: 1.1; letter-spacing: -0.01em;
}
.product-information [class*="hero_line_fsk"] p { font-size: 18px; font-weight: 600; line-height: 1.35; }
.product-information .price {
  font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 700; font-size: 30px; line-height: 1;
}
.sticky-add-to-cart .price { font-size: 17px; }
.product-information legend,
.product-information .variant-option__label,
.product-information .quantity-label {
  text-transform: uppercase; letter-spacing: 0.08em; font-size: 12px; font-weight: 800;
  color: var(--color-text-muted);
}
.product-information .variant-option__button-label {
  border-radius: var(--radius-seed-input); font-size: 14px; letter-spacing: 0;
}
.product-information .variant-option__button-label:has(input:checked) {
  background: var(--color-accent); border-color: var(--color-accent); color: #fff;
}
/* copy-final §5 "Recommended" tag on the recommended size. Real DOM node emitted by
   variant-main-picker.liquid (was a CSS ::after, so screen readers and crawlers never saw
   it). Outline-chip vocabulary, same family as the §8 trust chips, drawn in currentColor so
   it stays legible on all four button states: light surface, Deep Blue selected (light),
   dark surface, and Amber selected (dark, where --color-accent flips to amber and a citrus
   fill went yellow-on-yellow). No new colors. */
/* The tag sat high inside its bubble: as an inline-block with line-height 1.3, the
   uppercase glyphs (no descenders) rode the top of a line box sized for descender space.
   inline-flex + centring makes the bubble centre its own content instead of relying on
   the line box; the 1px optical bias (4px top / 3px bottom) compensates for the descender
   gap under a caps-only string. Measured centroid offset after: see buybox-picker-mock.
   Mechanical fix only -- the colour work is Andrew's pick, mocked, not shipped. */
.product-information .fsk-variant-rec {
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1; flex: 0 0 auto; margin-left: 8px; padding: 5.5px 9px 1.5px;
  /* Horizon's sweep pill is an absolutely-positioned sibling, and its own label text
     carries z-index:2 to clear it. This tag had no z-index and only cleared the pill as a
     side-effect of opacity:0.85 creating a stacking context -- so any future change to
     that opacity would silently hide the bubble behind the pill. Made explicit. */
  position: relative; z-index: 2;
  /* 2026-08-07 final audit · was 10px, under the ramp's 12px micro floor (§C.4: micro 12px is
     the bottom of the scale). Raised to the token so the buy box has nothing off-ramp in it.
     The tag is white-space:nowrap inside a row with slack, so nothing reflows. */
  font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  letter-spacing: var(--tracking-badge); text-transform: uppercase;
  color: inherit; background: transparent;
  border: var(--border-hairline) solid currentColor; border-radius: var(--radius-seed-badge);
  opacity: 0.85; white-space: nowrap; vertical-align: middle;
}
.product-information button[name="add"],
.product-information .add-to-cart-button,
.sticky-add-to-cart button[name="add"] {
  background: var(--color-cta-value-fill); color: var(--color-cta-value-label);
  border: 0; border-radius: var(--radius-seed-m); min-height: 52px; font-weight: 700;
  box-shadow: var(--shadow-amber-rest);
}
.product-information button[name="add"]:hover,
.product-information .add-to-cart-button:hover {
  transform: translateY(1px); box-shadow: var(--shadow-amber-settle);
  background-image: linear-gradient(var(--veil-hover-on-amber), var(--veil-hover-on-amber));
}
.product-information .quantity-selector { border-radius: var(--radius-seed-input); }
.product-information .accelerated-checkout-block {
  --shopify-accelerated-checkout-button-block-size: 44px; margin-top: 4px;
}
.product-information .product-media { border-radius: var(--radius-seed-m); overflow: hidden; }
.product-information .product-media__image { border-radius: var(--radius-seed-m); }

/* Dark mode: the Horizon buy-box section carries a static custom color scheme whose
   near-black text does not flip with [data-theme] — force the fsk text var. */
[data-theme="dark"] .product-information,
[data-theme="dark"] .product-information .text-block h1,
[data-theme="dark"] .product-information .price,
[data-theme="dark"] .product-information [class*="hero_line_fsk"] p {
  color: var(--color-text);
}
/* ============================================================================
   BUY-BOX VARIANT PICKER — brand recolour. RULED Andrew 2026-07-20 (sweep Amber,
   selected Citrus + Ink Navy) and 2026-07-21 (Recommended bubble = solid white/Mint;
   glass rejected — its fill measured 1.04:1 against the Citrus row because
   backdrop-filter has nothing to refract on a flat pill, and the buy-box panel is
   already the ruled glass surface). Mocked first per PF-11:
   content-drafts/website-preplan/buybox-picker-mock/.

   Done as a scoped CSS override, NOT by editing config/settings_data.json: the
   palette_variant_* settings are baked literals consumed by every scheme surface
   sitewide, so changing them there would reach far beyond the picker.
   Measured: Ink Navy on Citrus 12.68:1 · Ink Navy on Mint Air bubble 15.12:1 ·
   Ink Navy on Amber mid-sweep 9.54:1 · Ink Navy on white row 15.54:1.
   The Ink Navy hairline on the bubble is load-bearing, not decoration: every
   candidate fill sits under the 3:1 boundary gate against Citrus (Mint Air 1.19:1),
   so the border is what gives the chip its edge.
   ========================================================================== */
.product-information .variant-option__button-label {
  /* unselected row: brand neutrals instead of the palette's #fff/#000/#DFDFDF.
     This is also what makes the picker theme-aware -- the palette literals cannot
     follow [data-theme], which is why dark mode rendered a glaring white slab. */
  --color-variant-background: var(--color-surface-raised);
  --color-variant-text: var(--color-text);
  --color-variant-border: var(--color-border-strong);
  --color-variant-hover-background: var(--color-surface);
  --color-variant-hover-text: var(--color-text);
  --color-variant-hover-border: var(--ink-40);
  --color-selected-variant-background: var(--citrus);
  --color-selected-variant-text: var(--ink-navy);
  --color-selected-variant-border: var(--ink-navy);
}
/* the settled selected row. The label text is pinned as well as the label itself:
   leaving the child to inherit rendered it white-on-Citrus (1.23:1) in the mock. */
.product-information .variant-option__button-label:has(:checked),
.product-information .variant-option__button-label:has(:checked) .variant-option__button-label__text {
  color: var(--ink-navy);
}
.product-information .variant-option__button-label:has(:checked) { border-color: var(--ink-navy); }

/* THE SWEEP. Horizon's pill IS the selected background (one element), so "Amber sweep
   settling to Citrus" is a colour change on that pill. Done as a TRANSITION with a
   delay, deliberately not a keyframe animation: a keyframe would replay on every page
   load, and §0.5 allows no auto-playing motion. CSS transitions do not run on initial
   style computation, so on load the pill paints Citrus immediately; only a real variant
   change slides the pill in Amber and lets it settle to Citrus after the delay. */
.product-information .variant-option__button-label__pill { background: var(--amber); }
.product-information .variant-option__button-label:has(:checked) .variant-option__button-label__pill {
  background: var(--citrus);
  transition: background-color var(--motion-slow) var(--ease-settle) 220ms;
}
@media (prefers-reduced-motion: reduce) {
  .product-information .variant-option__button-label:has(:checked) .variant-option__button-label__pill {
    transition: none;
  }
}

/* the Recommended bubble: solid Mint Air, Ink Navy label, Ink Navy hairline. opacity
   goes to 1 -- the tag no longer needs to be dimmed now that it is a filled chip, and
   its stacking is explicit (position/z-index above) rather than a side-effect of opacity. */
.product-information .fsk-variant-rec {
  background: var(--mint-air);
  color: var(--ink-navy);
  border-color: var(--ink-navy);
  opacity: 1;
}

.fsk-pricerow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 6px; }
.fsk-pricerow .fsk-chip { font-size: 12px; padding: 4px 12px; }

/* Per-serving value on each size button (Andrew 2026-07-24, candidate B; mocked in
   buybox-perserving-mock/). The base label is a centered flex row; only labels that
   actually carry a per-serving line wrap to a second row (:has scopes this so every
   other product's variant buttons are untouched). The figure is live price / servings,
   emitted server-side per option value in variant-main-picker.liquid, so 2 oz visibly
   reads as the better value beneath the Recommended chip. */
.product-information .variant-option__button-label:has(.fsk-variant-perserv) {
  flex-wrap: wrap;
  row-gap: 2px;
}
.product-information .fsk-variant-perserv {
  flex: 0 0 100%;
  order: 3;
  text-align: center;
  font-family: var(--font-body);
  /* 2026-08-07 final audit · was 11px, under the ramp's 12px micro floor. This line is the
     per-serving anchor the buy-box spec requires in viewport 1, so it is the last thing that
     should be rendering off-ramp. It owns its own full-width row and is nowrap, so the extra
     pixel changes nothing but the size. */
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  color: var(--color-text-muted);
  position: relative;
  z-index: 2;
}
.product-information .variant-option__button-label:has(:checked) .fsk-variant-perserv {
  color: var(--ink-navy);
}

/* ============================================================
   PDP RELUME APPLICATION (2026-07-18b) — breadcrumb, subscribe
   selector cards (pdp-mock .subsel), 2x2 outcome grid, photo
   benefit cards, subscribe perk row. Vars only; dark inherits.
   ============================================================ */
.fsk-breadcrumb { font-size: 13px; color: var(--color-text-muted); display: flex; gap: 6px; flex-wrap: wrap; }
.fsk-breadcrumb a { color: var(--color-text-muted); text-decoration: none; }
.fsk-breadcrumb a:hover { color: var(--color-text); }
.fsk-subsel { border: 0; padding: 0; margin: 0; display: grid; gap: 10px; }
.fsk-subsel__legend { text-transform: uppercase; letter-spacing: 0.08em; font-size: 12px; font-weight: 800; color: var(--color-text-muted); padding: 0; margin-bottom: 4px; }
.fsk-subsel__card { display: flex; align-items: center; gap: 12px; padding: 13px 16px; border: 1.5px solid var(--color-border, rgba(16,34,46,0.18)); border-radius: var(--radius-seed-input); cursor: pointer; }
.fsk-subsel__card input { accent-color: var(--color-accent); width: 18px; height: 18px; flex: none; }
.fsk-subsel__card:has(input:checked) { border-color: var(--color-accent); box-shadow: 0 0 0 1.5px var(--color-accent); background: var(--color-surface-raised); }
.fsk-subsel__body { display: grid; gap: 2px; }
.fsk-subsel__label { font-weight: 700; }
.fsk-subsel__meta { font-size: 13px; color: var(--color-text-muted); }
.fsk-subsel__price { font-family: var(--font-display); font-variation-settings: var(--font-display-settings); font-weight: 700; font-size: 19px; margin-left: auto; white-space: nowrap; }
.fsk-subsel__perk { font-size: 13px; color: var(--color-text-muted); margin: 2px 0 0; }
.fsk-outcomes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 22px; }
.fsk-outcomes__item { display: flex; align-items: center; gap: 12px; background: var(--color-surface-raised); border-radius: var(--radius-seed-s); padding: 14px 16px; font-weight: 600; box-shadow: var(--shadow-card); }
.fsk-outcomes__item svg { width: 26px; height: 26px; color: var(--color-accent); flex: none; }
.fsk-bcard { background: var(--color-surface-raised); border-radius: var(--radius-seed-card); overflow: hidden; box-shadow: var(--shadow-card); display: flex; flex-direction: column; }
.fsk-bcard__media { aspect-ratio: 4 / 3; overflow: hidden; }
.fsk-bcard__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fsk-bcard__body { padding: 20px; display: grid; gap: 8px; align-content: start; }
/* .fsk-bcard's own background is --color-surface-raised (see above); the label sits
   directly on the card body with no separate plate, so the knockout token matches it 1:1 */
.fsk-bcard__label { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-accent); --fsk-glyph-knockout: var(--color-surface-raised); }
/* 24px legibility floor for duotone spot glyphs (was 18px) */
.fsk-bcard__label svg { width: 24px; height: 24px; }
.fsk-bcard__line { font-family: var(--font-display); font-variation-settings: var(--font-display-settings); font-size: 1.25rem; font-weight: 600; line-height: 1.25; }
.fsk-perkrow { display: flex; gap: 12px 26px; flex-wrap: wrap; justify-content: center; margin-top: 18px; }
.fsk-perkrow__item { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; }
.fsk-perkrow__item svg { width: 20px; height: 20px; flex: none; }
@media screen and (max-width: 749px) {
  .fsk-outcomes { grid-template-columns: 1fr; }
}

/* Buy box glass window (Andrew 2026-07-18: quiz-teaser glass treatment on the
   details column). Glow scene behind, frosted panel on .product-details —
   Horizon markup can't take the .fsk-glass class, so the styles are mirrored. */
.product-information { position: relative; isolation: isolate; }
.product-information::before {
  content: ""; position: absolute; inset: -6% -2%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(40% 52% at 78% 24%, var(--teal-35), transparent 70%),
    radial-gradient(44% 56% at 92% 62%, var(--blue-30), transparent 72%),
    radial-gradient(38% 48% at 64% 88%, var(--citrus-30), transparent 72%);
  filter: blur(22px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 18%, #000 82%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 18%, #000 82%, transparent 100%);
}
.product-information .product-details {
  background: rgba(255,255,255,0.14);
  -webkit-backdrop-filter: blur(24px) saturate(1.7);
  backdrop-filter: blur(24px) saturate(1.7);
  border: 1px solid rgba(255,255,255,0.5);
  border-radius: var(--radius-seed-feature);
  box-shadow: var(--shadow-raised), inset 0 1px 0 rgba(255,255,255,0.65);
  padding: clamp(20px, 2.6vw, 36px);
}
[data-theme="dark"] .product-information .product-details {
  background: rgba(18,20,25,0.68); border-color: rgba(255,255,255,0.14);
}
.product-information .product-details .fsk-chip--outline { background: var(--color-surface-raised); }

/* Subscribe band split + scroll-driven refill loop (NeuroGum-style life, abstract only) */
.fsk-refill-loop { width: min(300px, 70%); margin-inline: auto; display: block; color: var(--citrus); }
.fsk-refill-loop .loop-arc { fill: none; stroke: currentColor; stroke-width: 7; stroke-linecap: round; }
/* Arrowhead rides the leading edge of the drawing arc (PF-42): the shared driver positions it at
   the arc's tip via data-follow (getPointAtLength). Base transform in the Liquid parks it at the
   finished end for no-JS/reduced-motion. */
.fsk-refill-loop .loop-head { fill: none; stroke: currentColor; stroke-width: 7; stroke-linecap: round; stroke-linejoin: round; }
.fsk-refill-loop .loop-drop { color: var(--white); }
/* The "On your schedule" label inherits currentColor from .fsk-refill-loop (Citrus), which
   measures 4.44:1 on the Deep Blue band -- fine for the arc itself (a graphic, 3:1 gate)
   but under the 4.5 gate as text, in both themes. Only the text moves; the arc keeps its
   Citrus so the band's one accent is unchanged. */
.fsk-refill-loop text { fill: var(--white); }
/* JS-driven (shared scaffold). Base above = finished frame (arc drawn, perks in place); data-r
   ranges live in fsk-bundle-cta.liquid + fsk-subscribe-education.liquid. */
.fsk-motion-js .fsk-refill-loop .loop-arc { stroke-dasharray: 100; stroke-dashoffset: 100; animation-name: fsk-loop-draw; }
.fsk-motion-js .fsk-perkrow--animated .fsk-perkrow__item { opacity: 0; translate: 0 10px; animation-name: fsk-perk-in; }
@keyframes fsk-loop-draw { to { stroke-dashoffset: 0; } }
@keyframes fsk-perk-in { to { opacity: 1; translate: 0 0; } }
/* T1 home slot (bundle CTA): compact loop above the heading. On the navy band the arc
   reads Reef Teal, never Citrus -- the Amber CTA stays the band's one warm accent (PF-5). */
.fsk-refill-loop--compact { width: min(180px, 52%); margin-bottom: 6px; }
.fsk-band--dark .fsk-refill-loop { color: var(--reef-teal); }

/* ── 2026-08-07 final audit · teal-ground corrections ─────────────────────────────
   layout/theme.liquid stamps data-block="teal" site-wide, so .fsk-band--dark's ground IS
   Reef Teal. Three rules above were authored when that ground was Ink Navy and were never
   re-tuned, and each rendered its element invisible on the live page:
     · the loop arc took --reef-teal  -> teal on teal, 1.0:1
     · .fsk-refill-loop text took --white -> 1.54:1 (and it is an SVG <text>, so the
       [data-block="teal"] p.fsk-eyebrow repair above cannot reach it)
     · .loop-drop took --white -> 1.54:1, under the 3:1 graphic gate
   On a teal ground all three take the band's own ruled ink (Ink Navy, ~11:1).
   Scoped to [data-block="teal"] so the navy-ground behaviour above is preserved intact. */
[data-block="teal"] .fsk-band--dark .fsk-refill-loop            { color: var(--color-inverse-text); }
[data-block="teal"] .fsk-band--dark .fsk-refill-loop text       { fill: var(--color-inverse-text); }
[data-block="teal"] .fsk-band--dark .fsk-refill-loop .loop-drop { color: var(--color-inverse-text); }

/* PF-15 is explicit: Amber on Reef Teal measures ~1.1:1, so teal bands carry ZERO Amber.
   The bundle band's subscribe CTA was .fsk-btn--value (Amber fill) sitting on teal, giving the
   page's main conversion ask no visible button edge. Pinned per-band exactly the way
   .fsk-band--citrus pins its own CTA tokens above (PF-28b / PF-59 pattern) rather than changing
   the global tokens, so every other band is untouched. */
[data-block="teal"] .fsk-band--dark {
  --color-cta-value-fill:  var(--ink-navy);
  --color-cta-value-label: var(--mint-air);
  --color-cta-fill:        var(--ink-navy);
  --color-cta-label:       var(--mint-air);
}

/* Bundles row on Also-try */
.fsk-bundlerow { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin-top: 26px; }
.fsk-bundlerow .fsk-panel { max-width: none; display: grid; gap: 8px; align-content: start; text-decoration: none; color: inherit; }
.fsk-bundlerow .fsk-panel:hover { box-shadow: var(--shadow-raised); }
@media screen and (max-width: 749px) { .fsk-bundlerow { grid-template-columns: 1fr; } }

/* ============================================================
   FIND YOUR MUSHROOM QUIZ (/pages/quiz · sections/fsk-quiz.liquid)
   The static mapping and the interactive layer share the panel/card
   language so hydration is not a visual jump.
   ============================================================ */
.fsk-visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

.fsk-quiz__head { text-align: center; max-width: 62ch; margin: 0 auto var(--space-7); }
.fsk-quiz__intro { margin-top: var(--space-4); }

.fsk-quiz__panel { padding: clamp(24px, 4vw, 40px); border-radius: var(--radius-seed-feature); }
.fsk-quiz__panel--result { display: grid; gap: var(--space-5); }
.fsk-quiz__q { margin: 0 0 var(--space-5); }

/* Option cards ------------------------------------------------ */
.fsk-quiz__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-3); }
.fsk-quiz__grid--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fsk-quiz__grid--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.fsk-quiz__opt {
  position: relative;
  display: grid; gap: 6px; align-content: start; text-align: left; cursor: pointer;
  background: var(--color-surface-raised); color: inherit; font: inherit;
  border: 1px solid var(--color-border); border-radius: var(--radius-seed-card);
  padding: var(--space-4); transition: box-shadow .18s ease, border-color .18s ease, translate .18s ease;
}
.fsk-quiz__opt:hover { box-shadow: var(--shadow-raised); translate: 0 -2px; }
.fsk-quiz__opt:focus-visible,
.fsk-quiz__opt:has(:focus-visible) { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
.fsk-quiz__opt.is-selected { border-color: var(--color-brand); box-shadow: 0 0 0 2px var(--color-brand) inset; }
/* The checkbox covers the entire card so no part of it is dead to a tap. Card contents are
   pointer-transparent, so a tap anywhere (padding included) reaches the control exactly once.
   Regression guard: tapping the card's padding used to leave the option unselected. */
.fsk-quiz__optinput {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer; z-index: 1;
}
.fsk-quiz__opticon, .fsk-quiz__optlabel, .fsk-quiz__optgloss { pointer-events: none; }

.fsk-quiz__opticon { display: inline-flex; }
.fsk-quiz__opticon svg { width: 28px; height: 28px; color: var(--color-brand); }
.fsk-quiz__optlabel { font-weight: 600; }
.fsk-quiz__optgloss { color: var(--color-text-muted); font-size: .92rem; line-height: 1.45; }

.fsk-quiz__cue { margin-top: var(--space-4); color: var(--color-text-muted); font-size: .95rem; }
.fsk-quiz__continue { margin-top: var(--space-5); }
.fsk-quiz__continue[disabled] { opacity: .45; cursor: not-allowed; }

.fsk-quiz__back {
  background: none; border: 0; padding: 0 0 var(--space-4); font: inherit; cursor: pointer;
  color: var(--color-text-muted);
}
.fsk-quiz__back:hover { color: var(--color-link); }

/* Result ------------------------------------------------------ */
.fsk-quiz__leadin { font-family: var(--font-display); font-size: clamp(1.15rem, 2.2vw, 1.5rem); line-height: 1.35; }
.fsk-quiz__cards { display: grid; gap: var(--space-4); }
.fsk-quiz__cards:has(.fsk-quiz__card + .fsk-quiz__card) { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

.fsk-quiz__card {
  display: grid; gap: 10px; align-content: start;
  background: var(--color-surface-raised); border-radius: var(--radius-seed-card);
  padding: var(--space-5); box-shadow: var(--shadow-card);
}
.fsk-quiz__card--fresh.is-secondary { border: 1px dashed var(--color-border-strong); box-shadow: none; }
.fsk-quiz__micro-label {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--color-brand); font-weight: 600;
}
.fsk-quiz__cardtitle { font-family: var(--font-display); font-size: 1.25rem; margin: 0; }
.fsk-quiz__affirm { font-weight: 600; color: var(--color-brand); }
.fsk-quiz__benefit { font-size: 1.02rem; }
.fsk-quiz__feel, .fsk-quiz__usage, .fsk-quiz__conditional { color: var(--color-text-muted); font-size: .93rem; line-height: 1.5; }
.fsk-quiz__card .fsk-btn { margin-top: 4px; justify-self: start; }
.fsk-quiz__dshea { font-size: .72rem; line-height: 1.45; color: var(--color-text-muted); margin-top: 4px; }
.fsk-quiz__note { margin: 0; padding-left: var(--space-4); border-left: 3px solid var(--color-brand); font-style: italic; }

.fsk-quiz__stackcta { justify-self: start; }
.fsk-quiz__bridge, .fsk-quiz__links, .fsk-quiz__escape { font-size: .93rem; color: var(--color-text-muted); }
.fsk-quiz__startover { background: none; border: 0; padding: 0; font: inherit; text-decoration: underline; cursor: pointer; color: var(--color-text-muted); justify-self: start; }
.fsk-quiz__startover:hover { color: var(--color-link); }

/* Email capture ----------------------------------------------- */
.fsk-quiz__formwrap { border-top: 1px solid var(--color-border); padding-top: var(--space-5); }
.fsk-quiz__formlede { font-size: .95rem; line-height: 1.55; }
.fsk-quiz__formrow { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--space-4); }
.fsk-quiz__formrow input[type="email"], .fsk-quiz__formrow select {
  flex: 1 1 180px; min-width: 160px; padding: 12px 14px; font: inherit; color: inherit;
  background: transparent; border: 1px solid var(--color-border); border-radius: var(--radius-seed-input);
}
.fsk-quiz__micro { margin-top: 10px; font-size: .8rem; color: var(--color-text-muted); }
.fsk-quiz__ok { margin-top: 10px; font-weight: 600; color: var(--color-brand); }

/* Static mapping ---------------------------------------------- */
.fsk-quiz__maplist { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.fsk-quiz__maplist li { line-height: 1.55; }
.fsk-quiz__subhead { margin-top: var(--space-6); }
.fsk-quiz__pickup { font-size: .8rem; color: var(--color-text-muted); font-weight: 400; }

@media screen and (max-width: 749px) {
  .fsk-quiz__grid, .fsk-quiz__grid--two, .fsk-quiz__grid--three { grid-template-columns: 1fr; }
  .fsk-quiz__cards:has(.fsk-quiz__card + .fsk-quiz__card) { grid-template-columns: 1fr; }
  /* Long multi-select on Q1 and the primary CTA on result screens stay reachable (JRNY-9). */
  .fsk-quiz__continue {
    position: sticky; bottom: 12px; width: 100%; justify-content: center; z-index: 2;
    box-shadow: 0 6px 20px rgba(0,0,0,.16);
  }
}
@media (prefers-reduced-motion: reduce) {
  .fsk-quiz__opt { transition: none; }
  .fsk-quiz__opt:hover { translate: none; }
}

/* --------------- BUILT TO ABSORB (bioavailability band, PF-12) ----------- */
/* Glass feature panel on haze; COMBO motion ruled 2026-07-19: liquid-light drift
   + one solid drop shedding bubbles. All timings deliberately slow (8-20s). */
.fsk-wave--bg { color: var(--color-bg); } /* wave fill for colored-band -> haze seams */
.fsk-bio__glow { opacity: 0.5; filter: blur(30px); } /* softened vs buy-box glow */
.fsk-bio { padding: clamp(28px,4vw,56px); display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(24px,4vw,56px); align-items: center; }
.fsk-bio__copy .fsk-lede { margin-top: 12px; }
.fsk-bio__close { margin-top: 18px; }
.fsk-bio__chips { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 0; padding: 0; list-style: none; }
.fsk-bio__chips li { display: inline-flex; align-items: center; gap: 8px; width: fit-content;
  background: rgba(255,255,255,0.38); border: 1.5px solid rgba(255,255,255,0.55);
  border-radius: var(--radius-seed-badge); padding: 7px 13px;
  font-family: var(--font-body); font-size: var(--text-small); font-weight: 700; color: var(--color-text); }
.fsk-bio__chips li svg { width: 18px; height: 18px; flex: none; color: var(--color-accent); }
.fsk-bio__chips li:nth-child(2) svg { color: var(--color-brand); }
[data-theme="dark"] .fsk-bio__chips li { background: var(--mintair-10); border-color: var(--mintair-16); }
.fsk-bio__win { position: relative; overflow: hidden; aspect-ratio: 4/4.6; max-height: 520px; width: 100%;
  border-radius: var(--radius-seed-card); border: 1px solid rgba(255,255,255,0.5);
  background: linear-gradient(180deg, rgba(255,255,255,0.34), rgba(240,255,254,0.16)); }
[data-theme="dark"] .fsk-bio__win { border-color: var(--mintair-16); background: linear-gradient(180deg, var(--mintair-06), rgba(240,255,254,0.02)); }
/* "Built to Absorb" window — vesicle redesign (PF-36, candidate A "forming stream", ruled
   2026-07-21). The empty bubbles became VESICLES: a compound core wrapped in a translucent
   membrane = the abstract picture of nanoencapsulation (wordless, no numbers, PF-4). The drop
   sheds compounds that get wrapped and drift on; more form the further you scroll; rests calm.
   JS-driven via the shared scaffold (data-fsk-scroll on .fsk-bio__win, data-r per element).
   Base below = the calm rest frame (wash + settled drop, vesicles at opacity 0). */
.fsk-bio__blob { position: absolute; border-radius: 50%; filter: blur(28px); opacity: .85; }
.fsk-bio__b1 { width: 320px; height: 280px; left: -16%; top: -8%; background: rgb(47 231 225/.34); }
.fsk-bio__b2 { width: 360px; height: 320px; right: -22%; top: 26%; background: rgb(0 98 227/.26); }
.fsk-bio__b3 { width: 260px; height: 220px; left: -6%; bottom: -12%; background: rgb(242 238 84/.22); }
.fsk-bio__drop { position: absolute; left: 50%; top: 11%; width: 76px; height: 76px; margin-left: -38px;
  color: var(--color-accent); filter: drop-shadow(0 10px 22px rgba(10,37,64,0.18)); }
.fsk-ves { position: absolute; left: var(--x); top: var(--y); width: var(--s); height: var(--s); margin-left: calc(var(--s) / -2); opacity: 1; }
/* 2026-08-07 final audit · the field read as SCATTERED DOTS, not PF-36's "solid compound core
   in a translucent membrane". The cores were doing all the work: the membrane was a 1.5px ring
   at 50% teal over a nearly-transparent fill, which on the pale window wash left the smaller
   vesicles (32-38px) showing little more than their core dot. The scene's whole job is the
   enclosure, so the membrane is the part that has to read. Ring taken to 2px and up to 85% of
   the brand teal, and the fill given a real teal body instead of a 5-16% whisper, so every
   vesicle reads as something WRAPPED at every size in the field. Geometry, sizes, positions
   and the forming animation are untouched — this is legibility, not a redraw. Alpha values are
   now composed from --reef-teal / --white with color-mix instead of repeating the palette as
   rgba() literals, so they track the token. */
.fsk-ves__mem { position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 36% 30%,
    color-mix(in srgb, var(--white) 72%, transparent),
    var(--teal-35) 54%,
    var(--teal-12) 84%);
  border: 2px solid color-mix(in srgb, var(--reef-teal) 85%, transparent);
  box-shadow: inset 0 1px 3px color-mix(in srgb, var(--white) 55%, transparent), 0 2px 9px var(--ink-13); }
.fsk-ves__core { position: absolute; left: 50%; top: 50%; width: 30%; height: 30%; margin: -15% 0 0 -15%; border-radius: 50%; background: var(--color-accent); box-shadow: 0 0 0 3px rgba(255,255,255,.28); }
.fsk-ves__core2 { position: absolute; left: 62%; top: 38%; width: 15%; height: 15%; border-radius: 50%; background: var(--reef-teal); opacity: .9; }
[data-theme="dark"] .fsk-ves__mem { border-color: rgba(47,231,225,.42); background: radial-gradient(circle at 36% 30%, rgba(240,255,254,.24), rgba(47,231,225,.12) 55%, rgba(47,231,225,.04) 82%); box-shadow: inset 0 1px 3px rgba(240,255,254,.2), 0 2px 9px rgba(0,0,0,.3); }
[data-theme="dark"] .fsk-ves__core { box-shadow: 0 0 0 3px rgba(12,13,16,.4); }

@keyframes fsk-bio-blob { from { transform: translate(var(--bx,-30px), var(--by,-20px)) scale(1.08); } to { transform: none; } }
@keyframes fsk-bio-drop { from { transform: translateY(-14px) scale(.9); } to { transform: none; } }
/* Vesicles REST VISIBLE (base opacity 1 above) so the band is never empty, even with no JS.
   On scroll each forms in place (scale + fade), staggered, and holds -> "more forming as you
   scroll" while the compounds-in-membranes are always present. End state = the base field. */
@keyframes fsk-ves-form {
  0%   { opacity: 0; transform: translateY(14px) scale(.3); }
  55%  { opacity: 1; transform: translateY(0) scale(1.06); }
  78%  { transform: translateY(0) scale(1); }
  100% { opacity: 1; transform: none; }
}
.fsk-motion-js .fsk-bio__drop { animation-name: fsk-bio-drop; }
.fsk-motion-js .fsk-bio__b1 { --bx: -30px; --by: -20px; animation-name: fsk-bio-blob; }
.fsk-motion-js .fsk-bio__b2 { --bx: 42px;  --by: 22px;  animation-name: fsk-bio-blob; }
.fsk-motion-js .fsk-bio__b3 { --bx: -28px; --by: 26px;  animation-name: fsk-bio-blob; }
.fsk-motion-js .fsk-ves { animation-name: fsk-ves-form; }
@media screen and (max-width: 849px) {
  .fsk-bio { grid-template-columns: 1fr; }
  .fsk-bio__win { aspect-ratio: 4/3.4; max-height: 380px; }
}

/* ---------------- COMPACT ALWAYS/NEVER (PF-12 companion) ----------------- */
.fsk-anrows { display: grid; gap: var(--space-4); margin-top: var(--space-6); }
.fsk-anrow { position: relative; display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; padding-left: 84px; }
.fsk-anrow__label { position: absolute; left: 0; top: 11px; font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800; letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-text-muted); }
.fsk-anchip { display: inline-flex; align-items: center; gap: 8px; width: fit-content; background: var(--color-surface-raised); border-radius: var(--radius-seed-badge); padding: 8px 14px; font-family: var(--font-body); font-size: var(--text-small); font-weight: 600; color: var(--color-text); box-shadow: var(--shadow-card); }
.fsk-anchip svg { width: 18px; height: 18px; flex: none; color: var(--reef-teal); }
.fsk-anchip--no { background: transparent; box-shadow: none; border: 1.5px solid var(--color-border-strong); }
.fsk-anchip--no svg { color: var(--color-text-muted); }
.fsk-ancard { background: var(--color-surface-raised); border-radius: var(--radius-seed-feature); padding: var(--space-5) var(--space-6); box-shadow: var(--shadow-card); display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6); margin-top: var(--space-6); }
.fsk-ancard__label { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800; letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-text-muted); margin-bottom: var(--space-3); }
.fsk-ancard ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-2); }
.fsk-ancard li { display: flex; gap: 9px; align-items: flex-start; font-family: var(--font-body); font-size: var(--text-small); line-height: 1.5; color: var(--color-text); }
.fsk-ancard li svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }
.fsk-ancard__yes svg { color: var(--reef-teal); }
.fsk-ancard__no svg { color: var(--color-text-muted); }
@media screen and (max-width: 749px) {
  .fsk-anrow { padding-left: 0; }
  .fsk-anrow__label { position: static; width: 100%; }
  .fsk-ancard { grid-template-columns: 1fr; gap: var(--space-5); }
}

/* ============================================================================
   FSK · Sourcing band, "chain of custody" (PF-13 slot 5; DESIGN-DIRECTION §15
   PF-14, ruled 2026-07-20 on sourcing-band-mock/candidates.html #cand-a).
   Compact PDP-native rhythm -- this band runs shorter than a story band.
   ========================================================================== */
.fsk-src__band { padding-block: clamp(40px, 5.5vw, 68px); }

/* seam law (LAUNCH CORRECTION #8) is now sealed on .fsk-wave itself (see the SEAM SEAL
   block in the WAVES section), so the -1px margins that used to sit here are gone. They
   were both too narrow (this section only) and ineffective: this band still hairlined at
   1.5x and 1.75x DPR while carrying them. */

/* custody ribbon -- four beats on a hairline connector. RULED 2026-07-20: stays
   2-up at every width, never collapses to one column (measured 1164px on a
   390px phone at 1-col vs 851px at 2x2, on a band whose brief is "compact"). */
.fsk-src__chain { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--space-5); position: relative; }
.fsk-src__chain::before { content: ""; position: absolute; top: 27px; left: 12.5%; right: 12.5%; height: 2px; background: currentColor; opacity: 0.28; }
@media (max-width: 849px) {
  .fsk-src__chain { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .fsk-src__chain::before { display: none; }
}
.fsk-src__step { display: grid; gap: var(--space-3); justify-items: center; text-align: center; align-content: start; }
/* PF-15: the disc must be light in BOTH themes. --color-surface-raised resolves to
   night-surface in dark, which would put an Ink Navy glyph on a near-black disc
   (invisible) -- pinned to Mint Air instead so the glyph always clears its ground. */
.fsk-src__step-icon { width: 56px; height: 56px; border-radius: 50% 50% 50% 22%; display: grid; place-items: center; background: var(--mint-air); box-shadow: var(--shadow-card); position: relative; z-index: 1; }
[data-theme="dark"] .fsk-src__step-icon { background: var(--mintair-10); box-shadow: none; }
.fsk-src__step-icon svg { width: 28px; height: 28px; color: var(--ink-navy); }
[data-theme="dark"] .fsk-src__step-icon svg { color: var(--mint-air); }
.fsk-src__step-title { font-family: var(--font-body); font-weight: 800; font-size: var(--text-body); line-height: 1.3; }
.fsk-src__step-detail { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.5; opacity: 0.82; max-width: 24ch; }

/* provenance closer -- B7, "who made this" */
.fsk-src__prov { display: flex; align-items: center; justify-content: center; gap: var(--space-4); flex-wrap: wrap; text-align: left; max-width: 44rem; margin: var(--space-6) auto 0; padding-top: var(--space-5); border-top: var(--border-hairline) solid var(--ink-25); }
[data-theme="dark"] .fsk-src__prov { border-top-color: var(--mintair-28); }
/* landscape tile, not a 56px circle -- at circle size the photo read as a grey
   blob and failed the 44px legibility bar. */
.fsk-src__prov-face { flex: none; width: 104px; height: 78px; border-radius: var(--radius-seed-badge); object-fit: cover; box-shadow: var(--shadow-card); }
.fsk-src__prov-text { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.5; min-width: min(100%, 22rem); flex: 1 1 22rem; }
.fsk-src__prov-name { font-weight: 800; }
/* PF-15: Deep Blue on Reef Teal measures ~3.5:1 (fails 4.5:1), so on this band the
   link is Ink Navy + underline via color:inherit, never the standard blue link. */
.fsk-src__link { color: inherit; font-weight: 800; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 2px; white-space: nowrap; }
.fsk-src__link:hover { opacity: 0.72; }

/* ===================== SHARED scroll-motion scaffold (JS-driven, see assets/fsk-scroll-motion.js) =====================
   Native CSS scroll-timeline failed in a real supporting browser + gives no motion on iOS Safari (2026-07-21,
   memory reference_native_scroll_timeline_unreliable). All FSK scroll scenes are driven by the shared JS instead:
   paused keyframe animations whose progress is set via negative animation-delay. This scaffold turns any element
   into a JS-drivable one; per-scene CSS below just assigns the keyframe (animation-name) + the element carries
   data-r="start end" in the Liquid. Gated on .fsk-motion-js (added by the JS only when motion is allowed) so
   no-JS and reduced-motion users fall through to the base = finished-frame CSS with nothing to maintain. */
.fsk-motion-js [data-r] {
  animation-duration: 1s; animation-timing-function: linear; animation-fill-mode: both;
  animation-play-state: paused; animation-iteration-count: 1; animation-timeline: auto;
}

/* ===================== Powered by Nature "Arch light" scroll scene (Home §3, PF-35 / candidate D) =====================
   Abstract-only per PF-4. Named timeline is scoped to this section's media box so it never collides with
   the shared .fsk-split .fsk-media used elsewhere. Base CSS = the finished calm frame (bloom full, spill
   settled, breeze passed); the @supports + no-preference block adds the start-states + animation, so
   no-support browsers and reduced-motion users both land on the finished frame with nothing to maintain.
   Same discipline as .fsk-tl (below) and .fsk-refill-loop. */
/* .fsk-nature-media carries data-fsk-scroll in the Liquid = the JS scroll-driver root. */
.fsk-nature { display: block; width: 100%; height: 100%; }
.fsk-nature .ns-panel { fill: var(--color-bg); }
.fsk-nature .ns-arch { fill: var(--color-surface); }
.fsk-nature .ns-mass { fill: var(--color-text); }
.fsk-nature .ns-mass-tone { fill: var(--reef-teal); opacity: .35; }
/* 2026-08-07 audit: base opacity was 0, so with no JS or under reduced-motion the scene's only
   brand linework never appeared and the band read as a flat silhouette. This file's own
   convention is that the base state is the FINISHED frame (see .ns-spill directly below, and
   .fsk-refill-loop), and .fsk-motion-js overrides it to animate in. Rest state now matches the
   gust's drawn value; the animated path is untouched. */
.fsk-nature .ns-breeze { stroke: var(--color-brand); stroke-width: 4; fill: none; stroke-linecap: round; opacity: .45; }
.fsk-nature .ns-bloom { opacity: 1; }
.fsk-nature .ns-spill { opacity: .32; }
.fsk-nature .ns-ground { stroke: var(--color-text); stroke-width: 5; fill: none; stroke-linecap: round; opacity: .6; }
[data-theme="dark"] .fsk-nature .ns-arch { fill: var(--mintair-06); }
[data-theme="dark"] .fsk-nature .ns-mass-tone { opacity: .2; }

/* JS-driven (scaffold above). Each rule sets the start-state + keyframe; the element's
   data-r="start end" in fsk-powered-by-nature.liquid sets when it plays. Ranges preserve
   the ruled sequence: bloom -> breeze -> mass settles -> spill. */
.fsk-motion-js .fsk-nature .ns-bloom { opacity: .25; animation-name: fsknat-bloom; }
.fsk-motion-js .fsk-nature .ns-breeze { stroke-dasharray: 100 100; stroke-dashoffset: 100; animation-name: fsknat-gust; }
.fsk-motion-js .fsk-nature .ns-mass-g { animation-name: fsknat-settle; }
.fsk-motion-js .fsk-nature .ns-spill { opacity: 0; animation-name: fsknat-spill; }
@keyframes fsknat-bloom { to { opacity: 1; } }
@keyframes fsknat-gust {
  0% { stroke-dashoffset: 100; opacity: 0; }
  12% { opacity: .6; }
  48% { stroke-dashoffset: 0; opacity: .6; }
  85% { stroke-dashoffset: -100; opacity: .45; }
  100% { stroke-dashoffset: -100; opacity: 0; }
}
@keyframes fsknat-settle { from { translate: 0 -2px; } to { translate: 0 0; } }
@keyframes fsknat-spill { 0% { opacity: 0; } 70% { opacity: .40; } 100% { opacity: .32; } }

/* ===================== Timeline of Benefits (PF-13 slot 9, candidate A "drawn path") =====================
   Haze band, no wave seams (ruled). Disc fill is pinned to --white/--night-surface rather than
   --color-surface-raised: that token resolves to night-surface in dark and an Ink Navy glyph on it
   would go near-black-on-near-black -- the same failure mode PF-15 caught on the sourcing band, closed
   here before it could ship. The "on" disc fills Reef Teal with an Ink Navy glyph, ~9.2:1 either theme,
   because the disc carries its own ground rather than the band's. */
:root { --fsk-tl-disc-fill: var(--white); --fsk-tl-rail: var(--ink-13); }
[data-theme="dark"] { --fsk-tl-disc-fill: var(--night-surface); --fsk-tl-rail: var(--mintair-16); }

/* .fsk-tl__stage carries data-fsk-scroll in the Liquid = the JS scroll-driver root. */
.fsk-tl__path { position: relative; height: clamp(150px, 17vw, 200px); }
.fsk-tl__path svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.fsk-tl__line { fill: none; stroke: var(--color-brand); stroke-width: 3; stroke-linecap: round; }
.fsk-tl__line--ghost { stroke: var(--fsk-tl-rail); stroke-width: 2; }
.fsk-tl__nodes { position: absolute; inset: 0; }
/* Pinned to the path's three flat waypoints so each disc sits ON the drawn line at every
   scroll state and width, rather than floating beside it at a fixed vertical centre (the
   rejected state Andrew caught: "the icons would have to actually be on those waves").
   viewBox is stretched with preserveAspectRatio="none" on the path svg, so these percentages
   map straight to it. Binding geometry -- do not adjust without re-verifying against the path. */
.fsk-tl__node { position: absolute; top: auto; transform: translate(-50%, -50%); }
.fsk-tl__node:nth-child(1) { left: 16.7%; top: 28.9%; }
.fsk-tl__node:nth-child(2) { left: 50%;   top: 72.2%; }
.fsk-tl__node:nth-child(3) { left: 83.3%; top: 32.2%; }
.fsk-tl__beats { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 2.6vw, 32px); margin-top: var(--space-5); }
.fsk-tl__beat { display: grid; gap: var(--space-2); align-content: start; }
.fsk-tl__mdisc { display: none; }
@media screen and (max-width: 749px) {
  .fsk-tl__path { display: none; }
  .fsk-tl__beats { grid-template-columns: 1fr; gap: var(--space-6); }
  .fsk-tl__beat { grid-template-columns: 44px 1fr; grid-template-areas: "d l" "d t" "d b"; column-gap: var(--space-4); }
  .fsk-tl__mdisc { grid-area: d; display: block; }
  .fsk-tl__beat .fsk-tl__label { grid-area: l; } .fsk-tl__beat .fsk-tl__title { grid-area: t; } .fsk-tl__beat .fsk-tl__body { grid-area: b; }
}
.fsk-tl__disc { width: 44px; height: 44px; flex: none; border-radius: var(--radius-dot);
  background: var(--fsk-tl-disc-fill); border: var(--border-stroke) solid var(--color-brand);
  display: grid; place-items: center; color: var(--color-text); }
.fsk-tl__disc svg { width: 21px; height: 21px; }
.fsk-tl__disc--on { background: var(--color-brand); color: var(--ink-navy); }
.fsk-tl__label { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-text-muted); }
.fsk-tl__title { font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 600; font-size: clamp(1.15rem, 1.9vw, 1.4rem); line-height: 1.2; color: var(--color-heading); }
.fsk-tl__body { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.6; color: var(--color-text-muted); }
.fsk-tl__body p { margin: 0; }
.fsk-tl__close { margin-top: clamp(28px, 4vw, 44px); padding-top: var(--space-5);
  border-top: var(--border-hairline) solid var(--fsk-tl-rail); max-width: 62ch; }
.fsk-tl__close .fsk-p { font-size: 1.05rem; }

/* Motion is distance-keyed (vh off `cover`), not fraction-keyed, so the draw takes the same
   physical scroll distance regardless of band height or total page length
   (memory reference_scroll_motion_page_length). Base CSS above is the finished frame; this
   block only adds the start states, so reduced-motion and no-view()-support browsers both
   land on the finished frame with nothing extra to maintain -- the established refill-loop
   pattern (.fsk-refill-loop above). */
/* JS-driven (shared scaffold). Base above = finished frame (path drawn, discs/beats in place);
   data-r ranges live in fsk-timeline.liquid, staggered so beat 1 -> 2 -> 3 reveal in order. */
.fsk-motion-js .fsk-tl__line--draw { stroke-dasharray: 100; stroke-dashoffset: 100; animation-name: fsk-tl-draw; }
.fsk-motion-js .fsk-tl__node .fsk-tl__disc { opacity: 0; animation-name: fsk-tl-pop; }
.fsk-motion-js .fsk-tl__beat { opacity: 0; animation-name: fsk-tl-rise; }
@keyframes fsk-tl-draw { to { stroke-dashoffset: 0; } }
@keyframes fsk-tl-rise { from { opacity: 0; translate: 0 10px; } to { opacity: 1; translate: 0 0; } }
@keyframes fsk-tl-pop  { from { opacity: 0; scale: 0.7; } to { opacity: 1; scale: 1; } }

/* ===================== Heritage timeline (Meet the Farmer; plan 2026-07-24, candidate B) =====================
   Single vertical spine, chronological, Farm/Method chips, draws top-to-bottom on scroll. Reuses the
   global scroll driver + the `.fsk-motion-js [data-r]` scaffold above; base here is the finished frame.
   Distinct namespace (.fsk-hrt__) from the PDP `.fsk-tl__` benefits timeline. Rail colors reuse the
   --fsk-tl-disc-fill / --fsk-tl-rail vars. Section: sections/fsk-heritage.liquid. */
.fsk-hrt { position: relative; --hrt-tail: 274px; }
/* PF-56: the rail draw is its own scene (absolute, full height) so it draws across the whole
   timeline, while each NODE is its own scroll scene (data-fsk-scroll on the node) so cards reveal
   by center. `.fsk-hrt` itself carries NO data-fsk-scroll. */
.fsk-hrt__spine { position: absolute; inset: 0; pointer-events: none; }
/* `--hrt-tail` ends the rail AT the road-ahead disc instead of running past it into the capstone
   card (Andrew 2026-07-26). Measured: ahead disc sits ~266px (desktop) / ~277px (mobile) above the
   .fsk-hrt bottom; if the road-ahead copy length changes, re-measure and retune the var. */
.fsk-hrt__line { position: absolute; left: 21px; top: 14px; bottom: var(--hrt-tail, 14px); width: 2px; background: var(--fsk-tl-rail); border-radius: 2px; }
.fsk-hrt__draw { position: absolute; left: 20px; top: 14px; width: 4px; bottom: var(--hrt-tail, 14px); height: auto;
  background: var(--color-brand); border-radius: 2px; transform-origin: top center; transform: scaleY(1); }
.fsk-hrt__nodes { display: grid; gap: clamp(28px, 4vw, 44px); }
.fsk-hrt__node { position: relative; display: grid; grid-template-columns: 44px 1fr; gap: clamp(16px, 2.5vw, 28px); align-items: start; }
.fsk-hrt__disc { width: 44px; height: 44px; border-radius: var(--radius-dot); background: var(--color-brand);
  color: var(--ink-navy); border: var(--border-stroke) solid var(--color-brand); display: grid; place-items: center; z-index: 1; }
.fsk-hrt__disc svg { width: 21px; height: 21px; }
.fsk-hrt__card { display: grid; gap: var(--space-2); align-content: start; padding-top: 2px; }
.fsk-hrt__meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Date is TEXT, so it must never be Reef Teal (§0.2; Fable audit P0-2 2026-07-24 caught the
   original --color-brand here at ~1.6:1 on Mint Air). Muted ink, 5.3:1. */
.fsk-hrt__date { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-text-muted); }
/* Innovation kicker: the SEO-bearing name of the milestone. Deep Blue in light; in dark it must NOT
   ride --color-link (Amber) or all 8 kickers flood the section amber and kill the Farm/Method
   color coding (Fable P1-7) — plain text color instead, Amber stays with the method dots. */
.fsk-hrt__kick { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-link); }
[data-theme="dark"] .fsk-hrt__kick { color: var(--color-text); }
.fsk-hrt__chip { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-body); font-size: var(--text-micro);
  font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-text-muted);
  padding: 3px 10px 3px 8px; border: var(--border-hairline) solid var(--fsk-tl-rail); border-radius: 999px; background: var(--fsk-tl-disc-fill); }
.fsk-hrt__dot { width: 8px; height: 8px; border-radius: 50%; }
.fsk-hrt__dot--farm { background: var(--reef-teal); }
.fsk-hrt__dot--method { background: var(--amber); }
.fsk-hrt__dot--community { background: var(--deep-blue); }
/* Amber-as-text fails on light haze (~1.6:1) — flag rides an Amber chip with Ink Navy label (9.5:1). */
.fsk-hrt__flag { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800; letter-spacing: 0.06em;
  color: var(--ink-navy); background: var(--amber); padding: 2px 10px; border-radius: 999px; text-transform: uppercase; }
.fsk-hrt__title { font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 600; font-size: clamp(1.2rem, 2vw, 1.5rem); line-height: 1.2; color: var(--color-heading); }
.fsk-hrt__body { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.62; color: var(--color-text-muted); }
.fsk-hrt__body p { margin: 0; }
/* Desktop ≥750px: CENTER spine, Farm cards LEFT / Method cards RIGHT (Andrew 2026-07-24, PF-51).
   Base above stays the mobile/no-media single left rail. Farm cards anchor right against the spine
   (meta/kicker/title right-aligned) but BODY text stays left-aligned — ragged-left paragraphs at
   ~7 lines are a readability tax (Fable P1-1). */
@media screen and (min-width: 750px) {
  .fsk-hrt { --hrt-tail: 264px; }
  .fsk-hrt__line { left: 50%; margin-left: -1px; }
  .fsk-hrt__draw { left: 50%; margin-left: -2px; }
  .fsk-hrt__node { grid-template-columns: 1fr 44px 1fr; gap: 0 clamp(20px, 3vw, 36px); }
  .fsk-hrt__disc { grid-column: 2; justify-self: center; }
  :is(.fsk-hrt__node--farm, .fsk-hrt__node--community) .fsk-hrt__card { grid-column: 1; grid-row: 1; justify-self: end; text-align: right; }
  :is(.fsk-hrt__node--farm, .fsk-hrt__node--community) .fsk-hrt__meta { justify-content: flex-end; }
  :is(.fsk-hrt__node--farm, .fsk-hrt__node--community) .fsk-hrt__body { margin-left: auto; text-align: left; }
  .fsk-hrt__node--method .fsk-hrt__card { grid-column: 3; grid-row: 1; justify-self: start; text-align: left; }
  /* Forward-looking capstone (track "ahead"): centered on the spine, spans both sides. */
  .fsk-hrt__node--ahead { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .fsk-hrt__node--ahead .fsk-hrt__disc { grid-column: 1; justify-self: center; }
  .fsk-hrt__node--ahead .fsk-hrt__card { grid-column: 1; max-width: 600px; text-align: center; }
  .fsk-hrt__node--ahead .fsk-hrt__meta { justify-content: center; }
  .fsk-hrt__node--ahead .fsk-hrt__body { margin-inline: auto; text-align: center; max-width: 56ch; }
}
.fsk-hrt__close { margin: clamp(32px, 5vw, 52px) auto 0; padding-top: var(--space-5);
  border-top: var(--border-hairline) solid var(--fsk-tl-rail); max-width: 64ch; text-align: center;
  font-family: var(--font-body); font-size: 1.05rem; line-height: var(--leading-body); color: var(--color-text); }
.fsk-hrt__close p { margin: 0; }
.fsk-hrt__foot { margin-top: var(--space-6); font-size: 12px; color: var(--color-text-muted); text-align: center; opacity: 0.8; }
/* Motion: base above = finished frame; the global `.fsk-motion-js [data-r]` scaffold supplies the paused
   1s animation and the driver scrubs it via animation-delay; these rules add the start states + names. */
.fsk-motion-js .fsk-hrt__draw { transform: scaleY(0); animation-name: fsk-hrt-draw; }
.fsk-motion-js .fsk-hrt__disc { opacity: 0; animation-name: fsk-hrt-pop; }
.fsk-motion-js .fsk-hrt__card { opacity: 0; animation-name: fsk-hrt-rise; }
@keyframes fsk-hrt-draw { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes fsk-hrt-pop  { from { opacity: 0; scale: 0.7; } to { opacity: 1; scale: 1; } }
@keyframes fsk-hrt-rise { from { opacity: 0; translate: 0 10px; } to { opacity: 1; translate: 0 0; } }

/* ===================== Use Cases (PF-13 slot 8, candidate A "the day rail") =====================
   Compact PDP-native rhythm, same padding as the ruled sourcing band. Mint Surface ground is
   load-bearing (PF-21): it breaks what would otherwise be a fsk_bio -> fsk_timeline -> fsk_routine
   triple-haze stretch (both are bare .fsk-band--haze; Timeline is ruled haze/no-seams per
   PF-20). Rail runs from disc to disc, never
   past the last one. Ruled usage glyphs default their duotone accent to Amber; three Amber
   glyphs in one rail would blow the one-accent-per-composition rule, so the glyph accent is
   remapped to Reef Teal and the band's single Amber is spent on the "First thing" marker
   instead -- see .fsk-uc__when--key below. */
.fsk-uc__band { padding-block: clamp(40px, 5.5vw, 68px); }

.fsk-uc__rail { position: relative; max-width: 44rem; margin-inline: auto; }
.fsk-uc__moment { position: relative; display: grid; grid-template-columns: 56px 1fr; gap: var(--space-5);
  align-items: start; padding-bottom: var(--space-7); }
.fsk-uc__moment:last-child { padding-bottom: 0; }
.fsk-uc__moment:not(:last-child)::before { content: ""; position: absolute; left: 27px; top: 60px; bottom: 8px;
  width: 2px; background: var(--ink-25); }
[data-theme="dark"] .fsk-uc__moment:not(:last-child)::before { background: var(--mintair-28); }

.fsk-uc__disc { flex: none; display: grid; place-items: center; width: 56px; height: 56px; padding: 12px;
  border-radius: 50% 50% 50% 22%; background: var(--mint-air); box-shadow: var(--shadow-card); }
[data-theme="dark"] .fsk-uc__disc { background: var(--mintair-10); box-shadow: none; }
.fsk-uc__glyph { --fsk-glyph-accent: var(--reef-teal); display: block; width: 100%; height: 100%; color: var(--ink-navy); }
[data-theme="dark"] .fsk-uc__glyph { color: var(--mint-air); }

.fsk-uc__body { display: grid; gap: var(--space-2); padding-top: var(--space-1); }

/* the time marker: the temporal carrier that makes this band "when", not "what". justify-self
   is load-bearing -- without it the Amber marker stretches the full grid cell into a block-scale
   yellow bar, the exact discount-retail read PF-5 bans. Caught only by render, not by any gate. */
.fsk-uc__when { display: inline-block; justify-self: start; font-family: var(--font-body); font-size: var(--text-micro);
  font-weight: 800; letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-text-muted); }
.fsk-uc__when--key { background: var(--amber); color: var(--ink-navy); padding: 4px 10px;
  border-radius: var(--radius-seed-badge); letter-spacing: var(--tracking-badge); }
.fsk-uc__title { font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 600; font-size: 1.22rem; line-height: 1.25; color: var(--color-heading); }
.fsk-uc__detail { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.6; opacity: 0.84; max-width: 46ch; }

/* ============================================================
   COMPARISON MATRIX (PF-13 slot 12, PF-23/24/25 · sections/fsk-comparison.liquid)
   Candidate C "hairline ledger", ruled 2026-07-20. A real semantic <table> on the
   Tidewater hairline chassis -- the master pack's own ruled exception for data
   surfaces (master-pack/DIRECTION.md:53-54, "hairline-chassis survives only inside
   data surfaces, where precision outranks warmth"). Band-local token pair: "ours" =
   raised + mint/teal led, "theirs" = quiet, on the ground, no card. Scoped to .fsk-cmp
   (not :root) so nothing leaks outside this band.
   ============================================================ */
.fsk-cmp {
  --fsk-cmp-ours-fill: color-mix(in srgb, var(--mint-surface) 82%, var(--white));
  --fsk-cmp-ours-rail: var(--reef-teal);
  --fsk-cmp-ours-mark: var(--reef-teal);
  /* the category column needs a faint neutral scrim, not transparency: on bare haze it
     caught the Citrus fog pool and came out washed yellow, reading as a deliberate
     highlight (Citrus is a highlight token, §0.2) -- render-caught, not gate-caught. */
  --fsk-cmp-theirs-fill: color-mix(in srgb, var(--mint-air) 80%, transparent);
  --fsk-cmp-rule: var(--ink-13);
  --fsk-cmp-rule-strong: var(--ink-25);
}
[data-theme="dark"] .fsk-cmp {
  /* the FSK column keeps its teal identity as a WASH over the night surface, never a
     Reef Teal slab (PF-16's lesson, applied to a card instead of a band). */
  --fsk-cmp-ours-fill: color-mix(in srgb, var(--reef-teal) 12%, var(--night-surface));
  --fsk-cmp-ours-rail: var(--reef-teal);
  --fsk-cmp-ours-mark: var(--reef-teal);
  --fsk-cmp-theirs-fill: color-mix(in srgb, var(--night-surface) 55%, transparent);
  --fsk-cmp-rule: var(--mintair-16);
  --fsk-cmp-rule-strong: var(--mintair-28);
}

/* PDP-native rhythm: an objection-defeat band runs SHORT, it is not a story band. */
.fsk-cmp__band { padding-block: clamp(40px, 5.5vw, 68px); }

.fsk-cmp__head { font-family: var(--font-body); font-weight: 800; font-size: var(--text-body); line-height: 1.3; }
.fsk-cmp__head-sub { display: block; font-weight: 600; font-size: var(--text-micro); letter-spacing: var(--tracking-badge);
  text-transform: uppercase; color: var(--color-text-muted); margin-top: 4px; }
.fsk-cmp__axis { font-family: var(--font-body); font-weight: 800; font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--color-text-muted); }
.fsk-cmp__cell { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.55; }
.fsk-cmp__cell--ours { font-weight: 600; }
.fsk-cmp__cell--theirs { color: var(--color-text-muted); }

/* the ours-mark: a small teal seed-dot check (Tier-1 chrome glyph, fsk-ic-check). No
   counterpart mark on the category column -- an X, red or otherwise, would turn a
   factual contrast into a shame column (§0.2 status-without-red). */
.fsk-cmp__mark { flex: none; width: 19px; height: 19px; margin-top: 2px; color: var(--fsk-cmp-ours-mark); }
.fsk-cmp__mark svg { display: block; width: 100%; height: 100%; }

/* closer strip: affirmative FSK-only, no counterpart cell -- "who made it" had no
   defensible right-hand cell, so it left the grid for here instead. */
.fsk-cmp__closer { display: flex; gap: var(--space-4); align-items: flex-start;
  margin-top: var(--space-6); padding-top: var(--space-5); border-top: var(--border-hairline) solid var(--fsk-cmp-rule-strong); }
.fsk-cmp__closer-mark { flex: none; width: 26px; height: 26px; color: var(--fsk-cmp-ours-mark); margin-top: 1px; }
.fsk-cmp__closer-mark svg { display: block; width: 100%; height: 100%; }
.fsk-cmp__closer-text { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.6; max-width: 70ch; }
.fsk-cmp__closer-text strong { font-weight: 800; }

.fsk-cmp__shell { position: relative; }
.fsk-cmp__scroll { overflow-x: auto; -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-seed-card); background: var(--color-surface-raised); box-shadow: var(--shadow-card); }
/* RULED 2026-07-20: this band sits on a Mint Surface band. In dark, --color-surface-raised
   and --color-surface resolve to the SAME night-surface, so a raised card here would vanish
   into its own ground (same trap PF-15 hit with discs on the teal band). The card takes a
   lifted surface instead. Fable critique 2026-07-20: the lift was first applied to only
   .fsk-cmp__scroll and .fsk-cmp__axiscol, leaving .fsk-cmp__theirscol at the unlifted
   surface color -- it composited to within ~7 values of the page ground, so the one column
   the section exists to show lost its boundary. All three now share the lift. */
[data-theme="dark"] .fsk-cmp__scroll,
[data-theme="dark"] .fsk-cmp__table .fsk-cmp__axiscol,
[data-theme="dark"] .fsk-cmp__table .fsk-cmp__theirscol { background: color-mix(in srgb, var(--mint-air) 7%, var(--night-surface)); }

.fsk-cmp__table { border-collapse: collapse; width: 100%; min-width: 640px; }
.fsk-cmp__table th, .fsk-cmp__table td { text-align: left; vertical-align: top; padding: var(--space-4) var(--space-5); }
.fsk-cmp__table thead th { padding-top: var(--space-5); padding-bottom: var(--space-4); }
.fsk-cmp__table tbody tr { border-top: var(--border-hairline) solid var(--fsk-cmp-rule); }
.fsk-cmp__table .fsk-cmp__axiscol { background: var(--color-surface-raised); min-width: 190px; width: 190px; }
/* keep the two comparison columns even so neither side reads as squeezed */
.fsk-cmp__table .fsk-cmp__ourscol, .fsk-cmp__table .fsk-cmp__theirscol { width: calc((100% - 190px) / 2); }
/* ours column: full-height mint wash + teal crest on the header cell */
.fsk-cmp__table .fsk-cmp__ourscol { background: var(--fsk-cmp-ours-fill); }
.fsk-cmp__table thead .fsk-cmp__ourscol { border-top: var(--border-stroke) solid var(--fsk-cmp-ours-rail); }
.fsk-cmp__table .fsk-cmp__theirscol { background: var(--fsk-cmp-theirs-fill); }
.fsk-cmp__cellbody { display: flex; gap: var(--space-3); align-items: flex-start; }

/* on mobile the table STAYS a table, it does not scroll (PF-25). A horizontally-scrolling
   variant was built and rejected on its own proof: at rest the entire "generic powders"
   column sat off-screen, so the comparison the section exists to make was invisible until
   the user swiped, and the pinned axis column leaked orphaned word fragments of the column
   sliding under it. Instead the row label spans the full width and the two comparison
   columns split it 50/50, so both sides stay on screen together at every width. */
@media (max-width: 749px) {
  .fsk-cmp__scroll { overflow-x: visible; }
  .fsk-cmp__table { min-width: 0; }
  .fsk-cmp__table thead tr, .fsk-cmp__table tbody tr { display: grid; grid-template-columns: 1fr 1fr; }
  .fsk-cmp__table thead .fsk-cmp__axiscol { display: none; }
  .fsk-cmp__table tbody .fsk-cmp__axiscol { grid-column: 1 / -1; width: auto; min-width: 0;
    padding-bottom: var(--space-2); background: transparent; }
  .fsk-cmp__table th, .fsk-cmp__table td { padding: var(--space-3) var(--space-4); }
  .fsk-cmp__table thead th { padding-top: var(--space-4); }
  .fsk-cmp__table .fsk-cmp__ourscol, .fsk-cmp__table .fsk-cmp__theirscol { width: auto; }
  .fsk-cmp__table thead .fsk-cmp__ourscol { border-top: var(--border-stroke) solid var(--fsk-cmp-ours-rail); }
  /* fable critique 2026-07-20: on "Extracted or ground" ours runs several lines against
     theirs' one line; both cells stretch to the row's tallest content (grid default),
     top-pinning the short cell and leaving a dead pale rectangle under it. Centering the
     content instead makes the leftover space read as breathing room, not a gap. */
  .fsk-cmp__table tbody td { display: flex; align-items: center; }
}

/* ============================================================
   WHAT'S INSIDE (PF-13 slot 7, PF-17/PF-26 · sections/fsk-whats-inside.liquid)
   Candidate C "panel-led split", RULED 2026-07-20 (Andrew, on whats-inside-mock/
   candidates.html: "I agree, C is the winner here"). Teal band (ground proposed
   not ruled -- the slot-5/slot-7 teal-gap-teal question rides to the PF-18
   ordering pass, not settled here). Left column = the regulated Supplement
   Facts panel as a real document, typeset in these tokens, plus a label-photo
   proof slot. Right column = the same ingredients said in plain language, one
   line each on why it earns its place. No outer card -- the panel is allowed
   to be the only white object in the band, which is what keeps it reading as
   a document rather than another content module. Mobile order is deliberate:
   the selling column comes first, the documents follow.
   ============================================================ */
.wi-band { padding-block: clamp(40px, 5.5vw, 68px); }

.fsk-wi__grid { display: grid; grid-template-columns: minmax(0,0.92fr) minmax(0,1.08fr);
  gap: clamp(26px, 4vw, 56px); align-items: start; margin-top: clamp(28px,4vw,44px); }
.fsk-wi__docs { display: grid; gap: var(--space-4); }

/* the document surface. Light = raised white, the register a regulated panel
   wants (--color-surface-raised already resolves to white at :root). Dark:
   --color-surface-raised only lifts inside .fsk-band--surface (PF-23's ruled
   remedy); on THIS teal ground it would stay flat night-surface while the
   band itself is a teal-tinted wash, and the panel would sink below its own
   ground -- PF-26's finding, the same class of defect one ground family over.
   Lifted here out of the band's OWN dark value instead (--color-inverse-bg,
   already PF-16's ruled reef-teal/night-surface mix), which reproduces PF-26's
   ruled mint-air-12%-on-band formula exactly (verified 1.44 panel:band ratio
   by pixel probe in the mock's render-proofs.mjs). Scoped to this band only,
   never :root, so nothing leaks to other teal bands that don't carry a card. */
.fsk-wi { --fsk-wi-doc-fill: var(--color-surface-raised); }
[data-theme="dark"] [data-block="teal"].fsk-wi {
  --fsk-wi-doc-fill: color-mix(in srgb, var(--mint-air) 12%, var(--color-inverse-bg));
}
.fsk-wi__sf { background: var(--fsk-wi-doc-fill); border: var(--border-hairline) solid var(--color-border-strong);
  border-radius: var(--radius-sm); padding: var(--space-4) var(--space-5) var(--space-5);
  box-shadow: var(--shadow-card); color: var(--color-text); }
.fsk-wi__sf-title { font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-weight: 700; font-size: clamp(1.35rem,2.4vw,1.7rem); line-height: 1.1; letter-spacing: -0.01em; }
.fsk-wi__sf-bar { height: 8px; background: var(--color-heading); margin-top: var(--space-2); }
.fsk-wi__sf-bar--thin { height: 3px; margin-top: 0; }
.fsk-wi__sf-line { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.5;
  display: flex; justify-content: space-between; gap: var(--space-3); padding-block: 5px; }
.fsk-wi__sf-line--rule { border-bottom: var(--border-hairline) solid var(--color-border-strong); }
.fsk-wi__sf-colhead { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 800;
  text-align: right; padding-block: 4px; }
.fsk-wi__sf-row { display: grid; grid-template-columns: 1fr auto; gap: var(--space-3);
  align-items: baseline; padding-block: 7px; border-bottom: var(--border-hairline) solid var(--color-border-strong);
  font-family: var(--font-body); font-size: var(--text-small); line-height: 1.45; }
.fsk-wi__sf-amt { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 3.4em; text-align: right; }
.fsk-wi__sf-foot { font-family: var(--font-body); font-size: var(--text-micro); line-height: 1.5;
  color: var(--color-text-muted); margin-top: var(--space-3); }
.fsk-wi__sf-other { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.55;
  margin-top: var(--space-3); padding-top: var(--space-3); border-top: var(--border-stroke) solid var(--color-heading); }
.fsk-wi__sf-other b { font-weight: 800; }

/* the label-photo proof slot. Capped 1:1 / 300px: at 4:5 unbounded it towered
   over its column and opened a dead field of teal (render-caught in the mock,
   not gate-caught). Missing-asset policy (DESIGN-DIRECTION §0.4): never a
   stock stand-in, never a grey box shipped live -- an explicitly dashed,
   honestly-labelled slot is the correct state until Andrew's photo lands. */
.fsk-wi__shot { display: block; width: 100%; max-width: 300px; aspect-ratio: 1/1; border-radius: var(--radius-sm);
  object-fit: cover; box-shadow: var(--shadow-card); }
/* .fsk-wi__shot--pending / __shot-k / __shot-n removed 2026-08-06 with the
   show_label_placeholder toggle; the band renders the typeset panel alone when
   no label photo is set. */
.fsk-wi__cap { font-family: var(--font-body); font-size: var(--text-micro); line-height: 1.55; color: inherit; opacity: 0.72; margin-top: var(--space-3); }

/* the plain-language column sits directly on the teal band, so its text takes
   the band's own inherited colour (--color-inverse-text via .fsk-band--dark);
   muted lines use opacity on that inherited colour rather than
   --color-text-muted (unset at the teal block level) -- the same idiom
   fsk-sourcing.liquid uses for .fsk-src__step-detail. */
.fsk-wi__copy { display: flex; flex-direction: column; }
.fsk-wi__list { display: grid; }
.fsk-wi__item { padding-block: var(--space-5); }
.fsk-wi__item + .fsk-wi__item { border-top: var(--border-hairline) solid var(--color-border-strong); }
.fsk-wi__item:first-child { padding-top: 0; }
.fsk-wi__kicker { display: flex; align-items: baseline; gap: var(--space-3); }
.fsk-wi__num { font-family: var(--font-body); font-weight: 800; font-size: var(--text-micro);
  letter-spacing: var(--tracking-eyebrow); opacity: 0.72; }
.fsk-wi__name { font-family: var(--font-body); font-weight: 800; font-size: var(--text-body);
  line-height: 1.3; letter-spacing: var(--tracking-badge); }
.fsk-wi__why { font-family: var(--font-body); font-size: var(--text-small); line-height: 1.6;
  opacity: 0.82; margin-top: 6px; max-width: 56ch; }
.fsk-wi__footnote { font-family: var(--font-body); font-size: var(--text-micro); line-height: 1.5; opacity: 0.72; margin-top: var(--space-4); }
/* pins the serving line to the column's bottom edge so the copy column
   finishes level with the documents column instead of leaving a dead field
   under it -- a white card on a saturated ground makes every empty pixel
   visible (the same balancing move the mock applied to both other candidates). */
.fsk-wi__serving { margin-top: auto; padding-top: var(--space-4); border-top: var(--border-stroke) solid var(--color-border-strong); }
.fsk-wi__serving .fsk-p { opacity: 0.9; }

@media (max-width: 849px) {
  .fsk-wi__grid { grid-template-columns: 1fr; }
  .fsk-wi__docs { order: 2; }
  .fsk-wi__copy { order: 1; }
  .fsk-wi__serving { margin-top: var(--space-5); }
}

/* ============================================================
   CART · Free-shipping progress bar (.fsk-shipbar)
   DESIGN-DIRECTION §8 A8 + critique fix P1-1: Deep-Blue fill (--color-accent)
   on a Mint-Surface track (--color-surface); the text line is the primary carrier.
   Rendered in the cart drawer + cart page (snippets/fsk-shipbar.liquid). The
   --color-accent token gives Deep Blue in light and Amber in dark -- both legible
   on their track. The inset hairline keeps the track defined on any drawer ground.
   ============================================================ */
.fsk-shipbar {
  display: grid;
  gap: var(--space-2);
  padding-block: var(--space-4);
  font-family: var(--font-body);
}
.fsk-shipbar__label {
  margin: 0;
  font-size: var(--text-small);
  font-weight: 700;
  line-height: 1.35;
  color: var(--color-text);
}
.fsk-shipbar__label strong { font-weight: 800; }
.fsk-shipbar__check {
  color: var(--color-accent);
  font-weight: 900;
}
.fsk-shipbar__track {
  position: relative;
  height: 10px;
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  box-shadow: inset 0 0 0 1px var(--color-border);
  overflow: hidden;
}
.fsk-shipbar__fill {
  position: absolute;
  inset: 0 auto 0 0;
  min-width: 10px;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  transition: width var(--motion-slow) var(--ease-out);
}
.fsk-shipbar.is-unlocked .fsk-shipbar__fill { width: 100%; }
@media (prefers-reduced-motion: reduce) {
  .fsk-shipbar__fill { transition: none; }
}

/* ---------------------------------------------------------------------------
   NATIVE SHOPIFY POLICY PAGES (/policies/*)  -- P-06, SONNET5-PAGEBUILD-CHECKLIST
   These pages are Shopify-rendered: no theme template, no section, so section-scoped
   {% stylesheet %} cannot reach them. Horizon ships only
   `.shopify-policy__container { padding-block: var(--padding-xl); }` (base.css), i.e. NO
   max-width and NO inline padding, so the legal text runs edge to edge of the viewport on
   desktop. This block is the FSK reading layer for them: same 68ch measure and token
   typography as the /pages/policies index (DESIGN-DIRECTION s8 A8 "Policies page").
   NEW selectors only -- no existing FSK component base is modified. Dark mode follows for
   free because everything here consumes tokens.
   --------------------------------------------------------------------------- */
.shopify-policy__container {
  max-width: 68ch;
  margin-inline: auto;
  padding-inline: var(--page-margin, 16px);
  padding-block: var(--padding-xl, var(--space-8));
}
.shopify-policy__title h1 {
  font-family: var(--font-display);
  font-variation-settings: var(--font-display-settings);
  font-size: clamp(1.8rem, 4vw, 2.7rem);
  line-height: 1.15;
  color: var(--color-heading);
}
.shopify-policy__body {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--color-text);
}
.shopify-policy__body :is(h2, h3, h4) {
  font-family: var(--font-display);
  font-variation-settings: var(--font-display-settings);
  color: var(--color-heading);
  line-height: 1.25;
}
/* Explicit sizes: Horizon's heading scale is Liquid-generated, so a policy page that loads
   before those vars resolve would otherwise render sub-heads at body size. */
.shopify-policy__body h2 { font-size: clamp(1.3rem, 2.6vw, 1.7rem); }
.shopify-policy__body h3 { font-size: 1.15rem; }
.shopify-policy__body h4 { font-size: 1rem; }
.shopify-policy__body a {
  color: var(--color-link);
  font-weight: 700;
}

/* cdn-unstick 2026-08-04: forced version bump; the CDN served persistent 502/504 on the prior version of this file while base.css served fine. No style changes in this edit. */

/* ── Appstle duplicate purchase widget, hidden 2026-08-06 (Andrew ruled: hide with CSS, keep the
   app running) ────────────────────────────────────────────────────────────────────────────────
   Every product page rendered TWO subscription pickers: the designed buy box
   (blocks/fsk-purchase-options.liquid) and, directly beneath it, Appstle's own widget. They
   disagreed about which option was selected, and the app one carried a "SAVE 15%" badge, which
   cuts against the anti-discount rule.

   Why hide rather than disable the app embed: the embed is Appstle's whole script and may also
   power the subscriber portal, cancellation flow and emails. Turning it off to fix a visual
   duplicate would risk machinery that is not visible from the theme.

   Safe because the buy box does not depend on this DOM: it reads product.selling_plan_groups in
   Liquid, server-side, and syncs its own hidden `selling_plan` input into the product form. The
   only "appstle" string in that block is a word in a comment. Subscriptions are native Shopify
   selling plans, so nothing about checkout changes.

   Selectors taken from the app's own widget template embedded in the page markup, not guessed:
     <div id="appstle-widget-template"><div class="appstle_sub_widget" id="appstle_subscription_widget{{widgetId}}">
   Both are targeted so a change to either one does not silently un-hide it. */
.appstle_sub_widget,
[id^="appstle_subscription_widget"],
#appstle-widget-template {
  display: none !important;
}

/* ── 2026-08-07 · FMS strip (Andrew, decision 10b) ───────────────────────────────
   The mycological-society slot was a full-bleed Deep Blue band ~1,000px tall closing the
   homepage, against the A5 rule of one line + one CTA. Now a compact strip: the row sits
   on one line above 700px and stacks below it, and the band's vertical padding drops to
   the house compact value so it reads as a closing note rather than a section. */
/* ⚠️ RETIRED 2026-08-12. Everything from here to the end of this block styled the compact
   "strip" variant of the club section. Andrew reversed that change: "There's supposed to be
   copy. There's supposed to be a group photo club shot. We had this before. Restore it as it
   was." sections/fsk-fms.liquid is back to its pre-2026-08-07 form and no longer carries the
   .fsk-fms--strip or .fsk-fms__row classes, so none of these rules match anything. Kept
   rather than deleted only so the flex-wrap note below stays findable; do not debug them
   against the live section, and do not reintroduce the strip without asking him first. */
.fsk-fms--strip .fsk-band { padding-block: clamp(22px, 3vw, 34px); }
.fsk-fms--strip .fsk-wrap { text-align: left; }
.fsk-fms__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(16px, 3vw, 32px); flex-wrap: wrap;
}
/* 2026-08-12 (Andrew): "that button is way offset." It was not offset — the row was
   breaking. `flex: 1 1 auto` gives the text block a flex-basis of its own max-content, and a
   wrapping flex container decides line breaks from base sizes BEFORE it shrinks anything.
   Measured at 1440: heading base + 32px gap + 341px button came to more than the 740px
   content box, so the text claimed the whole first line and the button dropped to a second
   line — where `justify-content: space-between` has nothing to space it against, so it sat
   hard left under the text and read as a stray offset button. flex-shrink could never fix
   this: shrinking happens within a line, and the item had already been wrapped out of it.
   A small explicit basis keeps both on one line (260 + 32 + 341 = 633), after which the text
   grows into whatever is left. */
.fsk-fms__row > div { flex: 1 1 260px; min-width: 0; }
.fsk-fms__row .fsk-btn { flex: 0 0 auto; }
/* At the narrow wrap (820px, so a 740px box) the heading is then squeezed onto three lines
   beside the button. This strip's own ruling (2026-08-07, decision 10) is that "the line and
   its CTA sit on one row", so it gets the page's standard content width instead of the narrow
   one it inherited from the full-height band it replaced. Scoped to the strip; the .fsk-wrap
   --narrow in the Liquid stays put so nothing else moves. */
.fsk-fms--strip .fsk-wrap--narrow { max-width: 1180px; }
@media (max-width: 700px) {
  .fsk-fms--strip .fsk-wrap { text-align: center; }
  .fsk-fms__row { justify-content: center; text-align: center; }
}

/* ══ 2026-08-07 · FINAL LAUNCH AUDIT · money path + fresh pickup ═══════════════════════════ */

/* money-path 1 · Fresh products must never start a shipping checkout.
   Fresh mushrooms are farmers-market pickup only and are never shipped, and every fresh surface
   now says so. Shopify's dynamic checkout button was contradicting that in the one place it costs
   money: it skips the cart entirely and drops the customer into a shipping checkout, so the
   pickup-only banner three sections up never gets read. The button is emitted by
   blocks/accelerated-checkout.liquid through a `content_for` call inside blocks/buy-buttons.liquid,
   which is Horizon's own file and outside this pass's edit scope, so it is switched off here by
   template instead. `display: none` (not opacity or visibility) is deliberate: the control has to
   leave the hit-test and the tab order, not just the picture.
   The hook is real and verified in the rendered HTML, not assumed — <main> carries
   data-template="product.fresh", "product.fresh-blue-oyster" and "product.fresh-lions-mane" on the
   three fresh templates, and no other template's value begins with "product.fresh".
   Add to cart is untouched: the fresh buy path is still cart then checkout. */
[data-template^="product.fresh"] .accelerated-checkout-block { display: none; }

/* money-path 13 · the back-in-stock panel's heading.
   blocks/fsk-oos-capture.liquid and blocks/fsk-fresh-oos.liquid are the same panel in the same
   slot of the same buy box. Both now open with an h2 (h3 skipped a level under the product H1),
   but only h3 had type here, so the extract one was rendering at the theme's default h2 size
   inside a small panel. `:not([class])` keeps this to bare panel headings — the h2 inside
   sections/fsk-fresh-subscribe.liquid's panel carries .fsk-h .fsk-h--md and must keep it. */
.fsk-panel > h2:not([class]) {
  font-family: var(--font-display); font-variation-settings: var(--font-display-settings);
  font-size: 1.3rem; margin: 0 0 var(--space-4);
}

/* money-path 4 · the collection card's quick-add must not be hit-testable while it is invisible.
   Horizon reveals it on product-card:is(:hover, :focus-within) by animating opacity from 0, but
   left pointer-events: all underneath — so at opacity 0 it is still a live control sitting over
   the top-left corner of every card's photo. On a touch screen wide enough to clear the 750px
   breakpoint (an iPad in landscape is the obvious one) a tap meant for the card can land on a
   button nobody can see. Tying interactivity to the same state that reveals it means the control
   is live exactly when it is visible. Hover and focus still reach it, because both selectors test
   the CARD, and the pointer is over the card whenever it is over the button.
   NOT addressed here, because it is a merchandising choice rather than a defect: the collection
   grid has no add-to-cart control on mobile at all (--quick-add-mobile-display resolves to none). */
@media screen and (min-width: 750px) {
  product-card:not(:hover):not(:focus-within) .quick-add__button { pointer-events: none; }
}

/* ── Market Friends landing page (2026-08-24) ─────────────────────────────────
   Built from the locked market-friends-page/PACK.md. Tokens only, no raw hex.
   Layout goals from PACK §3: the pair buttons must enter view within about 1.5
   viewports at 390px, so bands 1 and 2 stay tight; every buy control reserves its
   own height so the buy path never shifts under a thumb. */

.fsk-mf__number { letter-spacing: -0.01em; }
.fsk-mf__terms {
  font-family: var(--font-body); font-size: var(--text-small);
  color: var(--color-text-muted); margin: var(--space-4) 0 0; max-width: 56ch;
}
.fsk-mf__promise {
  font-family: var(--font-body); font-size: var(--text-small);
  color: var(--color-text-muted); margin: 0; max-width: 62ch;
}
.fsk-mf__shipnote {
  font-family: var(--font-body); line-height: var(--leading-body);
  color: var(--color-text); margin: var(--space-6) 0 0; max-width: 62ch;
}

/* Buy controls. The disabled (pre-A6) state is a real disabled control with a visible
   reason beside it, not a hidden button: the reader is told why, in the booth's own
   register, rather than meeting a dead element. */
.fsk-mfbuy { display: flex; flex-direction: column; gap: var(--space-2); margin: 0; }
.fsk-mfbuy__btn { width: 100%; text-align: center; }
.fsk-mfbuy__sub {
  font-family: var(--font-body); font-size: var(--text-small);
  color: var(--color-text-muted);
}
.fsk-mfbuy--off .fsk-mfbuy__btn { opacity: 0.55; cursor: not-allowed; }
.fsk-mfbuy__sub--off { color: var(--color-text-muted); }

.fsk-mfbuy-stack {
  display: flex; flex-direction: column; gap: var(--space-4);
  margin-top: var(--space-6); max-width: 30rem;
}

/* Single-bottle tiles. Deliberately NOT the stretched-link card: see the markup note in
   sections/fsk-mf-singles.liquid. */
/* Ruled 2026-08-24 (render audit): this grid keeps .fsk-cardgrid's inherited
   justify-content: center, so five tiles wrap three on top and two CENTRED. An earlier
   flex-start override left a gap at the bottom right on a 1440 viewport that read as
   unfinished, and PF-34(c) records the centred wrap as correct-by-design for this component
   rather than a defect to patch. Do not re-introduce flex-start here. */
.fsk-mf__grid { margin-top: var(--space-6); }
  display: flex; flex-direction: column; gap: var(--space-2);
  background: var(--color-surface-raised); color: var(--color-text);
  border-radius: var(--radius-seed-card); box-shadow: var(--shadow-card);
  padding: var(--space-5);
}
  font-family: var(--font-body); font-size: var(--text-small);
  line-height: var(--leading-body); color: var(--color-text-muted);
  margin: 0; flex: 1 1 auto;
}

/* Mechanics rows on a hairline connector (PACK §3, band 5). */
.fsk-mfrows { margin: var(--space-6) 0 0; padding: 0; max-width: 68ch; }
.fsk-mfrow {
  display: grid; grid-template-columns: minmax(9rem, 14rem) 1fr;
  gap: var(--space-4); padding: var(--space-4) 0;
  border-top: 1px solid var(--color-border);
}
.fsk-mfrow:last-child { border-bottom: 1px solid var(--color-border); }
.fsk-mfrow__k {
  font-family: var(--font-body); font-weight: 700; color: var(--color-heading); margin: 0;
}
.fsk-mfrow__v {
  font-family: var(--font-body); line-height: var(--leading-body);
  color: var(--color-text); margin: 0;
}
@media (max-width: 749px) {
  .fsk-mfrow { grid-template-columns: 1fr; gap: var(--space-2); }
  .fsk-mfbuy-stack { max-width: none; }
}


/* ── Market Friends, render-audit fixes F1-F6 (2026-08-24) ───────────────────── */

/* F4: one guard note per button group instead of one per button. */
.fsk-mfbuy__groupnote {
  font-family: var(--font-body); font-size: var(--text-small);
  color: var(--color-text-muted); margin: 0;
}

/* F2a: band 3 is two columns on desktop, copy first, product photograph second. On phones it
   stacks with the photograph ABOVE the copy, so the reader sees the two bottles before the
   commitment. */
/* REMOVED 2026-08-26 with the v0.7 rebuild: the v0.4 two-column .fsk-mfpair grid, whose
   __copy and __media children no longer exist in the markup. It did not just sit there
   harmlessly. The v0.7 section reuses the .fsk-mfpair class name, so it INHERITED this
   grid: at desktop the arc and both cutouts were laid into column one and the two product
   cards squeezed into column two, and the band was visibly broken. Mobile looked correct
   because the old grid collapsed to one column under 900px, which is exactly how a stale
   rule survives a check that only looks at a phone.
   The lesson worth keeping: reusing a class name inherits every rule anyone ever wrote for
   it. Either delete the old rules or pick a new name. */

/* F2b: each tile carries its own product photograph. Fixed aspect box so the grid does not
   reflow as the lazy images arrive under a thumb. */
  aspect-ratio: 4 / 3; overflow: hidden; border-radius: var(--radius-seed-card);
  background: var(--color-surface); margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) var(--space-2);
}

/* F1: single column on phones. The shared .fsk-cardgrid mobile rule builds the homepage's
   one-featured-then-2x2 layout; inherited here it wrapped the buy-button label onto five
   stacked lines at 390px. Scoped modifier, never a base-rule change: seven sections share
   .fsk-cardgrid, and this file's own Also-Try note records that convention. */
@media (max-width: 640px) {
  .fsk-cardgrid.fsk-mf__grid > *,
  .fsk-cardgrid.fsk-mf__grid > :first-child { flex: 1 1 100%; max-width: none; min-width: 0; }
}

/* F5: centre the mechanics block. Rows keep their internal left alignment. */
.fsk-mfworks { max-width: 760px; }
.fsk-mfworks__h { text-align: center; }
.fsk-mfworks .fsk-mfrows { margin-inline: 0; }


/* Market Friends v0.4: the close band's pair block (2026-08-24).
   The page now has one close carrying every control, so the pair gets a compact buy block
   here rather than the full-width treatment band 3 used to give it. */
.fsk-mfpairbuy { display: grid; gap: var(--space-5); align-items: center; margin-top: var(--space-6); }
.fsk-mfpairbuy__media img {
  display: block; width: 100%; height: auto; border-radius: var(--radius-seed-card);
}
@media (min-width: 900px) {
  .fsk-mfpairbuy { grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: var(--space-6); }
}
.fsk-mf__orone { margin: var(--space-7) 0 0; }

/* ── Market Friends v0.6: the unique-section rebuild (2026-08-25) ───────────────
   Built from LOCKED PACK.md v0.6.2 §3. Every band on this page now has its own
   furniture; the only shared reuses left are the PF-7 card frame in S10 and the
   quiz teaser.

   SCROLLYTELLING, four elements, contract per assets/fsk-scroll-motion.js:
     S1 fsk-mfcard        settle
     S4 fsk-mfpair       arc draw
     S6 fsk-mfjrny        path draw
     S7 fsk-mfbtl         callout draw-ons, staggered
   Every base rule below is the FINISHED frame. animation-name is assigned ONLY
   under .fsk-motion-js. That is what makes prefers-reduced-motion and no-JS land
   on the completed state with nothing left to collapse.
   New @keyframes claimed here (add to the reserved list above if that list moves):
     fsk-mf-settle, fsk-mf-arc, fsk-mf-end-in, fsk-mf-rail, fsk-mf-callout
   ──────────────────────────────────────────────────────────────────────────── */

/* S1 THE CARD.  Print lineage: marketing-plan/market-friends-cards/cards/insert.html.
   Uncoated stock, seed-card radius, the wave strip running off both edges. */
.fsk-mfcard-scene { display: flex; justify-content: center; }
.fsk-mfcard {
  position: relative; overflow: hidden;
  width: min(560px, 100%);
  background: var(--color-surface-raised, var(--color-surface));
  border-radius: 18px;
  box-shadow: var(--shadow-card, 0 10px 30px -12px rgba(0,0,0,.28));
}
.fsk-mfcard--photo { background: none; box-shadow: none; }
.fsk-mfcard--photo img { display: block; width: 100%; height: auto; border-radius: 18px; }
.fsk-mfcard__wave { color: var(--reef-teal); line-height: 0; }
.fsk-mfcard__wave svg { display: block; width: 100%; height: 34px; }
.fsk-mfcard__safe { padding: clamp(20px,4vw,34px) clamp(20px,4.5vw,38px) clamp(24px,4.5vw,38px); }
.fsk-mfcard__eyebrow {
  font-family: var(--font-body); font-size: var(--text-micro); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--color-link); margin: 0 0 10px;
}
.fsk-mfcard__h1 {
  font-family: var(--font-heading); color: var(--color-heading);
  font-size: clamp(26px, 4.4vw, 40px); line-height: 1.14; margin: 0 0 14px; text-wrap: balance;
}
.fsk-mfcard__lede { color: var(--color-text); margin: 0 0 20px; max-width: 54ch; }
.fsk-mfcard__cta { margin: 0; }

/* S2 THE HONESTY TABLE.  ⛔ Deliberately unstyled numbers: no strikethrough, no
   emphasis colour, no weight change, no highlighted row. Disclosure, not anchoring
   (PACK §2 S2). Bolding the $25 here undoes a ruling. */
.fsk-mfprice { max-width: 760px; }
.fsk-mfprice .fsk-h { text-wrap: balance; }
.fsk-mfprice__table { width: 100%; border-collapse: collapse; margin: 22px 0 18px; }
.fsk-mfprice__table th,
.fsk-mfprice__table td {
  text-align: left; padding: 14px 8px; border-bottom: 1px solid var(--color-border);
  font-weight: 400; color: var(--color-text); vertical-align: top;
}
.fsk-mfprice__table th { white-space: nowrap; padding-right: 20px; }
.fsk-mfprice__note { color: var(--color-text-muted); margin: 0 0 8px; }
@media (max-width: 599px) {
  .fsk-mfprice__table, .fsk-mfprice__table tbody, .fsk-mfprice__table tr,
  .fsk-mfprice__table th, .fsk-mfprice__table td { display: block; }
  .fsk-mfprice__table tr { border-bottom: 1px solid var(--color-border); padding: 12px 0; }
  .fsk-mfprice__table th, .fsk-mfprice__table td { border: 0; padding: 2px 0; white-space: normal; }
  .fsk-mfprice__table th { color: var(--color-heading); }
}

/* S3 THE TICKET STUB.  The perforation is the motif, not an ornament: these are the
   terms of the arrangement, on the thing you keep. Same family as S1 and S8. */
.fsk-mfstub {
  max-width: 760px; margin: 24px 0 0; padding: 0;
  background: var(--color-surface); border-radius: 14px;
  box-shadow: var(--shadow-card, 0 8px 24px -14px rgba(0,0,0,.25));
  overflow: hidden;
}
.fsk-mfstub__row { display: grid; grid-template-columns: 190px 1fr; gap: 0 22px; padding: 18px 22px; position: relative; }
.fsk-mfstub__row + .fsk-mfstub__row::before {
  content: ""; position: absolute; inset-inline: 14px; top: 0; height: 0;
  border-top: 2px dashed var(--color-border);
}
.fsk-mfstub dt { font-family: var(--font-heading); color: var(--color-heading); margin: 0; }
.fsk-mfstub dd { margin: 0; color: var(--color-text); }
@media (max-width: 699px) {
  .fsk-mfstub__row { grid-template-columns: 1fr; gap: 4px; }
}

@media (max-width: 599px) {
  /* endpoints sit at 18%/82% of the viewBox; the mobile anchors moved to 25%/75%, so
     the arc is squeezed to match. Without this the arc ends float beside the anchors
     again, which is the exact defect the desktop realignment fixed. */
}
/* Anchored at 18% and 82%, which is where the arc path now starts and ends. The first
   build spread them with space-between while the arc ran 4% to 96%, so both ends of the
   arc landed in empty haze and the thing it was supposed to connect sat somewhere else.
   An arc that does not touch its anchors is decoration, which is the one thing the canon
   says a cutout must never be. */
/* height: 0 here would collapse the container, because both ends are absolutely
   positioned, and the next band would ride up over them. The reserved height is what keeps
   the anchors inside their own section. Measured against the rendered anchors rather than
   guessed: the first value left about 200px of dead haze under them. */
  position: absolute; top: -18px; margin: 0; text-align: center;
  width: min(26%, 250px); opacity: 1; translate: 0 0;
}
  display: block; font-family: var(--font-body); font-size: var(--text-micro); font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; margin-bottom: 6px;
}
  display: block; overflow: hidden; background: var(--color-surface);
  border-radius: 16px 16px 50% 50% / 16px 16px 30% 30%;
  box-shadow: 0 9px 0 0 var(--color-card-plate);
}
  position: absolute; top: 0; z-index: 2; display: block;
  width: 52%; height: auto; filter: drop-shadow(0 6px 12px rgba(0,0,0,.18));
}
/* At 390px the desktop geometry pushed both cutouts off the edges of the screen: anchors
   at 18% and 82% of a narrow band, each 42% wide, with the mushroom hung a further -12%
   outside. The LM lost its left third and the Reishi its right. Measured on a 390px render,
   not predicted. The anchors move inward and the mushrooms hang INSIDE the plate corner. */
@media (max-width: 599px) {
}

/* S5 THE ACCORDION.  Native details/summary: no JS, keyboard and screen-reader
   correct for free, and Chrome finds text inside a closed answer. */
.fsk-mfasked { max-width: 800px; }
.fsk-mfqa { margin-top: 22px; border-top: 1px solid var(--color-border); }
.fsk-mfqa__item { border-bottom: 1px solid var(--color-border); }
.fsk-mfqa__item > summary {
  cursor: pointer; list-style: none; padding: 16px 34px 16px 2px; position: relative;
  font-family: var(--font-heading); color: var(--color-heading);
}
.fsk-mfqa__item > summary::-webkit-details-marker { display: none; }
.fsk-mfqa__item > summary::after {
  content: ""; position: absolute; right: 6px; top: 50%; width: 9px; height: 9px;
  border-right: 2px solid var(--color-brand); border-bottom: 2px solid var(--color-brand);
  translate: 0 -70%; rotate: 45deg; transition: rotate .18s ease;
}
.fsk-mfqa__item[open] > summary::after { rotate: -135deg; translate: 0 -20%; }
.fsk-mfqa__item > summary:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 6px; }
.fsk-mfqa__a { padding: 0 2px 18px; }
.fsk-mfqa__a p { margin: 0; color: var(--color-text); max-width: 68ch; }

/* S6 THE DRAWN JOURNEY (PF-20).  Ghost rail always visible ahead of the drawn one, so
   the reader can see there is further to go. Teal band, so text inverts. */
.fsk-mfjrny { position: relative; list-style: none; margin: clamp(26px,4vw,44px) 0 0; padding: 0 0 0 46px; }
.fsk-mfjrny__rail { position: absolute; left: 13px; top: 6px; bottom: 6px; width: 2px; }
.fsk-mfjrny__ghost,
.fsk-mfjrny__draw { position: absolute; inset-inline: 0; top: 0; width: 2px; }
.fsk-mfjrny__ghost { bottom: 0; background: currentColor; opacity: .22; }
.fsk-mfjrny__draw { height: 100%; background: currentColor; transform-origin: top; }
.fsk-mfjrny__stop { position: relative; padding-bottom: clamp(22px,3vw,34px); }
.fsk-mfjrny__stop::before {
  content: ""; position: absolute; left: -39px; top: 7px; width: 12px; height: 12px;
  border-radius: 50%; background: currentColor;
}
.fsk-mfjrny__t { font-family: var(--font-heading); margin: 0 0 6px; font-size: clamp(18px,2.2vw,22px); }
.fsk-mfjrny__d { margin: 0; max-width: 62ch; }
/* THE CLOSER. Its photo had no width constraint and rendered at the full 1180px wrap,
   about 700px tall, so a supporting portrait became the largest thing on the page and the
   four journey stops read as a caption to it. The pack's order is photo, then sentence,
   then link: the photo LEADS, it does not dominate. */
.fsk-mfcloser {
  display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: clamp(18px, 3vw, 32px); align-items: center;
  margin-top: clamp(28px, 4vw, 44px);
}
.fsk-mfcloser__img { display: block; width: 100%; height: auto; border-radius: 14px; }
.fsk-mfcloser__text { margin: 0; max-width: 56ch; }
.fsk-mfcloser__link { margin: 10px 0 0; }
@media (max-width: 699px) {
  .fsk-mfcloser { grid-template-columns: 1fr; }
  .fsk-mfcloser__img { max-width: 320px; }
}

.fsk-mfjrny__cut { float: right; width: clamp(120px,18vw,210px); height: auto; margin: 0 0 10px 18px; }
@media (max-width: 599px) {
  .fsk-mfjrny__cut { float: none; display: block; width: 58%; margin: 0 0 12px; }
}

/* S7 THE ANNOTATED BOTTLE.  Callout hairlines draw on in sequence. Below 750px the
   schematic collapses to a plain list: hairlines pointing at a 390px image are noise,
   and the label facts are the payload. */
.fsk-mfbtl { display: grid; grid-template-columns: minmax(0,280px) minmax(0,1fr); gap: clamp(18px,3vw,40px); align-items: center; margin-top: 22px; padding: clamp(18px,3vw,32px); }
.fsk-mfbtl__media img { display: block; width: 100%; height: auto; }
.fsk-mfbtl__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.fsk-mfbtl__co { display: flex; align-items: baseline; gap: 12px; opacity: 1; }
.fsk-mfbtl__line { flex: 0 0 34px; height: 2px; background: var(--color-brand); transform-origin: left; scale: 1 1; }
.fsk-mfbtl__txt { color: var(--color-text); }
@media (max-width: 749px) {
  .fsk-mfbtl { grid-template-columns: 1fr; }
  .fsk-mfbtl__media { max-width: 200px; margin-inline: auto; }
  .fsk-mfbtl__line { flex-basis: 18px; }
}

/* S8 THE PROMISE LEDGER.  Keepable-card motif again, heavier stock. Static by ruling. */
.fsk-mfhold { max-width: 760px; }
.fsk-mfhold__list {
  list-style: none; margin: 22px 0 0; padding: clamp(18px,3vw,30px);
  background: var(--color-surface-raised, var(--color-surface));
  border-radius: 14px; box-shadow: var(--shadow-card, 0 8px 24px -14px rgba(0,0,0,.25));
  display: grid; gap: 0;
}
.fsk-mfhold__list li { padding: 14px 4px; color: var(--color-heading); font-family: var(--font-heading); font-size: clamp(16px,1.9vw,19px); }
.fsk-mfhold__list li + li { border-top: 1px dashed var(--color-border); }

/* S9 REVIEWS.  Renders only when Judge.me returns a live count AND an excerpt is
   approved; see the section comment. */
.fsk-mfrev { max-width: 900px; text-align: center; }
.fsk-mfrev__fact { font-family: var(--font-heading); color: var(--color-heading); font-size: clamp(18px,2.4vw,24px); margin: 10px 0 24px; }
.fsk-mfrev__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px,1fr)); gap: 18px; text-align: left; }
.fsk-mfrev__item { margin: 0; padding: 20px; background: var(--color-surface); border-radius: 14px; }
.fsk-mfrev__item blockquote { margin: 0; }
.fsk-mfrev__item blockquote p { margin: 0; color: var(--color-text); }
.fsk-mfrev__item figcaption { margin-top: 12px; color: var(--color-text-muted); font-size: var(--text-micro); }

/* S10 additions.  The tiles now ride the PF-7 .fsk-scard frame, so the old flat-tile
   padding is gone; only the MF-specific bits stay. */
.fsk-mf__sub { text-align: center; margin: clamp(22px,3vw,34px) 0 14px; }
.fsk-mf__tablenote { text-align: center; color: var(--color-text-muted); margin: clamp(26px,4vw,40px) 0 0; }

/* ── Scroll-motion, gated. Base rules above are the finished frames. ───────────── */
/* .fsk-mfcard's motion hook was REMOVED 2026-08-26 with the A2 rebuild. The card no longer
   .fsk-motion-js while nothing drives it back leaves it invisible forever, and silently:
   the driver only sets animation-delay on [data-r] elements. Same defect as the S7
   hairlines caught on 2026-08-25. Any new motion rule must name an element that actually
   carries data-r. */
.fsk-motion-js .fsk-mfjrny__draw { height: 0; animation-name: fsk-mf-rail; }
.fsk-motion-js .fsk-mfbtl__co { opacity: 0; animation-name: fsk-mf-callout; }
.fsk-motion-js .fsk-mfbtl__line { scale: 0 1; animation-name: fsk-mf-hairline; }

/* Settle, not bounce (PACK §3 S1): overshoot on a card that is meant to read as a real
   printed object makes it read as a toy. */
@keyframes fsk-mf-settle { from { opacity: 0; translate: 0 22px; } to { opacity: 1; translate: 0 0; } }
@keyframes fsk-mf-arc     { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes fsk-mf-end-in  { from { opacity: 0; translate: 0 16px; } to { opacity: 1; translate: 0 0; } }
@keyframes fsk-mf-rail    { from { height: 0; } to { height: 100%; } }
@keyframes fsk-mf-callout { from { opacity: 0; } to { opacity: 1; } }
@keyframes fsk-mf-hairline { from { scale: 0 1; } to { scale: 1 1; } }

/* ── Market Friends v0.7: the picked visual language (2026-08-26) ───────────────
   Andrew rejected the v0.6 visual layer and picked A2 (split hero), B2 (cutouts on
   the arc) and C1 (full pcard tiles) from the mock boards. What follows implements
   those three, and the rules they carry apply to every band on the page.

   TWO LAWS THIS BLOCK EXISTS TO KEEP:

   1. A PCARD IS NEVER CROPPED. Each product's featured image is a finished square
      composition: the arch, the crest word, the bottle, the bloom. v0.6 put it in a
      4/5 box with an arch radius and cropped every one of them, which is what Andrew
      no aspect-ratio, no mask and no overflow clip, on purpose. Do not add one.

   2. WAVES COME IN MATCHED PAIRS. Read off all 20 wave elements on the live LM PDP
      without exception: every wave is --top-haze and filled with the colour of the
      band it ENTERS, and every non-haze band is bracketed by a leading wave and a
      trailing --flip. Haze bands take none, because haze is the ground. That is
      section markup rather than CSS, recorded here because this is where someone
      looks when the page stops matching the site.
   ──────────────────────────────────────────────────────────────────────────── */

/* S1 hero, candidate A2: card object in the buy-panel position, mosaic beside it. */
  gap: clamp(16px,2.4vw,30px); align-items:start; }
/* Square cells. The mosaic mixes square gallery cards with a portrait market photo, and
   left on auto height the grid rendered ragged with a hole under the pair card. Cropping
   is safe HERE and only here: these are photographs. It would NOT be safe on a pcard,
   which is a finished composition, and the pcards in this grid are already square so
   object-fit has nothing to remove from them. */
  object-fit:cover; border-radius:14px; }
@media (max-width: 899px) {
}

/* S4 pair, candidate B2. The mushrooms live in the arc's own box and the cards in the
   box below it, so no viewport width can bring them into contact. That structural
   guarantee is why B2 was picked over hanging cutouts off the card corners. */
.fsk-mfpair { margin-top: clamp(24px,3.5vw,44px); }
.fsk-mfpair__sky { position:relative; }
.fsk-mfpair__arc { display:block; width:100%; height:clamp(120px,13vw,190px); overflow:visible; }
.fsk-mfpair__draw { stroke-dasharray:100; stroke-dashoffset:0; }
/* 29% and 74% are the measured card centres for the grid below, and the arc path runs
   x=290 to x=740 of a 1000-wide stretched viewBox to match. Re-measure if the grid's
   padding or gap changes, and re-measure at 390. */
.fsk-mfpair__cut { position:absolute; bottom:-6%; width:clamp(64px,9vw,130px); height:auto;
  z-index:2; filter: drop-shadow(0 8px 16px rgba(0,0,0,.20)); }
.fsk-mfpair__cut--day   { left:27%;  translate:-50% 0; }
.fsk-mfpair__cut--night { left:73%;  translate:-50% 0; }
/* PERCENTAGE padding and gap on purpose, so the two card centres land at 27% and 73% of the
   container at EVERY width. With px clamps they moved per breakpoint: measured at 390 the
   centres sat at 105 and 285 (26.9% and 73.1%) while the arc and cutouts were pinned to the
   desktop 29% and 74%, putting the day cutout 15px off its card. Fixed geometry beats a
   per-breakpoint correction that has to be re-derived every time the padding is touched.
   The arc path runs x=270 to x=730 of a 1000-wide stretched viewBox to match. */
.fsk-mfpair__cards { display:grid; grid-template-columns:1fr 1fr;
  gap: 4%; padding-inline: 6%; margin-top: clamp(14px,2vw,26px); }
.fsk-mfpair__slot { margin:0; }
.fsk-mfpair__moment { display:block; text-align:center; font-family:var(--font-body);
  font-size:var(--text-micro); font-weight:700; letter-spacing:.12em; text-transform:uppercase;
  margin-bottom:8px; }
.fsk-mfpair__moment--day { color: var(--amber); }
.fsk-mfpair__moment--night { color: var(--deep-blue); }
.fsk-mfpair__pcard { display:block; width:100%; height:auto; border-radius:16px; }
.fsk-mfpair__name { text-align:center; font-family:var(--font-heading);
  color:var(--color-heading); margin:10px 0 0; }
@media (max-width: 599px) {
  .fsk-mfpair__cut { width:clamp(54px,17vw,88px); }
}

/* S10 close, candidate C1: full pcard on top, controls on a plain body beneath. */
  margin-top: clamp(8px,1.4vw,16px); }
/* 3 + 2 with the last row centred. margin-left:50% inside a 1/3 column does NOT centre a
   row, it crushes it: that shipped once and squashed two tiles to half width. */
  box-shadow: var(--shadow-card, 0 10px 30px -14px rgba(0,0,0,.3)); }
/* box-sizing matters: .fsk-btn carries its own horizontal padding, so a bare width:100%
   pushes each control past the tile's padded edge by exactly that padding. */
@media (max-width: 899px) {
}
@media (max-width: 559px) {
}

/* Motion, gated. Base rules above are the finished frames. */
.fsk-motion-js .fsk-mfpair__draw { stroke-dashoffset:100; animation-name: fsk-mf-arcdraw; }
.fsk-motion-js .fsk-mfpair__cut { opacity:0; animation-name: fsk-mf-cutin; }
@keyframes fsk-mf-arcdraw { from { stroke-dashoffset:100; } to { stroke-dashoffset:0; } }
@keyframes fsk-mf-cutin   { from { opacity:0; } to { opacity:1; } }


/* ── Market Friends v0.8: the collection card, the echo strip, the rail ─────────
   The buy tiles are now the SITE'S OWN card family, rebuilt from measurements taken
   off the live collection page (redo-v07/LIVE-COMPONENT-SPEC.md). Every number here
   is measured, not chosen:
     arch    18px 18px 56% 56% / 18px 18px 33% 33%
     swell   0 11px 0 0 var(--color-card-plate), zero blur and zero spread
     gap     16px between arch and text
     title   14px / 22.4px Inter 400   price 12px / 14.4px Inter 500
   Verified in the mock round against a pixel crop of the real card: the rebuilt swell
   measured 79px tall and 171px wide against the live 79 and 170.
   ⛔ The arch mask is the component, never a crop. Do not add aspect-ratio or overflow
   rules to the tile that would slice the artwork differently.
   ──────────────────────────────────────────────────────────────────────────── */

.fsk-mfcc__gal {
  border-radius: 18px 18px 56% 56% / 18px 18px 33% 33%;
  overflow: hidden;
  box-shadow: 0 11px 0 0 var(--color-card-plate);
  margin-bottom: 16px;
}
.fsk-mfcc__gal img { display: block; width: 100%; height: auto; aspect-ratio: 1/1; object-fit: cover; }
.fsk-mfcc__title { font-family: Inter, sans-serif; font-size: 14px; font-weight: 400;
  line-height: 22.4px; color: var(--color-heading); margin: 0; text-align: left; }
.fsk-mfcc__line { font-family: Inter, sans-serif; font-size: 12px; font-weight: 400;
  line-height: 16px; color: var(--color-text-muted); margin: 2px 0 0; }
/* ⛔ THE CONTROLS MUST LINE UP ACROSS THE ROW. Trifecta's one-liner runs three lines where
   the others run one, and with the tile as a plain block that pushed its buttons and its
   details link out of line with the other four. A row of buy controls at four different
   heights is precisely the "alignment isn't there" Andrew rejected in v0.7. The tile is a
   flex column and the controls are pinned to its end, so the one-liner can be any length
   and the buttons still form a straight line. */
.fsk-mfcc { display: flex; flex-direction: column; height: 100%; }
.fsk-mfcc__buys { display: grid; gap: 6px; margin-top: auto; padding-top: 10px; }
.fsk-mfcc__buys .fsk-btn { width: 100%; box-sizing: border-box; text-align: center;
  font-size: 13px; padding-inline: 8px; }
.fsk-mfcc__details { display: inline-block; margin-top: 8px; font-size: 13px; }
.fsk-mfccgrid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 24px 16px;
  margin-top: 8px; align-items: stretch; }
@media (max-width: 899px) { .fsk-mfccgrid { grid-template-columns: repeat(2, 1fr); gap: 12px; } }

/* S10 copy furniture, v0.6.3 deltas */
.fsk-mf__bridge { text-align: center; color: var(--color-text); margin: 10px 0 0; }
.fsk-mf__consent { text-align: center; color: var(--color-text-muted); font-size: 14px;
  margin: 0 0 18px; }

/* S1b the card echo, C2 ticket-stub treatment (Andrew's pick from the M3 board) */
.fsk-mfecho { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--color-surface); border-radius: 14px; overflow: hidden;
  box-shadow: var(--shadow-card, 0 8px 24px -14px rgba(0,0,0,.25)); }
.fsk-mfecho > li { padding: 18px 20px; position: relative; }
.fsk-mfecho > li + li::before { content: ""; position: absolute; left: 0; inset-block: 14px;
  border-left: 2px dashed var(--color-border); }
.fsk-mfecho__ico { display: block; width: 26px; height: 26px; margin-bottom: 8px;
  color: var(--color-heading); }
.fsk-mfecho__ico svg { width: 26px; height: 26px; }
.fsk-mfecho__txt { display: block; font-size: 14px; line-height: 1.45; color: var(--color-text); }
@media (max-width: 899px) {
  .fsk-mfecho { grid-template-columns: 1fr 1fr; }
  .fsk-mfecho > li:nth-child(n+3) { border-top: 2px dashed var(--color-border); }
}

/* ── ONE RAIL, v0.8 pack law ────────────────────────────────────────────────────
   Measured off the live PDP: .fsk-wrap is max-width 1180 with 40px padding, so the
   content edge is x=170 at 1440 and x=16 at 390. Every band starts there.

   ⛔ A CENTRED NARROWER BOX CREATES A SECOND RAIL, and that is exactly what the craft
   audit caught: S2 sat at x=340 because it was 760px wide with margin-inline:auto,
   and 170 + (1100 - 760) / 2 = 340. The band left edges then wander down the page.
   The fix is to cap the MEASURE without centring the BOX: keep max-width, drop the
   auto margins, and let the element's left edge stay on the rail. Centred TEXT is
   fine and unrelated: text-align keeps the box where it is.
   ⛔ Do not put margin-inline:auto back on a band-level container.
   ──────────────────────────────────────────────────────────────────────────── */


/* ── S1 THE FOLD, revised C4 with photo Set A (Andrew confirmed 2026-08-26) ─────
   Card LEFT at 1:2, photos RIGHT, and the card panel runs the FULL HEIGHT of the
   photo column: "that window should equal the full length of the two photos".

   ⛔ This DEPARTS from the measured live PDP on purpose. There the buy panel is
   position:sticky and ends 147px above the media column (LIVE-COMPONENT-SPEC §3).
   His instruction supersedes the measurement, so align-items:stretch replaces the
   sticky-and-shorter behaviour and sticky becomes meaningless: a panel the same
   height as its neighbour has nothing to stick past. Do not "fix" this back.
   ──────────────────────────────────────────────────────────────────────────── */

.fsk-mffold { display: grid; grid-template-columns: 1fr 2fr; gap: 0; align-items: stretch; }
.fsk-mffold__panel { padding-right: 28px; display: flex; }
.fsk-mffold__card {
  flex: 1; display: flex; flex-direction: column; overflow: hidden;
  background: var(--color-surface);
  /* the card takes the site's arch, with a shallower belly than a product card so the
     swell reads as family resemblance rather than as "this is a bottle for sale" */
  border-radius: 18px 18px 56% 56% / 18px 18px 9% 9%;
  box-shadow: 0 11px 0 0 var(--color-card-plate);
}
.fsk-mffold__card .fsk-mfcard__body {
  flex: 1; display: flex; flex-direction: column; justify-content: center;
  padding: clamp(20px,2.4vw,32px) clamp(20px,2.4vw,32px) clamp(40px,4.5vw,64px);
}
.fsk-mffold__card .fsk-mfcard__h1 { font-size: clamp(24px,2.4vw,34px); }
.fsk-mfmosaic { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(10px,1.4vw,16px); }
.fsk-mfmosaic__img { display: block; width: 100%; height: auto; aspect-ratio: 1/1;
  object-fit: cover; border-radius: 14px; }
@media (max-width: 899px) {
  .fsk-mffold { grid-template-columns: 1fr; }
  .fsk-mffold__panel { padding: 0 0 14px; }
}

/* Motion, gated. Base rules above are the finished frames. */
.fsk-motion-js .fsk-mffold__panel { opacity: 0; translate: 0 22px; animation-name: fsk-mf-settle; }
.fsk-motion-js .fsk-mfmosaic { opacity: 0; translate: 0 18px; animation-name: fsk-mf-settle; }

/* A3 mid-page anchor CTAs, after S2 and after S5. On the rail like everything else, so no
   centred box and no second rail. */
.fsk-mf__anchorcta { margin: clamp(22px,3vw,34px) 0 0; }


/* ── S4c the five, and S7's INSIDE / NEVER (v0.6.4) ─────────────────────────────
   Five alternating rows inside ONE haze band, not five bands. Andrew's constraint was
   that the run of five must not double the page; five bands would have meant five sets
   of band padding and ten wave elements, which is the doubling itself.
   ──────────────────────────────────────────────────────────────────────────── */
  gap: clamp(20px,3vw,44px); align-items: center; padding-block: clamp(20px,2.6vw,34px); }
@media (max-width: 749px) {
}

/* The ingredients component, ported from the PDPs. The ONE sanctioned recycle. */
.fsk-mfin { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px,2.4vw,32px);
  margin-top: clamp(18px,2.4vw,28px); padding-top: clamp(16px,2vw,22px);
  border-top: 1px solid var(--color-border); }
.fsk-mfin__label { font-family: var(--font-body); font-size: var(--text-micro); font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; margin: 0 0 6px; }
.fsk-mfin__col--inside .fsk-mfin__label { color: var(--color-link); }
.fsk-mfin__col--never .fsk-mfin__label { color: var(--color-text-muted); }
.fsk-mfin__list { margin: 0; color: var(--color-text); }
.fsk-mfin__col--never .fsk-mfin__list { color: var(--color-text-muted); }
@media (max-width: 599px) { .fsk-mfin { grid-template-columns: 1fr; gap: 14px; } }


/* ── S4c the five, v0.6.5 rich rows + S4b the quality band ──────────────────────
   Andrew called the first version weak and asked for the site's design flow: the
   live PDP's pill chips, the house glyphs, the serif headings and the product art
   reading as ONE designed system rather than a text list with a picture beside it.
   The chip is .fsk-chip.fsk-chip--citrus reused verbatim from the PDPs, not restyled.
   ⛔ Still ONE band with five rows: five bands would bring five sets of band padding
   and ten waves, which is the page-doubling he ruled against.
   ──────────────────────────────────────────────────────────────────────────── */

.fsk-mffive__row { display: grid; grid-template-columns: minmax(0,1.3fr) minmax(0,1fr);
  gap: clamp(24px,3.4vw,52px); align-items: center; padding-block: clamp(26px,3.2vw,44px); }
.fsk-mffive__row + .fsk-mffive__row { border-top: 1px solid var(--color-border); }
.fsk-mffive__row--flip .fsk-mffive__copy { order: 2; }
.fsk-mffive__row--flip .fsk-mffive__media { order: 1; }

/* the chip rail sits between the eyebrow and the heading, the live PDP's own order */
.fsk-mffive__chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 10px; }
/* the timing chip is a different KIND of chip, so it reads differently: quieter, outlined,
   and last in the rail. A second citrus pill would just look like a fourth benefit. */
.fsk-mffive__timing { color: var(--color-text-muted); }
.fsk-mffive__timing svg { opacity: .85; }

.fsk-mffive__copy .fsk-h { margin: 0; }
.fsk-mffive__body { margin: 10px 0 0; color: var(--color-text); max-width: 56ch; }

/* the art gets a plate so it reads as a designed card rather than a floating square,
   in the same family as the buy cards without borrowing their arch, which would make
   these look shoppable when they are not */
.fsk-mffive__media { max-width: 320px; }
.fsk-mffive__img { display: block; width: 100%; height: auto; border-radius: 16px;
  box-shadow: 0 9px 0 0 var(--color-card-plate); }
.fsk-mffive__row--flip .fsk-mffive__media { justify-self: start; }
.fsk-mffive__row:not(.fsk-mffive__row--flip) .fsk-mffive__media { justify-self: end; }
@media (max-width: 749px) {
  .fsk-mffive__row { grid-template-columns: 1fr; gap: 16px; }
  .fsk-mffive__row--flip .fsk-mffive__copy,
  .fsk-mffive__row--flip .fsk-mffive__media { order: 0; }
  .fsk-mffive__media { max-width: 230px; }
}

/* S4b the quality band: three glyph cards on the house idiom */
  margin-top: clamp(24px,3vw,38px); }
  border-radius: 16px; padding: clamp(18px,2.2vw,26px);
  box-shadow: var(--shadow-card, 0 8px 24px -14px rgba(0,0,0,.25)); }
  color: var(--color-brand); }
  font-size: clamp(16px,1.8vw,19px); }


/* ── S4d WHY EVERY DAY (v0.6.6): the bridge band ────────────────────────────────
   Compact on purpose. It hands the reader from the five mushrooms into the accordion
   and the close carrying the subscription logic, and a full-height band here would
   stall that run. Copy left, three steps right, so it reads as one move rather than
   a headline followed by a list.
   ──────────────────────────────────────────────────────────────────────────── */
.fsk-mfday__band { padding-block: clamp(32px,4vw,56px) !important; }
.fsk-mfday { display: grid; grid-template-columns: minmax(0,1.25fr) minmax(0,1fr);
  gap: clamp(24px,3.4vw,52px); align-items: center; }
.fsk-mfday__body { margin: 10px 0 0; color: var(--color-text); max-width: 58ch; }
.fsk-mfday__steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.fsk-mfday__steps > li { display: flex; align-items: center; gap: 12px;
  background: var(--color-surface-raised, var(--color-surface)); border-radius: 12px;
  padding: 12px 16px; box-shadow: var(--shadow-card, 0 6px 18px -12px rgba(0,0,0,.22)); }
.fsk-mfday__ico { flex: 0 0 26px; width: 26px; height: 26px; color: var(--color-brand); }
.fsk-mfday__ico svg { width: 26px; height: 26px; }
.fsk-mfday__label { font-family: var(--font-heading); color: var(--color-heading); font-size: 16px; }
@media (max-width: 749px) { .fsk-mfday { grid-template-columns: 1fr; gap: 18px; } }


/* ── S4b-1 / S4b-2 the two quality sections (v0.6.7) ────────────────────────────
   Andrew asked four times for the quality story to be sold. It was three small cards
   in a strip; these are two full sections with the purpose-built duotone glyph pairs
   from the locked pack as their anchors, at a size that lets the artwork read.
   The glyphs were absent from the theme sprite until this round, which is exactly why
   stand-ins got used and why the icons were wrong.
   ──────────────────────────────────────────────────────────────────────────── */
.fsk-mfmethod { display: grid; grid-template-columns: minmax(0,1.45fr) minmax(0,1fr);
  gap: clamp(28px,4vw,64px); align-items: center; }
.fsk-mfmethod--flip .fsk-mfmethod__copy { order: 2; }
.fsk-mfmethod--flip .fsk-mfmethod__glyphs { order: 1; }
.fsk-mfmethod__body { margin: 12px 0 0; color: var(--color-text); max-width: 62ch; }
.fsk-mfmethod__glyphs { display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(16px,2.4vw,30px); }
.fsk-mfmethod__g { display: block; color: var(--ink-navy); }
.fsk-mfmethod__g svg { display: block; width: 100%; height: auto; }
@media (max-width: 749px) {
  .fsk-mfmethod { grid-template-columns: 1fr; gap: 22px; }
  .fsk-mfmethod--flip .fsk-mfmethod__copy,
  .fsk-mfmethod--flip .fsk-mfmethod__glyphs { order: 0; }
  .fsk-mfmethod__glyphs { max-width: 260px; }
}
