/* ==========================================================================
   Ilara — site styles
   Section order and geometry follow the reference layout one-to-one; the skin
   is Ilara's (ink base, lime accent, Inter Tight + JetBrains Mono).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Base
   -------------------------------------------------------------------------- */

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

html {
  height: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  scrollbar-width: none;
}

html, body {
  width: 100%;
  margin: 0;
}

/* Never allow horizontal panning on touch devices. The squash headings hold
   their split words 40% right of home until they scroll into view, which
   widens the document on any engine that misses `clip`; the hidden line is
   the fallback there, and clip wins elsewhere without creating a scroll
   container. On both elements because iOS has propagated root clip to the
   viewport unreliably. */
html, body {
  overflow-x: hidden;
  overflow-x: clip;
}


/* The hero tile is pulled down past the hero's rounded bottom edge, so the
   face reserves space at the bottom or the corner slices its content.
   How much bleed there actually is depends on viewport HEIGHT: the tile is a
   fixed 38.5em portrait centred in a hero that is one viewport tall, so it
   only overhangs once the viewport gets short. A flat 34cqw was sized for the
   worst case and charged it at every height, which on a 1080p monitor left a
   fifth of the card empty below the last row.
   28em - 50vh is that overhang plus the corner's own inset, so the reservation
   appears exactly when the corner starts to reach the content and is nearly
   nothing when it does not. Floored at 10cqw so the card keeps inner padding,
   capped at 44cqw for very short viewports. In em, so it tracks the fluid type
   the way the tile does. .queue and .queue__row are both flex:1, so whatever
   this does not take, the rows stretch into. */
.hero__visual-stage .face { padding-bottom: clamp(10cqw, calc(28em - 50vh), 44cqw); }

@media (min-width: 992px) {
  html, body { overscroll-behavior: none; }
}

body {
  min-height: 100%;
  font-size: var(--size-font);
  font-family: var(--font-body);
  font-weight: 450;
  letter-spacing: -0.011em;
  line-height: 1.35;
  color: var(--ink);
  background-color: var(--surface);
  -ms-overflow-style: none;
}

body::-webkit-scrollbar { display: none; }

img, svg { display: block; max-width: 100%; }
img { height: auto; }

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

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

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

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 0.1875em solid var(--ink);
  outline-offset: 0.1875em;
  border-radius: 0.25em;
}

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

.page-wrapper { position: relative; width: 100%; background-color: var(--surface); }
.main { position: relative; background-color: var(--surface); }

/* --------------------------------------------------------------------------
   2. Utilities
   -------------------------------------------------------------------------- */

.u-container {
  width: 100%;
  padding-left: var(--grid-margin);
  padding-right: var(--grid-margin);
}

.u-grid {
  display: grid;
  grid-template-columns: var(--grid);
  gap: 0 var(--grid-gutter);
}

.u-screen-reader {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.u-heading-xxl {
  font-family: var(--font-display);
  font-size: var(--font-size-heading-xxl);
  font-weight: 900;
  letter-spacing: -0.035em;
  line-height: 0.82;
}

.u-heading-l {
  font-family: var(--font-display);
  font-size: var(--font-size-heading-l);
  font-weight: 900;
  letter-spacing: -0.032em;
  line-height: 0.86;
}

.u-heading-m {
  font-family: var(--font-display);
  font-size: var(--font-size-heading-m);
  font-weight: 900;
  letter-spacing: -0.03em;
  line-height: 0.9;
}

.u-heading-s {
  font-family: var(--font-display);
  font-size: var(--font-size-heading-s);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 0.94;
}

.u-heading-xs {
  font-family: var(--font-display);
  font-size: var(--font-size-heading-xs);
  font-weight: 800;
  letter-spacing: -0.022em;
  line-height: 0.96;
}

.u-paragraph-large      { font-size: var(--font-size-paragraph-large);       letter-spacing: -0.02em; line-height: 1.2; }
.u-paragraph-medium     { font-size: var(--font-size-paragraph-medium);      letter-spacing: -0.01em; line-height: 1.2; }
.u-paragraph-regular    { font-size: var(--font-size-paragraph-regular);     letter-spacing: -0.02em; line-height: 1.25; }
.u-paragraph-small      { font-size: var(--font-size-paragraph-small);       letter-spacing: -0.02em; line-height: 1.25; }
.u-paragraph-extra-small{ font-size: var(--font-size-paragraph-extra-small); letter-spacing: -0.02em; line-height: 1.3; }

.u-dim { color: var(--ink-dim); }
.u-ink { color: var(--ink); }
.u-lime { color: inherit; text-decoration: underline dotted; text-underline-offset: 0.18em; }

/* Mono annotation — the reference's handwritten margin notes, translated. */
.u-note {
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.15;
  text-transform: uppercase;
  color: var(--ink);
}

.u-note-big { font-size: var(--font-size-note-big); }

.u-note::before {
  content: "// ";
  opacity: 0.55;
}

.u-note.right-side { transform: rotate(3deg); }
.u-note.left-side  { transform: rotate(-4deg); }

/* --------------------------------------------------------------------------
   3. Buttons
   -------------------------------------------------------------------------- */

.button {
  position: relative;
  display: inline-grid;
  height: var(--button-height);
  padding: 0;
  font-family: var(--font-body);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--button-color);
  background-color: transparent;
  outline-style: none;
  user-select: none;
}

.button__bg {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  background-color: var(--button-color-background);
  border: 1px solid var(--line);
  border-radius: var(--button-border-radius);
  transition: background-color 0.25s var(--ease-click), border-color 0.25s var(--ease-click);
}

.button__inner {
  z-index: 1;
  grid-area: 1 / 1;
  display: flex;
  gap: 0.25em;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: var(--button-padding);
}

.button__text { flex: none; font-size: 1.125em; }

.button:hover .button__bg { background-color: var(--lime); border-color: var(--lime); }
.button:active { scale: var(--button-click-scale); }
.button.is--current .button__bg { background-color: var(--lime); }

.button-alt {
  position: relative;
  display: inline-flex;
  height: var(--button-alt-height);
  padding: 0;
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.5;
  color: var(--button-alt-color);
  background-color: transparent;
  outline-style: none;
  user-select: none;
}

.button-alt__bg {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  background-color: var(--button-alt-color-background);
  border-radius: var(--button-alt-border-radius);
  transition: background-color 0.25s var(--ease-click);
}

.button-alt__text-wrap { display: grid; flex-shrink: 0; pointer-events: none; }
.button-alt__text-outer {
  z-index: 1;
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.button-alt__text {
  padding-left: var(--button-alt-padding-x);
  padding-right: var(--button-alt-padding-x);
  font-size: 1.40625em;
  white-space: nowrap;
}

.button-alt__icon-wrap {
  display: grid;
  aspect-ratio: 1;
  width: var(--button-alt-height);
  height: var(--button-alt-height);
  margin-left: -0.0625em;
  pointer-events: none;
}

.button-alt__icon-outer {
  z-index: 1;
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.button-alt__icon { flex: none; width: 1.09375em; height: 0.9375em; }
.button-alt__icon.is--menu-toggle { width: 1.5em; height: 1.5em; }

.button-alt:hover .button-alt__bg { background-color: #2a2a28; }
.button-alt:hover .button-alt__icon-outer { transform: translateX(0.1875em); }
.button-alt__icon-outer { transition: transform 0.3s var(--ease-soft-overshoot); }
.button-alt:active { scale: var(--button-click-scale); }

.button-alt.is--ghost { color: var(--ink); }
.button-alt.is--ghost .button-alt__bg {
  background-color: transparent;
  border: 1px solid var(--line-strong);
}
.button-alt.is--ghost:hover .button-alt__bg { background-color: rgba(13, 13, 14, 0.07); }

.button-social {
  position: relative;
  display: inline-grid;
  width: 3em;
  height: 3em;
  color: var(--surface-raised);
  outline-style: none;
  user-select: none;
}

.button-social__bg {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  background-color: var(--ink);
  border-radius: 50%;
  transition: background-color 0.25s var(--ease-click);
}

.button-social__icon-outer {
  z-index: 1;
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.button-social__icon { width: 1.5em; height: 1.5em; }
.button-social:hover .button-social__bg { background-color: var(--lime); }
.button-social:active { scale: var(--button-click-scale); }

.slider-button {
  display: inline-grid;
  width: 4.5em;
  height: 4.5em;
  padding: 0;
  color: var(--surface-raised);
  background-color: transparent;
  user-select: none;
  pointer-events: auto;
}

.slider-button__bg {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  background-color: var(--ink);
  border-radius: 50%;
  transition: background-color 0.25s var(--ease-click), opacity 0.25s linear;
}

.slider-button__icon-wrap {
  z-index: 1;
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.slider-button__icon { flex: none; width: 1.125em; height: 1em; }
.slider-button.is--previous { rotate: -180deg; }
.slider-button:hover .slider-button__bg { background-color: var(--lime-deep); }
.slider-button:active { scale: var(--button-click-scale); }
.slider-button[disabled] { cursor: default; }
.slider-button[disabled] .slider-button__bg { opacity: 0.35; }

/* --------------------------------------------------------------------------
   4. Header + mobile menu
   -------------------------------------------------------------------------- */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  width: 100%;
  height: var(--header-height);
  pointer-events: none;
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding-left: var(--grid-margin);
  padding-right: var(--grid-margin);
}

/* Positioned so the logo paints above .header::before. That backdrop is
   absolutely positioned, so it would otherwise cover a static logo once it
   fades in on scroll. The nav and CTA escape it via .button's own position. */
.header__title {
  position: relative;
  z-index: 1;
  width: calc((var(--grid-column-width) * 3) + (var(--grid-gutter) * 3));
}
.header__nav   { width: calc((var(--grid-column-width) * 6) + (var(--grid-gutter) * 5)); }

.header__sub {
  display: flex;
  gap: 1.5em;
  align-items: center;
  justify-content: flex-end;
  width: calc((var(--grid-column-width) * 3) + (var(--grid-gutter) * 3));
}

.header__title-link { pointer-events: auto; user-select: none; }
.header__title-logo { width: 8.5em; height: auto; }

.header__nav-list,
.header__sub-list {
  display: flex;
  gap: 0.5em;
  align-items: center;
}

.header__nav-list { justify-content: center; }
.header__sub-list { justify-content: flex-end; }
.header__nav-list-item,
.header__sub-list-item { display: flex; pointer-events: auto; }

.header__menu-toggle { display: none; pointer-events: auto; }

/* Backdrop that fades in once the page is scrolled */
.header::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: rgba(251, 250, 247, 0.78);
  backdrop-filter: blur(0.75em);
  border-bottom: 1px solid var(--line);
  opacity: 0;
  transition: opacity 0.4s var(--ease-smooth);
}

.header.is--scrolled::before { opacity: 1; }

.menu {
  position: fixed;
  inset: 0;
  z-index: 1100;
  visibility: hidden;
  pointer-events: none;
}

.menu.is--open { visibility: visible; pointer-events: auto; }

.menu__inner { display: grid; width: 100%; height: 100%; }

.menu__bg {
  position: relative;
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  overflow: clip;
  background-color: var(--surface-raised);
  clip-path: inset(0 0 100% 0 round 0 0 2.5em 2.5em);
  transition: clip-path 0.65s var(--ease-smooth);
}

.menu.is--open .menu__bg { clip-path: inset(0 round 0 0 2.5em 2.5em); }

.menu__bg-glow {
  position: absolute;
  inset: auto -20% -30% -20%;
  height: 70%;
  background: radial-gradient(ellipse at 50% 100%, rgba(163, 230, 53, 0.55), transparent 70%);
  pointer-events: none;
}

.menu__container {
  z-index: 1;
  grid-area: 1 / 1;
  display: grid;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.menu__content {
  position: relative;
  z-index: 1;
  grid-area: 1 / 1;
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  opacity: 0;
  transition: opacity 0.35s linear 0.1s;
}

.menu.is--open .menu__content { opacity: 1; }

.menu__header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 5em;
  padding: 0.5em 1.5em 0;
  margin-bottom: 2.5em;
}

.menu__header-title-logo { width: 8.5em; height: auto; }

/* The panel is a column of three: header, nav, footer. margin-top: auto here
   pushed the nav down until it sat flush against the footer -- 400px of dead
   space above the links and none below. Letting the nav take the space instead
   and centring inside it puts the links in the middle of the panel, which is
   where a hand reaches on a phone. */
.menu__nav { display: flex; flex: 1; align-items: center; }

.menu__nav-list {
  display: flex;
  flex-flow: column;
  gap: 0.625em;
  align-items: center;
  justify-content: center;
}

.menu__nav-list-item { display: flex; }

.menu__footer {
  display: flex;
  flex-flow: column;
  gap: 2em;
  align-items: center;
  justify-content: center;
  padding-top: 2.5em;
  padding-bottom: 3.25em;
}

.menu__sub-list { display: flex; gap: 0.5em; align-items: center; }

/* --------------------------------------------------------------------------
   5. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  display: flex;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  background-color: var(--lime);
  clip-path: inset(0% round 0 0 10em 10em);
}

.hero__container { position: relative; z-index: 1; overflow: hidden; }

/* The tile sits beside the copy: stacked, it pushed the fold down and left a
   band of dead space between the paragraph and the card. */
.hero__inner { display: flex; flex-flow: row; gap: 3.375em; align-items: center; }
.hero__inner > .hero__content { flex: 1 1 auto; min-width: 0; }
.hero__inner > .hero__visual { flex: 0 0 auto; }

.hero__content {
  position: relative;
  display: flex;
  flex-flow: column;
  gap: 1em;
  align-items: flex-start;
  justify-content: flex-start;
  padding-top: 13em;
  margin-left: -0.25em;
}

/* Same height blindness as .gap__content: the column measures 61.2em from the
   top padding to the base of the button, and at 1920 that is 979px against a
   real browser viewport of roughly 850-950px on a 1080p monitor, so the button
   and the rotated note fell below the fold. Budget 64em for clearance. Only
   above 992px, where the tile sits beside the copy and the hero is pinned to
   one viewport; below that the hero stacks and is free to grow. */
/* 64em cleared the fold but not the corner. .hero carries clip-path: inset(0%
   round 0 0 10em 10em), and the copy is left-aligned, so the demo button sits
   in the bottom-left corner exactly where the curve bites. The button began
   about 1.3em in from the left edge and 40px above the bottom, while at that
   height the curve reaches 82px in at 1920 and 107px at 2560. It was sliced
   flat on its left side at every desktop width: 24px at 1512, 30px at 1920,
   56px at 2560, 74px at 3440. The radius is 10em of a width-driven root, so
   the bigger the monitor the more it took.

   Raising the button is the only lever. Reserving space below it does not
   work: the column already fills the hero, so padding-bottom grows the hero
   past 100svh (measured +102px) and merely pushes the corner below the fold
   without moving the button a pixel. Nor can the copy shift right, since it
   aligns with the logo.

   66em of budget instead of 64em shortens the column enough to lift the
   button clear of the curve, at a cost of about 7% on the headline (155px to
   144px at 1920). Verified clear and the hero exactly one viewport at eleven
   sizes from 1024x681 to 3440x1440. */
@media (min-width: 992px) {
  .hero__content { font-size: min(1em, 1.45vh); }
}

.hero__header {
  display: flex;
  flex-flow: column;
  gap: 1.5em;
  align-items: flex-start;
  max-width: 78em;
}

.hero__eyebrow {
  display: flex;
  gap: 0.75em;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 1.125em;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
}

.hero__eyebrow::before {
  content: "";
  width: 0.5em;
  height: 0.5em;
  background-color: var(--ink);
  border-radius: 50%;
  box-shadow: 0 0 0 0.25em rgba(13, 13, 14, 0.16);
  animation: pulse 2.4s var(--ease-smooth) infinite;
}

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0.25em rgba(13, 13, 14, 0.16); }
  50%      { box-shadow: 0 0 0 0.6em rgba(13, 13, 14, 0); }
}

.hero__title { max-width: 100%; }
.hero__title em { font-style: normal; }

 /* full-bleed intro under the headline, set large enough that the full-width
    measure still lands at a readable line length */
.hero__paragraph {
  max-width: 100%;
  font-size: 2.75em;
  letter-spacing: -0.025em;
  line-height: 1.2;
  color: var(--ink-dim);
}
.hero__paragraph strong { font-weight: 600; color: var(--ink); }

/* live activation readout under the intro: the eyebrow's pulse dot, recoloured
   lime for "running in production", with a mono counter line beside it */
.hero__stat {
  display: flex;
  gap: 0.75em;
  align-items: flex-start;
  font-family: var(--font-mono);
  font-size: 1.5em;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink-dim);
}

.hero__stat strong { font-weight: 600; color: var(--ink); }

.hero__stat::before {
  content: "";
  flex: none;
  width: 0.5em;
  height: 0.5em;
  margin-top: 0.45em;
  background-color: var(--lime-deep);
  border-radius: 50%;
  box-shadow: 0 0 0 0.25em rgba(163, 230, 53, 0.35);
  animation: pulse-lime 2.4s var(--ease-smooth) infinite;
}

@keyframes pulse-lime {
  0%, 100% { box-shadow: 0 0 0 0.25em rgba(163, 230, 53, 0.35); }
  50%      { box-shadow: 0 0 0 0.6em rgba(163, 230, 53, 0); }
}

.hero__action { display: flex; gap: 1em; align-items: center; padding-top: 0.5em; }

.hero__text-wrap { opacity: 0.9; }

/* The note sat at bottom:15em when the copy ran the full width. With the tile
   beside it the column is narrower, so that position landed on the paragraph.
   Dropped to sit beside the button, where the column is empty. */
.hero__text-outer {
  position: absolute;
  right: 1.5em;
  bottom: 1.25em;
  transform: rotate(3deg);
}

.hero__text { max-width: 17ch; text-align: center; }

.hero__visual {
  display: flex;
  justify-content: flex-end;
  margin-bottom: -8em;
}

.hero__visual-stage {
  position: relative;
  right: 4em;
  width: 25em;
}

.hero__bg {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  color: #c1ed77;
  pointer-events: none;
}

.hero__bg-svg { width: 100%; height: auto; overflow: visible !important; }
.hero__bg-svg.is--mobile { display: none; }

.hero__grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(13, 13, 14, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(13, 13, 14, 0.055) 1px, transparent 1px);
  background-size: 5em 5em;
  mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, #000 20%, transparent 75%);
}

/* --------------------------------------------------------------------------
   6. Features — horizontal phone deck
   -------------------------------------------------------------------------- */

.features { position: relative; overflow: clip; background-color: var(--surface-raised); }

.features__inner { padding-bottom: 10em; }

.features__header {
  position: relative;
  padding-top: 13.75em;
  padding-bottom: 4em;
  text-align: center;
}

.features__header-content {
  display: flex;
  flex-flow: column;
  gap: 1.5em;
  align-items: center;
  justify-content: center;
}

.features__title { max-width: 18ch; }
/* The break between the two sentences is explicit in the markup, so this only
   has to be wide enough not to wrap either sentence again. 24ch was within a
   character of the longer one. */
.features__subtitle { max-width: 30ch; color: var(--ink); }
/* solid ink, like the gap paragraph: --ink-dim is 62% alpha, so the section's
   blob background shows through the letterforms and softens them */
.features__paragraph { max-width: 46ch; color: var(--ink); }

.features__text-wrap { opacity: 0.9; }

.features__text-outer {
  position: absolute;
  top: 9.375em;
  left: 7.25em;
  transform: rotate(-6deg);
}

.deck { position: relative; }

.deck__list {
  display: flex;
  align-items: stretch;
  justify-content: flex-start;
  padding-left: 1em;
  padding-right: 1em;
}








/* the tile shares the cover's proportion, so it fills it exactly */




.deck__tag-list { display: flex; flex-flow: wrap; gap: 0.25em; }

.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.375em 0.75em 0.4375em;
  font-family: var(--font-mono);
  font-size: 0.875em;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: #4d6b12;
  background-color: var(--lime-wash);
  border: 1px solid var(--lime);
  border-radius: 2em;
}

.tag.is--muted {
  color: var(--ink-dim);
  background-color: var(--surface);
  border-color: var(--line);
}

.deck__controls {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 0.5em;
  align-items: center;
  justify-content: flex-end;
  padding-top: 5em;
  padding-right: 2.5em;
  pointer-events: none;
}

.deck__controls.is--case { justify-content: center; padding-top: 3em; padding-right: 0; }
.deck__controls.is--insights { margin-top: -3em; padding-top: 0; padding-right: 2.5em; }

/* --------------------------------------------------------------------------
   Feature list — the reference's big-type list, not data cards. The row nearest
   the middle of the viewport is the live one; its description reads out beside
   it while the others sit back.
   -------------------------------------------------------------------------- */

.feature-list { width: 100%; }

.feature-list__item {
  display: grid;
  /* The first track was 1fr, so it swallowed all the free space and pushed the
     paragraph to the far right: 619-827px of nothing mid-row. Each row is its
     own grid, so the name track is a fixed width rather than max-content,
     otherwise every row would align its paragraph differently. 44em clears the
     widest name, "Personalise", which measures ~42em. */
  grid-template-columns: 44em minmax(0, 30em) minmax(0, 1fr);
  gap: 2.5em;
  align-items: center;
  padding: 0.875em 1em;
  border-top: 1px solid var(--line);
  border-radius: 0.75em;
  transition: background-color 0.45s var(--ease-smooth);
}

.feature-list__item:last-child { border-bottom: 1px solid var(--line); }

/* The row runs the full width but the copy stops two thirds across. The index
   closes it off and gives the rolldown a sense of position, using the same
   mono numbering as the hero queue and the how-it-works steps. */
.feature-list__index {
  justify-self: end;
  font-family: var(--font-mono);
  font-size: 2.75em;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--ink);
  opacity: 0.16;
  transition: opacity 0.5s var(--ease-smooth), transform 0.5s var(--ease-smooth);
}

.feature-list__item.is--active .feature-list__index { opacity: 0.55; transform: translateX(-0.15em); }

.feature-list__name {
  font-family: var(--font-display);
  font-size: 8em;
  font-weight: 900;
  letter-spacing: -0.04em;
  line-height: 0.9;
  color: #7fa83a;
  opacity: 0.5;
  transition: color 0.5s var(--ease-smooth), opacity 0.5s var(--ease-smooth), transform 0.5s var(--ease-smooth);
}

.feature-list__text {
  font-size: var(--font-size-paragraph-regular);
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: var(--ink-dim);
  opacity: 0;
  transform: translateY(0.5em);
  transition: opacity 0.5s var(--ease-smooth), transform 0.5s var(--ease-smooth);
}

.feature-list__item.is--active { background-color: rgba(163, 230, 53, 0.34); }
.feature-list__item.is--active .feature-list__name { color: var(--ink); opacity: 1; }
.feature-list__item.is--active .feature-list__text { color: var(--ink); opacity: 1; transform: none; }

/* Scroll position is the only thing that opens a row. A hover rule used to open
   them too, which meant the row under the pointer and the row the scroll had
   chosen could both be open, and moving the mouse across the list flickered
   through all four. */

/* --------------------------------------------------------------------------
   7. Flow — how it works
   -------------------------------------------------------------------------- */

.flow {
  position: relative;
  overflow: hidden;
  margin-bottom: calc(var(--grid-margin) * -1);
  background-color: var(--surface);
}

.flow__container { position: relative; z-index: 1; }

.flow__inner {
  padding-top: var(--grid-margin);
  padding-bottom: var(--grid-margin);
  background-color: var(--surface-soft);
  border-radius: 10em;
}

.flow__header {
  position: relative;
  display: flex;
  gap: 2.625em;
  align-items: flex-end;
  justify-content: flex-start;
  padding: 7.5em 6em 0;
}

.flow__heading { flex: none; display: flex; flex-flow: column; gap: 0.5em; }
.flow__title { max-width: 24ch; }
.flow__subtitle { color: var(--ink-dim); }

.flow__label { position: absolute; top: 4em; left: 6em; }

.case__label { margin-bottom: 0.25em; }

.insights__item-label { margin-bottom: 0.25em; }

.flow__text-wrap { opacity: 0.9; }

.flow__text-outer { padding-bottom: 0.5em; transform: rotate(2.4deg); }
.flow__text { max-width: 20ch; text-align: center; }

.flow__cta {
  position: absolute;
  top: 7.8125em;
  right: 5em;
  z-index: 1;
  display: flex;
  flex-flow: column;
  gap: 1.375em;
  align-items: center;
  justify-content: center;
}

.flow__cta-logo { width: 5em; height: 5em; user-select: none; }

.flow__content { padding-top: 9em; padding-bottom: 7.5em; }

.flow__list {
  position: relative;
  display: flex;
  align-items: stretch;
  justify-content: center;
}

.flow__list-item { height: auto; }

.flow__card {
  display: flex;
  width: 25em;
  height: 37.5em;
  background-color: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: 2em;
  box-shadow: 0 0.75em 2em rgba(13, 13, 14, 0.05);
  transition: border-color 0.5s var(--ease-smooth), box-shadow 0.5s var(--ease-smooth);
}

.flow__list-item:hover .flow__card {
  border-color: var(--lime-deep);
  box-shadow: 0 1.5em 3em rgba(13, 13, 14, 0.12);
}

.flow__card-inner {
  display: flex;
  flex-flow: column;
  gap: 1.25em;
  justify-content: space-between;
  width: 100%;
  height: 100%;
  padding: 2.5em 1.25em 1.5em;
}

.flow__card-header { flex: none; text-align: center; }

.flow__card-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.375em 1em 0.4375em;
  font-family: var(--font-mono);
  font-size: 1.125em;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink);
  background-color: var(--lime);
  border-radius: 2em;
}

.flow__card-img-wrap {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  /* top, not centre: the descriptions differ in length, so centring left each
     tile at a different height and the row of three did not line up */
  align-items: flex-start;
  justify-content: center;
  padding-top: 1.25em;
  min-height: 0;
  overflow: hidden;
}

/* sized to sit whole inside the card rather than being cropped by it */
/* The shared tile is a tall 320/493 portrait. In these cards its content sat
   in the middle with about 110px of nothing under it, roughly a third of the
   tile, and it only used 189 of the card's 315px width. Squared off and
   widened, the same fix the insights card covers got. */
.flow__card-visual { width: 100%; padding: 0 0.5em; }
.flow__card-visual .tile { aspect-ratio: 3 / 2; width: 100%; }

.flow__card-content {
  display: flex;
  flex: none;
  flex-flow: column;
  gap: 0.75em;
  padding-right: 1em;
}

/* .flow__card-inner is space-between, so the content block is bottom-anchored
   and a title that wraps to two lines lifts that whole card's copy above the
   other two. Reserve both lines (line-height is 0.96) so the three titles and
   the three paragraphs sit on the same baselines whatever the copy does. */
.flow__card-title { min-height: 1.92em; color: var(--ink); }
.flow__card-paragraph { color: var(--ink-dim); }

.flow__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  color: #f3fade;
  opacity: 1;
  pointer-events: none;
}

.flow__bg-svg { width: 100%; height: auto; overflow: visible !important; }
.flow__bg-svg.is--mobile { display: none; }

/* --------------------------------------------------------------------------
   8. Gap — sticky scroll moment
   -------------------------------------------------------------------------- */

.gap__wrap { position: relative; width: 100%; height: 190svh; }

.gap__sticky {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  /* svh, matching the hero: on Windows and on mobile the browser chrome is not
     included in vh, so the pinned panel measured taller than the space it had
     and the button under the meter was cut off at the bottom. */
  height: 100svh;
  min-height: 46.25em;
}

.gap__element {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: 100%;
  overflow: hidden;
  clip-path: inset(var(--grid-margin) round 10em);
  background-color: var(--surface-sand);
}

.gap__field {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(13, 13, 14, 0.13) 1px, transparent 1px);
  background-size: 2.5em 2.5em;
  mask-image: radial-gradient(ellipse 70% 70% at 50% 50%, #000 10%, transparent 70%);
}

.gap__glow {
  position: absolute;
  inset: auto 0 -30% 0;
  height: 80%;
  background: radial-gradient(ellipse at 50% 100%, rgba(163, 230, 53, 0.55), transparent 65%);
  pointer-events: none;
}

.gap__content {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;
  width: 62.5em;
  height: 100%;
  padding-top: 7.5em; /* clears the fixed header, which the old 4% of width did not */
  text-align: center;
}

/* Labels the block below as the status quo, not as Ilara. This is the one
   piece of copy on the page that is not verbatim from the source doc, added
   deliberately because the section was being read as a description of Ilara.
   Muted on purpose: it is the problem's label, against the lime payoff. */
.gap__eyebrow {
  display: flex;
  flex-flow: column;
  align-items: center;
  gap: 0.5em;
  max-width: 100%;
  margin-bottom: 1.1em;
  /* Same face as the headline, in solid ink, but set at a kicker size so it
     sits on one line. At full heading-l the block ran to five lines of 82px
     type before the point landed. */
  font-family: var(--font-display);
  font-size: 2.6em;
  font-weight: 800;
  letter-spacing: -0.022em;
  line-height: 1;
  color: var(--ink);
}

/* a short lime rule ties the label to the lime payoff at the foot of the
   section, so the two ends of the argument are visibly a pair */
.gap__eyebrow::after {
  content: "";
  width: 2.2em;
  height: 0.11em;
  background-color: var(--lime-deep);
  border-radius: 0.11em;
}

.gap__title { max-width: 100%; }
.gap__title .gap__title-line { display: block; }
/* The second line is the thing that arrives late, so it fills in with lime as
   you scroll and is complete by the end of the section. Filled per character
   rather than with a gradient across the block: a gradient wipes by horizontal
   position, so on a wrapped line the last row turns green before the middle
   one does. Characters fill in reading order. */
.gap__title .is--fill { color: rgba(13, 13, 14, 0.22); }
.gap__char { transition: color 0.18s var(--ease-smooth); }
.gap__char.is--on { color: #8dc039; }   /* lime, softened. The brand lime at
   full chroma was too vibrant here against the cream. This holds the hue at
   83 and drops the saturation from 78% to 54%, which also lifts it from
   1.25:1 to 1.79:1 against the panel. Still under the 3:1 bar for large
   text; the way to have this legible is a dark ground, not a darker green. */

/* Solid ink, not --ink-faint. At 42% alpha the panel's dot grid and the lime
   glow underneath showed straight through the letterforms, which is what made
   this read soft as well as pale. An opaque colour fixes the sharpness and the
   contrast in one go: this is the sentence that carries the section. */
.gap__paragraph {
  max-width: 44ch;
  margin-top: 1.5em;
  color: var(--ink);
}

/* The answer, given the same treatment as the label that opens the section.
   column-reverse puts the rule above the text, so the two bookend the block:
   problem label with a rule under it, answer with a rule over it. */
.gap__payoff {
  display: flex;
  flex-flow: column-reverse;
  align-items: center;
  gap: 0.5em;
  align-self: center;
  max-width: 100%;
  margin-top: 1.1em;
  font-family: var(--font-display);
  font-size: 2.6em;
  font-weight: 800;
  letter-spacing: -0.022em;
  line-height: 1;
  color: var(--ink);
}

.gap__payoff::after {
  content: "";
  width: 2.2em;
  height: 0.11em;
  background-color: var(--lime-deep);
  border-radius: 0.11em;
}

.gap__content-text-wrap { opacity: 0.9; }

.gap__content-text-outer {
  position: absolute;
  right: 3em;
  bottom: 5em;
  transform: rotate(4deg);
}

.gap__content-text { max-width: 16ch; text-align: center; }

.gap__action {
  display: flex;
  gap: 1em;
  align-items: center;
  justify-content: center;
  padding-top: 2em;
}

/* The block is centred in a sticky 100vh panel, so it has a hard height
   budget. The longer headline runs to three lines and pushed the button past
   the bottom edge. Every size in here is em-based, so scaling the container
   scales the whole block - title, meter, button and the gaps between them -
   and keeps it inside the panel on short viewports too. */
/* The panel is exactly one viewport tall and the copy is centred inside it, so
   anything taller than the viewport spills past the bottom edge and takes the
   button with it. The type scale is driven by viewport WIDTH (1em is 16px at
   1920 but 12.6px at 1512), which means height is not accounted for anywhere:
   a 1920x900 monitor gets the largest text in the smallest box. Measured, the
   content needs 62.2em top to bottom, so cap the local em against height with
   a budget of 65em to leave clearance. This replaces four max-height steps
   that were tuned at a 12.6px base and so never fired early enough at 1920. */
/* That budget measured against the full viewport, but the panel does not show
   all of it: .gap__element carries clip-path: inset(var(--grid-margin) round
   10em), which takes a band off every edge. The column ran to the panel's full
   height, so the demo button sat inside the bottom band and was cut by 17px at
   1440x693 through 31px at 2560x993.
   --grid-margin is 1.5em of a root that is 100vw/120 above 992px, so the two
   bands are 2.5vw. Subtracting them makes the budget measure the height that
   is actually visible, and because the term is in vw it tracks the band as it
   widens rather than needing a vh number retuned per monitor. 69 over the
   content's own 66.6em is the clearance: 12px at the tightest width tested,
   50px at the loosest, cut nowhere from 1024 to 3440. */
.gap__content { font-size: min(1em, calc((100vh - 2.5vw) / 69)); }

/* Below 992px the headline is on the raw px clamp and cannot follow the
   container, so capping the container there shrinks the body copy while the
   headline holds its size and wraps further. Keep the stepped behaviour these
   widths were tuned against. */
@media (max-width: 991px) { .gap__content { font-size: 1em; } }
/* Stepped down from 0.92: the eyebrow now takes the shared section-heading size
   (3em against the old 2.1em), which the original budget was not paying for. */
@media (max-width: 991px) and (max-height: 900px) { .gap__content { font-size: 0.86em; } }
@media (max-width: 991px) and (max-height: 800px) { .gap__content { font-size: 0.86em; } }
@media (max-width: 991px) and (max-height: 700px) { .gap__content { font-size: 0.74em; } }
@media (max-width: 991px) and (max-height: 620px) { .gap__content { font-size: 0.64em; } }

/* Meter: the visual payoff of the sticky scroll — a week collapsing to a session */
.gap__meter {
  width: 46em;
  max-width: 100%;
  margin-top: 2.5em;
}

.gap__meter-track {
  position: relative;
  height: 0.7em;
  background-color: rgba(13, 13, 14, 0.12);
  border-radius: 1em;
  /* visible, so the fill's leading edge can sit proud of the track */
  overflow: visible;
}

/* The midpoint tick is the whole point of the section: Session 1 is where
   Ilara acts, Day 7 at the far end is when the report would have arrived.
   Without a mark on the track the labels underneath relate to nothing. */
.gap__meter-track::before {
  content: "";
  position: absolute;
  top: -0.4em;
  bottom: -0.4em;
  left: 50%;
  width: 0.125em;
  margin-left: -0.0625em;
  background-color: var(--ink);
  opacity: 0.28;
  border-radius: 0.125em;
}

.gap__meter-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--gap-progress, 0%);
  background: linear-gradient(90deg, var(--lime-deep), var(--lime));
  border-radius: 1em;
}

/* a head on the fill, so the eye has something to follow along the track */
.gap__meter-fill::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  width: 0.8em;
  height: 0.8em;
  margin: -0.4em -0.4em 0 0;
  background-color: var(--lime-deep);
  border: 0.14em solid var(--surface-sand);
  border-radius: 50%;
}

.gap__meter-labels {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  margin-top: 0.875em;
  font-family: var(--font-mono);
  font-size: 1.15em;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.gap__meter-labels span { transition: color 0.3s var(--ease-smooth); }
.gap__meter-labels span:first-child { justify-self: start; }
.gap__meter-labels span:nth-child(2) { justify-self: center; }
.gap__meter-labels span:last-child { justify-self: end; text-align: right; }
.gap__meter-labels .is--active { color: var(--ink); font-weight: 600; }
















/* The row nearest the middle of the viewport swaps its label for the detail */

/* Holder: the device that tracks the active row, painted behind the words */


/* Sits in the right margin rather than behind the words: an ink-coloured phone
   under ink-coloured type on lime would swallow the row it is meant to explain. */




/* --------------------------------------------------------------------------
   9. Copilot — the AI layer
   Sits directly under Features in the DOM. Features paints strong lime and
   Risk paints bone, so this takes the raised surface: the run reads
   lime -> paper -> bone rather than two saturated blocks meeting.
   Ported from the Next.js site's AIShowcase component.
   -------------------------------------------------------------------------- */

.copilot { position: relative; z-index: 1; overflow: clip; background-color: var(--surface-raised); }

.copilot__container { position: relative; z-index: 1; }

.copilot__inner { padding-top: 9em; padding-bottom: 7em; }

/* -- Two columns: what it is on the left, the thing itself on the right ---- */

/* Both tracks sized to their contents. A 1fr track here was the whole problem:
   it measured 1044px while the aside inside it was capped at 408px, so 636px
   of empty track sat between the words and the phone and the two read as
   separate objects at opposite edges rather than one composition. */
.copilot__layout {
  display: flex;
  gap: 4em;
  align-items: center;
  justify-content: space-between;
  /* Mirrors .risk__inner: the aside is capped to a five-column measure so the
     shared section-heading size wraps like every other section title instead
     of stretching a full-width track, and the phone sits at the right edge.
     Flex with a fixed gap keeps the two as one composition without leaving an
     empty grid track between them. */
}

.copilot__aside {
  display: flex;
  flex-flow: column;
  gap: 3.5em;
  flex: none;
  /* Same five-column measure as .risk__content, so the heading is sized like
     the rest of the site. */
  width: calc((var(--grid-column-width) * 5) + (var(--grid-gutter) * 4));
}

/* No cap on the header: capping it just moved the hole down a level, leaving
   the heading wrapping at 30em inside a 1044px track. The heading takes the
   track; the lines that need a measure state their own. */
.copilot__subtitle { max-width: 22ch; }
.copilot__paragraph { max-width: 46ch; }

/* Same measure discipline as .features__title: the shared heading size is
   large, and without a limit this one ran the full 46em header. 16ch broke it
   over four lines and split "co-pilot" at its own hyphen. */
/* No measure of its own: the track is the measure. At the shared heading size
   "operations." alone runs about 40em, so any ch cap tight enough to shape the
   other lines was narrower than that one word, which cannot wrap, and it
   overflowed the column and ran under the phone. */

.copilot__subtitle { margin-top: 0.75em; }

.copilot__paragraph { margin-top: 1.25em; color: var(--ink-dim); }

/* -- Transcript + stats ---------------------------------------------------- */

/* -- The photograph, and the chat on its glass ---------------------------- */

/* The phone's five-column track, mirroring .risk__visual, so the mockup is
   centred in the right half and lands at the same measure as the reference
   section's card rather than flush against the container edge. */
.copilot__visual {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: calc((var(--grid-column-width) * 5) + (var(--grid-gutter) * 4));
}

.copilot__phone {
  position: relative;
  flex: none;
  width: 30em;
  /* never wider than its five-column track: on the narrower desktop bands the
     track falls below 30em, and the mockup shrinks to fit rather than
     overflowing it and pushing the aside. */
  max-width: 100%;
  /* the cutout's own ratio, so the glass percentages below stay true */
  aspect-ratio: 566 / 1162;
}

/* The cutout itself, on its own layer so the shadow can be a filter.

   drop-shadow follows the PNG's alpha, so the shade takes the phone's rounded
   silhouette rather than the square of its box — which is the whole point; a
   box-shadow here would draw a rectangle around a photograph. Several passes,
   tight-to-wide, are what makes it read as an object resting in the light
   rather than a sticker with a blur under it: a ring, a contact shade at the
   edge, a mid falloff, and a wide ambient one.

   It carries the image (rather than the phone element carrying it) so the
   filter has nothing live inside it to re-run over. The transcript animates
   its messages in, and a filtered ancestor would re-filter the whole 30em
   mockup on every frame of that. .copilot__window sits at z-index 1 and so
   still paints above this layer. */
.copilot__phone::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("../assets/copilot-phone.png");
  background-size: contain;
  background-repeat: no-repeat;
  /* Four passes: a ring with no offset so the shade is present on the sides
     and not only under the base, then contact, mid and ambient falling
     downward. Plain literal lengths — neither calc() nor container units.
     Both said the same thing more neatly, and both are a single point of
     failure: a browser that will not resolve the value drops the whole
     declaration and there is no shadow at all rather than a smaller one.
     Restated per band below for the same reason. */
  filter:
    drop-shadow(0 0 0.5em rgba(92, 90, 86, 0.5))
    drop-shadow(0 0.25em 0.3em rgba(92, 90, 86, 0.5))
    drop-shadow(0 1em 1em rgba(92, 90, 86, 0.46))
    drop-shadow(0 2.4em 2.4em rgba(92, 90, 86, 0.38));
}

/* The glass, in plain percentages of the cutout. The phone is photographed
   straight on, so there is no perspective to solve and no transform at all:
   the screen was measured out of the image at 3.710% / 1.721% / 92.580% /
   96.558% and that holds at every size the phone is ever drawn.

   Its scale of white-on-ink values is scoped here rather than added to
   tokens.css, because nothing else on the site has a dark surface and these
   must not leak into it. */
.copilot__window {
  --panel-line: rgba(255, 255, 255, 0.14);
  --panel-text: rgba(255, 255, 255, 0.92);
  --panel-dim: rgba(255, 255, 255, 0.55);
  --panel-raised: rgba(255, 255, 255, 0.07);

  position: absolute;
  z-index: 1;
  left: 3.710%;
  top: 1.721%;
  display: flex;
  flex-flow: column;
  width: 92.580%;
  height: 96.558%;
  overflow: hidden;
  color: var(--panel-text);
  background-color: var(--ink);
  /* the glass corner is about 14% of its width; stated per axis so it stays a
     circle rather than becoming an ellipse on a tall box */
  border-radius: 14% / 6.5%;
}

/* The glass catches light in the render, so the panel has to as well or it
   reads as a rectangle pasted over a photograph. */
.copilot__window::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(202deg, rgba(255, 255, 255, 0.13), rgba(255, 255, 255, 0) 46%);
}

.copilot__screen {
  display: flex;
  flex-flow: column;
  height: 100%;
}

/* Mirrors .face__bar, which is the site's established window chrome. */
.copilot__window-bar {
  display: flex;
  flex: none;
  gap: 1em;
  align-items: center;
  justify-content: space-between;
  padding: 1em 1.5em 0.85em;
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--panel-dim);
}

.copilot__brand { display: inline-flex; gap: 0.55em; align-items: center; }

/* Sized off the bar's own type so it tracks the chrome at every breakpoint
   instead of needing its own responsive rules. */
.copilot__brand-mark { display: block; width: auto; height: 0.8em; color: var(--lime); }

/* The white pill from the header nav, borrowed at rest. Not a .button: that
   carries hover machinery and a JS hook, and this is a label. */
.copilot__brand-pill {
  padding: 0.2em 0.7em;
  font-family: var(--font-body);
  font-size: 0.85em;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--ink);
  background-color: var(--surface-card);
  border-radius: 2em;
}

/* --lime, not --lime-text: the darkened member of the family exists to be
   legible on paper, and on ink it is the one that fails. */
.copilot__window-bar strong { font-weight: 500; color: var(--lime); }

/* The scroller. min-height: 0 is what actually lets a flex child scroll rather
   than grow to fit its content and push the panel open. The bar is hidden
   because a scrollbar inside a handset mock reads as a browser, not a phone;
   nobody drags this, the script drives it. */
.copilot__threads {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0.5em 1.25em 1.5em;
  scrollbar-width: none;
}

.copilot__threads::-webkit-scrollbar { display: none; }

.copilot__thread {
  display: flex;
  flex-flow: column;
  gap: 0.75em;
  padding: 0 0 1.25em;
  list-style: none;
}

/* A spent exchange, waiting at the back of the queue for its turn to come
   round again. It has to take up no room at all: the script moves these while
   the panel is mid-drift, and a thread that still owns its padding shifts
   everything below it the moment it is moved. `ol` is not in the reset at the
   top of the file, so the browser's own margin has to go here too. */
.copilot__thread.is--empty { margin: 0; padding: 0; }

/* Hidden only once the script is driving. Without JS every message is simply
   there, and the panel scrolls the way any transcript would. */
.copilot__msg { display: flex; }

/* display, not opacity. An unsent message left in the flow at opacity 0 still
   occupies its slot, so the scroller measured all twenty from the start and
   following the conversation to the bottom landed in empty space under it.
   An animation rather than a transition because display: none to flex does not
   transition, but it does restart an animation. */
.copilot__window.is--live .copilot__msg { display: none; }

.copilot__window.is--live .copilot__msg.is--in {
  display: flex;
  animation: copilot-msg-in 0.35s var(--ease-soft-bounce) both;
}

@keyframes copilot-msg-in {
  from { opacity: 0; transform: translateY(0.75em); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .copilot__window.is--live .copilot__msg.is--in { animation: none; }
}

.copilot__msg.is--user { justify-content: flex-end; }

/* Voices split by font: a person and the answer they get are prose, anything
   the machine emits on the way is mono. */
.copilot__bubble {
  max-width: 85%;
  padding: 0.75em 1em;
  border-radius: 1.125em;
  font-size: var(--font-size-paragraph-extra-small);
  line-height: 1.45;
  letter-spacing: -0.01em;
}

/* The person speaking is now the light bubble, the machine the dark one. */
.copilot__msg.is--user .copilot__bubble {
  color: var(--ink);
  background-color: var(--surface-raised);
  /* the squared corner is the tail: it points back at who is speaking */
  border-bottom-right-radius: 0.3em;
  /* holds the bubble's box while the text types in, so it grows sideways
     instead of the whole panel jumping on every character */
  min-height: 1.45em;
}

.copilot__msg.is--assistant .copilot__bubble {
  color: var(--panel-text);
  background-color: var(--panel-raised);
  border-bottom-left-radius: 0.3em;
}

/* Ilara volunteering something nobody asked for. Outlined rather than filled,
   so it reads as a note in the margin of the answer above it instead of a
   second reply, and labelled because a visitor skimming the section has to be
   able to tell at a glance that it was not requested. */
.copilot__msg.is--nudge .copilot__bubble {
  background-color: transparent;
  border: 1px solid rgba(163, 230, 53, 0.35);
}

.copilot__nudge-label {
  display: block;
  margin-bottom: 0.4em;
  /* relative to the bubble, which already sets a size: an absolute token here
     would compound against it */
  font-size: 0.78em;
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--lime);
}

.copilot__bubble.is--status {
  display: inline-flex;
  gap: 0.6em;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  color: var(--panel-dim);
  background-color: var(--panel-raised);
  border-bottom-left-radius: 0.3em;
}

.copilot__dots { display: inline-flex; flex: none; gap: 0.25em; }

.copilot__dots i {
  width: 0.35em;
  height: 0.35em;
  background-color: var(--panel-dim);
  border-radius: 50%;
  animation: copilot-dot 1.2s var(--ease-smooth) infinite;
}

.copilot__dots i:nth-child(2) { animation-delay: 0.15s; }
.copilot__dots i:nth-child(3) { animation-delay: 0.3s; }

@keyframes copilot-dot {
  0%, 60%, 100% { opacity: 0.3; transform: none; }
  30%           { opacity: 1;   transform: translateY(-0.22em); }
}

@media (prefers-reduced-motion: reduce) {
  .copilot__dots i { animation: none; opacity: 0.6; }
}

.copilot__msg.is--tools { flex-flow: wrap; gap: 0.5em; }

.copilot__tool {
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  letter-spacing: 0.02em;
  color: var(--lime);
  background-color: rgba(163, 230, 53, 0.12);
  border: 1px solid rgba(163, 230, 53, 0.32);
  border-radius: 0.375em;
  padding: 0.3em 0.7em;
}

/* -- Stats ----------------------------------------------------------------- */

/* The bar that holds the composition together. Sat inside the left column the
   figures were a third list under a heading and a paragraph; spanning the full
   width beneath both columns they become a base line that the words and the
   phone both stand on, and the section reads as one thing. */
.copilot__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 5em;
  border-top: 1px solid var(--line);
  list-style: none;
}

.copilot__stat {
  display: flex;
  flex-flow: column;
  gap: 0.375em;
  padding: 2em 1.5em 0;
  border-left: 1px solid var(--line);
}

.copilot__stat:first-child { border-left: 0; padding-left: 0; }

.copilot__stat-value {
  font-family: var(--font-display);
  font-size: var(--font-size-heading-s);
  font-weight: 900;
  letter-spacing: -0.025em;
  line-height: 1;
  /* --lime is a surface here, not a text colour: on the raised paper it fails
     contrast. --lime-text is the readable member of the family. */
  color: var(--lime-text);
}

.copilot__stat-label {
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* -- Domain ribbon --------------------------------------------------------- */

/* The list of domains rides the same angled strip the page opens with. The
   markup is .band verbatim, so everything that makes the ribbon -- the
   rotation, the oversized inner that keeps its corners off the page edge, the
   ground, the shapes behind the type, the marquee -- is inherited rather than
   restated. Only two things are set here, and neither is the strip itself.

   .band paints its own ground in --surface because it separates two sections
   that both use it. Here it sits inside the copilot, which is already raised,
   so it takes the surface it is standing on instead of laying a second one.
   Both selectors carry one class and .band is written further down the file,
   so this one has to name both to win. */
.band.copilot__band { background-color: transparent; }

/* .band__inner carries 9em top and bottom because the band is a section in
   its own right. This one closes a section that has already spent 7em below
   the stats, so the space above it is that padding and only the space beneath
   is its own. */
.copilot__band .band__inner { padding-top: 1.5em; padding-bottom: 5em; }

/* --------------------------------------------------------------------------
   Case studies
   -------------------------------------------------------------------------- */

/* A case study used to be a PDF and a click downloaded it, which ended the
   visit: no header, no footer, nothing to go back to. It is now a page like
   any other, built from the same source the PDF is set from, so the words are
   the same words. The file is still there, offered as a download rather than
   served as the only option.

   Embedding the PDF instead was the obvious move and the wrong one: a reader
   got paginated sheets, page furniture repeated at every break, and a second
   page holding one line -- a document viewer sitting inside a website rather
   than a part of one. */
.paper__note {
  display: flex;
  flex-flow: row wrap;
  gap: 1em 1.5em;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 2.5em;
  padding-bottom: 1.5em;
  border-bottom: 1px solid var(--line);
}

.paper__label {
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.paper__actions { display: flex; flex-flow: row wrap; gap: 1.25em; align-items: center; }

.paper__open {
  font-family: var(--font-mono);
  font-size: var(--font-size-note-regular);
  letter-spacing: 0.02em;
  color: var(--ink-dim);
  transition: color 0.25s var(--ease-smooth);
}

.paper__open:hover { color: var(--ink); }

/* `.article a` keeps links in prose the colour of the text around them, and it
   also catches the download button, painting its label the same near-black as
   the pill behind it. Hand the button back its own colour. */
.paper__note .button-alt { color: var(--button-alt-color); }

/* the download glyph is square, unlike the arrow the button normally carries */
.button-alt__icon.is--download { width: 0.9375em; height: 0.9375em; }

/* The source note the PDF carries at its foot, kept on the page so the two
   say the same thing about what was cleared for use. */
.article .article__foot {
  margin-top: 2.5em;
  padding-top: 1.25em;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.9375em;
  line-height: 1.6;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
}

@media (max-width: 767px) {
  .paper__note { margin-bottom: 2em; }
  .paper__actions { width: 100%; justify-content: space-between; }
}

/* --------------------------------------------------------------------------
   Copilot — tablet and phone
   -------------------------------------------------------------------------- */

@media (max-width: 991px) {
  .copilot__inner { padding-top: 5.5em; padding-bottom: 4.5em; }
  .copilot__header { max-width: 100%; }

  .copilot__layout { flex-flow: column; gap: 3em; }
  .copilot__aside { gap: 2.5em; width: 100%; }
  .copilot__visual { width: 100%; }

  /* Straight on and in percentages, the phone survives every width: it just
     gets smaller and the glass keeps its share of it. Only the em-to-pixel
     ratio changes per band, which is why the width is still restated. */
  .copilot__phone { width: 26em; margin: 0 auto; }

  /* the shadow's share of the phone, restated for this width */
  .copilot__phone::before {
    filter:
      drop-shadow(0 0 0.42em rgba(92, 90, 86, 0.5))
      drop-shadow(0 0.2em 0.26em rgba(92, 90, 86, 0.5))
      drop-shadow(0 0.9em 0.9em rgba(92, 90, 86, 0.46))
      drop-shadow(0 2.1em 2.1em rgba(92, 90, 86, 0.38));
  }

  .copilot__threads { padding: 0.5em 1em 1.25em; }
  .copilot__thread { gap: 0.625em; padding-bottom: 1em; }
  .copilot__bubble { max-width: 90%; }

  /* The stats are a grid at every width, so they stay a row here and only the
     breathing room shrinks. The old rules in this place set flex properties on
     a grid container, which did nothing, and zeroed padding-top on every stat
     but the first -- which left the first figure sitting 2em below its own
     row. Uniform padding is the whole fix. */
  .copilot__stat { gap: 0.3em; padding: 1.5em 1.25em 0; }

  .copilot__band .band__inner { padding-bottom: 3em; }
}

/* Under ~740px a third of the line is narrower than the word CONVERSATION,
   and a single word cannot wrap, so the row overflows the section rather than
   reflowing. Below this width the figures become a short stacked list --
   value and label share a baseline, and the hairline that divided the columns
   turns to run across the flow instead. */
@media (max-width: 767px) {
  .copilot__stats { grid-template-columns: minmax(0, 1fr); }

  .copilot__stat {
    flex-flow: row;
    align-items: baseline;
    gap: 0.6em;
    padding: 1.1em 0;
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  /* the list already sits under the container's own rule */
  .copilot__stat:first-child { border-top: 0; }
}

@media (max-width: 479px) {
  /* The mockup survives here too now. Straight on it is a portrait object
     rather than a wide one, so a handset column still fits it, and the glass
     lands around 290px across: wider than the angled render managed beside a
     desktop heading. */
  .copilot__phone { width: 20em; }

  .copilot__phone::before {
    filter:
      drop-shadow(0 0 0.32em rgba(92, 90, 86, 0.5))
      drop-shadow(0 0.16em 0.2em rgba(92, 90, 86, 0.5))
      drop-shadow(0 0.7em 0.7em rgba(92, 90, 86, 0.46))
      drop-shadow(0 1.6em 1.6em rgba(92, 90, 86, 0.38));
  }
}

/* --------------------------------------------------------------------------
   10. Proof — orbiting stats
   -------------------------------------------------------------------------- */

.proof {
  position: relative;
  display: flex;
  width: 100%;
}

.proof__container { display: flex; width: 100%; }

.proof__inner {
  position: relative;
  width: 100%;
  background-color: var(--surface-soft);
  clip-path: inset(0 round 0 0 10em 10em);
}

.proof__content {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 1.25em;
  align-items: center;
  justify-content: center;
  padding-top: 6em;
  padding-bottom: 2.5em;
  user-select: none;
}

.proof__logo-text { max-width: 100%; text-align: center; }

.proof__logo-text .u-heading-m { display: block; }
.proof__logo-text .is--lime { color: #8dc039; }   /* same softened lime as the
   gap headline, so the two big green lines on the page match. 1.90:1 on this
   panel, down from 4.26:1: Ismaeel's call, consistent with that headline. */

.proof__content { flex-flow: column; }
.proof__subtitle { max-width: 40ch; margin-top: 0.75em; text-align: center; color: var(--ink-dim); }

/* The mark was a circular badge beside the heading; it sat at the cap-height of
   a two-line title and aligned to neither line. The section already carries the
   brand in the lime "Real Impact.", so a lime rule replaces it. */
.proof__logo-text::before {
  content: "";
  display: block;
  width: 3.5em;
  height: 0.28em;
  margin: 0 auto 1.1em;
  border-radius: 0.14em;
  background-color: var(--lime-deep);
}

.proof__table-wrap {
  position: relative;
  z-index: 1;
  width: calc((var(--grid-column-width) * 8) + (var(--grid-gutter) * 7));
  margin: 0 auto;
  padding-bottom: 6em;
}








.proof__bg {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  color: #f3fade;
  pointer-events: none;
}

.proof__bg-svg { width: 100%; height: auto; overflow: visible !important; }
.proof__bg-svg.is--mobile { display: none; }

/* --------------------------------------------------------------------------
   11. FAQ
   -------------------------------------------------------------------------- */

.faq { position: relative; z-index: 1; background-color: var(--surface-raised); }

.faq__container { position: relative; z-index: 1; }

.faq__inner { padding-bottom: 5.3125em; }

.faq__header {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-top: 14em;
  padding-bottom: 2em;
  text-align: center;
}

.faq__content {
  display: flex;
  flex-flow: column;
  gap: 1em;
  align-items: center;
  justify-content: center;
  width: calc((var(--grid-column-width) * 6) + (var(--grid-gutter) * 5));
  margin-left: auto;
  margin-right: auto;
}

.faq__bg {
  position: absolute;
  top: 6.25em;
  left: 0;
  right: 0;
  z-index: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  color: #eff8dd;
  pointer-events: none;
}

.faq__bg-svg { width: 100%; height: auto; overflow: visible !important; }
.faq__bg-svg.is--mobile { display: none; }

.faq__action { display: flex; justify-content: center; padding-top: 1.5em; }

.accordion {
  width: 100%;
  background-color: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: 1.25em;
  transition: border-color 0.35s var(--ease-smooth), background-color 0.35s var(--ease-smooth);
}

.accordion.is--open { border-color: var(--lime-deep); background-color: var(--surface-card); }
.accordion:hover { border-color: var(--line-strong); }

.accordion__toggle {
  display: flex;
  gap: 1.5em;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 1.5em 1.75em;
  text-align: left;
}

.accordion__title { font-weight: 600; }

.accordion__icon {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 2.5em;
  height: 2.5em;
  color: var(--ink);
  background-color: var(--lime);
  border-radius: 50%;
}

.accordion__icon svg { grid-area: 1 / 1; width: 0.875em; height: 0.875em; }
.accordion__icon-minus { opacity: 0; }
.accordion.is--open .accordion__icon-plus { opacity: 0; }
.accordion.is--open .accordion__icon-minus { opacity: 1; }
.accordion__icon-plus,
.accordion__icon-minus { transition: opacity 0.25s linear; }

.accordion__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s var(--ease-smooth);
}

.accordion.is--open .accordion__panel { grid-template-rows: 1fr; }

.accordion__panel-inner { overflow: hidden; }

.accordion__paragraph {
  padding: 0 4.5em 1.75em 1.75em;
  color: var(--ink-dim);
}

.accordion__paragraph a { color: var(--lime-text); text-decoration: underline; text-underline-offset: 0.2em; }

/* --------------------------------------------------------------------------
   12. Risk — see it on your data first
   -------------------------------------------------------------------------- */

.risk { position: relative; z-index: 1; background-color: var(--surface); }

.risk__inner {
  display: flex;
  gap: 4em;
  align-items: center;
  justify-content: flex-start;
  padding-top: 11em;
  padding-bottom: 11em;
  padding-left: calc((var(--grid-column-width) * 1) + (var(--grid-gutter) * 0));
}

.risk__content {
  display: flex;
  flex-flow: column;
  gap: 1.5em;
  align-items: flex-start;
  width: calc((var(--grid-column-width) * 5) + (var(--grid-gutter) * 4));
}

.risk__paragraph { color: var(--ink-dim); }
.risk__paragraph strong { font-weight: 600; color: var(--ink); }

.risk__visual {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc((var(--grid-column-width) * 5) + (var(--grid-gutter) * 4));
}

.risk__visual-stage { position: relative; width: 26em; }

/* --------------------------------------------------------------------------
   13. The Ilara Difference — its own section
   -------------------------------------------------------------------------- */

.diff { position: relative; z-index: 1; background-color: var(--surface-raised); }

.tagline-curve {
  padding-top: 1.5em;
  margin-bottom: -3em;
  overflow-x: clip;
}

.tagline-curve__svg {
  width: 100%;
  height: auto;
  color: var(--ink);
  transform: translateY(50%) scale(1.1);
  overflow: visible !important;
}

.tagline-curve__svg text {
  font-family: var(--font-display);
  /* 11.625em set the phrase ~1901 units wide inside a 1920 viewBox, and the
     1.1 scale above crops the visible band to ~1745, so it overflowed at every
     offset. 10em fits the whole line on screen with room either side. */
  font-size: 10em;
  font-weight: 900;
  letter-spacing: -0.035em;
  fill: currentColor;
}

.tagline-curve__title { font-size: 6em; }

.diff__inner {
  padding-top: 7em; /* clears the curved tagline, which dips into this block */
  padding-bottom: 10em;
}

.diff__eyebrow { padding-top: 6em; text-align: center; }

/* three abreast now that the section is its own */
.diff__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25em;
  width: 100%;
}

.diff__list-item {
  display: flex;
  flex-flow: column;
  gap: 0.625em;
  padding: 2em 2em 2.25em;
  background-color: var(--surface-card);
  border: 1px solid var(--line);
  border-top: 0.375em solid var(--lime);
  border-radius: 1.25em;
  box-shadow: 0 0.75em 2em rgba(13, 13, 14, 0.05);
  transition: border-color 0.35s var(--ease-smooth), box-shadow 0.35s var(--ease-smooth);
}

.diff__list-item:hover {
  border-color: var(--line-strong);
  border-top-color: var(--lime);
  box-shadow: 0 1.5em 3em rgba(13, 13, 14, 0.1);
}

/* Reserve two lines (line-height 1.2) so the three "we do this" answers start
   on the same baseline whether or not the claim above them wraps. */
.diff__list-title { min-height: 2.4em; font-weight: 700; }
.diff__list-paragraph { color: var(--ink-dim); }

/* --------------------------------------------------------------------------
   Insights — blog article cards
   -------------------------------------------------------------------------- */

.insights__subtitle { max-width: 44ch; margin-top: 0.75em; color: var(--ink-dim); }

.insights__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5em;
  width: 100%;
  padding: 0;
  margin: 0;
  list-style: none;
}

.insights__card { display: flex; }

.insights__card-inner {
  display: flex;
  text-decoration: none;
  flex-flow: column;
  width: 100%;
  overflow: hidden;
  background-color: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: 1.25em;
  box-shadow: 0 0.75em 2em rgba(13, 13, 14, 0.05);
  transition: border-color 0.35s var(--ease-smooth), box-shadow 0.35s var(--ease-smooth),
    transform 0.35s var(--ease-smooth);
}

.insights__card-inner:hover {
  border-color: var(--line-strong);
  box-shadow: 0 1.5em 3em rgba(13, 13, 14, 0.1);
  transform: translateY(-0.25em);
}

.insights__card-body {
  display: flex;
  flex-flow: column;
  gap: 0.5em;
  flex: 1;
  padding: 1.5em;
}

/* the tag is what tells a reader these are articles, not more stats */
.insights__card-tag {
  align-self: flex-start;
  padding: 0.35em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.8125em;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  background-color: var(--lime);
  border-radius: 2em;
}

.insights__card-title {
  font-family: var(--font-display);
  font-size: 1.5em;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.06;
  color: var(--ink);
}

.insights__card-excerpt { font-size: 1.0625em; line-height: 1.35; color: var(--ink-dim); }

/* One pill colour across all six. The per-column amber and rose accents were
   there to separate three stat covers from each other; with the covers gone
   they only made six otherwise identical cards look inconsistent. The tag
   keeps its default lime, and Article vs Case study does the sorting. */

/* --------------------------------------------------------------------------
   Article pages
   -------------------------------------------------------------------------- */

/* Article pages wear the site's furniture: real header and footer, and the
   same stacked rounded blocks the sections use. */
/* The footer is pulled up by -10em so the preceding section tucks under its
   curve. That section has to paint over the tuck or the footer covers its last
   10em of content -- .faq does this on the homepage with the same two lines.
   Without them the about, privacy and article pages lose their final block
   under the lime. */
.article { display: block; position: relative; z-index: 1; background-color: var(--surface); }

.article__hero {
  /* Same construction as the site's hero: a lime field, a lighter blob layer
     and the faint grid over it, rather than a flat panel. */
  position: relative;
  overflow: hidden;
  background-color: var(--lime);
  clip-path: inset(0 round 0 0 2.5em 2.5em);
}

.pagehero__bg { color: #c1ed77; }
.pagehero__grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(13, 13, 14, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(13, 13, 14, 0.055) 1px, transparent 1px);
  background-size: 5em 5em;
}

/* copy sits above the blob and grid layers */
.article__hero .article__container,
.legal__hero .legal__container { position: relative; z-index: 1; }
.article__hero .article__container {
  padding-top: calc(var(--header-height) + 3em);
  padding-bottom: 3.5em;
}

.article__body .article__container { padding-top: 3em; padding-bottom: 6em; }

.article__container { max-width: 46em; margin: 0 auto; }
.article .article__tag {
  display: inline-block;
  padding: 0.35em 0.75em;
  margin-bottom: 1.5em;
  font-family: var(--font-mono);
  font-size: 0.8125em;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--lime);
  background-color: var(--ink);
  border-radius: 2em;
}
/* u-heading-l is a section-header size; an article headline is a sentence and
   at 6.5em it filled the viewport before the standfirst */
.article__title {
  margin-bottom: 0.4em;
  font-size: 3.25em;
  line-height: 1.02;
  letter-spacing: -0.03em;
}
.article .article__standfirst { max-width: 44ch; font-size: 1.25em; line-height: 1.4; color: rgba(13, 13, 14, 0.72); }
.article .article__meta {
  margin-top: 1.25em; padding-bottom: 2em;
  font-family: var(--font-mono); font-size: 0.8125em; letter-spacing: 0.04em;
  text-transform: uppercase; color: rgba(13, 13, 14, 0.55);
  border-bottom: 1px solid rgba(13, 13, 14, 0.18);
}
.article h2 {
  margin-top: 2.25em; margin-bottom: 0.5em;
  font-family: var(--font-display); font-size: 1.75em; font-weight: 800;
  letter-spacing: -0.025em; line-height: 1.1; color: var(--ink);
}
.article p { margin-bottom: 0.95em; font-size: 1.0625em; line-height: 1.55; color: var(--ink-dim); }
.article p strong { color: var(--ink); }
.article ul { padding-left: 1.2em; margin-bottom: 0.95em; color: var(--ink-dim); }
.article li { margin-bottom: 0.45em; font-size: 1.0625em; line-height: 1.5; }
.article a { color: var(--ink); }

/* the number the section turns on, pulled out of the prose */
.article__pull {
  margin: 1.5em 0;
  padding: 1.25em 1.5em;
  background-color: var(--surface-raised);
  border-left: 0.25em solid var(--lime-deep);
  border-radius: 0 0.75em 0.75em 0;
}
.article .article__pull-figure {
  font-family: var(--font-display); font-size: 2.75em; font-weight: 900;
  letter-spacing: -0.04em; line-height: 1; color: var(--ink);
}
.article .article__pull-note { margin-top: 0.4em; font-size: 1em; color: var(--ink-dim); }

/* every claim that needs a caveat carries it in the open */
.article__caveat {
  margin: 1.5em 0; padding: 1.1em 1.35em;
  font-size: 0.9375em; line-height: 1.5; color: var(--ink-dim);
  background-color: rgba(13, 13, 14, 0.035);
  border: 1px solid var(--line); border-radius: 0.75em;
}
.article__caveat strong { color: var(--ink); }

.article__back {
  display: block; width: fit-content; margin-bottom: 2em;
  font-family: var(--font-mono); font-size: 0.875em; letter-spacing: 0.04em;
  text-transform: uppercase; text-decoration: none; color: var(--ink-dim);
}
.article__back:hover { color: var(--ink); }
.article__back.is--bottom { margin-top: 3em; margin-bottom: 0; }

@media screen and (max-width: 991px) {
  .article__hero { clip-path: inset(0 round 0 0 1.75em 1.75em); }
  .article__hero .article__container { padding-top: calc(var(--header-height) + 1.5em); padding-bottom: 2.25em; }
  .article__body .article__container { padding-top: 2.25em; padding-bottom: 4em; }
  .article h2 { font-size: 1.5em; }
  .article__title { font-size: 2.35em; }
  .article .article__pull-figure { font-size: 2.25em; }
}

/* --------------------------------------------------------------------------
   Legal pages
   -------------------------------------------------------------------------- */

/* Same footer tuck as .article above -- privacy.html uses .legal, so it needs
   the guard too or the footer covers its closing note. */
.legal { display: block; position: relative; z-index: 1; background-color: var(--surface); }
/* same stacked-block treatment the article pages use */
.legal__hero { position: relative; overflow: hidden; background-color: var(--lime); clip-path: inset(0 round 0 0 2.5em 2.5em); }
.legal__hero .legal__container { padding-top: calc(var(--header-height) + 3em); padding-bottom: 3.5em; }
.legal__body .legal__container { padding-top: 3em; padding-bottom: 6em; }
.legal__container { max-width: 46em; margin: 0 auto; }
.legal .legal__tag {
  display: inline-block; padding: 0.35em 0.75em; margin-bottom: 1.25em;
  font-family: var(--font-mono); font-size: 0.8125em; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--lime); background-color: var(--ink); border-radius: 2em;
}

.legal__back {
  display: block;
  width: fit-content;
  margin-bottom: 2em;
  font-family: var(--font-mono);
  font-size: 0.875em;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-dim);
}
.legal__back:hover { color: var(--ink); }
.legal__back.is--bottom { margin-top: 3em; margin-bottom: 0; }

.legal__title { margin-bottom: 0.5em; }
.legal__lead { max-width: 46ch; color: rgba(13, 13, 14, 0.72); }

.legal__meta {
  margin-top: 1em;
  font-family: var(--font-mono);
  font-size: 0.8125em;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.legal__h2 {
  margin-top: 2.25em;
  margin-bottom: 0.5em;
  font-family: var(--font-display);
  font-size: 1.75em;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: var(--ink);
}

.legal p { max-width: 62ch; margin-bottom: 0.9em; line-height: 1.5; color: var(--ink-dim); }
.legal p strong { color: var(--ink); }
.legal a { color: var(--ink); text-underline-offset: 0.2em; }

.legal__list { max-width: 62ch; padding-left: 1.2em; margin-bottom: 0.9em; color: var(--ink-dim); }
.legal__list li { margin-bottom: 0.4em; line-height: 1.5; }

.legal code {
  padding: 0.1em 0.35em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  background-color: rgba(13, 13, 14, 0.06);
  border-radius: 0.3em;
}

/* anything still needing a real answer from the founder, marked so it cannot
   ship unnoticed */
.legal__todo {
  display: inline;
  padding: 0.1em 0.4em;
  background-color: rgba(163, 230, 53, 0.35);
  border-radius: 0.3em;
  color: var(--ink);
}

.legal__note {
  margin-top: 2.5em;
  padding: 1.25em 1.5em;
  font-size: 0.9375em;
  background-color: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: 1em;
}

@media screen and (max-width: 991px) {
  .legal__hero { clip-path: inset(0 round 0 0 1.75em 1.75em); }
  .legal__hero .legal__container { padding-top: calc(var(--header-height) + 1.5em); padding-bottom: 2.25em; }
  .legal__body .legal__container { padding-top: 2.25em; padding-bottom: 4em; }
  .legal__h2 { font-size: 1.5em; }
}

/* --------------------------------------------------------------------------
   Closing CTA — its own block in the document, ahead of the FAQ
   -------------------------------------------------------------------------- */

.cta {
  position: relative;
  z-index: 1;
  background-color: var(--lime);
  clip-path: inset(0 round 10em 10em 0 0);
}

.cta__inner {
  display: flex;
  flex-flow: column;
  gap: 1.25em;
  align-items: center;
  justify-content: center;
  padding-top: 9em;
  padding-bottom: 9em;
  text-align: center;
}

/* The heading scale jumps 2.5em to 5em between s and m, so stepping the
   utility class up would double this rather than nudge it. Sized explicitly
   between the two, with the rule above it that the gap section already uses to
   mark a line as the point of the block. */
.cta__title {
  display: flex;
  flex-flow: column;
  align-items: center;
  gap: 0.42em;
  max-width: 20ch;
  font-size: 3.25em;
  letter-spacing: -0.028em;
  line-height: 1;
}

.cta__title::before {
  content: "";
  width: 2.2em;
  height: 0.1em;
  background-color: var(--ink);
  border-radius: 0.1em;
}
.cta__paragraph { max-width: 44ch; color: rgba(13, 13, 14, 0.72); }
.cta__inner .button-alt { margin-top: 0.75em; }

/* Closer form — the lead capture that replaced the single mailto button. Sits
   on the lime CTA, so the inputs carry their own raised surface for contrast. */
/* Longer, not fatter: the row was 48em wide with 1.05em of vertical padding,
   giving 194x56px fields that read as squat. Widen the row and take the
   height back out of the padding. */
.closer { width: 100%; max-width: 64em; margin-top: 1em; text-align: left; }

.closer__row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.875em;
}

.closer__field { display: flex; flex-flow: column; gap: 0.4em; }

.closer__label {
  font-family: var(--font-mono);
  font-size: 0.8125em;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(13, 13, 14, 0.66);
}

/* `font: inherit` gave these body size, 12.6px at 1512, which is smaller than
   the paragraph above them and left a 42px field beside a 55px button. Sized off
   the fluid scale instead so the field matches the button and clears the 44px
   touch target. Padding is em, so it tracks the new size. */
.closer__input {
  width: 100%;
  padding: 0.9em 1.1em;
  font: inherit;
  font-size: var(--font-size-paragraph-small);
  color: var(--ink);
  background-color: var(--surface-raised);
  border: 1px solid rgba(13, 13, 14, 0.16);
  border-radius: 0.75em;
  transition: border-color 0.25s var(--ease-smooth), box-shadow 0.25s var(--ease-smooth);
}

.closer__input:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 0.16em rgba(13, 13, 14, 0.16);
}

.closer__input.is--invalid { border-color: #b3261e; }

/* honeypot: off-screen for people, fillable by bots */
.closer__hp {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* stacked rather than a centred row: with the status beside it, the button
   would jump off-centre the moment a message appeared */
.closer__actions {
  display: flex;
  flex-flow: column;
  gap: 0.8em;
  align-items: center;
  margin-top: 1.15em;
}

/* the submit reuses .button-alt so it inherits the shared hover animation;
   <button> needs the resets an <a> got for free */
button.button-alt { border: none; cursor: pointer; font-size: inherit; }
button.button-alt[disabled] { opacity: 0.55; cursor: default; }
button.button-alt[disabled] .button-alt__icon-outer { transform: none; }
/* oval: the radius is a token on the component, so overriding it here rounds
   both the label block and the arrow block without touching other buttons */
.closer__actions .button-alt { margin-top: 0; --button-alt-border-radius: 10em; }

.closer__status {
  min-height: 1.4em;
  text-align: center;
  font-size: 0.9375em;
  color: rgba(13, 13, 14, 0.72);
}

.closer__status.is--error { color: #7a1b16; }

/* --------------------------------------------------------------------------
   13. Band — scrolling quote
   -------------------------------------------------------------------------- */

.band { position: relative; z-index: 2; background-color: var(--surface); overflow-x: clip; }

/* The original lime strip, angled. The rotation is the only change: the inner
   is oversized and shifted so turning it never exposes a corner of the page. */
.band__inner {
  width: 108%;
  margin-left: -4%;
  padding-top: 9em;
  padding-bottom: 9em;
  transform: rotate(-2.4deg);
  overflow-x: clip;
}

.band__item {
  display: inline-grid;
  width: calc(100% + 6em);
  margin-left: -3em;
  color: var(--ink);
}

.band__item-title {
  font-family: var(--font-display);
  font-size: 4em;
  font-weight: 900;
  letter-spacing: -0.035em;
  line-height: 1.05;
  white-space: nowrap;
}

.band__item-title-outer {
  z-index: 1;
  grid-area: 1 / 1;
  place-self: center;
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  padding-top: 2.875em;
  padding-bottom: 2.875em;
}

.band__item-title-outer .marquee { align-items: center; }

.band__item-bg {
  position: relative;
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  overflow: clip;
  color: rgba(13, 13, 14, 0.14);
  background-color: var(--lime);
}

.band__item-bg.is--dark {
  color: rgba(13, 13, 14, 0.1);
  background-color: var(--amber);
}

.band__item.is--second { color: var(--ink); }

.band__item-bg-svg {
  position: absolute;
  top: -1px;
  bottom: -1px;
  left: 0;
  width: auto;
  height: calc(100% + 2px);
}

.marquee {
  display: flex;
  width: 100%;
  overflow: hidden;
  mask-image: none;
}

.marquee__track {
  display: flex;
  flex: none;
  gap: 0;
  align-items: center;
  will-change: transform;
}

.marquee__item { flex: none; padding-right: 1.5em; }

/* The separator on a ribbon. A vertical rule rather than a bullet or a slash:
   at 900 weight a bullet reads as a full stop and a slash as a fraction, while
   a bar just divides. It sits lighter and dimmer than the words so it separates
   without being read as one of them.

   Its margins are the only space between items, and every item carries one at
   its end too — so the join where the track loops is the same width as every
   other join. That also means these items must not keep .marquee__item's
   trailing padding, or the seam would be a gap wider than the rest again. */
.band__item-title.marquee__item { padding-right: 0; }

.band__item-sep {
  margin: 0 0.5em;
  font-weight: 700;
  color: rgba(13, 13, 14, 0.45);
}

/* --------------------------------------------------------------------------
   14. Case study
   -------------------------------------------------------------------------- */

.case { position: relative; overflow: clip; margin-top: -5em; background-color: var(--surface-sand); }

.case__container { position: relative; z-index: 1; }

.case__header {
  position: relative;
  padding-top: 7.5em;
  padding-bottom: 7.5em;
  text-align: center;
}

.case__header-content {
  display: flex;
  flex-flow: column;
  gap: 1.5em;
  align-items: center;
  justify-content: center;
}

.case__title { max-width: 22ch; }
.case__paragraph { max-width: 42ch; color: var(--ink-dim); }

.case__visual { position: absolute; top: 11.1875em; left: 10.625em; }
.case__visual-img { width: 9em; height: auto; opacity: 0.9; }

.case__content { padding-bottom: 10.8125em; }

.case__table-wrap {
  position: relative;
  z-index: 1;
  width: calc((var(--grid-column-width) * 10) + (var(--grid-gutter) * 9));
  margin: 0 auto;
}

















.case__rain-container {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  user-select: none;
  pointer-events: none;
}

.case__rain-item {
  position: absolute;
  width: max(140px, 7vw);
  font-family: var(--font-mono);
  font-size: 1.25em;
  font-weight: 500;
  color: rgba(13, 13, 14, 0.13);
  white-space: nowrap;
  will-change: transform;
}

.case__rain-item.is--hidden { opacity: 0; }

/* --------------------------------------------------------------------------
   15. Insights
   -------------------------------------------------------------------------- */

.insights {
  position: relative;
  z-index: 1;
  overflow: clip;
  background-color: var(--surface);
  clip-path: inset(0 round 0 0 10em 10em);
}

.insights__inner { padding-bottom: 11.875em; }

/* Matches .features__header: the top padding sits the large heading off the
   section above, the bottom padding is the gap down to the cards. */
.insights__header {
  position: relative;
  padding-top: 13.75em;
  padding-bottom: 3.5em;
  text-align: center;
}

.insights__header-content {
  display: flex;
  flex-flow: column;
  gap: 1.5em;
  align-items: center;
  justify-content: center;
}

.insights__title { max-width: 18ch; }
.insights__paragraph { max-width: 40ch; color: var(--ink-dim); }

.insights__list {
  display: flex;
  align-items: stretch;
  justify-content: flex-start;
  /* The track has to be a real scroll container: swipe, pointer drag and the
     prev/next buttons all move it via scrollLeft, and without overflow that
     assignment is silently ignored. This only existed under 991px, so on
     desktop the second and third cards could not be reached at all. */
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}

.insights__list::-webkit-scrollbar { display: none; }

.insights__list-item { flex: none; width: 77.625em; scroll-snap-align: center; }

.insights__item { position: relative; user-select: none; }

.insights__item-outer {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding-top: 1.875em;
  padding-bottom: 5.75em;
  border: 1em solid var(--surface);
  border-radius: 5em;
}

.insights__item-inner {
  display: grid;
  width: 26em;
}

.insights__item-cover {
  position: relative;
  aspect-ratio: 320 / 493;
  width: 100%;
  overflow: clip;
  border-radius: 1.5em;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(163, 230, 53, 0.5), transparent 62%),
    linear-gradient(180deg, var(--surface) 0%, var(--surface-raised) 100%);
}

.insights__item-cover .tile {
  position: absolute;
  inset: 0;
  border: 0;
  border-radius: inherit;
  box-shadow: none;
}

.insights__item-text {
  display: flex;
  flex-flow: column;
  gap: 0.75em;
  padding-top: 1.25em;
}

.insights__item-title { color: var(--ink); }
.insights__item-paragraph { color: var(--ink-dim); }

.insights__meta {
  position: absolute;
  right: 8.25em;
  bottom: 8.5em;
  display: flex;
  flex-flow: column;
  gap: 0.5em;
  align-items: flex-start;
  justify-content: flex-start;
  width: 15em;
  padding: 1em 1.125em 1.5em;
  background-color: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: 2em;
  transform: rotate(4deg);
}

.insights__meta-title { font-size: 1.5em; font-weight: 600; letter-spacing: -0.01em; line-height: 0.9; }
.insights__meta-paragraph { font-size: 1.25em; letter-spacing: -0.02em; line-height: 1.2; color: var(--ink-dim); }

.insights__quote-01 { position: absolute; top: 12.5em; left: 4.5em;  transform: rotate(-8deg); }
.insights__quote-02 { position: absolute; top: 15em;   right: 7.5em; transform: rotate(4deg); }
.insights__note { max-width: 20ch; opacity: 0.9; }

.insights__stat {
  position: absolute;
  display: grid;
  place-items: center;
  width: 8.625em;
  height: 8.625em;
  font-family: var(--font-display);
  font-size: 1em;
  color: var(--ink);
  background-color: var(--lime);
  border-radius: 50%;
}

.insights__stat span {
  font-size: 2.25em;
  font-weight: 900;
  letter-spacing: -0.04em;
}

.insights__stat.is--01 { bottom: 17.1875em; left: 10.375em; transform: rotate(-5deg); }
.insights__stat.is--02 { top: 8.5em; right: -2em; transform: rotate(-10deg); background-color: var(--amber); }
.insights__stat.is--03 { bottom: 8em; left: -4.5em; width: 11.8125em; height: 11.8125em; transform: rotate(-10deg); background-color: var(--surface-card); box-shadow: inset 0 0 0 0.1875em var(--ink); }

.insights__badge {
  position: absolute;
  right: 2.5em;
  bottom: -2.75em;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* --------------------------------------------------------------------------
   16. Footer
   -------------------------------------------------------------------------- */

.footer {
  position: relative;
  overflow: hidden;
  margin-top: -10em;
  padding-top: 10em;
  background-color: var(--lime);
}

.footer__top { padding-top: 7em; padding-bottom: 2.5em; background-color: var(--lime); }

.footer__top-inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  padding-left: calc(var(--grid-column-width) * 1);
}

.footer__top-nav { width: calc((var(--grid-column-width) * 5) + (var(--grid-gutter) * 4)); }

.footer__logo-img { width: 13em; height: auto; }

.footer__cta {
  display: flex;
  gap: 0.875em;
  align-items: center;
  justify-content: flex-start;
  padding-top: 2.1875em;
}

.footer__cta-title { max-width: 20ch; }
.footer__cta-paragraph { max-width: 40ch; padding-top: 1em; color: var(--ink-dim); }

.footer__socials { display: flex; gap: 1.25em; padding-top: 2.5em; }

.footer__nav-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 2.5em 1.5em;
  width: calc((var(--grid-column-width) * 6) + (var(--grid-gutter) * 5));
  padding-top: 0.5em;
}

.footer__nav-col { display: flex; flex-flow: column; gap: 0.875em; }

.footer__nav-title {
  font-family: var(--font-mono);
  font-size: 1em;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.55;
}

.footer__nav-list { display: flex; flex-flow: column; gap: 0.5em; }

.footer__nav-link {
  font-size: 1.125em;
  color: rgba(13, 13, 14, 0.72);
  transition: color 0.2s linear;
}

.footer__nav-link:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 0.2em; }

/* lime, same as .footer and .footer__top above it: the cream band read as a
   separate strip pinned under the footer rather than part of it */
.footer__bottom {
  padding-top: 0.875em;
  padding-bottom: 1em;
  color: var(--ink);
  background-color: var(--lime);
}

.footer__bottom-inner { display: flex; align-items: center; justify-content: flex-start; }

.footer__bottom-copyright {
  width: calc((var(--grid-column-width) * 4) + (var(--grid-gutter) * 3));
  padding-left: var(--grid-column-width);
}

/* 0.5 was 3.3:1 against the lime (and only 3.5:1 against the cream it used to
   sit on), under the 4.5:1 that small text needs. 0.7 is 6.1:1 and still reads
   as a quiet line rather than body copy. */
.footer__bottom-text { opacity: 0.7; }

.footer__link { color: inherit; }
.footer__link:hover { color: var(--lime-text); }

.footer__visual {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: clip;
  pointer-events: none;
}

.footer__visual-wrap {
  position: absolute;
  right: -6em;
  bottom: -26em;
  rotate: -21deg;
}

.footer__visual-stage { width: 24em; opacity: 0.85; }

.footer__mob-bottom { display: none; }

/* --------------------------------------------------------------------------
   Data tables — the two tables that exist in the source document
   -------------------------------------------------------------------------- */

.data-table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
}

.data-table thead th {
  padding: 0 1em 0.875em;
  font-family: var(--font-mono);
  font-size: 1em;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
  border-bottom: 0.1875em solid var(--ink);
}

.data-table tbody th,
.data-table tbody td {
  padding: 1.5em 1em;
  font-weight: 500;
  vertical-align: baseline;
  border-bottom: 1px solid var(--line);
  transition: background-color 0.25s var(--ease-click);
}

.data-table tbody tr:last-child th,
.data-table tbody tr:last-child td { border-bottom: 0; }

.data-table tbody tr:hover th,
.data-table tbody tr:hover td { background-color: rgba(13, 13, 14, 0.045); }

/* the row's subject */
.data-table__card {
  font-family: var(--font-display);
  font-size: var(--font-size-paragraph-medium);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--ink);
}

/* the number carries the row */
.data-table__result { white-space: nowrap; }

.data-table__figure {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--font-size-heading-s);
  font-weight: 900;
  letter-spacing: -0.035em;
  line-height: 0.95;
  color: var(--ink);
  white-space: nowrap;
}

.data-table__method {
  font-family: var(--font-mono);
  font-size: var(--font-size-paragraph-extra-small);
  line-height: 1.35;
  color: var(--ink-dim);
}

.data-table__desc {
  font-size: var(--font-size-paragraph-regular);
  line-height: 1.3;
  color: var(--ink-dim);
}

/* the stats table has no header row in the document */



.data-table thead th:first-child,
.data-table tbody tr > *:first-child { padding-left: 0; }
.data-table thead th:last-child,
.data-table tbody tr > *:last-child { padding-right: 0; }

/* --------------------------------------------------------------------------
   17. Device — the phone mock used everywhere a cover used to be
   -------------------------------------------------------------------------- */

/* Flat tile. Same proportion as the reference layout's covers (320 x 493), so
   it drops straight into a card's cover slot and fills it edge to edge. */
.tile {
  position: relative;
  aspect-ratio: 320 / 493;
  width: 100%;
  overflow: hidden;
  background-color: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: 1em;
  box-shadow: 0 0.75em 2em rgba(13, 13, 14, 0.07);
}

.tile__inner {
  display: flex;
  flex-flow: column;
  width: 100%;
  height: 100%;
  container-type: inline-size;
}

/* -- Tile face -------------------------------------------------------------
   One statement per tile. The old face packed a dashboard's worth of rows and
   sparklines into a thumbnail, which was unreadable at card size.
   -------------------------------------------------------------------------- */

.face {
  display: flex;
  flex-flow: column;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  padding: 7cqw 7cqw 8cqw;
  background:
    radial-gradient(120% 60% at 50% 0%, rgba(163, 230, 53, 0.3), transparent 62%),
    var(--surface-raised);
}

.face__bar {
  display: flex;
  gap: 1em;
  align-items: baseline;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 4cqw;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.face__bar strong { font-weight: 500; color: var(--lime-text); }

.face__figure {
  margin-top: auto;
  font-family: var(--font-display);
  font-size: 21cqw;
  font-weight: 900;
  letter-spacing: -0.05em;
  line-height: 0.86;
  color: var(--ink);
}

/* Hero decision queue — ported from the Edda draft: the leading row drops to
   the bottom every few seconds and the rest slide up, so the card reads as a
   list being continuously re-ranked. Sized in cqw like the rest of the face. */
/* This tile lists what the first run finds, then closes on what it cost.
   The figure is not the whole card here, so it stays below the 21cqw the
   other faces use: it should read as the footer of a report, not a poster.
   Point size is tuned to the figure's character count, since visual mass is
   what matters and a lone "1" carries far less of it than a two-digit
   number. 12cqw suited "23"; this needs more to hold the corner. */
/* Figure and caption centre as a pair, so the close reads as a footer under
   the findings rather than a fifth left-aligned row. */
.risk__visual-stage .face__figure { font-size: 16cqw; line-height: 0.9; text-align: center; }
.risk__visual-stage .face__caption { font-size: 4.4cqw; text-align: center; }

/* teardown rows are a manifest, not a ranking: no value column, and a rule
   under the list to separate it from the figure it closes on.
   The gap under that rule is optical, not geometric: .face__figure runs at
   line-height 0.9, so its box is shorter than the digits and the glyphs sit
   near the top of it, which is why a small margin still reads as touching.
   The margin needs .face in front of it. `.queue { margin: 0 }` below is the
   same specificity and comes later, so a bare .queue--teardown margin loses
   and silently computes to zero. Do not flatten this selector. */
.face .queue--teardown { margin-bottom: 7cqw; }
.queue--teardown { border-bottom: 1px solid var(--line); }

/* Keeps a hyphenated term whole. Titles fit on one line at desktop widths but
   wrap on phones, where a break inside "fraud-suspect" reads as two words. */
.u-nobreak { white-space: nowrap; }
.queue--teardown .queue__row { grid-template-columns: auto minmax(0, 1fr); }

.queue {
  display: flex;
  flex-flow: column;
  flex: 1;
  margin: 0;
  padding: 0;
  list-style: none;
}

.queue__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  flex: 1;
  gap: 0 2.6cqw;
  align-items: baseline;
  align-content: center;
  padding: 2.4cqw 0;
  border-top: 1px solid var(--line);
}

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

.queue__rank {
  font-family: var(--font-mono);
  font-size: 3.4cqw;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.queue__body { display: flex; flex-flow: column; min-width: 0; }

.queue__title {
  font-family: var(--font-display);
  font-size: 5.1cqw;
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.025em;
  color: var(--ink);
}

.queue__why {
  display: flex;
  gap: 1.4cqw;
  align-items: baseline;
  margin-top: 1.8cqw;
  font-family: var(--font-mono);
  font-size: 3.2cqw;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink-dim);
}

.queue__chip {
  font-size: 2.9cqw;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--lime-text);
}

.queue__value {
  font-family: var(--font-display);
  font-size: 5.5cqw;
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--ink);
  transition: color 0.5s var(--ease-smooth);
}

.queue__row.is--fresh .queue__value { color: var(--lime-text); }

.face__caption {
  margin-top: 0.55em;
  margin-bottom: auto;
  font-size: 5.4cqw;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--ink-dim);
}

/* --------------------------------------------------------------------------
   Stat rows — same behaviour as the feature list, so the two sections rhyme.
   The row nearest the middle of the viewport lights up; the figure and its
   description converge and a wash binds them into a single object.
   -------------------------------------------------------------------------- */

.data-table.is--stats { border-collapse: separate; border-spacing: 0; }

.stat-row > * {
  padding: 0.5em 0;
  border-top: 1px solid var(--line);
  transition: background-color 0.45s var(--ease-smooth);
}

.stat-row:first-child > * { border-top: 0; }

.stat-row__figure {
  width: 1%;
  text-align: right;
  white-space: nowrap;
  padding-right: 3em;
  vertical-align: middle;
}

.stat-row__figure span {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 4em;
  font-weight: 900;
  letter-spacing: -0.045em;
  line-height: 1;
  color: var(--ink);
  opacity: 0.32;
  transform: translateX(0.12em);
  transition: opacity 0.45s var(--ease-smooth), transform 0.45s var(--ease-smooth);
}

.stat-row__desc { vertical-align: middle; padding-left: 0; }

.stat-row__desc span {
  display: inline-block;
  font-size: var(--font-size-paragraph-regular);
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--ink-dim);
  opacity: 0.55;
  transform: translateX(-0.5em);
  transition: opacity 0.45s var(--ease-smooth), transform 0.45s var(--ease-smooth);
}

.stat-row.is--active > * { background-color: rgba(163, 230, 53, 0.34); }
.stat-row.is--active > *:first-child { border-radius: 0.75em 0 0 0.75em; }
.stat-row.is--active > *:last-child { border-radius: 0 0.75em 0.75em 0; }
.stat-row.is--active .stat-row__figure span { opacity: 1; transform: none; }
.stat-row.is--active .stat-row__desc span { opacity: 1; color: var(--ink); transform: none; }

/* Hover is owned by initActiveList, the same as the feature list, so there is
   no :hover rule here. As a separate CSS rule the hovered row and the row the
   scroll had chosen were both lit at once, and dragging down the table
   flickered through every row. It also missed the rounded ends above, so the
   two states did not match. */

/* --------------------------------------------------------------------------
   Section backgrounds — the breathing blob, tinted per section
   -------------------------------------------------------------------------- */

.section-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}

.section-bg svg { width: 100%; height: auto; overflow: visible !important; }
.section-bg .is--mobile { display: none; }

/* The blob is this design's colour carrier. Between the hero and the CTA every
   one of these was a neutral grey-beige, so the middle of the page drained to
   black-on-bone. They now step through lime, light to deep, still light enough to stay
   background — #fdf3dd on the case section was the intensity reference. */
/* features keeps its neutral blob on purpose: the capability words (Operate /
   Predict / Personalise / Protect) are pale lime until they activate, and a
   lime blob behind them wipes them out. */
.features__bg { color: #f2f0ea; }
.risk__bg     { color: #eef7da; }
.diff__bg     { color: #e6f4c6; }
.insights__bg { color: #ddefb8; }
.cta__bg      { color: #b3ee56; }

/* content must sit above the blob layer */
.features__container,
.risk__container,
.case__container,
.diff__container,
.diff__eyebrow,
.insights__container,
.cta__container,
.tagline-curve { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   18. Scroll reveal
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(2em);
  transition: opacity 0.8s var(--ease-smooth), transform 0.8s var(--ease-smooth);
}

.reveal.is--in { opacity: 1; transform: none; }

/* SplitText output */
/* No standing will-change. There are ~167 of these across the page's buttons,
   and the hint promotes every one to its own compositor layer for the life of
   the page. initLabelSquash applies it on hover and drops it when the tween
   settles, which is the only time it buys anything. */
.split-char { display: inline-block; }
.split-word { display: inline-block; }

/* Cards thrown by the momentum hover must not be clipped mid-flight */

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   19. Responsive
   -------------------------------------------------------------------------- */

@media screen and (max-width: 991px) {
  .header__nav,
  .header__sub { display: none; }
  .header__menu-toggle { display: flex; }
  .header__title { width: auto; }
  .header__title-logo { width: 7em; }
  .menu__header-title-logo { width: 7em; }

  /* Without the tile the column no longer fills a screen, so a pinned 100svh
     left a band of bare lime under the button. Let the hero close on its
     content and carry its own bottom padding instead. */
  .hero { min-height: auto; clip-path: inset(0% round 0 0 2.5em 2.5em); }
  .hero__content { padding-top: 10.5em; padding-bottom: 4em; margin-left: 0; }
  .hero__header { gap: 1em; max-width: 100%; }
  .hero__paragraph { max-width: 100%; font-size: 1.375em; line-height: 1.3; }
  .hero__stat { font-size: 1.25em; line-height: 1.3; }
  .hero__text-outer {
    position: static;
    inset: auto;
    padding-top: 0.5em;
    transform: rotate(-1.5deg);
  }
  .hero__text { max-width: 100%; text-align: left; }
  .hero__visual { display: none; }  /* the live-scoring tile is desktop only */
  .hero__bg-svg.is--desktop { display: none; }
  .hero__bg-svg.is--mobile { display: block; }
  .hero__grid { background-size: 3.5em 3.5em; }

  .features__inner { padding-bottom: 2.5em; }

  /* stacked, and every row readable — a scroll-position-dependent reveal is
     poor on a small screen where rows barely leave the viewport */
  .feature-list__item {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.375em;
    padding: 1.125em 0;
  }
  /* Match .features__subtitle ("Every player evaluated.") exactly — same size,
     weight and tracking, so the four names read as list items rather than as
     four competing headlines. */
  .feature-list__name {
    font-size: var(--font-size-heading-s);
    font-weight: 800;
    letter-spacing: -0.025em;
    color: var(--ink);
    opacity: 1;
  }
  /* the index closes the empty right end of a wide row; stacked, there is no
     empty end for it to close and it just becomes a stray number */
  .feature-list__index { display: none; }
  .feature-list__text { opacity: 1; transform: none; }
  .features__header { padding-top: 4.5em; padding-bottom: 1.5em; }
  .features__header-content { gap: 0.75em; }
  .features__text-wrap { display: none; }

  .deck__list {
    padding: 2em 1.25em;
    overflow-x: scroll;
    scroll-snap-type: x mandatory;
  }
  .deck__controls { display: none; }

  .flow__inner { border-radius: 2.5em; }
  .flow__header { align-items: flex-start; justify-content: center; padding: 5em 1em 0; }
  .flow__text-wrap, .flow__cta { display: none; }
  .flow__content { padding-top: 1em; padding-bottom: 2.125em; }
  .flow__list {
    align-items: stretch;
    justify-content: flex-start;
    padding-top: 1em;
    padding-bottom: 1em;
    overflow-x: scroll;
    scroll-snap-type: x mandatory;
  }
  .flow__list-item { padding-left: 0.75em; padding-right: 0.75em; scroll-snap-align: start; }
  .flow__card { width: 18.75em; height: auto; min-height: 17em; }
  .flow__card-img-wrap { display: none; }
  .flow__card-inner { padding: 1.875em 0.9375em 1.125em; }
  .flow__bg-svg.is--desktop { display: none; }
  .flow__bg-svg.is--mobile { display: block; }

  .gap__wrap { height: 160svh; }
  .gap__sticky { min-height: auto; height: 100svh; }
  .gap__element { clip-path: inset(var(--grid-margin) round 2.5em); }
  .gap__content { width: 31em; padding-top: 0; }
  .gap__content-text-outer { right: 1em; }
  /* the tile stacks under the copy again once there is no room beside it */
  .hero__inner { flex-flow: column; gap: 2.5em; align-items: stretch; }
  .insights__grid { grid-template-columns: minmax(0, 1fr); gap: 1.25em; }
  .insights__card-body { padding: 1.25em; }
  .insights__card-title { font-size: 1.375em; }
  .gap__meter { width: 100%; margin-top: 2.5em; }

  /* Queue cards: the tiles drop to 20em/15em/13.25em here, and cqw sizing
     shrinks with them, so the desktop values land at 5-9px on a phone. */
  .queue__title { font-size: 5.8cqw; }
  .queue__why { font-size: 4cqw; }
  .queue__chip { font-size: 3.6cqw; }
  .queue__rank { font-size: 4cqw; }
  .queue__value { font-size: 6.2cqw; }

  /* The teardown tile is the narrowest on the page (169-285px here), too
     narrow to carry a title and a sub-line legibly. Drop the sub-lines and
     let the numbered titles carry the manifest. */
  /* The sub-lines used to be dropped here, on the grounds that this tile is
     the narrowest on the page and could not carry a title and a sub-line
     legibly. That held while they were only a note on the finding. They now
     carry the recommendation, which is half of what each row says, so hiding
     them would leave a phone reading four numbers and no advice. Kept at
     every width and sized down to fit instead. */
  .queue--teardown .queue__why { font-size: 3.5cqw; margin-top: 1.2cqw; }
  .queue--teardown .queue__chip { font-size: 3.2cqw; }
  .queue--teardown .queue__title { font-size: 6cqw; }
  .queue--teardown .queue__rank { font-size: 5cqw; }
  .queue--teardown .queue__row { padding: 2.2cqw 0; }
  .risk__visual-stage .face__caption { font-size: 6cqw; }
  /* 2.6em is a desktop size: the mobile scale rebases to a smaller ideal
     container, so it lands ~40px and wraps the payoff onto three lines.
     2.1em is the largest size that holds both to two lines from 360px up. */
  .gap__eyebrow, .gap__payoff { font-size: 2.1em; }
  /* the three labels measure ~86% of the track at 1.15em, which leaves almost
     no gap between them once "Day 7 report" is in play */
  .gap__meter-labels { font-size: 0.8em; }
  .gap__action { padding-top: 2em; }


  .proof__inner { clip-path: inset(0 round 0 0 2.5em 2.5em); }
  .proof__logo-text { max-width: 20em; margin-bottom: -1em; }
  .proof__bg-svg.is--desktop { display: none; }
  .proof__bg-svg.is--mobile { display: block; }

  .faq__header { padding-top: 5em; padding-bottom: 2em; }
  .faq__content { gap: 0.75em; width: 100%; }
  .accordion__toggle { padding: 1.125em 1.25em; }
  .accordion__paragraph { padding: 0 1.25em 1.25em; }

  /* column-reverse used to float the tile above the heading, so the section
     opened on a card with nothing to frame it. display:contents lifts the
     content's own children into this flex flow, which lets the tile be ordered
     between the heading and the copy it illustrates. */
  .risk__inner {
    flex-flow: column;
    align-items: stretch;
    gap: 1.25em;
    padding-top: 4.5em;
    padding-bottom: 4.5em;
    padding-left: 0;
  }
  .risk__content { display: contents; }
  .risk__content > h2 { order: 1; }
  .risk__visual { order: 2; width: 100%; margin: 0.5em 0; }
  .risk__content > .risk__paragraph { order: 3; }
  .risk__content > .button-alt { order: 4; align-self: flex-start; margin-top: 0.75em; }
  .risk__visual-stage { width: 15em; }

  /* the arc is illegible at this width, so the subhead is set straight */
  /* stacked, the 0.875em gap left each label only 2.2x closer to its own
     field than to the one above it, so labels read as belonging upward */
  .closer__row { grid-template-columns: 1fr; gap: 1.4em; }
  .tagline-curve { padding-top: 1em; margin-bottom: 0; }
  .tagline-curve__svg { display: none; }
  .tagline-curve__title.u-screen-reader {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    white-space: normal;
    font-family: var(--font-display);
    font-size: var(--font-size-heading-s);
    font-weight: 800;
    letter-spacing: -0.025em;
    line-height: 0.98;
    text-align: center;
    color: var(--ink);
  }
  .diff__inner { padding-top: 3em; padding-bottom: 4.5em; }
  .diff__eyebrow { padding-top: 3em; }
  .diff__list { grid-template-columns: minmax(0, 1fr); gap: 0.75em; }
  .diff__list-item { padding: 1.25em 1.5em 1.5em; }

  .band__inner { padding-top: 4.5em; padding-bottom: 4.5em; }
  .band__item-title { font-size: 2em; }
  .band__item-title-outer { padding-top: 2em; padding-bottom: 2em; }
  .band__item-bg-svg { left: -5em; }

  .cta { clip-path: inset(0 round 2.5em 2.5em 0 0); }
  .cta__inner { padding-top: 4.5em; padding-bottom: 4.5em; }
  .cta__title { font-size: 2.4em; }
  .cta__title { max-width: 100%; }

  .case { margin-top: -2.5em; }
  .case__header { padding-top: 4.5em; padding-bottom: 1.5em; }
  .case__table-wrap,
  .proof__table-wrap { width: 100%; }
  .proof__content { flex-flow: column; gap: 1em; padding-top: 4.5em; text-align: center; }
  .proof__table-wrap { padding-bottom: 4.5em; }

  .stat-row > * { padding: 0.4em 0; }
  .stat-row__figure { width: auto; text-align: left; padding-right: 0; }
  .stat-row.is--active > *:first-child { border-radius: 0.75em 0.75em 0 0; }
  .stat-row.is--active > *:last-child { border-radius: 0 0 0.75em 0.75em; }
  .stat-row__figure span { font-size: 2.5em; opacity: 1; transform: none; }
  .stat-row__desc { padding-left: 0; }
  .stat-row__desc span { font-size: var(--font-size-paragraph-small); opacity: 1; transform: none; }

  /* a 3-column table cannot hold its shape at this width, so each row becomes
     a block and every cell carries its column name */
  .data-table thead { display: none; }
  .data-table tbody tr {
    display: block;
    padding: 1.25em 0;
    border-bottom: 1px solid var(--line);
  }
  .data-table tbody tr:last-child { border-bottom: 0; }
  .data-table tbody th,
  .data-table tbody td {
    display: block;
    padding: 0.25em 0;
    border-bottom: 0;
  }
  .data-table tbody td[data-label]::before,
  .data-table tbody th[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 0.25em;
    font-family: var(--font-mono);
    font-size: 0.8125em;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-dim);
  }
  .case__header-content { gap: 0.75em; }
  .case__visual { display: none; }
  .case__visual-img { width: 4.1875em; }
  .case__content { padding-bottom: 5.5em; }
  .case__rain-item { width: max(90px, 6vw); font-size: 1em; }

  .insights { clip-path: inset(0 round 0 0 2.5em 2.5em); }
  .insights__inner { padding-bottom: 3.5em; }
  .insights__header { padding-top: 4.5em; padding-bottom: 1.5em; }
  .insights__header-content { gap: 0.75em; }
  .insights__list { padding: 3.5em 0; overflow-x: scroll; scroll-snap-type: x mandatory; }
  .insights__list-item { width: 21em; scroll-snap-align: center; }
  .insights__item-outer {
    padding: 0 1.3125em;
    background-color: transparent !important;
    border: none !important;
  }
  .insights__item-inner { width: 100%; }
  .insights__meta,
  .insights__quote-01,
  .insights__quote-02,
  .insights__stat { display: none; }
  .insights__badge { right: auto; left: 50%; bottom: -2.75em; translate: -50%; }
  .deck__controls.is--insights { display: none; }

  .footer { margin-top: -2.5em; padding-top: 2.5em; }
  .footer__top { padding-top: 2em; padding-bottom: 2em; }
  .footer__top-inner { flex-flow: column; align-items: flex-start; padding-left: 0; }
  .footer__top-nav { width: 100%; }
  .footer__nav-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; padding-top: 3em; }
  .footer__bottom { padding-top: 1.5em; padding-bottom: 1.5em; }
  .footer__bottom-inner { flex-flow: column; gap: 1em; text-align: center; }
  .footer__bottom-copyright { width: 100%; padding-left: 0; }
  .footer__visual { display: none; }
}

@media screen and (max-width: 767px) {
  .flow__header { padding-top: 4em; }
  .gap__content { width: 22.5em; }
  .band__item-title { font-size: 1.125em; }
  .band__item-title-outer { padding-top: 0.8125em; padding-bottom: 0.8125em; }
  .tagline-curve__svg text { font-size: 3em; }
  .footer__nav-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2em 1.25em; }
}

@media screen and (max-width: 479px) {
  .hero__content { padding-top: 9.5em; }
  .risk__visual-stage { width: 13.25em; }
  .gap__content-text-outer { right: -0.5em; }
}

/* --------------------------------------------------------------------------
   Insights cards carry their own case study
   The standalone "Case studies" section was removed; each insight card now
   owns the PDF write-up of the same engagement. The download sits outside
   .insights__card-inner because that element is an <a> and anchors cannot nest.
   -------------------------------------------------------------------------- */
.insights__card { flex-flow: column; gap: 0.625em; }

/* Case studies are the same card as the articles, so they take the same
   markup and styles. The only differences are the tag word, the download
   affordance inside it, and that the whole card is a file rather than a page. */
.insights__card-tag {
  display: inline-flex;
  gap: 0.5em;
  align-items: center;
}

.insights__card-dl {
  width: 0.85em;
  height: 0.85em;
  color: currentColor;
}

.insights__card--study .insights__card-inner:hover .insights__card-dl { transform: translateX(0.15em); }
.insights__card-dl { transition: transform 0.3s var(--ease-smooth); }

/* --------------------------------------------------------------------------
   "How the first run works" and its closing form are one section
   The CTA used to be a full-bleed lime slab with its own rounded top, stacked
   under the pale flow panel's rounded bottom. Two rounded slabs read as two
   sections however the markup is nested. The CTA now sits inside flow__inner
   and is clipped by that panel's own corners, so the section is one shape
   that changes colour at the point of action.
   -------------------------------------------------------------------------- */
.flow__inner { overflow: hidden; padding-bottom: 0; }

.flow .cta { clip-path: none; border-radius: 0; }

.flow .cta__container { padding-left: 0; padding-right: 0; }

.flow .cta__inner { padding-top: 6em; padding-bottom: 7em; }

/* --------------------------------------------------------------------------
   Live-site fixes
   1. The pill button is two grid cells, each painting its own .button-alt__bg.
      Both were rounded on all four corners, so two rounded edges met in the
      middle and pinched the shape. Square off the inner edge of each half.
   2. .gap__title inherits u-heading-l, which is 6.5em against a viewport-scaled
      root, so it grew without limit: 51px at 1024, 139px at 2560. Capped.
   -------------------------------------------------------------------------- */
/* Only square the text half's inner edge when an icon half actually follows it
   to close the shape. The closer's submit button is text-only, so squaring it
   unconditionally left it rounded on the left and cut off square on the right.
   :not(:last-child) is the test: text-wrap is last only when there is no icon. */
.button-alt__text-wrap:not(:last-child) .button-alt__bg {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.button-alt__icon-wrap .button-alt__bg {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.gap__title { font-size: clamp(32px, 5vw, 96px); }

/* Above 992px the root font is exactly 100vw/120, so 6em of .gap__content is
   algebraically identical to 5vw and this renders at the same size as the
   clamp above at every width, capped at 96px the same way. The difference is
   that it is now expressed against the container, so when .gap__content takes
   its height cap the headline shrinks with it. Left on the raw clamp it stayed
   at 96px inside a shrinking column and simply wrapped onto more lines, which
   made the panel taller as the cap tried to make it shorter. */
@media (min-width: 992px) {
  .gap__title { font-size: min(6em, 96px); }
}

/* The eyebrow needed the same treatment, and had a second fault besides.
   Sized from --font-size-heading-m it tracks viewport WIDTH, so it did not
   shrink when .gap__content took its height cap. That is height the panel's
   budget never accounted for, and the panel clips: measured overflow was 92px
   at 1024 and 122px at 1920 and above, taken off the top and bottom of a
   centred column, which eats into the eyebrow and the button.

   It also never stopped growing when the headline hit its 96px ceiling, so at
   2560 the section's label rendered at 152px above a 96px statement. A kicker
   that outsizes the line it introduces reads as the headline.

   4.2em is 0.7 of the headline's 6em and 88px is 0.7 of its cap, so the label
   holds the same relationship to the statement at every width and shrinks with
   the block. It is smaller than the other section titles by design: inside
   this section the statement is the headline, not the label.

   Needs .gap__content in front of it: the shared section-title rule near the
   foot of this file also matches .gap__eyebrow at the same specificity and
   comes later, so a bare class here loses. Do not flatten this selector. */
@media (min-width: 992px) {
  .gap__content .gap__eyebrow { font-size: min(4.2em, 88px); }
}

/* The lime block and the panel above it are one section, so the join should
   read as a colour changing, not a new block starting. A short fade from the
   panel tone into the lime removes the hard full-width line at the top edge.
   The bottom corners are already handled by the panel's own overflow clip. */
.flow .cta {
  background-image: linear-gradient(to bottom, var(--surface-soft) 0, rgba(232, 246, 201, 0) 8em);
}


/* --------------------------------------------------------------------------
   The Ilara Difference runs lime.
   features / risk / diff / insights / flow were five sections alternating
   between #fbfaf7 and #f3f1ec, which read as one long pale stretch. This one
   is text-only, so it takes the brand lime cleanly and gives the run a middle.
   Lime is light, so the inversion flips with it: white on lime is 1.34:1,
   ink on lime is 12.88:1.
   -------------------------------------------------------------------------- */
.diff { background-color: var(--lime); color: var(--ink); }

/* The dark block met the bone section on a hard full-width line. Fade the last
   8em into the next tone so the colour changes rather than the block ending.
   This is an overlay rather than a background-image because .diff__bg is a
   child at z-index 0: painting the fade on the section's own background left
   the blob sitting on top of it, still fully dark, and it got sliced at the
   boundary. ::after is the last child, so it covers the blob but stays under
   the content, which is z-index 1. 8em fits inside the 126px of clear space
   below the cards, so nothing reads over a shifting background. */
.diff::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  height: 12em;
  /* Eased, not linear. A straight two-stop gradient shows a visible edge where
     it starts, because the eye is sensitive to the sudden onset of change. The
     stops below approximate an ease-in, so the fade is imperceptible at the top
     and does its work low down. Written in the bone tone rather than the green
     so it stays correct if the section tone is retuned. */
  background-image: linear-gradient(
    to bottom,
    rgba(243, 241, 236, 0) 0%,
    rgba(243, 241, 236, 0.08) 30%,
    rgba(243, 241, 236, 0.28) 55%,
    rgba(243, 241, 236, 0.58) 75%,
    rgba(243, 241, 236, 0.86) 90%,
    rgb(243, 241, 236) 100%
  );
  pointer-events: none;
}
.diff .u-heading-l { color: var(--ink); }
.diff .tagline-curve__svg { color: var(--ink); }
.diff__bg { color: #97dc2c; }

.diff__list-item {
  background-color: rgba(13, 13, 14, 0.05);
  border-color: rgba(13, 13, 14, 0.16);
  border-top-color: var(--ink);
  box-shadow: none;
}
.diff__list-item:hover {
  border-color: rgba(13, 13, 14, 0.28);
  border-top-color: var(--ink);
  box-shadow: 0 1.5em 3em rgba(13, 13, 14, 0.16);
}
.diff__list-title { color: var(--ink); }
.diff__list-paragraph { color: rgba(13, 13, 14, 0.72); }

/* --------------------------------------------------------------------------
   Real Data / Real Impact: legible at rest, and centred as a block
   The figure column shrank to its content and the rows filled the full eight
   columns, so the numbers and their labels clustered on the left with dead
   space on the right. The table now hugs its content and centres under the
   heading. Rows that are not being hovered were also ghosted at 0.32 and 0.55,
   which read as broken rather than secondary; they are legible now and the
   hovered row still leads through the lime wash and full ink.
   -------------------------------------------------------------------------- */
.data-table.is--stats { width: auto; margin-inline: auto; }

.stat-row__figure span { opacity: 0.62; }

.stat-row__desc span { opacity: 0.85; }

/* The figures were right-aligned, so their left edges stepped in and out by up
   to 123px: "<30 min" jutted out while "9x" sat far right of it. Left-aligning
   them in the column the widest one already defines gives both the numbers and
   their labels a straight edge. The idle nudge went too, so nothing slides
   sideways as the pointer moves down the list. */
.stat-row__figure { text-align: left; padding-left: 0.5em; }

.stat-row__figure span { transform: none; }

/* The labels carried the same idle nudge, so the hovered row's text sat 8px
   right of every other row's. With five rows on screen at once that reads as a
   ragged column rather than as emphasis. */
.stat-row__desc span { transform: none; }

/* --------------------------------------------------------------------------
   Real Data rows: spacing
   Left-aligning the figures fixed the ragged edge but moved the raggedness
   into the gap: 135px of air after "9x" and 23px after "<30 min", because the
   column is sized by the widest figure and the short ones leave slack. Smaller
   figures narrow that column, so the gap range tightens, and the table hugs
   its content instead of stretching 315px past the longest label. Rows get
   more room between them, which is what the block was actually short of.
   -------------------------------------------------------------------------- */
.data-table.is--stats { width: max-content; max-width: 100%; }

.stat-row > * { padding-top: 0.85em; padding-bottom: 0.85em; }

.stat-row__figure { padding-right: 1.25em; padding-left: 0.75em; }

.stat-row__figure span { font-size: 3.4em; }

.stat-row__desc span { max-width: 30ch; }

/* The shared column was the problem: a table column is as wide as its widest
   figure, so short numbers left the slack after them and the gap ran 23px to
   118px. Each row becomes its own flex line instead, so every label sits the
   same distance after its own number. The figures still start on one edge
   because the row starts there; only the labels step, which reads as a list
   rather than as a broken grid. Also undoes the 30ch cap, which was wrapping
   labels that fit on one line. */
.stat-row { display: flex; align-items: baseline; gap: 1.25em; }

.stat-row__figure { width: auto; padding-right: 0; flex: none; }

.stat-row__desc span { max-width: none; }

.data-table.is--stats { width: 100%; }

/* The rules and the active wash were painted on the cells, which worked while
   the row was a table row. As a flex line the cells no longer meet, so both
   broke into segments with the gap showing through. Move them onto the row
   itself, where they belong now, and let the block hug its content so it sits
   under the heading rather than drifting left of it. */
.stat-row > * { border-top: 0; background: none; padding-left: 0; padding-right: 0; }

.stat-row { border-top: 1px solid var(--line); padding: 0.85em 1em; }

.stat-row:first-child { border-top: 0; }

.stat-row.is--active { background-color: rgba(163, 230, 53, 0.34); border-radius: 0.75em; }

.stat-row.is--active > *:first-child,
.stat-row.is--active > *:last-child { border-radius: 0; }

.data-table.is--stats { width: max-content; max-width: 100%; margin-inline: auto; }

/* .data-table tbody td still carried its own bottom rule, which showed up as
   two short segments under each row instead of one line across it. */
.data-table.is--stats tbody td,
.data-table.is--stats tbody th { border-bottom: 0; }

/* The cells still carried the active wash from before the row became a flex
   line, and my earlier reset was one class less specific, so it lost. The row
   and both cells were each painting the same translucent lime, and the overlaps
   stacked into the darker blocks behind the figure and the label. The wash
   belongs to the row alone. The generic table hover tint goes too: it is a grey
   that muddies the lime underneath it. */
.stat-row.is--active > *,
.data-table.is--stats tbody tr:hover td,
.data-table.is--stats tbody tr:hover th { background-color: transparent; }

/* The claim and the answer are one statement, so they get one treatment: the
   answer was a size down and at 72% ink, which made it read as a caption under
   the claim rather than as the half that matters. Same size, same weight, same
   ink now. Kept ink rather than white because the panel is lime: white on lime
   is 1.34:1, ink is 12.88:1. */
.diff__list-paragraph { font-weight: 700; color: var(--ink); }

/* The claim reserved two lines so the answers would start on the same baseline
   across the three cards. That was worth it while the answer was smaller and
   dimmer. Now both lines are the same, the reserve just leaves an empty line
   inside the two cards whose claim fits on one, so the pairs look unevenly
   spaced. One consistent gap instead; the grid still keeps the cards level. */
.diff__list-title { min-height: 0; margin-bottom: 0.55em; }

/* Two bold sentences stacked at line-height 1.2 set solid: the cards read as
   blocks of type rather than as a claim and its answer. More air between the
   lines, and let the browser balance the rag so we stop getting one-word last
   lines like "game." and "zero." hanging under a full line. */
.diff__list-title,
.diff__list-paragraph {
  line-height: 1.35;
  text-wrap: balance;
}

/* The claim is the setup and the answer is the payoff, so the answer keeps the
   full weight and the claim steps back to medium. Same size, same colour, so
   the pair still reads as one statement rather than as heading and caption. */
.diff__list-title { font-weight: 500; }

/* 13.75em of top padding was borrowed from .features__header, which follows a
   section that ends in ordinary text. This one follows the lime block, whose
   own bottom padding is 125px and whose fade adds another 150px of clear space
   on top of that. Stacked, the gap from the last Difference card to the Ilara
   Insights heading came to 436px. Halved: the sections still separate, without
   a screen of nothing between them. */
.insights__header { padding-top: 6.5em; }

/* Centred. Both lines are the same size and colour, so ranged left they read as
   one long left edge with two weights on it; centring gives each card a middle
   to sit around and separates the claim from the answer without another rule. */
.diff__list-item { text-align: center; }

/* Tighter: 1.25em put 37px between a figure and its label, which read as two
   columns rather than one line. */
.stat-row { gap: 0.6em; }

/* The gap was coming from three places at once: the figure's right padding
   (12.6px), the row's flex gap (7.6px) and the label's left padding (12.6px),
   which is why halving the flex gap barely moved it. The cells no longer pad
   toward each other, so the flex gap is the only thing setting this distance. */
.data-table.is--stats .stat-row__figure { padding-right: 0; }
.data-table.is--stats .stat-row__desc { padding-left: 0; }
.stat-row { gap: 1.1em; }

/* --------------------------------------------------------------------------
   The Ilara Difference: white cards, green claim, black answer
   The cards were a 5% ink wash on the lime panel, which made them read as
   slightly darker lime rather than as cards. Solid white separates them from
   the panel and gives both lines a clean ground.

   The claim is a lighter green than --lime-text, so it is a local value rather
   than the token: the token is also the colour of footer and accordion links,
   which are ordinary body size and need the darker end. Here the type is
   1.75em and bold, so it carries a lighter green without going soft. Brand
   lime itself is 1.6:1 on white and not an option. The answer is solid ink.
   Both bold, so the pair still reads as one statement in two colours.
   -------------------------------------------------------------------------- */
.diff {
  /* #63901a, 3.8:1 on white, against 4.9:1 for --lime-text */
  --diff-green: #63901a;
}

/* The top edge is --lime-deep, not --lime. Brand lime is the colour of the
   panel the cards sit on, so a lime stripe on a lime ground disappeared into
   it and the cards just looked like they started lower. --lime-deep is one
   step down, which is enough to draw as a band while still reading as lime. */
.diff__list-item {
  background-color: var(--surface-card);
  border-color: var(--line);
  border-top-color: var(--lime-deep);
}

.diff__list-item:hover {
  border-color: var(--line-strong);
  border-top-color: var(--lime-deep);
  box-shadow: 0 1.5em 3em rgba(13, 13, 14, 0.16);
}

.diff__list-title { font-weight: 700; color: var(--diff-green); }
.diff__list-paragraph { font-weight: 700; color: var(--ink); }

/* ==========================================================================
   Mobile pass
   ========================================================================== */

/* "How the first run works" was cut off on every phone width. .flow__heading
   is flex: none inside a centred flex header, so it took its max-content width
   (404px at a 390px viewport) and .flow__inner, which is overflow: hidden,
   sliced the ends off. Measured before the fix: -62→342 at 320, -42→362 at
   360, -27→377 at 390, -7→397 at 430. Letting the block flex and shrink puts
   the title back inside the container's padding at all four widths, wrapped
   over two lines. min-width: 0 is the part that actually allows the shrink;
   flex items default to min-width: auto and refuse to go below max-content. */
@media screen and (max-width: 991px) {
  .flow__heading {
    flex: 1 1 auto;
    min-width: 0;
    align-items: center;
    text-align: center;
  }

  .flow__title,
  .flow__subtitle { max-width: 100%; }

  /* .flow__text-wrap inside this is already display: none on mobile, so all
     that was left was a 1px sliver sitting past the right edge. */
  .flow__text-outer { display: none; }
}

/* The header is position: fixed, so every in-page anchor landed with the
   target heading underneath it. Offset by the header's own height. */
#features,
#proof,
#insights,
#how,
#faq { scroll-margin-top: var(--header-height); }

/* Footer links were 21px tall in a 8px-gap stack, which is a small target for
   a thumb. Padding takes each row to roughly 38px without opening the stack
   up so far that the footer turns into a screen of its own. */
@media screen and (max-width: 991px) {
  .footer__nav-link { display: inline-block; padding: 0.4em 0; }
  .footer__nav-list { gap: 0.125em; }
}

/* The Get in touch panel on phones. Two things made it oversized: the fields
   carried the desktop 0.9em/1.1em padding, which is 51px of box for a 15px
   line, and .flow .cta__inner beats the 991px rule on specificity, so the
   panel kept 6em/7em of vertical padding (93px and 109px at 390) and the form
   sat in a screen and a half of empty lime. 45px fields still clear the 44px
   touch target, and the panel comes down from 755px to about 640, so the whole
   form lands on one screen. */
@media screen and (max-width: 991px) {
  .flow .cta__inner { padding-top: 3.5em; padding-bottom: 3.5em; }
  .closer__input { padding: 0.7em 0.9em; border-radius: 0.625em; }
  .closer__field { gap: 0.3em; }
  .closer__grid { gap: 0.75em; }
}

/* The fields ran the full width of the lime panel, 16→374 against a panel of
   16→374, because .flow .cta__container zeroes the container padding so the
   CTA can sit flush inside the rounded section. That is right for the desktop
   layout, where the form is a centred row inside a much wider panel, but on a
   phone it left the inputs and the paragraph touching both edges. Put the
   padding back on the inner, where the zeroed container cannot reach it. */
@media screen and (max-width: 991px) {
  .flow .cta__inner { padding-left: 1.375em; padding-right: 1.375em; }
}

/* --------------------------------------------------------------------------
   Phones: shorter copy, and one size for every section heading
   -------------------------------------------------------------------------- */

.u-narrow-copy { display: none; }

/* Five paragraphs carried their full desktop length onto a 390px screen, where
   the hero alone ran to seven lines directly under the title. Both versions are
   in the markup and one is switched off at each width, so nothing is hidden
   from a reader or a crawler and the wide layout is unchanged. */
.u-narrow-copy { display: none; }

@media screen and (max-width: 991px) {
  .u-wide-copy { display: none; }
  .u-narrow-copy { display: inline; }
}

/* Their centring is kept: the mark is a display:block img, so inline centring
   had nothing to act on. The width below is set in the mobile block above. */
@media screen and (max-width: 991px) {
  .footer__logo { display: flex; justify-content: center; }
}

/* The Difference cards on phones: composition, not two centred sentences.
   Desktop can afford the pair at one size because the three cards sit abreast
   and the column edges do the separating. Stacked on a phone there are no
   neighbours to read against, so identical size, identical weight and a centred
   rag on both lines left each card looking like a paragraph someone had
   coloured half of. The claim and the answer are not equals — one is the setup,
   one is the payoff — so they stop pretending to be.

   Three axes of contrast instead of one: size (1em against 1.5em), weight (500
   against 800) and colour (the quiet green against solid ink). Ranged left so
   both lines share a hard edge, and a hairline between them so the card has an
   internal structure rather than a colour change halfway down. */
@media screen and (max-width: 991px) {
  .diff__list-item {
    text-align: left;
    padding: 1.5em 1.5em 1.75em;
  }

  .diff__list-title {
    margin-bottom: 0.85em;
    padding-bottom: 0.85em;
    border-bottom: 1px solid var(--line);
    font-size: var(--font-size-paragraph-small);
    font-weight: 500;
    line-height: 1.35;
    /* balance centres the rag, which is what a centred card wanted; ranged left
       it just makes short lines shorter. pretty only fixes the orphan. */
    text-wrap: pretty;
  }

  .diff__list-paragraph {
    font-size: 1.5em;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.2;
    text-wrap: pretty;
  }
}

/* One size for every section heading, keyed to "Real Data. Real Impact."

   That heading is an <h2> carrying no font-size of its own, so it keeps the
   user-agent default of 1.5em and its .u-heading-m child resolves against that
   — 47.8px on a phone, where every other section title, which does set its own
   size, lands on 31.8px. The 1.5 was an accident of the default stylesheet
   rather than a decision, but it is the size the page is being read against, so
   it is pinned here instead of left to the browser, and the rest are given the
   same product so they track it at every breakpoint. */
.proof__logo-text { font-size: 1.5em; }

.features__title,
.copilot__title,
.diff__eyebrow h2,
.insights__title,
.flow__title,
.faq__title,
.risk__content h2,
/* "Get in touch" — same rank as the rest, and the only section title that was
   being sized by a rule this one replaced. */
.cta__title,
/* Not an h2 — the gap section names itself with a <p> and a lime rule under it
   — but it is the section heading as far as the page reads, so it sizes with
   the rest rather than with body copy. Its .gap__title is deliberately NOT in
   this set: that is the section's statement, not its name, and at the shared
   size the two together ran the pinned panel 918px into an 844px screen. */
.gap__eyebrow {
  font-size: calc(var(--font-size-heading-m) * 1.5);
}

/* The gap panel is pinned to a full viewport, and it used to centre its column
   inside it, so the free space above the eyebrow was only ever what was left
   over — and a fixed 89px header sits on top of that space. Once the eyebrow
   took the shared section-heading size the first line went under the nav. The
   column pays for the header explicitly now (see below), and the height budget
   at the top of this file was stepped down to 0.86em to cover the larger type
   rather than squeezing the panel. */
@media screen and (max-width: 991px) {
  /* The panel is pinned to a full viewport and centres its column, so the space
     above the eyebrow is only ever what is left over — and the header is fixed
     on top of it. Centring put the first line under the nav once the eyebrow
     took the shared heading size. Top-align against an explicit reserve instead,
     so clearance is a stated number rather than a remainder. --header-height is
     5em nominal but the bar measures 89px here, hence the extra.  */
  .gap__content {
    justify-content: flex-start;
    padding-top: calc(var(--header-height) + 1em);
  }

  /* 13em is a desktop measure. Against a phone's em it drew 231px — 52% of the
     screen, and nearly twice the 125px wordmark in the header, so the footer
     opened louder than the nav it echoes. Sized to sit just above the header
     mark rather than shout over it. */
  .footer__logo-img { width: 8.5em; }
}

/* The session meter on phones. It sits inside .gap__content, whose whole type
   budget is scaled to 0.86em to fit the pinned panel, so the meter was being
   shrunk twice: a 9px track and 10.7px labels under a 34px headline, which is
   the smallest thing on the page carrying the section's actual argument.

   Track to 15px, labels to 14px, and the meter itself widened past its column
   by 1.25em each side, which is what buys the labels room: at the old 300px
   "SESSION 1" and "DAY 7 REPORT" sat 10px apart and read as one string. Now 19,
   and 16 at the narrowest step.

   The top margin comes down from 2.5em to 1.75em to pay for the added height.
   The panel is pinned to the viewport and already overruns on short screens,
   and this should not make that worse: measured within a pixel of the previous
   height at 320x640, 360x740 and 375x667. */
@media screen and (max-width: 991px) {
  .gap__meter {
    width: calc(100% + 3em);
    max-width: none;
    margin-top: 1.75em;
    margin-left: -1.5em;
    margin-right: -1.5em;
  }

  .gap__meter-track { height: 1.15em; }

  .gap__meter-track::before {
    top: -0.45em;
    bottom: -0.45em;
    width: 0.18em;
    margin-left: -0.09em;
  }

  .gap__meter-fill::after {
    width: 1.15em;
    height: 1.15em;
    margin: -0.575em -0.575em 0 0;
    border-width: 0.18em;
  }

  /* The three labels are pinned to the track: Install at the left end, Session 1
     on the midpoint tick, Day 7 report at the right. That leaves "Session 1" and
     "Day 7 report" fighting over the right half, 19px apart, close enough that
     they read as one string. Dropping the 0.04em tracking is what buys the room
     without shrinking the type or adding a line: the mono face is already wide
     enough to read at 14px unspaced. 31px between them now, 27px at the
     narrowest step. */
  .gap__meter-labels { font-size: 1.05em; margin-top: 0.7em; letter-spacing: 0; }
}

/* The band is the join between the hero and Real Data. Real Impact., so it has
   to read as a bridge between them. Below 768 it was doing the opposite: the
   type dropped from 2em to 1.125em (17.5px) and the strip's own padding from
   2em to 0.8125em, leaving a 65px sliver of lime stranded in 188px of cream
   with a clear gap above and below it.

   Type to 1.75em and the strip's padding to 1.4em, so the lime is 93px deep
   and the line is readable at a glance. The section's outer padding comes down
   from 4.5em to 2.25em at the same time, which is what closes the gaps: the
   band is 147px overall, less than before, but nearly all of it is now the
   strip rather than the space around it. */
@media screen and (max-width: 767px) {
  .band__inner { padding-top: 2.25em; padding-bottom: 2.25em; }
  .band__item-title { font-size: 1.75em; }
  .band__item-title-outer { padding-top: 1.4em; padding-bottom: 1.4em; }
}

/* The band's loop runs on the compositor on phones (see js/main.js): the track
   holds an even number of copies and travels exactly half its own width per
   cycle, so the wrap lands on a copy edge and is invisible. Duration is set per
   element, since it depends on the copy width and the configured speed. */
@keyframes marquee-drift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

.marquee__track.is--drift {
  animation: marquee-drift var(--marquee-duration, 24s) linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .marquee__track.is--drift { animation: none; }
}

/* ==========================================================================
   Motion-and-cards port from the design-1b branch
   The reference's load intro and elastic entrances, plus the coloured card
   language for the flow steps and the insight cards. The band, the
   Difference cards and the first-run tile copy are deliberately untouched -
   they carry newer main-branch work. Values and rationale:
   design-1b docs/research/aardvarkbookclub.com/.
   ========================================================================== */

/* -- Load intro curtain ---------------------------------------------------- */

.transition { display: none; }

html.has--intro .transition {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--surface);
}

html.has--intro .transition {
  display: grid;
  place-items: center;
  background: radial-gradient(120% 85% at 50% 40%, #fefdfa 0%, #f3f1ec 58%, #eae7df 100%);
  overflow: hidden;
}

/* faint grid floor, panning - from the draft-v3 loader */
html.has--intro .transition::before {
  content: "";
  position: absolute;
  inset: -2px;
  opacity: 0.55;
  pointer-events: none;
  background:
    linear-gradient(to right, rgba(13, 13, 14, 0.05) 1px, transparent 1px) 0 0 / 56px 56px,
    linear-gradient(to bottom, rgba(13, 13, 14, 0.05) 1px, transparent 1px) 0 0 / 56px 56px;
  -webkit-mask: radial-gradient(72% 58% at 50% 54%, #000 16%, transparent 78%);
          mask: radial-gradient(72% 58% at 50% 54%, #000 16%, transparent 78%);
  animation: ilwGridPan 3.2s linear infinite;
}

/* smaller and in black - the owner's spec on the draft-v3 flowing-line loader */
.transition__stage { position: relative; width: min(238px, 44vw); display: grid; }
.transition .ilw { grid-area: 1 / 1; width: 100%; height: auto; }
.transition .ilw path { stroke: var(--ink); stroke-width: 7; stroke-dasharray: 1; stroke-dashoffset: 1; }
.transition .ilw-draw { filter: drop-shadow(0 1px 0 rgba(13, 13, 14, 0.12)); }
.transition .ilw-draw path { animation: ilwDraw 1.15s cubic-bezier(0.33, 0, 0.15, 1) forwards; }
.transition .ilw-fill { transform-origin: center; opacity: 0; }
.transition .ilw-fill path { fill: var(--ink); stroke: none; }
.transition.is--formed .ilw-fill { animation: ilwFillIn 0.55s cubic-bezier(0.22, 0.68, 0.24, 1) forwards; }
.transition.is--formed .ilw-draw { opacity: 0; transition: opacity 0.55s ease 0.05s; }

@keyframes ilwDraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes ilwFillIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
@keyframes ilwGridPan { to { background-position: 0 -56px, -56px 0; } }

/* -- Flow cards: saturated slabs, scattered by JS -------------------------- */

.flow__card {
  border: 0;
  box-shadow: none;
  transition: none;
}

.flow__list-item:hover .flow__card { border-color: transparent; box-shadow: none; }

.flow__card.is--lime  { background-color: var(--lime); }
.flow__card.is--amber { background-color: var(--amber); }
.flow__card.is--rose  { background-color: var(--rose); }

/* ink pill on a colour slab, the inverse of the old lime-on-white */
.flow__card-step { color: var(--surface-raised); background-color: var(--ink); }

/* dimmed ink fails contrast on the saturated grounds; full ink everywhere */
.flow__card .flow__card-paragraph { color: var(--ink); }

/* the tile reads as a cover mounted on the slab, so it gets a real shadow */
.flow__card .tile {
  border-color: rgba(13, 13, 14, 0.2);
  box-shadow: 0 0.625em 1.5em rgba(13, 13, 14, 0.22);
}

@media (min-width: 992px) {
  .flow__list-item { position: relative; z-index: 1; margin-left: -0.75em; margin-right: -0.75em; }
  .flow__list-item:nth-child(2) { z-index: 2; }
  .flow__list-item:hover { z-index: 6; }
  /* the scattered cards need air above and below or the throw-in clips */
  .flow__list { padding-top: 1.5em; padding-bottom: 1.5em; }
}

/* -- Insights cards: wash slabs with a sticker chip ------------------------ */

.insights__card-inner {
  position: relative;
  overflow: visible;
  border-color: transparent;
  box-shadow: 0 0.75em 2em rgba(13, 13, 14, 0.07);
  rotate: -1.3deg;
  transition: rotate 0.85s var(--ease-elastic-out), translate 0.85s var(--ease-elastic-out),
    box-shadow 0.35s var(--ease-smooth);
}

.insights__card:nth-child(even) .insights__card-inner { rotate: 1.6deg; }
.insights__card:nth-child(3n) .insights__card-inner { rotate: -2deg; }

.insights__card-inner:hover {
  border-color: transparent;
  transform: none;
  translate: 0 -0.35em;
  rotate: 0deg;
  box-shadow: 0 1.5em 3em rgba(13, 13, 14, 0.12);
}

/* article and its case study share a wash, so the pairs read across the rows */
.insights__card:nth-child(3n + 1) .insights__card-inner { background-color: var(--lime-wash); }
.insights__card:nth-child(3n + 2) .insights__card-inner { background-color: var(--amber-wash); }
.insights__card:nth-child(3n)     .insights__card-inner { background-color: var(--rose-wash); }

/* the tag stops being a row in the copy and sits on the card edge */
.insights__card-tag {
  position: absolute;
  top: -0.9em;
  left: 1.2em;
  z-index: 1;
  rotate: -6deg;
  box-shadow: 0 0.25em 0.75em rgba(13, 13, 14, 0.18);
}

.insights__card-body { padding-top: 1.9em; }

/* -- Difference cards: the same coloured-card family ----------------------- */
/* The saturated trio, as on the flow steps. Two consequences of sitting ON
   the lime panel: the type goes full ink (the green claim colour fails
   contrast on these grounds, badly on rose), and the shadow does the
   separating where lime lands on lime. Tilts live in the CSS rotate property
   so the JS pop-in (which owns transform) composes with them. */

.diff__list-item {
  border: 0;
  box-shadow: 0 1.125em 2.25em rgba(13, 13, 14, 0.3);
  rotate: -1.6deg;
  transition: rotate 0.85s var(--ease-elastic-out), box-shadow 0.35s var(--ease-smooth);
}

/* No lime card on the lime panel - the owner vetoed green on green. The
   palette's only saturated tones are lime/amber/rose, so the trio runs
   amber/rose/amber: an A-B-A rhythm, white claims readable on all three. */
.diff__list-item:nth-child(1) { background-color: var(--amber); }
.diff__list-item:nth-child(2) { background-color: var(--rose); rotate: 1.4deg; }
.diff__list-item:nth-child(3) { background-color: var(--lime); rotate: -1.1deg; }

/* the claim runs white, the owner's call - same voice as the feature names
   on the lime section; the answer stays ink and carries the reading load */
.diff__list-item .diff__list-title { color: #fff; }
.diff__list-item .diff__list-paragraph { color: var(--ink); }

.diff__list-item:hover {
  border-color: transparent;
  rotate: 0deg;
  box-shadow: 0 1.75em 3.25em rgba(13, 13, 14, 0.34);
}

@media screen and (max-width: 991px) {
  .diff__list-item { rotate: -1deg; }
  .diff__list-item:nth-child(2) { rotate: 0.8deg; }
  .diff__list-item:nth-child(3) { rotate: -0.7deg; }
}

/* -- Footer parallax ------------------------------------------------------- */
/* The halves are pre-shifted up and ride down into place, so the footer clips
   its own box or the shifted content would paint over the FAQ above it. */

.footer[data-footer-parallax] { overflow: clip; }

/* -- FAQ blob stays inside the FAQ ----------------------------------------- */
/* The section stacks above the footer for the arch seam, so anything its
   background paints past its own bottom edge lands ON the footer. Clip it:
   the seam strip is inside the FAQ's box, so the arch is unaffected, but the
   breathing blob (whose swelling stroke escapes the svg box) can no longer
   reach the footer text. */

.faq { overflow: clip; }

/* -- Accordion: the reference's 450ms -------------------------------------- */

.accordion__panel { transition: grid-template-rows 0.45s var(--ease-smooth); }

@media (prefers-reduced-motion: reduce) {
  .transition { display: none !important; }
  .insights__card-inner,
  .diff__list-item { rotate: 0deg; }
}

/* -- Features runs on the strong lime ------------------------------------- */
/* The owner's call: the capability list was a wall of black on bone,
   especially on phones. The section takes the brand lime like the hero; the
   big names go white and flip to ink when their row is live, so the list
   reads as a lit sequence rather than a text wall. */

.features { background-color: var(--lime); }
.features__bg { color: #c1ed77; }

.feature-list__item { border-top-color: rgba(13, 13, 14, 0.18); }
.feature-list__item:last-child { border-bottom-color: rgba(13, 13, 14, 0.18); }

.feature-list__name { color: rgba(255, 255, 255, 0.92); opacity: 1; }
.feature-list__text { color: rgba(13, 13, 14, 0.78); }
.feature-list__index { color: var(--ink); opacity: 0.22; }

.feature-list__item.is--active { background-color: rgba(255, 255, 255, 0.42); }
.feature-list__item.is--active .feature-list__name { color: var(--ink); }
.feature-list__item.is--active .feature-list__text { color: var(--ink); }
.feature-list__item.is--active .feature-list__index { opacity: 0.6; }

/* -- Real Data figures on phones ------------------------------------------- */
/* Smaller and centred: at 3.4em the numbers were the loudest thing on the
   screen, and the left rag read as accidental. */

@media (max-width: 767px) {
  .stat-row { display: flex; flex-flow: column; gap: 0.2em; align-items: center; text-align: center; }
  .stat-row__figure { width: auto; padding: 0; text-align: center; }
  .stat-row__figure span { font-size: 2.25em; }
  .stat-row__desc { padding: 0; text-align: center; }
  .stat-row__desc span { max-width: 26ch; }
}

/* -- No tiles: proof and the gap run full width ----------------------------- */
/* The owner prefers full-bleed over the rounded inset islands. The hero's
   bottom arch and the flow panel keep their shapes; only these two flatten. */

.proof__inner { clip-path: none; }
.gap__element { clip-path: none; }

/* -- The footer wears the hero's curves ------------------------------------- */
/* Same blob, same deeper-lime tone, breathing through the same
   data-background-animation hook. The footer halves go transparent so the
   root lime and the blob show through them. */

.footer__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: flex-start;
  color: #c1ed77;
  pointer-events: none;
}

.footer__bg-svg { width: 100%; height: auto; overflow: visible !important; }
.footer__bg-svg.is--mobile { display: none; }

.footer__top,
.footer__bottom {
  position: relative;
  z-index: 1;
  background-color: transparent;
}

@media (max-width: 991px) {
  .footer__bg-svg.is--desktop { display: none; }
  .footer__bg-svg.is--mobile { display: block; }
}

/* -- Actually full width: the surface moves off the boxed inners ------------ */
/* Both sections painted their ground on an element INSIDE .u-container, so
   the container's side padding read as bone gutters - the tiling the owner
   keeps seeing. The ground moves to the section; the inners go transparent.
   The Get in touch slab bleeds out of the container padding it sits in, and
   its own container puts the content back on the grid. */

.proof { background-color: var(--surface-soft); }
.proof__inner { background-color: transparent; }

.flow { background-color: var(--surface-soft); }
.flow__inner { background-color: transparent; border-radius: 0; }

.flow .cta {
  margin-left: calc(-1 * var(--grid-margin));
  margin-right: calc(-1 * var(--grid-margin));
}

/* -- Phones: the lit row runs the full width -------------------------------- */
/* Both scroll-lit lists sit inside the container, so their active wash read
   as a narrow tile. The rows bleed out of the container padding and put it
   back as their own, so the highlight touches both screen edges while the
   text stays on the grid. */

@media (max-width: 991px) {
  .feature-list__item {
    margin-left: calc(-1 * var(--grid-margin));
    margin-right: calc(-1 * var(--grid-margin));
    padding-left: var(--grid-margin);
    padding-right: var(--grid-margin);
    border-radius: 0;
  }
}

@media (max-width: 767px) {
  .data-table.is--stats,
  .data-table.is--stats tbody { display: block; width: 100%; }

  .stat-row {
    margin-left: calc(-1 * var(--grid-margin));
    margin-right: calc(-1 * var(--grid-margin));
    padding-left: var(--grid-margin);
    padding-right: var(--grid-margin);
  }

  .stat-row.is--active { border-radius: 0; }
  .stat-row.is--active > *:first-child,
  .stat-row.is--active > *:last-child { border-radius: 0; }
}

/* -- Get in touch actually reaches the edges -------------------------------- */
/* The slab already bled out of the container, but .flow__inner still carried
   overflow:hidden from the rounded-panel days and clipped the paint back to
   the container edge. The section's own overflow does the real clipping now.
   The cta stacks above the card strip so throw-ins pass beneath the form. */

.flow__inner { overflow: visible; }
.flow .cta { position: relative; z-index: 2; }

/* -- Difference claims at full size, phones only ----------------------------- */
/* The owner's call: on phones the white 'Others...' lines match the 'We...'
   answers - they had stepped down to paragraph-small/500. Desktop keeps its
   deliberate claim-steps-back-to-medium weight. */

@media (max-width: 991px) {
  .diff__list-item .diff__list-title {
    font-size: 1.5em;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.2;
  }
}

/* -- The teardown tile reads at phone size ----------------------------------- */
/* It was capped at 13-15em on phones - a 200px card whose cqw-sized type was
   unreadable. Near-full width; the face's container-query units scale the
   whole card up together. */

@media (max-width: 991px) {
  .risk__visual-stage { width: min(22em, 92%); }
}

/* -- Insights subtitle at the curve's scale ---------------------------------- */
/* The owner's call: same size as "What nobody else publishes". The curve's
   SVG text renders at exactly 10em-of-root on desktop and 3em on phones, so
   the subtitle takes the same display treatment - small section h2, giant
   statement line under it, mirroring the Difference section's pattern. */

/* Measured, not derived: the curve's glyphs render at ~8.25em of root once
   the SVG's own scaling is applied (10em computed x 1.1 transform x the
   viewBox ratio), and the curve does not render on phones at all - there the
   subtitle sits one step above the normalised section-heading size. */
.insights__subtitle {
  max-width: 100%;
  margin-top: 0.1em;
  font-family: var(--font-display);
  font-size: 8em;
  font-weight: 900;
  letter-spacing: -0.035em;
  line-height: 0.95;
  color: var(--ink);
}

/* Phones: matched to the Difference section's proportions - there the
   'What nobody else publishes' line runs at roughly 0.7x its section title,
   so against the 3em normalised titles the subtitle lands at 2.25em. The
   4.5em statement-line reading of the owner's screenshots was wrong; the
   subheading is the SMALLER line of the pair. */
@media (max-width: 991px) {
  .insights__subtitle { font-size: 2.25em; }
}

/* -- The teardown tile, green again ------------------------------------------ */
/* It was amber because its lime top-glow melted into the section's lime blob
   behind it. That was true of the glow at the strength every other face uses:
   0.3 lime over the raised surface lands on #e1f4bd, and the blob behind is
   #eef7da. Separation does not need a different hue, it needs a stronger one
   -- 0.55 lands on #cbef8c, which reads as lime against that pale wash rather
   than dissolving into it, and the card's own edge and shadow do the rest.
   The bar label goes back to the shared lime that every other face uses. */

.risk__visual-stage .face {
  background:
    radial-gradient(120% 60% at 50% 0%, rgba(163, 230, 53, 0.55), transparent 62%),
    var(--surface-raised);
}

/* -- Air under the gap section's button -------------------------------------- */
/* The content column carried 7.5em of top padding for the fixed header and
   none below, so the centred block sat low and the demo button hugged the
   field's bottom edge. */

.gap__content { padding-bottom: 5em; }

/* -- Phones: more air still under the gap section's button ------------------- */

@media (max-width: 991px) {
  .gap__content { padding-bottom: 10em; }
}

/* -- The gap eyebrow matches Real Data exactly ------------------------------- */
/* The pinned panel shrinks its content 0.86x under 900px of height to fit the
   fold - every current phone - which left 'The problem with LiveOps now' at
   40px against Real Data's 46.5, and a weight lighter. The eyebrow opts back
   out of the shrink and takes the full 900 weight. */

.gap__eyebrow { font-weight: 900; }

@media (max-width: 991px) and (max-height: 900px) {
  .gap__eyebrow { font-size: calc(var(--font-size-heading-m) * 1.5 / 0.86); }
}

/* -- The gap button clearance, done honestly --------------------------------- */
/* Three rounds of padding changed nothing on screen: the pinned column is
   taller than a phone viewport, overflows its centred box, and swallows any
   padding. The real lever is the fold-fit scale - the column shrinks a step
   further on phones so the whole stack PLUS real clearance fits. The eyebrow
   compensates by the same factor, so it keeps its Real Data size. */

/* Phones stop pinning entirely. The pinned column can never fit every real
   phone viewport (svh varies with browser chrome), and when it loses, the
   button is what gets clipped - as it did in production. The section flows
   at natural height on phones, so the button's clearance is structural.
   Desktop keeps the pin, with the auto-fit divisor taught about the added
   padding. */

@media (max-width: 991px) {
  .gap__wrap { height: auto; }
  .gap__sticky { position: static; height: auto; }
  .gap__element { height: auto; min-height: 100svh; }
  .gap__content {
    position: static;
    inset: auto;
    height: auto;
    font-size: 0.86em;
    padding-top: 7em;
    padding-bottom: 5em;
  }
  .gap__eyebrow { font-size: calc(var(--font-size-heading-m) * 1.5 / 0.86); }
}

@media (min-width: 992px) {
  .gap__content { font-size: min(1em, calc((100vh - 2.5vw) / 74)); }
}

/* -- Phones: the Difference cards stack as you scroll ------------------------ */
/* Card one holds, card two rides up and stacks on top, then card three; when
   the third is in, the page scrolls on. Pure sticky - each card pins at the
   same offset, and DOM order stacks later cards above earlier ones. Tall
   cards make the covering read deliberate and give the travel its length. */

@media (max-width: 991px) {
  .diff__list { display: block; }
  .diff__list-item {
    position: sticky;
    top: calc(var(--header-height, 5em) + 1.5em);
    /* content height, not a viewport minimum - the 56svh floor left a dead
       zone under the answer on every card */
    margin-bottom: 1.5em;
  }
  .diff__list-item:last-child { margin-bottom: 0; }
}
