/* ==========================================================================
   RETAIN MATTERS - 2026
   Retention & lifecycle marketing for Shopify DTC brands.
   --------------------------------------------------------------------------
   ONE stylesheet, ONE design language. Everything below is driven by the
   tokens in :root - no section hardcodes a colour, radius, easing or step in
   the type scale. Change a token and the whole page follows.

   Structure
     01  Tokens
     02  Reset & base
     03  Layout primitives      (.shell / .section / .eyebrow / .sec-title)
     04  Buttons & links
     05  Cards & surfaces
     06  Header / navigation
     07  Hero
     08  Email sample rail      (drag to explore)
     09  Our Work               (tabbed gallery)
     10  Channels               (+ system diagram)
     11  Method                 (lifecycle graph + stage rail)
     12  Process                (icon phases)
     13  Results                (case-study slider)
     14  Testimonials
     15  Capabilities accordion
     16  Audience card stack
     17  FAQ
     18  About
     19  Final CTA
     20  Footer
     21  Motion system
     22  Accessibility & print
   ========================================================================== */


/* ==========================================================================
   01 · TOKENS
   ========================================================================== */

:root {
  /* ---- Brand ------------------------------------------------------------
     A cool periwinkle carried over from the existing brand. It is a MARK,
     not a body colour: used for rules, dots, focus, active states and the
     single load-bearing word in a headline. */
 --accent:        #8d9af1;
 --accent-strong: #aeb8f8;
 --accent-deep:   #6675dd;
 --accent-ink:    #0b0c0f;
 --accent-wash:   rgba(141, 154, 241, 0.10);
 --accent-line:   rgba(141, 154, 241, 0.26);
 --accent-glow:   rgba(141, 154, 241, 0.16);

  /* ---- Surfaces - cool near-black, never pure #000 (avoids OLED smear) -- */
 --bg:        #0b0c0f;
 --bg-card:   #121419;
 --bg-elev:   #191c23;
 --bg-night:  #07080b;   /* deep bands: method, final CTA, footer           */
 --bg-glass:  rgba(11, 12, 15, 0.72);

  /* ---- Text ------------------------------------------------------------- */
 --fg1:       #f2f4f9;   /* 16.4:1 on --bg                                  */
 --fg2:       #c8ccd6;   /* 11.1:1 - secondary body                         */
 --fg3:       #9aa0ac;   /*  7.2:1 - body / captions, AA at any size        */
 --fg-muted:  #6b7180;   /*  4.1:1 - LARGE display text & decoration only   */

  /* ---- Borders ---------------------------------------------------------- */
 --line-whisper: rgba(255, 255, 255, 0.045);
 --line:         rgba(255, 255, 255, 0.075);
 --line-strong:  rgba(255, 255, 255, 0.14);

  /* ---- Signal colours ----------------------------------------------------
     Reserved for the results dashboards, where up/down carries real meaning.
     Never used decoratively - that is what --accent is for. */
 --pos:      #43cf7c;
 --pos-bg:   rgba(67, 207, 124, 0.12);
 --pos-line: rgba(67, 207, 124, 0.32);
 --neg:      #f2565b;
 --neg-bg:   rgba(242, 86, 91, 0.12);
 --neg-line: rgba(242, 86, 91, 0.32);

  /* ---- Motion ------------------------------------------------------------
 --ease is the same EASE_PREMIUM curve the React source uses in
     lib/motion.ts, so a port back to Framer Motion needs no retiming. */
 --ease:      cubic-bezier(0.16, 1, 0.3, 1);
 --ease-soft: cubic-bezier(0.33, 1, 0.68, 1);
 --t-fast: 180ms;
 --t-base: 320ms;
 --t-slow: 640ms;

  /* ---- Radii ------------------------------------------------------------ */
 --r-xs: 6px;
 --r-sm: 10px;
 --r-md: 14px;
 --r-lg: 20px;
 --r-xl: 28px;
 --r-pill: 999px;

  /* ---- Layout ----------------------------------------------------------- */
 --maxw: 1280px;
 --edge: clamp(20px, 4vw, 48px);
 --nav-h: 72px;
 --section-y: clamp(60px, 3.4rem + 3.2vw, 100px);

  /* ---- Type families ---------------------------------------------------- */
 --font-sans:  "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
 --font-mono:  "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
 --font-serif: "Instrument Serif", "Iowan Old Style", Georgia, serif;

  /* ---- Type scale - one fluid ramp, 375px to 1600px --------------------- */
 --fs-xl:   clamp(2.75rem, 1.95rem + 3.35vw, 5rem);      /* hero            */
 --fs-lg:   clamp(2.15rem, 1.5rem + 2.75vw, 3.85rem);    /* band display    */
 --fs-md:   clamp(1.75rem, 1.35rem + 1.75vw, 2.85rem);   /* section heading */
 --fs-sm:   clamp(1.375rem, 1.15rem + 0.95vw, 1.95rem);  /* card heading    */
 --fs-xs:   clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);     /* sub-heading     */
 --fs-lede: clamp(1.0625rem, 0.97rem + 0.42vw, 1.3125rem);
 --fs-body:  0.9375rem;
 --fs-small: 0.8125rem;
 --fs-label: 0.6875rem;

  /* ---- Focus ------------------------------------------------------------ */
 --focus: var(--accent-strong);

  color-scheme: dark;
}

/* Deep bands re-point the tokens the components already use, so a section
   inverts by adding one attribute rather than by rewriting its rules. */
[data-tone="night"] {
 --bg:      var(--bg-night);
 --bg-card: #0e1015;
 --bg-elev: #14171d;
 --line:    rgba(255, 255, 255, 0.065);
}


/* ==========================================================================
   02 · RESET & BASE
   ========================================================================== */

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

* { margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
 -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

body {
  min-height: 100dvh;
  background: var(--bg);
  color: var(--fg1);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.55;
  letter-spacing: -0.011em;
  font-feature-settings: "cv11", "ss01";
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
  /* Guards against any single element blowing out the mobile viewport. */
  overflow-x: clip;
}

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

button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

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

ul, ol { list-style: none; }

h1, h2, h3, h4 {
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.032em;
  text-wrap: balance;
}

p { text-wrap: pretty; }

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

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

/* Anchor targets clear the fixed header. */
[id] { scroll-margin-top: calc(var(--nav-h) + 32px); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 200;
  padding: 12px 22px;
  border-radius: var(--r-pill);
  background: var(--fg1);
  color: var(--bg);
  font-size: var(--fs-small);
  font-weight: 600;
  transform: translateY(-180%);
  transition: transform var(--t-base) var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); }


/* ==========================================================================
   03 · LAYOUT PRIMITIVES
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--edge);
}
.shell--wide { max-width: 1440px; }

.section {
  position: relative;
  background: var(--bg);
  padding-block: var(--section-y);
}
.section--flush-top    { padding-top: 0; }
.section--flush-bottom { padding-bottom: 0; }
.section--rule { border-top: 1px solid var(--line); }

/* ---- Section head ------------------------------------------------------ */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg3);
}
.eyebrow::before {
  content: "";
  width: 6px; height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--accent);
}

.sec-head { max-width: 64ch; }
.sec-head--center { margin-inline: auto; text-align: center; }
.sec-head--center .eyebrow { justify-content: center; }

.sec-title {
  margin-top: 20px;
  max-width: 22ch;
  font-size: var(--fs-md);
}
.sec-head--center .sec-title { margin-inline: auto; max-width: 24ch; }

.sec-lede {
  margin-top: 22px;
  max-width: 52ch;
  font-size: var(--fs-lede);
  line-height: 1.5;
  color: var(--fg3);
}
.sec-head--center .sec-lede { margin-inline: auto; }

/* The one editorial flourish: a serif italic used for a single word or short
   phrase, never for a whole heading. */
.serif {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.005em;
}

/* Underline that marks the load-bearing word in a headline. */
.mark { position: relative; display: inline-block; white-space: nowrap; }
.mark::after {
  content: "";
  position: absolute;
  inset-inline: -0.05em;
  bottom: 0.05em;
  height: 0.1em;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 800ms var(--ease) 300ms;
}
.is-in .mark::after { transform: scaleX(1); }

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

.meta {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* Dotted separator list - "Email · SMS · WhatsApp". */
.dot-list { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.dot-list li {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg3);
}
/* Separator trails its own item rather than leading the next one - as a
   ::before it wrapped onto a new line ahead of the word, which read as a
   stray bullet at the start of the row. */
.dot-list li:not(:last-child)::after {
  content: "";
  width: 4px; height: 4px;
  margin-right: -6px;
  border-radius: 50%;
  background: var(--accent);
}


/* ==========================================================================
   04 · BUTTONS & LINKS
   ========================================================================== */

.btn {
 --btn-h: 50px;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: var(--btn-h);
  padding-inline: 26px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: var(--fs-body);
  font-weight: 500;
  letter-spacing: -0.01em;
  white-space: nowrap;
  user-select: none;
  transition:
    background-color var(--t-base) var(--ease),
    border-color var(--t-base) var(--ease),
    color var(--t-base) var(--ease),
    transform var(--t-base) var(--ease),
    box-shadow var(--t-base) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn[disabled] { pointer-events: none; opacity: 0.5; }

.btn--sm { --btn-h: 40px; padding-inline: 18px; font-size: var(--fs-small); }
.btn--lg { --btn-h: 56px; padding-inline: 32px; font-size: 1rem; }
.btn--block { width: 100%; }

.btn--primary { background: var(--fg1); color: var(--bg); }
.btn--primary:hover {
  background: #fff;
  transform: translateY(-2px);
  box-shadow: 0 16px 36px -18px rgba(242, 244, 249, 0.5);
}
.btn--primary:active { transform: translateY(0); }

.btn--ghost { border-color: var(--line-strong); color: var(--fg1); }
.btn--ghost:hover {
  border-color: var(--fg3);
  background: var(--bg-elev);
  transform: translateY(-2px);
}
.btn--ghost:active { transform: translateY(0); }

.btn--accent { background: var(--accent); color: var(--accent-ink); }
.btn--accent:hover {
  background: var(--accent-strong);
  transform: translateY(-2px);
  box-shadow: 0 16px 36px -18px var(--accent-glow);
}

.btn .glyph { transition: transform var(--t-base) var(--ease); }
.btn:hover .glyph--x { transform: translateX(4px); }
.btn:hover .glyph--y { transform: translateY(3px); }

.btn-note { margin-top: 16px; font-size: var(--fs-small); color: var(--fg-muted); }

.cta-row {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 36px;
}
@media (min-width: 560px) {
  .cta-row { flex-direction: row; align-items: center; }
  .cta-row--center { justify-content: center; }
}

.link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 500;
  transition: color var(--t-base) var(--ease);
}
.link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -3px;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-base) var(--ease);
}
.link:hover { color: var(--accent-strong); }
.link:hover::after { transform: scaleX(1); }

.icon-btn {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  flex: none;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  color: var(--fg1);
  transition:
    background-color var(--t-base) var(--ease),
    border-color var(--t-base) var(--ease),
    color var(--t-base) var(--ease),
    opacity var(--t-base) var(--ease);
}
.icon-btn:hover:not([disabled]) {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.icon-btn[disabled] { opacity: 0.28; cursor: default; }


/* ==========================================================================
   05 · CARDS & SURFACES
   ========================================================================== */

.card {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--bg-card) 72%, transparent);
  transition:
    background-color var(--t-slow) var(--ease),
    border-color var(--t-slow) var(--ease),
    transform var(--t-slow) var(--ease);
}
.card--hover:hover {
  background: var(--bg-card);
  border-color: var(--line-strong);
  transform: translateY(-3px);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--bg) 60%, transparent);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  line-height: 1.4;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg3);
  white-space: nowrap;
}
.chip--accent {
  border-color: var(--accent-line);
  background: var(--accent-wash);
  color: var(--accent-strong);
}
.chip .pulse {
  width: 6px; height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 2.4s var(--ease-soft) infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: 0.4; transform: scale(0.8); }
}

.icon-tile {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg);
  color: var(--fg1);
  transition:
    border-color var(--t-slow) var(--ease),
    color var(--t-slow) var(--ease),
    background-color var(--t-slow) var(--ease);
}
.icon-tile svg { width: 21px; height: 21px; }
:is(.channel-card, .process-step, .cap-row):hover .icon-tile,
.cap-row[aria-expanded="true"] .icon-tile {
  border-color: var(--accent-line);
  background: var(--accent-wash);
  color: var(--accent-strong);
}


/* ==========================================================================
   06 · HEADER / NAVIGATION
   ========================================================================== */

.header {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition:
    background-color var(--t-slow) var(--ease),
    border-color var(--t-slow) var(--ease),
    backdrop-filter var(--t-slow) var(--ease);
}
.header.is-stuck,
.header.is-open {
  background: var(--bg-glass);
  border-bottom-color: var(--line);
  backdrop-filter: blur(18px) saturate(140%);
 -webkit-backdrop-filter: blur(18px) saturate(140%);
}

.header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  height: var(--nav-h);
  transition: height var(--t-slow) var(--ease);
}
.header.is-stuck:not(.is-open) .header__bar { height: 62px; }

/* ---- Wordmark ---------------------------------------------------------- */
.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.42em;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  user-select: none;
}
.wordmark span:last-child {
  opacity: 0.45;
  transition: opacity var(--t-slow) var(--ease);
}
a:hover > .wordmark span:last-child { opacity: 1; }
.wordmark--lg { font-size: clamp(1.125rem, 0.9rem + 0.8vw, 1.5rem); letter-spacing: 0.18em; }

/* ---- Desktop nav ------------------------------------------------------- */
.nav { display: none; }
@media (min-width: 1024px) { .nav { display: block; } }

.nav__list { display: flex; align-items: center; gap: 34px; }

.nav__link {
  position: relative;
  display: inline-block;
  padding-block: 4px;
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--fg3);
  transition: color var(--t-base) var(--ease);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-base) var(--ease);
}
.nav__link:hover,
.nav__link[aria-current="true"] { color: var(--fg1); }
.nav__link:hover::after,
.nav__link[aria-current="true"]::after { transform: scaleX(1); }

.header__actions { display: flex; align-items: center; gap: 10px; }
.header__status { display: none; }
@media (min-width: 1180px) { .header__status { display: inline-flex; } }
.header__cta { display: none; }
@media (min-width: 600px) { .header__cta { display: inline-flex; } }

/* ---- Mobile toggle ----------------------------------------------------- */
.burger {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  margin-right: -10px;
  border-radius: 50%;
  color: var(--fg1);
}
@media (min-width: 1024px) { .burger { display: none; } }

.burger__box { position: relative; width: 20px; height: 10px; }
.burger__box span {
  position: absolute;
  left: 0;
  display: block;
  width: 100%; height: 1.5px;
  border-radius: 2px;
  background: currentColor;
  transition: transform var(--t-base) var(--ease), top var(--t-base) var(--ease);
}
.burger__box span:nth-child(1) { top: 0; }
.burger__box span:nth-child(2) { top: 8px; }
.header.is-open .burger__box span:nth-child(1) { top: 4px; transform: rotate(45deg); }
.header.is-open .burger__box span:nth-child(2) { top: 4px; transform: rotate(-45deg); }

/* ---- Mobile drawer ----------------------------------------------------- */
.drawer {
  display: none;
  height: calc(100dvh - var(--nav-h));
  overflow-y: auto;
  border-top: 1px solid var(--line);
  background: var(--bg);
}
.header.is-open .drawer { display: block; }
@media (min-width: 1024px) { .header.is-open .drawer { display: none; } }

.drawer__inner {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding-block: 24px 32px;
}
.drawer__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 62px;
  border-bottom: 1px solid var(--line);
  font-size: 1.5rem;
  letter-spacing: -0.03em;
  opacity: 0;
  transform: translateY(8px);
  animation: drawer-in 420ms var(--ease) forwards;
}
.drawer__link span { font-size: 1rem; color: var(--fg-muted); }
@keyframes drawer-in { to { opacity: 1; transform: translateY(0); } }

.drawer .btn { margin-top: 28px; }
.drawer .dot-list { margin-top: auto; padding-top: 40px; }


/* ==========================================================================
   07 · HERO
   --------------------------------------------------------------------------
   A motion graphic across the whole banner, with the claim layered on top.

   The reason this works as a hero and not as wallpaper is the scrim: the
   graphic is allowed to be busy because a two-stop gradient sits between it
   and the type, so contrast on the headline never depends on which frame of
   the animation you happen to land on. Change the graphic freely; do not
   remove the scrim.

   Desktop and mobile are composed differently rather than reflowed. Desktop
   weights the scrim to the left so the claim sits in calm space and the
   motion runs out to the right. Mobile weights it to the bottom: the graphic
   owns the top of the screen, the claim sits under it, centred.
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: min(94vh, 820px);
  display: flex;
  align-items: center;
  padding-top: calc(var(--nav-h) + clamp(40px, 7vw, 72px));
  padding-bottom: clamp(56px, 8vw, 96px);
}

/* ---- The graphic ------------------------------------------------------- */
.hero__stage {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
/* A single bloom off to the side gives the paths somewhere to come from,
   and stops the right half of the banner reading as flat black. */
.hero__stage::before {
  content: "";
  position: absolute;
  right: -14%;
  top: 6%;
  width: min(76rem, 112vw);
  height: min(42rem, 72vh);
  border-radius: 50%;
  background:
    radial-gradient(48% 48% at 55% 45%, var(--accent-glow), transparent 72%),
    radial-gradient(40% 40% at 52% 48%, rgba(242, 244, 249, 0.045), transparent 74%);
}

/* A faint weave under the paths, for texture at rest. */
.hero__weave {
  position: absolute;
  inset: 0;
  opacity: 0.45;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.022) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.022) 1px, transparent 1px);
  background-size: 76px 76px;
 -webkit-mask-image: radial-gradient(90% 80% at 60% 40%, #000 20%, transparent 82%);
  mask-image: radial-gradient(90% 80% at 60% 40%, #000 20%, transparent 82%);
}

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

/* ---- The scrim: what makes the type readable --------------------------- */
.hero__scrim {
  position: absolute;
  inset: 0;
  /* Phone: the ribbon runs BEHIND the claim, not in a band of its own - a
     separate strip below the type read as a second block rather than one
     composition. So the cover is an even veil across the whole banner:
     enough to hold the headline's contrast, light enough that the graphic
     still reads through it. The headline carries a text-shadow on top of
     this, which is what makes the overlap safe at any frame. */
  background: linear-gradient(to bottom,
    var(--bg) 0%,
    color-mix(in srgb, var(--bg) 66%, transparent) 16%,
    color-mix(in srgb, var(--bg) 49%, transparent) 46%,
    color-mix(in srgb, var(--bg) 64%, transparent) 76%,
    var(--bg) 100%);
}

/* ---- The claim --------------------------------------------------------- */
.hero__inner { width: 100%; }


.hero__say {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.hero__title {
  margin-top: 20px;
  font-size: clamp(2.5rem, 1.7rem + 2.7vw, 4.15rem);
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.042em;
  max-width: 15ch;
  /* Cheap insurance: even mid-animation the headline keeps its edge. */
  text-shadow: 0 2px 28px rgba(11, 12, 15, 0.55);
}
.hero__title em { font-style: normal; color: var(--accent-strong); }

.hero__lede {
  margin-top: 22px;
  max-width: 40ch;
  font-size: var(--fs-lede);
  line-height: 1.5;
  color: var(--fg3);
  text-shadow: 0 1px 18px rgba(11, 12, 15, 0.6);
}

.hero__cta { margin-top: 30px; }
.hero__cta .btn-note { margin-top: 14px; }
.hero__channels { justify-content: center; margin-top: 34px; }

/* ---- Desktop: claim left, motion running out to the right -------------- */
@media (min-width: 900px) {
  .hero__say {
    align-items: flex-start;
    text-align: left;
    max-width: 46rem;
  }
  .hero__channels { justify-content: flex-start; }

  .hero__scrim {
    background:
      linear-gradient(to bottom, var(--bg) 0%, transparent 22%, transparent 70%, var(--bg) 100%),
      /* the calm column the type sits in */
      /* Pulled in so the ribbon is genuinely in the frame rather than
         hiding past the fold - the type keeps its calm column, the graphic
         gets the rest. */
      linear-gradient(to right,
        var(--bg) 0%,
        color-mix(in srgb, var(--bg) 78%, transparent) 24%,
        transparent 52%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero__title, .hero__lede { text-shadow: none; }
}


/* ==========================================================================
   08 · MARQUEE & TECHNOLOGY PARTNERS
   --------------------------------------------------------------------------
   One marquee primitive, used by the partner band and the testimonial band.
   Two identical tracks sit side by side and translate in lockstep, so the loop
   is seamless; hovering or tabbing into the band pauses it. Each track sizes
   to its content - the script clones items until a track is wider than the
   viewport, which is what stops a short list leaving a hole in the row.
   ========================================================================== */

.marquee {
  --gap: 20px;
  --duration: 38s;
  position: relative;
  display: flex;
  gap: var(--gap);
  overflow: hidden;
  /* The dissolve at both ends. Applied to the band, not the page, so the
     hairlines above and below stay crisp all the way across. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade, 7%), #000 calc(100% - var(--fade, 7%)), transparent);
  mask-image: linear-gradient(to right, transparent, #000 var(--fade, 7%), #000 calc(100% - var(--fade, 7%)), transparent);
}
/* A percentage fade collapses to a hard slice on a narrow screen, which is
   what made the partner strip look cut off on a phone. */
@media (max-width: 767px) { .marquee { --fade: 14%; } }

.marquee__track {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--gap);
  width: max-content;
  animation: marquee var(--duration) linear infinite;
  will-change: transform;
}
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-100% - var(--gap))); }
}

/* Pause for anyone reading, by pointer or by keyboard. */
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

/* The mask does the dissolving; these stay as a hook for browsers without it. */
.marquee__fade { display: none; }
@supports not ((-webkit-mask-image: linear-gradient(#000, #000)) or (mask-image: linear-gradient(#000, #000))) {
  .marquee__fade {
    position: absolute;
    inset-block: 0;
    z-index: 2;
    display: block;
    width: clamp(32px, 7vw, 110px);
    pointer-events: none;
  }
  .marquee__fade--l { left: 0;  background: linear-gradient(to right, var(--bg), transparent); }
  .marquee__fade--r { right: 0; background: linear-gradient(to left,  var(--bg), transparent); }
}


/* ---- Partner section --------------------------------------------------- */

.partners {
  padding-block: clamp(56px, 5vw, 88px) 0;
  border-top: 1px solid var(--line);
  background: var(--bg);
}

/* Heading left, the qualifying line right, both hanging from the same top
   edge - the previous version bottom-aligned them, which read as a mistake
   against a two-line title. */
.partners__head {
  display: grid;
  gap: 20px;
  margin-bottom: clamp(40px, 4vw, 60px);
}
@media (min-width: 900px) {
  .partners__head {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: 64px;
    align-items: start;
  }
}
.partners__title {
  margin-top: 20px;
  max-width: 18ch;
  font-size: var(--fs-md);
}
.partners__note {
  max-width: 44ch;
  font-size: var(--fs-lede);
  line-height: 1.55;
  color: var(--fg3);
}
@media (min-width: 900px) { .partners__note { margin-top: 46px; } }

/* The band frames the motion so the row reads as one deliberate element
   rather than a scatter of floating chips. */
.partners__band {
  position: relative;
  border-block: 1px solid var(--line);
  background:
    linear-gradient(to bottom, var(--accent-wash), transparent 55%),
    color-mix(in srgb, var(--bg-card) 42%, transparent);
  padding-block: clamp(26px, 3vw, 38px);
}
.partners__band .marquee { --gap: clamp(30px, 7vw, 76px); --duration: 44s; }
@media (max-width: 767px) { .partners__band .marquee { --duration: 32s; } }

/* No pill chrome. Mark plus wordmark, dimmed, brightening on hover - which is
   how a real partner strip behaves and what the placeholder glyphs need to
   avoid looking like buttons. */
.partner {
  display: inline-flex;
  align-items: center;
  gap: 13px;
  flex: none;
  color: var(--fg-muted);
  white-space: nowrap;
  transition: color var(--t-base) var(--ease), opacity var(--t-base) var(--ease);
}
.partner:hover { color: var(--fg1); }
.partner__mark {
  width: 27px; height: 27px;
  flex: none;
  opacity: 0.85;
  transition: opacity var(--t-base) var(--ease), color var(--t-base) var(--ease);
}
.partner:hover .partner__mark { opacity: 1; color: var(--accent-strong); }
.partner span {
  font-size: clamp(1.0625rem, 0.95rem + 0.5vw, 1.1875rem);
  font-weight: 500;
  letter-spacing: -0.02em;
}

/* Reduced motion: stop the slide, let the band be scrolled by hand instead. */
@media (prefers-reduced-motion: reduce) {
  .marquee {
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .marquee::-webkit-scrollbar { display: none; }
  .marquee__track { animation: none; }
  .marquee__track[aria-hidden="true"] { display: none; }
  .partners__band .marquee { padding-inline: var(--edge); }
}

/* Without the script the tracks are never topped up, so a short list would
   leave a hole. Drop the duplicate and centre what is left. */
.no-js .marquee {
  flex-wrap: wrap;
  justify-content: center;
  -webkit-mask-image: none;
  mask-image: none;
}
.no-js .marquee__track {
  animation: none;
  flex-wrap: wrap;
  justify-content: center;
  width: auto;
}
.no-js .marquee__track[aria-hidden="true"] { display: none; }


/* ==========================================================================
   09 · OUR WORK - email design samples
   Replaces the old editorial statement band. Each frame shows the top of a
   full-length email; hovering scrolls the whole thing past.
   ========================================================================== */

.work__head {
  display: flex;
  flex-direction: column;
  gap: 28px;
}
@media (min-width: 900px) {
  .work__head .sec-head { max-width: 46ch; }
}


.work__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 20px;
  margin-top: 44px;
}
/* Five designs, and auto-fill tops out at four - which left the fifth alone
   on a second row. Wide enough to hold them at a sensible size, they go in
   one line. */
@media (min-width: 1180px) {
  .work__grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* Panels swap with a short fade + lift rather than a hard cut. */
.work__panel[hidden] { display: none; }
.work__panel { animation: panel-in 480ms var(--ease) both; }
@keyframes panel-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- A single email sample --------------------------------------------- */

.sample { display: flex; flex-direction: column; }

.sample__frame {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-elev);
  transition: border-color var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.sample:hover .sample__frame {
  border-color: var(--line-strong);
  transform: translateY(-3px);
}

/* The image is far taller than its frame. Parking it at the top shows the
   header of the email; on hover it travels so the whole design can be read
   without opening anything. */
.sample__frame img {
  display: block;
  width: 100%;
  height: auto;
  transform: translateY(0);
  transition: transform 9s linear;
}
.sample:hover .sample__frame img,
.sample:focus-within .sample__frame img,
.sample.is-open .sample__frame img { transform: translateY(-72%); }

.sample__hint {
  position: absolute;
  left: 12px; bottom: 12px;
  z-index: 2;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-glass);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg2);
  opacity: 1;
  transition: opacity var(--t-base) var(--ease);
}
.sample:hover .sample__hint,
.sample.is-open .sample__hint { opacity: 0; }

/* Touch has no hover, so the whole frame becomes a button that scrolls the
   design instead - without this the samples could not be read on a phone. */
@media (hover: none) {
  .sample__frame { cursor: pointer; }
  .sample__frame:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
}


@media (prefers-reduced-motion: reduce) {
  .sample__frame img,
  .sample:hover .sample__frame img { transition: none; transform: none; }
}


/* ==========================================================================
   10 · CHANNELS - "Graphic representation of the channels"
   ========================================================================== */

.channels__layout {
  display: grid;
  gap: 48px;
  margin-top: 52px;
}
@media (min-width: 1080px) {
  .channels__layout { grid-template-columns: minmax(0, 380px) minmax(0, 1fr); gap: 56px; align-items: start; }
}

/* ---- The system diagram ------------------------------------------------ */
.sysmap {
  position: relative;
  padding: 28px 24px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 90% at 50% 0%, var(--accent-wash), transparent 60%),
    color-mix(in srgb, var(--bg-card) 70%, transparent);
}
.sysmap__svg { width: 100%; height: auto; }

/* Connector paths draw themselves in when the section enters view. */
.sysmap__wire {
  fill: none;
  stroke: var(--line-strong);
  stroke-width: 1.25;
  stroke-dasharray: var(--len, 300);
  stroke-dashoffset: var(--len, 300);
  transition: stroke-dashoffset 1200ms var(--ease);
}
.is-in .sysmap__wire { stroke-dashoffset: 0; }

/* A pulse that travels the wire, showing direction of flow. Motion and
   opacity are both animateMotion / animate in the markup - CSS offset-path
   was what left these frozen on mobile. All three channel pulses share one
   begin time, because the point of the diagram is that they arrive at the
   profile together. */
.sysmap__pulse { fill: var(--accent); opacity: 0; }

.sysmap__node {
  fill: var(--bg-elev);
  stroke: var(--line-strong);
  stroke-width: 1;
}
.sysmap__label {
  fill: var(--fg2);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.sysmap__icon { stroke: var(--fg1); stroke-width: 1.4; fill: none; stroke-linecap: round; stroke-linejoin: round; }

.sysmap__caption {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--fg3);
}

/* ---- Channel cards ----------------------------------------------------- */
.channels__cards { display: grid; gap: 16px; }
@media (min-width: 700px)  { .channels__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1080px) { .channels__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.channel-card {
  display: flex;
  flex-direction: column;
  padding: 26px 24px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--bg-card) 72%, transparent);
  transition:
    background-color var(--t-slow) var(--ease),
    border-color var(--t-slow) var(--ease),
    transform var(--t-slow) var(--ease);
}
.channel-card:hover {
  background: var(--bg-card);
  border-color: var(--line-strong);
  transform: translateY(-3px);
}
.channel-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.channel-card h3 { margin-top: 22px; font-size: var(--fs-sm); }
.channel-card__lead {
  margin-top: 8px;
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--accent-strong);
}
.channel-card__body {
  flex: 1;
  margin-top: 12px;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--fg3);
}
.channel-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}

/* The fourth cell states what holds the three channels together. */
.channel-card--sum {
  justify-content: center;
  background:
    linear-gradient(150deg, var(--accent-wash), transparent 55%),
    color-mix(in srgb, var(--bg-card) 72%, transparent);
  border-color: var(--accent-line);
}
.channel-card--sum h3 { margin-top: 18px; max-width: 16ch; }


/* ==========================================================================
   11 · METHOD - lifecycle graph + stage rail
   ========================================================================== */

.method { color: var(--fg1); }

/* ---- The graph: "Add a graph showcasing the lifecycle" ----------------- */
.graph {
  margin-top: 52px;
  padding: 26px 24px 20px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--bg-card) 60%, transparent);
}
@media (min-width: 768px) { .graph { padding: 32px 32px 24px; } }

.graph__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px 24px;
  margin-bottom: 24px;
}
.graph__title { font-size: var(--fs-xs); font-weight: 500; letter-spacing: -0.02em; }
.graph__legend { display: flex; flex-wrap: wrap; gap: 18px; }
.graph__legend li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-small);
  color: var(--fg3);
}
.graph__swatch { width: 14px; height: 3px; border-radius: 2px; flex: none; }
.graph__swatch--flat { background: var(--line-strong); }
.graph__swatch--lift { background: var(--accent); }

.graph__plot { width: 100%; height: auto; overflow: visible; }
.graph__gridline { stroke: var(--line); stroke-width: 1; }
.graph__axis {
  fill: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.graph__line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--len, 1200);
  stroke-dashoffset: var(--len, 1200);
  transition: stroke-dashoffset 1800ms var(--ease) 200ms;
}
.is-in .graph__line { stroke-dashoffset: 0; }
.graph__line--flat { stroke: var(--line-strong); stroke-dasharray: 4 5; stroke-dashoffset: 0; }
.graph__line--lift { stroke: var(--accent); }

.graph__area {
  fill: url(#liftFill);
  opacity: 0;
  transition: opacity 900ms var(--ease) 900ms;
}
.is-in .graph__area { opacity: 1; }

.graph__dot {
  fill: var(--bg);
  stroke: var(--accent);
  stroke-width: 2;
  opacity: 0;
  transform: scale(0.4);
  transform-origin: center;
  transform-box: fill-box;
  transition: opacity 400ms var(--ease), transform 400ms var(--ease);
}
.is-in .graph__dot { opacity: 1; transform: scale(1); }

.graph__callout {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 600ms var(--ease) 1400ms, transform 600ms var(--ease) 1400ms;
}
.is-in .graph__callout { opacity: 1; transform: translateY(0); }
.graph__callout rect { fill: var(--bg-elev); stroke: var(--accent-line); rx: 6; }
.graph__callout text { fill: var(--fg1); font-family: var(--font-mono); font-size: 10px; }

.graph__foot {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: var(--fs-small);
  color: var(--fg-muted);
}

/* ---- Stage rail -------------------------------------------------------- */
.stages { margin-top: 56px; }

/* Mobile is the default; the seven-across rail takes over at 1024px. Both
   declarations sit before the query so the query always wins. */
.stages__desktop { display: none; }

/* ---- The lifecycle loop -------------------------------------------------
   The section claims a continuous lifecycle; a line with two ends argued the
   opposite, so this is a closed figure-of-eight with the purchase on the
   crossing.

   Weight is the whole hierarchy here. The loop is the boldest thing in the
   section, the traced light is brighter still, and the exit branch is the
   thinnest line on the page - a customer leaving should read as a footnote
   to the journey, not a second path through it.

   Desktop only: the curve needs width before six labels can sit around it
   without collapsing into each other, so a phone keeps the vertical rail.
   ------------------------------------------------------------------------ */
/* Capped rather than full-bleed: at container width the figure-of-eight
   grew tall enough to push its own caption off the screen. */
.loop { display: block; max-width: 64rem; margin-inline: auto; }
.stages__mobile { display: none; }

/* ---- Phone: the same loop, scaled ---------------------------------------
   Same horizontal figure-of-eight, same stages, same tracing - only the
   weights change. Stroke, type and nodes are set in viewBox units, so a
   drawing scaled to about a quarter needs them roughly four times larger to
   LAND at the same optical size. The box also opens up (data-vbox) to give
   the enlarged labels somewhere to sit.

   The loop goes full-bleed here: every pixel of column width buys curve.
   ------------------------------------------------------------------------ */
@media (max-width: 899px) {
  .loop {
    max-width: none;
    margin-inline: calc(var(--edge) * -1);
  }

  .loop__base  { stroke-width: 22; }
  .loop__trace { stroke-width: 22; }

  /* The Churn branch is the one thing the phone cannot carry: at this scale
     its label renders about 6px tall, and reserving room for it on the right
     is what pushed the figure-of-eight off centre. It goes, and the eight
     gets the full column. */
  .loop__exit,
  .loop__exitlabel { display: none; }
  .loop__node  { stroke-width: 7; }
  .loop__name  { font-size: 46px; }
  .loop__exit  { stroke-width: 4; stroke-dasharray: 11 13; }
  .loop__exitlabel { font-size: 40px; letter-spacing: 0.14em; }

  /* Scaled about the crossing it sits on, so the pill grows without the
     rect and its label drifting apart. */
  .loop__pivot {
    transform-box: view-box;
    transform-origin: 500px 230px;
    transform: scale(1.75);
  }
}

.loop__svg { width: 100%; height: auto; overflow: visible; }

/* The track the journey runs on. Bold, but recessive. */
.loop__base {
  fill: none;
  stroke: color-mix(in srgb, var(--fg1) 9%, transparent);
  stroke-width: 11;
  stroke-linecap: round;
}

/* The light travelling it. Dash geometry is set by the script from the
   path's real length, so the comet keeps its proportion at any size. */
.loop__trace {
  fill: none;
  stroke: url(#loopGrad);
  stroke-width: 11;
  stroke-linecap: round;
  filter: drop-shadow(0 0 14px var(--accent-glow));
}

/* ---- The few who leave -------------------------------------------------- */
.loop__exit {
  fill: none;
  stroke: var(--line-strong);
  stroke-width: 1.5;
  stroke-dasharray: 5 6;
}
.loop__arrowhead { fill: var(--fg-muted); }
.loop__exitlabel {
  fill: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: 15px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* ---- Stage nodes and labels (built by the script) ---------------------- */
.loop__node {
  fill: var(--bg);
  stroke: color-mix(in srgb, var(--fg1) 22%, transparent);
  stroke-width: 3;
  transition: fill 300ms var(--ease), stroke 300ms var(--ease), r 300ms var(--ease);
}
.loop__node.is-on {
  fill: var(--accent-strong);
  stroke: var(--accent-strong);
}

.loop__name {
  fill: var(--fg3);
  font-size: 25px;
  font-weight: 500;
  letter-spacing: -0.02em;
  text-anchor: middle;
  transition: fill 300ms var(--ease);
}
.loop__label.is-on .loop__name { fill: var(--fg1); }

/* ---- The crossing ------------------------------------------------------ */
.loop__pivot rect {
  fill: var(--bg-elev);
  stroke: var(--accent);
  stroke-width: 2;
}
.loop__pivot text {
  fill: var(--fg1);
  font-size: 25px;
  font-weight: 600;
  letter-spacing: -0.02em;
}
.loop__pivot.is-on rect { fill: var(--accent); stroke: var(--accent-strong); }
.loop__pivot.is-on text { fill: var(--accent-ink); }
.loop__pivot rect, .loop__pivot text { transition: fill 300ms var(--ease), stroke 300ms var(--ease); }

.loop__head {
  fill: #fff;
  filter: drop-shadow(0 0 16px var(--accent));
}

/* ---- What the current stage contains ----------------------------------- */
.loop__detail {
  position: relative;
  max-width: 40rem;
  margin: clamp(16px, 2.4vw, 28px) auto 0;
  min-height: 5.5rem;
}
.loopcard {
  position: absolute;
  inset: 0;
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 400ms var(--ease), transform 400ms var(--ease);
  pointer-events: none;
}
.loopcard[data-on] { opacity: 1; transform: translateY(0); }
.loopcard h4 {
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--fg1);
}
.loopcard p {
  margin-top: 10px;
  font-size: var(--fs-small);
  letter-spacing: 0.02em;
  color: var(--fg-muted);
}

@media (prefers-reduced-motion: reduce) {
  .loopcard { transition: none; }
  .loop__trace { filter: none; }
  .loop__head { display: none; }
}


/* ---- Mobile rail ------------------------------------------------------
   The seven-across desktop rail becomes one vertical spine. The spine has a
   track and a fill, and the fill plus the travelling dot are driven by
   --rail (0-1) which the script sets from scroll position - so the marker
   follows the path down as the list passes, instead of sitting still.
   ------------------------------------------------------------------------ */

.stages__mobile { --rail: 0; position: relative; padding-left: 30px; }

.rail {
  position: absolute;
  left: 4px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: var(--line-strong);
}
.rail__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 1px;
  height: calc(var(--rail) * 100%);
  background: linear-gradient(to bottom, var(--accent-deep), var(--accent));
}
.rail__dot {
  position: absolute;
  left: 50%;
  top: calc(var(--rail) * 100%);
  width: 9px; height: 9px;
  margin: -4px 0 0 -4.5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--bg), 0 0 14px 2px var(--accent-glow);
}

.mstages { display: grid; gap: 34px; }

.mstage { position: relative; }
.mstage__node {
  position: absolute;
  left: -30px;
  top: 5px;
  width: 7px; height: 7px;
  margin-left: 1px;
  border-radius: 50%;
  background: var(--line-strong);
  box-shadow: 0 0 0 3px var(--bg);
  transition: background-color var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
/* Lit once the rail has travelled past this stage. */
.mstage.is-passed .mstage__node { background: var(--accent); transform: scale(1.2); }

.mstage h3 {
  margin-top: 9px;
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--fg1);
}
/* The bug this replaces: the old markup carried no list styling at all, so
   these inherited body sizing and block spacing and sprawled down the page. */
.mstage ul { display: grid; gap: 6px; margin-top: 11px; }
.mstage ul li {
  font-size: var(--fs-small);
  line-height: 1.35;
  color: var(--fg-muted);
}
.mstage.is-passed ul li { color: var(--fg3); }

@media (prefers-reduced-motion: reduce) {
  .mstage__node, .rail__fill, .rail__dot { transition: none; }
}


/* ==========================================================================
   12 · PROCESS - a stepped path, walked by scroll
   --------------------------------------------------------------------------
   The four phases sit on a zigzag joined by right-angle elbows. Each title
   illuminates word by word as its step crosses the screen, and the panel
   alongside swaps to whatever that phase produces.

   The elbows are drawn with two borders and one corner radius rather than an
   SVG, so the path reflows with the type at every width instead of needing
   the geometry recomputed.
   ========================================================================== */

.phases { margin-top: clamp(64px, 7vw, 104px); }

/* ---- The path ---------------------------------------------------------
   One column, not two. The reference put a photograph alongside; without it
   the path gets the width to itself and the zigzag has room to read.
   ------------------------------------------------------------------------ */
.phases__steps {
  margin-top: clamp(36px, 4vw, 60px);
  max-width: 44rem;
  --rail: 13px;          /* centre of the node column                      */
  --jog: 46px;           /* how far the b-side steps sit in                */
  position: relative;
  display: grid;
}
@media (min-width: 560px) { .phases__steps { --jog: 68px; } }

.phase {
  position: relative;
  padding-left: 46px;
  padding-bottom: clamp(46px, 5vw, 66px);
}
.phase--b { margin-left: var(--jog); }
.phase:last-child { padding-bottom: 0; }

/* The elbow to the next step: down out of this node, then across to the
   next one's rail. Mirrored for the steps that jog back left. */
.phase::after {
  content: "";
  position: absolute;
  left: var(--rail);
  top: 34px;
  bottom: 14px;
  width: var(--jog);
  border-left: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-strong);
  border-bottom-left-radius: 16px;
  opacity: 0.55;
  transition: opacity var(--t-slow) var(--ease), border-color var(--t-slow) var(--ease);
}
.phase--b::after {
  left: auto;
  right: calc(100% - var(--rail) - 1px);
  border-left: 0;
  border-right: 1px solid var(--line-strong);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 16px;
}
.phase:last-child::after { display: none; }
.phase.is-on::after { opacity: 1; border-color: var(--accent-line); }

/* ---- The node --------------------------------------------------------- */
.phase__node {
  position: absolute;
  left: 0;
  top: 4px;
  display: grid;
  place-items: center;
  width: 27px; height: 27px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--bg);
  color: var(--fg-muted);
  transition:
    border-color var(--t-slow) var(--ease),
    color var(--t-slow) var(--ease),
    background-color var(--t-slow) var(--ease),
    transform var(--t-slow) var(--ease);
}
.phase__node svg { width: 14px; height: 14px; }
.phase.is-on .phase__node {
  border-color: var(--accent);
  background: var(--accent-wash);
  color: var(--accent-strong);
  transform: scale(1.08);
}

.phase__idx {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  color: var(--fg-muted);
  transition: color var(--t-slow) var(--ease);
}
.phase.is-on .phase__idx { color: var(--accent-strong); }

/* ---- Word-by-word illumination ---------------------------------------- */
.phase__title {
  margin-top: 10px;
  font-size: clamp(1.6rem, 1.15rem + 1.9vw, 2.5rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.035em;
}
/* Wrapped by the script. Words start dim and are lit as the step is walked
   past, which is the whole read of the section - the path is being travelled,
   not just revealed. */
.phase__title .w {
  color: var(--fg-muted);
  transition: color 420ms var(--ease);
}
.phase__title .w.is-lit { color: var(--fg1); }
.no-js .phase__title .w { color: var(--fg1); }

/* Step 04 - the point where the client decides. The one beat in accent, so
   the section reads as a journey with a decision in it rather than a task
   list. */
.phase--turn .phase__title .w.is-lit { color: var(--accent-strong); }
.phase--turn .phase__node { border-color: var(--accent-line); }
.phase--turn.is-on .phase__node {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}

.phase__body {
  margin-top: 14px;
  max-width: 46ch;
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--fg-muted);
  transition: color var(--t-slow) var(--ease);
}
.phase.is-on .phase__body { color: var(--fg3); }


@media (prefers-reduced-motion: reduce) {
  .phase__title .w { transition: none; }
}


/* ==========================================================================
   13 · RESULTS - case-study slider
   Layout follows the supplied reference: statement on the left, the
   before/after account screens stacked on the right, one case per slide.
   ========================================================================== */

.results__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}

.slider { margin-top: 48px; }

.slider__viewport {
  overflow: hidden;
  border-radius: var(--r-xl);
  transition: height 600ms var(--ease);
}
.slider__track {
  display: flex;
  align-items: flex-start;
  transition: transform 700ms var(--ease);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .slider__viewport { transition: none; }
}
.slider__track.is-dragging { transition: none; }

.slide {
  flex: 0 0 100%;
  min-width: 0;
  padding: 28px 22px;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background:
    radial-gradient(90% 120% at 100% 0%, var(--accent-wash), transparent 55%),
    color-mix(in srgb, var(--bg-card) 60%, transparent);
}
@media (min-width: 768px)  { .slide { padding: 40px 36px; } }
@media (min-width: 1080px) { .slide { padding: 52px 48px; } }

.slide__grid { display: grid; gap: 36px; }
@media (min-width: 1080px) {
  .slide__grid {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    gap: 56px;
    align-items: center;
  }
}

/* ---- Left column: the claim ------------------------------------------- */
.slide__example {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.slide__sector { margin-top: 18px; }
.slide__claim {
  margin-top: 22px;
  font-size: clamp(1.5rem, 1.15rem + 1.6vw, 2.375rem);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -0.035em;
  max-width: 20ch;
}
.slide__claim em {
  font-style: normal;
  color: var(--pos);
  font-variant-numeric: tabular-nums;
}
.slide__body {
  margin-top: 20px;
  max-width: 44ch;
  font-size: var(--fs-lede);
  line-height: 1.5;
  color: var(--fg3);
}

.slide__metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin-top: 32px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
}
/* Sans, not mono, for one reason: in a monospace face the full stop takes a
   whole character cell, so "$1.36M" and "33.92%" read with a gap either side
   of the decimal. Tabular figures keep the columns lining up without it. */
.slide__metrics dd {
  font-family: var(--font-sans);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  font-weight: 600;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  color: var(--fg1);
}
.slide__metrics dt {
  margin-top: 8px;
  font-size: var(--fs-small);
  line-height: 1.3;
  color: var(--fg-muted);
}

/* ---- Right column: the account screens --------------------------------
   These ship as rendered images (assets/results/), not as markup - see the
   note in index.html. Each card carries its own border, radius and light
   palette inside the raster, with transparent corners, so the only thing
   left to the page is the lift off the background.
   ------------------------------------------------------------------------ */

.shots { display: grid; gap: 18px; }

.ks-shot { min-width: 0; }
.ks-shot picture { display: block; }
.ks-shot img {
  display: block;
  width: 100%;
  height: auto;
  /* drop-shadow rather than box-shadow: it follows the alpha channel, so the
     lift traces the card's rounded corners instead of a rectangle behind them. */
  filter: drop-shadow(0 22px 34px rgba(0, 0, 0, 0.55));
}

@media (prefers-reduced-motion: reduce) {
  .ks-shot img { filter: none; }
}


/* ---- Slider controls ---------------------------------------------------
   Six cases rather than three, so the dot row is long enough to push the
   counter and arrows off a phone screen - which is what was making the whole
   page scroll sideways. The row wraps, and the dots step down on small
   screens so the set still fits on one line. */
.slider__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 20px;
  margin-top: 28px;
}
.slider__dots { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.slider__dot {
  position: relative;
  width: 18px; height: 3px;
  border-radius: 2px;
  background: var(--line-strong);
  transition: background-color var(--t-base) var(--ease), width var(--t-base) var(--ease);
}
.slider__dot[aria-selected="true"] { width: 32px; background: var(--accent); }
@media (min-width: 640px) {
  .slider__dots { gap: 10px; }
  .slider__dot { width: 30px; }
  .slider__dot[aria-selected="true"] { width: 48px; }
}
.slider__dot::after {
  /* Larger invisible hit area - keeps the visual thin but the target 44px. */
  content: "";
  position: absolute;
  inset: -20px -6px;
}
.slider__count {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  letter-spacing: 0.1em;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}
.slider__nav { display: flex; align-items: center; gap: 14px; margin-left: auto; }
.slider__arrows { display: flex; gap: 10px; }


/* ==========================================================================
   14 · TESTIMONIALS - quote cards with the person attached
   --------------------------------------------------------------------------
   Four cards in a row, each ending in a face. The old sliding band of brand
   wordmarks kept two cards half-cut at the edges on a phone; a grid reads in
   one pass and puts the person, not the logo, at the end of the quote.
   ========================================================================== */

/* The band the cards travel in. Full-bleed rather than inside the shell:
   a card sliding to a stop 48px short of the edge reads as a broken grid,
   not as motion. */
.voiceband__rail {
  margin-top: clamp(40px, 4vw, 56px);
}
.marquee--voices {
  --gap: 18px;
  --duration: 68s;          /* ~25px/s - slow enough to read a card in passing */
  --fade: 5%;
}
@media (max-width: 767px) { .marquee--voices { --duration: 46s; --fade: 8%; } }

/* Cards differ in length; stretching them to a common height is what keeps
   the row of attributions on one line as the band moves. */
.marquee--voices .marquee__track { align-items: stretch; }
.marquee--voices .voice { width: clamp(280px, 76vw, 372px); flex: none; }

@media (prefers-reduced-motion: reduce) {
  .voiceband__rail .marquee { padding-inline: var(--edge); }
}

.voice { display: flex; }
.voice figure {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 26px 24px 22px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--bg-card) 70%, transparent);
  transition:
    background-color var(--t-slow) var(--ease),
    border-color var(--t-slow) var(--ease),
    transform var(--t-slow) var(--ease);
}
.voice:hover figure {
  background: var(--bg-card);
  border-color: var(--line-strong);
  transform: translateY(-3px);
}

.voice__mark { width: 24px; height: 24px; color: var(--accent); opacity: 0.75; }

.voice blockquote {
  flex: 1;
  margin-top: 18px;
  font-size: 1rem;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--fg2);
}

/* ---- The person ---- */
.voice__by {
  display: flex;
  align-items: center;
  gap: 13px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}
.voice__face {
  width: 46px; height: 46px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-elev);
  /* Keeps four different photographs, shot in four different rooms, from
     reading as a scrapbook. */
  filter: grayscale(0.35) contrast(1.02);
  transition: filter var(--t-slow) var(--ease);
}
.voice:hover .voice__face { filter: grayscale(0) contrast(1); }


.voice__who { display: grid; gap: 3px; min-width: 0; }
.voice__name {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg1);
}
.voice__role {
  font-size: var(--fs-small);
  line-height: 1.35;
  color: var(--fg-muted);
}
.voice__role em { font-style: normal; color: var(--accent-strong); }


/* ==========================================================================
   15 · CAPABILITIES ACCORDION - why Retain Matters
   ========================================================================== */

.caps__layout { display: grid; gap: 44px; margin-top: 48px; }
@media (min-width: 1024px) {
  .caps__layout { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); gap: 64px; align-items: start; }
}

.caps__list { border-top: 1px solid var(--line); }
.caps__item { border-bottom: 1px solid var(--line); }

.cap-row {
  display: flex;
  align-items: center;
  gap: 18px;
  width: 100%;
  padding-block: 20px;
  text-align: left;
}
.cap-row__title {
  flex: 1;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: -0.022em;
  color: var(--fg2);
  transition: color var(--t-base) var(--ease);
}
.cap-row:hover .cap-row__title,
.cap-row[aria-expanded="true"] .cap-row__title { color: var(--fg1); }

/* Plus that becomes a minus. */
.plus { position: relative; width: 14px; height: 14px; flex: none; }
.plus::before, .plus::after {
  content: "";
  position: absolute;
  background: currentColor;
  transition: transform var(--t-base) var(--ease), opacity var(--t-base) var(--ease);
}
.plus::before { left: 0; top: 50%; width: 100%; height: 1px; transform: translateY(-50%); }
.plus::after  { top: 0; left: 50%; width: 1px; height: 100%; transform: translateX(-50%); }
[aria-expanded="true"] .plus::after { transform: translateX(-50%) rotate(90deg); opacity: 0; }

.cap-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 420ms var(--ease);
}
.cap-panel.is-open { grid-template-rows: 1fr; }
.cap-panel > div { overflow: hidden; }
.cap-panel p {
  padding: 0 32px 24px 64px;
  max-width: 58ch;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--fg3);
}

/* Left column: the proposition, plus a compact icon grid. */
.caps__icons {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid var(--line);
}
.caps__icon svg { width: 26px; height: 26px; color: var(--accent-strong); }
.caps__icon b {
  display: block;
  margin-top: 14px;
  font-size: 0.875rem;
  font-weight: 500;
}
.caps__icon span {
  display: block;
  margin-top: 5px;
  font-size: var(--fs-small);
  line-height: 1.45;
  color: var(--fg-muted);
}


/* ==========================================================================
   16 · WHO WE WORK WITH
   Statement only. The qualifying checklist is gone by design - the section
   should read as open, not as a gate.
   ========================================================================== */

.audience__head { display: grid; gap: 24px; }
@media (min-width: 900px) {
  .audience__head {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 56px;
    align-items: start;
  }
  .audience__head .sec-title { max-width: 16ch; }
}
.audience__head .cta-row { margin-top: 28px; }


/* ==========================================================================
   17 · FAQ
   ========================================================================== */

.faq__layout { display: grid; gap: 44px; }
@media (min-width: 1024px) {
  .faq__layout { grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr); gap: 64px; align-items: start; }
}

/* The left column used to be empty. It now carries the thing a reader wants
   when the FAQ has not answered them. */
.faq__aside {
  position: sticky;
  top: calc(var(--nav-h) + 32px);
}
@media (max-width: 1023px) { .faq__aside { position: static; } }

.faq__card {
  margin-top: 36px;
  padding: 26px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 100% at 0% 0%, var(--accent-wash), transparent 58%),
    color-mix(in srgb, var(--bg-card) 70%, transparent);
}
.faq__card h3 { font-size: var(--fs-xs); font-weight: 500; }
.faq__card p {
  margin-top: 10px;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--fg3);
}
.faq__card .btn { margin-top: 22px; }
.faq__direct {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: var(--fs-small);
  color: var(--fg-muted);
}
.faq__direct svg { width: 15px; height: 15px; flex: none; }

.faq__list { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }

.faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 28px;
  width: 100%;
  padding-block: 24px;
  text-align: left;
}
.faq__q span:first-child {
  max-width: 40ch;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: -0.022em;
  color: var(--fg2);
  transition: color var(--t-base) var(--ease);
}
.faq__q:hover span:first-child,
.faq__q[aria-expanded="true"] span:first-child { color: var(--fg1); }
.faq__q .plus { margin-top: 5px; }

.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 420ms var(--ease);
}
.faq__a.is-open { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p {
  padding-bottom: 26px;
  padding-right: 40px;
  max-width: 58ch;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--fg3);
}


/* ==========================================================================
   18 · ABOUT
   ========================================================================== */

.about__layout { display: grid; gap: 44px; }
@media (min-width: 1024px) {
  .about__layout { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 64px; align-items: center; }
}

.about__copy { display: grid; gap: 22px; margin-top: 32px; }
.about__copy p { font-size: var(--fs-lede); line-height: 1.55; color: var(--fg3); }
.about .dot-list { margin-top: 34px; padding-top: 28px; border-top: 1px solid var(--line); }

/* ---- Lifestyle image ---------------------------------------------------
   The <img> sits on top of a designed fallback, so the block still reads as
   intentional if the photograph has not been dropped in yet. */
.about__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background:
    radial-gradient(120% 100% at 20% 0%, var(--accent-wash), transparent 60%),
    linear-gradient(150deg, var(--bg-elev), var(--bg-night));
}
.about__media picture,
.about__media img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.about__media img {
  /* Pulls any photograph into the site's cool, low-key range so it sits in the
     dark band instead of punching a bright hole in it. */
  filter: grayscale(0.42) contrast(1.06) brightness(0.72);
  transition: transform 900ms var(--ease), filter 900ms var(--ease);
}
.about__media:hover img {
  transform: scale(1.03);
  filter: grayscale(0.2) contrast(1.06) brightness(0.86);
}

/* Scrim keeps the caption legible over the lighter part of the frame. */
.about__media-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, rgba(7, 8, 11, 0.72), rgba(7, 8, 11, 0) 45%);
}

.about__media-grid {
  position: absolute;
  inset: 0;
  opacity: 0.6;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 48px 48px;
  pointer-events: none;
}


/* ==========================================================================
   19 · FINAL CTA - "this section needs to be bold and direct"
   ========================================================================== */

.final { position: relative; overflow: hidden; text-align: center; }
.final__bloom {
  position: absolute;
  left: 50%; bottom: -22rem;
  width: min(70rem, 140vw); height: 40rem;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%, var(--accent-glow), transparent 70%);
  pointer-events: none;
}
.final__inner { position: relative; max-width: 64rem; margin-inline: auto; }

.final__title {
  margin-top: 26px;
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 0.98;
  letter-spacing: -0.042em;
}
.final__lede {
  margin-top: 26px;
  margin-inline: auto;
  max-width: 46ch;
  font-size: var(--fs-lede);
  line-height: 1.5;
  color: var(--fg3);
}
.final__terms {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 22px;
  margin-top: 40px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
}
.final__terms li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-small);
  color: var(--fg-muted);
}
.final__terms svg { width: 14px; height: 14px; color: var(--accent); flex: none; }


/* ==========================================================================
   20 · FOOTER
   ========================================================================== */

.footer {
  position: relative;
  border-top: 1px solid var(--line);
  background: var(--bg);
  color: var(--fg1);
}
.footer::before {
  content: "";
  position: absolute;
  left: 50%; top: 0;
  width: 33%; height: 1px;
  transform: translateX(-50%);
  background: var(--accent-line);
  filter: blur(1px);
}

/* ---- Footer columns ---------------------------------------------------- */
.footer__main {
  display: grid;
  gap: 44px;
  padding-block: clamp(44px, 5vw, 72px);
}
@media (min-width: 900px) {
  .footer__main { grid-template-columns: minmax(0, 1.2fr) repeat(2, minmax(0, 0.9fr)); gap: 32px; }
}
.footer__blurb {
  margin-top: 22px;
  max-width: 32ch;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--fg3);
}
.footer__col h3 { font-family: var(--font-mono); font-size: var(--fs-label); font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--fg-muted); }
.footer__col ul { margin-top: 20px; display: grid; gap: 12px; }
.footer__col a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* Keeps every footer link at or above the 24px minimum target size. */
  min-height: 26px;
  padding-block: 2px;
  font-size: var(--fs-body);
  color: var(--fg2);
  transition: color var(--t-base) var(--ease);
}
.footer__col a:hover { color: var(--fg1); }
.footer__col a svg {
  width: 13px; height: 13px;
  color: var(--fg-muted);
  transition: transform var(--t-slow) var(--ease), color var(--t-slow) var(--ease);
}
.footer__col a:hover svg { transform: translate(2px, -2px); color: var(--accent); }

/* One line now that the legal links have gone, so it no longer needs to be a
   row that collapses. */
.footer__bottom {
  padding-block: 26px 34px;
  border-top: 1px solid var(--line);
}


/* ==========================================================================
   21 · MOTION SYSTEM
   --------------------------------------------------------------------------
   Mirrors lib/motion.ts: an 18px lift, 700ms, EASE_PREMIUM, fired once when
   the element scrolls into view. [data-reveal] is the child; [data-stagger]
   on a parent walks its children with a delay step, exactly like Framer
   Motion's staggerChildren. Ported back to React this is a 1:1 mapping.
   ========================================================================== */

[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 700ms var(--ease) var(--delay, 0ms),
    transform 700ms var(--ease) var(--delay, 0ms);
  will-change: opacity, transform;
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* Variants used where a plain lift is not the right gesture. */
[data-reveal="fade"]  { transform: none; }
[data-reveal="blur"]  { transform: translateY(-8px); filter: blur(4px); }
[data-reveal="blur"].is-in { filter: blur(0); }
[data-reveal="scale"] { transform: translateY(14px) scale(0.985); }

/* Once revealed, drop will-change so long pages do not hold GPU layers. */
[data-reveal].is-settled { will-change: auto; }


/* ==========================================================================
   22 · ACCESSIBILITY & PRINT
   ========================================================================== */

/* Anything that has not been revealed yet must still be readable if the
   script never runs. */
.no-js [data-reveal] { opacity: 1; transform: none; filter: none; }
.no-js .cap-panel,
.no-js .faq__a { grid-template-rows: 1fr; }

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

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

  /* Reveals resolve instantly rather than being left mid-transition. */
  [data-reveal] { opacity: 1; transform: none; filter: none; }
  .is-in .graph__line,
  .is-in .sysmap__wire { stroke-dashoffset: 0; }
  .stages__wire { transform: scaleX(1); }
  .is-in .sysmap__pulse { animation: none; opacity: 0; }
  .chip .pulse { animation: none; }
  .slider__track { transition: none; }
}

/* Coarse pointers get a bigger hit area on the small controls. */
@media (pointer: coarse) {
  .slider__dot { height: 4px; }
  .tab { height: 44px; }
  .icon-btn { width: 44px; height: 44px; }
}

@media print {
  .marquee__track { animation: none; }
  .marquee { overflow: visible; -webkit-mask-image: none; mask-image: none; }
  .header, .skip-link, .slider__controls, .marquee__fade, .final__bloom, .hero__backdrop { display: none !important; }
  body { background: #fff; color: #000; }
  .section { padding-block: 24px; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.75em; }
}
