/* ==========================================================================
   Sheesh Media
   Tinted neutrals + two hinted accents. Colour is atmosphere, never a fill.
   Tokens and the full reasoning are documented in ../DESIGN.md
   ========================================================================== */

:root {
  /* --- Brand, sampled from the marked-up concepts ------------------------ */
  --lime:      oklch(0.946 0.165 112);   /* #F0F868 — growth, the up arrow  */
  --violet:    oklch(0.567 0.274 302);   /* #9828F8 — the diagnostic, down  */

  /* --- Neutrals -----------------------------------------------------------
     Not grey. Lights carry a trace of the lime hue, darks a trace of the
     violet. Far below the threshold where anyone reads it as colour, but it
     stops the page sitting dead next to the accents and means the whole
     surface is quietly tinted without a single block of colour. --------- */
  --ink:       oklch(0.155 0.016 300);
  --ink-deep:  oklch(0.115 0.018 300);
  --grey-900:  oklch(0.36 0.014 300);
  --grey-700:  oklch(0.53 0.011 300);
  --grey-500:  oklch(0.67 0.009 300);
  --grey-400:  oklch(0.77 0.008 300);
  --grey-300:  oklch(0.87 0.007 108);
  --grey-200:  oklch(0.93 0.009 108);
  --grey-100:  oklch(0.965 0.009 108);
  --paper:     oklch(0.99 0.005 110);

  /* --- Bloom -------------------------------------------------------------
     The blend technique. One large, very low-alpha radial per section,
     anchored off an edge so it reads as light in the room rather than a
     shape on the page. Lime only ever blooms on dark (a light hue needs a
     dark ground to glow); violet only ever blooms on light. ------------ */
  --bloom-lime-dark:    oklch(0.946 0.165 112 / 0.15);
  --bloom-lime-light:   oklch(0.930 0.170 110 / 0.24);
  --bloom-violet-dark:  oklch(0.600 0.270 302 / 0.20);
  --bloom-violet-light: oklch(0.567 0.274 302 / 0.075);

  /* Contextual roles. Flipped wholesale by .section--dark. */
  --bg:        var(--paper);
  --fg:        var(--ink);
  --fg-muted:  var(--grey-700);
  --rule:      var(--grey-300);
  --accent:    var(--violet);

  --wrap:      1240px;
  --gutter:    clamp(1.25rem, 5vw, 4.5rem);
  --pad-y:     clamp(5rem, 11vh, 9rem);

  --ease:      cubic-bezier(0.16, 1, 0.3, 1);

  /* Two roles, the Clouted model: expressive display + neutral body.
     Anybody carries a 50-150% width axis; 125% is the Obviously-Wide equivalent. */
  --sans:      "Public Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --display:   "Anybody", var(--sans);
  --logo:      "Baloo 2", var(--sans);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { margin: 0; text-wrap: balance; }
p  { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }
svg { display: block; }

::selection { background: var(--lime); color: var(--ink); }

/* --------------------------------------------------------------- a11y --- */

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--paper);
  padding: 0.75rem 1.25rem; font-weight: 600; text-decoration: none;
}
.skip:focus { left: 0; }

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

/* --------------------------------------------------------- primitives --- */

.wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.eyebrow {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: 1.5rem;
}

h1 {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: clamp(2.3rem, 6.2vw, 5.1rem);
  font-weight: 800;
  letter-spacing: -0.015em;
  line-height: 1.0;
  text-transform: uppercase;
}

h2 {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: clamp(1.7rem, 3.8vw, 3rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.05;
  text-transform: uppercase;
}

/* Sentence case, normal width. Caps at this size would shout over the H2s
   and the extra width would wreck the measure in body columns. */
h3 {
  font-family: var(--display);
  font-stretch: 100%;
  font-size: clamp(1.15rem, 2vw, 1.4rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.lead {
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  line-height: 1.55;
  letter-spacing: -0.01em;
  color: var(--fg-muted);
  max-width: 54ch;
}

/* ------------------------------------------------------------ wordmark --- */
/* Rebuilt in CSS from the mark: heavy rounded letterform, thin grey edge,
   hard offset shadow, no blur. Matches raw/Assets/sheesh-logo.png.
   TODO(Q11): swap for a true SVG once one is drawn from the source file. */

.wordmark {
  font-family: var(--logo);
  font-weight: 800;
  font-size: 2rem;
  line-height: 1;
  letter-spacing: -0.005em;
  color: var(--paper);
  text-decoration: none;
  padding-block: 0.15em 0.3em;
  /* Thin edge only: at nav size a heavier stroke closes the counters and the
     mark turns to mush. The offset shadow does the defining work. */
  -webkit-text-stroke: 0.9px var(--grey-500);
  text-shadow: 0.06em 0.065em 0 var(--ink);
  transition: transform 0.2s var(--ease);
  display: inline-block;
}

.wordmark:hover { transform: translate(-1px, -1px); }
.wordmark__bang { margin-left: 0.02em; }

/* On dark grounds the black shadow disappears, so it is dropped.
   Documented rule in raw/Brand/Brand-Identity.md */
.wordmark--invert {
  text-shadow: none;
  -webkit-text-stroke: 0;
  color: var(--paper);
}

/* ------------------------------------------------------------- buttons --- */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 46px;
  padding: 0.8rem 1.6rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease),
              border-color 0.2s var(--ease), transform 0.2s var(--ease);
}

/* Colour lives on the objects, not the grounds. The primary button takes the
   section's accent: violet on light, lime on dark. Lime can never be a button
   on a light ground (L 0.946 against paper at 0.99 is invisible), which is
   exactly why the accent flips by context rather than being fixed. */
/* Three layers, which is what stops a flat fill reading as a coloured
   rectangle: a top inner highlight for the lit edge, a tinted drop shadow in
   the button's own hue so it sits in the page rather than on it, and a tight
   neutral shadow for contact. */
.btn--primary {
  background: var(--accent);
  color: var(--paper);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.22),
    0 6px 16px oklch(0.567 0.274 302 / 0.32),
    0 1px 2px oklch(0.155 0.016 300 / 0.28);
}

.btn--primary:hover {
  transform: translateY(-2px);
  filter: saturate(1.1);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.28),
    0 10px 24px oklch(0.567 0.274 302 / 0.42),
    0 2px 4px oklch(0.155 0.016 300 / 0.3);
}

.btn--primary:active { transform: translateY(0); }

.btn--ghost {
  background: var(--paper);
  color: var(--fg);
  border-color: var(--rule);
  box-shadow: 0 2px 6px oklch(0.155 0.016 300 / 0.06);
}

.btn--ghost:hover {
  border-color: var(--fg);
  transform: translateY(-2px);
  box-shadow: 0 8px 18px oklch(0.155 0.016 300 / 0.12);
}

.btn--ghost:active { transform: translateY(0); }

.btn--sm { min-height: 40px; padding: 0.6rem 1.2rem; font-size: 0.875rem; }
.btn--lg { min-height: 54px; padding: 1rem 2.25rem; font-size: 1.05rem; }

/* Inverted sections flip the primary button so it stays the loudest thing.
   --accent is already lime here, so only the text colour needs correcting. */
.section--dark .btn--primary { color: var(--ink); }
.section--dark .btn--ghost   { color: var(--paper); border-color: oklch(1 0 0 / 0.28); }
.section--dark .btn--ghost:hover { border-color: var(--paper); }

/* ----------------------------------------------------------------- nav --- */

/* The nav is a floating pill from the first paint, not only once the page
   moves. The bar itself stays transparent so the page shows through around it;
   scrolling only deepens the pill's shadow and opacity. */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  padding: clamp(0.6rem, 1.4vw, 0.9rem) var(--gutter) 0;
  background: transparent;
}

.nav__inner {
  max-width: min(880px, 100%);
  margin-inline: auto;
  padding: 0.62rem clamp(0.9rem, 2.2vw, 1.6rem) 0.62rem clamp(1rem, 2.4vw, 1.75rem);
  display: flex;
  align-items: center;
  gap: 1rem;

  border: 1px solid var(--grey-300);
  border-radius: 999px;
  background: oklch(0.99 0.005 110 / 0.86);
  backdrop-filter: blur(14px);
  box-shadow: 0 4px 18px oklch(0.155 0.016 300 / 0.06);
  transition: background-color 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

/* Scrolled: same object, just sitting further off the page. */
.nav.is-stuck .nav__inner {
  background: oklch(0.99 0.005 110 / 0.94);
  box-shadow: 0 8px 32px oklch(0.155 0.016 300 / 0.14);
}


/* --------------------------------------------------------------- bloom ---
   The blend technique, lifted from how Clouted handles its cyan: one large,
   very low-alpha radial per section, anchored off an edge so it reads as
   light in the room rather than a shape on the page. Never a fill.

   Placement follows the page's emotional arc rather than a repeating rule:
   violet haze through the problem and the diagnosis, lime warmth as it
   turns toward growth, strongest on the final ask. Four sections carry no
   bloom at all, which is what keeps the ones that do from feeling decorative.
   ------------------------------------------------------------------------ */

.section, .hero { position: relative; overflow: hidden; }

.section::before, .hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.hero::before {
  background:
    radial-gradient(70% 55% at 88% 6%, var(--bloom-violet-light), transparent 62%),
    radial-gradient(58% 46% at -6% 106%, var(--bloom-lime-light), transparent 70%);
}

.problem::before {
  background: radial-gradient(68% 54% at 6% -4%, var(--bloom-violet-light), transparent 68%);
}

.diagnostic::before {
  background:
    radial-gradient(48% 34% at 96% 30%, var(--bloom-violet-light), transparent 68%),
    radial-gradient(58% 40% at 4% 88%, var(--bloom-lime-light), transparent 70%);
}

.process::before {
  background: radial-gradient(74% 58% at 92% -4%, var(--bloom-lime-light), transparent 68%);
}

.close::before {
  background: radial-gradient(54% 44% at 96% 6%, var(--bloom-violet-light), transparent 70%);
}

.outcomes::before {
  background: radial-gradient(66% 54% at -4% 2%, var(--bloom-lime-light), transparent 70%);
}

/* Hairline dividers fade out at both ends rather than butting the gutters,
   so the rule reads drawn rather than boxed. */
.section--tint + .section:not(.section--dark)::after,
.diagnostic::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(to right, transparent, var(--rule) 22%, var(--rule) 78%, transparent);
}

/* ------------------------------------------------------------ sections --- */

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

.section--tint { background: var(--grey-100); }

.section--dark {
  --bg: var(--ink-deep);
  --fg: var(--paper);
  --fg-muted: var(--grey-400);
  --rule: oklch(1 0 0 / 0.15);
  --accent: var(--lime);
  background: var(--bg);
  color: var(--fg);
}

/* Light text on a dark ground needs a touch more leading to stay readable. */
.section--dark p { line-height: 1.7; }

.head { max-width: min(100%, 42rem); margin-bottom: clamp(3rem, 6vw, 4.5rem); }

/* Measure is set on the heading itself: `ch` resolves against the element's
   own font-size, so putting it on the wrapper would compute against body text
   and break these into two-word lines. */
.head h2 { max-width: 18ch; }

/* Asymmetric two-column report layout: sticky label rail, wide content. */
.cols {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
  gap: clamp(2.5rem, 6vw, 6rem);
  align-items: start;
}

.cols__label { position: sticky; top: 7rem; }

/* The rail is narrow, so a full-size H2 sets to three or four words a line.
   Step it down here rather than widening the column and losing the asymmetry.
   Caps are dropped too: "WE TELL YOU WHAT IS WRONG BEFORE WE TOUCH ANYTHING"
   runs to seven lines in a 300px rail. A rail label is a different
   typographic role from a section head, so sentence case reads as intentional. */
.cols__label h2 {
  font-size: clamp(1.5rem, 2.4vw, 2.15rem);
  font-stretch: 110%;
  letter-spacing: -0.025em;
  line-height: 1.12;
  text-transform: none;
  margin-bottom: 1.25rem;
}
.cols__note { color: var(--fg-muted); max-width: 34ch; font-size: 0.98rem; }
.cols__body > h2 { margin-bottom: 1.5rem; }
.cols__body > .lead { margin-bottom: 2.5rem; }

/* ---------------------------------------------------------------- hero --- */

.hero { padding-block: clamp(4.5rem, 13vh, 8.5rem) clamp(2.5rem, 6vh, 4rem); }
/* Caps at 125% width set much wider than sentence case did, so the measure
   is looser here than it looks. Tighter than this orphans "DID." on line 5. */
.hero__title { margin-bottom: 2rem; max-width: 19ch; }
.hero__title-dim { color: var(--grey-500); }
.hero .lead { max-width: 56ch; }

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-top: 2.75rem;
}

/* ------------------------------------------------------------- arrows --- */
/* The mark's hand-drawn arrows, redrawn. Used exactly twice on the page:
   down at the plateau, up at the outcome. */

.arrow {
  width: clamp(64px, 8vw, 108px);
  height: auto;
  margin-top: 2.75rem;
  color: var(--accent);
  opacity: 1;
}

/* ------------------------------------------------------------- problem --- */

.symptoms { display: grid; gap: 0; margin-bottom: 3rem; }

.symptoms li {
  padding-block: 1.15rem;
  border-top: 1px solid var(--rule);
  font-size: 1.075rem;
  color: var(--fg);
  max-width: 60ch;
}
.symptoms li:last-child { border-bottom: 1px solid var(--rule); }

.callout {
  font-size: clamp(1.05rem, 1.5vw, 1.2rem);
  line-height: 1.6;
  max-width: 58ch;
  color: var(--fg);
  font-weight: 500;
  letter-spacing: -0.01em;
}

.callout--light { color: var(--grey-900); }

/* ---------------------------------------------------------- diagnostic ---
   Six items as a stepped stack rather than a ruled list. The list version ran
   to most of a screen on its own; this holds one item at a time with the next
   two peeking behind it, so the section keeps its weight without its height. */

.dx { position: relative; }

.dx__stack {
  position: relative;
  min-height: 268px;
}

.dx__card {
  position: absolute;
  inset: 0 0 auto 0;
  min-height: 226px;
  padding: clamp(1.6rem, 3vw, 2.25rem);
  border: 1px solid var(--grey-300);
  border-radius: 14px;
  background: var(--paper);
  box-shadow: 0 10px 30px oklch(0.155 0.016 300 / 0.06);
  transform-origin: top center;
  /* Short on purpose: a click is applied immediately, so this has to be
     quick enough that an interrupted card still reads. */
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}

/* Stack positions. Only three are ever visible; the rest wait out of sight. */
.dx__card[data-pos="0"] { transform: none;                       opacity: 1;    z-index: 3; }
.dx__card[data-pos="1"] { transform: translateY(15px) scale(.972); opacity: .5;  z-index: 2; }
.dx__card[data-pos="2"] { transform: translateY(30px) scale(.944); opacity: .22; z-index: 1; }
/* Two parking states, not one. "out" is the card just dismissed, which leaves
   upward; "wait" is anything not yet reached, which sits behind the stack so it
   fades forward instead of sliding down through the cards in front of it. */
.dx__card[data-pos="out"]  { transform: translateY(-20px) scale(.97); opacity: 0; z-index: 0;
                             pointer-events: none; }
.dx__card[data-pos="wait"] { transform: translateY(40px)  scale(.92); opacity: 0; z-index: 0;
                             pointer-events: none; }

.dx__num {
  display: inline-block;
  font-family: var(--display);
  font-stretch: 110%;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--paper);
  background: var(--accent);
  border-radius: 999px;
  padding: 0.22rem 0.6rem;
  margin-bottom: 1rem;
}

.dx__card h3 { margin-bottom: 0.6rem; }
.dx__card p  { color: var(--fg-muted); max-width: 46ch; }

/* --- stepper controls, in the rail ------------------------------------- */

.dx__nav {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: clamp(1.75rem, 4vh, 2.5rem);
}

.dx__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--grey-300);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease),
              color 0.2s var(--ease), transform 0.2s var(--ease);
}

.dx__btn svg { width: 17px; height: auto; }

.dx__btn:hover {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--paper);
  transform: translateY(-2px);
}

.dx__count {
  margin-left: 0.5rem;
  font-family: var(--display);
  font-stretch: 110%;
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: var(--grey-500);
  font-variant-numeric: tabular-nums;
}

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

.index__close {
  margin-top: clamp(2.5rem, 5vh, 3.5rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  max-width: 46ch;
}

/* --------------------------------------------------------------- map ---
   Animated roadmap. Nodes and SVG share one 1200x620 coordinate space so
   the arrows always meet the boxes. On desktop the container is locked to
   that aspect ratio and everything is positioned in percentages of it. */

.map {
  position: relative;
  margin-top: clamp(1rem, 3vw, 2rem);
}

/* The container is only a reveal trigger, so it must not fade itself. */
.map[data-reveal] { opacity: 1; transform: none; }

.map__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  z-index: 0;
}

.map__line {
  stroke: var(--grey-900);
  stroke-width: 3;
  stroke-dasharray: 11 9;
  stroke-linecap: round;
  fill: none;
}

/* The head is no longer inside the mask. It waits for its line to finish and
   then pops, so the arrow lands rather than fading up alongside the stroke.
   --dl per head in the markup = that line's delay plus its duration. */
.map__head {
  stroke: var(--grey-900);
  stroke-width: 3.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.map.is-in .map__head {
  animation: headpop 0.4s var(--ease) var(--dl, 0s) both;
}

@keyframes headpop {
  0%   { opacity: 0; transform: scale(0.4); }
  65%  { opacity: 1; transform: scale(1.18); }
  100% { opacity: 1; transform: scale(1); }
}

/* The mask stroke is what animates. pathLength="1" normalises every path so
   one keyframe works for all five regardless of their real length. */
.map__draw {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.map.is-in .map__draw {
  animation: draw 0.6s var(--ease) var(--dl, 0s) forwards;
}

@keyframes draw { to { stroke-dashoffset: 0; } }

.map__node {
  position: relative;
  z-index: 1;
  opacity: 0;
  transform: translateY(12px);
}

.map.is-in .map__node {
  animation: pop 0.6s var(--ease) var(--dl, 0s) forwards;
}

@keyframes pop { to { opacity: 1; transform: none; } }

.map__num {
  display: inline-block;
  font-family: var(--display);
  font-stretch: 110%;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--paper);
  background: var(--accent);
  border-radius: 999px;
  padding: 0.22rem 0.6rem;
  margin-bottom: 0.7rem;
}

/* Each badge lights the moment the arrow pointing at it finishes drawing, so
   the section reads as a relay rather than six things fading in at once.
   --glow is set per node in the markup and is timed off the arrow's end. */
.map.is-in .map__num {
  animation: badgeglow 0.9s var(--ease) var(--glow, 0s) both;
}

@keyframes badgeglow {
  0%   { box-shadow: 0 0 0 0 oklch(0.567 0.274 302 / 0.5); transform: scale(1); }
  35%  { box-shadow: 0 0 0 9px oklch(0.567 0.274 302 / 0); transform: scale(1.14); }
  100% { box-shadow: 0 0 0 0 oklch(0.567 0.274 302 / 0); transform: scale(1); }
}

.map__node h3 { margin-bottom: 0.5rem; }
.map__node p  { color: var(--fg-muted); font-size: 0.98rem; }

/* --- desktop: the actual roadmap ---------------------------------------- */

@media (min-width: 1000px) {
  .map { aspect-ratio: 1200 / 560; }

  .map__node { position: absolute; width: 24%; }

  /* Three columns, each shared by one node in the top row and one in the
     bottom, so the serpentine reads as a grid rather than a scatter. */
  .map__node--n1 { left: 0;   top: 3%; }
  .map__node--n2 { left: 37%; top: 14%; }
  .map__node--n3 { left: 71%; top: 4%; }
  .map__node--n4 { left: 71%; top: 55%; }
  .map__node--n5 { left: 37%; top: 68%; }
  .map__node--n6 { left: 0;   top: 57%; }
}

/* --- below 1000px: a plain numbered list with a spine ------------------- */

@media (max-width: 999px) {
  .map__svg { display: none; }

  .map {
    display: grid;
    gap: 0;
    border-left: 2px dashed var(--grey-300);
    padding-left: 1.5rem;
    margin-left: 0.5rem;
  }

  .map__node { padding-block: 1.4rem; }
  .map__node::before {
    content: "";
    position: absolute;
    left: calc(-1.5rem - 5px);
    top: 1.75rem;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
  }
}

/* ------------------------------------------------------------- process --- */

.steps {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--rule);
}

.step {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
  gap: clamp(1.5rem, 6vw, 6rem);
  padding-block: clamp(2.5rem, 5vw, 3.75rem);
  border-bottom: 1px solid var(--rule);
  align-items: start;
}

.step__num {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: clamp(3.5rem, 9vw, 7rem);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 0.82;
  /* Ghosted, not muted: the numeral is scale and rhythm, not information.
     On the old dark ground this was white at 22%. */
  color: var(--grey-300);
  font-variant-numeric: tabular-nums;
  transition: color 0.4s var(--ease);
}

.step:hover .step__num { color: var(--accent); }

.step__body h3 { margin-bottom: 0.9rem; font-size: clamp(1.3rem, 2.3vw, 1.65rem); }
.step__body p { color: var(--fg-muted); max-width: 56ch; }

/* ------------------------------------------------------------ outcomes ---
   Card layout after the ContentCashMedia process block: number badge in the
   top-right corner, icon, title, rule, body. Theirs is centred on dark green;
   this keeps the site's left-aligned head and light palette. */

.outcomes__head {
  display: flex;
  align-items: flex-start;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  max-width: 62rem;
  margin-bottom: clamp(2.5rem, 6vw, 4rem);
}

.outcomes__head .arrow { margin-top: 0.25rem; flex: 0 0 auto; }
.outcomes__head h2 { margin-bottom: 1.1rem; }

.goals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
  gap: clamp(1rem, 2vw, 1.6rem);
  margin-bottom: clamp(2.5rem, 5vw, 3.5rem);
}

.goal {
  position: relative;
  padding: clamp(1.6rem, 2.6vw, 2.1rem);
  border: 1px solid var(--grey-300);
  border-radius: 14px;
  background: var(--paper);
  box-shadow: 0 10px 30px oklch(0.155 0.016 300 / 0.05);
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}

.goal:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 40px oklch(0.155 0.016 300 / 0.09);
}

/* Corner badge, the one detail that makes the reference block read as a set
   rather than three unrelated cards. */
.goal__n {
  position: absolute;
  top: clamp(1.1rem, 2vw, 1.5rem);
  right: clamp(1.1rem, 2vw, 1.5rem);
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--paper);
  font-family: var(--display);
  font-stretch: 110%;
  font-size: 0.8rem;
  font-weight: 800;
}

.goal__icon {
  width: 26px;
  height: 26px;
  color: var(--accent);
  margin-bottom: 1.1rem;
}

/* Reserve two lines so the rule sits at the same height on every card, the
   way it does in the reference. */
.goal h3 { margin-bottom: 1rem; padding-right: 2.5rem; min-height: 2.5em; }

.goal__rule {
  height: 1px;
  border: 0;
  margin: 0 0 1rem;
  background: var(--grey-300);
}

.goal p { color: var(--fg-muted); font-size: 0.98rem; }

@media (max-width: 700px) {
  .outcomes__head { flex-direction: column; gap: 1rem; }
}

/* ------------------------------------------------------------ the ask ---
   A dark card on a light page rather than a dark section. It ends up the
   only dark object on the page, which is exactly why the eye lands on it. */

.ctacard {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  margin-top: clamp(3.5rem, 8vh, 6rem);
  padding: clamp(3rem, 7vw, 5.5rem) clamp(1.5rem, 5vw, 4rem);
  border-radius: clamp(16px, 2vw, 26px);
  background: var(--ink-deep);
  color: var(--paper);
  text-align: center;
}

/* Violet rising from below, a trace of lime top-right. Same blend logic as
   the section blooms, just contained by the card instead of the viewport. */
.ctacard::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(62% 74% at 50% 122%, oklch(0.60 0.27 302 / 0.60), transparent 64%),
    radial-gradient(44% 54% at 86% -14%, oklch(0.946 0.165 112 / 0.12), transparent 68%);
}

.ctacard h2 {
  color: var(--paper);
  max-width: 22ch;
  margin-inline: auto;
  margin-bottom: 1.25rem;
}

.ctacard p {
  color: var(--grey-400);
  max-width: 48ch;
  margin-inline: auto;
  margin-bottom: 2.25rem;
  line-height: 1.6;
}

.ctacard__note {
  margin-top: 1.5rem;
  margin-bottom: 0;
  font-size: 0.85rem;
  color: var(--grey-500);
}

/* Pill button, lime on the dark card. The one fully saturated lime left. */
.btn--pill {
  border-radius: 999px;
  background: var(--lime);
  color: var(--ink);
  min-height: 52px;
  padding: 0.9rem 1.9rem;
  font-size: 1rem;
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.5),
    0 8px 30px oklch(0.946 0.165 112 / 0.34),
    0 2px 4px oklch(0 0 0 / 0.3);
}
.btn--pill:hover {
  background: var(--paper);
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 oklch(1 0 0 / 0.6),
    0 14px 38px oklch(0.946 0.165 112 / 0.4),
    0 3px 6px oklch(0 0 0 / 0.34);
}
.btn--pill svg { width: 18px; height: auto; }

/* ------------------------------------------------------------ bookform ---
   Lives inside .ctacard, so every ground here is ink-deep and every rule is
   a low-alpha paper, not a grey token — the card sits on its own violet bloom
   and flat greys go muddy over it. The card centres its text; the form is the
   one thing inside it that is left-aligned, because scanning labels down a
   centre line is measurably slower. */
.bookform {
  max-width: 34rem;
  margin: 0 auto;
  text-align: left;
}

.bookform__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 34rem) {
  .bookform__row { grid-template-columns: 1fr; }
}

.field { margin-bottom: 1rem; }

.field label {
  display: block;
  margin-bottom: 0.4rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--grey-400);
}

.field input,
.field textarea {
  width: 100%;
  padding: 0.8rem 0.95rem;
  border: 1px solid oklch(1 0 0 / 0.16);
  border-radius: 10px;
  background: oklch(1 0 0 / 0.05);
  color: var(--paper);
  font: inherit;
  font-size: 0.95rem;
  line-height: 1.5;
  transition: border-color 200ms var(--ease), background 200ms var(--ease);
}

.field textarea { resize: vertical; min-height: 5.5rem; }

.field input::placeholder,
.field textarea::placeholder { color: oklch(1 0 0 / 0.3); }

.field input:hover,
.field textarea:hover { border-color: oklch(1 0 0 / 0.28); }

.field input:focus,
.field textarea:focus {
  outline: 2px solid var(--lime);
  outline-offset: 1px;
  border-color: transparent;
  background: oklch(1 0 0 / 0.08);
}

/* Only marked once the field has actually been submitted or blurred dirty,
   so nothing is red while the visitor is still typing their first character. */
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] { border-color: oklch(0.72 0.18 25); }

.field__error {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.78rem;
  color: oklch(0.78 0.15 25);
}

/* Honeypot. Off-canvas rather than display:none, because some bots skip
   fields that are not rendered at all. */
.bookform__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.bookform__turnstile {
  margin: 1.25rem 0 1.4rem;
  min-height: 65px;
}
.bookform__turnstile:empty { min-height: 0; margin-bottom: 0.4rem; }

.bookform .btn--pill { display: flex; width: 100%; }

.bookform .btn--pill[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.bookform__status {
  margin: 0.9rem 0 0;
  min-height: 1.2rem;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--grey-400);
  text-align: center;
}
.bookform__status[data-state="error"] { color: oklch(0.78 0.15 25); }
.bookform__status[data-state="ok"]    { color: var(--lime); }

/* The card keeps its own note spacing below the form. */
.bookform + noscript .ctacard__note,
.bookform ~ .ctacard__note { margin-top: 1.5rem; }


/* ----------------------------------------------------------------- faq --- */

.acc { border-top: 1px solid var(--rule); }
.acc__item { border-bottom: 1px solid var(--rule); }

.acc__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.5rem 0;
  background: none;
  border: 0;
  font-family: var(--display);
  font-stretch: 100%;
  font-size: clamp(1.02rem, 1.5vw, 1.15rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.35;
  color: var(--fg);
  text-align: left;
  cursor: pointer;
  transition: opacity 0.2s var(--ease);
}

.acc__trigger:hover { opacity: 0.6; }

/* Plus that becomes a minus. Rotation carries the state change. */
.acc__icon {
  position: relative;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
}
.acc__icon::before,
.acc__icon::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: var(--fg);
  transition: transform 0.3s var(--ease);
}
.acc__icon::after { transform: rotate(90deg); }
.acc__trigger[aria-expanded="true"] .acc__icon::after { transform: rotate(0deg); }
.acc__trigger[aria-expanded="true"] .acc__icon::before,
.acc__trigger[aria-expanded="true"] .acc__icon::after { background: var(--accent); }

/* grid-template-rows, never height. Animates cleanly at any content length. */
.acc__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s var(--ease);
}
.acc__panel.is-open { grid-template-rows: 1fr; }
.acc__inner { overflow: hidden; }
.acc__inner p {
  color: var(--fg-muted);
  max-width: 58ch;
  padding-bottom: 1.6rem;
}

/* -------------------------------------------------------------- footer --- */

.footer {
  background: var(--paper);
  color: var(--ink);
  padding-block: clamp(3rem, 7vh, 4.5rem);
  border-top: 1px solid var(--grey-300);
}

.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem 2.5rem;
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.75rem;
  font-size: 0.92rem;
}

.footer__links a {
  color: var(--grey-400);
  text-decoration: none;
  transition: color 0.2s var(--ease);
}
.footer__links a:hover { color: var(--lime); }

.footer__legal {
  font-size: 0.82rem;
  color: var(--grey-500);
  width: 100%;
  padding-top: 1.5rem;
  border-top: 1px solid var(--grey-300);
}

/* -------------------------------------------------------------- motion --- */

[data-reveal],
.hero__el {
  opacity: 0;
  transform: translateY(14px);
}

[data-reveal].is-in,
.hero__el.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

/* ---------------------------------------------------------- responsive --- */

@media (max-width: 900px) {
  /* minmax(0, 1fr), not 1fr: a plain 1fr track has min-width:auto, so the
     results carousel's flex row stretched the column past the viewport and
     dragged the heading off the screen with it. */
  .cols { grid-template-columns: minmax(0, 1fr); gap: 2.5rem; }
  .cols__label { position: static; }
  .arrow { margin-top: 1.5rem; }

  .step { grid-template-columns: 1fr; gap: 0.75rem; }

  .deliver__item { padding-right: 0; }
}

@media (max-width: 560px) {
  .hero__actions .btn { flex: 1 1 100%; }
  .index__row { grid-template-columns: 2.5rem minmax(0, 1fr); }
  .footer__inner { align-items: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  [data-reveal], .hero__el { opacity: 1; transform: none; }
}

/* ==========================================================================
   FLOATING OBJECTS
   Where the colour actually lives. The blooms are atmosphere; these are the
   things wearing the brand outright.
   ========================================================================== */

/* --------------------------------------------------------- floating nav ---
   The bar detaches into a pill once the page moves, so the nav reads as an
   object sitting over the page rather than a band welded to the top of it. */

/* ------------------------------------------------------- floating pills ---
   Six labels, one per thing the diagnostic reads. Label-only by design: a
   number on any of these would read as a client result we do not have. */

/* The hero is a single column since the pill cluster was removed. */
.hero__lower { display: block; }

/* ---------------------------------------------------- floating marquee ---
   A banner, not a section: it sits at an angle and runs past both edges, so
   it reads as an object laid over the page rather than a coloured band. */

/* The banner is wider than the viewport and tilted, so it needs its own
   clipping parent. Putting overflow-x on body instead would break the
   sticky nav. */
.marquee-clip {
  overflow: hidden;
  position: relative;
  z-index: 2;
  /* The band is tilted, so its corners rise above and below its own layout
     box. Without vertical room inside the clip they get sliced off. The
     negative margin cancels the padding so the page position is unchanged. */
  padding-block: 2rem;
  margin-block: -2rem;
}

.marquee {
  position: relative;
  overflow: hidden;
  margin-block: clamp(1rem, 4vh, 2.5rem) calc(clamp(1rem, 4vh, 2.5rem) * -1);
  padding-block: 0.85rem;
  background: var(--lime);
  border-block: 1px solid var(--ink);
  rotate: -1.4deg;
  width: 104%;
  margin-inline: -2%;
}

/* The loop must land on an exact content boundary. `gap` only sits BETWEEN
   children, so half the track width fell mid-gap and the reset was visible as
   a hitch. Trailing margin on every child instead makes each word a uniform
   unit, so -50% is exactly one full copy and the wrap is invisible. */
.marquee__track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: slide 22s linear infinite;
}

.marquee__track > * { margin-right: 1.5rem; }

.marquee span {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: clamp(0.95rem, 1.7vw, 1.3rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.marquee i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--violet);
  flex: 0 0 auto;
}

/* -50% is not the same as one copy: the flex container's max-content width
   does not account for the final child's trailing margin, so -50% undershoots
   by a few pixels and the wrap shows as a hitch. --shift is measured in JS
   (and re-measured once the webfont lands, since that changes the widths). */
@keyframes slide {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-1 * var(--shift, 50%))); }
}

/* ---------------------------------------------------------- responsive --- */

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
  .map.is-in .map__num { animation: none; }
  .map.is-in .map__head { animation: none; opacity: 1; }
}

/* ==========================================================================
   THE DIAGNOSTIC ENGINE
   Blueprint diagram. SVG carries the grid, the machine and every connector;
   HTML carries the pills and labels so they get real type and wrap properly.
   Both share the 1200x560 coordinate space, so the container is locked to
   that aspect ratio and the pills are positioned in percentages of it.
   ========================================================================== */

.mx {
  position: relative;
  aspect-ratio: 1200 / 560;
  margin-top: clamp(1.25rem, 3vw, 2rem);
}

/* Lead-in, not a section head. The engine is the diagnostic drawn rather
   than listed, so it must not announce itself as a new topic. */
.mx-intro {
  margin-top: clamp(3.5rem, 8vh, 6rem);
  font-family: var(--display);
  font-stretch: 110%;
  font-weight: 800;
  font-size: clamp(1.15rem, 2vw, 1.5rem);
  letter-spacing: -0.02em;
  color: var(--fg);
}

.mx[data-reveal] { opacity: 1; transform: none; }

.mx__svg { position: absolute; inset: 0; width: 100%; height: 100%; }

/* --- blueprint ------------------------------------------------------------ */

.mx-grid  { stroke: var(--violet); stroke-width: 1; opacity: 0.18; fill: none; }
.mx-frame { stroke: var(--violet); stroke-width: 1.5; opacity: 0.5; }

/* --- machine -------------------------------------------------------------- */

.mx-housing { stroke: var(--violet); stroke-width: 2.5; fill: oklch(0.99 0.005 110 / 0.6); }
.mx-line    { stroke: var(--violet); stroke-width: 2; fill: none; }
.mx-bolt    { fill: var(--violet); opacity: 0.45; }
.mx-screen  { stroke: var(--violet); stroke-width: 2; fill: var(--ink); }
.mx-trace   { stroke: var(--lime); stroke-width: 3; fill: none; stroke-linecap: round; }
.mx-slider  { fill: var(--violet); }
.mx-led     { fill: var(--violet); }
.mx-node    { fill: none; stroke: var(--grey-900); stroke-width: 2.5; }

/* --- flow ----------------------------------------------------------------- */

/* Dashes march rather than draw on: the point of this diagram is that the
   machine is running, not that it is being built. */
.mx-flow {
  stroke: var(--grey-900);
  stroke-width: 2.5;
  stroke-dasharray: 8 7;
  fill: none;
  animation: march 0.9s linear infinite;
}

.mx-head { stroke: var(--grey-900); stroke-width: 2.8; fill: none;
           stroke-linecap: round; stroke-linejoin: round; }

.mx-loop { stroke: var(--grey-900); stroke-width: 2; fill: none;
           stroke-dasharray: 6 6; opacity: 0.75;
           animation: march 1.6s linear infinite; }

.mx-tick { stroke: var(--grey-700); stroke-width: 2; fill: none; stroke-linecap: round; }

@keyframes march  { to { stroke-dashoffset: -15; } }
@keyframes spin   { to { transform: rotate(360deg); } }
@keyframes spinr  { to { transform: rotate(-360deg); } }
@keyframes slidex { to { transform: translateX(118px); } }
@keyframes blink  { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

.mx-gear--a { animation: spin 11s linear infinite;  transform-origin: 578px 206px; }
.mx-gear--b { animation: spinr 8s linear infinite;  transform-origin: 566px 322px; }
.mx-slider  { animation: slidex 3.4s ease-in-out infinite alternate; }
.mx-led     { animation: blink 2.4s ease-in-out var(--dl, 0s) infinite; }

/* --- reveal --------------------------------------------------------------- */

.mx-g, .mx-pill, .mx-label, .mx-note { opacity: 0; }
.mx.is-in .mx-g,
.mx.is-in .mx-pill,
.mx.is-in .mx-label,
.mx.is-in .mx-note { animation: fadein 0.7s var(--ease) var(--dl, 0s) forwards; }

@keyframes fadein { to { opacity: 1; } }

/* --- pills ---------------------------------------------------------------- */

.mx-pill {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  text-align: center;
  border-radius: 999px;
  font-family: var(--display);
  font-stretch: 110%;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  line-height: 1.12;
  font-size: clamp(0.62rem, 1.05vw, 0.92rem);
  padding: 0.7rem 0.9rem;
}

.mx-pill--in  { left: 1%;  top: 43%; width: 17%; min-height: 11%;
                border: 2.5px solid var(--ink); color: var(--ink); background: var(--paper); }

.mx-pill--out { left: 58%; width: 19.5%; min-height: 9%;
                background: var(--ink); color: var(--paper); }
.mx-o1 { top: 18%; }
.mx-o2 { top: 42%; }
.mx-o3 { top: 66%; }

/* The terminal node. Clouted put a multiplier here; ours stays qualitative
   because a number would be a client result we do not have. */
.mx-pill--end {
  left: 81%; top: 33%; width: 17.5%; min-height: 20%;
  flex-direction: column;
  background: var(--lime);
  color: var(--ink);
  border: 2.5px solid var(--ink);
  font-size: clamp(0.66rem, 1.15vw, 1rem);
}
.mx-pill--end svg { width: clamp(16px, 1.7vw, 24px); height: auto; }

.mx-label {
  position: absolute;
  left: 29%;
  top: 78%;
  width: 26%;
  text-align: center;
  font-family: var(--display);
  font-stretch: 110%;
  font-weight: 800;
  font-size: clamp(0.58rem, 0.95vw, 0.8rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--violet);
}

/* --- handwritten annotations ---------------------------------------------- */
/* Caveat is loaded for these three notes and nothing else. It is an
   annotation face, in the same restricted sense that Baloo 2 is a logotype
   face: never use it for headings, body, or UI. */

.mx-note {
  position: absolute;
  font-family: "Caveat", cursive;
  font-weight: 600;
  font-size: clamp(0.85rem, 1.6vw, 1.3rem);
  line-height: 1.15;
  color: var(--grey-700);
}

.mx-note--a { left: 1%;  top: 25%; }
.mx-note--b { left: 19%; top: 85%; }
.mx-note--c { left: 45%; top: 2%; }

/* --- below 1000px: a stacked flow ----------------------------------------- */

@media (max-width: 999px) {
  .mx { aspect-ratio: auto; display: grid; gap: 0.85rem; justify-items: stretch; }
  .mx__svg, .mx-note, .mx-label { display: none; }

  /* position:relative is needed for the chevron, but that means the desktop
     left/top offsets still apply and shove the pills off-screen. Clear them. */
  .mx-pill {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
    min-height: 0;
    padding: 0.95rem 1rem;
    font-size: 0.85rem;
  }

  /* A chevron between each stacked node, standing in for the connectors.
     Not :last-child — the hidden label and notes still follow the pills in
     the DOM, so the terminal pill is never actually last. */
  .mx-pill:not(.mx-pill--end)::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -0.68rem;
    width: 9px;
    height: 9px;
    border-right: 2.5px solid var(--grey-900);
    border-bottom: 2.5px solid var(--grey-900);
    transform: translateX(-50%) rotate(45deg);
  }
  .mx-pill--end { flex-direction: row; padding-block: 1.1rem; }
  .mx-pill--end svg { width: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  /* These are infinite, so the global 0.01ms override would thrash them. */
  .mx-flow, .mx-loop, .mx-gear--a, .mx-gear--b, .mx-slider, .mx-led { animation: none !important; }
  .mx-g, .mx-pill, .mx-label, .mx-note { opacity: 1; }
}

/* ------------------------------------------------- mirrored marquee ---
   Bookend at the foot of the page. Tilted the other way, words reversed,
   and scrolling the opposite direction, so the pair reads as deliberate
   asymmetry rather than a repeated element. */
/* --flip is orientation only. Placement is separate, because the foot-of-page
   band needs pulling up into the last section while a band sitting on a seam
   between two sections needs pushing down onto the join. */
.marquee--flip { rotate: 1.4deg; }


.marquee--flip .marquee__track {
  animation-name: slideback;
}

@keyframes slideback {
  from { transform: translateX(calc(-1 * var(--shift, 50%))); }
  to   { transform: translateX(0); }
}

/* ------------------------------------------------------------ nav links ---
   Sat next to the wordmark rather than centred: with one link a centred group
   reads as lonely, and this scales when more are added. */

.nav__links {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2vw, 1.6rem);
  /* auto on both sides centres the group between the mark and the button,
     rather than parking it against the mark and leaving a gap on the right. */
  margin-inline: auto;
}

.nav__links a {
  position: relative;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--grey-900);
  text-decoration: none;
  padding-block: 0.4rem;
  transition: color 0.2s var(--ease);
}

.nav__links a::after {
  content: "";
  position: absolute;
  inset: auto 0 0.1rem 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s var(--ease);
}

.nav__links a:hover { color: var(--ink); }
.nav__links a:hover::after,
.nav__links a[aria-current="page"]::after { transform: scaleX(1); }
.nav__links a[aria-current="page"] { color: var(--ink); }

@media (max-width: 560px) {
  /* The wordmark and the booking button take priority on a phone. */
  .nav__links a { font-size: 0.82rem; }
}

/* Below ~380px the wordmark, link and button no longer fit the pill together
   (measured: 44px of overflow at a 320px viewport). The link drops out rather
   than the booking button, and the footer carries it instead. */


/* --------------------------------------------------------- page header ---
   Interior pages: the hero treatment without the floating pills. */

.pagehead { padding-block: clamp(3.5rem, 10vh, 7rem) clamp(1rem, 3vh, 2rem); }
.pagehead__title { max-width: 17ch; margin-bottom: 1.75rem; }
.pagehead .lead { max-width: 58ch; }

/* The page header already supplies the top gap; the section's own padding on
   top of it leaves a dead band before the first row. */
.pagehead + .section { padding-top: 0; }

/* --------------------------------------------------- wordmark arrows ---
   The mark has always carried two hand-drawn arrows, one up and one down.
   Each one is nested inside the letter it belongs to — up over the first e,
   down under the second — so alignment comes from the real glyph box instead
   of a guess at where the letter falls.

   The source PNG spaces them much further from the word than is possible at
   nav size, so this is a tightened lockup rather than a literal trace. */

.wordmark { position: relative; }
.wordmark__word { position: relative; z-index: 1; }
.wm-e { position: relative; }

.wordmark__arrow {
  position: absolute;
  left: 50%;
  width: 0.34em;
  height: auto;
  color: var(--ink);
  opacity: 0.92;
  pointer-events: none;
  transform: translateX(-50%);
  transition: transform 0.25s var(--ease);
}

/* Measured, not estimated. For a 32px wordmark the e-box runs 22.0 to 73.0
   with the baseline at 56.0, and the glyph itself occupies 40.0 to 57.0.
   These offsets sit each arrow 3px clear of the letter; being in em against a
   percentage of the same box, they hold at any wordmark size. */
.wordmark__arrow--up   { bottom: 1.125em; }
.wordmark__arrow--down { top:    1.188em; }

/* They lean apart on hover — the whole idea of the mark in one gesture. */
.wordmark:hover .wordmark__arrow--up   { transform: translate(-50%, -2px); }
.wordmark:hover .wordmark__arrow--down { transform: translate(-50%, 2px); }

/* The nav pill needs a touch more room now the arrows sit outside the text. */
/* Tighter than the first pass, closer to the reference proportions. The
   wordmark steps down in the nav only; the footer keeps the larger mark. */
.nav__inner { padding-block: 0.62rem; }
.nav .wordmark { font-size: 1.6rem; }
.nav .btn--sm { min-height: 38px; padding: 0.55rem 1.15rem; font-size: 0.85rem; }
.nav__links a { font-size: 0.86rem; }

/* ============================ OUR RESULTS ============================
   Horizontally floating cards, after the reference. The track runs off the
   right edge of the section rather than stopping at the column, which is what
   makes them read as floating rather than as a grid.

   Every number is a blank bar by design. The reference screenshots carry other
   agencies' real client figures; none of them appear here. */

/* Clipped on both edges. Cards vanish at the column's left boundary instead
   of sliding across the heading, and still bleed off the right. */
.rs { position: relative; min-width: 0; overflow: hidden; }

.rs__track {
  display: flex;
  align-items: flex-start;
  padding-block: 1.75rem;
  gap: clamp(0.9rem, 1.6vw, 1.4rem);
  transition: transform 0.55s var(--ease);
  will-change: transform;
}

.rs__card {
  position: relative;
  flex: 0 0 clamp(268px, 26vw, 340px);
  padding: clamp(1.5rem, 2.3vw, 1.9rem);
  border-radius: 16px;
  background: var(--ink-deep);
  color: var(--paper);
  overflow: hidden;
  isolation: isolate;
  transition: transform 0.5s var(--ease);
}

/* Fanned rather than flush, after the reference: each slot carries its own
   lift and tilt, so the row reads as a stack of cards laid down by hand. The
   offsets belong to the slot, not the card, so they persist as the carousel
   rotates. */
.rs__card:nth-child(1) { transform: translateY(16px) rotate(-0.7deg); }
.rs__card:nth-child(2) { transform: translateY(2px)  rotate(0.5deg); }
.rs__card:nth-child(3) { transform: translateY(-10px) rotate(-0.4deg); }
.rs__card:nth-child(4) { transform: translateY(-22px) rotate(0.6deg); }

/* Same bloom logic as the booking card, contained by the tile. */
.rs__card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(70% 60% at 88% -12%, oklch(0.60 0.27 302 / 0.55), transparent 66%),
    radial-gradient(60% 50% at 6% 112%, oklch(0.60 0.27 302 / 0.30), transparent 68%);
}

.rs__tag {
  display: inline-block;
  margin-bottom: 0.9rem;
  padding: 0.16rem 0.5rem;
  border: 1px dashed oklch(1 0 0 / 0.35);
  border-radius: 999px;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-400);
}

.rs__head { display: flex; align-items: center; gap: 0.65rem; margin-bottom: 1.1rem; }

.rs__avatar {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: oklch(1 0 0 / 0.08);
  box-shadow: 0 0 0 2px var(--violet);
}

.rs__name  { font-size: 1.08rem; margin-bottom: 0.1rem; }
.rs__niche { font-size: 0.8rem; color: var(--grey-500); }

.rs__stats { margin: 0; }

.rs__row {
  padding-block: 0.72rem;
  border-top: 1px solid oklch(1 0 0 / 0.1);
}
.rs__row:last-child { border-bottom: 1px solid oklch(1 0 0 / 0.1); }

.rs__row dt {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey-500);
  margin-bottom: 0.4rem;
}

.rs__row dd { margin: 0; display: flex; align-items: center; gap: 0.55rem; }

/* Blank where a figure will go. Deliberately reads as empty, not as data. */
.rs__bar {
  display: block;
  height: 16px;
  flex: 1 1 auto;
  border-radius: 4px;
  background: oklch(1 0 0 / 0.09);
}
.rs__bar--after { background: oklch(0.946 0.165 112 / 0.34); }

.rs__to { color: var(--violet); font-size: 0.9rem; }

.rs__span {
  margin-top: 1rem;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--grey-500);
}

.rs__nav { display: flex; align-items: center; gap: 0.6rem; margin-top: clamp(1.75rem, 4vh, 2.5rem); }

@media (min-width: 900px) {
  /* Let the track bleed past the column so cards run off the section edge. */
  .results .cols__body { margin-right: calc(-1 * var(--gutter) - 6vw); }
}

/* Disabled carousel arrows must read as unavailable, not just unresponsive. */
.dx__btn:disabled { opacity: 0.32; cursor: default; }
.dx__btn:disabled:hover {
  border-color: var(--grey-300);
  background: var(--paper);
  color: var(--ink);
  transform: none;
}

/* Four nav links no longer fit the pill alongside the wordmark and the button
   on a phone. They drop out below 900px and the footer carries all of them.
   ⚠️ The nav has outgrown a link row on mobile — a menu is now needed. */
@media (max-width: 899px) {
  .nav__links { display: none; }
}

.footer__links { max-width: 100%; }

/* --------------------------------------------------------- word swap ---
   One noun in the headline cycles. min-width is measured in JS against the
   widest word, so swapping never reflows the line beneath it. Held still
   entirely under reduced motion: auto-updating text is a WCAG 2.2.2 concern,
   not just a motion preference. */

.swap {
  display: inline-block;
  text-align: left;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.swap.is-out {
  opacity: 0;
  transform: translateY(-0.14em);
}

/* ------------------------------------------------------------- plateau ---
   The problem drawn rather than described: two lines that climb together,
   then one keeps going while the other flattens. The gap is the section.
   No axes and no figures — it illustrates a shape, it does not report data. */

.plat {
  width: min(100%, 300px);
  height: auto;
  margin-top: clamp(3.75rem, 9vh, 6.5rem);
}

.plat__grid {
  stroke: var(--grey-300);
  stroke-width: 1.5;
  stroke-linecap: round;
}

.plat__expect {
  stroke: var(--grey-500);
  stroke-width: 2.5;
  stroke-dasharray: 6 7;
  stroke-linecap: round;
  opacity: 0;
}

.plat__actual {
  stroke: var(--violet);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* pathLength="1" again, so one keyframe drives a line of any real length. */
.plat__actual { stroke-dasharray: 1; stroke-dashoffset: 1; }

.plat.is-in .plat__expect { animation: fadein 0.6s var(--ease) 0.2s forwards; }
.plat.is-in .plat__actual { animation: draw 1.3s var(--ease) 0.35s forwards; }

.plat__dot {
  fill: var(--violet);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

/* Marks the moment the two part company, and keeps a slow pulse afterwards so
   the rail has something alive in it while the section is read. */
.plat.is-in .plat__dot { animation: platdot 2.6s var(--ease) 1.1s infinite; }

@keyframes platdot {
  0%   { opacity: 1; transform: scale(0.6); }
  18%  { opacity: 1; transform: scale(1.3); }
  40%  { opacity: 1; transform: scale(1); }
  100% { opacity: 1; transform: scale(1); }
}

.plat__tag {
  font-family: "Caveat", cursive;
  font-size: 17px;
  font-weight: 600;
  fill: var(--grey-500);
  opacity: 0;
}

.plat__tag--flat { fill: var(--violet); }

.plat.is-in .plat__tag { animation: fadein 0.5s var(--ease) 1.4s forwards; }

@media (prefers-reduced-motion: reduce) {
  .plat.is-in .plat__dot { animation: none; opacity: 1; }
  .plat__expect, .plat__tag { opacity: 1; }
  .plat__actual { stroke-dashoffset: 0; }
}

/* ------------------------------------------------------------- burst ---
   The mark's two arrows scatter from the cursor on click. Purely a moment of
   personality, so it is inert to the page: fixed, pointer-events none, and
   removed from the DOM once it has played. Off under reduced motion. */

.burst {
  position: fixed;
  z-index: 9999;
  width: 0;
  height: 0;
  pointer-events: none;
}

.burst__a {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  width: 19px;
  color: var(--violet);
  animation: burst 0.72s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.burst__a--down { color: var(--ink); width: 17px; }

.burst__a svg { width: 100%; height: auto; }

@keyframes burst {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) rotate(var(--a)) translateY(0)
               rotate(var(--r)) scale(0.35);
  }
  /* Holds full opacity through the middle of the flight rather than peaking
     and immediately fading, or the arrows are gone before they register. */
  16%, 58% { opacity: 1; }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) rotate(var(--a)) translateY(calc(-1 * var(--d)))
               rotate(var(--r)) scale(1);
  }
}
