/* ─────────────────────────────────────────────────────────────
   sections.css — the narrative below the fold

   One band anatomy for every section: an eyebrow that numbers
   and names it, a display statement, a lede, then the section's
   own content. Hierarchy comes from spacing, type and alignment
   before it comes from borders — so almost nothing here is a card.
   ───────────────────────────────────────────────────────────── */

.band {
  position: relative;
  padding-block: var(--section-y);
}

/* The first band rises out of the signal field. It needs enough room above
   the type for the sheet's fade to finish before anything has to be read
   against it. */
.sheet > .band:first-child {
  padding-top: clamp(112px, 15vh, 208px);
}

.band--surface { background: var(--surface); }

/* The closing band. Paper at the top settling into Pale Sage, rather than a
   flat fill — and the top stop is not a decoration: the section above ends on
   paper, so starting here on the same value makes that boundary vanish
   instead of stepping. The footer below is Deep Forest, and THAT edge is
   meant to be an edge.

   Fifteen eased stops over the top half, not two. The distance from Warm
   Ivory to Pale Sage is short enough that a two-stop ramp bands visibly
   across a section this tall; easing the colour on evenly-spaced stops is the
   same construction the hero-to-problem ramp uses. sRGB first as the
   fallback, oklab second. */
.band--cta {
  background: linear-gradient(to bottom,
    var(--paper) 0, var(--surface) 52%);
  background: linear-gradient(to bottom in oklab,
    #F7F3EC 0,
    #F7F3EC 3.7%,
    #F7F3EC 7.4%,
    #F6F3EC 11.1%,
    #F5F2EC 14.9%,
    #F3F2EC 18.6%,
    #F2F2EC 22.3%,
    #F0F1EC 26.0%,
    #EEF0EB 29.7%,
    #ECF0EB 33.4%,
    #EAF0EB 37.1%,
    #E9EFEB 40.9%,
    #E8EFEB 44.6%,
    #E8EFEB 48.3%,
    #E8EFEB 52.0%);
}

/* ── Section head ─────────────────────────────────────────────
   Asymmetric: the statement takes the wide left column, the lede
   the narrow right one, and the two share a baseline grid rather
   than being stacked and centred.                                */
.section-head {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--space-5) clamp(32px, 5vw, 90px);
  align-items: end;
}

/* Stacked and centered rather than the shared two-column grid, matching
   #demonstration below: the ring diagram underneath is itself centered on
   the section, so a left-aligned two-column heading sitting above it read
   as two different layouts stacked on each other. One centered column over
   a centered diagram reads as one composition. (This also replaces the
   align-items:start override this used to carry — the two-column
   end-alignment mismatch it fixed no longer applies once the columns
   themselves are gone.) */
#how .section-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
}

#how .section-lede { margin-inline: auto; max-width: 46em; text-wrap: pretty; }

/* Stacked and centered rather than the shared two-column grid: the
   screenshot underneath is itself centered on the section (see
   demo.css/main.js's syncDemoHeight), and a left-aligned two-column
   heading sitting above a centered image read as two different layouts
   stacked on each other. One centered column over a centered image reads
   as one composition. */
#demonstration .section-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
}

/* Wider than the shared 34em: at that measure the lede wraps to three
   lines, which (stacked under the title rather than beside it, see above)
   adds a full line's worth of height to the section's fixed overhead and
   leaves that much less room for the screenshot below — see main.js's
   syncDemoHeight. 46em holds it to two lines at the sizes this renders at. */
#demonstration .section-lede { margin-inline: auto; max-width: 46em; }

/* Smaller than the shared .section-title/.section-lede sizes, scoped to
   this section only: the ring diagram right below has to share the
   viewport with this heading (see main.js's syncCycleRing), and a smaller
   heading frees real height that gets spent as top padding instead — see
   PAD_TOP_MIN there. */
#how .section-title { font-size: clamp(28px, 3.4vw, 46px); }
#how .section-lede { font-size: var(--t-body); line-height: 1.6; }

/* Same move, same reason, for the demonstration section: the screenshot
   below is now a modest, framed image (see demo.css/main.js's
   syncDemoHeight) rather than a full-bleed panel, and the full-size
   .section-title/.section-lede pair reads oversized next to it. */
#demonstration .section-title { font-size: clamp(28px, 3.4vw, 46px); }
/* text-wrap: pretty avoids single-word orphan lines — this lede was
   ending with "own." alone on its own line. Centered text makes an orphan
   more visible than left-aligned copy does (there's no ragged edge to
   camouflage it against), which is why this gets it and the shared
   .section-lede doesn't. */
#demonstration .section-lede {
  font-size: var(--t-body);
  line-height: 1.6;
  text-wrap: pretty;
}

.section-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(34px, 4.3vw, 62px);
  line-height: 1.03;
  letter-spacing: clamp(-1.5px, 0.55px - 0.14vw, -0.4px);
  font-optical-sizing: auto;
  color: var(--ink);
  text-wrap: balance;
}

.section-title em {
  font-style: italic;
  color: var(--signal);
}

/* The second line of a two-part statement, set italic and a step down —
   the same relationship the hero uses. */
.section-title span {
  display: block;
  font-style: italic;
  font-size: 0.88em;
}

.section-lede {
  margin: 0;
  max-width: 34em;
  font-size: var(--t-lede);
  line-height: 1.55;
  color: var(--ink-soft);
}

/* The noise-to-signal field now lives in css/problem.css. It is driven by
   scroll progress rather than a one-shot reveal, so the rules that used to
   sit here would have fought it — and worse, their `.figure.is-in` activator
   no longer exists, which would have pinned the signal permanently hidden. */

/* ── The loop ─────────────────────────────────────────────────
   Six stages on one rule. The rule is a border on each stage
   rather than a line behind the row, so it stays continuous
   when the grid rewraps — and column gaps become padding for
   the same reason.                                              */
.loop {
  display: grid;
  /* 3x2, not 6x1. At six columns the text track measured 197px — 21-25
     characters a line, and narrower at 1440 than it was at 1024, because the
     breakpoint promoted 3→6 exactly when the copy stopped fitting. At three
     the row break lands between Recommendation and Decision, which is where
     the copy says the turn is. This is the FALLBACK now: the ring takes over
     at 940 and up, so the three-column grid only ever renders between 761 and
     939, where the track measures ~260px / ~30 characters. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: var(--gap-block) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: stage;
}

.loop__stage {
  position: relative;
  border-top: 1px solid var(--rule);
  padding: var(--space-4) clamp(12px, 1.6vw, 26px) var(--space-5) 0;
}

.loop__stage::before {
  content: "";
  position: absolute;
  top: -3.5px;
  left: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: inset 0 0 0 1.5px var(--signal-soft);
}

/* Newsreader, not Inter. These are the names of the six stages — the same
   register as the section title above them and the sentence in the middle of
   the ring — and setting them in the functional face made the diagram change
   voice from its own heading.

   Sentence case with normal tracking, not uppercase with 0.13em. The tracked
   all-caps label is an Inter idiom; carried onto a serif at this size it reads
   as a small-caps costume rather than as a name. */
.loop__name {
  margin: 0 0 10px;
  font-family: var(--font-display);
  font-size: clamp(17px, 2.1vw, 20px);
  font-weight: 400;
  letter-spacing: -0.005em;
  color: var(--ink);
}

/* --signal-ink rather than --signal: Eucalyptus reads 4.54:1 on this band
   against a 4.5 requirement, and these numerals are small. */
.loop__name::before {
  counter-increment: stage;
  content: counter(stage, decimal-leading-zero) " ";
  color: var(--signal-ink);
  font-variant-numeric: tabular-nums;
}

.loop__body {
  margin: 0;
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 900px) {
  .section-head { align-items: start; }
}

@media (max-width: 760px) {
  .loop { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* One column below the width where two tracks stop being readable. The same
   argument as the 3x2 note above, at the other end: two tracks measure 18.5
   characters at 390px and 14.5 at 320 — narrower than the six-column layout
   this section already rejected. The cut is at 600 rather than at the nav's
   520 because two tracks are still only 25-28 characters between them. */
@media (max-width: 600px) {
  .loop { grid-template-columns: minmax(0, 1fr); }
}

/* ── The cycle ────────────────────────────────────────────────
   Six stages on a ring rather than in a 3x2 grid. The grid could
   list the stages in order but it could not show that the sixth
   returns to the first, which is the claim the section makes.
   The return is carried by the six chevrons: with no closing arc
   and no moving highlight, they are the only thing stating which
   way the cycle turns, which is why they sit at every arc
   midpoint rather than once or twice for decoration.

   The full label-on-ring diagram only assembles at 940px and up,
   where there is room for six names around the circle without
   colliding — below that the stage list falls back to the plain
   stacked grid it always had. But the ring graphic itself (track,
   nodes, direction chevrons — no text) is cheap to show at any
   size and is the one thing that actually SHOWS "this is a cycle"
   rather than asserting it in a heading, so a small static copy of
   it sits above the stacked list from 939px down to 601px. Below
   that — true single-column phone width — the spine below replaces
   it instead: a ring sitting over an unrelated vertical list read as
   two disconnected things, where the spine runs through the list
   itself. */
.cycle__ring {
  display: block;
  width: min(200px, 52vw);
  height: min(200px, 52vw);
  margin: 0 auto var(--space-5);
  overflow: visible;
}

/* Colour lives here, shared by the small mobile ring and the large
   positioned one the 940px block below resizes and repositions —
   duplicating it per breakpoint would drift the two out of sync. */
.cycle__track {
  stroke: var(--signal);
  stroke-width: 1.5;
}

.cycle__flow path {
  stroke: var(--signal);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.cycle__node {
  fill: var(--signal);
  stroke: var(--signal);
  stroke-width: 1.8;
}

/* The stacked fallback still needs the sentence, and it belongs where
   the original footnote had it. */
.cycle__hub {
  max-width: 62ch;
  margin: var(--space-5) 0 0;
  font-family: var(--font-display);
  font-size: clamp(19px, 1.5vw, 23px);
  line-height: 1.35;
  color: var(--ink);
}
.cycle__hub em { font-style: italic; color: var(--signal-ink); }

/* Mobile keeps the stage names so the list still reads as six named
   steps, but drops each one's explanatory sentence — the ring above
   plus the closing "each cycle..." line already carry what the loop
   is and why it repeats, and six paragraphs of supporting copy is the
   part of this diagram that most crowds a phone screen. */
@media (max-width: 939px) {
  .loop__body { display: none; }
  .loop__name { margin-bottom: 0; }
  .loop__stage { padding-bottom: var(--space-4); }
}

/* ── Zigzag stepper (single-column phone width only) ─────────
   Below 940px the list falls back to a 3x2 or 2x1 grid before it goes to
   one column at 600px — a stepper reads as a single sequence, so this only
   replaces the small ring from exactly that width down, not the whole
   sub-940 range.

   Earlier passes tried a hairline "spine" down the left edge, then a
   left-aligned badge-and-line stepper — both put every stage's text in
   the same column, which is legible but reads as a plain list with
   decoration bolted on. This centres the line and badges instead and
   alternates each stage's text left/right of it, the classic infographic
   timeline — plus a short, phone-specific line of copy per stage, since
   the full sentence doesn't fit a half-width column. */
@media (max-width: 600px) {
  .cycle__ring { display: none; }

  .loop { padding-left: 0; }

  .loop__stage {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 30px 1fr;
    column-gap: 14px;
    align-items: center;
    border-top: none;
    padding-block: var(--space-4);
  }

  /* The connecting line: one segment per stage stacking into a continuous
     line down the centre column, the same way the left-aligned version
     stacked its segments — see the badge-and-line stepper this replaced.
     Absolutely positioned rather than a grid item, so it isn't affected by
     which side .loop__content is on. */
  .loop__stage::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 1.5px;
    /* Resets the shared rule's fixed 7px height (sized for the small dot
       used at wider breakpoints) — left in place, it wins over `bottom: 0`
       and the line never stretches past 7px. */
    height: auto;
    border-radius: 0;
    box-shadow: none;
    transform: translateX(-50%);
    background: var(--rule-strong);
    z-index: 0;
  }
  .loop__stage:first-child::before { top: 50%; }
  .loop__stage:last-child::before { bottom: 50%; }

  /* The badge. counter-increment moved here from .loop__name::before
     (suppressed below) since this is now the pseudo-element guaranteed to
     render at this breakpoint. */
  .loop__stage::after {
    counter-increment: stage;
    content: counter(stage, decimal-leading-zero);
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--signal);
    color: var(--paper);
    font-size: 13px;
    font-weight: 600;
  }

  /* Alternating sides: odd stages sit left of the line (text hugging it,
     right-aligned), even stages sit right (left-aligned, the natural
     direction) — the zigzag that makes this read as a timeline rather
     than a centred list. */
  .loop__content { grid-column: 1; text-align: right; }
  .loop__stage:nth-child(even) .loop__content { grid-column: 3; text-align: left; }

  /* The badge now carries the number; the inline "01 " prefix would
     duplicate it right next to the circle that already shows it.
     content:none suppresses this pseudo-element entirely, which is also
     why its own counter-increment (in the shared rule above) safely does
     nothing here — see .loop__stage::after taking over that job. */
  .loop__name::before { content: none; }

  .loop__body { display: none; }
  .loop__body--short {
    display: block;
    margin: 4px 0 0;
    font-size: var(--t-sm);
    line-height: 1.5;
    color: var(--ink-soft);
  }

  /* Matches the rest of the section at this width — the heading, the
     stepper and now the closing line all share the same centred axis. */
  .cycle__hub {
    margin-inline: auto;
    text-align: center;
  }
}

@media (min-width: 601px) {
  .loop__body--short { display: none; }
}

@media (min-width: 940px) {
  .cycle {
    /* Full measure, matching the section head above it. The ring used to be
       capped at 860px inside a 1320px band, which read as a diagram that had
       been dropped into the column rather than one built for it.

       --ring is the circle's RADIUS, and every other number here derives from
       it, so the whole diagram scales as one object. */
    --ring: clamp(210px, 21vw, 300px);
    --lw: clamp(180px, 16vw, 256px);

    position: relative;
    width: 100%;
    /* +380, not +300. The six labels are absolutely positioned, so the box
       has to be told how tall they make the diagram. The bottom label is the
       tallest — at 1024 its copy wraps to five lines in a 180px column — and
       at +300 it hung past the container's edge into the section below. */
    height: calc(var(--ring) * 2 + 380px);
    margin: var(--gap-block) auto 0;

  }

  /* A medium green radiating out of the ring. Sized off --ring so the falloff
     always lands in the same place relative to the circle, and kept under the
     labels — a wash that dims the copy it sits behind is a decoration that
     costs content. */
  .cycle::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 0;
    width: calc(var(--ring) * 4);
    height: calc(var(--ring) * 4);
    transform: translate(-50%, -50%);
    border-radius: 50%;
    /* Strictly outside the ring. The box is 4x the radius, so the ring's own
       edge falls at exactly 1/2 = 50% of it — the wash is held at zero until
       that stop and only then begins, which leaves the disc itself clean and
       makes the green read as light coming OFF the circle rather than filling
       it.

       It reaches full strength AT that stop rather than ramping up to it. An
       earlier version eased in over 5.4% of the box, which was ~29px of pale
       band sitting between the stroke and the green and read as a gap the line
       had been cut out of. The step is now 0.4% wide and lands under the 1.5px
       stroke, so the green starts exactly at the line and only falls off
       outward.

       Seven stops across a 4x box rather than five across a 3.6x one: the wash
       fades over ~294px instead of ~223px, at a gentler rate. 4x is the
       ceiling — at the 940px breakpoint the diagram's column is only ~860px
       wide, and a wider box would push the page into horizontal scroll.

       A lighter, fresher green than Soft Sage, which composited to a chroma of
       18 over this band — a grey with a hint of green in it rather than a
       green. This is chroma 35 at the same lightness, so it reads as colour
       without getting darker. Verified against all three things that sit on
       it: body copy, the stage names, and the ring. */
    background: radial-gradient(closest-side,
      rgba(127, 199, 166, 0)    0%,
      rgba(127, 199, 166, 0)    49.8%,
      rgba(127, 199, 166, 0.40) 50.2%,
      rgba(127, 199, 166, 0.33) 59%,
      rgba(127, 199, 166, 0.24) 68%,
      rgba(127, 199, 166, 0.15) 78%,
      rgba(127, 199, 166, 0.07) 88%,
      rgba(127, 199, 166, 0)    99%);
    pointer-events: none;
  }

  .cycle__ring {
    display: block;
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 1;
    /* The circle is r=210 in a 600 viewBox, so the box is 600/210 of the
       radius. Sizing the box from --ring keeps the drawn circle exactly
       --ring across however the box is scaled. */
    width: calc(var(--ring) * 600 / 210);
    height: calc(var(--ring) * 600 / 210);
    transform: translate(-50%, -50%);
    overflow: visible;
  }

  /* Colour (stroke/fill for track, flow chevrons and nodes) is shared with
     the small mobile ring and lives above, outside this block — 3:1 against
     the glow per 1.4.11, verified once rather than twice. */

  /* The diagram is static. Nothing is lost by that: the six chevrons carry
     the direction on their own, and a still figure is legible from the first
     frame rather than only after watching it for a turn. */

  .cycle__hub {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 2;
    width: min(23ch, calc(var(--ring) * 1.42));
    max-width: none;
    margin: 0;
    transform: translate(-50%, -50%);
    text-align: center;
    /* Off --ring, not vw: when JS shrinks --ring to fit a short viewport
       (see main.js's syncCycleRing), the ring's own type has to shrink with
       it or a small circle ends up carrying oversized text. Also lower than
       the old vw-derived sizes at their own top end (24px, now 21px) — a
       smaller hub sentence needs a smaller --ring to sit comfortably inside
       it, which is what buys the extra top/bottom breathing room around the
       whole diagram (see FIXED_REACH in main.js). */
    font-size: clamp(15px, calc(var(--ring) * 0.07), 21px);
    line-height: 1.38;
    letter-spacing: -0.005em;
    text-wrap: balance;
  }

  .cycle .loop {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 2;
    margin: 0;
  }

  .cycle .loop__stage {
    position: absolute;
    width: var(--lw);
    transform: translate(-50%, -50%);
    border: 0;
    padding: 0;
  }
  .cycle .loop__stage::before { content: none; }

  /* Seats derived from --ring rather than from percentages of the box.
     The side labels clear the circle at its WIDEST point — inner edge at
     --ring + 40px — so the clearance holds at every height the label spans,
     which a single-radius circular arrangement does not. Their vertical
     centres sit at 0.5r, which is exactly sin(30deg): the 2, 4, 8 and 10
     o'clock nodes. */
  .cycle .loop__stage:nth-child(1),
  .cycle .loop__stage:nth-child(4) { left: 50%; text-align: center; }
  .cycle .loop__stage:nth-child(1) { top: calc(50% - var(--ring) - 88px); }
  .cycle .loop__stage:nth-child(4) { top: calc(50% + var(--ring) + 88px); }

  .cycle .loop__stage:nth-child(2),
  .cycle .loop__stage:nth-child(3) {
    left: calc(50% + var(--ring) + 40px + var(--lw) / 2);
    text-align: left;
  }
  .cycle .loop__stage:nth-child(5),
  .cycle .loop__stage:nth-child(6) {
    left: calc(50% - var(--ring) - 40px - var(--lw) / 2);
    text-align: right;
  }
  .cycle .loop__stage:nth-child(2),
  .cycle .loop__stage:nth-child(6) { top: calc(50% - var(--ring) * 0.5); }
  .cycle .loop__stage:nth-child(3),
  .cycle .loop__stage:nth-child(5) { top: calc(50% + var(--ring) * 0.5); }

  .cycle .loop__name {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 8px;
  }
  .cycle .loop__stage:nth-child(1) .loop__name,
  .cycle .loop__stage:nth-child(4) .loop__name { justify-content: center; }
  .cycle .loop__stage:nth-child(5) .loop__name,
  .cycle .loop__stage:nth-child(6) .loop__name { justify-content: flex-end; }

  /* Off --ring rather than vw, for the same reason as .cycle__hub above:
     when JS shrinks --ring to fit a short viewport, or grows it back on a
     tall one, the label text has to move with it — a small ring paired
     with vw-sized (viewport-only) text either overruns a small ring or
     reads as a tiny caption beside a large one. The name still has to
     outweigh its own body copy (0.072 vs 0.052 — the same ratio the old
     18-24px/15.5-18px pair held), and the whole pair is a shade smaller
     than that old pair so the label's own footprint takes less of the
     ring's vertical reach, which is what funds the extra breathing room
     FIXED_REACH gives the diagram in main.js. */
  .cycle .loop__name {
    font-size: clamp(16px, calc(var(--ring) * 0.072), 22px);
  }

  .cycle .loop__body {
    font-size: clamp(14px, calc(var(--ring) * 0.052), 16.5px);
    line-height: 1.55;
    text-wrap: pretty;
  }
}
