/* ===== 00-tokens.css ===== */
/*
 * Link Prism design tokens.
 *
 * Derived from the Steep style reference (docs: DESIGN.md) with two corrections
 * made after measuring the real site, both of which the written reference omits
 * and both of which are what actually make it read as premium:
 *   1. The hero is NOT flat white — it sits on a soft chromatic gradient wash.
 *   2. A fractal-noise grain overlays the whole page at low opacity.
 * Everything else here matches the reference's documented scale.
 */
:root {
  /* — Ink & paper —————————————————————————————— */
  --ink: #17191c;
  /*
   * Paper is NOT pure white, deliberately. Two reasons, both measured:
   *  - `overlay` grain over #ffffff is an identity operation (overlay(1,x) === 1),
   *    so a pure-white page can carry no texture at all.
   *  - The reference's "white" is never actually white; every band sits on a
   *    faint warm ground, which is most of why it reads as paper and not screen.
   */
  --paper: #fdfcfa;
  --raised: #ffffff;        /* floating artifacts stay true white so they lift off the paper */
  --mist: #f2f2f3;
  --fog: #fafafb;
  /*
   * These three were taken from the reference palette and all FAILED WCAG AA on
   * our paper: slate 4.13:1, ash 2.84:1, smoke 2.37:1 against 4.5:1 for small
   * text. Every eyebrow, footnote and body paragraph on the site was below the
   * threshold. Darkened within the same family until they pass; the greys read
   * fractionally deeper and everything stays legible.
   */
  --slate: #636772;   /* 4.52:1 worst ground (peach) — body copy, ledes, muted text */
  --ash:   #686c76;   /* 4.70:1 worst ground (mist) — eyebrows, footnotes, labels  */
  --smoke: #7d818b;   /* 3.80:1 — LARGE type only (>=24px), never small text */

  /*
   * TEXT ON DARK SURFACES. The greys above are light-ground tokens; several
   * sections place a dark ink panel on the page and reused them inside it, where
   * mid-grey on near-black measures 3.4:1. These are the dark-surface equivalents
   * and are the ONLY muted colours permitted inside an ink panel.
   */
  --on-dark:        color-mix(in srgb, var(--paper) 92%, transparent);  /* body on ink   */
  --on-dark-muted:  color-mix(in srgb, var(--paper) 66%, transparent);  /* labels, ~7:1  */
  --on-dark-faint:  color-mix(in srgb, var(--paper) 48%, transparent);  /* LARGE type only */
  --peach: #fbe1d1;
  --sienna: #5d2a1a;
  --hair: #ececec;
  --hair-strong: rgba(23, 25, 28, 0.12);

  /* Warm tints for the gradient wash — same family as --peach, never used as text */
  --wash-1: #ffd9c2;
  --wash-2: #ffe9d6;
  --wash-3: #f0e2f2;
  --wash-4: #dfe6f5;

  /* — Type —————————————————————————————————————— */
  --serif: 'Source Serif 4', 'Iowan Old Style', Georgia, ui-serif, serif;
  --sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  --t-caption: 15px;
  --t-body: 17px;
  --t-body-lg: 20px;
  --t-subhead: 22px;
  --t-h-sm: 26px;
  --t-h: 44px;
  --t-h-lg: 64px;
  --t-display: 90px;

  /* Tracking tightens as size grows — the typographic signature of the system */
  --tr-display: -0.025em;
  --tr-h-lg: -0.015em;
  --tr-h: -0.015em;
  --tr-h-sm: -0.009em;
  --tr-body-lg: -0.009em;

  /* — Space (4px base) ————————————————————————— */
  --s4: 4px;   --s8: 8px;   --s12: 12px; --s16: 16px; --s20: 20px;
  --s24: 24px; --s28: 28px; --s32: 32px; --s40: 40px; --s48: 48px;
  --s64: 64px; --s80: 80px; --s96: 96px; --s128: 128px; --s160: 160px;

  --nav-h: 76px;
  --page: 1200px;
  --gutter: 32px;

  /*
   * THREE SECTION RHYTHMS, AND ONLY THREE.
   *
   * Nineteen section files used to set their own band height, and they split
   * into two systems: multipliers of --section-y (0.66, 0.82, 1.2, 1.7 …) and
   * fixed pixels (104, 112, 136, 176 …). The two agree at exactly one viewport
   * width and separate everywhere else, so the page's vertical beat changed
   * with the window. Every band now picks one of these and nothing derives its
   * own.
   */
  --section-y-tight: 64px;   /* a strip: a logo rail, a short ledger */
  --section-y: 96px;         /* the normal band — most of the site */
  --section-y-loose: 128px;  /* a stage: the closing band, a tall drawing */

  /*
   * ONE HERO OPENING for all eight pages. The nav is sticky and 76px tall and
   * every hero is pulled up under it, so this figure INCLUDES the nav band:
   * 148 is 72px of visible air above the first mark, on every page. It used to
   * run 148 / 172 / 228 / 244 / 252 across eight heroes that share one nav.
   */
  --hero-y: 148px;

  /* One eyebrow, one gap under it. Seventeen instances used to set thirteen. */
  --eyebrow-gap: var(--s24);

  /* — Shape ——————————————————————————————————— */
  --r-card: 24px;
  --r-elevated: 20px;
  --r-input: 16px;
  --r-small: 16px;
  --r-pill: 9999px;

  /* — Drawings ————————————————————————————————
   * TWO sizes for the whole site, and no third. A set of drawings at six
   * different sizes is size used as hierarchy, which _src/ILLUSTRATION.md
   * items 3 and 7 forbid: a terminal and a printer are comparable objects and
   * must be drawn comparably. `card` is the mark that sits inside a card in a
   * grid; `feature` is the one drawing a section is built around. Both are
   * CEILINGS — `.illo--card` / `.illo--feature` pair them with width:100%, so a
   * narrow column still fits its drawing without inventing a third size.
   */
  --illo-card: 250px;
  --illo-feature: 500px;

  /* Only floating product artifacts earn elevation. Content cards stay flat. */
  --sh-artifact: 0 0 0 1px rgba(4, 23, 43, 0.05), 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
  --sh-overlay: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 8px 40px 0 rgba(0, 0, 0, 0.1);
  --sh-pop: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 4px 24px 0 rgba(0, 0, 0, 0.08);

  /* — Motion ——————————————————————————————————— */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 160ms;
  --dur: 320ms;
  --dur-slow: 720ms;
}

/* The three rhythms and the hero opening ramp together, so the ratios between
   them hold at every width and no section has to re-tune itself. */
@media (max-width: 1080px) {
  :root { --t-display: 68px; --t-h-lg: 48px; --t-h: 36px; --gutter: 28px;
          --section-y-tight: 56px; --section-y: 80px; --section-y-loose: 104px;
          --hero-y: 124px; }
}
@media (max-width: 720px) {
  :root { --t-display: 44px; --t-h-lg: 34px; --t-h: 28px; --t-h-sm: 22px;
          --t-body-lg: 18px; --gutter: 20px; --r-card: 20px;
          --section-y-tight: 40px; --section-y: 64px; --section-y-loose: 80px;
          --hero-y: 104px; }
}

/* ===== 10-base.css ===== */
/* Reset + page substrate: the grain and the gradient wash live here. */
*, *::before, *::after { box-sizing: border-box; }
/*
 * `overflow-x: clip` on the ROOT, not `hidden` on body alone.
 * Sections intentionally crop product cards past the viewport edge; with only
 * body clipping, the document still grew (measured 1510px against a 1440px
 * viewport) and shipped a horizontal scrollbar. `clip` contains it WITHOUT
 * creating a scroll container, so the sticky nav keeps working — `hidden` would
 * silently break it.
 */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; overflow-x: clip; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.35;
  font-weight: 400;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

/*
 * THE GRAIN. A fractal-noise tile at low opacity in `overlay` blend, fixed to the
 * viewport so it never scrolls against the content. This is the single largest
 * contributor to the reference's "printed paper" quality and it is absent from
 * every written description of the system.
 */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  /*
   * `multiply`, not `overlay`. The noise tile is opaque-black-or-transparent, and
   * overlay leaves any near-white base untouched — the grain was mathematically
   * invisible across every light section. Multiply darkens the speckle instead,
   * so the texture reads on paper AND on the warm wash.
   */
  opacity: 0.13;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.91' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='0 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}
@media (prefers-reduced-motion: no-preference) { body::after { will-change: opacity; } }

/* Layout primitives.
   ONE page rail, and every headline block on the site sits on it. There used to
   be a second, wider container (`.wrap-wide`, 1400) used by three sections; at
   1440 it put their headlines on the 32px page gutter while their neighbours
   held 120, an 88px jump between consecutive sections. Full bleed is still
   legal — a drawing, a rule, a background band — but it is done per element,
   never by moving a headline off the rail. */
.wrap { width: min(var(--page), 100% - var(--gutter) * 2); margin-inline: auto; }
.section { padding-block: var(--section-y); position: relative; }
.section--fog { background: var(--fog); }
.section--mist { background: var(--mist); }

/* Type primitives */
.display, .h-lg, .h, .h-sm-serif {
  font-family: var(--serif);
  font-weight: 400;
  font-optical-sizing: auto;
  text-wrap: balance;
  /*
   * THE SIDEBEARING CORRECTION, ONCE, FOR THE WHOLE SITE.
   *
   * A serif cap set flush to a rail reads as indented: the stem sits inside the
   * glyph's left sidebearing, while the sans eyebrow above it and the sans lede
   * below it start on their own ink. Pulling the block back a hair of its own
   * size puts the STEM on the rail, and stated in em it re-derives itself at
   * every step of the type ramp instead of needing a value per breakpoint.
   * Measured on Source Serif 4: cap B, lowercase b and the italic a all land
   * within 1px of each other at -0.026em.
   *
   * This lived in hardware-hero.css as a private rule, bundled with a 64px
   * "hang" that pulled that one title to x=54 while its own eyebrow held 120.
   * The hang is gone; the correction is shared. Three more sections carried
   * near-duplicates of it (-0.02, -0.023, -0.03) and now inherit this one.
   *
   * A CENTRED serif block must switch it off — see .prh-title in pricing-hero —
   * because there the margin moves the centre rather than the left edge.
   */
  margin-left: -0.026em;
}
.display { font-size: var(--t-display); line-height: 1.06; letter-spacing: var(--tr-display); }
.h-lg    { font-size: var(--t-h-lg);   line-height: 1.1;  letter-spacing: var(--tr-h-lg); }
.h       { font-size: var(--t-h);      line-height: 1.16; letter-spacing: var(--tr-h); }
.h-sm-serif { font-size: var(--t-h-sm); line-height: 1.28; letter-spacing: var(--tr-h-sm); }
.display em, .h-lg em, .h em { font-style: italic; }

/*
 * THE ONE FIT-TO-WIDTH OPT-IN, AND THE ONLY ONE.
 *
 * A headline whose authored line genuinely cannot hold the phone column takes
 * this class on top of its scale class instead of inventing a divisor of its
 * own. Six inner heroes each invented one, and at 390px they rendered the same
 * rank at 31.8 / 41 / 41.6 / 42 / 44 and 48px — a 1.8x spread across six
 * elements that are the same thing.
 *
 * It can only ever make type SMALLER than the ramp: it is a min() against the
 * token, so it cannot be used to promote a headline past the class it wears.
 * The divisor is taken from the widest binding line on the site — "When
 * something breaks," which Source Serif sets at 10.47em once the optical axis
 * has opened the face up at small sizes — so one number covers every candidate.
 * Above about 414px of viewport it stops binding entirely and the token ramp is
 * the only thing sizing the line.
 */
.h-fit { font-size: min(var(--t-h-lg), calc((100vw - var(--gutter) * 2) / 11)); }

.h-sm { font-family: var(--sans); font-size: var(--t-h-sm); font-weight: 450;
        line-height: 1.22; letter-spacing: var(--tr-h-sm); }
.lede { font-size: var(--t-body-lg); line-height: 1.45; letter-spacing: var(--tr-body-lg);
        color: var(--slate); text-wrap: pretty; }
.body { font-size: 16px; line-height: 1.55; color: var(--slate); text-wrap: pretty; }
.caption { font-size: var(--t-caption); line-height: 1.5; color: var(--slate); }

/*
 * Ghost typographic tag — groups without visual weight. Never a badge.
 *
 * ONE COMPONENT: one size, one weight, one colour, and one gap to whatever it
 * labels. The gap used to take thirteen values across seventeen instances (2,
 * 16, 19, 24, 26, 28, 32, 38, 42, 45, 57 …) — even the four page-label eyebrows
 * that share the same hero pattern disagreed — and the colour ran --ash on 29
 * of them, --smoke on four, and full --ink at weight 500 on one.
 *
 * Where an eyebrow is a grid or flex participant whose spacing the container
 * already owns, it sets `margin-bottom: 0` and says so. That is the only legal
 * override.
 */
.eyebrow {
  font-size: 14px;
  font-weight: 400;
  color: var(--ash);
  letter-spacing: 0;
  margin-bottom: var(--eyebrow-gap);
}

.tnum { font-variant-numeric: tabular-nums; }
.muted { color: var(--slate); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
:where(a, button, input, [tabindex]):focus-visible {
  outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 4px;
}

/*
 * A hero that carries a wash starts UNDER the transparent nav, so the wash paints
 * behind the logo and links instead of leaving a bald white strip across the top.
 *
 * THE OPENING IS SET HERE AND NOWHERE ELSE. Eight heroes used to compute their
 * own top padding off --section-y plus a private number — 148 / 172 / 228 / 244
 * / 252, a 104px spread on eight components that share one 76px nav — and eight
 * more numbers for the bottom (96 … 236). --hero-y includes the nav band, so
 * every page shows the same 72px of air above its first mark, and the hero
 * closes on the loose rhythm like any other stage.
 */
main > .section:first-child.has-wash {
  margin-top: calc(var(--nav-h) * -1);
  padding-top: var(--hero-y);
  padding-bottom: var(--section-y-loose);
}

/* A whisper of warmth for sections that would otherwise be an undifferentiated slab. */
.section--tint { background:
  radial-gradient(120% 80% at 50% 0%, rgba(251, 225, 209, 0.30) 0%, rgba(251, 225, 209, 0) 60%),
  var(--paper); }
.section--tint-b { background:
  radial-gradient(120% 80% at 50% 100%, rgba(251, 225, 209, 0.26) 0%, rgba(251, 225, 209, 0) 60%),
  var(--paper); }

/* ===== 20-components.css ===== */
/* ————————————————————————————————————————————————
   The gradient wash. Original composition in the brand's warm family — four
   soft radial blooms over paper. Sections opt in with .has-wash.
   ———————————————————————————————————————————————— */
.has-wash { position: relative; isolation: isolate; }
.has-wash > .wash {
  position: absolute; inset: -10% -5% 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(58% 44% at 74% 30%, var(--wash-1) 0%, rgba(255, 217, 194, 0) 62%),
    radial-gradient(46% 38% at 22% 46%, var(--wash-3) 0%, rgba(240, 226, 242, 0) 66%),
    radial-gradient(52% 40% at 46% 72%, var(--wash-2) 0%, rgba(255, 233, 214, 0) 68%),
    radial-gradient(40% 34% at 90% 74%, var(--wash-4) 0%, rgba(223, 230, 245, 0) 70%);
  filter: blur(8px) saturate(112%);
}
/* Fade the wash into paper at the seam so sections never end on a hard edge. */
.has-wash > .wash::after {
  content: ''; position: absolute; inset-inline: 0; bottom: 0; height: 200px;
  background: linear-gradient(to top, var(--paper), rgba(255, 255, 255, 0));
}

/* ————————————————————————————————————————————————
   Pills. Filled and ghost share geometry so they sit as a matched pair.
   ———————————————————————————————————————————————— */
.pill, .ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 48px; padding-inline: 26px; border-radius: var(--r-pill);
  font-size: 16px; font-weight: 450; letter-spacing: -0.005em;
  white-space: nowrap; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.pill { background: var(--ink); color: var(--paper); border: 1px solid var(--ink); }
.pill:hover { background: #2b2e33; border-color: #2b2e33; }
.ghost { background: transparent; color: var(--ink); border: 1px solid var(--ink); }
.ghost:hover { background: var(--ink); color: var(--paper); }
.pill:active, .ghost:active { transform: translateY(1px); }
.pill--sm, .ghost--sm { height: 42px; padding-inline: 20px; font-size: 15px; }

/* Lowest-emphasis link: the arrow carries the affordance, not an underline. */
.alink {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 16px; font-weight: 450; color: var(--ink);
}
.alink svg { transition: transform var(--dur) var(--ease-out); }
.alink:hover svg { transform: translateX(4px); }
.alink:hover span { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }

/* ————————————————————————————————————————————————
   Surfaces
   ———————————————————————————————————————————————— */
/*
 * ONE CARD, TWO VARIANTS — and nothing else. The card is the most repeated
 * object on the site, and it had drifted into six grounds doing the same job:
 * mist, white-with-a-hairline, transparent-with-a-hairline, white-no-border,
 * white-with-a-top-only-radius and white-on-a-heavier-hairline. Two of them
 * shipped on ONE page, three sections apart, on the same six-card isometric
 * grid. Sections must not restate background, border, radius or padding here.
 *
 *   .card         mist, no border — the default, and what a grid of drawings
 *                 sits on, on paper and on fog alike.
 *   .card--paper  white and a hairline — reserved for the one case mist cannot
 *                 do: a card that has to lift off a filled ground. It is down
 *                 to a single user (customers-more); nothing else may take it,
 *                 and no section may invent a third.
 */
/* --illo-ground is the surface a drawing's occlusion silhouette is painted in.
   It is declared beside the background it has to match, so the two can never
   drift apart; see the illustration block below. */
.card { background: var(--mist); --illo-ground: var(--mist); border-radius: var(--r-card); padding: var(--s32); }
.card--paper { background: var(--raised); --illo-ground: var(--raised); border: 1px solid var(--hair); }
.card__title { font-size: var(--t-body-lg); font-weight: 500; letter-spacing: -0.01em; margin-bottom: 10px; }
/*
 * The ONE permitted louder card title, for the lead of a grid. Same family and
 * same weight as its siblings — a lead that changes typeface puts two families
 * at one rank inside a single grid, which is what three sections were doing.
 */
.card__title--lead { font-size: var(--t-h-sm); letter-spacing: var(--tr-h-sm); line-height: 1.22; }
.card__body { font-size: 16px; line-height: 1.55; color: var(--slate); }

/* Rationed to one per page. Warm ink on warm paper — never on a tinted section. */
.card--peach { background: var(--peach); color: var(--sienna); --illo-ground: var(--peach); }
.card--peach .card__title, .card--peach .card__body, .card--peach p { color: var(--sienna); }

/* The only elements with visible elevation. */
.artifact {
  background: var(--raised); border-radius: var(--r-elevated); box-shadow: var(--sh-artifact);
}

.rule { height: 1px; background: var(--hair); border: 0; margin: 0; }

/* ————————————————————————————————————————————————
   Nav
   ———————————————————————————————————————————————— */
.nav {
  position: sticky; top: 0; z-index: 100; height: 76px; display: flex; align-items: center;
  transition: background var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
              backdrop-filter var(--dur) var(--ease-out);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--hair);
}
/*
 * NO `width: 100%` HERE. .nav__inner also carries .wrap, and an equal-specificity
 * `width` declared later overrides the 1200px column .wrap exists to set — which
 * pushed the logo and the CTA hard against the viewport edges and left the nav
 * links misaligned against every other element on the page. Most visible on wide
 * displays, but it was wrong at every width.
 */
.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.nav__logo { display: inline-flex; align-items: center; gap: 9px; flex: 0 0 auto; white-space: nowrap;
             font-family: var(--serif); font-size: 21px; letter-spacing: -0.015em; }
.nav__logo em { font-style: italic; }
.nav__links { display: flex; align-items: center; gap: 34px; }
.nav__links a { font-size: 16px; font-weight: 400; color: var(--ink); position: relative; padding-block: 4px; }
.nav__links a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--ink); transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur) var(--ease-out);
}
.nav__links a:hover::after, .nav__links a.is-active::after { transform: scaleX(1); }
.nav__cta { display: flex; align-items: center; gap: 22px; }
/* A text link in the nav is still a tap target: it was 21px tall, under the 24px
   floor and well under the 44px comfortable size on touch. */
.nav__cta .alink { min-height: 44px; }
.nav__burger { display: none; width: 44px; height: 44px; align-items: center; justify-content: center;
               background: none; border: 0; cursor: pointer; margin-right: -10px; }

@media (max-width: 940px) {
  .nav__links, .nav__cta .alink, .nav__cta .ghost { display: none; }
  .nav__burger { display: inline-flex; }
}
@media (max-width: 360px) {
  .nav__cta > .pill { display: none; }
}

.navdrawer {
  position: fixed; inset: 0; z-index: 200; background: var(--paper);
  display: flex; flex-direction: column; padding: 20px var(--gutter) 40px;
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out), visibility var(--dur);
}
.navdrawer.is-open { opacity: 1; visibility: visible; transform: none; }
.navdrawer__top { display: flex; align-items: center; justify-content: space-between; height: 56px; }
.navdrawer__links { display: flex; flex-direction: column; gap: 4px; margin-top: 32px; }
.navdrawer__links a { font-family: var(--serif); font-size: 34px; line-height: 1.5; letter-spacing: -0.015em; }
.navdrawer__foot { margin-top: auto; display: flex; flex-direction: column; gap: 12px; }
.navdrawer__foot .pill, .navdrawer__foot .ghost { width: 100%; }

/* ————————————————————————————————————————————————
   Footer
   ———————————————————————————————————————————————— */
.footer { border-top: 1px solid var(--hair); padding-block: 72px 56px; background: var(--paper); }
.footer__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 48px; }
.footer__brand p { margin-top: 14px; max-width: 260px; font-size: 15px; line-height: 1.55; color: var(--slate); }
.footer__col .footer__coltitle { font-size: 14px; font-weight: 450; color: var(--ash); margin-bottom: 18px; }
.footer__col a { display: block; font-size: 15px; line-height: 1; padding-block: 9px; color: var(--ink); }
.footer__col a:hover { color: var(--slate); }
.footer__base { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
                margin-top: 64px; padding-top: 28px; border-top: 1px solid var(--hair);
                font-size: 14px; color: var(--ash); }
@media (max-width: 860px) {
  .footer__grid { grid-template-columns: 1fr 1fr; gap: 40px 24px; }
  .footer__brand { grid-column: 1 / -1; }
}

/* ————————————————————————————————————————————————
   THE ILLUSTRATION SYSTEM
   Every drawing on the site must obey these, or the page reads as clip-art
   assembled by six different people — which is exactly what reviewers found:
   "five different conventions" across six cards in one section.
   ———————————————————————————————————————————————— */
.illo {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  color: var(--ink);
  /* Strokes must survive the warm ground. A floor plan drawn at low contrast was
     measured as "effectively does not exist" — opacity belongs on the wrapper,
     never on individual strokes. */
  opacity: 0.78;
}
.illo--quiet { opacity: 0.52; }
.card--peach .illo,
.illo--sienna { color: var(--sienna); }
.illo--invert { color: var(--raised); }

/* One stroke weight for the whole site. Anything thinner disappears on paper;
   anything heavier reads as an icon rather than a drawing. */
.illo [stroke],
.illo path, .illo line, .illo circle, .illo rect, .illo ellipse, .illo polyline, .illo polygon {
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
  vector-effect: non-scaling-stroke;   /* weight stays 1.4 at any scale */
}
/* The single permitted fill: a solid accent mark, used sparingly for emphasis. */
.illo .illo-fill { fill: currentColor; stroke: none; }
/* Construction lines — hidden faces, guides — sit back without changing weight. */
.illo .illo-back { opacity: 0.34; }

/* ————————————————————————————————————————————————
   HIDDEN-LINE REMOVAL — and it lives HERE, not in a section file.

   ILLUSTRATION.md item 5 makes occlusion mandatory: where one object sits in
   front of another, the object behind must BREAK, or the drawing is an x-ray.
   The tool that does it is an opaque silhouette painted in whatever surface the
   drawing stands on, laid down immediately before the object it belongs to.

   It used to be declared locally, in two section files out of thirteen, and
   that is most of why eleven sections carried no occlusion at all: an author
   who copied class="illo-mask" anywhere else got `fill: none` from the generic
   rule above and the drawing silently rendered as an x-ray. No error, no
   missing style — just a worse drawing. Declared globally, the class works
   wherever it is written.

   The surface comes from --illo-ground, set once per card beside its own
   background (.card / .card--paper / .card--peach above). A drawing standing on
   bare paper needs to set nothing; the fallback is the page.
   ———————————————————————————————————————————————— */
.illo .illo-mask { fill: var(--illo-ground, var(--paper)); stroke: none; }

/* ————————————————————————————————————————————————
   TWO SIZES, AND NO THIRD.

   Measured across the site, .illo boxes ran from 45px to 1102px — a 24x range
   under one class, which makes the class mean nothing, and inside a grid of
   peers makes size read as importance (ILLUSTRATION.md items 3 and 7).
   A drawing is now either a card mark or a section's feature. Both are
   CEILINGS paired with width:100%, so a narrow column shrinks its drawing
   instead of earning a size of its own.
   ———————————————————————————————————————————————— */
.illo--card { width: 100%; max-width: var(--illo-card); }
.illo--feature { width: 100%; max-width: var(--illo-feature); }

/* ————————————————————————————————————————————————
   BLEED STAGE — for absolutely-positioned decoration around a content column.
   `position:absolute; inset:0` on a full-bleed section anchors children to the
   VIEWPORT, so on a wide display the floating cards fly out to the edges and
   lose all relationship to the headline they are meant to frame. This bounds the
   layer to the content column plus a fixed bleed, centred, so the composition
   holds at any width and only ever crops by --bleed.
   ———————————————————————————————————————————————— */
.stage {
  position: absolute;
  top: 0; bottom: 0; left: 0; right: 0;
  width: min(100%, calc(var(--page) + var(--bleed, 240px) * 2));
  margin-inline: auto;
  pointer-events: none;
}

/* ===== 30-motion.css ===== */
/*
 * Motion primitives. Everything is opt-in via a data attribute so a section
 * author never writes keyframes — and everything collapses to "already visible"
 * under prefers-reduced-motion, which is the accessible default, not an afterthought.
 */
[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* Headline reveal: lines rise from a clipped baseline, staggered. */
[data-reveal-lines] .line-mask { display: block; overflow: hidden; }
[data-reveal-lines] .line-mask > span {
  display: block;
  transform: translateY(105%);
  transition: transform 900ms var(--ease-out);
  transition-delay: var(--line-delay, 0ms);
}
[data-reveal-lines].is-in .line-mask > span { transform: none; }

/* Floating artifacts drift in from their resting offset. */
[data-float] {
  opacity: 0;
  transform: translate3d(var(--float-x, 0), var(--float-y, 26px), 0) scale(0.985);
  transition: opacity 1000ms var(--ease-out), transform 1000ms var(--ease-out);
  transition-delay: var(--float-delay, 0ms);
}
[data-float].is-in { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }

/* Idle bob for hero artifacts, once they have landed. */
@keyframes lp-bob {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -7px, 0); }
}
[data-float].is-in[data-bob] {
  animation: lp-bob var(--bob-dur, 7s) var(--ease-in-out) infinite;
  animation-delay: var(--bob-delay, 0s);
}

/* Counters and bars */
[data-count] { font-variant-numeric: tabular-nums; }
[data-bar] { transform: scaleX(0); transform-origin: left; transition: transform 1100ms var(--ease-out); }
[data-bar].is-in { transform: scaleX(1); }

/* Drawn SVG strokes */
[data-draw] {
  stroke-dasharray: var(--len, 1000);
  stroke-dashoffset: var(--len, 1000);
  transition: stroke-dashoffset 1600ms var(--ease-out);
}
[data-draw].is-in { stroke-dashoffset: 0; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-float], [data-bar], [data-draw],
  [data-reveal-lines] .line-mask > span {
    opacity: 1 !important;
    transform: none !important;
    stroke-dashoffset: 0 !important;
    transition: none !important;
    animation: none !important;
  }
}

/* ===== section:solutions-hero ===== */
/* ===========================================================================
   solutions-hero — the Solutions page opening.

   THE BRIEF asked for very little: a left-set hero on the wash, one headline,
   one paragraph, no buttons, "the value is in the grid below". So the section
   is built out of four marks and nothing else, and the composition has to come
   from where those four marks sit rather than from anything added to them.

   THE ONE IDEA: THE GAP BETWEEN THE SIX AND THE ONE.
   Line one of the headline stands on the text rail. Line two is set flush RIGHT
   to the page measure. Measured at 1440, line one ends at x=644 inside a measure
   that runs 120–1320, and line two starts at x=1005: 361px of bare wash — 30% of
   the measure — opens on the diagonal between them. That void is the sentence,
   six shapes over there and one system over here, and it is the only reason this
   hero is not a stack of three left-aligned blocks.

   And the void only works if the far end of it is worth arriving at, which is
   why the wash is re-pointed below rather than left as the page-level default.
   A void that delivers the eye onto flat ground is just a hole.

   WHY FLUSH TO THE MEASURE AND NOT TO LINE ONE'S RAG. Aligning line two's right
   edge to line one's right edge would be prettier on the day it was measured and
   meaningless the moment Source Serif fails to load and Iowan or Georgia sets
   the line 4% wider. The measure is a structural edge that every other section
   on the site also uses, so the relationship holds under any fallback.

   HOW IT DIFFERS FROM THE OTHER PAGE HERO. product-hero is a WEDGE — headline
   wide, lede held short beneath it, one floating artifact on the right, a rule
   that bleeds in from the left and is absorbed by the card. This one is a STEP:
   no artifact, no card, no shadow, ink pushed to the far right and then brought
   back, and the rule runs the other way — hard on the rail, off the right of the
   frame. Same hand, opposite gesture, so the two pages do not open identically.

   WHAT THE INDEX RULE IS FOR, honestly stated. It is a hairline carrying six
   marks: one line, six divisions, which is the headline drawn as structure. It
   is also load-bearing compositionally — it is the only ink under the right half
   of the frame, and without it "One system." hangs off the margin with nothing
   below it and the section goes lopsided rather than asymmetric. The figures
   enumerate a count the headline already states, so they invent no datum and
   there is no chart-honesty question here; the strip is decorative and
   aria-hidden, since six loose numbers read as noise to a screen reader.

   (It also lands as a contents strip: the grid immediately below numbers its six
   cards 01–06 in the same small tabular figures. That is a section this file
   does not own, so the rule above does not lean on it — the structural argument
   stands on its own if that numbering ever goes away.)

   Everything is scoped under .sec-solutions-hero.
   =========================================================================== */

.sec-solutions-hero {
  /* Both ends of the stage come from the shared hero rule in 10-base.css.
     This file used to set a 116px foot of its own. */

  /* CLIP THE X AXIS ONLY. `.has-wash > .wash` is inset -5% on both flanks and
     the index rule deliberately runs 40px past the right of the frame; both
     count toward document scrollWidth even under the root's overflow-x: clip,
     and an unclipped section here measured a horizontal scrollbar into every
     capture. Y stays visible so nothing gets guillotined at the seam. */
  overflow-x: clip;
  overflow-y: visible;
}

/* — THE GROUND, WHICH WAS THE THING THIS SECTION HAD WRONG ————————
 *
 * The shared four-bloom wash is a page-level texture: it knows nothing about
 * where a given section puts its ink, and here that produced a composition with
 * two focal points fighting each other. Sampled from the raster, the frame's two
 * most saturated grounds were the bloom at `74% 30%` — which resolves to roughly
 * (1100, 97) in this section's box, i.e. the EMPTY top-right corner — and the
 * bloom at `46% 72%`, which sits in the dead band between the lede and the index
 * rule and props up nothing at all. Every mark of type, including the italic the
 * whole layout is built to deliver the eye to, sat on flat ground. The void was
 * doing its job and handing the eye to the flattest part of the frame.
 *
 * So the wash is re-registered to THIS section's ink, scoped here and nowhere
 * else. Two blooms, not four:
 *
 *   1. THE PAYOFF. Measured, the italic's box runs x 1005–1327 / y 226–325 at
 *      1440 (viewport coords; the section's own top is at -76). The wash is
 *      inset -10% top and -5% on the flanks, so it measures 1584 x 848 against a
 *      1440 x 771 section, and `at 78% 50%` puts the bloom's core at (1164, 271)
 *      — on the italic's ink, within three pixels of its optical centre. Those
 *      two numbers are that arithmetic, not a guess. The stop holds full
 *      --wash-1 out to 16% before it starts falling, so the italic sits ON the
 *      plateau rather than on a shoulder. The ellipse is wide enough (45% of
 *      1584 = 713px of radius) that its falloff reaches back past line one's rag
 *      at x=644, so the warm diagonal runs down the same path the eye does.
 *
 *   2. THE LEFT COLUMN, at a deliberately lower chroma: --wash-2 is the palest
 *      of the four tints, and it is centred under the lede rather than under the
 *      headline. It gives the left half a ground without ever threatening to be
 *      the brightest thing in the frame, which is the whole point.
 *
 * The two cool tints are dropped here. They earn their place on a hero with an
 * artifact to sit behind; on a section made of four typographic marks they are
 * two more things competing for a focal point that is already spoken for.
 *
 * The zero-alpha end stops are spelled out as rgba() of the same tint rather
 * than `transparent`, which is what 20-components.css does and for the same
 * reason: `transparent` is rgba(0,0,0,0), so interpolating to it drags the ramp
 * through grey and leaves a dirty edge on a warm bloom.
 */
.sec-solutions-hero > .wash {
  background:
    radial-gradient(38% 40% at 78% 51%,
      var(--wash-1) 0%, var(--wash-1) 7%, rgba(255, 217, 194, 0) 66%),
    radial-gradient(42% 40% at 10% 66%,
      var(--wash-2) 0%, rgba(255, 233, 214, 0) 74%);
}

/* — The chapter mark ————————————————————————————————
   Deliberately plain. product-hero's eyebrow leads with a drawn hairline; that
   move belongs to that page and repeating it here would make the two openings
   read as the same template rather than the same hand. */

/* — The headline ————————————————————————————————————— */
.sec-solutions-hero .sh-title {
  /*
   * NO SIZE HERE. --t-h-lg, from the class, like the other five page openers.
   * This used to set 72px "because a page opener is not a section heading" —
   * true, and the ramp already says so: .h-lg IS the page title and .h is the
   * section headline. Setting 72 only made this one page title a size nothing
   * else on the site uses, so six inner heroes rendered at four different
   * sizes.
   */

  /*
   * THE DESCENDER CLEARANCE, WHICH IS ARITHMETIC AND WAS NEARLY WRONG.
   *
   * The line masks clip to the LINE BOX, and both lines carry descenders — two
   * p's in "shapes of shop.", the y in "system". Source Serif's content area at
   * 64px measures 87px against a 74.23px line box at the stock 1.16, so the box
   * is 12.8px SHORTER than the glyphs it holds and the overhang is split evenly
   * top and bottom. Sampled from the raster, the p's ink ended at y=216.50 with
   * the mask clipping at 217.13: six tenths of a pixel of clearance, i.e. the
   * descenders were surviving by accident. A Georgia fallback lands in the same
   * place from the other direction (shallower ink, but a shorter content area,
   * so 1.4px).
   *
   * Fixed in two parts because leading alone is an expensive way to buy
   * clearance — it pays at the top of the line as well, where nothing is at
   * risk. 1.2 buys 1.3px; the masks then take 0.045em of padding-bottom for the
   * rest, which extends the CLIP box without moving the type. Both numbers are
   * in em, so the fix survived the move to 72px without being re-derived:
   * re-sampled from the raster at 72, line one's ink bottom is 229 against a
   * clip at 232.5 and line two's is 319 against 322.2 — 3.5px and 3.2px, up
   * from 0.6px.
   *
   * The padding has a ceiling: the hidden state translates the inner span by
   * 105% of the line box, so any padding over 5% of the line-height would leave
   * a sliver of the next line showing before the reveal fires. 0.045em against a
   * 1.2 line box is 3.75%, and being in em it stays 3.75% at 64px, 48px and the
   * fluid mobile size alike — a fixed 3px would have broken that ceiling at the
   * mobile size, which is exactly where nobody would have looked for it.
   */
  line-height: 1.2;
  /* The cap-stem sidebearing correction is the shared one in 10-base.css; this
     file used to hold a -0.02em copy of it. */
}
.sec-solutions-hero .sh-l1,
.sec-solutions-hero .sh-l2 { padding-bottom: 0.045em; }   /* see the note above */

.sec-solutions-hero .sh-l2 {
  /* The excursion. Flush to the page measure, not to line one's rag. */
  text-align: right;

  /*
   * OPTICAL FLUSH, MEASURED AGAINST THE TICK IT HAS TO MEET.
   * Layout-flush is not visually flush: the italic full stop carries a right
   * sidebearing, and sampling the raster put its last ink column five pixels
   * short of the closing tick that occupies x=1319–1320 — the one alignment the
   * right-hand side of this section owns. A negative margin walks the ink onto
   * the tick's own column; in em it holds the same relationship at every size,
   * since the sidebearing scales too. -0.1em was correct at 64px and left the
   * ink at x=1318 once the headline went to 72; -0.115em (8.3px) re-seats it at
   * x=1319, inside the tick's own column. Re-measure this if the size moves
   * again — it is the one value here that is genuinely size-specific.
   *
   * The margin goes on the MASK, not on the <em> inside it. The mask clips its
   * overflow, so a negative margin on the inline would push the period's
   * antialiasing into the clip edge and shave it; on the block it moves the clip
   * box along with the type.
   */
  margin-right: -0.115em;
}
.sec-solutions-hero .sh-title em {
  /* Source Serif's italic sets marginally tighter than its roman; a hair of
     extra tracking keeps the accent from reading as compressed beside line one,
     and it is the only italic in the section. */
  letter-spacing: -0.008em;
}

/* — The lede ————————————————————————————————————————
   Back on the rail. The paragraph returning to the left after the headline's
   excursion is what makes the excursion read as deliberate: the rail is
   re-established immediately underneath it.

   THE MEASURE IS 460, NOT THE BRIEF'S 620 CAP, AND BOTH NUMBERS ARE MEASURED.
   At the 620 cap the paragraph sets as [583, 395] — its long line runs 117px
   PAST the end of "Six shapes of shop." (which ends at x=586 against a text rail
   at 120), so the left column reads as a rectangle with a ragged bite out of it
   and the body copy outruns the display type. At 500–620 it sets as [484, 494],
   which is worse in a different way: the long line lands within 8px of the
   headline's rag, and a near-alignment reads as a miss rather than a decision.
   At 460 the wrapper is forced onto three lines and `balance` evens them to
   [341, 323, 308] — a gentle taper that sits a clear 125px inside the headline,
   so the left column is a wedge, and the extra line gives that column enough
   height to stand against the void the right-hand excursion opens.

   `balance` rather than the inherited `pretty`: pretty only tidies the last
   lines and leaves [393, 433, 147] here, with a 147px orphan. Where balance is
   unsupported the paragraph falls back to exactly that, which is untidy but not
   broken. */
.sec-solutions-hero .sh-sub {
  max-width: 460px;
  margin-top: 34px;
  text-wrap: balance;
}

/* — The index rule ——————————————————————————————————— */
.sec-solutions-hero .sh-index {
  position: relative;
  margin-top: 104px;
}

/*
 * THE RULE. Left end hard on the text rail — it shares an edge with the eyebrow,
 * the headline and the lede, which is what stops it reading as a stray line —
 * and the right end runs 40px past the frame at every width, so it leaves the
 * page rather than stopping at it. (50% resolves against the wrap, 50vw against
 * the viewport, so the overhang is always the gutter plus a constant.)
 *
 * No fade at the right end: a gradient tuned to look right at 1440 was still
 * ramping inside the page measure at 1200, dimming the 06 mark on a line that is
 * supposed to be one continuous weight. A hairline cropped by the frame reads as
 * "continues" on its own; the fade was solving a problem the crop already solved.
 *
 * data-bar draws it left to right on entry — an existing primitive, no keyframes.
 */
.sec-solutions-hero .sh-index__rule {
  position: absolute;
  top: 0;
  left: 0;
  right: calc(50% - 50vw - 40px);
  height: 1px;
  background: var(--hair-strong);
}

.sec-solutions-hero .sh-index__marks {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}
.sec-solutions-hero .sh-index__marks span {
  position: relative;
  padding-top: 19px;
  font-size: 13px;
  line-height: 1;
  color: var(--smoke);
  letter-spacing: 0;
}
/* The mark itself: a 7px tick dropping from the rule, one per division, sitting
   directly above its figure. The first tick lands on the text rail, so the
   figure 01 is the fourth element in the section to start on that same axis. */
.sec-solutions-hero .sh-index__marks span::before,
.sec-solutions-hero .sh-index__marks span:last-child::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 7px;
  background: var(--hair-strong);
}
/*
 * THE SEVENTH TICK, WHICH IS THE ONE THAT DOES THE WORK.
 * Six figures need seven boundaries, so a closing tick is what the scale wants
 * anyway — but the reason it is here is that it lands exactly on the page
 * measure, directly under the last letter of "One system.". Without it the
 * headline's flush-right alignment is to an edge nothing else in the section
 * touches, i.e. an alignment only the stylesheet can see. With it the right side
 * gets the same treatment the left rail gets: two elements on one axis, so the
 * excursion is visibly registered to the page rather than merely pushed over.
 */
.sec-solutions-hero .sh-index__marks span:last-child::after {
  left: auto;
  right: 0;
}

/* ———————————————————————————————————————————————————————————————————
   TABLET.

   The global ramp steps --t-h-lg from 64px to 48px at 1080, and the headline
   steps with it — the per-section ramp that used to hold it between 52 and 72
   through this band is gone, because a page title that is a different size on
   every page is the problem this file was audited for.

   What the band still owes is the LEDE'S MEASURE, tied to the headline's size
   rather than to a constant so the two rags cannot drift into each other. The
   350px floor is measured, not reasoned: at 340 the lede's first sentence
   (341px) misses by a single pixel and balance keeps four lines of about 26
   characters. Ten pixels of floor is the whole difference between three lines
   and a column of confetti.
   ——————————————————————————————————————————————————————————————————— */
@media (max-width: 1080px) {
  /* The lede's measure is tied to the headline's SIZE, so it follows the token
     ramp down instead of a divisor of its own. */
  .sec-solutions-hero .sh-sub { max-width: clamp(350px, calc(var(--t-h-lg) * 6.4), 460px); }
  .sec-solutions-hero .sh-index { margin-top: 88px; }
}

/* THE VERTICAL STEP STARTS BEFORE THE PHONE BREAKPOINT DOES, because the
   horizontal one dies before then. Measured at the tablet ramp: the void between
   line one's rag and the italic runs 361px at 1264, 180px at 900, 94px at 768
   and 47px at 721 — by 768 it is no longer legible as a void, it is a gap. So
   the step turns through ninety degrees at 768 rather than at 720, and from
   there down line two takes 0.34em of extra leading (about 14px on the 52px
   floor) on top of its line box. That is far more than any leading accident and
   reads as what it is: a deliberate break before the payoff. The margin sits on
   the mask, which is outside the clip box, so the reveal transform is untouched.
   The full argument, and the measurement that killed the old claim, is in the
   mobile block below. */
@media (max-width: 768px) {
  .sec-solutions-hero .sh-l2 { margin-top: 0.34em; }
}

/* ===========================================================================
   MOBILE — the step has to survive, or the section has no idea left in it.

   The failure to avoid is the usual one: inheriting --t-h-lg at 34px puts the
   headline within 1.9x of the 18px lede, which is the point at which display
   type stops being a focal point and becomes a label, and it also shrinks line
   one so far that flush-right line two lands almost underneath it and the gap —
   the section's entire argument — closes to nothing.

   So the headline is sized to the column instead of to the breakpoint. The
   binding line is "Six shapes of shop.", and at the sizes that matter here it
   sets at a measured 7.70px of advance per px of font-size (311.9px at 40.51px,
   sampled from the rendered range, not estimated — and note the ratio is not a
   constant across the ramp: optical sizing widens the small masters, so the same
   line is 7.46 at 52px and 7.30 at 64px, and a formula derived at one size must
   not be reused at another). Fitting it inside the column — 100vw less 40px of
   gutter — gives F <= 0.122 * vw - 6px, capped at 52px so it stops climbing once
   there is room and so nothing steps as the 720px breakpoint is crossed (the
   tablet band floors at the same 52).

   THE 31px OF SLACK THAT FORMULA LEAVES AT 390 IS THE POINT, NOT WASTE. Line one
   measures 319px in a 350px column; Source Serif is the narrowest thing that can
   set it, and Georgia — the fallback most likely to be doing the work on a phone
   with a cold cache — sets 6–8% wider, which is 344px. It still fits on one
   line. Tightening the formula to fill the column would put the fallback at two
   lines and collapse the step into a stack.

   At 390 that is 41.6px against an 18px lede — 2.31x, back above the ramp floor.

   THE STEP CANNOT BE HORIZONTAL HERE, AND THIS FILE USED TO CLAIM IT WAS.
   The earlier note asserted mobile opened "the same gesture" as the desktop.
   Measured, it did not: line one ends at x=318 and flush-right line two starts
   at x=159, so the two lines OVERLAP across 159px of the column and there is no
   void at all — the desktop opens its step at 77% of the measure, mobile at
   -45%. It read as an ordinary right-ragged headline, which is to say as an
   accident. "One system." is 191px wide in a 350px column; no amount of tuning
   makes a horizontal gap fit, because the two lines together are wider than the
   column.

   So the step is turned through ninety degrees, in the 768px block above. Line
   two keeps its flush-right alignment — that is what registers it to the same
   structural edge the closing tick sits on — but takes 0.34em of extra leading
   above it, roughly 14px on top of the 50px line box, so the break reads
   vertically: six shapes ABOVE, one system BELOW. Same argument, on the axis the
   column can actually afford.

   The lede is tied to the same number (8x the headline size) rather than to a
   fixed measure. At 390 that lands at 333px — the column, effectively — and at
   720 it holds the paragraph to 416px instead of letting it run the full 680px
   column at ~80 characters a line. One rule, correct at both ends. Below about
   370px of viewport the column itself forces a fourth line on the lede; that is
   the column's arithmetic, not a decision, and the step still measures.
   =========================================================================== */
@media (max-width: 720px) {
  .sec-solutions-hero {
  }
  /*
   * THE GROUND, RE-POINTED FOR THE PHONE. The desktop percentages are arithmetic
   * against a 1584 x 848 wash box; at 390 the box is 429 x 630 and the italic
   * has moved to the middle of the column, so the same numbers put the core at
   * x=317 against an italic centred on x=278 — half the bloom hanging off the
   * right edge, measured, not guessed. 69% lands it back on the ink. The ellipse
   * is also flattened (48% x 24% rather than 38% x 40%): a two-line column is
   * wide and short, and a tall bloom on it fills the frame instead of marking a
   * spot.
   */
  .sec-solutions-hero > .wash {
    background:
      radial-gradient(48% 24% at 69% 51%,
        var(--wash-1) 0%, var(--wash-1) 6%, rgba(255, 217, 194, 0) 68%),
      radial-gradient(56% 24% at 20% 70%,
        var(--wash-2) 0%, rgba(255, 233, 214, 0) 76%);
  }

  .sec-solutions-hero .sh-sub {
    margin-top: 26px;
    max-width: calc(var(--t-h-lg) * 8);
  }

  .sec-solutions-hero .sh-index { margin-top: 64px; }
  .sec-solutions-hero .sh-index__marks span {
    padding-top: 16px;
    font-size: 12px;
  }
  .sec-solutions-hero .sh-index__marks span::before { height: 6px; }
}

/* ===== section:solutions-shapes ===== */
/* ————————————————————————————————————————————————————————————————
   solutions-shapes — the six venue shapes.

   The hero directly above carries the headline, so this section has no header
   of its own. It is a bed of six cards hung off ONE hairline datum, and the
   composition is one asymmetry run twice:

     row one   1.28fr 1fr 1fr, bottom-aligned. The lead is 28% WIDER, 86px
               TALLER and peach, and it rises through the datum. All six carry
               the same three parts in the same order — title at the top,
               drawing in the middle, copy at the bottom — so the stagger is
               real height rather than a card that had something taken away.
     row two   mirrored — 1fr 1fr 1.28fr, tops on one hard edge, with the wide
               tail hanging 64px below it.

   So the two big cards sit on the diagonal (top-left, bottom-right) and the
   four small ones hold the rails.

   THE TYPE STEP IS THE POINT OF THIS REVISION. The section shipped with
   `.card__title` at --t-body-lg (20px) over 19px body copy — a 1.05x step, so
   five of six cards had no hierarchy at all and the two-line body paragraph
   was the heaviest mass in its own card. Worse, every paragraph was --sienna,
   which spent the page's one warm accent on all six cards at once. It now
   runs 64 / 44 / 34 / 26 / 16, and the warmth is back to the peach card alone.
   ———————————————————————————————————————————————————————————————— */

.sec-solutions-shapes {
  position: relative;
  isolation: isolate;

  /* One set of numbers drives the whole bed. */
  --sh-lead-h: 510px;   /* the peach lead */
  --sh-row1-h: 424px;   /* its two rowmates */
  --sh-row2-h: 410px;   /* the hard edge row two sits on */
  --sh-tail-drop: 64px; /* how far the tail hangs below it */
  --sh-rise: 40px;      /* how far the lead climbs above the datum */
  /* The card's top pad, named because the index figure hangs off it and the
     tail card changes it. */
  --sh-pt: var(--s32);
}

/* ---- the datum -------------------------------------------------------
   Full-bleed, and the only non-card ink in the section: one line for the peach
   lead to rise through. There was a matching line under the bed for the tail
   card to cross; the cards covered ~85% of it and it read as two gutter
   slivers, so the gesture never landed. Deleted — the tail's drop is the
   signal. The 13px "01 — 06" register that stopped this line at the right went
   too: the hero above rules a line and ticks it 01 to 06, and the cards below
   now carry their own figures at 44px, so it was the third numeric system on
   one screen and the smallest. */
.sec-solutions-shapes .sh-datum {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--section-y);
  height: 0;
  z-index: 0;
}
.sec-solutions-shapes .sh-datum::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: var(--hair-strong);
}
/* ---- the bed --------------------------------------------------------- */
.sec-solutions-shapes .sh-grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 30px;
  /* Pull the whole bed up so the lead starts ABOVE the datum and the line
     passes behind it. */
  margin-top: calc(var(--sh-rise) * -1);
}

.sec-solutions-shapes .sh-row {
  display: grid;
  gap: 26px;
}
/* Bottoms on one line; the extra height is all taken at the TOP by the lead. */
.sec-solutions-shapes .sh-row--one {
  grid-template-columns: 1.28fr 1fr 1fr;
  align-items: end;
}
/* Tops on one line, so only the tail hangs. */
.sec-solutions-shapes .sh-row--two {
  grid-template-columns: 1fr 1fr 1.28fr;
  align-items: start;
}

/* ---- the card --------------------------------------------------------
   Every height is one inherited custom property, so a breakpoint retunes the
   NUMBERS on the section and never has to out-specify these rules. */
.sec-solutions-shapes .sh-card {
  position: relative;
  display: flex;
  flex-direction: column;
  --card-h: var(--sh-row1-h);
  min-height: var(--card-h);
}
.sec-solutions-shapes .sh-row--two > .sh-card { --card-h: var(--sh-row2-h); }
.sec-solutions-shapes .sh-card--lead { --card-h: var(--sh-lead-h); }
/* The tail is taller by the drop — and it SPENDS that height above its title,
   not in the band between drawing and copy. It used to pay the whole 64px out
   of one dead gap (~90px there against ~25px on card 02), which is the same
   "slid rather than placed" failure a previous revision was rejected for. */
.sec-solutions-shapes .sh-row--two > .sh-card--tail {
  --card-h: calc(var(--sh-row2-h) + var(--sh-tail-drop));
  /*
   * The extra height is spent BELOW the title, not above it. Paying it out as top
   * padding pushed this title 42px off its two rowmates — far enough to read as a
   * misalignment, not far enough to read as a deliberate offset. The card stays
   * taller; the titles share one baseline across the row.
   */
}
.sec-solutions-shapes .sh-card { padding-top: var(--sh-pt); }

/* ---- the index, as the section's display moment ----------------------
   The loudest type here was 26px inside a scale that runs to 90, and the six
   cards read as one flat plain. The figure is the only element that can carry
   a display size without inventing copy: serif at --t-h, weight 400, tabular
   and pale, sitting on the title's own baseline at the right end of the card's
   top rail. --smoke is a LARGE-type-only grey and this is 44px, which is
   exactly what it is for.

   It sat at the BOTTOM right for one revision, level with the last line of
   copy, which cost the paragraph 62px of measure on every narrow card and
   broke two-line sentences into three short ones. The 14px lift is the
   difference between a 44px serif baseline and a 26px sans one. */
.sec-solutions-shapes .sh-card__n {
  position: absolute;
  right: 30px;
  top: calc(var(--sh-pt) - 14px);
  font-family: var(--serif);
  font-size: var(--t-h);
  font-weight: 400;
  line-height: 1;
  letter-spacing: var(--tr-h);
  color: var(--smoke);
}
/* The lead's figure takes the one step up the ramp its card takes everywhere
   else — wider, taller, warm — so the section has a single display moment
   instead of six equal ones. Nothing else on the page is louder than 64px
   here, which is the point: the loudest mark used to be a 26px card title. */
.sec-solutions-shapes .sh-card--lead .sh-card__n {
  font-size: var(--t-h-lg);
  letter-spacing: var(--tr-h-lg);
  color: var(--sienna);
  opacity: 0.34;
}

/* ---- title -----------------------------------------------------------
   Family and weight stay `.card__title`'s — an earlier revision set six titles
   at Inter 450 against the site's 500 and its lead at a serif scale, which put
   two families at one rank inside one grid. SIZE is this file's business and
   has to be: the component's --t-body-lg (20px) against body copy leaves a
   1.05x step, and a card whose paragraph outweighs its heading has no
   hierarchy to read. 26 over 16 is 1.63x; the lead takes one step past its
   siblings, derived off the same token so it re-ramps at every breakpoint. */
.sec-solutions-shapes .sh-card__title {
  font-size: var(--t-h-sm);
  letter-spacing: -0.018em;
  line-height: 1.16;
  margin-bottom: 0;
  padding-right: 54px;   /* the figure's column */
  text-wrap: balance;
}
.sec-solutions-shapes .sh-card--lead .sh-card__title {
  font-size: calc(var(--t-h-sm) + 8px);
  letter-spacing: -0.022em;
  line-height: 1.1;
  padding-right: 88px;   /* its figure is 64px, so its column is wider */
}
.sec-solutions-shapes .sh-card--lead .sh-card__n { top: calc(var(--sh-pt) - 22px); }

/* ---- the drawing box -------------------------------------------------
   SIZE IS NOT RANK. These six used to draw at 252, 400 and 332px inside one
   grid — a 1.6x spread that says card 01 is a more important venue shape than
   card 04. All six sit on the one card ceiling (`.illo--card`).

   What DOES vary, and what was missing, is composition. Every drawing was
   planted dead-centre in an identical three-part frame, so six well-made
   isometric objects read as one icon sheet.

   Each drawing is now ANCHORED to a corner of its own band — tucked under the
   title on the right, or dropped onto the copy on the left — and crops into
   the card's padding on the side it is anchored to. That is what separates
   this from the failure a previous revision was rejected for, where the tail's
   drawing floated CENTRED in an oversized band with a ~90px dead gap under it:
   an anchored drawing has its air on one side, all of it, deliberately. The
   bleed never exceeds 26px of a 32px pad, so no card edge can amputate a
   drawing. */
.sec-solutions-shapes .sh-card__art {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 150px;
  margin-block: 20px 0;
}

/* 01 — dropped low and hard against the left pad, so the peach card runs the
   diagonal its 64px figure opens at the top right. */
.sec-solutions-shapes .sh-card--lead .sh-card__art {
  align-items: flex-end;
  justify-content: flex-start;
  margin-block: 30px 14px;
  margin-left: -26px;
  min-height: 200px;
}
/* 02 — tucked under the title, right rail. */
.sec-solutions-shapes .sh-row--one > .sh-card:nth-child(2) .sh-card__art {
  align-items: flex-start;
  justify-content: flex-end;
  margin-block: 14px 0;
  margin-right: -24px;
}
/* 03 — dropped onto the copy, left rail. */
.sec-solutions-shapes .sh-row--one > .sh-card:nth-child(3) .sh-card__art {
  align-items: flex-end;
  justify-content: flex-start;
  margin-bottom: -6px;
  margin-left: -22px;
}
/* 04 — low, right rail. Its object is mirrored in the markup, so the recession
   runs upper-left here and on 06 against upper-right on 03. */
.sec-solutions-shapes .sh-row--two > .sh-card:nth-child(1) .sh-card__art {
  align-items: flex-end;
  justify-content: flex-end;
  margin-bottom: -6px;
  margin-right: -22px;
}
/* 05 — tucked under the title, left rail. */
.sec-solutions-shapes .sh-row--two > .sh-card:nth-child(2) .sh-card__art {
  align-items: flex-start;
  justify-content: flex-start;
  margin-block: 14px 0;
  margin-left: -20px;
}
/* 06 — the widest card, and the one that crops furthest past its padding
   edge. Centred vertically, because its own drop is doing the vertical work. */
.sec-solutions-shapes .sh-card--tail .sh-card__art {
  justify-content: flex-end;
  margin-right: -26px;
}

/* ---- copy ------------------------------------------------------------
   The component's `.card__body` — 16px, --slate, and recoloured to --sienna
   for free inside `.card--peach`. This file used to set 19px sienna on all
   six, which is one step off the title AND spends the page's rationed warm
   ink six times over. */
.sec-solutions-shapes .sh-card__body {
  margin-top: 20px;
  max-width: 30ch;
  text-wrap: pretty;
}

/* Hidden-line removal is the global `.illo-mask` (20-components.css): the
   silhouette is painted in --illo-ground, which .card sets to mist and
   .card--peach to peach, so the lead needs no rule of its own either. */

/* ---- two up ----------------------------------------------------------
   The rows dissolve (display:contents) and all six cards fall into one
   two-column bed, so the pairing changes rather than the cards squashing.
   The per-card placement above survives it untouched — it is keyed off the
   row, and the rows still exist in the markup. */
@media (max-width: 1080px) {
  .sec-solutions-shapes .sh-grid {
    grid-template-columns: 1fr 1fr;
    gap: 22px;
    align-items: end;
    margin-top: -32px;
  }
  .sec-solutions-shapes .sh-row { display: contents; }

  /* Retuned, not re-specified. The tail keeps a drop, and the third card of
     each row is the taller one, so the two-column bed staggers left/right
     instead of settling into three level bands. */
  .sec-solutions-shapes {
    --sh-lead-h: 438px;
    --sh-row1-h: 374px;
    --sh-row2-h: 374px;
    --sh-tail-drop: 44px;
    --sh-pt: var(--s28);
  }
  .sec-solutions-shapes .sh-card { padding: var(--s28); padding-top: var(--sh-pt); }
  .sec-solutions-shapes .sh-row--one > .sh-card:nth-child(3) { --card-h: 410px; }
  .sec-solutions-shapes .sh-card__n { right: 26px; }
}

/* ---- one up ----------------------------------------------------------
   NOT the desktop grid at one column, and NOT the zig-zag it used to run:
   six same-height boxes whose drawings shifted 40px left or right read as
   failed alignment rather than rhythm, and the right-hand pair crowded the
   padding edge with ~110px of dead space opposite.

   One decisive treatment instead. Text holds the left rail; every drawing is
   pushed to the RIGHT until its edge sits 6px off the card's, so each card is
   one diagonal — title, drawing, copy, figure. The rhythm comes from HEIGHT,
   alternating a compact band against one deep enough to anchor the drawing on
   the copy, which is the same device the full-width bed uses, run in one
   dimension instead of two.

   The bed is capped at a phone measure and centred. One-up runs to 700px, and
   at that width an unbounded column is a 660px card with one 232px drawing in
   its corner — 420px of dead paper, which is the failure this treatment is
   meant to end, not a wider version of the fix. */
@media (max-width: 700px) {
  .sec-solutions-shapes .sh-grid {
    grid-template-columns: 1fr;
    max-width: 392px;
    margin-inline: auto;
    gap: 16px;
    /* The bed drops BELOW the datum here instead of rising through it. At one
       column the cards cover all but ~20px of the line, which is the same two
       stray gutter slivers the closing datum was deleted for; a hairline in
       clear air is worth more than a crossing nobody can see. */
    margin-top: 16px;
  }
  /* Heights go back to the copy; the rhythm is rebuilt below out of the art
     bands instead. */
  .sec-solutions-shapes {
    --sh-lead-h: 0px;
    --sh-row1-h: 0px;
    --sh-row2-h: 0px;
    --sh-tail-drop: 0px;
    --sh-pt: var(--s24);
  }
  .sec-solutions-shapes .sh-card { padding: var(--s24); padding-top: var(--sh-pt); }
  .sec-solutions-shapes .sh-row--one > .sh-card:nth-child(3) { --card-h: 0px; }
  .sec-solutions-shapes .sh-row--two > .sh-card--tail { --sh-pt: var(--s24); }
  .sec-solutions-shapes .sh-card__n { right: 22px; }
  .sec-solutions-shapes .sh-card__title { padding-right: 46px; }

  /* One treatment for all six: centred in its band, run to the right edge. */
  .sec-solutions-shapes .sh-card__art,
  .sec-solutions-shapes .sh-card--lead .sh-card__art,
  .sec-solutions-shapes .sh-card--tail .sh-card__art,
  .sec-solutions-shapes .sh-row--one > .sh-card:nth-child(2) .sh-card__art,
  .sec-solutions-shapes .sh-row--one > .sh-card:nth-child(3) .sh-card__art,
  .sec-solutions-shapes .sh-row--two > .sh-card:nth-child(1) .sh-card__art,
  .sec-solutions-shapes .sh-row--two > .sh-card:nth-child(2) .sh-card__art {
    align-items: center;
    justify-content: flex-end;
    min-height: 0;
    margin: 14px -18px 2px 0;
  }
  /* 03 and 05 take the deep band and drop their drawing onto the copy; 02 and
     04 stay compact under the title. */
  .sec-solutions-shapes .sh-row--one > .sh-card:nth-child(3) .sh-card__art,
  .sec-solutions-shapes .sh-row--two > .sh-card:nth-child(2) .sh-card__art {
    align-items: flex-end;
    min-height: 188px;
    margin-block: 24px 2px;
  }
  /* One ceiling for all six — lowered, never raised — so the bleed reads
     without any drawing changing size relative to its siblings. */
  .sec-solutions-shapes .sh-card__art .illo { max-width: 232px; }
  /* The lead and the tail bracket the stack with a taller band, the same two
     cards that bracket it on the diagonal at full width — so the run has a
     rhythm without any drawing changing size. */
  .sec-solutions-shapes .sh-card--lead .sh-card__art,
  .sec-solutions-shapes .sh-card--tail .sh-card__art {
    margin-block: 20px 8px;
    min-height: 196px;
  }
  .sec-solutions-shapes .sh-card__body {
    margin-top: 14px;
    font-size: 15px;
    max-width: 34ch;
  }
}

/* A title that wraps to two lines must not push its drawing below its rowmates'.
   Reserving two lines keeps every drawing in a row on one horizon. */
.sec-solutions-shapes .sh-card__title { min-height: calc(2 * 1.22em); }
@media (max-width: 720px) { .sec-solutions-shapes .sh-card__title { min-height: 0; } }

/* ===== section:solutions-onboard ===== */
/* ————————————————————————————————————————————————————————————
   solutions-onboard — "Four steps, and we do three of them."

   The section that follows six illustrated cards, so it carries NO drawing on
   purpose: its whole job is to be quiet after a dense grid. Everything it has
   is typographic — one hairline horizon, three small numerals sitting on it,
   and a fourth that is 3.5x their size, in ink, hanging off the line.

   The scale break IS the argument: the step we do differently is the step you
   cannot miss. Nothing else in the band is emphasised, and there is no marker
   anywhere on the axis.
   ———————————————————————————————————————————————————————————— */

.sec-solutions-onboard {
  /* Three equal tracks and one half again as wide. The width is not decorative:
     it is what lets 04's sentence set on a visibly longer measure than the
     three narrow columns beside it. */
  --on-cols: 1fr 1fr 1fr 1.46fr;
  --on-gap: clamp(24px, 2.3vw, 32px);

  --on-n: clamp(32px, 3.05vw, 44px);
  --on-n-key: clamp(100px, 10.4vw, 150px);
  /* Equal air on both sides of every knockout, so the hole a numeral punches in
     the horizon is symmetrical about the glyph. */
  --on-knock: 18px;
  --on-knock-key: 26px;
  /* The caesura. Track 4 is where the argument turns, so its content starts a
     beat late inside its own track — three columns on one rhythm, then a pause,
     then the one we do differently. It is a margin on the step rather than a
     wider gutter because the horizon must stay continuous across it. */
  --on-caesura: clamp(14px, 2.1vw, 34px);

  padding-block: var(--section-y);
}

/* ——— Header ————————————————————————————————————————————————
   Same grid as the band, so the eyebrow lands on the first step's rail and the
   sentence is indented off it. Track 4 stays empty. */
.sec-solutions-onboard .on-head {
  display: grid;
  grid-template-columns: var(--on-cols);
  column-gap: var(--on-gap);
  align-items: start;
}
.sec-solutions-onboard .on-eyebrow {
  grid-column: 1;
  /* Cap-to-cap with the headline beside it, not box-to-box. The label's line box
     carries half-leading above its own capital and the serif carries more above
     its own, so aligning the two BOXES left the label 7px low — visibly
     unregistered against a 44px cap.

     The offset is derived, not typed: the gap between a box top and a cap top
     grows with the type it belongs to, so a fixed em value that registers at
     44px is 1px out at 36px. Solved from two measured pairs (44px needs 3.68px,
     36px needs 2.40px) — it is linear in the headline size, and --t-h is the
     token that carries that size through every breakpoint. */
  padding-top: calc(var(--t-h) * 0.16 - 3.4px);
  /* The header grid owns the spacing under this row. */
  margin-bottom: 0;
}
.sec-solutions-onboard .on-h {
  grid-column: 2 / span 2;
  max-width: 20ch;
  text-wrap: initial;      /* the break is authored, not balanced */
}
/* Italic descenders are taller than the line box the reveal clips to. */
.sec-solutions-onboard .on-h .line-mask { padding-bottom: 0.13em; margin-bottom: -0.13em; }

/* ——— The axis ————————————————————————————————————————————— */
.sec-solutions-onboard .on-band {
  position: relative;
  margin-top: clamp(84px, 8.9vw, 132px);
}

.sec-solutions-onboard .on-rule {
  position: absolute;
  color: var(--hair-strong);
  pointer-events: none;
  z-index: 0;
  /* 10-base.css puts `max-width: 100%` on every svg; the horizontal axis is
     deliberately WIDER than its containing block, so that has to be released
     or the bleed silently collapses to the page measure. */
  max-width: none;
  transition: opacity var(--dur) var(--ease-out);
}
.sec-solutions-onboard .on-rule path {
  stroke: currentColor;
  stroke-width: 1;
  fill: none;
}

/* A horizon: it crosses the whole viewport and is cropped by both edges, so the
   four steps read as four points on something continuous rather than as a
   four-up grid that happens to have a line under it. */
.sec-solutions-onboard .on-rule--h {
  top: 0;
  left: calc(50% - 50vw);
  width: 100vw;
  height: 1px;
}
/* The same line stood up, for the stacked layout. Kept in the layout (opacity,
   not display) at every width so the observer always draws it — a rule revealed
   by a resize after the observer has passed would paint as a missing line.
   The height MUST be stated: `height: auto` on an SVG is intrinsic sizing, not
   top/bottom resolution, so the 1600-unit viewBox made the document 1,260px
   taller than its own content. */
.sec-solutions-onboard .on-rule--v {
  top: -38px;
  /* Trails past the last step the way the horizontal axis runs out past 04. */
  height: calc(100% + 76px);
  left: calc(var(--on-numcol, 76px) / 2);
  width: 1px;
  opacity: 0;
}

/* ——— Steps ———————————————————————————————————————————————— */
.sec-solutions-onboard .on-steps {
  position: relative;
  z-index: 1;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: var(--on-cols);
  column-gap: var(--on-gap);
  align-items: start;
}
.sec-solutions-onboard .on-step { position: relative; }

/* The numeral straddles the axis and breaks it: its own paper ground is the
   hidden-line removal. -0.52em puts the optical centre of the figures — not
   the centre of the line box — on the line. */
.sec-solutions-onboard .on-n {
  display: block;
  width: max-content;
  margin-top: -0.52em;
  padding-inline: var(--on-knock);
  margin-left: calc(var(--on-knock) * -1);
  background: var(--paper);
  font-family: var(--serif);
  font-weight: 400;
  font-size: var(--on-n);
  line-height: 1;
  letter-spacing: -0.022em;
  /* --smoke is the LARGE-type token (>=24px, 3.8:1) and these figures are 44px
     and decorative — the <ol> carries the ordering for assistive tech. Keeping
     them at the body-grade grey closed the tonal gap to 04, which is the only
     thing in the band saying which step is the differentiator. */
  color: var(--smoke);
  /* Optical, not metric: the serif figure carries a left side bearing, so the
     glyph hung ~3px right of the sans title set to the same rail. */
  text-indent: -0.035em;
}

/* The scale event. -0.222em sets the CAP of the figure ON the horizon instead
   of its optical centre, so 04 hangs off the line and falls through the row
   where 01–03 set their titles. -0.185 left the line grazing ~5px of clear
   ground above the figure, which reads as a near miss rather than a join.
   Tracking tightens as the size grows, the way it does everywhere else. */
.sec-solutions-onboard .on-step--key {
  margin-left: var(--on-caesura);
}
.sec-solutions-onboard .on-step--key .on-n {
  font-size: var(--on-n-key);
  margin-top: -0.222em;
  padding-inline: var(--on-knock-key);
  margin-left: calc(var(--on-knock-key) * -1);
  letter-spacing: -0.04em;
  color: var(--ink);
}

/* The measure of the three narrow tracks is what sets this size, not taste:
   "We look at how you work." is 235px at 20px, and track 1 falls to ~220px by
   1120. The clamp keeps every step title on ONE line across the whole desktop
   range — a single title wrapping would drop only its own paragraph and break
   the row of body baselines the band depends on. */
.sec-solutions-onboard .on-step__t {
  margin-top: 32px;
  font-family: var(--sans);
  font-size: clamp(17px, 1.55vw, var(--t-body-lg));
  font-weight: 500;
  line-height: 1.28;
  letter-spacing: -0.012em;
  color: var(--slate);
  text-wrap: pretty;
}
/* The step's own text starts where the numeral lets it, ~90px below the other
   three — the drop is the numeral's, not an arbitrary offset. */
.sec-solutions-onboard .on-step--key .on-step__t {
  margin-top: 26px;
  color: var(--ink);
}

.sec-solutions-onboard .on-step__b {
  margin-top: 11px;
  font-size: 16px;
  line-height: 1.55;
  color: var(--slate);
  max-width: 30ch;
  text-wrap: pretty;
}
/* Wider measure, because the track is wider. */
.sec-solutions-onboard .on-step--key .on-step__b { max-width: 40ch; }

/* ——— Ledger ————————————————————————————————————————————————
   Four narrow tracks stop holding a 20px title and a 30ch paragraph well before
   the phone, so the band stands its axis up instead of squashing the columns.
   Turning at 1120 rather than 1024 is a measured limit: below it, track 1 is
   too narrow to hold "We look at how you work." on a line at any size that is
   still a step title.

   But standing the axis up is not, on its own, a tablet layout. Rotating the
   band and keeping each title stacked over its paragraph put every word inside
   the left 570px of a 1120 canvas and left a 490px column of nothing down the
   right — a void with no composition in it, which is the one kind this site
   does not want. So between the phone and the desktop the step opens out into
   a LEDGER ROW: figure, then title, then paragraph, title and paragraph sharing
   a first baseline and the vertical hairline running down through the figures.
   It uses the width it has, and the scale break survives the rotation — 04 is
   still twice its neighbours and still the only ink figure in the column. */
@media (max-width: 1120px) {
  .sec-solutions-onboard {
    --on-n: clamp(26px, 3.4vw, 32px);
    --on-n-key: clamp(54px, 7vw, 66px);
    --on-numcol: 88px;
  }

  /* The header re-registers to the LEDGER grid, so the eyebrow keeps sitting on
     the same rail as the figures below it and the sentence stays indented off
     that rail. Losing this at 1120 was what made the tablet layout read as a
     desktop composition that had fallen over. */
  .sec-solutions-onboard .on-head {
    grid-template-columns: var(--on-numcol) minmax(0, 0.72fr) minmax(0, 1.28fr);
    column-gap: clamp(20px, 2.6vw, 30px);
  }
  .sec-solutions-onboard .on-eyebrow { grid-column: 1; }
  .sec-solutions-onboard .on-h { grid-column: 2 / span 2; max-width: 20ch; }

  .sec-solutions-onboard .on-band { margin-top: 64px; }
  .sec-solutions-onboard .on-rule--h { opacity: 0; }
  .sec-solutions-onboard .on-rule--v { opacity: 1; }

  .sec-solutions-onboard .on-steps { grid-template-columns: 1fr; }
  .sec-solutions-onboard .on-step {
    display: grid;
    grid-template-columns: var(--on-numcol) minmax(0, 0.72fr) minmax(0, 1.28fr);
    column-gap: clamp(20px, 2.6vw, 30px);
    /* Title and paragraph share a first baseline; the figure opts out below and
       hangs from the top of the row instead. */
    align-items: baseline;
    padding-bottom: 56px;
  }
  .sec-solutions-onboard .on-step:last-child { padding-bottom: 0; }
  /* The caesura is a horizontal device; stacked, the steps share one left rail
     and 04 would hang off it. */
  .sec-solutions-onboard .on-step--key { margin-left: 0; }

  .sec-solutions-onboard .on-n {
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: start;
    justify-self: center;
    width: 100%;
    text-align: center;
    text-indent: 0;
    /* Hangs the figure's cap on the title's cap, not on the paragraph below it.
       The 8px of ground above the glyph is inside the offset. */
    margin-top: -0.27em;
    margin-left: 0;
    padding: 8px 0;
  }
  /* Same cap alignment, solved for the larger figure. */
  .sec-solutions-onboard .on-step--key .on-n {
    margin-top: -0.23em;
    margin-left: 0;
    padding: 8px 0;
    letter-spacing: -0.03em;
  }

  /* The measure constraint that forced the desktop clamp is gone once the steps
     stack, so the titles go back to full size. */
  .sec-solutions-onboard .on-step__t {
    grid-column: 2; grid-row: 1; margin-top: 0;
    font-size: var(--t-body-lg);
  }
  .sec-solutions-onboard .on-step--key .on-step__t { margin-top: 0; }
  .sec-solutions-onboard .on-step__b {
    grid-column: 3; grid-row: 1;
    margin-top: 0;
    max-width: 60ch;
  }
  .sec-solutions-onboard .on-step--key .on-step__b { max-width: 60ch; }
}

/* ——— Stacked ——————————————————————————————————————————————
   Below ~780 the ledger's two text columns are 210px and 370px, which is a
   step title broken over three lines beside a paragraph broken over three —
   two ragged stacks pretending to be a row. So the paragraph drops under its
   own title and the step goes back to two columns: figure, then text. The
   paragraph takes a longer measure than the phone's here, because the canvas
   at this width is genuinely wider than the phone's and a 44ch column left a
   quarter of it empty. */
@media (max-width: 780px) {
  .sec-solutions-onboard .on-step {
    grid-template-columns: var(--on-numcol) minmax(0, 1fr);
    align-items: start;
    padding-bottom: 52px;
  }
  .sec-solutions-onboard .on-step__t { grid-column: 2; grid-row: 1; }
  .sec-solutions-onboard .on-step__b {
    grid-column: 2; grid-row: 2;
    margin-top: 11px;
    max-width: 52ch;
  }
  .sec-solutions-onboard .on-step--key .on-step__b { max-width: 52ch; }
}

@media (max-width: 720px) {
  .sec-solutions-onboard {
    --on-numcol: 78px;
    /* The phone cannot carry the desktop's 3.4x break in an 78px rail, but it
       can carry more than 2x: 60px is the widest figure that still clears the
       rail with air on both sides. */
    --on-n-key: clamp(60px, 7vw, 66px);
  }
  /* The phone column cannot carry an indent AND a headline, so here — and only
     here — the eyebrow goes back above the sentence and takes the site's one
     eyebrow gap with it. */
  .sec-solutions-onboard .on-head { grid-template-columns: 1fr; column-gap: 0; }
  .sec-solutions-onboard .on-eyebrow {
    grid-column: 1;
    padding-top: 0;
    margin-bottom: var(--eyebrow-gap);
  }
  /* The break is authored; a ch cap on top of it produced a four-line ladder. */
  .sec-solutions-onboard .on-h { grid-column: 1; max-width: none; }
  /* The stood-up rule leads in 38px above the band, so the band's own top gap
     is what keeps that lead-in from touching the headline's italic descender. */
  .sec-solutions-onboard .on-band { margin-top: 62px; }
  .sec-solutions-onboard .on-step { column-gap: 18px; padding-bottom: 44px; }
  .sec-solutions-onboard .on-step__t { font-size: 19px; }
  .sec-solutions-onboard .on-step__b { font-size: 15.5px; }
}

/* ===== section:cta-band ===== */
/* ————————————————————————————————————————————————
   cta-band — the closing punctuation, shared by all eight pages.

   Round 4. Round 3 lost on FINISH, not on idea: the two largest objects in the
   frame were hand-drawn placeholder-bar SVGs (a 264×426 field and a 290×214
   fragment), so a third of the composition read as content-TBD; every surface
   in the band sat between #FFF and #EAEAEA, so there was no mass anywhere; and
   ~550×290 of empty gradient sat between the headline's descender and the
   card's left edge. Three changes, in order of size:

   1. THE SLAB. The card is now the only dark mass in any page's closing band —
      var(--ink), white keys, paper values, no shadow (elevation is reserved for
      .artifact and this is not one). It is the "one genuinely heavy element"
      the band never had.
   2. REAL TYPE, NOT BARS. The menu inside it is SET: 29 priced rows under six
      small-caps category headers, prices on one shared tabular column per
      column of the menu. The kitchen ticket at the other corner is set the same
      way. Nothing in this section is a placeholder bar any more, and the slab
      earns its area with character density rather than filling it.
   3. INTERLOCK. The slab is taller (768px against a ~690px band) and pinned so
      its top rides ABOVE the headline's first line rather than starting below
      it, and the file tile is now a CHILD of the slab, hung across its left
      edge — so the overlap is measured from the slab and holds at every width.
      The hole in the middle is closed by the tile, not by moving the rail.

   The crop is still measured: the slab overhangs the right edge by 108px and
   its inner padding-right is that overhang plus 28px, so every price and every
   value ends 28px inside the cut and the edge falls through row whitespace.
   ———————————————————————————————————————————————— */
.sec-cta-band {
  padding-block: var(--section-y-loose);
  border-top: 1px solid var(--hair);
  /* Every object here is meant to be cut by these edges, and the bloom must
     never bleed onto whichever section happens to precede us. */
  overflow: hidden;
}

/* — The light —————————————————————————————————
   Recomposed for a left-anchored frame: the warm primary bloom sits behind the
   display head at 30/26 rather than on the axis, a lilac holds the object half,
   and a low warm one sits under the cut cards so the bottom of the band never
   flattens out. The cool --wash-4 stays dropped (it read as a blue-grey corner
   on --fog) and the component's paper-coloured bottom fade is removed — this
   band sits on --fog, so that fade would paint a white shelf across the close
   of every page. */
.sec-cta-band > .wash {
  inset: 0;
  opacity: 0.72;
  filter: blur(18px) saturate(106%);
  background:
    radial-gradient(38% 46% at 24% 20%, var(--wash-1) 0%, transparent 66%),
    radial-gradient(48% 54% at 58% 32%, var(--wash-2) 0%, transparent 70%),
    radial-gradient(40% 46% at 14% 76%, var(--wash-3) 0%, transparent 72%),
    radial-gradient(40% 46% at 88% 80%, var(--wash-1) 0%, transparent 72%);
}
.sec-cta-band > .wash::after { content: none; }

/* — Stacking ———————————————————————————————————
   Type above everything; the objects above the closing rule; the rule beneath
   both. That ordering is what lets the full-measure hairline disappear under
   the slab instead of drawing a grey line across it. */
.sec-cta-band .ctab__wrap { position: relative; z-index: 2; }
.sec-cta-band .ctab__footwrap { position: relative; z-index: 0; }

/* — The rail ———————————————————————————————— */
.sec-cta-band .ctab {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  max-width: 760px;
}

.sec-cta-band .ctab__h {
  /* SECTION-HEAD SCALE, NOT DISPLAY. This partial is byte-identical on all
     eight pages, so a display-scale sign-off made the last words on six of them
     the loudest words on the page — louder than the page's own H1. The site's
     one display is the home hero; every section headline, this one included,
     sits on .h. The measure still makes the two decks read as a natural break
     off the rail rather than as a balanced pair of centred lines. */
  font-size: var(--t-h);
  line-height: 1.16;
  letter-spacing: var(--tr-h);
  max-width: 15ch;
}
/* Give the clipped line masks room for the italic 'y' descender, then take the
   extra leading back so the two decks keep the rhythm .h sets for them. */
.sec-cta-band .ctab__h .line-mask { padding-bottom: 0.14em; margin-bottom: -0.14em; }

/* Dropped from --t-body-lg. At 20px the lede competed with the headline; at
   17px it becomes the quiet second voice, and at 44ch it sets three short lines
   against the rail instead of two long centred ones. */
/* The measure is also a CLEARANCE. The slab's left edge marches left as the
   viewport narrows (it is 53vw wide against a fixed 108px overhang) while the
   rail's text stays pinned at the gutter, so the lede is the line that would
   meet the file tile first. Every step below is set to keep ~40px of air
   between the end of this paragraph and the tile's send button. */
.sec-cta-band .ctab__sub {
  margin: var(--s24) 0 0;
  font-size: var(--t-body);
  line-height: 1.5;
  max-width: 40ch;
}

/* One filled pill and one plain link, both flush to the rail. */
.sec-cta-band .ctab__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s12) var(--s28);
  margin-top: var(--s40);
}
.sec-cta-band .ctab__wa {
  /* .alink is a text link; give it a real hit target anyway. */
  min-height: 44px;
  padding-inline: 4px;
}

/* — The close ————————————————————————————————
   Full page measure, flush left, with a 2px ink tab thickening its left end and
   the fine print hanging off exactly that end. */
.sec-cta-band .ctab__foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin-top: var(--s48);
}
.sec-cta-band .ctab__rule {
  position: relative;
  display: block;
  width: 100%;
  height: 1px;
  background: var(--hair-strong);
}
.sec-cta-band .ctab__rule::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 76px;
  height: 2px;
  background: var(--ink);
}
.sec-cta-band .ctab__fine { margin-top: var(--s20); color: var(--ash); }

/* — The objects ———————————————————————————————
   Placed against the section, not the wrap, so their crops are measured from
   the viewport edge and stay identical at every desktop width. */
.sec-cta-band .ctab__stage {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
}

/* THE SLAB. Anchored to the BOTTOM, never the top: the shared shell gives a
   first-child section 44px of extra top padding, and bottom anchoring is the
   only way the crop and the offset against the type read identically on a real
   page and in the isolated preview. Its HEIGHT is declared rather than derived,
   because the menu inside deliberately overruns it — that overrun is what
   guarantees the slab is never a part-empty dark field at any width. */
.sec-cta-band .ctab__art {
  position: absolute;
  right: -108px;
  bottom: -130px;
  /* 53vw keeps the overhang constant while the slab narrows with the viewport,
     so it can never reach across into the rail. At 1440 the slab's left edge
     lands at x=788, ~200px off the headline's ragged right — the hole the last
     round left between the two masses was 550px wide. */
  width: min(760px, 53vw);
  height: 768px;
}
.sec-cta-band .ctab__card {
  /* Overhang + 28px, so the price column ends well inside the cut and the edge
     always falls through whitespace. */
  --crop: 136px;
  /* The one dark mass. No shadow: elevation belongs to .artifact, and a slab
     this heavy separates on value alone. */
  --slab-hair: color-mix(in srgb, var(--paper) 58%, transparent);
  height: 100%;
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--r-card);
  text-align: left;
  overflow: hidden;
}

.sec-cta-band .ctab__card-top {
  display: flex;
  align-items: center;
  gap: var(--s16);
  padding: 24px var(--crop) 20px 30px;
  border-bottom: 1px solid var(--slab-hair);
}
.sec-cta-band .ctab__card-title {
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.008em;
  color: var(--paper);
  white-space: nowrap;
}
/* The single confirmation beat in the whole band, so it is the highest-contrast
   thing in it: paper on ink, on the same flush right column as every value and
   every price below it. */
.sec-cta-band .ctab__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  height: 24px;
  padding-inline: 11px;
  border-radius: var(--r-pill);
  background: var(--paper);
  color: var(--ink);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.004em;
  white-space: nowrap;
}

.sec-cta-band .ctab__list { list-style: none; margin: 0; padding: 0; }
.sec-cta-band .ctab__list li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 13px var(--crop) 13px 30px;
  font-size: 13.5px;
  line-height: 1.3;
}
.sec-cta-band .ctab__list li + li { border-top: 1px solid var(--slab-hair); }
.sec-cta-band .ctab__k { color: var(--smoke); white-space: nowrap; }
/* One flush right edge shared by the chip, every value here and every price in
   the menu below — the column that makes the slab read as one object. */
.sec-cta-band .ctab__v {
  margin-left: auto;
  color: var(--paper);
  font-weight: 450;
  white-space: nowrap;
}

/* — The menu, set ————————————————————————————
   28 priced rows under six small-caps headers. It overruns the slab's declared
   height by ~70px at 1440 and by more as the columns narrow, so the band always
   cuts it mid-row rather than leaving dark air at the bottom. */
.sec-cta-band .ctab__menu {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 36px;
  border-top: 1px solid var(--slab-hair);
  padding: 24px var(--crop) 0 30px;
}
.sec-cta-band .ctab__cat {
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--smoke);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--slab-hair);
}
.sec-cta-band .ctab__rows { list-style: none; margin: 9px 0 22px; padding: 0; }
.sec-cta-band .ctab__rows li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding-block: 4.5px;
  font-size: 12.5px;
  line-height: 1.34;
  letter-spacing: -0.002em;
  color: var(--paper);
}
.sec-cta-band .ctab__it { min-width: 0; }
/* The qualifier is part of the item name, not a second field — set in the same
   line at the same size, one step down in value. */
.sec-cta-band .ctab__it i { font-style: normal; color: var(--smoke); }
.sec-cta-band .ctab__pr { margin-left: auto; color: var(--paper); white-space: nowrap; }

/* — The file tile ————————————————————————————
   A CHILD of the slab wrapper, hung across the slab's left edge at a fixed
   offset, so the object-on-object overlap is measured from the slab and cannot
   drift into the rail as the viewport narrows. It is also what closes the
   ~550px hole that used to sit between the headline and the card. */
.sec-cta-band .ctab__art3 {
  position: absolute;
  /* Crosses the slab's edge by 30px — exactly the slab's own left padding, so
     the overlap occludes surface and never a glyph. Vertically it straddles the
     hairline between the fact table and the menu, so it cuts a structural line
     rather than a row of type. */
  left: -192px;
  top: 232px;
  width: 214px;
}
.sec-cta-band .ctab__tile {
  display: flex;
  align-items: center;
  gap: 11px;
  /* Raised white, ringed rather than shadowed — elevation is reserved for
     .artifact. Most of the tile lies on the pale gradient, where an unringed
     white card has no edge at all. */
  background: var(--raised);
  border: 1px solid var(--hair-strong);
  border-radius: var(--r-small);
  padding: 12px 14px;
  transform: rotate(-2.5deg);
}
.sec-cta-band .ctab__tile-ico {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 11px;
  background: var(--mist);
  color: var(--slate);
}
.sec-cta-band .ctab__tile-txt { min-width: 0; }
.sec-cta-band .ctab__tile-name {
  display: block;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.006em;
  color: var(--ink);
  white-space: nowrap;
}
.sec-cta-band .ctab__tile-meta {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.3;
  color: var(--slate);
  white-space: nowrap;
}
/* The second ink mass, hanging off the tile's left edge onto the gradient — a
   third overlap, at a third scale. */
.sec-cta-band .ctab__send {
  position: absolute;
  left: -19px;
  top: 12px;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--paper);
}

/* — The ticket ————————————————————————————————
   What the built shop prints: light, flat, no elevation, cut by the OPPOSITE
   edge and by the bottom. It sits below every line of type, so it can never
   collide with the rail at any viewport width. */
.sec-cta-band .ctab__art2 {
  position: absolute;
  left: -60px;
  width: 400px;
  /* Height is declared so the standing part is EXACTLY 130px at every width.
     The band's bottom padding is a constant 160px, so the ticket's top edge is
     always 30px clear of the fine print however the type above it reflows —
     anchoring by content height alone let it climb over the closing line at
     1024. */
  height: 260px;
  bottom: -130px;
}
.sec-cta-band .ctab__slip {
  height: 100%;
  background: var(--mist);
  border: 1px solid var(--hair-strong);
  border-radius: var(--r-card);
  /* Left padding is deeper than the 60px crop, so the viewport edge cuts empty
     card and never a glyph — the object is cropped, the type is not. */
  padding: 20px 24px 0 88px;
  overflow: hidden;
  /* Pivoted on its top-right corner, so the rotation can only ever drop the
     ticket away from the fine print, never lift it into the text. */
  transform: rotate(-4deg);
  transform-origin: 100% 0;
}
.sec-cta-band .ctab__slip-top {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--hair-strong);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--slate);
}
.sec-cta-band .ctab__slip-top span:last-child { margin-left: auto; }
.sec-cta-band .ctab__slip-rows { list-style: none; margin: 10px 0 0; padding: 0; }
.sec-cta-band .ctab__slip-rows li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding-block: 5px;
  font-size: 12.5px;
  line-height: 1.34;
  letter-spacing: -0.002em;
  color: var(--ink);
  white-space: nowrap;
}
.sec-cta-band .ctab__q { flex: none; width: 12px; color: var(--slate); }
.sec-cta-band .ctab__slip-rows i { font-style: normal; color: var(--slate); }

/* — Narrower desktops —————————————————————————
   The objects are anchored to the viewport, so the crops hold all the way down;
   only the type measure and the menu's column count need to give. */
@media (max-width: 1180px) {
  .sec-cta-band .ctab { max-width: 620px; }
  .sec-cta-band .ctab__sub { max-width: 32ch; }
  .sec-cta-band .ctab__menu { column-gap: 28px; }
}
@media (max-width: 1080px) {
  .sec-cta-band .ctab { max-width: 500px; }
  .sec-cta-band .ctab__sub { max-width: 30ch; }
  .sec-cta-band .ctab__card { --crop: 126px; }
  .sec-cta-band .ctab__art3 { left: -166px; top: 206px; width: 196px; }
}

/* — Stacked ————————————————————————————————————
   Below 980 there is no room beside the rail, so the slab drops into flow
   between the CTA and the closing line. It is NOT a full-width block inside
   both gutters: it keeps its left edge on the rail, runs 24px past the right
   edge of the screen, and keeps the file tile lying across its top-left corner
   — the crop-and-overlap idea survives the breakpoint instead of being deleted
   at it. The stage is a sibling BETWEEN the two wraps in source for exactly
   this reason, so the page still ends on the closing line. */
@media (max-width: 980px) {
  .sec-cta-band .ctab { max-width: none; }
  .sec-cta-band .ctab__sub { max-width: 46ch; }

  .sec-cta-band .ctab__stage {
    position: relative;
    inset: auto;
    width: 100%;
  }
  .sec-cta-band .ctab__art {
    position: relative;
    inset: auto;
    width: auto;
    /* Tuned so the cut lands mid-row, never on a category header — an orphan
       header at the crop reads as a bug, a half-row reads as a crop. */
    height: 620px;
    /* Left edge on the rail; right edge 24px past the screen, cropped by the
       section's own overflow. */
    margin: var(--s64) -24px 0 var(--gutter);
    animation: none;
  }
  /* Room above the title for the tile to cross the corner without covering it. */
  .sec-cta-band .ctab__card { --crop: 48px; }
  .sec-cta-band .ctab__card-top { padding: 52px 48px 18px 26px; }
  .sec-cta-band .ctab__list li { padding: 13px 48px 13px 26px; }
  .sec-cta-band .ctab__menu {
    grid-template-columns: minmax(0, 1fr);
    padding: 22px 48px 0 26px;
  }
  .sec-cta-band .ctab__mcol:last-child { display: none; }

  .sec-cta-band .ctab__art3 {
    left: 10px;
    top: -30px;
    width: 200px;
    animation: none;
  }
  .sec-cta-band .ctab__art2 { display: none; }

  .sec-cta-band .ctab__foot { margin-top: var(--s64); }
}

/* — Phones ————————————————————————————————————
   The action row is capped to the measure of the copy above it, so it can never
   bulge wider than the sentence it belongs to. */
@media (max-width: 720px) {
  .sec-cta-band .ctab__h { max-width: 13ch; }
  .sec-cta-band .ctab__sub { margin-top: var(--s16); max-width: 32ch; }
  .sec-cta-band .ctab__actions {
    margin-top: var(--s32);
    max-width: 34ch;
    gap: var(--s8) var(--s20);
  }
  .sec-cta-band .ctab__art { margin-top: var(--s48); height: 480px; }
  .sec-cta-band .ctab__art3 { left: 6px; top: -28px; width: 184px; }
  .sec-cta-band .ctab__foot { margin-top: var(--s48); }
  .sec-cta-band .ctab__rule::before { width: 56px; }
}
