/* COTI — The System (system.html)
   Order: tokens & base → shared site chrome (nav, cart drawer, footer, CTA)
   → reveal → shared layout & typography → Preface → chapter marker →
   00 Whole Food → 01 Node → 02 Role → 03 Module → 04 Finale → responsive
   overrides. Chrome rules mirror assets/css/index.css; the page tokens in
   :root are System-specific. */

/* ── TOKENS & BASE ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; overflow-x: hidden; scroll-snap-type: y proximity; scroll-padding-top: 84px; }
:root {
  --ivory:#F4F3EF; --charcoal:#181714; --forest:#1C3328; --brick:#9B4A34;
  --ink:#4A4840; --ink-light:#5C5A54;
  --rule:rgba(24,23,20,0.09);
  --role-primary:#B82E1A;
  --role-support:#1C5C3A;
  --role-balance:#7A5C30;
  --role-transport:#4A4070;
  --serif: 'Cormorant Garamond', Georgia, serif;
  --display: 'Fraunces', Georgia, serif;
  --system-display: 'Cormorant Garamond', Georgia, serif;
  --mono:'DM Sans',sans-serif;
  --sans:'DM Sans',sans-serif;
  /* One outer gutter for the whole page: nav, mobile menu, cart drawer,
     footer and every chapter use it, so their left edges coincide. It mirrors
     index.css (24px ≤900, 20px ≤480, then 5.5vw up to 80px). */
  --pad:clamp(24px,5.5vw,80px);
  /* Container matches index.html's .hero-inner so margins line up with the
     homepage hero at every desktop width. --page-gutter is an alias of --pad,
     kept so the existing selectors need no change. */
  --page-max: 1360px;
  --page-gutter: var(--pad);
  /* Vertical scrollbar width, set by system.js. #s-whole-food and #s-role
     break out to the viewport edge with calc(50% - 50vw); 100vw includes the
     scrollbar but percentages do not, so the breakout is corrected by half
     this value. 0px until the script runs and wherever scrollbars overlay
     content (macOS, most touch devices). */
  --sbw: 0px;
  --header-height: 84px;
  --hairline: rgba(28, 51, 40, 0.10);
  /* Chapter-marker column and its gap, shared by 00–03 and the 04 Finale so
     every stage's content starts on one x. ≥1200px redefines both below. */
  --marker-col: clamp(100px, 10vw, 150px);
  --marker-gap: clamp(36px, 4vw, 64px);

  /* Spacing */
  --space-xl: 64px;
  --space-2xl: 96px;
  /* Copy-to-visual gap once 00–03 stack to one column (≤900px). */
  --system-stack-gap: 44px;
  --space-section: clamp(104px, 10vw, 144px);

  /* Preface "cover" sage is --ivory with its R and G channels swapped: same
     lightness, cooler hue. --system-divider is shared by the Preface and
     Finale chapter boundaries. */
  --system-opening-sage: #F3F4EF;
  --system-divider: rgba(70, 84, 70, 0.18);
}
/* overflow-x lives on <html> only: setting it on <body> too would make body
   the nearest scroll container and break position:sticky descendants. */
body { background:var(--ivory); color:var(--charcoal); font-family:var(--mono); font-weight:300; font-size:13px; line-height:1.6; -webkit-font-smoothing:antialiased; }
/* <html> carries overflow-x:hidden, so a body overflow value is never
   propagated to the viewport; the lock has to sit on <html> itself. */
html.scroll-locked, body.scroll-locked { overflow:hidden; }

/* ── SHARED SITE CHROME ── */

.section-eyebrow {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(28, 51, 40, 0.65);
}

/* Nav */
nav#nav { position:fixed; top:0; left:0; right:0; z-index:500; height:84px; display:flex; align-items:center; padding:0 var(--pad); transition:background .4s,border-color .4s,top .35s cubic-bezier(.4,0,.2,1); border-bottom:1px solid transparent; }
nav#nav.on { background:rgba(244,243,239,0.92); backdrop-filter:blur(12px); border-color:transparent; box-shadow:0 1px 8px rgba(0,0,0,0.04); }
nav#nav.hidden { top:-84px; }
.n-logo { text-decoration:none; display:flex; align-items:center; line-height:1; flex-shrink:0; }
.n-logo svg { height:28px; width:70px; display:block; overflow:visible; flex-shrink:0; }
.n-nav-group { margin-left:auto; display:flex; align-items:center; gap:80px; }
.n-center { display:flex; align-items:center; }
.n-links { display:flex; gap:52px; list-style:none; align-items:center; white-space:nowrap; }
.n-links li { position:relative; }
.n-links a { font-family:var(--mono); font-size:16px; letter-spacing:.13em; line-height:1.2; text-transform:uppercase; color:var(--forest); font-weight:500; text-decoration:none; transition:color .22s; white-space:nowrap; }
.n-links a:hover { color:var(--forest); }
.n-links li[data-module] > a { color:var(--forest); }
.n-links a[aria-current="page"] { position:relative; }
.n-links a[aria-current="page"]::after {
  content:""; position:absolute; left:0; bottom:-7px; width:100%; height:1px;
  background-color:var(--forest); transform:scaleX(1); transform-origin:left center;
  transition:transform .25s ease, background-color .25s ease;
}

.coti-cart-btn { background:none; border:none; cursor:pointer; padding:0; margin:0; display:inline-flex; align-items:center; justify-content:center; gap:12px; line-height:1; color:var(--forest); }
.coti-cart-btn svg { overflow:visible; transition:transform .35s cubic-bezier(.34,1.56,.64,1); flex-shrink:0; }
.n-cart-icon-wrap { position:relative; display:inline-flex; align-items:center; }
.n-cart-count { display:none; position:absolute; top:-7px; right:-8px; background:#1C3328; color:#fff; font-family:var(--mono); font-size:9px; font-weight:400; line-height:1; min-width:16px; height:16px; border-radius:8px; padding:0 4px; align-items:center; justify-content:center; letter-spacing:0; }
.coti-cart-btn:hover svg { transform:scale(1.08); }
.n-palette-label { font-family:var(--mono); font-size:16px; letter-spacing:.13em; text-transform:uppercase; color:var(--forest); font-weight:500; line-height:1; transition:color .22s; }
.coti-cart-btn:hover .n-palette-label { color:var(--forest); }

/* Hamburger */
.n-hamburger { display:none; flex-direction:column; justify-content:center; align-items:center; gap:5px; width:36px; height:36px; background:none; border:none; cursor:pointer; padding:4px; }
.n-hamburger span { display:block; width:20px; height:1.5px; background:var(--charcoal); transition:transform .3s ease, opacity .2s ease; }
.n-hamburger.open span:nth-child(1) { transform:translateY(6.5px) rotate(45deg); }
.n-hamburger.open span:nth-child(2) { opacity:0; transform:scaleX(0); }
.n-hamburger.open span:nth-child(3) { transform:translateY(-6.5px) rotate(-45deg); }

/* Mobile menu */

@media (max-width:900px) {
  :root { --pad: 24px; }
  nav#nav { gap:4px; }
  .n-nav-group { gap:4px; }
  .n-center { display:none; }
  .n-hamburger { display:flex; min-width:44px; min-height:44px; }
  .coti-cart-btn { min-width:44px; min-height:44px; }
  .n-palette-label { display:none; }
}
@media (max-width:480px) {
  :root { --pad: 20px; }
  nav#nav { padding:0 16px 0 var(--pad); }
}

/* Keyboard focus outlines for nav, mobile menu and cart controls */
.n-logo:focus-visible {
  outline: 1.5px solid var(--forest);
  outline-offset: 4px;
}
.n-links a:focus-visible,
.n-mobile-menu a:focus-visible {
  outline: 1.5px solid var(--forest);
  outline-offset: 4px;
}
.coti-cart-btn:focus-visible,
.n-hamburger:focus-visible {
  outline: 2px solid var(--forest);
  outline-offset: 3px;
  border-radius: 2px;
}
.cart-close:focus-visible,
.cart-qty-btn:focus-visible,
.cart-remove:focus-visible {
  outline: 2px solid var(--forest);
  outline-offset: 2px;
  border-radius: 2px;
}
.checkout-btn:focus-visible,
.continue-btn:focus-visible {
  outline: 2px solid var(--forest);
  outline-offset: 2px;
}




/* Shared CTA — same as index.html's .hero-product-cta */
.cta-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  padding-bottom: 5px;
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--forest);
  text-decoration: none;
}
.cta-link::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 44px;
  transform: translateY(-50%);
}
.cta-link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  opacity: 0.45;
  transform-origin: left center;
  transition: transform 300ms cubic-bezier(.22,1,.36,1), opacity 300ms ease;
}
.cta-link:focus-visible { outline: 1.5px solid var(--forest); outline-offset: 4px; }
.cta-link span:last-child,
.cta-link .cta-arrow { transition: transform 300ms cubic-bezier(.22,1,.36,1); display: inline-block; }
@media (hover:hover) and (pointer:fine) {
  .cta-link:hover span:last-child,
  .cta-link:hover .cta-arrow { transform: translateX(6px); }
  .cta-link:hover::after { opacity: 0.75; }
}

/* ── REVEAL ON SCROLL ──
   Content is visible by default. system.js adds .reveal-armed to each
   .reveal element only after its IntersectionObserver exists; the hidden
   state below applies to armed elements only, and .in releases them. With
   JavaScript off or failing, an old browser, or reduced motion, nothing is
   armed and everything stays visible.
   The transition lives on the revealed state (.in), not the armed one, so
   arming is instant: elements go straight to hidden with no visible→hidden
   fade, and only the reveal itself animates. The longhands (not the
   shorthand) keep the .reveal-dN delays. */
.reveal-armed { opacity:0; transform:translateY(12px); }
.reveal-armed.in {
  opacity:1; transform:none;
  transition-property:opacity, transform; transition-duration:.55s; transition-timing-function:ease;
}
.reveal-d1 { transition-delay:80ms; }
.reveal-d2 { transition-delay:180ms; }
.reveal-d3 { transition-delay:280ms; }
.reveal-d5 { transition-delay:480ms; }
.reveal-scale.reveal-armed { transform:scale(.98); }
.reveal-scale.reveal-armed.in { transform:scale(1); transition:opacity .7s ease, transform .7s ease; }

/* Short landscape screens: stage content is taller than the viewport, so
   snapping to section starts would fight scrolling. */
@media (max-height: 600px) {
  html { scroll-snap-type: none; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal-armed, .reveal-scale.reveal-armed { opacity:1; transform:none; transition:none; }
  html { scroll-behavior: auto; scroll-snap-type: none; }
}

/* ══════════════════════════════════════════════════════════════════
   SHARED LAYOUT & TYPOGRAPHY
   ══════════════════════════════════════════════════════════════════ */

/* Sections span the full viewport; .system-inner centers the content at the
   same width as the homepage hero. */
.system-section {
  width: 100%;
  padding-block: var(--space-section);
  position: relative;
}
.system-section + .system-section {
  border-top: 0.5px solid rgba(28,51,40,0.07);
}
.system-section--cream { background: var(--ivory); }

.system-inner {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

/* The four numbered stages (Whole Food, Node, Role, Module) share one
   two-column grid and align-items:center, so every headline starts on the
   same axis and the copy centers against its artwork. Track widths are
   viewport-driven clamp() values rather than minmax() ranges, so the copy
   and visual columns start at the same X in every section. The floors
   scale with the viewport because the headline font-size is itself a
   vw-driven clamp; the coefficients and px caps were calibrated against the
   widest headline line via canvas.measureText. */
.system-two-column,
.node-content,
.role-layout,
.module-layout-simple {
  display: grid;
  grid-template-columns:
    minmax(max(365px, min(500px, 32vw)), 0.9fr)
    minmax(max(190px, min(360px, 23vw)), 1.1fr);
  column-gap: clamp(40px, 5vw, 72px);
  align-items: center;
}

/* Editorial headlines: Cormorant Garamond, italic accents.
   Intro headline: ≤768px is set by the phone block below (40–48px). From
   769px the size ramps linearly from that 48px to 64px at 901px (slope
   0.1203px per px of width), then holds 64px until 5.7vw overtakes it
   (≈1123px) and caps at 92px — the desktop scale, unchanged. Line-height
   and bottom margin ramp the same way, so nothing steps at 769 or 901. */
.system-preface__title {
  font-family: var(--system-display);
  font-size: clamp(44px, calc(44px + (100vw - 768px) * 0.1128), min(84px, max(59px, 5.2vw)));
  font-weight: 500;
  line-height: calc(47.5px + (100vw - 768px) * 0.1045);
  letter-spacing: -0.025em;
  color: var(--forest);
  max-width: 650px;
  margin: 0;
}
/* Capped at 58px so the authored two-line breaks hold in the 1360px
   container (checked with canvas.measureText). */
.system-section-title,
.role-headline,
.module-headline {
  font-family: var(--system-display);
  font-size: clamp(42px, 3.5vw, 58px);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--forest);
  max-width: 520px;
  margin-bottom: 30px;
}
.system-preface__title em,
.system-section-title em,
.role-headline em,
.module-headline em {
  font-family: var(--system-display);
  font-style: italic;
  font-weight: 500;
  color: rgba(28, 51, 40, 0.62);
}

/* DM Sans body copy */
.system-body {
  font-family: var(--sans);
  font-size: clamp(20px, 1.4vw, 21px);
  font-weight: 400;
  line-height: 1.66;
  letter-spacing: 0;
  color: rgba(28, 51, 40, 0.86);
  max-width: 460px;
}

/* Eyebrow variant used above the Preface headline. From 769px its size ramps
   16 → 19px (reached at 901px) instead of stepping. */
.system-eyebrow {
  font-size: clamp(16px, calc(16px + (100vw - 768px) * 0.0226), 19px);
  font-weight: 500;
  letter-spacing: 0.14em;
  color: rgba(28, 51, 40, 0.86);
}

/* Authored <br> line breaks; hidden at ≤768px (see responsive overrides). */
.desktop-break { display: inline; }

/* Main column: full-width rows. Horizontal padding comes from this wrapper
   (zeroed at ≤768px and re-applied to each .system-inner, so section
   backgrounds can run edge to edge). */
.system-content-layout {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}
.system-sections .system-section {
  width: 100%;
  /* Shared floor so the four stages read as equal-weight screens; content
     taller than this (Module) grows the section instead of clipping. */
  min-height: calc(100svh - var(--header-height));
  padding-block: clamp(76px, 7vw, 104px);
  border-top: 0.5px solid rgba(28,51,40,0.09);
  background: var(--ivory);
  display: flex;
  align-items: center;
  scroll-snap-align: start;
  scroll-snap-stop: normal;
}
.system-sections .system-section:first-child {
  border-top: none;
}
.system-sections .system-inner {
  width: 100%;
  max-width: none;
  padding-inline: 0;
  margin: 0;
}

/* Visual stage — the container shared by the Node diagram and the Module
   plate. The explicit bound track keeps the child from overflowing at narrow
   widths (an auto track would size to its max-content). */
.system-visual-stage {
  width: 100%;
  min-width: 0;
  max-width: 500px;
  min-height: 320px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  justify-self: center;
}

/* ── CHAPTER MARKER — one component for 00 Whole Food through 04 Palette: a
   vertical forest rule beside a stacked number/name label. Decorative
   (aria-hidden), never focusable. ── */
.system-chapter-marker {
  display: grid;
  grid-template-columns: 2px auto;
  column-gap: 16px;
  align-items: start;
  width: fit-content;
}
.system-chapter-rule {
  width: 2px;
  min-height: 52px;
  align-self: stretch; /* follows the label when a narrow marker column wraps it to three lines */
  background: var(--forest);
}
.system-chapter-label {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-family: var(--mono);
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--forest);
}
.system-chapter-number {
  font-size: 18px;
  line-height: 1.1;
  letter-spacing: 0.08em;
}
/* At ≥769px the marker sits in a narrow left column beside the section
   content (one clamp() across tablet and desktop; ≥1200px overrides it
   below). At ≤768px it stacks above the content in normal flow. */
@media (min-width: 769px) {
  .system-sections .system-inner.system-section-inner {
    display: grid;
    grid-template-columns: var(--marker-col) minmax(0, 1fr);
    column-gap: var(--marker-gap);
    align-items: start;
  }
}

/* ── PREFACE — centered cover: sage ground, four corner botanicals behind
   the type, eyebrow, headline, intro copy, and a line-and-dot marker that
   hands off to Whole Food. ── */
.system-preface {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  overflow: clip;
  min-height: 100svh;
  padding-top: 112px;
  padding-bottom: 56px;
  background: var(--system-opening-sage);
  border-bottom: 1px solid var(--system-divider);
}

/* Corner artwork keeps its own aspect ratio and scales with clamp(), so it
   is resized, never cropped or stretched. */
.system-preface__botanical-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  user-select: none;
}
.system-preface__corner {
  position: absolute;
  display: block;
  height: auto;
  object-fit: contain;
}
/* Base (narrow) sizes are modest so corners never collide with the centered
   text; ≥901px grows each to its full proportions. Top-right sits below the
   84px nav with extra clearance under "My Palette".
   Top-left branch, ≤900px: placed from its own width (--tl-w) so scale and
   position move together. The artwork (734×1024) has about 13% transparent
   padding on its left and 9% on its right. Its foliage is the thin stem
   (≈29–37% across, entering from the top edge and running to ≈50% down), an
   upper-right leaf at ≈49–91% across / 48–64% down, and a lower-left leaf at
   ≈13–34% across / 65–97% down. As on desktop, the stem passes behind the
   left of the wordmark (the "c"/"o", ~x34–40 on a wordmark that spans
   x20–90), so --tl-stem-x puts the stem there. --tl-leaf-y is the top of the
   upper-right leaf, 60px: just under the wordmark's bottom (≈56px), so no
   leaf sits behind a letter. The lower-left leaf then hangs at x≈14–35,
   left of the eyebrow, and the stem's tip ends ≈8px above the eyebrow. Nothing
   reaches the controls on the right. It paints at z-index 0, below the nav
   (500) and its controls, pointer-events:none, and belongs to the Preface, so
   it scrolls away with it. */
.system-preface__corner--tl {
  --tl-w: clamp(100px, 28vw, 112px);
  --tl-leaf-y: 60px;
  --tl-stem-x: 36px;
  width: var(--tl-w);
  top: calc(var(--tl-leaf-y) - var(--tl-w) * 0.668);
  left: calc(var(--tl-stem-x) - var(--tl-w) * 0.35);
}
@media (min-width: 481px) {
  .system-preface__corner--tl { --tl-w: clamp(104px, 16vw, 112px); --tl-stem-x: 40px; }
}
.system-preface__corner--tr {
  top: clamp(80px, 11vh, 150px);
  right: 0;
  width: clamp(64px, 19vw, 340px);
}
.system-preface__corner--bl,
.system-preface__corner--br {
  bottom: 0;
}
.system-preface__corner--bl {
  left: 0;
  width: clamp(72px, 21vw, 290px);
}
.system-preface__corner--br {
  right: 0;
  width: clamp(72px, 19.1vw, 270px);
  transform: translate(4%, 3%);
}
@media (min-width: 481px) and (max-width: 900px) {
  .system-preface__corner--br {
    width: clamp(87px, 20.7vw, 294px);
    transform: translate(6%, 0);
  }
}
@media (min-width: 901px) {
  /* The top-left asset has a long upper stem that enters from above the
     viewport (negative top) and ends behind the "c" of the wordmark; the nav
     stays above it. Its base leaf cluster must stay clear of the left edge,
     which is why left is positive. */
  .system-preface__corner--tl {
    top: -20px;
    left: 23px;
    width: clamp(150px, 15.5vw, 220px);
  }
  .system-preface__corner--tr { width: clamp(170px, 24vw, 340px); }
  .system-preface__corner--bl { width: clamp(160px, 25vw, 330px); }
  .system-preface__corner--br {
    width: clamp(180px, 25vw, 370px);
    transform: translate(9%, 7%);
  }
}
/* Dedicated mobile composite. Not currently shown at any width: ≤768px uses
   the two-corner diagonal instead (see responsive overrides). */
.system-preface__mobile-botanical {
  display: none;
  position: absolute;
  inset: 84px 0 0;
  z-index: 0;
  pointer-events: none;
  user-select: none;
}
.system-preface__mobile-botanical img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}

.system-preface__eyebrow,
.system-preface__content {
  margin-left: 0;
  text-align: center;
}
.system-preface > .system-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  flex: 1;
}
/* 28px on phones, ramping to the desktop gap (64px) at 901px. */
.system-preface__eyebrow {
  margin-bottom: calc(28px + (100vw - 768px) * 0.2707);
}
.system-preface__content {
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* Forces the authored three-line headline at every width. */
.system-preface__title span { display: block; }
.system-preface__title {
  margin-bottom: calc(34px + (100vw - 768px) * 0.135);
}
.system-preface__body {
  font-family: var(--sans);
  font-size: clamp(20px, 1.5vw, 23px);
  font-weight: 400;
  line-height: 1.62;
  letter-spacing: 0;
  color: rgba(28, 51, 40, 0.88);
  max-width: 520px;
  margin-top: 0;
}
/* Scroll cue: a line and a dot, part of the centered text group. */
.system-preface__marker {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 42px on phones, ramping to the desktop gap at 901px (no step at 769). */
  margin-top: clamp(42px, calc(42px + (100vw - 768px) * 0.1654), clamp(64px, 7vw, 88px));
}
.system-preface__marker-line {
  width: 1px;
  height: 26px;
  background: rgba(28, 51, 40, 0.22);
}
.system-preface__marker-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--forest);
  opacity: 0.7;
  margin-top: 9px;
}
@media (min-width: 901px) {
  .system-preface {
    padding-top: clamp(130px, 18vh, 172px);
    padding-bottom: 32px;
  }
  .system-preface__eyebrow { margin-bottom: clamp(64px, 5.4vw, 72px); }
  .system-preface__title {
    line-height: 1.04;
    max-width: 760px;
    letter-spacing: -0.025em;
    margin-bottom: clamp(52px, 4.5vw, 60px);
  }
}

/* ── 00 WHOLE FOOD — annotated botanical plate (labels are baked into the
   WebP) on a warm ground. The id selector keeps the ground scoped to this
   section (Module shares .system-section--warm) and outranks the shared
   ivory default. ── */
#s-whole-food {
  background: #F0ECE5;
}
/* At ≥769px .system-content-layout still has horizontal padding, which would
   leave ivory strips beside a tinted section. Whole Food and Role break out
   to the viewport edge (calc(50% - 50vw), corrected by --sbw) and rebuild
   the container's max-width and gutter on their own .system-inner so the
   content does not move. At ≤768px the layout padding is already zero, so
   this applies to tablet and desktop only. */
@media (min-width: 769px) {
  #s-whole-food {
    width: calc(100vw - var(--sbw));
    margin-left: calc(50% - 50vw + var(--sbw) / 2);
    margin-right: calc(50% - 50vw + var(--sbw) / 2);
  }
  #s-whole-food > .system-inner {
    max-width: var(--page-max);
    margin-inline: auto;
    padding-inline: var(--page-gutter);
  }
}
.botanical-note-image {
  display: block;
  width: 100%;
  min-width: 0;
  max-width: 460px;
  height: auto;
  margin: 0 auto;
  justify-self: center;
}

/* ── 01 NODE — static inline SVG diagram; scales as one unit with its
   column. ── */
.node-copy { max-width: 500px; }
.node-figure { min-width: 0; width: 100%; margin: 0; }
.node-visual {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
/* Narrower than the shared track so the diagram's outer labels (which render
   at the SVG's visible edge, overflow:visible) keep an inset from the copy
   column like the other stages' artwork has. Still the largest of the four
   visuals. */
#s-node .system-visual-stage {
  max-width: clamp(450px, 35vw, 570px);
}
.node-matrix {
  --nm-bg: var(--ivory);
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.nm-out, .nm-cat {
  font-family: var(--sans);
  paint-order: stroke;
  stroke: var(--nm-bg);
  stroke-width: 3px;
  stroke-linejoin: round;
}
.nm-out { font-size: 10px; font-weight: 400; fill: #2f2e2a; }
.nm-cat { font-size: 12px; font-weight: 400; }
.nm-center-kicker { font-family: var(--mono); font-size: 12px; font-weight: 500; letter-spacing: 0.2em; fill: #F4F3EF; opacity: 0.8; }
.nm-center-name { font-family: var(--display); font-size: 20px; font-weight: 400; letter-spacing: 0.02em; fill: #F4F3EF; }
.nm-center-sub { font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; fill: #F4F3EF; opacity: 0.7; }
/* Readable companion to the diagram. The SVG's 10px/12px labels are SVG
   units and scale with the diagram (≈4–7px on phones, ≈4px at 901px), so the
   same compounds are listed as normal text inside a closed disclosure. The
   disclosure is hidden by default (desktop) and shown at phone/tablet widths
   (≤900px) by the media query after the .node-legend rules below; the
   diagram itself is untouched, so its proportions never change. */
.node-legend-disclosure {
  display: none;
  width: 100%;
  max-width: 560px;
  margin-top: 24px;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.node-legend-disclosure > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 48px;
  padding: 8px 2px;
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--forest);
  cursor: pointer;
  list-style: none;
}
.node-legend-disclosure > summary::-webkit-details-marker { display: none; }
.node-legend-disclosure > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin-right: 4px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 250ms ease;
}
.node-legend-disclosure[open] > summary::after { transform: translateY(2px) rotate(-135deg); }
.node-legend-disclosure > summary:focus-visible { outline: 1.5px solid var(--forest); outline-offset: -3px; }
.node-legend { display: block; padding-bottom: 6px; }
.node-legend__row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr);
  column-gap: 14px;
  padding: 14px 2px;
  border-top: 1px solid var(--hairline);
}
.node-legend__row::before {
  content: "";
  grid-row: 1 / span 2;
  width: 10px;
  height: 10px;
  margin-top: 0.4em;
  border-radius: 50%;
  background: var(--dot);
}
.node-legend dt {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--forest);
}
.node-legend dd {
  margin: 4px 0 0;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  color: rgba(28, 51, 40, 0.86);
}
@media (max-width: 900px) {
  .node-legend-disclosure { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .node-legend-disclosure > summary::after { transition: none; }
}

/* ── 02 ROLE — four selectable rows separated by hairlines. Selecting a row
   only tints it; no extra content is revealed. ── */
#s-role {
  color: var(--forest);
  background: #E8E4DA;
}
@media (min-width: 769px) {
  /* Full-bleed breakout, same technique as #s-whole-food above. The shorter
     floor (87% of the shared one) trims dead space around Role's compact
     content. */
  #s-role {
    width: calc(100vw - var(--sbw));
    margin-left: calc(50% - 50vw + var(--sbw) / 2);
    margin-right: calc(50% - 50vw + var(--sbw) / 2);
    min-height: calc((100svh - var(--header-height)) * 0.87);
  }
  #s-role > .system-inner {
    max-width: var(--page-max);
    margin-inline: auto;
    padding-inline: var(--page-gutter);
  }
}
.role-rows {
  --role-row-inset: clamp(14px, 3.6vw, 18px);
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--rule);
}
/* Capped and centered like the Whole Food plate (460px) so the list sits at
   the same distance from the copy as the other stages' visuals. */
@media (min-width: 901px) {
  .role-rows {
    max-width: 460px;
    margin-inline: auto;
  }
}
/* Real <button>s: keyboard-reachable and clickable. */
.role-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  background: transparent;
  margin: 0;
  /* One inner inset for every row at every width, so the selected wash has
     room around the text and rows stay aligned with each other. */
  padding: clamp(15px, 1.7vw, 20px) var(--role-row-inset);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: background-color 350ms ease;
}
.role-row:focus-visible {
  outline: 1.5px solid var(--forest);
  outline-offset: -4px;
}
/* Revealed rows keep the tint transition only (they appear without a fade). */
.role-row.reveal-armed.in { transition: background-color 350ms ease; }
.role-row__head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.role-row__number {
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.12em;
  color: #4C564F;
}
.role-row__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 auto;
  transition: filter 350ms ease;
}
.role-row--primary .role-row__dot { background: var(--role-primary); }
.role-row--support .role-row__dot { background: var(--role-support); }
.role-row--balance .role-row__dot { background: var(--role-balance); }
.role-row--transport .role-row__dot { background: var(--role-transport); }
.role-label {
  font-family: var(--mono);
  font-style: normal;
  font-weight: 500;
  font-size: 15.5px;
  line-height: 1.2;
  color: var(--forest);
  text-transform: uppercase;
  letter-spacing: 0.13em;
  transition: filter 350ms ease;
}
.role-def {
  font-family: var(--sans);
  font-size: 18.5px;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0;
  color: #3E4A42;
  max-width: 560px;
  margin: 0 0 6px;
}
.role-examples {
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0;
  color: #56605A;
  max-width: 560px;
  margin: 0;
}
/* Hover and selected share one role-tinted wash. Hover applies only on
   hover-capable devices so touch taps leave no stuck tint. */
@media (hover: hover) and (pointer: fine) {
  .role-row--primary:hover { background-color: rgba(184, 46, 26, 0.03); }
  .role-row--support:hover { background-color: rgba(28, 92, 58, 0.04); }
  .role-row--balance:hover { background-color: rgba(122, 92, 48, 0.05); }
  .role-row--transport:hover { background-color: rgba(74, 64, 112, 0.04); }
}
/* Selected: a restrained wash (Primary's red is the strongest hue, so it gets
   the lightest value), distinguished mainly by the darkened dot and label
   below. */
.role-row--primary.is-selected { background-color: rgba(184, 46, 26, 0.035); }
.role-row--support.is-selected { background-color: rgba(28, 92, 58, 0.05); }
.role-row--balance.is-selected { background-color: rgba(122, 92, 48, 0.06); }
.role-row--transport.is-selected { background-color: rgba(74, 64, 112, 0.05); }
/* Verified: the washes alone sit at only 1.05–1.08:1 against the section
   ground, so selection also gets a thin inset rule in the role's own colour
   (all four are ≥3:1 on the ground). It is inset, so row size and text
   alignment do not change. */
.role-row--primary.is-selected   { box-shadow: inset 2px 0 0 var(--role-primary); }
.role-row--support.is-selected   { box-shadow: inset 2px 0 0 var(--role-support); }
.role-row--balance.is-selected   { box-shadow: inset 2px 0 0 var(--role-balance); }
.role-row--transport.is-selected { box-shadow: inset 2px 0 0 var(--role-transport); }
/* Selected rows darken the dot and role name (filter works on text and
   fill alike). */
.role-row.is-selected .role-row__dot,
.role-row.is-selected .role-label {
  filter: brightness(0.78);
}

/* ── 03 MODULE — RED-01 as an abstract composition: one flat plate (labels
   baked into the WebP) beside the copy. Never the physical tablet. ── */
.module-left { min-width: 0; }
/* Both groups are always block-level, giving the two-line reading at every
   width; "A module" is kept together with a non-breaking space. */
.module-headline span,
.module-headline em {
  display: block;
}
#s-module .system-body { max-width: 380px; }
.module-artwork { min-width: 0; }
#s-module .system-visual-stage {
  width: 100%;
  max-width: none;
  min-height: 0;
}
.module-plate-image {
  display: block;
  width: 100%;
  max-width: 440px;
  height: auto;
  margin: 0 auto;
}

/* ── 04 FINALE — closing line that hands off to the Palette. The CTA stays
   Forest Green, the sitewide action color. ── */
.system-finale {
  min-height: 78svh;
  display: flex;
  align-items: center;
  padding-block: clamp(100px, 11vw, 156px);
  border-top: 0.5px solid rgba(28, 51, 40, 0.07);
  scroll-snap-align: start;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
/* The id outranks .system-section + .system-section's border-top. */
#s-finale {
  border-top: 1px solid var(--system-divider);
}
/* Closing botanical pair: a small leaf branch top-left, a longer acerola
   branch bottom-right, behind the content. Positioning and sizing only; the
   source files are already color-graded. The right branch is anchored from
   the bottom, 8px up from the edge, so its lowest leaf is not cut off. */
.finale-botanical {
  position: absolute;
  display: block;
  height: auto;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
.finale-botanical-left {
  top: -8px;
  left: -6px;
  width: clamp(190px, 17vw, 285px);
}
.finale-botanical-right {
  bottom: 8px;
  right: -8px;
  width: clamp(360px, 27vw, 500px);
}
.system-finale-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}
@media (min-width: 769px) {
  .system-finale-inner {
    display: grid;
    grid-template-columns: var(--marker-col) minmax(0, 1fr);
    column-gap: var(--marker-gap);
    align-items: start;
  }
}
.system-finale-content {
  width: 100%;
  max-width: 1100px;
}
.system-finale__eyebrow {
  margin: 0 0 28px;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(28, 51, 40, 0.84);
}
.system-finale__title {
  max-width: 780px;
  margin: 0;
  font-family: var(--system-display);
  font-size: clamp(48px, 4vw, 64px);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--forest);
}
.system-finale .cta-link {
  display: flex;
  width: fit-content;
  margin-top: clamp(46px, 5vw, 64px);
  margin-left: clamp(180px, 29vw, 470px);
  font-size: 16px;
}

/* ══════════════════════════════════════════════════════════════════
   RESPONSIVE OVERRIDES
   Same hierarchy as index.css: 1200 desktop composition, 1024 finale
   artwork, 900 structural stack, 768 mobile type/padding, 700 and 480
   small-phone touch-ups. Later blocks intentionally win over earlier ones
   at equal specificity.
   ══════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  .finale-botanical-left {
    top: -6px;
    left: -6px;
    width: clamp(155px, 19vw, 220px);
  }
  .finale-botanical-right {
    bottom: 8px;
    right: -10px;
    width: clamp(290px, 34vw, 390px);
  }
}

/* ── ≤900px: all four numbered stages stack to one column; the Preface and
   Finale tighten their padding. ── */
@media (max-width: 900px) {
  /* Sections are content-height here (min-height:auto) and often taller than
     a phone screen, so snapping to their starts only fights reading. */
  html { scroll-snap-type: none; }

  .system-two-column,
  .node-content,
  .role-layout,
  .module-layout-simple { grid-template-columns: 1fr; gap: var(--system-stack-gap); }
  .system-visual-stage { min-height: 0; max-width: 260px; }

  /* The plate carries its labels in the raster, so it gets a wider cap than
     the Node/Module stages. */
  .botanical-note-image { min-height: 0; max-width: 520px; margin-inline: auto; }
  #s-node .system-visual-stage { max-width: min(100%, 620px); }

  /* Content-height at the phone floor (480px), growing to the desktop's
     full-screen cover (100svh) exactly at 901px, so neither 769px nor 901px
     steps the height, whatever the screen's aspect ratio. The first
     declaration is the fallback where tan()/atan2() are unsupported; the
     second turns (100vw − 768px) / 133px into a unitless 0–1 factor. */
  .system-preface {
    min-height: max(480px, min(100svh, calc(480px + (100vw - 768px) * 3.2)));
    min-height: max(480px, calc(480px + (100svh - 480px) * clamp(0, tan(atan2(100vw - 768px, 133px)), 1)));
  }
  .system-preface__title { max-width: none; }
  .system-preface__body { line-height: 1.58; }

  .system-sections .system-section {
    min-height: auto;
    padding-block: clamp(52px, 9vw, 68px);
  }
  .node-copy { max-width: none; }

  .system-finale { padding-block: var(--space-2xl); }
}

/* ── ≤768px: mobile type, padding, and artwork ── */
@media (max-width: 768px) {
  /* Finale padding between 701 and 768px; ≤700px sets its own below. */
  .system-finale { padding-block: clamp(72px, 12vw, 88px) 40px; }
  .system-inner,
  .system-finale-inner { padding-inline: var(--pad); }

  .system-preface__title { font-size: clamp(37px, 10.2vw, 44px); line-height: 1.1; margin-bottom: 34px; }
  .system-section-title,
  .role-headline,
  .module-headline { font-size: clamp(32px, 8.5vw, 40px); line-height: 1.1; margin-bottom: 20px; }
  .system-preface__eyebrow { font-size: 16px; margin-bottom: 28px; }

  /* Below 769px the chapter-marker grid is off, so each marker stacks above
     its headline. */
  .system-chapter-marker { margin-bottom: 32px; }
  .system-finale .system-chapter-marker { margin-bottom: 18px; }

  /* Preface artwork becomes a two-corner diagonal (top-left stem, bottom-
     right rosehip); the top-right and bottom-left crops are hidden. */
  .system-preface__botanical-layer .system-preface__corner--tr,
  .system-preface__botanical-layer .system-preface__corner--bl { display: none; }
  /* The rosehip is anchored to the bottom-right corner; the small rightward
     bleed crops only empty margin. It is not pushed down: the stem's tip
     reaches the artwork's bottom edge, so any downward shift (the previous
     8%, about 8–11px) clipped it against the section's bottom border. */
  .system-preface__corner--br {
    width: clamp(112px, 35vw, 175px);
    transform: translate(8%, 0);
  }

  /* Hero height follows its content here (small safety-net floor, no
     full-viewport minimum). */
  .system-preface > .system-inner {
    flex: none;
    justify-content: flex-start;
  }

  .system-body {
    font-size: 19px;
    line-height: 1.65;
    color: rgba(28, 51, 40, 0.88);
  }
  /* After .system-body (equal specificity) so the Preface keeps its own
     size and a narrower measure. */
  .system-preface__body {
    font-size: 20px;
    line-height: 1.58;
    max-width: 350px;
  }
  .desktop-break { display: none; }
  /* The intro keeps its authored three-line body copy at every width ≥375px. */
  .system-preface__body .desktop-break { display: inline; }

  .system-sections .system-section { padding-block: 64px; }

  /* Edge-to-edge section backgrounds: the layout wrapper's padding moves
     onto each section's own .system-inner. */
  .system-content-layout { padding-inline: 0; }
  .system-sections .system-inner { padding-inline: var(--pad); }

  /* Node and Module sit on a barely warmer white. */
  #s-node { background-color: #FBFAF7; }
  #s-module { background-color: #FBFAF7; }

  /* The Node diagram fills the phone width minus the page gutter; its
     stage drops the ≤900px cap so it can reach that width. Labels stroke
     in the section's background color. */
  #s-node .system-visual-stage { max-width: none; }
  .node-matrix {
    --nm-bg: #FBFAF7;
    width: calc(100vw - var(--pad) * 2);
    max-width: none;
    margin-inline: auto;
  }

  /* Both branches sit fully inside the section: the leaf branch hangs from
     the top-left corner (its stem still enters from the section's top edge)
     and the acerola branch rests in the bottom-right padding, clear of the
     CTA and the footer rule. Sized so the leaves end above the marker. */
  .finale-botanical-left {
    top: 0;
    left: 0;
    width: clamp(80px, 26vw, 112px);
  }
  .finale-botanical-right {
    top: auto;
    right: 0;
    bottom: 16px;
    width: clamp(88px, 26vw, 128px);
  }

  .role-label { font-size: 15px; }
  .role-row__number { font-size: 14px; }
  .role-def { line-height: 1.6; }
  .role-examples { line-height: 1.52; }
}

@media (max-width: 700px) {
  /* Content-driven Finale: top-aligned, no viewport-height minimum, so the
     section ends at the CTA. */
  .system-finale {
    min-height: 0;
    align-items: flex-start;
    padding-block: 88px 40px;
  }
  .system-finale__eyebrow { margin-bottom: 22px; }
  .system-finale__title {
    max-width: 100%;
    font-size: clamp(34px, 9.5vw, 44px);
  }
  .system-finale .cta-link {
    margin-top: 40px;
    margin-left: 0;
  }
}

@media (max-width: 600px) {
  .role-row { padding-block: clamp(14px, 4vw, 18px); }
}

@media (max-width: 480px) {
  /* Slightly smaller branch so its lower leaf clears the eyebrow label. */
  .system-preface__corner--tl { --tl-w: clamp(88px, 24vw, 96px); }
  .system-preface {
    padding-top: 108px;
    padding-bottom: 48px;
  }
}

@media (max-width: 374px) {
  /* The authored three-line break needs ~331px; on narrower phones it would
     leave one-word orphans, so the intro copy flows naturally instead. */
  .system-preface__body .desktop-break { display: none; }
}

/* ── ≥1200px desktop composition: the numbered stages share one grid. The
   copy column is 8.2em of the headline size (≈ the widest line, so the
   two-line breaks hold) and the art/list column is a fixed 540px track, so
   every visual hangs from one right-hand axis. The marker column and gap are
   shared by 00–03 and the 04 Finale. ── */
@media (min-width: 1200px) {
  :root {
    --marker-col: 124px;
    --marker-gap: clamp(36px, 3.4vw, 52px);
    --system-column-gap: clamp(72px, 6vw, 108px);
  }
  .system-two-column,
  .node-content,
  .role-layout,
  .module-layout-simple {
    grid-template-columns: calc(clamp(42px, 3.5vw, 58px) * 8.2) minmax(0, 540px);
    column-gap: var(--system-column-gap);
    justify-content: start;
  }
  /* The copy column is sized to the widest headline line at its weight
     (500) within a pixel or two, so the one-line Role headline stays on one
     line; any sub-3px overshoot falls into the column gap. */
  .role-headline { white-space: nowrap; }
}

/* Footer styles (including the divider) live in footer.css. */

.node-legend .nowrap { white-space: nowrap; }
