:root {
  color-scheme: light;
  --page-bg: #f8faf0;
  --page-bg-deep: #ecefe5;
  --surface-alt: #f2f5ea;
  --surface-strong: #e1e4da;
  --ink: #191d17;
  --ink-soft: #43483f;
  --muted: #73796e;
  --sage: #436833;
  --sage-deep: #2c4f1e;
  --sage-night: #1f2a1f;
  --sage-container: #c3efac;
  --app-blue: #9dcbca;
  --app-blue-soft: #c9e7fb;
  --hero-ink: #f8faf0;
  --hero-ink-soft: #e1e4da;
  --gold: #78590c;
  --gold-bright: #ffdea0;
  --gold-deep: #78590c;
  /* The one colour a run of body text turns to say "this is the point". The
     Storyworld band carries its own copy of this value: it is a standalone
     component with its own palette and cannot read the shell's tokens when it
     is opened in its own harness. Change both together. */
  --gold-text: #78590c;
  --gold-on-dark: #ffdea0;
  --line: rgba(67, 104, 51, 0.28);
  --hero-max-width: 1448px;
  /* Phone values. The laptop ones are restored at 861px, where the hero has
     to hold a mark, a headline, a paragraph and two buttons above the fold
     and so needs a height sized off the viewport rather than the content. */
  --hero-height: auto;
  --hero-gutter: 7.7%;
  --brand-big: clamp(58px, 15vw, 76px);
  /* The landed wordmark has to live inside a 56px bar. At 7vw it reached 43px
     by 614px wide and filled the bar edge to edge with 6px to spare, which is
     why it read as spilling even once it was centred. 6vw tops out at 38 and
     leaves the mark room to sit in. */
  --mark-size: clamp(30px, 6vw, 38px);
  /* The header bar is fixed, so nothing below it is pushed down by it — every
     piece of chrome that has to clear it has to be told this number. It was
     written out longhand in one place and guessed at in another, which is how
     the big opening wordmark came to be drawn straight across the bar. */
  --header-h: calc(clamp(56px, 4.7vw, 68px) + env(safe-area-inset-top));
  --hero-stage-height: clamp(360px, 37vw, 500px);
  --serif: Georgia, "Times New Roman", Times, serif;
  --sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  background: var(--page-bg);
}

body {
  margin: 0;
  min-width: 320px;
  color: var(--ink);
  background: linear-gradient(180deg, var(--page-bg) 0%, var(--page-bg-deep) 100%);
  font-family: var(--sans);
  overflow-x: hidden;
}

button,
a {
  font: inherit;
}

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

.landing-page {
  min-height: 100vh;
  background: var(--page-bg);
}

/* The shell's own ground is the page's, not the night's. The night is a panel
   inside it — see .hero-shell__night — and it covers only the rows the wordmark
   and the copy occupy. Everything under those rows (the Method band, the
   animation, the outro) stands on cream and runs straight into the section
   below without a seam. */
.hero-shell {
  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  isolation: isolate;
  /* Still the night's ink by default: the wordmark and the copy are the bulk of
     what inherits from here. The three blocks that now stand on cream —
     .tour-section, the animation slot and .hero-outro — say so themselves. */
  color: var(--hero-ink);
  background: var(--page-bg);
}

/* The picture ends at the line that opens the Method, and it has to do that
   without anyone measuring the copy: the copy's height is a headline that wraps
   differently at every width. So the night is not a layer over the shell — it
   is a grid item spanning the copy's rows, which makes the grid itself say
   where the night stops. Full-bleed, because the grid it sits in is padded to
   the gutter and the picture is not.

   The negative margins are the two things a grid area does not include and the
   night does: the inner's top padding (the night runs up under the header) and
   the row gap below it (so the picture's last pixel and the Method's line are
   the same edge, not 22px apart). */
.hero-shell__night {
  position: relative;
  grid-column: 1;
  z-index: -1;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-top: calc(-1 * var(--hero-pad-top));
  margin-bottom: calc(-1 * var(--hero-row-gap));
  overflow: hidden;
  color: var(--hero-ink);
  background: var(--sage-deep);
  pointer-events: none;
}

.hero-shell__background {
  position: absolute;
  inset: 0;
  z-index: -5;
  /* A background-image cannot carry a srcset, so the plate is a media query
     instead. The small one is the default: the hero is ~400 CSS px wide on a
     phone and 800 covers it at 2x, while the 1600 plate costs a DPR-3 iPhone
     4.4 MB of decoded RAM for no visible gain — and that is the memory that
     kills the tab. The big screen asks for the big plate, not the other way
     round. */
  background-image: url("../assets/hero-city-800w.webp");
  background-repeat: no-repeat;
  /* Off-centre on a phone: the plate's subject sits right of middle, and a
     portrait crop through its centre lands on empty sky. */
  background-position: 63% top;
  background-size: cover;
  transform: scale(1.03);
  filter: saturate(0.76) brightness(0.94);
}

@media (min-width: 601px) {
  .hero-shell__background { background-image: url("../assets/hero-city-1600w.webp"); }
}

.hero-shell__night::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -4;
  pointer-events: none;
  /* One column of copy over the plate, so the scrim runs top-to-bottom. The
     wide layout's left-to-right scrim comes back at 861px, where the copy has
     a side of its own to sit on. */
  background:
    linear-gradient(180deg,
      rgba(44, 79, 30, 0.88) 0%,
      rgba(44, 79, 30, 0.9) 48%,
      rgba(44, 79, 30, 0.68) 72%,
      rgba(31, 42, 31, 0.76) 100%),
    linear-gradient(90deg, rgba(44, 79, 30, 0.82), rgba(44, 79, 30, 0.22));
}

/* The night belongs only to the hero. Its last edge dissolves into the app's
   light surface so the methodology begins as part of the same page. The
   progressively masked blur keeps that dissolve from reading as color bands.

   Shorter than it was, and for a reason: the night used to run to the bottom of
   the whole shell, three sections below the copy, so a 290px fade had a whole
   animation to happen over. It now ends a little under the buttons, and the
   only room it has is the air .hero-copy holds below them — so the fade is cut
   to that air and no more, or it would wash out the two things the hero is
   asking the reader to press. */
.hero-shell__night::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  height: var(--hero-copy-foot);
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(248, 250, 240, 0) 0%,
    rgba(248, 250, 240, 0.025) 14%,
    rgba(248, 250, 240, 0.07) 27%,
    rgba(248, 250, 240, 0.145) 40%,
    rgba(248, 250, 240, 0.25) 53%,
    rgba(248, 250, 240, 0.39) 65%,
    rgba(248, 250, 240, 0.56) 76%,
    rgba(248, 250, 240, 0.72) 85%,
    rgba(248, 250, 240, 0.86) 93%,
    var(--page-bg) 100%);
  -webkit-backdrop-filter: blur(20px) saturate(0.92);
  backdrop-filter: blur(20px) saturate(0.92);
  -webkit-mask-image: linear-gradient(180deg,
    transparent 0%,
    rgba(0, 0, 0, 0.1) 14%,
    rgba(0, 0, 0, 0.45) 40%,
    #000 72%);
  mask-image: linear-gradient(180deg,
    transparent 0%,
    rgba(0, 0, 0, 0.1) 14%,
    rgba(0, 0, 0, 0.45) 40%,
    #000 72%);
}

/* The hero reads top to bottom: wordmark, wide copy, then the phone-to-book
   story in its own row. The art no longer competes with the copy for width. */
.hero-shell__inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  /* Five named rows even on a phone, where they used to be left to DOM order.
     The night is placed by row, and one explicitly placed item is enough to
     shove auto-placed siblings out of the cells they were sitting in — so once
     one of them is named they all are. */
  grid-template-rows: repeat(5, auto);
  /* Held in variables because the night's margins have to cancel exactly these
     two numbers, and a fade below the buttons has to be exactly that third one.
     Change one and the picture's bottom edge moves off the Method's line. */
  --hero-pad-top: calc(var(--header-h) + 10px);
  --hero-row-gap: 22px;
  --hero-copy-foot: clamp(64px, 9vw, 104px);
  row-gap: var(--hero-row-gap);
  width: min(100%, var(--hero-max-width));
  min-height: 100svh;
  margin: 0 auto;
  /* Top padding starts below the bar, not at 30px. The bar is fixed and the
     wordmark opens at --brand-big, so 30px put a 58px letterform across a 56px
     bar and the two were drawn on top of each other before the flight had even
     started. On a wide screen the same clearance is bought differently — an
     empty --mark-size grid row above the anchor — which is why this only ever
     went wrong on a phone. 10px on top of the bar so the mark has air under it
     rather than sitting on the hairline. */
  padding: var(--hero-pad-top) 18px 42px;
}

/* The phone's rows, named. Row 1 and 2 are the night's; 3, 4 and 5 stand on
   cream. The wide layout at 861px re-numbers all of these, because it opens a
   sixth row above the anchor to clear the header bar. */
.hero-shell__night     { grid-row: 1 / 3; }
.brand-anchor          { grid-row: 1; }
.hero-copy             { grid-row: 2; }
.tour-section          { grid-row: 3; }
.component-slot--hero  { grid-row: 4; }
.hero-outro            { grid-row: 5; }

/* The air the fade lives in, and the reason the buttons are not standing on
   the seam between the picture and the page. */
.hero-copy {
  padding-bottom: var(--hero-copy-foot);
}

/* The lantern is a wide-screen flourish: it lives in the gutter, and on a
   phone there is no gutter to live in. It hangs off the bottom of the night
   now rather than the bottom of the shell — the night is where the night is. */
.hero-shell__lantern {
  display: none;
  position: absolute;
  left: max(0px, calc((100vw - var(--hero-max-width)) / 2));
  bottom: 0;
  z-index: 1;
  width: clamp(66px, 7.2vw, 105px);
  height: auto;
  opacity: 0.94;
  pointer-events: none;
  filter: drop-shadow(0 0 18px rgba(229, 151, 42, 0.15));
}

/* 100vw minus the two gutters, not 100%: the grid parent is already inside
   the padding, and the copy's children need an explicit width to wrap long
   Spanish and English words against rather than a percentage of `auto`. */
.hero-copy {
  grid-column: 1;
  align-self: start;
  z-index: 5;
  width: calc(100vw - 36px);
  min-width: 0;
  max-width: calc(100vw - 36px);
}

.hero-copy > * {
  max-width: 100%;
}

.site-header {
  position: fixed;
  inset: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: var(--header-h);
  padding: max(10px, env(safe-area-inset-top)) max(var(--hero-gutter), calc((100vw - var(--hero-max-width)) / 2 + var(--hero-gutter)));
  z-index: 99;
  pointer-events: none;
}

/* The links fly up out of the hero buttons; landing-shell.js writes transform
   and opacity every frame off the scroll position. No transition here on
   purpose — one would lag the scroll and turn the flight to rubber. The
   left-centre origin keeps the near end of the flight aligned to the buttons'
   left edge while it is still scaled up. */
.site-header__menu {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: clamp(18px, 2vw, 28px);
  opacity: 0;
  transform-origin: left center;
  will-change: transform, opacity;
  pointer-events: none;
}

.site-header__menu.is-visible {
  pointer-events: auto;
}

/* The text is 15px but the target is 44px: the links were 51x18 boxes, which is
   a fine mouse target and a poor thumb one. The height comes from the flex box,
   not from padding-block, so the bar's own height is unchanged and the flight
   still lands where it did. The gap tightens to keep the pair from spreading
   once each link carries its own inline padding. */
.site-header__menu-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 10px;
  margin-inline: -10px;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--hero-ink-soft);
  white-space: nowrap;
}

.site-header__menu-link:hover,
.site-header__menu-link:focus-visible {
  color: var(--hero-ink);
}

/* Colour alone is not a focus indicator — on this dark bar the hover and focus
   states were the same two-step lightening, invisible to anyone navigating by
   keyboard. */
.site-header__menu-link:focus-visible,
.site-header__mark:focus-visible {
  outline: 2px solid var(--gold-on-dark);
  outline-offset: 3px;
  border-radius: 6px;
}

.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(180deg, rgba(44, 79, 30, 0.97), rgba(31, 42, 31, 0.93));
  border-bottom: 1px solid rgba(255, 222, 160, 0.18);
  box-shadow: 0 12px 30px rgba(25, 29, 23, 0.28);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.site-header__mark {
  position: relative;
  z-index: 1;
  pointer-events: auto;
  font-family: var(--serif);
  font-size: var(--mark-size);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.055em;
  will-change: transform;
  filter:
    drop-shadow(0 0 7px rgba(255, 191, 73, 0.26))
    drop-shadow(0 1px 0 rgba(61, 27, 4, 0.8));
}

/* Direct child only, still: nothing but text lives in here now, but the clip
   erases the background of anything it reaches, so a descendant selector would
   break the first non-text thing anyone puts inside the mark. */
.site-header__mark > span {
  background: linear-gradient(180deg, #fff0bd 0%, #f7bf52 34%, #c97517 71%, #8a3f08 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* The dot over the i used to wake up here — a face that swelled over the
   tittle, opened its eyes and smiled once the mark landed in the bar. Removed:
   the header is chrome and has to stay still. logo-motion still plays the beat
   in the opening title, which is where it belongs.
   ------------------------------------------------------------------------ */

/* The flight itself. The mark lives in the header in the DOM and starts life
   transformed down onto .brand-anchor, so releasing the transform IS the
   animation and both ends stay correct at any width. */
/* The mark is drawn at its LARGE size and scaled DOWN into the header. Scaling
   type up with a transform rasterises it at the small size and the opening
   wordmark comes out soft, which is the one thing it must not be. Out of flow
   so the header keeps its height underneath it. */
.site-header__mark.is-opening,
.site-header__mark.is-scroll-linked {
  position: fixed;
  inset: 0 auto auto 0;
  font-size: var(--brand-big);
  transform-origin: left top;
}

/* The phone flight is shorter and also has to shrink the type: the mark
   starts at --brand-big and lands at --mark-size, and those are far apart
   here than on a wide screen. */
.site-header__mark.is-flying {
  transition:
    font-size 600ms cubic-bezier(0.26, 0.82, 0.2, 1),
    transform 600ms cubic-bezier(0.26, 0.82, 0.2, 1);
}

/* Once the opening flight lands, keep the wordmark in the page's title rail.
   Its measured left edge preserves the grid alignment while the tighter top
   inset lets it read as chrome instead of another piece of hero copy. */
.site-header__mark.is-docked {
  position: fixed;
  left: var(--mark-dock-left);
  top: max(10px, env(safe-area-inset-top));
  z-index: 100;
}

.site-header__mark.is-scroll-linked {
  z-index: 100;
  pointer-events: auto;
}

/* Holds the room the big wordmark occupies, then hands it to the caption and
   gives most of it back so the book grows into the space. font-size carries
   --brand-big so the script can read it as a resolved pixel value. */
.brand-anchor {
  grid-column: 1;
  display: flex;
  align-items: center;
  min-height: 1.15em;
  width: min(100%, 920px);
  padding-right: 0;
  font-size: var(--brand-big);
  transition: min-height 760ms cubic-bezier(0.2, 0.84, 0.18, 1);
}

.brand-anchor.is-settled {
  min-height: 0.52em;
}

@media (min-width: 861px) and (max-height: 850px) {
  /* Written as the two variables rather than row-gap and padding-top directly:
     the night's margins cancel these, so a value set here that the layout used
     but the night did not know about would slide the picture's bottom edge off
     the Method's line. (As it stands the plain 861px block below sets both
     again, so these two have no effect — which is how it was before.) */
  .hero-shell__inner {
    --hero-row-gap: 14px;
    --hero-pad-top: 16px;
  }

  .hero-divider {
    margin-top: 24px;
  }

  /* Eyebrow leads the block, so the room it needs is underneath it. */
  .hero-kicker {
    margin-bottom: 10px;
  }

  .hero-body {
    margin-top: 14px;
    line-height: 1.48;
  }

  .hero-actions {
    margin-top: 20px;
  }
}

.hero-copy h1 {
  display: grid;
  gap: 0.05em;
  margin: 0;
  width: calc(100vw - 36px);
  max-width: calc(100vw - 36px);
  font-family: var(--serif);
  font-size: clamp(37px, 11.3vw, 52px);
  font-weight: 400;
  line-height: 1.01;
  letter-spacing: -0.045em;
  color: var(--hero-ink);
  text-wrap: balance;
  text-shadow: 0 2px 22px rgba(18, 29, 17, 0.52);
}

.hero-copy h1 span {
  display: block;
}

.hero-copy h1 em {
  font-style: normal;
  color: transparent;
  background: linear-gradient(180deg, #ffcd68, #cf741d);
  -webkit-background-clip: text;
  background-clip: text;
  filter: drop-shadow(0 0 12px rgba(218, 132, 34, 0.13));
}

.hero-divider {
  display: flex;
  align-items: center;
  width: calc(100vw - 36px);
  max-width: calc(100vw - 36px);
  margin: 29px 0 0;
}

.hero-divider__star {
  position: relative;
  flex: 0 0 17px;
  width: 17px;
  height: 17px;
  margin-right: 2px;
  background:
    linear-gradient(90deg, transparent 46%, #ffe4a1 48%, #ffe4a1 52%, transparent 54%),
    linear-gradient(0deg, transparent 46%, #ffe4a1 48%, #ffe4a1 52%, transparent 54%);
  filter: drop-shadow(0 0 7px #ffb43c);
  transform: rotate(45deg);
}

.hero-divider__star::before,
.hero-divider__star::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: #fff4c9;
  box-shadow: 0 0 12px #efa83d;
}

.hero-divider__star::after {
  inset: -6px;
  background: radial-gradient(circle, rgba(255, 190, 73, 0.42), transparent 66%);
  box-shadow: none;
}

.hero-divider__line {
  height: 1px;
  flex: 1;
  background: linear-gradient(90deg, rgba(245, 177, 65, 0.78), rgba(245, 177, 65, 0.13), transparent);
}

/* The eyebrow above the headline. Held well under the h1's size on purpose:
   two serif lines of similar weight read as two competing headlines, so this
   one stays small enough to be read as the lead-in it is. Gold, because it is
   the promise; the second half goes back to hero ink so the colour lands on
   "prepare for the world" rather than on the whole line. */
.hero-kicker {
  width: calc(100vw - 36px);
  max-width: calc(100vw - 36px);
  margin: 0 0 clamp(13px, 1.2vw, 18px);
  font-family: var(--serif);
  font-size: clamp(17px, 4.6vw, 21px);
  line-height: 1.2;
  overflow-wrap: break-word;
  color: var(--gold-on-dark);
  letter-spacing: -0.02em;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.38);
}

.hero-kicker span {
  color: var(--hero-ink);
}

.hero-body {
  width: calc(100vw - 36px);
  max-width: calc(100vw - 36px);
  margin: clamp(18px, 1.8vw, 25px) 0 0;
  font-family: var(--sans);
  font-size: clamp(16px, 4.4vw, 20px);
  line-height: 1.57;
  color: var(--hero-ink-soft);
  letter-spacing: -0.012em;
  overflow-wrap: break-word;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.36);
}

/* Side by side at every width. These two are a pair — the offer and the
   explanation — and stacking them turned the second into a consequence of the
   first, which is the wrong reading and cost a button's height of fold as well.
   Two 192px buttons genuinely do not fit a 360px screen, so they stop being
   192px buttons: the gap, the padding and the label all come down with the
   viewport and settle at their desktop sizes by about 420px. The labels are
   two words and one word, so the columns can be equal and neither wraps. */
.hero-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: center;
  gap: clamp(8px, 2.4vw, 14px);
  max-width: 460px;
  margin-top: clamp(24px, 2.4vw, 32px);
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 2.6vw, 13px);
  width: 100%;
  min-width: 0;
  height: 54px;
  padding: 0 clamp(12px, 3.4vw, 16px);
  border: 1px solid rgba(232, 167, 65, 0.65);
  border-radius: 15px;
  font-family: var(--serif);
  /* 16px is the floor, not a preference: "Early access" is the longer label and
     at 16px Georgia it is about 91px, which is what fits a 147px column on a
     360px screen once the padding and the arrow have taken their share. */
  font-size: clamp(16px, 4.3vw, 18px);
  line-height: 1;
  transition: transform 180ms ease, box-shadow 180ms ease, background 180ms ease;
}

.button:hover,
.button:focus-visible {
  transform: translateY(-2px);
}

.button:focus-visible {
  outline: 2px solid #ffd275;
  outline-offset: 4px;
}

.button--primary {
  position: relative;
  isolation: isolate;
  color: #ffffff;
  background:
    linear-gradient(180deg, #527d40 0%, var(--sage) 46%, #365629 100%);
  border-color: rgba(255, 222, 160, 0.62);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    0 10px 28px rgba(18, 29, 17, 0.31),
    0 0 18px rgba(255, 222, 160, 0.11);
}

/* Filter definitions only — nothing in here is ever drawn. width/height 0 on
   the tag is not enough on its own: an SVG element still takes part in layout,
   and one at the end of the body would put a stray line box under the footer. */
.fx-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* The puddle the hero buttons stand in.
 *
 * Both of them, and only them. The selector is .hero-actions .button rather
 * than .button--primary, which is the same class the download buttons carry —
 * they had pools for a while and it was the wrong idea. Water under a pair of
 * buttons says those two are standing in something together; water under every
 * green button on the page says the site has a wet floor. The two in the hero
 * are on the water. Nothing else is.
 *
 * A puddle does not give back a picture. It gives back the light — where the
 * bright things were, roughly, smeared across a surface that will not hold
 * still. So this is painted rather than mirrored, and everything about it is
 * chosen to be unreadable:
 *
 * - The gold band along the top is the button's rim breaking on the surface.
 * - Under it, the button's fill upside down — dark foot at the waterline,
 *   lighter as it goes down, because down here is the top of the button.
 * - A wide, weak light in the middle: the wash the label's reflection sits in.
 *   The button is a centred flex row, so everything lit on it sits as one
 *   cluster in the middle with dark button either side, and the water is lit to
 *   match. Two ellipses, a narrow core inside a broad wash, because one ellipse
 *   fades at a single rate and a single rate is what makes a light look aimed.
 *
 * The label's actual reflection is not here — it is ::before, above this rule.
 * This element is the water; that one is what the water is giving back. They
 * were one thing for a long time, a glow shaped to look like a reflection, and
 * shaping it was never going to be enough: a glow that is not tied to anything
 * above it reads as a lamp no matter what shape it is.
 *
 * -webkit-box-reflect was tried first and does mirror the real button, rim and
 * label and all. It was dropped because it cannot be softened: the reflection
 * lives in the button's own layer, so a filter blurs the button with it and a
 * backdrop-filter laid over the reflection never sees it. A legible reflection
 * is the wrong thing anyway — it reads as a second button parked underneath.
 * Painting it costs the true mirror and buys the blur, which is the part that
 * makes it water. It also works in Firefox, which has no box-reflect at all.
 *
 * NOTHING HERE MOVES, and that was the hard-won part. Two earlier versions
 * animated: a band of highlights raked off horizontal and drifting across, then
 * two of them crossing. Both read as small lights skating around on the surface,
 * which is not what a pool does. A pool is still. What makes it read as water is
 * that its surface is broken up, and #fx-puddle breaks up a standing image just
 * as well as a moving one. Motion was the wrong instinct twice; there is no
 * animation on this rule and it does not need the prefers-reduced-motion rule
 * that used to freeze it.
 *
 * The distortion is the whole difference between this and a smudge, and it is
 * not a CSS filter — it is #fx-puddle in index.html, a turbulence map that
 * slides each row of the picture sideways and none of it up or down. Blur alone
 * softens a reflection evenly; water never does anything evenly. The blur that
 * remains here is 1.4px, just enough to take the edge off the strips the warp
 * cuts, and the ripple bands are painted INTO the background rather than cut
 * out of the mask — a filter runs before the mask, so anything in the mask
 * comes out ruler-straight and reads as corduroy, while anything in the
 * background gets bent along with everything else.
 *
 * The mask is now only what the warp must not touch: the fade into depth, and
 * the fade at the two ends without which the pool is a rectangle with visible
 * sides. The radius is the button's own bottom corners, mirrored, so the near
 * lip of the pool has the shape the foot of the button does.
 *
 * 12px, a quarter of the button. Every version before this one was taller and
 * every one of them read as depth below the page — a pool the button is sunk
 * into — rather than the wet patch it is standing on. Water seen from standing
 * height gives back almost nothing: a hand's width of broken light at the foot
 * of the thing and then the ground again. Half the height did more for it than
 * any amount of work on what was inside it.
 */
/* THE REFLECTION PROPER — the button's own label, upside down in the water.
 *
 * Everything before this was light: a glow under the button, tuned until it was
 * the right shape and the right strength, and still reading as a lamp on the
 * floor because it was tied to nothing above it. Water gives back the thing
 * standing in it. Until the bright parts of the pool line up with the letters
 * that threw them, no amount of shaping makes it a reflection.
 *
 * The text comes from a data-reflect attribute on the button rather than from
 * the label element, because CSS cannot copy an element's text. That is a real
 * cost: the attribute and the label are two copies of one string and they will
 * drift apart if only one is edited. It is worth paying, and the alternatives
 * are worse — -webkit-box-reflect mirrors the real markup but cannot be blurred
 * or warped independently of the button, and it does not exist in Firefox.
 *
 * The `/ ""` after the attr() is the alternative-text syntax, and it is not
 * decoration: without it a screen reader reads generated content, and the
 * button announces its own name twice.
 *
 * How it lands the right way up. The box is the pool's box, 12px, and the text
 * inside it is 18px — taller than the box on purpose. align-items: flex-end
 * sits the text on the box's floor so it overflows the ceiling by the height of
 * the letters' upper halves; scaleY(-1) then turns the whole painted box over,
 * which puts the feet of the letters at the waterline, sends their tops down
 * into the depth, and pushes the overflow out of the bottom where the mask
 * clips it. What survives is the six-or-so pixels of glyph nearest the water,
 * mirrored — a shape you can tell is lettering and cannot read, which is what a
 * puddle gives back.
 *
 * Mask and filter both run in the element's own coordinates and the transform
 * maps the result, so the vertical mask is written upside down here: opaque at
 * the BOTTOM, which is the waterline once it has been flipped.
 */
.hero-actions .button::before {
  content: attr(data-reflect) / "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 1px);
  height: 12px;
  /* Above the water, below the real label. .hero-actions .button > * takes z-index 1
     and this has to clear the pool's own 0; the letters are outside the
     button's box, so nothing up there is covered. */
  z-index: 2;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Face and size are inherited from .button, which is the point — a reflection
     of a different typeface is not a reflection. */
  line-height: 1;
  white-space: nowrap;
  color: rgba(255, 250, 228, .62);
  transform: scaleY(-1);
  -webkit-mask-image:
    linear-gradient(180deg, transparent 4%, rgba(0, 0, 0, .34) 42%, rgba(0, 0, 0, .78) 74%, #000 100%),
    linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, .55) 14%, #000 30%, #000 70%, rgba(0, 0, 0, .55) 86%, transparent 100%);
  mask-image:
    linear-gradient(180deg, transparent 4%, rgba(0, 0, 0, .34) 42%, rgba(0, 0, 0, .78) 74%, #000 100%),
    linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, .55) 14%, #000 30%, #000 70%, rgba(0, 0, 0, .55) 86%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  /* The same warp the water is under, so the letters break on the same waves,
     and then a good deal more blur than the water itself gets. The ripple wants
     to stay legible as ripple; the letters must not stay legible as letters. At
     1.1px the word was still readable upside down, which makes it a mirror —
     and a mirror is a hard surface. Water hands back the shape of a word and
     none of the word. The colour came down with it: a reflection is dimmer than
     the thing it reflects, always, and this one was competing with the label
     three pixels above it. */
  filter: url(#fx-puddle) blur(2px);
  pointer-events: none;
}

/* The secondary button stands in the same water and gets the same pool, but it
   is a dark translucent panel rather than a lit green one, so what the water
   gives back of its FILL has to be dark to match. Only the fill: the rim is the
   same gold on both, and the reflected letters are the same white, because both
   of those are the same brightness on the button itself. */
.hero-actions .button--secondary::after {
  background:
    radial-gradient(34% 130% at 50% 6%, rgba(255, 250, 228, .13) 0%, rgba(255, 250, 228, .04) 55%, transparent 78%),
    radial-gradient(62% 150% at 50% 4%, rgba(255, 250, 228, .08) 0%, rgba(255, 250, 228, .03) 50%, transparent 80%),
    repeating-linear-gradient(180deg,
      rgba(247, 252, 232, 0) 0px, rgba(247, 252, 232, .4) .8px,
      rgba(247, 252, 232, .4) 1.3px, rgba(247, 252, 232, 0) 2.2px,
      rgba(247, 252, 232, 0) 4.2px),
    repeating-linear-gradient(180deg,
      rgba(14, 26, 13, 0) 0px, rgba(14, 26, 13, .62) 1px,
      rgba(14, 26, 13, 0) 2.3px, rgba(14, 26, 13, 0) 3.4px),
    linear-gradient(180deg, rgba(255, 231, 175, .58) 0%, rgba(255, 231, 175, .14) 18%, rgba(255, 231, 175, 0) 42%),
    linear-gradient(180deg, #23361d 0%, #2c4426 60%, #35502d 100%);
}

.hero-actions .button::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  /* 1px of seam, so the button stands at the edge of the water rather than
     dissolving into its own reflection. */
  top: calc(100% + 1px);
  height: 12px;
  z-index: 0;
  border-radius: 12px 12px 5px 5px;
  background:
    /* The lift under the lit part of the button. This used to be the whole of
       the light down here and it was the reason the pool kept reading as a lamp
       on the floor rather than as water: a glow tied to nothing above it is a
       glow. The letters themselves are the reflection now — ::before, below —
       and these two ellipses are only the wash the letters sit in, dropped to
       about half their old strength so they support the reflection instead of
       drowning it.

       Travelling glints were tried here and were wrong. They read as little
       lights skating about, and a puddle does not do that — a puddle is still,
       and what makes it water is that its surface is broken, not that anything
       on it is moving. The warp does the breaking. Nothing here animates. */
    radial-gradient(34% 130% at 50% 6%, rgba(255, 250, 228, .20) 0%, rgba(255, 250, 228, .06) 55%, transparent 78%),
    radial-gradient(62% 150% at 50% 4%, rgba(255, 250, 228, .12) 0%, rgba(255, 250, 228, .04) 50%, transparent 80%),
    /* The ripple, in two passes: the crests that catch the light and the
       troughs that hold the shade. Both are painted rather than masked, because
       a filter runs before the mask and only what is in the background is
       there for the warp to bend — these horizontal edges are the only thing
       in the pool the wave has to run along, and without them the warp has
       nothing to show.

       Light and dark are on different periods, 4.2px against 3.4px, so the two
       never line up into the even corduroy that a single band spacing always
       reads as. Both periods halved with the pool: three crests is what reads
       as a surface rather than as string, and three crests have to fit in 12px
       now. The dark is the deep green of the shadow the button casts, not
       black, so the pool stays water over grass. */
    repeating-linear-gradient(180deg,
      rgba(247, 252, 232, 0) 0px, rgba(247, 252, 232, .52) .8px,
      rgba(247, 252, 232, .52) 1.3px, rgba(247, 252, 232, 0) 2.2px,
      rgba(247, 252, 232, 0) 4.2px),
    repeating-linear-gradient(180deg,
      rgba(14, 26, 13, 0) 0px, rgba(14, 26, 13, .62) 1px,
      rgba(14, 26, 13, 0) 2.3px, rgba(14, 26, 13, 0) 3.4px),
    linear-gradient(180deg, rgba(255, 231, 175, .8) 0%, rgba(255, 231, 175, .2) 18%, rgba(255, 231, 175, 0) 42%),
    linear-gradient(180deg, #37582a 0%, #4c7639 60%, #5b8a46 100%);
  background-size: 100% 100%;
  background-position: 0 0;
  /* Only the two fades the warp must not touch. The vertical one keeps most of
     its weight to two-thirds down: the ripple is the whole point now, and a
     fade that had gone to a third by then left the warp bending nothing anyone
     could see below the first crest.

     The horizontal one holds full strength across the middle 40% and is down to
     half by 14% and 86%, so the water is only really there under the label and
     the arrow and has thinned to nothing before the button's own corners. Two
     jobs in one gradient: it keeps the pool from being a rectangle with visible
     sides, and it is most of what makes the light read as coming off the lit
     part of the button rather than lying under the whole of it. */
  -webkit-mask-image:
    linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .8) 44%, rgba(0, 0, 0, .36) 76%, transparent 100%),
    linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, .55) 14%, #000 30%, #000 70%, rgba(0, 0, 0, .55) 86%, transparent 100%);
  mask-image:
    linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .8) 44%, rgba(0, 0, 0, .36) 76%, transparent 100%),
    linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, .55) 14%, #000 30%, #000 70%, rgba(0, 0, 0, .55) 86%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  /* The warp first, then just enough blur to take the edge off the strips it
     cuts. The other way round and the blur is what the map displaces, which
     smears the noise instead of the picture.

     .6px, and it wants to be small. A gaussian reaches about three times its
     radius, so at the 1.4px this started on it was averaging across four and a
     half pixels of a pool whose ripple repeats every 4.2 — it erased the thing
     it was meant to soften, and the water went back to being a smudge. The
     shove came down with the height for the same reason: 6px inside a 12px pool
     is not a ripple, it is a puree. */
  filter: url(#fx-puddle) blur(.6px);
  opacity: .95;
  pointer-events: none;
}

/* The filter is an id in the page, so a page that does not carry the defs would
   drop the whole layer rather than fall back. Nothing on this site is in that
   position today; the rule is here so it stays true if the buttons are ever
   lifted into a component of their own. */
@supports not (filter: url(#fx-puddle)) {
  .hero-actions .button::after { filter: blur(2.5px); }
}

/* button-pool used to live here: highlights that drifted across the water and
   back. It is gone and not coming back. Motion was the wrong instinct — a pool
   at the foot of a button is still, and drifting highlights read as small lights
   skating over it rather than as a surface. What makes it water is that the
   surface is broken, which #fx-puddle does to a standing image. */

.hero-actions .button > * {
  position: relative;
  z-index: 1;
}

.method-flow-map {
  position: absolute;
  inset: 0 auto auto 0;
  z-index: 7;
  width: 100%;
  overflow: visible;
  pointer-events: none;
}

.method-flow-map__guide {
  fill: none;
  stroke: transparent;
}

.method-flow-map__drop {
  fill: #ffd77a;
  filter: drop-shadow(0 0 5px rgba(255, 184, 61, .9));
}

.button--primary:hover,
.button--primary:focus-visible {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.74),
    0 13px 32px rgba(0, 0, 0, 0.29),
    0 0 23px rgba(227, 147, 35, 0.2);
}

/* Outlined, not filled, and lit by the same gold rim as the primary. It used
   to be a solid slab of --app-blue-soft: a real brand colour, but everywhere
   else on the site that blue is a translucent wash, and as a solid fill it was
   both the only cold thing in a warm hero and brighter than the green button
   next to it — so the secondary action out-shouted the primary. Sitting it in
   the hero's own dark green settles the palette and puts the two back in
   order: one filled, one outlined. */
.button--secondary {
  /* Both of these are here for the pool. It hangs off ::after, positioned
     against this box, and the isolate keeps the reflected letters' z-index from
     climbing out into the hero. .button--primary carries the same pair. */
  position: relative;
  isolation: isolate;
  color: var(--hero-ink);
  border-color: rgba(255, 222, 160, 0.5);
  background: rgba(28, 46, 24, 0.42);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 10px 26px rgba(18, 29, 17, 0.26);
  backdrop-filter: blur(3px);
}

.button--secondary:hover,
.button--secondary:focus-visible {
  border-color: rgba(255, 222, 160, 0.82);
  background: rgba(28, 46, 24, 0.62);
}

.button__arrow {
  margin-top: -1px;
  font-family: var(--sans);
  font-size: 34px;
  font-weight: 250;
  line-height: 0.7;
}

.component-slot {
  position: relative;
}

/* Auto-placed, so it lands in DOM order — after the copy and before the outro.
   The hairline across its top is the line that opens the method, and the outro
   is the method's opening paragraph, so the outro reads underneath it here the
   same way it does at every other width.

   Full-bleed past the gutter — the book is the widest thing on the page and
   the 18px margin is worth more to it than to the copy. */
.component-slot--hero {
  grid-column: 1;
  z-index: 3;
  /* A definite height: the component sizes the phone and book off its stage
     height, so an auto-height slot collapses the animation to nothing. */
  width: calc(100% + 36px);
  height: min(78vw, 590px);
  min-height: min(78vw, 590px);
  margin: 4px -18px -12px;
  overflow: visible;
  contain: layout style;
}

/* Nothing mounted: give the room back rather than leaving a hole. */
.component-slot--hero:empty {
  min-height: 0;
  height: 0;
  margin-top: 0;
  margin-bottom: 0;
}

html[data-show-slots="true"] .component-slot--hero:empty {
  min-height: min(78vw, 590px);
  height: min(78vw, 590px);
  margin-top: 4px;
  margin-bottom: -12px;
}

/* The hairline that opens the Method used to be drawn here, across the top of
   the animation, because the animation was the Method's first beat. The film
   introduces it now, so the line moved up to .tour-section::before with it —
   a divider a screen below the thing it opens is not a divider. */

/* The slot here is short and wide, so the book is height-limited rather than
   width-limited. --book-h and --book-mini-scale are a documented pair: their
   product has to stay at --phone-h * .435 or the book stops filling the phone
   screen on the way out. */
.component-slot--hero .stage {
  --phone-h: 82%;
  --book-h: calc(var(--phone-h) * .78);
  --book-mini-scale: .558;
  width: 100%;
}

.component-slot--hero > * {
  position: relative;
  width: 100%;
  height: 100%;
}

/* Its own row under the copy, at full measure. Only once the stage stops
   growing with the viewport — 1121px — does this move beside the animation,
   where the art owns the left field and this copy owns the right and neither
   one's visual center is allowed to pull the other out of place. */
.hero-outro {
  grid-column: 1;
  z-index: 6;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-self: start;
  justify-self: start;
  width: min(100%, 620px);
  height: auto;
  color: var(--ink);
}

.hero-outro__lead {
  margin: 0;
  font-family: var(--sans);
  font-size: clamp(21px, 1.65vw, 27px);
  font-weight: 520;
  line-height: 1.22;
  letter-spacing: -.025em;
  color: var(--ink);
  text-wrap: balance;
}

/* --gold-text, the one a run of body text turns on the page's cream. The
   bright gold this used to carry was for the night, which now ends above it. */
.hero-outro__lead span {
  color: var(--gold-text);
}

.hero-outro__body {
  margin: clamp(10px, 0.9vw, 14px) 0 0;
  font-family: var(--sans);
  font-size: clamp(17px, 1.25vw, 19px);
  line-height: 1.5;
  color: var(--ink-soft);
}

.storyworld-mount {
  position: relative;
  z-index: 6;
  width: 100%;
  background: var(--page-bg);
  scroll-margin-top: 64px;
}

.component-slot--storyworld:not(:empty) {
  width: min(100%, var(--hero-max-width));
  margin: 0 auto;
  padding: 0 7px clamp(48px, 5vw, 84px);
}

/* ---- The app tour -------------------------------------------------------
   A 4:5 film beside its own caption. The film is the widest thing in the band
   on a phone and the tallest thing on a desktop, so it is capped in both
   directions: `min()` against the viewport height keeps a portrait video from
   running past the fold on a laptop, which is the one way a piece of footage
   this shape can go wrong on a wide screen.

   The band still lives inside .hero-shell__inner rather than on the page below
   it, because it shares the hero's grid and its gutter — but it no longer
   shares its ground. The night stops at this band's first pixel, so from here
   down the shell is the page's cream, and the band is written dark-on-light
   like every section under it. It draws no background of its own (the shell's
   is already the right one) and takes no side padding (the hero inner already
   pads to the gutter).
   ------------------------------------------------------------------------ */

.tour-section {
  position: relative;
  grid-column: 1;
  z-index: 6;
  width: 100%;
  color: var(--ink);
  padding: clamp(34px, 4vw, 58px) 0 clamp(4px, .8vw, 12px);
}

/* The line that opens the Method. It is drawn at the top of this band and not
   at the top of the animation below it because this is where the Method now
   begins — the header link, the hero's Method button and the hero divider all
   arrive here. It is also the seam: the picture's last pixel is the pixel above
   it. Drawn in the dark gold, not the bright one — the bright gold was written
   to be read against the night and is all but invisible on cream. */
.tour-section::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(120, 89, 12, .34) 18%, rgba(120, 89, 12, .34) 82%, transparent);
  opacity: .82;
  pointer-events: none;
}

.tour-section__inner {
  width: min(100%, var(--hero-max-width));
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(22px, 3vw, 40px);
}

.tour-section__copy {
  max-width: 46ch;
}

/* The page's ink, not the hero's: the night ends at this band's top edge, so
   everything from here down is dark type on cream. */
.tour-section .page-section__title {
  color: var(--ink);
}

.tour-section__body {
  margin: clamp(13px, 1.3vw, 20px) 0 0;
  font-family: var(--sans);
  font-size: clamp(17px, 1.25vw, 20px);
  line-height: 1.55;
  color: var(--ink-soft);
}

/* --muted rather than --ink-soft at .68: the opacity was standing in for a
   lighter grey on a dark ground, and fading dark type on cream just makes it
   look faint rather than quiet. */
.tour-section__body--quiet {
  font-size: clamp(14px, 1vw, 16px);
  color: var(--muted);
}

/* The film keeps its own shape whatever else happens: aspect-ratio rather than
   a height, so the box is the right size before a single byte of video has
   arrived and the page never jumps when it does. */
.component-slot--tour {
  width: 100%;
  max-width: min(100%, 62vh, 460px);
}

/* No ground, no corner radius and no shadow, and all three are the same
   decision. The film is a porthole: a circle of picture with a real alpha
   channel and nothing at all outside it. A card behind it would be a rounded
   rectangle standing on the page with a circle of film in the middle of it,
   which is the arbitrary background the transparent master exists to be rid
   of; a drop shadow would be that rectangle's edge drawn again, in the one
   place there is no edge. What is behind the film is the page, which is the
   point.

   The aspect ratio stays. It is the box the master was shot in, so the slot is
   the right size and the circle is centred in it before a byte has arrived. */
.tour-film {
  position: relative;
  aspect-ratio: 1080 / 1350;
  width: 100%;
}

.tour-film__video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The film had a Play/Pause pill in the corner the porthole leaves empty. It is
   gone: the film runs from its first frame when it comes up the screen and
   winds back when it leaves, the same as every other clip on the page, so the
   only thing the button did was put a chrome-coloured lozenge on the hero. */

/* Wide enough for the caption to stand beside the film rather than above it.
   The film leads, because it is the evidence and the copy is the caption. */
@media (min-width: 900px) {
  /* space-between, not center: the caption is the first words under the line
     that opens the Method, and everything else on this dark ground — the
     kicker, the headline, the buttons — starts at the gutter. Centred, the
     pair floats a hundred pixels in from an edge nothing else leaves. */
  .tour-section__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: clamp(36px, 4vw, 64px);
  }

  /* Top-aligned, not centred on the film: the hairline above is the line that
     opens the Method and this heading is the Method's first sentence, so the
     two have to read as one thing. Centred against a 590px film it drifts a
     third of the way down the band and the line is left opening nothing. */
  .tour-section__copy {
    flex: 1 1 0;
    align-self: start;
    max-width: 42ch;
  }

  .component-slot--tour {
    flex: 0 0 auto;
    max-width: min(42vw, 72vh, 470px);
  }
}

/* A plain section on the page's own background, for the bands that are written
   as HTML rather than mounted as components. The heading follows the hero and
   the Storyworld band: the line is the page's ink and the phrase it is really
   making is gold. */
.page-section {
  position: relative;
  z-index: 6;
  width: min(100%, var(--hero-max-width));
  margin: 0 auto;
  padding: clamp(40px, 5vw, 88px) var(--hero-gutter) clamp(48px, 5vw, 84px);
  background: var(--page-bg);
}

.page-section__title {
  margin: 0;
  font-family: var(--sans);
  font-size: clamp(26px, 2.6vw, 44px);
  font-weight: 520;
  letter-spacing: -.025em;
  line-height: 1.06;
  color: var(--ink);
}

.page-section__title span {
  color: var(--gold-text);
}

.benefits-section {
  padding-top: clamp(58px, 6vw, 92px);
  padding-bottom: clamp(72px, 7vw, 112px);
  padding-left: 18px;
  padding-right: 18px;
  background:
    linear-gradient(135deg, rgba(201, 231, 251, .5), rgba(248, 250, 240, 0) 36%),
    linear-gradient(180deg, var(--page-bg), var(--surface-alt));
}

.benefits-section::before {
  content: "";
  position: absolute;
  top: 0;
  left: 18px;
  right: 18px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(120, 89, 12, .28) 16%, rgba(120, 89, 12, .28) 84%, transparent);
}

.benefits-section__title {
  max-width: 1080px;
  font-size: clamp(42px, 4.4vw, 68px);
  line-height: 1.02;
  letter-spacing: -.04em;
  text-wrap: balance;
}

.benefits-section__intro {
  max-width: 1080px;
  margin: clamp(20px, 2vw, 29px) 0 0;
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(23px, 2.05vw, 31px);
  font-weight: 520;
  line-height: 1.18;
  letter-spacing: -.025em;
  text-wrap: balance;
}

/* One sentence, two beats: the claim, then the concession that carries the
   joke. Each line breaks on its own, while only the technology phrase turns
   gold. */
.benefits-section__intro-line {
  display: block;
}

.benefits-section__intro-line + .benefits-section__intro-line {
  margin-top: .24em;
}

.benefits-section__intro-line span {
  color: var(--gold-text);
}

.benefits-section__content {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 34px;
  max-width: 1120px;
  margin: clamp(32px, 3.2vw, 48px) 0 0;
}

.benefits-section__values,
.benefits-section__features {
  margin: 0;
  padding: 0;
  list-style: none;
}

.benefits-section__values {
  display: grid;
  gap: clamp(14px, 1.25vw, 18px);
}

.benefits-section__values li {
  display: grid;
  grid-template-columns: clamp(42px, 3.7vw, 50px) minmax(0, 1fr);
  align-items: center;
  gap: clamp(13px, 1.3vw, 18px);
  min-height: clamp(46px, 4vw, 54px);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(18px, 1.55vw, 22px);
  font-weight: 540;
  line-height: 1.3;
  letter-spacing: -.018em;
}

.benefits-section__value-icon {
  display: grid;
  place-items: center;
  width: clamp(42px, 3.7vw, 50px);
  aspect-ratio: 1;
  border: 1px solid rgba(67, 104, 51, .28);
  border-radius: 14px;
  color: var(--sage);
  background:
    radial-gradient(circle at 35% 25%, rgba(248, 250, 240, .72), transparent 52%),
    rgba(157, 203, 202, .42);
  box-shadow:
    inset 0 1px 0 rgba(248, 250, 240, .72),
    0 8px 20px rgba(67, 104, 51, .08);
}

.benefits-section__value-icon svg {
  width: 54%;
  height: 54%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.55;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 5px rgba(67, 104, 51, .16));
}

/* Stacked, the divider between the two lists is a rule above rather than a
   rule beside. */
.benefits-section__feature-group {
  padding-top: 30px;
  padding-left: 0;
  border-top: 1px solid rgba(67, 104, 51, .22);
  border-left: 0;
}

.benefits-section__features {
  display: grid;
  gap: clamp(11px, 1vw, 15px);
}

.benefits-section__features li {
  display: grid;
  grid-template-columns: 1.35em minmax(0, 1fr);
  align-items: start;
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: clamp(17px, 1.35vw, 20px);
  line-height: 1.45;
  letter-spacing: -.012em;
}

.benefits-section__features li::before {
  content: "✓";
  padding-top: .04em;
  color: var(--gold-text);
  font-size: .92em;
  font-weight: 720;
  line-height: 1.45;
  text-shadow: 0 0 12px rgba(255, 222, 160, .5);
}

.anchor-target {
  height: 0;
  overflow: hidden;
}

/* Anchored sections sit under a fixed 56-68px bar, so an unadjusted jump lands
   with the heading hidden behind it. */
#method,
#pricing,
#early-access {
  scroll-margin-top: calc(clamp(56px, 4.7vw, 68px) + 12px);
}

/* ---- Price --------------------------------------------------------------
   The last band on the page. It drafted once as a cream section above the
   download buttons, on the theory that cost is the question standing between
   reading and tapping. There is no price yet to weigh, so all that did was hand
   the reader an open question to carry past the buttons; behind them it reads
   as what it is, a note about who is building this.

   It takes the closing band's ground rather than its own, picking up at the
   sage-night the section above ends on, so the foot of the page is one dark
   region in two parts. Centred, because the band it continues is centred and a
   change of alignment here would read as a change of subject.
   ------------------------------------------------------------------------ */
.pricing-section {
  position: relative;
  padding: clamp(46px, 5vw, 76px) var(--hero-gutter) clamp(58px, 7vw, 104px);
  background: var(--sage-night);
  color: var(--hero-ink);
  text-align: center;
}

/* The same hairline as every other seam on the page, in the dark band's gold. */
.pricing-section::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--hero-gutter);
  right: var(--hero-gutter);
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 222, 160, .34) 18%, rgba(255, 222, 160, .34) 82%, transparent);
}

/* The same 720px measure the band above uses. The two are stacked, centred and
   on one ground: a different column width would read as a misalignment rather
   than as a distinction. */
.pricing-section__inner {
  width: min(100%, 720px);
  margin: 0 auto;
}

/* The cap line that names the band. Shared with the download band above rather
   than copied, because they are one device: a small gold label sitting over a
   serif heading. Both bands say what they are, which is what lets the header's
   Price link land somewhere that answers to the name. */
.pricing-section__kicker,
.early-access__kicker {
  margin: 0 0 clamp(14px, 1.4vw, 20px);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 620;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--gold-on-dark);
}

.pricing-section__title {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(28px, 3.6vw, 42px);
  font-weight: 500;
  line-height: 1.06;
  letter-spacing: -.03em;
  text-wrap: balance;
}

.pricing-section__title span {
  color: var(--gold-on-dark);
}

.pricing-section__body {
  max-width: 52ch;
  margin: clamp(16px, 1.8vw, 24px) auto 0;
  font-family: var(--sans);
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.5;
  color: var(--hero-ink-soft);
  text-wrap: pretty;
}

/* ---- Early access -------------------------------------------------------
   The download band, on the hero's dark green so the page is bookended. It is
   no longer the last thing on the page — .pricing-section continues this same
   dark ground below it — but it is still where the page is going. Written
   mobile-first: the base rule is the phone layout and the only query below adds
   room back on bigger screens, which is the direction the rest of this file is
   moving in.
   ------------------------------------------------------------------------ */
.early-access {
  position: relative;
  padding: clamp(64px, 9vw, 116px) var(--hero-gutter) clamp(72px, 10vw, 128px);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(67, 104, 51, .55), transparent 62%),
    linear-gradient(180deg, var(--sage-deep) 0%, var(--sage-night) 100%);
  color: var(--hero-ink);
  text-align: center;
}

/* The same gold hairline that opens the benefits section, so the two page
   breaks are recognisably the same device. */
.early-access::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--hero-gutter);
  right: var(--hero-gutter);
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 222, 160, .34) 18%, rgba(255, 222, 160, .34) 82%, transparent);
}

.early-access__inner {
  max-width: 720px;
  margin: 0 auto;
}

/* .early-access__kicker is styled with .pricing-section__kicker, up in the Price
   block — the two bands label themselves with the same cap line. */

.early-access__title {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(34px, 5.4vw, 54px);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -.035em;
  text-wrap: balance;
}

/* Each half on its own line at every width: the two clauses are a call and a
   response, and letting them re-wrap into each other loses the beat. */
.early-access__title span {
  display: block;
}

.early-access__title em {
  font-style: italic;
  color: var(--gold-on-dark);
}

.early-access__body {
  max-width: 46ch;
  margin: clamp(18px, 2vw, 26px) auto 0;
  font-family: var(--sans);
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.5;
  color: var(--hero-ink-soft);
  text-wrap: pretty;
}

.early-access__actions {
  display: flex;
  justify-content: center;
  margin-top: clamp(26px, 3vw, 38px);
}

/* Full-width on a phone, hugging its label from tablet up. */
.early-access__actions .button {
  width: 100%;
  max-width: 320px;
  height: 54px;
}

/* The two store buttons stack on a phone and sit side by side from tablet up.
   Both are .button--primary, so both stand in their own pool, and stacked that
   decides the gap: 12px landed the upper button's reflection across the lower
   button's face, where it stopped being water and became a smear on a button.
   26px is the pool's own reach — 1px of waterline plus the 24px ::after — so
   each one gets its own surface. Side by side
   the two pools run together into a single wet band under both, which is what a
   shared surface should look like, so that gap stays tight. */
.early-access__actions--stores {
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* Icon and label, left-aligned inside the button: the base .button centres its
   children, which leaves a two-line label looking accidental. */
.early-access__store {
  gap: 12px;
}

.early-access__store-icon {
  display: block;
  flex: none;
}

.early-access__store-icon svg {
  display: block;
  width: 25px;
  height: 25px;
  fill: currentColor;
}

.early-access__store-label {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
}

.early-access__store-lead {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 620;
  letter-spacing: .09em;
  line-height: 1.3;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .78);
}

.early-access__store-name {
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.15;
}

/* Small print, but not a footnote: it is the one thing between deciding to
   install and failing to. Sized with .early-access__contact rather than the
   band's body copy, because it qualifies the buttons instead of continuing the
   argument above them.

   The top margin clears the pool under the buttons — the waterline plus its
   24px — and no more, so the note stays tethered to what it qualifies. The
   languages block below keeps its own larger gap and is what separates this
   pair from the next subject. */
.early-access__store-note {
  max-width: 52ch;
  margin: clamp(28px, 3vw, 34px) auto 0;
  font-family: var(--sans);
  font-size: clamp(14.5px, 1.3vw, 16px);
  line-height: 1.55;
  color: var(--hero-ink-soft);
  text-wrap: pretty;
}

/* ---- Early-access languages ---------------------------------------------
   Three tiers under the store buttons, and the only thing distinguishing them
   is how much decoration each one has earned. Available now is a filled pill,
   coming soon is an outline, one day is bare text. Nothing here says "not yet"
   in words, because the weight already does and repeating it in a caption
   would make the last row sound like an apology.

   Centred, unlike the caveats box below: these are three short lists of proper
   nouns, not prose, so centring them under a centred heading costs no
   legibility and keeps the band's axis intact all the way down to the box.

   The top margin now measures from the TestFlight note rather than from the
   pool under the buttons, so it is doing a different job than it used to: it
   is the gap that ends the download and starts the next subject, which is why
   it stays the larger one even though it no longer has a reflection to clear.
   ------------------------------------------------------------------------ */
.early-access__languages {
  margin: clamp(34px, 4vw, 52px) auto 0;
  /* Narrower than the 62ch of the box below. These lists wrap on their own
     terms; left to the full width, the five-item row would sit as one long
     line while the others stayed short, and the tiers would stop reading as a
     stack of comparable things. */
  max-width: 54ch;
}

.early-access__languages-title {
  margin: 0 0 clamp(14px, 1.5vw, 20px);
  font-family: var(--sans);
  /* Matches .early-access__caveats-title exactly: these are the two subheads in
     this band and they are peers, so any difference would imply a hierarchy
     that is not there. */
  font-size: 14px;
  font-weight: 620;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--gold-on-dark);
}

/* A paragraph under the title used to carry the English-speaker condition. It
   is in the title itself now, which is where a condition on all three tiers
   belongs and costs three words instead of two lines. */

.ea-langs {
  display: grid;
  gap: clamp(18px, 2vw, 24px);
}

.ea-langs__label {
  margin: 0 0 10px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 620;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .56);
}

/* Only the shipping tier gets the dot, and it is the same gold as the rule at
   the top of the section rather than a status green — this is a marker on a
   list, not a server light. */
.ea-langs__tier--live .ea-langs__label {
  color: var(--gold-on-dark);
}

.ea-langs__tier--live .ea-langs__label::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--gold-on-dark);
  /* Nudged up off the baseline: a 6px circle sitting on it reads as a period. */
  vertical-align: 1px;
}

.ea-langs__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ea-langs__list li {
  font-family: var(--sans);
  font-size: clamp(14px, 1.25vw, 15.5px);
  line-height: 1.2;
  /* One padding for all three tiers even though only two draw a box, so the
     three rows sit on the same rhythm and the last one does not look like it
     slipped out of alignment. */
  padding: 7px 14px;
  border: 1px solid transparent;
  border-radius: 999px;
  color: var(--hero-ink-soft);
  white-space: nowrap;
}

.ea-langs__tier--live .ea-langs__list li {
  border-color: rgba(255, 222, 160, .46);
  background: rgba(255, 222, 160, .14);
  font-weight: 600;
  color: var(--hero-ink);
}

.ea-langs__tier--soon .ea-langs__list li {
  border-color: rgba(255, 255, 255, .22);
}

/* Nothing drawn at all: no border, no fill, and a colour that sits just above
   the floor of readable on this green. It is a wish list and should look like
   one from across the room. */
.ea-langs__tier--later .ea-langs__list li {
  padding-inline: 6px;
  color: rgba(255, 255, 255, .52);
}

/* ---- Early-access caveats ----------------------------------------------
   Left-aligned inside a centred band. The section above it is display copy and
   reads fine centred; this is small print that someone is meant to actually
   read, and centred prose at that size is hard work.

   It also sits directly under the store buttons, whose reflections occupy the
   band below them — the top margin here clears it.
   ------------------------------------------------------------------------ */
.early-access__caveats {
  max-width: 62ch;
  margin: clamp(34px, 4vw, 52px) auto 0;
  padding: clamp(20px, 2.4vw, 28px) clamp(20px, 2.6vw, 32px);
  border: 1px solid rgba(255, 222, 160, .22);
  border-radius: 16px;
  background: rgba(18, 32, 15, .36);
  text-align: left;
}

.early-access__caveats-title {
  margin: 0 0 clamp(12px, 1.2vw, 16px);
  font-family: var(--sans);
  /* 14px, not the 13 this started at: it is a heading over small print someone
     is meant to actually read, and uppercase with .09em tracking already costs
     legibility before the size does. */
  font-size: 14px;
  font-weight: 620;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--gold-on-dark);
}

.early-access__caveat-list {
  display: grid;
  /* Wider than the 11-14px this had as a bulleted list: these are paragraphs
     now, and the gap between them has to beat the 1.55 gap between their own
     lines or the two items read as one block of text. */
  gap: clamp(16px, 1.6vw, 22px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.early-access__caveat-list li {
  font-family: var(--sans);
  font-size: clamp(14.5px, 1.3vw, 16px);
  line-height: 1.55;
  color: var(--hero-ink-soft);
  text-wrap: pretty;
}

/* Inline, not a line of its own: the label is the first two words of the
   sentence it introduces, and breaking it off would cost the run-on reading. */
.early-access__caveat-label {
  font-weight: 620;
  color: var(--gold-on-dark);
}

.early-access__contact {
  margin: clamp(16px, 1.8vw, 22px) 0 0;
  font-family: var(--sans);
  font-size: clamp(14.5px, 1.3vw, 16px);
  line-height: 1.55;
  color: var(--hero-ink-soft);
  text-wrap: pretty;
}

/* Underlined, because the global reset strips decoration from every anchor and
   this one is a lone link inside a paragraph — colour alone would not mark it. */
.early-access__contact a {
  color: var(--gold-on-dark);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.early-access__contact a:hover,
.early-access__contact a:focus-visible {
  color: #ffd275;
}

@media (min-width: 601px) {
  .early-access__actions .button {
    width: auto;
    min-width: 240px;
  }

  .early-access__actions--stores {
    flex-direction: row;
    gap: clamp(16px, 2vw, 24px);
  }

  .early-access__actions--stores .button {
    min-width: 232px;
  }
}

/* Optional integration visualization: append ?slots=1 to the URL. */
html[data-show-slots="true"] .component-slot {
  outline: 1px dashed rgba(67, 104, 51, 0.72);
  outline-offset: -1px;
  background: rgba(157, 203, 202, 0.08);
}

html[data-show-slots="true"] .component-slot::before {
  content: attr(data-link-slot);
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 9999;
  padding: 6px 9px;
  border: 1px solid rgba(67, 104, 51, 0.34);
  border-radius: 999px;
  color: var(--sage-deep);
  background: rgba(201, 231, 251, 0.92);
  font: 700 10px/1 var(--sans);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  pointer-events: none;
}

.reference-overlay {
  position: fixed;
  inset: 0 auto auto 50%;
  z-index: 99999;
  width: min(100vw, 1448px);
  height: auto;
  transform: translateX(-50%);
  opacity: var(--reference-opacity, 0.5);
  pointer-events: none;
}

/* The book grows with the viewport but the stage does not, so below this the
   two would meet: the copy takes its own row under the animation instead. */
/* ===========================================================================
 * The width ladder, narrow to wide.
 *
 * Everything above this line is the phone layout: one column, gutters in
 * pixels, type sized off vw, buttons full-bleed to 220px. Each block below
 * only adds back what a wider screen has room for, so a phone parses the
 * rules it uses and stops — it never inherits a desktop value and then pays
 * to override it.
 *
 * 481  — the gutter opens from 18 to 22 and the buttons take their full label
 * 861  — the hero stops being a stack: lantern, gutters, side-by-side lists
 * 1121 — the stage stops growing, so the outro copy moves in beside it
 * ======================================================================== */

@media (min-width: 481px) {
  .hero-shell__inner {
    padding-left: 22px;
    padding-right: 22px;
  }

  .hero-copy,
  .hero-copy h1,
  .hero-divider,
  .hero-kicker,
  .hero-body {
    width: calc(100vw - 44px);
    max-width: calc(100vw - 44px);
  }

  .hero-copy h1 {
    font-size: clamp(40px, 11.8vw, 61px);
  }

  .hero-actions {
    gap: 16px;
  }

  .button {
    gap: 30px;
    padding: 0 27px 1px 31px;
    font-size: 20px;
  }

  .component-slot--hero {
    width: calc(100% + 44px);
    margin-left: -22px;
    margin-right: -22px;
  }

  .benefits-section {
    padding-left: 22px;
    padding-right: 22px;
  }

  .benefits-section::before {
    left: 22px;
    right: 22px;
  }
}

/* Wide enough for two columns and for the hero to be composed rather than
   stacked: the mark flies, the lantern comes back into the gutter, and the
   scrim turns from top-to-bottom to left-to-right because the copy now has a
   side of its own. */
@media (min-width: 861px) {
  :root {
    /* Sized off the viewport, not the content: the mark, the book, the
       headline, the paragraph and the buttons all have to clear the fold on
       a laptop. */
    --hero-height: max(100svh, 1120px);
    --brand-big: clamp(70px, 7vw, 112px);
    --mark-size: clamp(25px, 2.1vw, 33px);
  }

  .hero-shell {
    min-height: var(--hero-height);
    overflow: clip;
  }

  .hero-shell__background {
    background-position: center top;
    transform: scale(1.012);
  }

  .hero-shell__night::before {
    background:
      linear-gradient(90deg,
        rgba(44, 79, 30, 0.93) 0%,
        rgba(44, 79, 30, 0.87) 24%,
        rgba(44, 79, 30, 0.72) 39%,
        rgba(44, 79, 30, 0.3) 61%,
        rgba(67, 104, 51, 0.08) 84%,
        rgba(44, 79, 30, 0.2) 100%),
      linear-gradient(180deg,
        rgba(44, 79, 30, 0.06) 0%,
        rgba(44, 79, 30, 0.03) 50%,
        rgba(44, 79, 30, 0.05) 62%,
        rgba(44, 79, 30, 0.1) 73%,
        rgba(44, 79, 30, 0.18) 84%,
        rgba(44, 79, 30, 0.3) 93%,
        rgba(31, 42, 31, 0.42) 100%);
  }

  .hero-shell__inner {
    /* Six tracks, and the tall one is fifth: the film takes row 4, and between
       here and 1121 the outro copy takes a row of its own BELOW the animation.
       The film opens the Method, the animation is its first item and the outro
       says in words what the animation is showing, so that copy reads as the
       item's own paragraph — which is what it is. */
    grid-template-rows: var(--mark-size) auto auto auto minmax(360px, 1fr) auto;
    --hero-pad-top: clamp(18px, 2.2vw, 34px);
    --hero-row-gap: clamp(18px, 2.1vw, 30px);
    row-gap: var(--hero-row-gap);
    min-height: var(--hero-height);
    padding: var(--hero-pad-top) var(--hero-gutter) clamp(28px, 3vw, 48px);
  }

  .hero-shell__lantern {
    display: block;
  }

  /* Each piece back in its named row. The first row is the empty one that
     clears the header bar, so the night takes it too. */
  .hero-shell__night    { grid-row: 1 / 4; }
  .brand-anchor         { grid-row: 2; }
  .hero-copy            { grid-row: 3; }
  .tour-section         { grid-row: 4; }
  .component-slot--hero { grid-row: 5; }
  .hero-outro           { grid-row: 6; }

  .hero-copy {
    width: min(100%, 1100px);
    max-width: none;
  }

  .hero-copy > * {
    max-width: none;
  }

  .hero-copy h1 {
    width: auto;
    max-width: none;
    font-size: clamp(40px, 5.3vw, 60px);
    line-height: 0.99;
  }

  .hero-divider {
    width: min(100%, 530px);
    max-width: none;
    margin-top: clamp(31px, 3vw, 43px);
  }

  .hero-kicker {
    width: auto;
    max-width: none;
    font-size: clamp(17px, 1.75vw, 21px);
    overflow-wrap: normal;
  }

  .hero-body {
    width: auto;
    max-width: 760px;
    font-size: clamp(16px, 1.7vw, 19px);
    overflow-wrap: normal;
  }

  .site-header__mark.is-flying {
    transition: transform 980ms cubic-bezier(0.26, 0.82, 0.2, 1);
  }

  /* Two 192px minimums plus the gap exceed the 460px cap the narrow grid wears,
     so the cap has to come off with the grid or the buttons fight it. */
  .hero-actions {
    display: flex;
    grid-template-columns: none;
    max-width: none;
  }

  .button {
    width: auto;
    min-width: 192px;
    height: 57px;
    font-size: 22px;
  }

  .component-slot--hero,
  html[data-show-slots="true"] .component-slot--hero:empty {
    width: 100%;
    height: var(--hero-stage-height);
    min-height: 360px;
    margin: 0;
  }

  /* An unmounted slot keeps its room here: the desktop hero is a composed
     grid and collapsing row 4 would pull the outro up into the artwork. */
  .component-slot--hero:empty {
    height: var(--hero-stage-height);
    min-height: 360px;
  }

  .benefits-section {
    padding-left: var(--hero-gutter);
    padding-right: var(--hero-gutter);
  }

  .benefits-section::before {
    left: var(--hero-gutter);
    right: var(--hero-gutter);
  }

  .benefits-section__content {
    grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
    gap: clamp(40px, 6vw, 92px);
  }

  .benefits-section__feature-group {
    padding-top: 0;
    padding-left: clamp(28px, 3.6vw, 54px);
    border-top: 0;
    border-left: 1px solid rgba(67, 104, 51, .22);
  }
}

/* Below this the book grows with the viewport while the stage does not, so
   the two would meet — which is why the outro takes its own row until here. */
@media (min-width: 1121px) {
  /* Wide enough for the copy to sit beside the animation instead of above it,
     so the two share a row again and the tall track is the last one. */
  .hero-shell__inner {
    grid-template-rows: var(--mark-size) auto auto auto minmax(360px, 1fr);
  }

  .component-slot--hero .stage {
    --phone-h: 76%;
    width: 74%;
  }

  .component-slot--hero {
    grid-row: 5;
  }

  .hero-outro {
    grid-row: 5;
    justify-self: end;
    width: min(100%, 340px);
    height: var(--hero-stage-height);
  }

  .hero-copy h1 {
    font-size: clamp(42px, 4.25vw, 66px);
  }

  .hero-kicker {
    font-size: clamp(18px, 1.5vw, 23px);
  }

  .hero-body {
    max-width: 940px;
    font-size: clamp(17px, 1.45vw, 21px);
  }
}

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

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