/* ==========================================================================
   See More Leadership Group
   Hybrid direction per the 05 Aug feedback brief:

     structure + content ....... Design 2 (flagship)
     visual treatment .......... Design 1 (light, Brand Bible palette)
     layout .................... alternating left / right
     colour .................... predominantly white, blue accent, tan sparing
     motion .................... restrained
     focus ..................... the reader, not Stewart

   ========================================================================== */

/* --- Tokens --------------------------------------------------------------
   Brand Bible palette. Blue carries the emphasis; tan appears only on
   section indices and hairlines so it never dominates the interface.
   ------------------------------------------------------------------------ */
:root {
  --paper: #f9f8f4;
  --white: #ffffff;
  --paper-warm: #f4f2ec;

  --blue: #013ca4;
  --blue-deep: #012a73;
  --blue-ink: #0b1f3f;

  /* Tan is now marks and graphics only: the hero's flanking rules, the
     Friction to Flow rail, the quote glyph, the footer bar. The darker
     --tan-text grade it needed as label type is gone with the tan labels. */
  --tan: #b67c2f;

  --text: #181c25;
  --body: rgba(24, 28, 37, 0.75);
  /* Darkened from #6e6e7a, which measured 4.49:1 on the warm surface and
     missed AA by a hair. This grade passes on paper, warm and white. */
  --grey: #63636f;
  --line: rgba(24, 28, 37, 0.1);
  --line-soft: rgba(24, 28, 37, 0.06);

  /* The pale rung of the blue family. It was already being asked for by
     `.offer--lead` and `.slot.is-on` but had never been defined, so both
     resolved to an invalid value and lost their background entirely: the free
     Offerings tier read as an ordinary third column, and a selected time slot
     showed only its border. */
  --blue-tint: #eef1f9;

  /* Accent foreground, as a role rather than a colour. It is --blue on light
     ground and a pale blue on the inverted sections, so a rule that means
     "this text is the accent" no longer has to know which surface it is on.
     --blue on --blue measures 1:1, which is what made this necessary. */
  --accent: var(--blue);

  /* Hover surface and the emphasised hairline, also as roles. The price rows
     hard-coded a white wash, which is invisible on anything but the solid
     blue panel they happened to be on. */
  --wash: rgba(24, 28, 37, 0.03);
  --rule-hi: rgba(24, 28, 37, 0.22);

  --serif: "Playfair Display", Georgia, serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --container: 75rem;
  --header-h: 4.75rem;
  /* The floating capsule at rest: its own height, and the gap between it
     and the top of the viewport. Both collapse on scroll. */
  --cap-h: 3.875rem;
  --cap-gap: clamp(0.75rem, 1.7vw, 1.375rem);
  /* Tightened from clamp(72px, 9vw, 132px). The vertical rhythm was the
     largest single source of the white space: nine sections on the
     homepage at 132px top and bottom is 2,376px of padding alone. */
  --section-y: clamp(3.25rem, 6.4vw, 6rem);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

html {
  scroll-behavior: smooth;
  /* Anchor targets clear the fixed header. */
  scroll-padding-top: var(--header-h);
  /* Was on `body`. There it made body a scroll container, which silently
     broke `position: sticky` for every descendant, including the pinned
     Friction to Flow stage. On the root element the overflow propagates to
     the viewport instead, so horizontal overflow is still clipped and the
     viewport stays the scrollport that sticky needs. */
  overflow-x: hidden;

  /* --- Proportional scaling above the design width -------------------
     The site is drawn at 1440. Above that it used to stop growing: the
     container was a fixed 1200px and 70 of 81 vw clamps had already hit
     their ceiling by 1440, so a 1920 monitor showed 1200px of content in a
     360px-either-side gutter, and 73 of 96 font sizes never moved at all.

     Every length in this file is now rem, so this one declaration scales
     the whole page. 1.1111vw is exactly 16px at 1440, which means nothing
     at or below the design width changes by even a subpixel; from 1440 to
     1920 everything grows in step, and it stops there so very large
     displays do not get absurd type.

     The floor and ceiling are rem, not px, on purpose: on the root element
     rem resolves against the browser's own default, so a reader who has set
     20px type keeps it and still gets the scaling. A px floor would have
     silently overridden that preference.

     Breakpoints stay in px, since those are viewport questions and must not
     move when the root does. Hairlines and small radii stay in px too, so a
     1px rule stays a 1px rule at every size.
     ------------------------------------------------------------------- */
  font-size: clamp(1rem, 1.1111vw, 1.3333rem);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

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

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

h1,
h2,
h3,
h4,
p,
figure,
blockquote {
  margin: 0;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

::selection {
  background: var(--blue);
  color: #fff;
}

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

/* --- Layout -------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
}

/* Not every section wants the same measure. Varying the container is half of
   what stops a page reading as one template applied nine times. */
.wrap--tight {
  max-width: 58.75rem;
}

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

/* Alternating surface. Every second block sits on the warmer paper so the
   page has banding without introducing a second hue. */
.section--warm {
  background: var(--paper-warm);
  border-block: 1px solid var(--line-soft);
}

/* --- Solid blue sections ------------------------------------------------
   Note for the record: Stewart's brief asks for "predominantly white, blue
   accent", and this deliberately goes past that on instruction. Ten sections
   across the six pages are now solid --blue.

   It works by redefining the neutral tokens rather than overriding a list of
   selectors. Everything inside inherits the inverted set, so a component
   dropped into a blue section is correct without knowing it moved, and the
   dozens of rules that reference --text, --body, --grey and --line need no
   blue-specific twin. --paper is remapped too, because several gradients and
   feathers are built from it and would otherwise punch light holes through
   the panel.

   Every rung was measured against #013ca4:
     white           9.62:1      --accent #cfe0ff   7.22:1
     --body 0.86     7.50:1      --grey 0.66        5.04:1
   All well clear of AA, and the quiet rung has room to go quieter if needed.
   ------------------------------------------------------------------------ */
/* NAVY VARIANT: every solid blue-section panel now uses --blue-ink #0b1f3f
   instead of --blue #013ca4, sitewide, across all 8 instances. Contrast only
   improves versus what was measured against #013ca4 -- the audit's numbers
   are the conservative floor, not the actual ratio here.

   .bookhero deliberately keeps brand blue: its own comment records that
   --blue-ink was tried there already and rejected, reading "near-black"
   rather than on-brand at full-bleed hero scale. Not reversed here. */
.section--blue {
  background: var(--blue-ink);
  color: var(--white);

  --text: #ffffff;
  --body: rgba(255, 255, 255, 0.86);
  --grey: rgba(255, 255, 255, 0.66);
  --line: rgba(255, 255, 255, 0.2);
  --line-soft: rgba(255, 255, 255, 0.12);
  --paper: #013ca4;
  --paper-warm: #012a73;
  --accent: #cfe0ff;
  --wash: rgba(255, 255, 255, 0.04);
  --rule-hi: rgba(255, 255, 255, 0.28);
}

/* The pill would be --blue on --blue inside these, so it reverses. Done by
   setting the component's own tokens, so the markup never has to carry
   .btn--light and no rule here has to compete with the component. */
.section--blue .btn {
  --btn-bg: var(--white);
  --btn-fg: var(--blue-ink);
  --btn-bg-hover: var(--blue-tint);
  box-shadow: none;
}

/* --tan measures 2.71:1 on blue and fails, so the marks that carry it step
   up to the accent rung instead. */
.section--blue .voice__mark,
.section--blue .hero__eyebrow .r,
.section--blue .brandmark {
  color: var(--accent);
  border-color: var(--accent);
}

/* --- Light islands inside an inverted section ---------------------------
   Inverting the tokens on the section is what makes the blue surface work,
   but it cascades into descendants that set their own LIGHT background and
   are therefore still light. `--white` is deliberately not remapped above,
   so those keep their pale ground while inheriting white text: on
   `.stand__col--against` that meant white on white, and the whole "what we
   stand against" column rendered blank. Its cross marks survived only
   because their stroke is a hard-coded hex in the markup, which is exactly
   what pointed at the cause.

   So the light set is re-asserted on every component that owns a light
   ground. Listed rather than inferred, because CSS cannot ask "is my
   background light" -- and stated once here, so any of these dropped into a
   blue section is correct without a second per-component rule. `:is()` keeps
   this at two classes of specificity, below the component rules it feeds.

   Cards only. The booking form's controls own a light ground too, but the
   form is deliberately not on a blue panel -- inputs, labels and focus states
   on solid colour are a usability question, not a styling one, and this is
   the conversion page. Listing them here would be dead code.
   ------------------------------------------------------------------------ */
.section--blue :is(
  .stand__col--against,
  .case,
  .offer,
  .voice,
  .ff__item,
  .post
) {
  --text: #181c25;
  --body: rgba(24, 28, 37, 0.75);
  --grey: #63636f;
  --line: rgba(24, 28, 37, 0.1);
  --line-soft: rgba(24, 28, 37, 0.06);
  --paper: #f9f8f4;
  --paper-warm: #f4f2ec;
  --accent: var(--blue);
  --wash: rgba(24, 28, 37, 0.03);
  --rule-hi: rgba(24, 28, 37, 0.22);
  color: var(--text);
}

/* --- Type ---------------------------------------------------------------- */
/* The label layer, quietened.

   Every label on the page was weight 500, uppercase and tracked at 0.14 to
   0.16em, and three of them were tan. That combination made the labels
   compete with the headings they were supposed to introduce. They are now
   weight 400 on tighter tracking, and the label text is grey rather than
   tan; tan is kept for actual marks and graphics, which is what the brief
   means by an accent. */
.idx {
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey);
}

h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.08;
  text-wrap: balance;
}

/* A default measure so headline wrapping is a stylesheet decision rather
   than an inline one on every instance. Overridden where a section needs a
   different break (.closing h2, .hero h1). */
h2 {
  font-size: clamp(1.9rem, 4vw, 3rem);
  max-width: 21ch;
}

.em {
  font-style: italic;
  font-weight: 400;
}

.accent {
  color: var(--accent);
}

/* --- Button -------------------------------------------------------------
   One component, four modifiers, no page-specific variants. Buttons were
   drifting: `.offer__btn` and `.details__go` had grown their own layout and
   disabled rules inside the Offerings and Booking blocks, which meant three
   places to change if a button ever changed. Those are now --push and
   --block on the component itself.

   Composition:
     .btn              the component; blue fill, pill, sentence-case label
     .btn--sm          header and inline use
     .btn--lg          a page's single primary action
     .btn--light       reversed, for placing on a dark surface
     .btn--block       fills its container's width
     .btn--push        sticks to the foot of a flex column
     :disabled         handled here, not per page

   Sizes and variants are independent: --lg --light --block all compose.
   ------------------------------------------------------------------------ */
.btn {
  /* The surface it sits on retints it by setting these, rather than by trying
     to out-specify the rule below. See the note on that rule. */
  --btn-bg: var(--blue);
  --btn-fg: var(--white);
  --btn-bg-hover: var(--blue-deep);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  background: var(--btn-bg);
  border: 1px solid var(--btn-bg);
  border-radius: 999px;
  padding: 1rem 1.75rem;
  font-family: var(--sans);
  font-size: 0.90625rem;
  font-weight: 500;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.22s ease, border-color 0.22s ease,
    transform 0.22s ease, box-shadow 0.22s ease;
}

/* Stated across the link states because an element-qualified `a` colour
   further down the sheet would otherwise win on source order.

   And it has to read a token rather than a value, because that state list is
   what broke the reversed pill on blue. `.btn:visited` and `.btn:focus` are
   both 0,2,0 -- identical to a `.section--blue .btn` override -- and they sit
   149 lines later, so source order handed it back to white and the label
   vanished into the white pill. Only once the link had been visited, or while
   it held focus, which is why it looked correct the first time and blank the
   second. A token set by the surface is not a specificity contest, so this
   cannot recur for any future surface either. */
.btn,
.btn:hover,
.btn:visited,
.btn:focus {
  color: var(--btn-fg);
}

.btn:hover {
  background: var(--btn-bg-hover);
  border-color: var(--btn-bg-hover);
  transform: translateY(-1px);
  box-shadow: 0 0.375rem 1.125rem rgba(1, 60, 164, 0.2);
}

/* --- Sizes --- */
.btn--sm {
  padding: 0.6875rem 1.25rem;
  font-size: 0.84375rem;
}

/* A page's single primary action, with a soft cast so it holds up when it is
   sitting on a photograph. */
.btn--lg {
  padding: 1.1875rem 2.125rem;
  font-size: 0.9375rem;
  box-shadow: 0 0.625rem 1.875rem rgba(1, 60, 164, 0.22);
}

.btn--lg:hover {
  box-shadow: 0 0.875rem 2.25rem rgba(1, 60, 164, 0.28);
}

/* --- Variants --- */
/* Reversed, for a dark ground: a blue button on --blue-ink has almost no edge
   against its own background. Declared after the colour pinning above, on
   purpose: both are one class deep, so source order decides, and with this
   first the pinned white won and the label vanished into the fill. */
/* Colour is pinned across every state, and it has to include :hover: without
   it `.btn:hover` above is two classes deep against this one and repaints the
   label white on a near-white fill. Fill and border are then set once for the
   resting state and once for hover, so no property is declared twice. */
/* Three tokens, where this was three rules and its own four-state colour
   list. It carried exactly the same latent fault as the component: anything
   trying to retint a --light pill would have lost to `.btn--light:visited`.
   It is used in the footer of all six pages, so that was worth closing too. */
.btn--light {
  --btn-bg: var(--white);
  --btn-fg: var(--blue-ink);
  --btn-bg-hover: var(--paper);
}

.btn--light:hover {
  box-shadow: 0 0.625rem 1.875rem rgba(0, 0, 0, 0.24);
}

/* --- Layout modifiers --- */
.btn--block {
  width: 100%;
}

/* Sits at the foot of a flex column, so a row of cards keeps its buttons on
   one line however long the copy above them runs. */
.btn--push {
  margin-top: auto;
}

/* --- State --- */
.btn:disabled,
.btn[aria-disabled="true"] {
  background: rgba(1, 60, 164, 0.32);
  border-color: transparent;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn:disabled:hover,
.btn[aria-disabled="true"]:hover {
  background: rgba(1, 60, 164, 0.32);
  border-color: transparent;
  transform: none;
  box-shadow: none;
}

/* --- Scroll progress ----------------------------------------------------
   A 2px rule across the top, scaled from the page's scroll position. Above
   the header so it is never covered, and pointer-events off so it cannot
   intercept a click on the capsule beneath it.
   ------------------------------------------------------------------------ */
.progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 80;
  pointer-events: none;
  background: transparent;
}

.progress__bar {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--blue) 0%, var(--tan) 100%);
  transform: scaleX(0);
  transform-origin: left center;
}

/* --- Header ---------------------------------------------------------------
   Two states from one element. At rest it is a floating capsule over the
   hero photograph; once scrolled it flattens into the full-width bar the
   rest of the page needs. Only the geometry animates, so the transition
   costs nothing.
   ------------------------------------------------------------------------ */
.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  padding-top: var(--cap-gap);
  border-bottom: 1px solid transparent;
  transition: padding-top 0.34s var(--ease), background 0.3s ease,
    border-color 0.3s ease;
}

.header.is-stuck {
  padding-top: 0;
  background: rgba(249, 248, 244, 0.88);
  backdrop-filter: saturate(180%) blur(0.875rem);
  -webkit-backdrop-filter: saturate(180%) blur(0.875rem);
  border-color: var(--line-soft);
}

.header__cap {
  position: relative;
  height: var(--cap-h);
  display: flex;
  align-items: center;
  gap: 1.625rem;
  /* Asymmetric: the wordmark needs breathing room from the capsule edge,
     the pill button only needs its own 10px. */
  padding: 0 0.625rem 0 1.375rem;
  border: 1px solid rgba(255, 255, 255, 0.68);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: saturate(150%) blur(1rem);
  -webkit-backdrop-filter: saturate(150%) blur(1rem);
  box-shadow: 0 0.625rem 2.125rem rgba(24, 28, 37, 0.07);
  transition: height 0.34s var(--ease), padding 0.34s var(--ease),
    border-radius 0.34s var(--ease), background 0.3s ease,
    border-color 0.3s ease, box-shadow 0.3s ease;
}

.header.is-stuck .header__cap {
  height: var(--header-h);
  padding: 0;
  border-radius: 0;
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.logo img {
  height: 1.625rem;
  width: auto;
}

/* --- Phone: the mark only ------------------------------------------------
   The lockup is 508x84 and the mark ends at x=126, so it is the first 24.8%
   of the image. Constraining the box to the mark's own 1.5:1 ratio and letting
   `cover` crop from the left shows the mark alone -- no second asset, no extra
   request, and the file is already in cache from the header.

   Saves 118px of header width at this size, which is what lets the capsule
   hold the toggle and the Book pill without crowding.
   ------------------------------------------------------------------------ */
@media (max-width: 560px) {
  .logo img {
    width: 2.4375rem;
    object-fit: cover;
    object-position: left center;
  }
}

/* Links group left beside the wordmark; the pill is pushed to the far
   edge. `flex: 1` is what does the pushing, so the mobile rules that hide
   the links leave the pill exactly where it was. */
.nav {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 1.625rem;
}

.nav .btn {
  margin-left: auto;
}

.nav a:not(.btn) {
  position: relative;
  font-size: 0.90625rem;
  color: var(--grey);
  white-space: nowrap;
  transition: color 0.2s ease;
}

.nav a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.3125rem;
  height: 1px;
  background: var(--blue);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.28s var(--ease);
}

.nav a:not(.btn):hover {
  color: var(--text);
}

.nav a:not(.btn):hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  padding: 0.5rem;
  cursor: pointer;
  color: var(--text);
}

/* --- Hero ----------------------------------------------------------------
   Centred stack over a full-bleed plate: capsule nav above, headline,
   deck, one pill, and a credential band along the bottom edge. Everything
   sits inside one viewport height and nothing is pinned.
   ------------------------------------------------------------------------ */
/* #fefffe, not --paper: sampled directly from ridgelines.jpg's own blank sky
   (measured mean rgb(254.5, 254.9, 254.5) across rows 5-35% of the source).
   --paper is #f9f8f4, a warmer, greyer tone -- close enough in isolation, but
   this flat area sits directly beside the photo's own near-identical white,
   and even a 5-10 point difference reads as an edge across two otherwise
   perfectly flat surfaces. Matching it removes that edge outright. */
.hero {
  position: relative;
  min-height: min(100vh, 58.75rem);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding-block: 0;
  background: #fefffe;
}

/* The plate keeps its own 2.36 proportion instead of being stretched to the
   full hero height. Stretching it was cropping 36-49% off the width of the
   panorama depending on the viewport, and filling the frame edge to edge
   left nowhere for the type to breathe. At natural ratio the whole
   photograph survives and the hero gains 300px of clear paper above it.

   `bottom: -80px` is the slack the scroll drift moves into. Without it the
   plate would pull away from the bottom edge and show paper underneath. */
.hero__media {
  position: absolute;
  inset: auto 0 -5rem 0;
  z-index: 0;
  aspect-ratio: 2000 / 848;
  will-change: transform;
}

/* `center`, not `center top`. The Y axis is inert: the plate's ratio equals
   the source's exactly, so cover crops nothing at desktop, and in the two
   narrow branches below the crop is horizontal. Saying `top` implied a
   vertical decision that was never being made, which is how the earlier
   `object-position: top` mistake got past review. */
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Feathers the top edge of the plate into the hero's own background. It
   lives on the plate rather than the scrim so it travels with the drift and
   stays glued to the edge it is hiding, whatever the viewport height.

   Recoloured to #fefffe, matching .hero's background above -- both sampled
   from the photo's own blank sky rather than the site's --paper token. Every
   step of the composite (photo blended through this gradient) was checked
   numerically before this change: with --paper (249,248,244) the largest
   single-percent shift through the whole feather was 0.67 dE, already smooth.
   This tightens that same smooth ramp against the true colour either side of
   it, so the flat area above the plate and the feather's own starting edge
   can no longer differ by even the few points that were there before.

   Contained in the top 30% of the plate, down from 70%. At 70% its tail
   reached 0.16 opacity across the upper half of the ridgelines, washing the
   one part of the frame that carries the subject -- this recolour does not
   touch that boundary or extend it. */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    #fefffe 0%,
    rgba(254, 255, 254, 0.82) 9%,
    rgba(254, 255, 254, 0.42) 18%,
    rgba(254, 255, 254, 0.12) 25%,
    rgba(254, 255, 254, 0) 30%
  );
}

/* The plate feathers its own top edge now, so this is left with two jobs: a
   breath of mist behind the headline, and a fade at the very bottom so the
   hero hands off to section 01 without a seam.

   That bottom fade used to start at 74% and reach 0.82 at the boundary, which
   put it across the whole of the ridgelines: at 1440x900 they sit at 75-92%
   of the hero, so the fade was veiling them from 0.03 up to 0.50 and lifting
   their tone from 179 to 208. It is now held off until 88% and completes by
   92.5%, so roughly three quarters of the strip is entirely clear and the
   ramp only crosses its last few pixels.

   It still has to be fully up by 92.5%, because the credential band's type
   begins at about 94% and this is its ground. There is no slack between the
   two: the band starts where the ridgelines end. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Radial patch recoloured to #fefffe, matching the photo (see .hero and
     .hero__media::after) -- it sits over the photograph and now fades in as
     you scroll, so a --paper-toned haze would reintroduce the same mismatch
     against the corrected background at every opacity above 0. The bottom
     linear-gradient stays --paper: it hands off to the NEXT section's real
     background, not to the photo, so it is matched to the right thing. */
  background: radial-gradient(
      112% 54% at 50% 20%,
      rgba(254, 255, 254, 0.5) 0%,
      rgba(254, 255, 254, 0) 72%
    ),
    linear-gradient(
      180deg,
      rgba(249, 248, 244, 0) 88%,
      rgba(249, 248, 244, 0.86) 92.5%,
      rgba(249, 248, 244, 0.86) 100%
    );
}

/* Resting default for no-JS/before-first-paint: clear, matching the JS's
   value at scroll progress 0. Without this the full baked-in haze (radial
   patch + bottom handoff) would flash visible for one frame before the
   scroll handler's first run sets it to 0. */
.js .hero__scrim {
  opacity: 0;
}

/* .js .hero__scrim {
  opacity: 1;
  transition: opacity 1.2s ease;
}

.hero__scrim--scroll {
  transition: none;
} */

.hero__in {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  padding-top: calc(var(--cap-h) + var(--cap-gap) + clamp(1.875rem, 5vw, 4.5rem));
  /* Biased upward, not balanced. With `justify-content: center` a larger
     bottom padding lifts the whole stack, and it has to be lifted: at the old
     56px the CTA's note ended at y 662 and the ridgelines begin at 675, so the
     type was sitting directly on the photograph's only content and needed a
     wash over it to stay legible. At 15vh the note ends near 622 and clears
     them by about 17px, which is what lets the band above stop short.

     vh rather than vw because this is a vertical measure, and because short
     viewports are the case that matters: they compress the stack back down
     onto the ridgelines, which is when the band earns its keep. */
  padding-bottom: clamp(2.5rem, 15vh, 10.625rem);
}

/* --- Rhythm ---
   The three gaps down this stack were 32 / 28 / 26px, near enough identical
   that five elements read as an evenly spaced list rather than a hierarchy.
   They are now 28 / 18 / 46: the headline and its deck bind into one
   statement, and the call to action separates as its own move. */
.hero__eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.875rem;
  margin-bottom: clamp(1.125rem, 2.2vw, 1.75rem);
}

/* One rule each side, so the label reads as a centred datum rather than a
   left-anchored one. */
.hero__eyebrow .r {
  flex: none;
  height: 1px;
  width: clamp(1.375rem, 3.4vw, 2.75rem);
  background: var(--tan);
}

/* Sized so the roman line holds on one line at every width down to the
   smallest handset. The `5vw` middle term is what does that, shrinking the
   type faster than the container narrows.

   The 32ch cap does not: 32 characters of Playfair at the 3.9rem ceiling
   measure about 930px against a 1088px cap, and both scale with font-size,
   so the ratio is constant and the cap never engages at any width. Kept
   because it states the intended measure, but it is not load-bearing. */
.hero h1 {
  font-size: clamp(2.15rem, 5vw, 3.9rem);
  line-height: 1.06;
  letter-spacing: -0.03em;
  max-width: 32ch;
  margin-inline: auto;
}

.hero h1 .ln {
  display: block;
}

/* The italic half carries the promise. Lighter weight as well as italic:
   at this size Playfair's bold italic is heavier than the roman, which
   would put the emphasis on the wrong half. */
.hero h1 .ln.em {
  font-weight: 400;
  /* Italics carry their own slant, so they need less negative tracking than
     the roman line above to hold the same rhythm. */
  letter-spacing: -0.015em;
}

/* Set as a deck rather than body copy: the jump from a 4rem headline to
   17px paragraph text needed a rung in the middle. */
/* `balance` evens the line lengths rather than filling each one to the
   measure, which is what stops the last line arriving as a single word. The
   nbsp in the markup is the fallback where it is unsupported. */
.hero__sub {
  /* Tightened to bind to the headline; see the rhythm note above. */
  margin: clamp(0.875rem, 1.5vw, 1.125rem) auto 0;
  /* Widened from 56ch, which forced it to three lines. At 72ch it settles on
     two, and `balance` evens them. */
  max-width: 72ch;
  font-size: clamp(1rem, 1.24vw, 1.13rem);
  font-weight: 300;
  line-height: 1.62;
  letter-spacing: -0.004em;
  color: var(--body);
  text-wrap: balance;
}

.hero__act {
  position: relative;
  /* Opened to separate the CTA from the statement; see the rhythm note. */
  margin-top: clamp(1.875rem, 3.4vw, 2.875rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

/* The ground behind the pill, sized to cover the note as well.

   This is legibility, not decoration. The plate is blank white down to about
   37% of its depth and then falls to a mean of 179-236 with minima at 145
   through the band this block lands on, and by then the plate's own feather
   has expired, so it lightens nothing: 13px type at --grey measured 1.9:1
   there. Tying the ground to the block's own height keeps it guaranteed
   wherever the block ends up, which a fixed-position gradient in the scrim
   could not.

   A full-width band rather than the 780px ellipse it was. An ellipse has a
   perimeter, so at 0.9 opacity mid-composition it read as a pale object
   sitting behind the button. A band running the full viewport with a purely
   vertical falloff has no edge to notice, so it reads as light.

   0.80, down from 0.9, because the wash was over-built: the note measures
   6.53:1 at 0.80 against 7.00:1 at 0.90. The last tenth of opacity bought
   0.16:1 of contrast and cost the hero a visible blob.

   Negating z-index is safe: .hero__in opens its own stacking context, so
   this cannot fall behind the photograph. 100vw can overhang the content box
   by the scrollbar width, which is invisible on a gradient that is uniform
   horizontally, and .hero clips it regardless.

   Positioned with `top` and half the overhang rather than `top: 50%` and a
   translate, so no transform is needed to place it. That matters because the
   reduced-motion block sets `transform: none !important` on every pseudo
   element: the old ellipse used `translate(-50%, -50%)` for its own layout,
   so under reduced motion it lost both axes and the CTA's ground has been
   sitting half a block low and 390px right this whole time. Transform is now
   used only for the entrance, which is the one thing safe to strip.

   Deliberately asymmetric: 150px of reach above the block, 35px below. It was
   centred, which put its falloff 95px under the note and straight onto the
   top of the ridgelines at 0.59 -- worse than the scrim it replaced, and
   across the full width rather than 780px. Upward reach is free because
   everything above is the photograph's blank white third; downward reach is
   not, because the ridgelines start immediately under the note. */
.hero__act::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -9.375rem;
  z-index: -1;
  width: 100vw;
  margin-left: -50vw;
  height: calc(100% + 11.5625rem);
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(249, 248, 244, 0) 0%,
    rgba(249, 248, 244, 0.28) 24%,
    rgba(249, 248, 244, 0.62) 42%,
    rgba(249, 248, 244, 0.8) 56%,
    rgba(249, 248, 244, 0.8) 88%,
    rgba(249, 248, 244, 0) 100%
  );
}

/* Widened to hold on one line at desktop, and stepped up from --grey at 300
   to --body at 400. Small light type over photography is the most fragile
   thing on the page; it should not also be the lightest colour. */
.hero__micro {
  margin: 0 auto;
  max-width: 54ch;
  font-size: 0.86rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--body);
  text-wrap: balance;
}

/* --- Hero credential band -----------------------------------------------
   The reference anchors its hero with a row of client logos. There are no
   client logos to run, so this is the operator's own record, typeset. The
   label keeps it honest: these are posts held, not endorsements given.
   ------------------------------------------------------------------------ */
.hero__proof {
  position: relative;
  z-index: 2;
  padding-bottom: clamp(1.375rem, 3.4vw, 2.625rem);
}

.hero__proof-in {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.625rem clamp(1rem, 2.6vw, 1.875rem);
}

.hero__proof-k {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey);
}

.hero__brands {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
}

/* 0.64, up from 0.52, which measured 3.45:1 on paper and 3.35:1 over the
   photograph and failed AA at every viewport. At 20px regular this is normal
   text, not large text, so 4.5:1 is the bar; 0.64 clears it at 4.79:1
   worst-case.

   The ground cannot fix this. At 0.52 the row measures 3.30-3.43 across every
   ground from 0.82 to 0.92, because the foreground is low-alpha ink over that
   same ground, so strengthening the ground lifts both and the ratio barely
   moves. Only the alpha moves it.

   Not 0.68, which would clear 5.44:1 but make the names heavier than the
   label above them and read as a change to the section's tone. */
.hero__brands li {
  font-family: var(--serif);
  font-size: clamp(0.98rem, 1.5vw, 1.24rem);
  line-height: 1.25;
  color: rgba(24, 28, 37, 0.64);
  padding-inline: clamp(0.625rem, 1.4vw, 1.125rem);
}

.hero__brands li + li {
  border-left: 1px solid var(--line);
}

/* --- Alternating rows ---------------------------------------------------
   Left -> right -> left -> right. The feedback praises this layout twice and
   names it in its instruction line, so the rhythm is the constant.

   What made four consecutive rows read as a template last time was that they
   were also identical in every other respect. So the alternation stays and
   the treatment inside it varies: each row has its own column ratio, its own
   media proportion, and its own vertical alignment, and row three breaks the
   rhythm with a full-width panel beneath it. Alternating, not stamped.
   ------------------------------------------------------------------------ */
.row {
  display: grid;
  gap: clamp(2rem, 5.5vw, 4.875rem);
  align-items: center;
}

/* Media to the left. Text stays first in the DOM either way, so the reading
   order for screen readers never alternates with the visual order. */
.row--flip .row__media {
  order: -1;
}

/* Per-row variation. The four ratios and the four media proportions are all
   deliberately different; that difference is the whole point of naming them
   individually rather than sharing one rule. */
.row--list      { grid-template-columns: 0.82fr 1.18fr; align-items: start; }
/* Was 1.28 / 0.72, which left the section's only photograph at 364px, a
   third of the container and the smallest image on the page. It read as a
   thumbnail beside a heading rather than as a plate. */
.row--claim     { grid-template-columns: 0.95fr 1.05fr; }
/* No align override: the base row centres, so the claim sits on the
   portrait's vertical centre. It was `start` while this column also held the
   figures and the quote, where top-aligning was the only thing that made a
   658px pile sit sensibly against a 356px photograph. With the column down to
   heading and copy, centred is the correct relationship. */
.row--record    { grid-template-columns: 0.88fr 1.12fr; }

.row--list .row__media      { aspect-ratio: 3 / 4; }
.row--claim .row__media     { aspect-ratio: 4 / 3; }
/* Was 4 / 5 against a 768x532 landscape source, which threw away 45% of the
   frame's width. 5 / 4 brings that down to 13% and still gives the column
   enough height to sit against the record beside it. */
.row--record .row__media    { aspect-ratio: 5 / 4; }

.row__media {
  position: relative;
  overflow: hidden;
  border-radius: 3px;
  aspect-ratio: 4 / 5;
  background: var(--paper-warm);
}

.row__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease);
}

.row__media:hover img {
  transform: scale(1.03);
}

/* The source is landscape (768 x 532) in a 5:4 frame, so `cover` still crops
   on the WIDTH, now by 13% rather than 45%. Vertical position has no effect
   either way; the sitter is framed right of centre with dead space to his
   left, so 60% recentres what is kept on him. */
.row__media--face img {
  object-position: 60% top;
}



.note {
  margin-top: 1.375rem;
  font-size: 1.02rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--body);
  max-width: 50ch;
}

/* --- The statement, pinned ----------------------------------------------
   Base state is an ordinary section: heading, paragraph, plate. Everything
   that makes it a pinned sequence lives behind `.js`, because the line runs
   about 5,700px at full size and setting that nowrap without a script to
   move it would leave two thirds of the sentence permanently off-screen.
   ------------------------------------------------------------------------ */
.epic {
  padding-block: var(--section-y);
}

/* This section is the one on the site with no `.wrap` inside it -- the pinned
   stage has to be full-bleed, so the measure lives on `.epic__in` instead.
   That leaves the stacked and script-less states with no gutter at all, which
   is what put the plate and the copy hard against the viewport edge. The stage
   carries the container here and gives it back. */
.epic__stage {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
}

.epic__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2;
  border-radius: 3px;
  margin-bottom: clamp(1.75rem, 3.4vw, 2.625rem);
  background: var(--paper-warm);
}

.epic__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 15%, not 42%. At 42% the compass rim sat under the body copy: mean tone
     205 but a minimum of 0 and a standard deviation of 49, so the ground
     swung across a single line of text and read as mottled. 15% puts the
     flat map band there instead -- mean 227, minimum 125, deviation 20. */
  object-position: center 15%;
}

.epic__veil {
  display: none;
}

.epic__line {
  font-family: var(--serif);
  font-size: clamp(1.6rem, 3.4vw, 2.5rem);
  font-weight: 400;
  line-height: 1.26;
  letter-spacing: -0.02em;
  max-width: 20ch;
}

.epic .u {
  font-family: var(--serif);
  color: var(--accent);
  font-style: italic;
}

.epic__body {
  margin-top: clamp(1.25rem, 2.4vw, 1.875rem);
}

.epic__cap {
  margin-top: 0.875rem;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--grey);
}

/* --- With script: the pinned sequence --- */
.js .epic {
  padding-block: 0;
}

.js .epic__track {
  position: relative;
  /* 260vh, down from 680. The old number existed to give one 5,461px nowrap
     line enough scroll to cross four screens at a readable rate. Three
     stacked lines travel their own height instead, so the pin only has to
     last long enough to stage four beats, and the homepage gets five screens
     back. 280 rather than 260 so a third of the pin is dead-still hold with
     the quote fully assembled -- see the beat table in main.js. */
  height: 280vh;
}

.js .epic__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  /* Flex, not grid. In a grid container the alignment properties also apply
     to an absolutely positioned child's inset-modified containing block, so
     `place-items: center` was overriding .epic__cap's right/bottom anchors
     and pushing it off the edge -- the caption was rendering as "THEN MOV".
     A flex container only uses alignment for an abspos child's static
     position, which specified insets replace. */
  display: flex;
  align-items: center;
  justify-content: center;
  /* Full bleed while pinned: the veil and plate have to reach the edges, and
     `.epic__in` supplies the measure instead. */
  max-width: none;
  padding-inline: 0;
}

.js .epic__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  aspect-ratio: auto;
  border-radius: 0;
  margin: 0;
}

/* Paper, not white: the site's ground is #f9f8f4 and a pure white veil would
   read as a different surface from the sections either side. Starts nearly
   opaque and lifts to 0.78, which is the 70-80% asked for. */
.js .epic__veil {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--paper);
  opacity: 0.94;
}

/* Quote and body share one centred column now, so they read together at the
   end rather than one having to clear before the other can arrive. */
.js .epic__in {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--container);
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
  text-align: center;
}

/* Sized so the longest line, "The people who get stuck" at 24 characters,
   holds on one line at every width. The binding term is the 6.4vw, not the
   rem ceiling: at 1440 that is 92px, giving roughly 968px against 1,088px of
   usable width, and at 1920 the ceiling takes over at 119px for 1,290px
   against 1,451px. My first pass used 7.2vw and 6.5rem, which measured 3%
   over and would have wrapped that line.

   Worth noting the failure mode is a wrap, not a clip: `white-space: normal`
   means an over-long line breaks inside its own mask, which looks like an
   uneven break rather than a lost word. */
.js .epic__line {
  position: static;
  margin: 0;
  max-width: none;
  white-space: normal;
  font-size: clamp(2.4rem, 6.4vw, 5.6rem);
  line-height: 1.05;
  letter-spacing: -0.03em;
  transform: none;
}

/* Each line is its own mask. Padding buys back the room the mask would
   otherwise crop from Playfair's descenders and the italic overhang, and the
   negative margin puts the line spacing back where it was. The same
   arrangement the hero headline uses. */
.js .epic__ln {
  display: block;
  overflow: hidden;
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
}

.js .epic__ln i {
  display: block;
  font-style: inherit;
  will-change: transform;
}

/* Parked below its mask from the moment the driver executes, so no line shows
   before its beat. Gated on `js-run`, not `js`: if main.js never loads this
   rule never applies and all three lines sit where they can be read. */
.js-run .epic__ln i {
  transform: translate3d(0, 110%, 0);
}

.js .epic__body {
  position: static;
  inset: auto;
  z-index: 3;
  margin-top: clamp(1.5rem, 2.6vw, 2.25rem);
  display: block;
  padding-inline: 0;
  opacity: 0;
  will-change: transform, opacity;
}

/* 56ch, up from 44. Read against a twelve-column container that is 1,088px
   of usable width at 1440, one column is 91px: 44ch measured 458px, or five
   columns, and 56ch measures 582px, so this is 1.4 columns wider. The figure
   holds at 1920 too -- 610px to 777px, the same 1.4 columns -- because the
   container, the type and the measure now all scale off the same root.
   Still inside the 45-75 character band, so the measure stays readable. */
.js .epic__body .note {
  max-width: 56ch;
  margin-inline: auto;
  text-align: center;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  line-height: 1.6;
  color: var(--text);
}

.js .epic__cap {
  position: absolute;
  z-index: 3;
  right: clamp(1.25rem, 5vw, 3.5rem);
  bottom: clamp(1.25rem, 3vw, 2.375rem);
  margin: 0;
}

/* Below this the sequence is off and the section is a plain block again: a
   line that needs four screens of horizontal travel has nowhere to go on a
   phone. */
@media (max-width: 860px) {
  .js .epic {
    padding-block: var(--section-y);
  }

  .js .epic__track {
    height: auto;
  }

  /* `display: block`, and its absence was the bug. The stage became a flex
     container when the caption needed pinning bottom-right, and neither
     collapse branch undid it -- so the plate, the copy column and the caption
     stopped stacking and became three flex items in a ROW, each squeezed to a
     third of a phone. That is why the quote was setting one word per line. */
  .js .epic__stage {
    position: static;
    display: block;
    height: auto;
    overflow: visible;
    max-width: var(--container);
    margin-inline: auto;
    padding-inline: clamp(1.25rem, 5vw, 3.5rem);
  }

  .js .epic__in {
    max-width: none;
    padding-inline: 0;
    text-align: left;
  }

  /* The three hard breaks are a desktop composition; stacked they would give
     six short lines, so the spans run inline and wrap on their own. */
  .js .epic__ln,
  .js .epic__ln i {
    display: inline;
  }

  .js .epic__media {
    position: relative;
    inset: auto;
    aspect-ratio: 3 / 2;
    border-radius: 3px;
    margin-bottom: clamp(1.75rem, 3.4vw, 2.625rem);
  }

  .js .epic__veil {
    display: none;
  }

  .js-run .epic__ln i,
  .js .epic__ln i {
    transform: none;
  }

  .js .epic__ln {
    overflow: visible;
  }

  .js .epic__line {
    position: static;
    width: auto;
    white-space: normal;
    text-wrap: balance;
    max-width: 20ch;
    font-size: clamp(1.6rem, 6vw, 2.4rem);
    line-height: 1.26;
    letter-spacing: -0.02em;
    transform: none;
  }

  .js .epic__body {
    position: static;
    display: block;
    opacity: 1;
    padding-inline: 0;
    margin-top: clamp(1.25rem, 2.4vw, 1.875rem);
    transform: none;
  }

  .js .epic__body .note {
    text-align: left;
    max-width: 50ch;
    font-size: 1.02rem;
  }

  .js .epic__cap {
    position: static;
    margin-top: 0.875rem;
  }
}

/* --- Pains --------------------------------------------------------------
   Four recognitions, not four table rows. The copy is set a step larger than
   ordinary body text because this list is the part a reader is meant to see
   themselves in; the closing rule is gone, so four items carry four hairlines
   instead of five; and the marker sits in a fixed-width column so all four
   paragraphs share one left edge.
   ------------------------------------------------------------------------ */
.pain {
  display: flex;
  gap: 1.125rem;
  align-items: flex-start;
  padding: 1.5rem 0 1.625rem;
  border-bottom: 1px solid var(--line);
}

.pain:first-of-type {
  border-top: 1px solid var(--line);
  /* Air between the section headline and the list it introduces. */
  margin-top: 2.125rem;
}

/* A rule under the last item closes the list off from the section around it;
   the four items only need the lines between and above them. */
.pain:last-of-type {
  border-bottom: 0;
  padding-bottom: 0;
}

.pain__no {
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  color: var(--grey);
  /* Fixed, so a/b/c/d do not each start their paragraph at a slightly
     different x. Nudged down to sit on the larger copy's first baseline. */
  width: 0.875rem;
  padding-top: 0.4375rem;
  flex: none;
}

.pain p {
  font-size: 1.08rem;
  font-weight: 300;
  line-height: 1.62;
  color: var(--body);
}

/* --- Stand for / against ------------------------------------------------
   The single dark-blue surface on the page. It is the emphasis Stewart
   liked, kept to one panel so the site still reads predominantly white.
   ------------------------------------------------------------------------ */
.stand {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
  margin-top: clamp(2rem, 4vw, 3.25rem);
}

.stand__col {
  padding: clamp(1.625rem, 3.4vw, 2.5rem);
}

.stand__col--against {
  background: var(--white);
}

.stand__col--for {
  /* Traded to --blue so the card reads as a lighter panel against the
     section's own darker background, the same pairing tested in the
     #difference experiment. */
  background: var(--blue);
  color: rgba(255, 255, 255, 0.92);
}

.stand__col h3 {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 1.625rem;
}

.stand__col--against h3 {
  color: var(--grey);
}

.stand__col--for h3 {
  color: rgba(255, 255, 255, 0.62);
}

.stand__col ul {
  display: grid;
  gap: 1.125rem;
}

.stand__col li {
  display: flex;
  gap: 0.875rem;
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.45;
}

.stand__col li svg {
  flex: none;
  width: 0.9375rem;
  height: 0.9375rem;
  margin-top: 0.3125rem;
}

.stand__col--against li {
  color: var(--body);
}

/* --- About Stewart ------------------------------------------------------
   The four figures are the section's spine, so they run the full width of the
   container under both columns rather than sitting as a boxed 2x2 inside the
   text column. Bounded top and bottom with a single hairline each and divided
   between cells, on the warm paper: a band, not a table of white boxes.
   ------------------------------------------------------------------------ */
/* The bounding hairlines are pseudo-elements rather than borders so they can
   be drawn across as the band arrives. */
.stats {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin: clamp(2.5rem, 5vw, 4.25rem) 0 0;
}

.stats::before,
.stats::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}

.stats::before { top: 0; }
.stats::after { bottom: 0; }

.stat {
  padding: clamp(1.5rem, 2.6vw, 2rem) clamp(1.125rem, 2vw, 1.625rem)
    clamp(1.625rem, 2.8vw, 2.125rem);
}

.stat + .stat {
  border-left: 1px solid var(--line);
}

.stat__n {
  font-family: var(--serif);
  font-size: clamp(1.9rem, 3.4vw, 2.6rem);
  font-weight: 400;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.stat__c {
  margin-top: 0.625rem;
  font-size: 0.94rem;
  font-weight: 300;
  line-height: 1.5;
  color: var(--body);
}

/* Closes the section under the band. */
/* Closes the section under the band. The blue rule is a pseudo-element rather
   than a border so it can be drawn on entry. */
.pull {
  position: relative;
  margin-top: clamp(2.125rem, 4vw, 3.375rem);
  max-width: 60ch;
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.24rem;
  line-height: 1.45;
  color: var(--text);
  padding-left: 1.5rem;
}

.pull::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--accent);
}

.pull .who {
  display: block;
  margin-top: 1.25rem;
  font-family: var(--sans);
  font-style: normal;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text);
}

.pull .who em {
  display: block;
  margin-top: 0.25rem;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--grey);
}

/* --- Friction to Flow ---------------------------------------------------
   Design 2's method section, its declarations reproduced exactly. Only the
   formatting is reflowed to match this file.

   Its palette and typefaces are declared on `.method` rather than in :root,
   so the near-black ink, the amber, and the Helvetica/mono stack apply inside
   this section and nowhere else. --paper is deliberately shadowed here: every
   `var(--paper)` below then resolves to Design 2's warm value, which is what
   its own rules were written against.
   ------------------------------------------------------------------------ */
.method {
  --ink: #0f1d30;
  --paper: #efeadf;
  --amber-bright: #ce9c4e;
  --f-display: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
  --f-mono: "SF Mono", ui-monospace, Menlo, Consolas, monospace;

  /* Drives the centred grid's measure and gutter. */
  --m-text: 46ch;
  --m-gap: clamp(1.5rem, 5vw, 4rem);


  padding: 0;
  background: var(--ink);
  color: var(--paper);
}

.method-track {
  position: relative;
  height: 360vh;
}

.method-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
}

.method-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.method-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.5;
}

/* Design 2's was a left-to-right ramp because its content sat hard left.
   With the block centred, the darkening is centred to match: heaviest under
   the type, opening at both edges so the winding path still reads. */
.method-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    124% 104% at 50% 50%,
    rgba(10, 18, 30, 0.76) 0%,
    rgba(10, 18, 30, 0.68) 46%,
    rgba(10, 18, 30, 0.42) 78%,
    rgba(10, 18, 30, 0.28) 100%
  );
}

.method-stage .wrap {
  position: relative;
  z-index: 2;
  width: 100%;
}

.method-inner {
  display: grid;
  /* Was `auto 1fr`, which pinned the block to the left edge of the container.
     A fixed measure plus justify-content centres the rail and the text as one
     unit while the type inside stays left-aligned. */
  grid-template-columns: auto minmax(0, var(--m-text));
  justify-content: center;
  gap: var(--m-gap);
  align-items: center;
}

.m-rail {
  position: relative;
  width: 2px;
  height: 18.75rem;
  background: rgba(239, 234, 223, 0.18);
  margin-left: 0.375rem;
}

.m-rail .fill {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  background: var(--amber-bright);
  height: 0%;
}

.m-rail .node {
  position: absolute;
  left: 50%;
  width: 0.6875rem;
  height: 0.6875rem;
  border-radius: 50%;
  background: var(--ink);
  border: 2px solid rgba(239, 234, 223, 0.4);
  transform: translate(-50%, -50%);
}

.m-rail .node.n1 { top: 0; }
.m-rail .node.n2 { top: 50%; }
.m-rail .node.n3 { top: 100%; }

.m-rail .node.on {
  background: var(--amber-bright);
  border-color: var(--amber-bright);
  box-shadow: 0 0 0 0.3125rem rgba(206, 156, 78, 0.2);
}

.m-content {
  position: relative;
  min-height: 20rem;
}

.m-step {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(1.5rem);
  transition: opacity 0.6s, transform 0.6s;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.m-step.active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.m-step .cn {
  font-family: var(--f-mono);
  font-size: 0.875rem;
  color: var(--amber-bright);
  letter-spacing: 0.1em;
}

.m-step h3 {
  font-family: var(--f-display);
  font-weight: 800;
  font-size: clamp(2.1rem, 4.6vw, 3.4rem);
  letter-spacing: -0.03em;
  margin: 1rem 0;
  line-height: 1.02;
}

.m-step p {
  color: rgba(239, 234, 223, 0.82);
  font-size: 1.16rem;
  line-height: 1.55;
  max-width: 46ch;
}

/* Design 2's hook for anything its parallax moves. */
.par {
  will-change: transform;
}

@media (max-width: 820px) {
  .method-track { height: auto; }

  /* 80px top and bottom was tuned for the pinned desktop stage, where the
     padding is the frame. Stacked it lands right after the section above and
     its own dark plate makes it read as an empty band: 52px of warm paper from
     `#about`, then 80px of grey before a single word appears. */
  .method-stage {
    position: static;
    height: auto;
    padding: clamp(2rem, 6vw, 3.5rem) 0 clamp(2.5rem, 7vw, 4rem);
  }

  .method-inner {
    grid-template-columns: 1fr;
    justify-content: stretch;
  }

  .m-rail { display: none; }

  .m-content {
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 2.6rem;
  }

  .m-step {
    position: static;
    opacity: 1;
    transform: none;
  }
}

/* --- Engagements --------------------------------------------------------- */
.price {
  border-top: 1px solid var(--line);
  margin-top: clamp(1.75rem, 3.4vw, 2.5rem);
}

/* The hover was `transition: padding-left`, and padding is a layout property:
   on a three-column grid every frame re-ran layout, so the columns resized
   and the description re-wrapped as it slid. That re-wrap mid-transition is
   what read as judder rather than as movement. Nothing here touches layout --
   background and border-color are paint, transform is composite. */
.price__row {
  display: grid;
  grid-template-columns: 1.3fr 2fr auto;
  gap: 1.5rem;
  align-items: center;
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--line);
  transition: background-color 0.36s var(--ease), border-color 0.36s var(--ease);
}

/* One signal, not two. This used to carry an 8px slide on the row's cells as
   well, and that was the part that read as loud: movement is what catches the
   eye, and on a table row it reads as busy rather than as responsive. What is
   left is a tonal shift, both halves fading over the same 0.36s.

   Both halves are also halved. The wash was 0.07, a 33% jump in luminance,
   and the rule doubled from 0.20 to 0.40. At 0.04 and 0.28 the ground lifts
   18% and the rule firms up 1.4x, which is a hint rather than a state change.
   Text still holds at 6.9:1 for body and 6.6:1 for the accent. */
.price__row:hover {
  background-color: var(--wash);
  border-color: var(--rule-hi);
}

/* 500, down from 700. On a solid blue panel a bold serif at this size was
   the heaviest element in the section and the reason it read as loud; the
   background was never really the problem. At 500 the name still leads the
   row against the 500-weight cost beside it, because Playfair against Inter
   already carries the distinction without the extra weight. */
.price__name {
  font-family: var(--serif);
  font-size: 1.24rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.price__desc {
  font-size: 0.96rem;
  font-weight: 300;
  color: var(--body);
}

.price__cost {
  font-size: 1.08rem;
  font-weight: 500;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.price__cost--free,
.price__name--free {
  color: var(--accent);
}

.price__note {
  margin-top: 1.625rem;
  font-size: 0.78125rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--grey);
}

/* --- Voices -------------------------------------------------------------- */
/* One lead quote and two supporting it, rather than three equal columns.
   The steps above are already a 3-up, and matching them exactly is what
   made this section feel like a repeat of that one. */
/* The gap to the eyebrow above was 66px: this element's 48px plus the
   kicker's own 18px margin. An 11px label captions the grid it sits on, so it
   belongs close to it -- 30px total is about twice the label's own height.

   Reduced here rather than behind the --grid modifier because this is the only
   place `.voices` is used: the homepage rail builds its cards in
   `.rail__cards`, so the old 48px was serving nothing. */
.voices {
  display: grid;
  /* Was `1.34fr 1fr 1fr`, a one-lead-and-two ratio that could never render:
     `.voices--grid` overrode it, and the base never appears without that
     modifier anywhere on the site. The lead-quote layout it was written for
     lives on the homepage rail, which builds its own cards in `.rail__cards`. */
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.375rem);
  margin-top: clamp(0.5rem, 1vw, 0.75rem);
}

.voice:first-child .voice__q {
  font-size: 1.14rem;
  line-height: 1.55;
}

.voice:first-child .voice__mark {
  font-size: 3rem;
}

.voice {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 1.75rem 1.625rem 1.625rem;
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
}

.voice__mark {
  font-family: var(--serif);
  font-size: 2.4rem;
  line-height: 0.4;
  height: 0.6em;
  color: var(--tan);
}

.voice__q {
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--text);
}

.voice__attr {
  margin-top: auto;
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey);
}

/* --- Voices: the pinned rail --------------------------------------------
   The heading holds top left while the quotes travel in from the right edge
   and lock into their slots on the left, one at a time, on scroll.

   The track supplies the scroll length; the stage pins inside it. This only
   works because `overflow-x: hidden` moved off `body` and onto `html` -- on
   body it made body a scroll container and no descendant could stick.

   Resting state is the finished state: cards sit in their slots at
   translate(0) and the script only ever pushes them right and brings them
   back. If it never runs, the section reads as a plain three-up.
   ------------------------------------------------------------------------ */
.rail {
  padding-block: 0;
}

.rail__track {
  position: relative;
  height: 300vh;
}

.rail__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  /* Clips the cards while they are still off to the right, so they do not
     lengthen the page. The stage is not a sticky ancestor of anything, so
     clipping here costs nothing. */
  overflow: hidden;
}

/* Wider container than the rest of the site. The quotes are the content here
   and the heading only has to label them, so this section buys itself extra
   room rather than squeezing three cards into the standard measure. */
.rail .wrap {
  max-width: 87.5rem;
}

.rail__grid {
  display: grid;
  /* Was 0.82 / 2.18, which left each card at about 232px. The heading needs
     far less than a quarter of the row. */
  grid-template-columns: minmax(0, 0.58fr) minmax(0, 2.42fr);
  gap: clamp(1.375rem, 3.2vw, 3.25rem);
  align-items: start;
  width: 100%;
}

/* Top left, and it stays there for the length of the track. */
.rail__head {
  align-self: start;
}

.rail__head h2 {
  max-width: 14ch;
}

.rail__meter {
  position: relative;
  height: 2px;
  margin-top: clamp(1.25rem, 2.6vw, 1.875rem);
  background: var(--line);
  overflow: hidden;
}

.rail__fill {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
}

.rail__cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.875rem, 1.6vw, 1.25rem);
  align-items: start;
}

/* Wider cards can carry a little more air and a slightly larger quote. */
.rail__cards .voice {
  padding: clamp(1.75rem, 2.4vw, 2.25rem) clamp(1.625rem, 2.2vw, 2.125rem);
}

.rail__cards .voice__q {
  font-size: 1.06rem;
  line-height: 1.62;
}

/* Each card is pushed out to the right by the script and brought back as its
   turn arrives. `will-change` on three elements is the whole cost. */
.js .rail__cards .voice {
  will-change: transform;
}

@media (max-width: 860px) {
  .rail {
    padding-block: var(--section-y);
  }

  /* No pinning: the track collapses and the stage becomes an ordinary block,
     so the three quotes are just a stack. */
  .rail__track {
    height: auto;
  }

  .rail__stage {
    position: static;
    height: auto;
    overflow: visible;
  }

  .rail__grid {
    grid-template-columns: 1fr;
  }

  .rail__head h2 {
    max-width: 21ch;
  }

  .rail__cards {
    grid-template-columns: 1fr;
    margin-top: clamp(1.625rem, 3.4vw, 2.375rem);
  }

  .rail__meter {
    display: none;
  }
}

/* --- Closing ------------------------------------------------------------- */
.closing {
  position: relative;
  overflow: hidden;
  text-align: center;
  min-height: 68vh;
  display: flex;
  align-items: center;
}

.closing__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.closing__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 58%;
}

.closing__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    180deg,
    rgba(249, 248, 244, 0.9) 0%,
    rgba(249, 248, 244, 0.68) 45%,
    rgba(249, 248, 244, 0.94) 100%
  );
}

.closing .wrap {
  position: relative;
  z-index: 2;
}

.closing h2 {
  font-size: clamp(2.4rem, 6.4vw, 4.6rem);
  max-width: 16ch;
  margin: 1.125rem auto 0;
}

.closing p {
  max-width: 42ch;
  margin: 1.25rem auto 2rem;
  font-size: 1.08rem;
  font-weight: 300;
  color: var(--body);
}

.closing__meta {
  margin-top: 1.5rem;
  display: flex;
  justify-content: center;
  gap: 0.875rem;
  flex-wrap: wrap;
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--grey);
}

.closing__meta span + span::before {
  content: "";
  display: inline-block;
  width: 0.75rem;
  height: 1px;
  margin-right: 0.875rem;
  vertical-align: middle;
  background: var(--line);
}

/* --- About page ----------------------------------------------------------
   Its own components, built from the same parts as the homepage: hairlines
   rather than shadows, 3px corners, Playfair headings with a blue accent
   phrase, the quietened label layer. Nothing here introduces a treatment the
   rest of the site does not already use.
   ------------------------------------------------------------------------ */

/* The label above each block. Not a section index -- those were removed
   site-wide -- but a column heading doing real work: it is what tells the
   problem apart from the outcome when the two sit side by side. */
.kicker {
  margin-bottom: 1.125rem;
}

/* Page hero. The plate runs to the left edge of the viewport and the copy
   holds the container's right half, so the two columns meet on the site grid
   even though only one of them starts on it. */
.phero {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: clamp(1.875rem, 5vw, 4.75rem);
  /* The plate no longer bleeds, so the section needs its own room -- and the
     top has to clear the floating header capsule, which the full-bleed plate
     used to run underneath. Same expression the page heads use. */
  padding-block: calc(var(--cap-h) + var(--cap-gap) + clamp(1.5rem, 3vw, 2.75rem))
    clamp(2.5rem, 5vw, 4rem);
  min-height: min(78vh, 45rem);
}

/* Inset on the left rather than run to the viewport edge, and centred rather
   than stretched.

   `align-self: stretch` was the whole problem: it overrode the grid's own
   `align-items: center` for this one item, so the portrait ran the full height
   of the section while the copy centred inside it. That is what made the text
   look top-hung against an image with no top or bottom.

   The left inset mirrors the exact expression `.phero__body` uses for its
   right padding, so the portrait's left edge and the copy's right edge both
   land on the container's own edges and the composition is symmetrical. */
.phero__plate {
  position: relative;
  align-self: center;
  margin-left: max(
    calc(50vw - var(--container) / 2 + clamp(1.25rem, 5vw, 3.5rem)),
    clamp(1.25rem, 5vw, 3.5rem)
  );
  aspect-ratio: 4 / 5;
  min-height: 0;
  border-radius: 3px;
  overflow: hidden;
  background: var(--paper-warm);
}

.phero__plate img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Landscape source in a tall frame, so the crop is on the width and the
     sitter is right of centre. Same reason as the homepage portrait. */
  object-position: 60% center;
}

.phero__body {
  /* Was clamp(4rem, 8vw, 6.5rem). The section owns its vertical room now, and
     padding here only inflated the grid row, which fought the centring. */
  padding-block: 0;
  /* Pulls the copy onto the container's own right half rather than the raw
     half of the viewport. */
  padding-right: max(calc(50vw - var(--container) / 2 + clamp(1.25rem, 5vw, 3.5rem)), clamp(1.25rem, 5vw, 3.5rem));
  max-width: 58ch;
}

.phero h1 {
  font-size: clamp(2.4rem, 5.4vw, 4rem);
  margin-bottom: 1.625rem;
}

.phero .note + .note {
  margin-top: 1.125rem;
}

/* Two columns that argue with each other. Wider gutter than a normal row
   because there is no media between them to hold them apart. */
.pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2.125rem, 6vw, 5.75rem);
  align-items: start;
}

.pair--wide {
  gap: clamp(2.125rem, 7vw, 6.875rem);
}

/* Grid children default to min-width:auto, which lets a long word push a
   track wider than its share. */
.pair__col {
  min-width: 0;
}

.pair h2 {
  font-size: clamp(1.55rem, 2.5vw, 2.05rem);
  max-width: 20ch;
  margin-bottom: 1.25rem;
}

/* The question the practice is built on: one line, centred, given a whole
   band to itself. */
.creed {
  text-align: center;
}

.creed__q {
  font-family: var(--serif);
  font-size: clamp(1.9rem, 4.6vw, 3.2rem);
  font-weight: 400;
  line-height: 1.16;
  letter-spacing: -0.02em;
  max-width: 18ch;
  margin-inline: auto;
  text-wrap: balance;
}

.creed__sub {
  margin: 1.25rem auto 0;
  max-width: 44ch;
  font-size: 1.02rem;
  font-weight: 300;
  color: var(--body);
}

/* Three principles, stacked. Hairline-bounded blocks rather than cards: the
   rest of the site has no elevation and these should not be the exception. */
.tenets {
  margin-top: clamp(1.75rem, 3.4vw, 2.375rem);
  border-top: 1px solid var(--line);
}

.tenet {
  padding: 1.25rem 0 1.375rem;
  border-bottom: 1px solid var(--line);
}

.tenet h3 {
  font-family: var(--sans);
  font-size: 0.98rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  line-height: 1.3;
  margin-bottom: 0.4375rem;
}

.tenet p {
  font-size: 0.96rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--body);
}

/* A plain full-bleed band, for a page that needs a breath rather than a
   close. */
.band {
  position: relative;
  overflow: hidden;
  height: clamp(11.875rem, 24vw, 20rem);
  background: var(--paper-warm);
}

/* Top-aligned: the container's clamped height (190-320px) is shorter than
   the stairwell photo renders at, so `cover` crops it vertically. Anchoring
   to the top keeps the doorway light and the full climbing figures in frame
   and crops the empty lower stairs instead -- the only used instance of
   `.band`, so this is scoped safely to just this one photo. */
.band img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* The page's close: the field band and the ask as one composition rather
   than a photograph followed by a void. */
.closer {
  position: relative;
  overflow: hidden;
  min-height: clamp(20rem, 34vw, 27.5rem);
  display: flex;
  align-items: center;
  text-align: center;
  padding-block: clamp(3rem, 6vw, 5rem);
  background: var(--paper-warm);
}

.closer__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.closer__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 58%;
}

/* Paper, heaviest under the type so the button and its note keep the same
   dark-on-light relationship they have everywhere else on the site, and
   thinning at the edges so the field still reads. */
.closer__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(
    92% 130% at 50% 50%,
    rgba(249, 248, 244, 0.93) 0%,
    rgba(249, 248, 244, 0.86) 40%,
    rgba(249, 248, 244, 0.5) 74%,
    rgba(249, 248, 244, 0.24) 100%
  );
}

.closer__in {
  position: relative;
  z-index: 2;
}

/* The band was a lone button on a photograph with no heading, so it read as a
   stray control rather than as the page's closing move. The line is the site's
   own tagline, reused rather than newly written: it already carries the
   homepage h1 and the title tag, so this adds no claim. */
.closer__t {
  margin: 0.75rem auto clamp(1.5rem, 2.6vw, 2.25rem);
  font-size: clamp(2rem, 4.6vw, 3.25rem);
  max-width: 20ch;
}

.closer__micro {
  margin-top: 1.125rem;
  font-size: 0.9rem;
  font-weight: 400;
  color: var(--body);
}

/* Current page in the nav, distinct from the current-section marker the
   homepage uses while scrolling. */
.nav a:not(.btn).is-here {
  color: var(--text);
}

.nav a:not(.btn).is-here::after {
  transform: scaleX(1);
  transform-origin: left;
}

@media (max-width: 860px) {
  .phero {
    grid-template-columns: 1fr;
    gap: 0;
    min-height: 0;
  }

  /* Stacked here, so the plate goes back to full bleed. Without resetting the
     inset it would carry a left margin and sit flush right: lopsided. */
  .phero__plate {
    min-height: 0;
    aspect-ratio: 3 / 2;
    margin-left: 0;
    border-radius: 0;
  }

  .phero__body {
    padding-inline: clamp(1.25rem, 5vw, 3.5rem);
    padding-block: clamp(2.375rem, 6vw, 3.75rem);
    max-width: none;
  }

  .pair,
  .pair--wide {
    grid-template-columns: 1fr;
    gap: clamp(2.375rem, 6vw, 3.5rem);
  }
}

/* --- Inner page components ----------------------------------------------
   Shared by Offerings and Transformation, built from the same parts as the
   homepage: hairlines instead of shadows, 3px corners, Playfair headings with
   a blue accent phrase, the quiet label layer.
   ------------------------------------------------------------------------ */

/* Masthead for a page that opens on type rather than a photograph. */
.pagehead {
  padding-block: calc(var(--cap-h) + var(--cap-gap) + clamp(3rem, 7vw, 5.75rem))
    clamp(0.625rem, 1.6vw, 1.375rem);
}

/* The tight bottom above is right for a page head on paper: it flows straight
   into the next section and the two share their breathing room. As a solid
   band it is not, because that padding becomes a visible edge -- 176px of top
   against 22px of bottom, a ratio of 8:1, so the copy sat almost on the fold.

   Not matched to the top, which carries 84px of header-capsule clearance that
   reads as necessary rather than as space. Matched to the visual top instead:
   the 92px below the capsule, against 86px here. */
.pagehead.section--blue {
  padding-bottom: clamp(3rem, 6vw, 5.5rem);
}

.pagehead h1 {
  font-size: clamp(2.3rem, 5.2vw, 3.9rem);
  max-width: 18ch;
  margin-bottom: 1.375rem;
}

.pagehead__sub {
  max-width: 46ch;
  font-size: clamp(1rem, 1.2vw, 1.1rem);
  font-weight: 300;
  line-height: 1.6;
  color: var(--body);
}

/* --- Offerings ---------------------------------------------------------- */
/* No outer border. This element carries `wrap` as well, so `padding-inline`
   sat inside the border and the line was drawn around the padding rather than
   around the cards: 56px of bare paper between the rule and the tinted first
   column on either side, which read as a misdrawn box.

   The radius and the `overflow: hidden` went with it. Both existed to clip the
   card backgrounds to the rounded corner, and with the border gone there is
   nothing at that edge to round. The dividers between columns are separate --
   `.offer + .offer` -- and stay. */
.offers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
}

/* The card plate. Full-bleed to the card's own edges rather than inset, so the
   three images read as one band across the top of the table rather than three
   framed pictures. The negative margin cancels the card's padding; `.offers`
   clips at the outer corners. */
/* Four lines reserved: the three run 79, 118 and 103 characters, which is
   three, four and three lines in a card this wide. */
.offer__desc {
  min-height: 6.4em;
}

.offer__plate {
  position: relative;
  margin: calc(-1 * clamp(1.5rem, 2.6vw, 2.125rem));
  margin-bottom: clamp(1.25rem, 2.2vw, 1.75rem);
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--paper-warm);
}

.offer__plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Divided rather than gapped, so the three read as one table of options to
   choose between rather than three separate objects. */
.offer {
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 2.6vw, 2.125rem);
  background: var(--white);
}

/* A floor under the pushed button. `.btn--push` is `margin-top: auto`, which
   only distributes space that is left over -- so the tallest of the three
   cards had none and its button sat flush against the last tick, while the
   two shorter ones looked fine. Margins do not collapse in a flex container,
   so this adds to whatever `auto` resolves to rather than competing with it,
   and it is slightly more than the 28px above the list because a control
   needs more room than a list does. */
.offer .ticks {
  margin-bottom: clamp(1.625rem, 3vw, 2.375rem);
}

.offer + .offer {
  border-left: 1px solid var(--line);
}

/* The entry point to everything else on the page, so it is not simply the
   leftmost of three identical columns. */
.offer--lead {
  background: var(--blue-tint);
}

/* An h2, not an h3: these are the page's main content and jumping h1 -> h3
   skipped a level in the document outline. The size is a design decision and
   is set here; `max-width: none` releases the global h2 measure, which is cut
   for a section heading rather than a card title. */
/* Two lines reserved. "Executive Leadership Partnership" wraps and the other
   two do not, so without this its price sits a line lower than the others and
   the three stop reading as one table. */
.offer h2 {
  font-size: 1.28rem;
  max-width: none;
  min-height: 2.7em;
  margin-bottom: 0.875rem;
}

/* Reserves one price line for all three cards, so the row keeps a shared
   baseline even if a figure wraps or one of them ever reverts to a longer
   note. It was 84px while the third card carried a boxed "varies by client"
   line, which stood 29px taller than a plain figure and pushed that column's
   description a line below the other two. */
/* A column, not a row. As a row the term sat beside the price and aligned to
   its top, so "3-month engagement" rendered as a superscript hanging off
   "$3,000". The min-height reserves the two-line case so the three
   descriptions below still start level when only one card carries a term. */
.offer__slot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  min-height: 4.25rem;
  margin-bottom: 1.125rem;
}

.offer__price {
  font-family: var(--serif);
  font-size: clamp(1.7rem, 2.6vw, 2.1rem);
  font-weight: 400;
  line-height: 1;
}

/* The term under a price. Two of the three tiers are engagements rather than
   single sessions, and the length is as much a part of the offer as the
   number, so it sits with the price rather than in the body copy. */
.offer__term {
  margin-top: 0.375rem;
  font-size: 0.82rem;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--grey);
}

/* Team Development has no price yet. Set at the body grade rather than the
   serif display size the real prices use, so it does not read as a number. */
.offer__price--soon {
  font-family: var(--sans);
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--grey);
}

.offer__desc {
  font-size: 0.96rem;
  font-weight: 300;
  line-height: 1.62;
  color: var(--body);
}

.ticks {
  display: grid;
  gap: 0.6875rem;
  margin-top: clamp(1.25rem, 2.4vw, 1.75rem);
}

.ticks li {
  display: flex;
  gap: 0.6875rem;
  align-items: flex-start;
  font-size: 0.93rem;
  font-weight: 300;
  line-height: 1.45;
  color: var(--body);
}

/* Was hard-coded stroke="#013CA4" on all sixteen paths in the markup, which
   measured 1.38:1 against the deep-blue panel and 1.00:1 against the section
   itself -- invisible. The paths now inherit, and the colour comes from the
   accent role: --blue on light ground, unchanged at 9.62:1 on a white card,
   and #cfe0ff at 7.22:1 on blue. */
.ticks svg {
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  margin-top: 0.25rem;
  color: var(--accent);
}

/* --- Coming soon -------------------------------------------------------- */
.soon-band {
  padding-block: 0 var(--section-y);
}

/* Three columns, not two. A third item was added and it wrapped to a second
   row on its own, where `+ .soon__item` still gave it a left border and an
   indent, so it read as a broken cell rather than a third option. */
.soon {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  margin-top: clamp(1.125rem, 2vw, 1.625rem);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* Held at reduced strength: a roadmap, not a menu. Divided rather than boxed,
   because two more bordered panels here made three box-groups in a row. */
.soon__item {
  padding: clamp(1.25rem, 2.2vw, 1.625rem) 0;
}

.soon__item + .soon__item {
  padding-left: clamp(1.375rem, 3vw, 2.75rem);
  border-left: 1px solid var(--line);
}

.soon__item h3 {
  font-size: 1.14rem;
  margin-bottom: 0.5625rem;
  color: var(--grey);
}

.soon__item p {
  font-size: 0.93rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--grey);
}

/* --- Team development --------------------------------------------------- */
/* The page carried no imagery at all. This band sits directly above the group
   panel and is the one place a photograph belongs here: the branch of the work
   that is about a room of people rather than one person. */
.group__plate {
  position: relative;
  overflow: hidden;
  height: clamp(9.375rem, 17vw, 14.375rem);
  border-radius: 3px 3px 0 0;
  background: var(--paper-warm);
  min-height:340px;
}

.group__plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

.group {
  display: grid;
  grid-template-columns: 1.08fr 0.92fr;
  gap: clamp(1.875rem, 5vw, 4.75rem);
  /* Was `start`, which stranded a four-item list against a much taller lead
     column and left a large dead corner bottom right. */
  align-items: center;
  padding: clamp(1.75rem, 4vw, 3.5rem);
  background: var(--paper-warm);
  border: 1px solid var(--line-soft);
  /* Square across the top: it sits flush under its own plate. */
  border-top: 0;
  border-radius: 0 0 3px 3px;
}

/* Grid child: min-width:0 stops a long word widening the track. */
.group__lead {
  min-width: 0;
}

.group h2 {
  font-size: clamp(1.6rem, 2.6vw, 2.1rem);
  margin-bottom: 1.125rem;
}

.group .note {
  margin-bottom: 1.625rem;
}

/* Parent-scoped so it beats `.ticks` on specificity rather than on sitting
   later in the file, which is the discipline used everywhere else here. */
.group .group__list {
  margin-top: 0.375rem;
}

/* On a blue section the panel's --paper-warm resolves to #012a73, which put a
   darker blue box inside a brighter blue one: two blues close in hue but
   different in lightness, reading as an accident rather than a decision. The
   content sits straight on the section instead, and the inverted --line-soft
   hairline is what defines the block. */
.section--blue .group {
  background: transparent;
}

/* --- Transformation: friction to flow ----------------------------------- */
.ff {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0;
  margin-top: clamp(1.625rem, 3vw, 2.25rem);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}

/* Centred, as asked, but designed for it rather than switched to it. The first
   attempt just set text-align and it read as four plaques, for four reasons
   that are all addressed below: the divider stayed full-width so it anchored
   to edges the text no longer reached; the lines were not balanced so they
   wobbled; the statements wrapped to different line counts so the cells did
   not match; and the labels were heavier than their own content. */
.ff__item {
  padding: clamp(1.75rem, 3.4vw, 2.75rem);
  text-align: center;
  background: var(--white);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}

.ff__item:nth-child(-n + 2) {
  border-top: 0;
}

.ff__item:nth-child(odd) {
  border-left: 0;
}

/* Bold and black for FRICTION, which was the fallback in your manager's note,
   and it is the right one: the only other contrast tone in the palette is
   --tan, and tan measures 3.55:1 on this white card. It fails AA at label
   size, which is exactly why it was retired as label type earlier and left as
   marks only. --text measures 17.05:1.

   It also reads better than tan would. Black and heavy for the stuck half,
   blue for the turn: the weight carries the meaning and the colour carries
   the pair. Both labels take the weight so they stay a matched set; only the
   colour separates them. */
/* Highlighted, as chips rather than as loose caps. Two small badges centre
   far better than two lines of tracked text do, so this also firms up the
   centred layout the rest of the section is now built on.

   The two grounds are deliberately the same strength: ink at 0.07 is a 1.15:1
   step off the white card and --blue-tint is 1.13:1, so the pair reads as
   matched and only the hue separates them. Text holds at 14.84:1 and 8.51:1.

   The right padding is short by the tracking value. Letter-spacing adds space
   after every letter including the last, so symmetric padding would sit the
   word visibly left of centre in its own chip. */
.tag,
.ff__k {
  display: inline-block;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
  background: rgba(24, 28, 37, 0.07);
  border-radius: 999px;
  padding: 0.375rem 0.6875rem 0.375rem 0.75rem;
}

/* Size and rhythm differ by role, so they sit here rather than in the shared
   rule above -- setting them twice on `.tag` would be a real duplicate, not an
   override. `.ff__k` labels half of a small cell; `.tag` heads a whole column
   on About and can carry more weight. */
.ff__k {
  font-size: 0.72rem;
  margin-bottom: 0.875rem;
}

.tag {
  font-size: 0.86rem;
  margin-bottom: 1.125rem;
}

/* Same trap as the stats band: that 36px top margin existed to clear the
   "Friction to flow" eyebrow, and with the eyebrow gone the table is the first
   thing in its wrap, so the margin was stacking on the section's own padding.
   Nothing above it now needs clearing. */
.wrap > .ff:first-child {
  margin-top: 0;
}

/* The turn. Blue and a rule above it, so the eye can find the second half of
   each pair without reading the label. */
/* The turn. The chip does the work the rule used to: a blue badge is a far
   stronger cue for "second half of the pair" than a hairline was, and it does
   not have the rule's problem of anchoring to cell edges that centred content
   never reaches. So the divider is gone and the separation is margin. */
/* The turn. Blue rather than black; the chip does the work a hairline rule
   used to. Split so the margin belongs to the Friction-to-Flow cell only --
   `.tag--flow` is used on the About pair, where the two sit in separate
   columns and need no gap above. */
.tag--flow,
.ff__k--flow {
  color: var(--accent);
  background: var(--blue-tint);
}

.ff__k--flow {
  margin-top: 1.625rem;
}


/* Up from 0.96rem and 300. At the larger size a 300 weight reads thin and
   cold, so it steps to 400 -- the same weight floor applied across the body
   copy elsewhere. About 20px at 1440, roughly 46 characters to the line in a
   half-width cell, so the measure stays comfortable while centred. */
/* 20px, and the measure is the reason it works at 20px this time. Capped at
   42ch, which is the width where all eight statements land on exactly two
   lines -- they run 54 to 80 characters, so anything narrower splits the long
   ones to three and the cells stop matching. At 42ch and 20px that is 420px
   inside 468px of usable cell, so it fits with room.

   `balance` evens the two lines rather than filling the first and leaving a
   short second, which is what stops centred text looking wobbly. */
.ff__t {
  font-size: clamp(1.05rem, 1.4vw, 1.25rem);
  font-weight: 400;
  line-height: 1.55;
  color: var(--body);
  max-width: 42ch;
  margin-inline: auto;
  text-wrap: balance;
}

/* --- Transformation: case studies --------------------------------------- */
.cases {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.875rem, 1.8vw, 1.375rem);
  margin-top: clamp(1.625rem, 3vw, 2.25rem);
}

.case {
  padding: clamp(1.375rem, 2.4vw, 1.875rem);
  text-align: center;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
}

/* --- Sourced figures and cases -------------------------------------------
   Both blocks now carry framing that is load-bearing rather than decorative:
   the figures are the profession's, not Stewart's, and the cases are the
   ICF's. Each line is styled to be read, not skimmed past.
   ------------------------------------------------------------------------ */
.stats__lead {
  max-width: 58ch;
  font-size: clamp(1rem, 1.3vw, 1.12rem);
  font-weight: 400;
  line-height: 1.6;
  color: var(--body);
}

/* The margin here is tuned to follow a lead line, not the figure-and-heading
   stack the homepage band sits under, so it is scoped to this section. */
#figures .stats {
  margin-top: clamp(1.5rem, 2.6vw, 2.25rem);
}

.stats__src {
  margin-top: clamp(1rem, 1.8vw, 1.375rem);
  max-width: 72ch;
  font-size: 0.78rem;
  font-weight: 400;
  line-height: 1.65;
  color: var(--grey);
}

.stats__src em {
  font-style: italic;
}

.cases__lead {
  max-width: 60ch;
  margin: 0.875rem auto 0;
  text-align: center;
  font-size: clamp(0.95rem, 1.2vw, 1.05rem);
  font-weight: 400;
  line-height: 1.6;
  color: var(--body);
}

.case__who {
  margin-top: 0.5rem;
  font-size: 0.86rem;
  font-weight: 400;
  color: var(--grey);
}

/* Underlined rather than a pill: these leave the site, and a button would
   read as one of Stewart's own actions. */
.case__go {
  display: inline-block;
  margin-top: clamp(1rem, 1.8vw, 1.375rem);
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  text-decoration-thickness: 1px;
}

.case__go:hover {
  text-decoration-thickness: 2px;
}

.case__sector {
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
  margin-bottom: 0.875rem;
}

/* Also promoted from h3 to close the outline gap after the page h1. */
/* The section heading, big and centred. It was a `.kicker` -- an 11px tracked
   paragraph -- so making it big meant making it a real h2 as well, or the page
   would carry a 48px visual heading that the document outline calls body text.
   The card titles drop to h3 for the same reason: with the section owning an
   h2, three sibling h2s inside it would read as four peers with no parent.

   `margin-inline: auto` because the global h2 caps at 21ch, and a capped block
   does not centre on text-align alone. */
.cases__t {
  text-align: center;
  margin-inline: auto;
}

/* `balance` because the three titles run 23 to 28 characters and there is a
   narrow band just above the 960px stack point where the longest one wraps:
   234px of title against 235px of card. Centred, an uneven two-line break is
   the first thing the eye catches. */
.case h3 {
  font-family: var(--serif);
  font-size: 1.16rem;
  max-width: none;
  line-height: 1.28;
  text-wrap: balance;
}

/* The grid override that used to live here is gone: `.voices` now declares
   the equal-column layout directly. The class stays on the element because
   the rule below and the 960px collapse both key off it. */
.voices--grid .voice:first-child .voice__q {
  font-size: 1rem;
  line-height: 1.6;
}

@media (max-width: 960px) {
  .offers,
  .ff,
  .cases,
  .voices--grid {
    grid-template-columns: 1fr;
  }

  .offer + .offer {
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  .ff__item {
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  .ff__item:first-child {
    border-top: 0;
  }

  .soon,
  .group {
    grid-template-columns: 1fr;
  }

  /* Stacked, so the divider between items turns from vertical to horizontal.
     Left over, it drew a stray rule down the side of every item but the first
     and indented them all. */
  .soon__item + .soon__item {
    padding-left: 0;
    padding-top: clamp(1.25rem, 2.2vw, 1.625rem);
    border-left: 0;
    border-top: 1px solid var(--line);
  }
}

/* --- Insights: the bento ------------------------------------------------
   One lead across the full width, two beneath it. Divided rather than gapped
   so the three read as one body of writing, and the grid has no cell it
   cannot fill: it grows by adding a card, not by leaving a hole.
   ------------------------------------------------------------------------ */
.bento {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0;
  margin-top: clamp(1.875rem, 4vw, 3rem);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}

.post {
  display: flex;
  flex-direction: column;
  padding: clamp(1.625rem, 3vw, 2.5rem);
  background: var(--white);
}

.post + .post {
  border-top: 1px solid var(--line);
}

.post + .post + .post {
  border-left: 1px solid var(--line);
}

/* The featured piece: full width, and the only one running its meta in a
   column of its own beside the text. */
.post--lead {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: flex-start;
  gap: clamp(1.5rem, 4vw, 4rem);
}

.post--lead .post__body {
  flex: 1 1 auto;
  min-width: 0;
}

.post--lead h2 {
  font-size: clamp(1.5rem, 2.7vw, 2.15rem);
  max-width: 26ch;
  margin-bottom: 1rem;
}

.post--lead .post__meta {
  flex: none;
  margin-top: 0;
  padding-top: 0;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.375rem;
  text-align: right;
}

.post__cat {
  font-size: 0.65625rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
  margin-bottom: 0.875rem;
}

.post h3 {
  font-size: clamp(1.1rem, 1.7vw, 1.32rem);
  line-height: 1.3;
  max-width: 24ch;
  margin-bottom: 0.875rem;
}

.post__dek {
  font-size: 0.96rem;
  font-weight: 300;
  line-height: 1.62;
  color: var(--body);
  max-width: 52ch;
}

.post__meta {
  display: flex;
  align-items: center;
  gap: 0.5625rem;
  margin-top: auto;
  padding-top: 1.375rem;
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey);
}

.post__dot {
  color: var(--line);
}

.bento__note {
  margin-top: clamp(1.25rem, 2.4vw, 1.75rem);
  font-size: 0.9rem;
  font-weight: 300;
  color: var(--grey);
}

/* --- Booking ------------------------------------------------------------- */
.bookhero {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  min-height: clamp(18.75rem, 34vw, 26.25rem);
  padding-block: 0 clamp(1.875rem, 4vw, 3.25rem);
  /* Brand blue, not navy: this is the only page with no --blue section,
     and at #0b1f3f it read as near-black rather than as the brand. */
  background: var(--blue);
}

.bookhero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.bookhero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 42%;
}

/* Weighted to the lower left, under the title. */
.bookhero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
      12deg,
      rgba(11, 31, 63, 0.86) 0%,
      rgba(11, 31, 63, 0.6) 46%,
      rgba(11, 31, 63, 0.22) 82%,
      rgba(11, 31, 63, 0.1) 100%
    ),
    linear-gradient(180deg, rgba(11, 31, 63, 0.34) 0%, rgba(11, 31, 63, 0) 42%);
}

.bookhero__in {
  position: relative;
  z-index: 2;
}

.bookhero h1 {
  color: var(--white);
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  max-width: 20ch;
}

.book__lead {
  max-width: 62ch;
}

.book__lead h2 {
  font-size: clamp(1.45rem, 2.4vw, 1.95rem);
  max-width: 26ch;
  margin-bottom: 1.25rem;
}

.book__lead .note + .note {
  margin-top: 0.875rem;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  margin-top: clamp(1.5rem, 3vw, 2.125rem);
}

.chips li {
  padding: 0.5625rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.86rem;
  font-weight: 400;
  color: var(--body);
}

/* --- Stepper ------------------------------------------------------------- */
.stepper {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0;
  margin: clamp(2.125rem, 4.4vw, 3.5rem) 0 clamp(1.5rem, 3vw, 2.125rem);
}

.stepper__s {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey);
}

.stepper__s + .stepper__s {
  position: relative;
  margin-left: 0.875rem;
  padding-left: 1.5rem;
}

.stepper__s + .stepper__s::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 0.875rem;
  height: 1px;
  background: var(--line);
}

.stepper__n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  font-size: 0.71875rem;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

.stepper__s.is-done .stepper__n {
  border-color: var(--blue);
  color: var(--blue);
}

.stepper__s.is-now .stepper__n {
  background: var(--blue);
  border-color: var(--blue);
  color: var(--white);
}

.stepper__s.is-now {
  color: var(--text);
}

/* Only the current step names itself; the two behind it are numerals alone,
   so the row reads as progress rather than as three competing labels. */
.stepper__l {
  display: none;
}

.stepper__s.is-now .stepper__l {
  display: inline;
}

/* --- Picker and form ----------------------------------------------------- */
.book__cols {
  display: grid;
  /* grid-template-columns: 1.05fr 0.95fr; */
  grid-template-columns: 1;
  gap: clamp(1.125rem, 2.4vw, 1.875rem);
  align-items: start;
}

.picker {
  padding: clamp(1.375rem, 2.8vw, 2.125rem);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
}

.picker__month {
  display: flex;
  align-items: center;
  gap: 0.5625rem;
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey);
}

.picker__month svg {
  width: 0.9375rem;
  height: 0.9375rem;
}

.picker__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.25rem;
}

.picker__day {
  font-size: 1rem;
  font-weight: 400;
  color: var(--text);
}

.picker__days,
.picker__times {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.375rem, 1fr));
  gap: 0.625rem;
  margin-top: 1rem;
}

.slot {
  padding: 0.8125rem 0.625rem;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
  font-family: var(--sans);
  font-size: 0.94rem;
  font-weight: 400;
  color: var(--text);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
}

.slot:hover {
  border-color: rgba(1, 60, 164, 0.4);
}

.slot.is-on {
  background: var(--blue-tint);
  border-color: var(--blue);
  color: var(--blue);
  font-weight: 500;
}

.slot__sub {
  display: block;
  margin-top: 3px;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--grey);
}

.slot.is-on .slot__sub {
  color: var(--blue);
}

.picker__prompt {
  margin-top: 1.625rem;
  font-size: 0.94rem;
  font-weight: 300;
  color: var(--body);
}

.picker__sum {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-size: 0.9rem;
  font-weight: 400;
  color: var(--accent);
}

.picker__sum svg {
  flex: none;
  width: 1rem;
  height: 1rem;
}

.details {
  padding: clamp(1.375rem, 2.8vw, 2.125rem);
  background: var(--paper-warm);
  border: 1px solid var(--line-soft);
  border-radius: 3px;
}

.field {
  display: block;
  margin-top: 1.125rem;
}

.field__l {
  display: block;
  margin-bottom: 0.4375rem;
  font-size: 0.86rem;
  font-weight: 400;
  color: var(--text);
}

.field__l em {
  font-style: normal;
  color: var(--accent);
}

.field input,
.field textarea {
  width: 100%;
  padding: 0.75rem 0.875rem;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
  font-family: var(--sans);
  font-size: 0.96rem;
  font-weight: 400;
  color: var(--text);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.field textarea {
  min-height: 6rem;
  line-height: 1.55;
  resize: vertical;
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--grey);
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(1, 60, 164, 0.1);
}

.details .btn {
  margin-top: 1.5rem;
}

.details__micro {
  margin-top: 1rem;
  font-size: 0.84rem;
  font-weight: 600;
  line-height: 1.55;
  color: #079b0e;
  text-align: center;
}

.details__micro a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

@media (max-width: 960px) {
  .bento {
    grid-template-columns: 1fr;
  }

  .post + .post + .post {
    border-left: 0;
  }

  .post--lead {
    flex-direction: column;
  }

  .post--lead .post__meta {
    flex-direction: row;
    align-items: flex-start;
    text-align: left;
    padding-top: 1.375rem;
  }

  .book__cols {
    grid-template-columns: 1fr;
  }
}

/* --- Footer -------------------------------------------------------------
   The wordmark is set in type rather than the PNG: the supplied logo is
   dark-on-light and has no reversed variant, so it cannot sit on navy.
   ------------------------------------------------------------------------ */
/* --- Footer -------------------------------------------------------------
   The mark, oversized and bleeding off the left and bottom, as a graphic field
   rather than a logo placement. Everything readable sits in a column to its
   right and never over it, so the mark can carry real weight without becoming
   a background the text has to fight.

   Brand blue now, not --blue-ink. That moved the alpha floor: white at 0.55
   measures 5.78:1 on navy but only 3.96:1 on --blue, and the old footer meta
   was at 0.55. Nothing below 0.62 survives here, so the quiet rungs are 0.66
   and 0.72 rather than 0.55.
   ------------------------------------------------------------------------ */
.footer {
  position: relative;
  overflow: hidden;
  background: var(--blue-ink);
  color: rgba(255, 255, 255, 0.82);
  padding-block: clamp(3.25rem, 6vw, 5rem) 1.75rem;
}

/* Decorative and inert: aria-hidden in the markup, and out of the hit-testing
   so it can sit under the grid without swallowing clicks. */
/* Decorative and inert: aria-hidden in the markup, and out of the hit-testing
   so it can sit under the grid without swallowing clicks.

   Sized so it never reaches the right column. At min(58%, 44rem) it did, but
   only in a band -- clear at 1440 and 1920, overlapping by 26 to 36px from
   about 1200px down to the 860px stack point, because the container stops
   growing at 1200 while the mark keeps tracking the viewport. min(48%, 36rem)
   holds a 69px clearance at its tightest, which is 861px.
   ------------------------------------------------------------------------ */
.fmark {
  position: absolute;
  left: -4%;
  bottom: -16%;
  z-index: 0;
  width: min(48%, 36rem);
  pointer-events: none;
}

.fmark__svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Three alphas rather than one flat fill, so the mark's internal stagger still
   reads as the logo instead of as an anonymous silhouette. The reference is
   solid, but solid white over this much of a saturated panel would outshout
   the header lockup on every page. */
.fmark__a { stroke: rgba(255, 255, 255, 0.26); }
.fmark__b { stroke: rgba(255, 255, 255, 0.38); }
.fmark__c { stroke: rgba(255, 255, 255, 0.16); }

.footer__grid {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: end;
  min-height: clamp(17rem, 26vw, 24rem);
}

/* The lockup column. On desktop only the wordmark is in flow here -- the mark
   inside is absolute and bleeds off the panel -- so this just holds the words
   at the bottom of the column, level with the base row opposite. */
.footer__lock {
  align-self: end;
}

.brandmark {
  display: inline-block;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 1rem;
  line-height: 1;
  letter-spacing: 0.02em;
  color: #fff;
  border-left: 2px solid var(--tan);
  padding-left: 0.75rem;
}

.brandmark small {
  display: block;
  margin-top: 0.375rem;
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.24em;
  color: rgba(255, 255, 255, 0.72);
}

.footer__side {
  display: grid;
  gap: clamp(1.5rem, 2.6vw, 2.25rem);
}

/* The one lifted surface, so the action is not just another line of text. */
.footer__card {
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 0.75rem;
  padding: clamp(1.25rem, 2.2vw, 1.625rem);
}

/* One line. The `max-width: 18ch` I had here was the only thing wrapping it:
   the string is 26 characters, about 300px of Playfair at this size, inside
   464px of usable card at 1440. The cap was 230px. It holds on one line from
   1024 up, because the card and the type scale off the same root, so the
   ratio is constant -- 300 against 464 at 1440, 399 against 619 at 1920.

   `nowrap` as a floor rather than a bet: below the stacking breakpoint the
   card goes full width and has far more room, so this cannot clip. */
.footer__card-t {
  font-family: var(--serif);
  font-size: clamp(1.24rem, 2vw, 1.6rem);
  line-height: 1.2;
  color: #fff;
  margin-bottom: 1.125rem;
  white-space: nowrap;
}

.footer__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

.footer__col {
  display: grid;
  align-content: start;
  gap: 0.5rem;
}

.footer__ck {
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.66);
  margin-bottom: 0.25rem;
}

.footer__col a {
  font-size: 0.9rem;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.82);
  transition: color 0.2s ease;
}

.footer__col a:hover {
  color: #fff;
}

.footer__meta {
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.85;
  color: rgba(255, 255, 255, 0.72);
}

.footer__base {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.25rem;
  flex-wrap: wrap;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.66);
}

.footer__tag {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.06rem;
  color: rgba(255, 255, 255, 0.82);
}

/* --- Footer stacked ------------------------------------------------------
   There was no branch here at all, which left a two-column grid and a mark at
   58% of the width on a phone. Stacked, the mark can be larger as a share of
   the frame because nothing sits beside it, and it drops behind the type
   instead of alongside it.
   ------------------------------------------------------------------------ */
@media (max-width: 860px) {
  .footer__grid {
    grid-template-columns: 1fr;
    gap: clamp(1.75rem, 5vw, 2.5rem);
    min-height: 0;
  }

  /* Back into the flow and small. The oversized treatment is a desktop move:
     it works because a text column sits beside it and the two share the width.
     Stacked there is nothing beside it, so at full width it stops being a
     graphic field and becomes a large object the reader has to scroll past
     before reaching a single word.

     At 3.5rem it is a mark above a wordmark -- a lockup, which is what a
     footer identity should be on a phone. */
  /* One row, mark at one end and the words at the other. Now that they are
     siblings this is a single flex rule rather than two stacked blocks. */
  .footer__lock {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
  }

  /* Pulled out of the grid's own gutter so it sits hard on the left edge.
     The negative margin is exactly the padding `.footer__grid` applies, so the
     mark's left edge lands at x=0 while the wordmark stays on the gutter at
     the other end. `.footer` clips, so this cannot cause a scrollbar. */
  .fmark {
    position: static;
    width: 3.25rem;
    flex: none;
    margin-bottom: 0;
    margin-left: calc(-1 * clamp(1.25rem, 5vw, 3.5rem));
  }

  /* The tan rule reads as a left edge, and at the right end of a row there is
     nothing to its left to edge against. */
  .footer__lock .brandmark {
    border-left: 0;
    padding-left: 0;
    text-align: right;
  }

  /* Near-solid at this size. The desktop alphas are calibrated for something
     covering half the panel; at 56px they would read as a smudge. */
  .fmark__a { stroke: rgba(255, 255, 255, 0.72); }
  .fmark__b { stroke: rgba(255, 255, 255, 0.95); }
  .fmark__c { stroke: rgba(255, 255, 255, 0.5); }
}

@media (max-width: 560px) {
  .chips{
    margin-bottom:20px;
  }
  .footer__cols {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }

  .footer__base {
    flex-direction: column;
    gap: 0.5rem;
  }
}

/* ==========================================================================
   Motion: restrained by instruction

   One gesture: a short fade-and-lift on entry. No parallax, no scroll
   hijacking, no per-word reveals. Hidden states are gated behind `.js`, and
   `js/main.js` carries a fallback that reveals anything still hidden, so a
   script failure can never leave content invisible.
   ========================================================================== */
.js [data-in] {
  opacity: 0;
  transform: translateY(0.875rem);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  transition-delay: var(--d, 0s);
}

.js [data-in].in {
  opacity: 1;
  transform: none;
}

/* Photography opens rather than lifts. A second gesture so the page is not
   one fade-up repeated forty times, but still no motion cost worth naming:
   clip-path and transform are both compositor-only. */
.js .row__media[data-in] {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.85s var(--ease);
}

.js .row__media[data-in].in {
  clip-path: inset(0 0 0 0);
}

/* The picture settles back as the frame opens. */
.js .row__media[data-in] img {
  transform: scale(1.06);
  transition: transform 1.2s var(--ease);
}

.js .row__media[data-in].in img {
  transform: none;
}

/* --- Friction to Flow: the turn, on scroll ------------------------------
   Instead of pinning this section the way the voices rail does, the motion
   comes from the content: each cell's friction half arrives, then its flow
   chip and statement follow a beat later. The section already means "this
   becomes that", so the reveal says the same thing rather than decorating it,
   and it costs no scroll at all -- the rail would have added three screens to
   a page that currently has none.

   The cell itself is neutralised, because the generic fade-up would otherwise
   compound with the children's and read as a drift. Same arrangement the hero
   headline uses.

   Targeted by class rather than by nth-child, so the pairing survives a
   markup change: the flow half is the chip and whatever statement follows it.
   ------------------------------------------------------------------------ */
.js .ff__item[data-in] {
  opacity: 1;
  transform: none;
}

.js .ff__item[data-in] > * {
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
  transition-delay: var(--d, 0s);
}

.js .ff__item[data-in].in > * {
  opacity: 1;
  transform: none;
}

/* The beat. 0.3s is long enough to register as a turn rather than as one
   block arriving unevenly, and short enough not to feel like a wait. */
.js .ff__item[data-in] > .ff__k--flow {
  transition-delay: calc(var(--d, 0s) + 0.3s);
}

.js .ff__item[data-in] > .ff__k--flow + .ff__t {
  transition-delay: calc(var(--d, 0s) + 0.38s);
}

/* And the four cells cascade in reading order. */
.js .ff__item:nth-child(1) { --d: 0s; }
.js .ff__item:nth-child(2) { --d: 0.08s; }
.js .ff__item:nth-child(3) { --d: 0.16s; }
.js .ff__item:nth-child(4) { --d: 0.24s; }

/* Hover scale must win over the reveal's resting transform. */
.js .row__media[data-in].in:hover img {
  transform: scale(1.03);
}

/* --- Hero entrance -------------------------------------------------------
   The hero arrives top to bottom rather than all at once. It runs on the
   same [data-in] mechanism as the rest of the page, so it inherits the
   audit sweep and the 4s fallback: if the script dies, the hero still
   reads. Every property animated below is transform or opacity, so the
   whole sequence stays on the compositor.
   ------------------------------------------------------------------------ */
.js .hero__eyebrow { --d: 0.05s; }
.js .hero__sub { --d: 0.34s; }
.js .hero__act { --d: 0.46s; }
.js .hero__proof { --d: 0.6s; }

/* The plate settles rather than fades: a slow release of scale over the
   first two and a half seconds. `both` holds the end state, and the whole
   rule is behind `.js`, so with no script the image simply sits at 1. */
@keyframes heroPlate {
  from {
    transform: scale(1.07);
  }
  to {
    transform: scale(1);
  }
}

.js .hero__media img {
  animation: heroPlate 2.5s var(--ease) both;
}

/* The two flanking rules draw outward from the label. */
.js .hero__eyebrow .r {
  transform: scaleX(0);
  transition: transform 0.85s var(--ease);
  transition-delay: calc(var(--d, 0s) + 0.12s);
}

.js .hero__eyebrow .r:first-child {
  transform-origin: right center;
}

.js .hero__eyebrow .r:last-child {
  transform-origin: left center;
}

.js .hero__eyebrow.in .r {
  transform: scaleX(1);
}

/* The headline rises out of its own baseline, one line at a time. The
   generic fade-up is switched off for the h1 so the two gestures do not
   compound into a drift. */
.js .hero h1[data-in] {
  opacity: 1;
  transform: none;
}

.js .hero h1 .ln {
  overflow: hidden;
  /* The mask would otherwise crop Playfair's descenders and the overhang of
     the italic. Padding buys the room back, the negative margin keeps the
     line spacing where it was. */
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
  padding-right: 0.06em;
  margin-right: -0.06em;
}

.js .hero h1 .ln__i {
  display: block;
  transform: translateY(112%);
  transition: transform 0.95s var(--ease);
  transition-delay: var(--d, 0s);
}

.js .hero h1.in .ln__i {
  transform: translateY(0);
}

.js .hero h1 .ln:nth-child(1) { --d: 0.16s; }
.js .hero h1 .ln:nth-child(2) { --d: 0.32s; }

/* The ground opens after the button itself lands. scaleY only, for two
   reasons: the band runs the full viewport width now, so scaling it on X
   would pull its edges into frame, which is the one thing a full-bleed band
   must never do; and it carries no layout, so the reduced-motion reset can
   strip it and still leave the band correctly placed. */
.js .hero__act::before {
  opacity: 1;
  transform: scaleY(1);
  transition: opacity 2.1s var(--ease), transform 2.6s var(--ease);
  transition-delay: calc(var(--d, 0s) + 0.18s);
}

.js .hero__act.in::before {
  opacity: 0;
  transform: scaleY(0.72);
}

/* The credential band's names come in as a run, left to right. */
.js .hero__brands li {
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}

.js .hero__proof.in .hero__brands li {
  opacity: 1;
  transform: none;
}

.js .hero__brands li:nth-child(1) { transition-delay: 0.72s; }
.js .hero__brands li:nth-child(2) { transition-delay: 0.8s; }
.js .hero__brands li:nth-child(3) { transition-delay: 0.88s; }
.js .hero__brands li:nth-child(4) { transition-delay: 0.96s; }

/* Section headings wipe open rather than fading up with everything else, so
   each section announces itself. The generic fade is switched off for them so
   the two gestures do not compound.

   The negative top and bottom insets are load-bearing: clipped at inset(0) a
   Playfair heading loses its descenders and the tops of its ascenders. */
.js h2[data-in] {
  opacity: 1;
  transform: none;
  clip-path: inset(-0.16em 0 100% 0);
  transition: clip-path 0.9s var(--ease);
  transition-delay: var(--d, 0s);
}

.js h2[data-in].in {
  clip-path: inset(-0.16em 0 -0.32em 0);
}

/* The stand panel's two columns arrive from their own sides. The container's
   own lift is cancelled so only the columns move. */
.js .stand[data-in] {
  opacity: 1;
  transform: none;
}

.js .stand[data-in] .stand__col {
  opacity: 0;
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

.js .stand[data-in] .stand__col--against { transform: translateX(-1rem); }
.js .stand[data-in] .stand__col--for { transform: translateX(1rem); }

.js .stand[data-in].in .stand__col {
  opacity: 1;
  transform: none;
}

/* Both lists tick down in step with each other. */
.js .stand[data-in] .stand__col li {
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}

.js .stand[data-in].in .stand__col li {
  opacity: 1;
  transform: none;
}

.js .stand__col li:nth-child(1) { transition-delay: 0.28s; }
.js .stand__col li:nth-child(2) { transition-delay: 0.36s; }
.js .stand__col li:nth-child(3) { transition-delay: 0.44s; }
.js .stand__col li:nth-child(4) { transition-delay: 0.52s; }

/* The price rows come in as a run. They are children of one revealed block
   rather than four separately tracked ones, which keeps the reveal list short
   and still lets them stagger. */
.js .price[data-in] .price__row {
  opacity: 0;
  transform: translateY(0.625rem);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
}

.js .price[data-in].in .price__row {
  opacity: 1;
  transform: none;
}

.js .price__row:nth-child(1) { transition-delay: 0.04s; }
.js .price__row:nth-child(2) { transition-delay: 0.13s; }
.js .price__row:nth-child(3) { transition-delay: 0.22s; }
.js .price__row:nth-child(4) { transition-delay: 0.31s; }

/* The quote's blue rule draws down before the words settle. */
.js .pull[data-in]::before {
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 0.7s var(--ease);
  transition-delay: 0.12s;
}

.js .pull[data-in].in::before {
  transform: scaleY(1);
}

/* The band's rules draw outward from the left as it arrives.

   Keyed off the container's own [data-in] rather than off `:has(.stat.in)`.
   With :has() the hidden state would apply but the reveal would never fire in
   an engine that does not support it, leaving the hairlines permanently at
   scaleX(0). [data-in] is covered by the fallback timer, so a failure ends
   with them drawn rather than gone. The container's own lift is cancelled;
   only the rules move. */
.js .stats[data-in] {
  opacity: 1;
  transform: none;
}

.js .stats[data-in]::before,
.js .stats[data-in]::after {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.9s var(--ease);
}

.js .stats[data-in].in::before,
.js .stats[data-in].in::after {
  transform: scaleX(1);
}

/* The closing section's three assurances arrive one after another. */
.js .closing__meta[data-in] span {
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}

.js .closing__meta[data-in].in span {
  opacity: 1;
}

.js .closing__meta span:nth-child(1) { transition-delay: 0.1s; }
.js .closing__meta span:nth-child(2) { transition-delay: 0.22s; }
.js .closing__meta span:nth-child(3) { transition-delay: 0.34s; }

/* Retargeted from `.footer__nav`, which the rebuild replaced with a two-column
   `.footer__cols`. The links tick down inside it as the block arrives. */
.js .footer__cols[data-in] .footer__col a {
  opacity: 0;
  transform: translateY(0.375rem);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
}

.js .footer__cols[data-in].in .footer__col a {
  opacity: 1;
  transform: none;
}

.js .footer__col a:nth-of-type(1) { transition-delay: 0.06s; }
.js .footer__col a:nth-of-type(2) { transition-delay: 0.13s; }
.js .footer__col a:nth-of-type(3) { transition-delay: 0.2s; }
.js .footer__col a:nth-of-type(4) { transition-delay: 0.27s; }
.js .footer__col a:nth-of-type(5) { transition-delay: 0.34s; }

/* The mark itself settles rather than fades: it is the largest thing on the
   page and a plain opacity ramp on that much area reads as a flash. */
/* The footer element only carries data-in so the mark can key off `.in`; the
   footer itself must not fade, or every word in it would fade with it. */
.js .footer[data-in] {
  opacity: 1;
  transform: none;
}

.js .fmark {
  opacity: 0;
  transform: translateY(1.5rem);
  transition: opacity 1.1s var(--ease), transform 1.1s var(--ease);
}

.js .footer.in .fmark {
  opacity: 1;
  transform: none;
}

/* The nav link for whichever section is in view. */
.nav a:not(.btn).is-current {
  color: var(--text);
}

.nav a:not(.btn).is-current::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Small cascades where a group arrives together. */
.js .pain:nth-of-type(1) { --d: 0.04s; }
.js .pain:nth-of-type(2) { --d: 0.1s; }
.js .pain:nth-of-type(3) { --d: 0.16s; }
.js .pain:nth-of-type(4) { --d: 0.22s; }

.js .voice:nth-child(1) { --d: 0.04s; }
.js .voice:nth-child(2) { --d: 0.12s; }
.js .voice:nth-child(3) { --d: 0.2s; }

.js .stat:nth-child(1) { --d: 0.04s; }
.js .stat:nth-child(2) { --d: 0.1s; }
.js .stat:nth-child(3) { --d: 0.16s; }
.js .stat:nth-child(4) { --d: 0.22s; }

@media (prefers-reduced-motion: reduce) {
  .js *,
  .js *::before,
  .js *::after {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
    clip-path: none !important;
  }

  html {
    scroll-behavior: auto;
  }

  /* Both pinned sections buy their scroll length from a tall track. Killing
     the transforms above is not enough on its own: the track would still be
     360vh and 300vh of nothing to scroll through, with a stage pinned in the
     middle of it. Collapse the tracks so each section is an ordinary block.
     Design 2 did not handle this for its own section either. */
  .method-track,
  .rail__track,
  .js .epic__track {
    height: auto;
  }

  .method-stage,
  .rail__stage,
  /* `display: block`, and its absence was the bug. The stage became a flex
     container when the caption needed pinning bottom-right, and neither
     collapse branch undid it -- so the plate, the copy column and the caption
     stopped stacking and became three flex items in a ROW, each squeezed to a
     third of a phone. That is why the quote was setting one word per line. */
  .js .epic__stage {
    position: static;
    display: block;
    height: auto;
    overflow: visible;
    max-width: var(--container);
    margin-inline: auto;
    padding-inline: clamp(1.25rem, 5vw, 3.5rem);
  }

  .js .epic__in {
    max-width: none;
    padding-inline: 0;
    text-align: left;
  }

  /* The three hard breaks are a desktop composition; stacked they would give
     six short lines, so the spans run inline and wrap on their own. */
  .js .epic__ln,
  .js .epic__ln i {
    display: inline;
  }

  /* The statement needs its whole plain-block treatment back, not just its
     transforms killed: at 208px and nowrap, x:0 shows a quarter of the
     sentence and hides the rest. */
  .js .epic {
    padding-block: var(--section-y);
  }

  .js .epic__media {
    position: relative;
    inset: auto;
    aspect-ratio: 3 / 2;
    border-radius: 3px;
    margin-bottom: clamp(1.75rem, 3.4vw, 2.625rem);
  }

  .js .epic__veil {
    display: none;
  }

  .js-run .epic__ln i,
  .js .epic__ln i {
    transform: none;
  }

  .js .epic__ln {
    overflow: visible;
  }

  .js .epic__line {
    position: static;
    width: auto;
    white-space: normal;
    text-wrap: balance;
    max-width: 20ch;
    font-size: clamp(1.6rem, 6vw, 2.4rem);
    line-height: 1.26;
    letter-spacing: -0.02em;
  }

  .js .epic__body {
    position: static;
    display: block;
    padding-inline: 0;
    margin-top: clamp(1.25rem, 2.4vw, 1.875rem);
  }

  .js .epic__body .note {
    text-align: left;
    max-width: 50ch;
    font-size: 1.02rem;
  }

  .js .epic__cap {
    position: static;
    margin-top: 0.875rem;
  }

  .method-stage {
    padding-block: var(--section-y);
  }

  .rail {
    padding-block: var(--section-y);
  }

  /* One step at a time is a scroll effect; without it all three must show. */
  .m-step {
    position: static;
    opacity: 1;
  }

  .m-content {
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 2.6rem;
  }
}

/* --- Responsive ---------------------------------------------------------- */
@media (max-width: 960px) {
  .stand {
    grid-template-columns: 1fr;
  }

  /* Two across, so the dividers have to move: vertical between the pair,
     horizontal between the rows. */
  .stats {
    grid-template-columns: repeat(2, 1fr);
  }

  .stat + .stat {
    border-left: 0;
  }

  .stat:nth-child(2n) {
    border-left: 1px solid var(--line);
  }

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

  /* One column, and every row's media takes the same landscape proportion:
     the per-row variation above is a desktop composition device and would
     just read as inconsistency in a single stack. */
  .row {
    grid-template-columns: 1fr;
  }

  .row--list,
  .row--claim,
  .row--record {
    grid-template-columns: 1fr;
  }

  .row--list .row__media,
  .row--claim .row__media,
  .row--record .row__media {
    aspect-ratio: 3 / 2;
  }

  /* On one column the media leads, so the flip has nothing left to swap. */
  .row--flip .row__media {
    order: 0;
  }

  .voices {
    grid-template-columns: 1fr;
  }



  .footer__meta {
    text-align: left;
  }
}

/* --- Phone: the figures go one-up ---------------------------------------
   `.stats` stepped 4 columns to 2 in the branch above and stopped there. At
   375px that leaves each caption about 120px wide, roughly 17 characters a
   line, so the longest of them breaks into a three-line sliver beside a 30px
   numeral. One stat per row instead, and the dividers turn with it.

   This has to sit AFTER that branch, not before. I wrote it 1,255 lines
   earlier first, where both queries match at 375px and the later one won on
   source order -- so the fix was in the file and doing nothing.
   ------------------------------------------------------------------------ */
@media (max-width: 520px) {
  .stats {
    grid-template-columns: 1fr;
  }

  .stat:nth-child(2n) {
    border-left: 0;
  }

  .stat + .stat {
    border-top: 1px solid var(--line);
  }
}

@media (max-width: 760px) {
  .nav a:not(.btn) {
    display: none;
  }

  .nav-toggle {
    display: inline-flex;
  }

  .header.is-open .nav a:not(.btn) {
    display: block;
  }

  /* Hangs off the capsule rather than the viewport, so the open menu keeps
     the floating geometry instead of reverting to a full-width sheet. */
  .header.is-open .nav {
    position: absolute;
    top: calc(100% + 0.625rem);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 1.125rem;
    padding: 1.375rem 1.5rem 1.625rem;
    border: 1px solid var(--line-soft);
    border-radius: 1.375rem;
    background: rgba(249, 248, 244, 0.97);
    backdrop-filter: saturate(150%) blur(1rem);
    -webkit-backdrop-filter: saturate(150%) blur(1rem);
    box-shadow: 0 1rem 2.5rem rgba(24, 28, 37, 0.1);
  }

  .header.is-open .nav .btn {
    margin-left: 0;
  }

  .price__row {
    grid-template-columns: 1fr auto;
    gap: 0.375rem;
  }

  .price__desc {
    grid-column: 1 / -1;
    order: 3;
  }
}

/* --- Hero on narrow screens ---------------------------------------------
   A 2.36 panorama at natural ratio is only 159px tall on a 375px screen,
   which is too thin to read as landscape. So the band is allowed a mild
   16/9 crop here, taking about a quarter off the width. That is a long way
   from the 77% the old full-height cover was taking.
   ------------------------------------------------------------------------ */
@media (max-width: 760px) {
  .hero {
    min-height: min(92vh, 47.5rem);
  }

  /* No drift below this width, so the plate needs no slack under the fold. */
  .hero__media {
    bottom: 0;
    aspect-ratio: 16 / 9;
  }

  .hero__in {
    padding-top: calc(var(--cap-h) + var(--cap-gap) + 2.125rem);
    padding-bottom: 1.25rem;
  }

  .hero__proof-in {
    flex-direction: column;
    gap: 0.5rem;
  }
}

/* --- Hero on narrow-but-tall screens ------------------------------------
   There was no branch between 761px and desktop, and the axis that matters
   here is viewport aspect, not width. At iPad portrait, 768x1024, the hero is
   940px tall and the plate 326px, of which 80 sits below the fold: the
   panorama becomes a 246px strip, 26% of the hero, and stops reading as a
   landscape at all.

   16/9 rather than a third value, so the system carries one crop: it is the
   same ratio the <=760px branch already uses. At 768 wide that is 432px, 46%
   of the hero. The 5/6 bound catches iPad portrait at 0.75 and iPad Pro 11 at
   0.70, and correctly leaves 1280x800 at 1.6 alone.
   ------------------------------------------------------------------------ */
@media (min-width: 761px) and (max-aspect-ratio: 5 / 6) {
  .hero__media {
    aspect-ratio: 16 / 9;
  }
}

/* The eyebrow is one line of tracked 11px caps and it is the first thing to
   run out of room. The flanking rules go first, then the tracking. */
@media (max-width: 560px) {
  .hero__eyebrow .r {
    display: none;
  }
}

/* Smallest common handset: the headline's clamp floor still overflows here. */
@media (max-width: 440px) {
  .hero h1 {
    font-size: 2rem;
  }

  .hero__sub {
    font-size: 1rem;
  }

  .hero__eyebrow .idx {
    font-size: 0.625rem;
    letter-spacing: 0.11em;
  }

  .hero__brands li {
    padding-inline: 0.5rem;
  }

  .header__cap {
    padding-left: 1rem;
  }

  .wrap {
    padding-inline: 1.125rem;
  }
}
