/* ==========================================================================
   Wiseman Analytics (film version, from v2)
   One lead effect: a 3D film down the whole page, from a tangle to one clear
   line (film.js, Tier 2C in ~/studio/assets/3d-playbook.md). Scroll scenes
   and micro-interactions support it in the same language: lines that draw,
   a red pen that corrects, steps that arrive in order.
   Mobile-first. Bright only, at Dan's request: dark-mode phones get the same
   white page. No framework, no build step. WCAG 2.2 AA.
   ========================================================================== */

/* --- Tokens --------------------------------------------------------------- */

:root {
  color-scheme: only light;

  /* Ratios measured with ../../assets/contrast-check.js */
  --paper:      #ffffff;   /* bright white */
  --paper-alt:  #f2f5fb;   /* cool light tint for alternate sections */
  --ink:        #121826;   /* 17.7:1 on --paper */
  --ink-muted:  #4b5565;   /* 7.5:1 on --paper, 6.9:1 on --paper-alt */
  --line:       #dfe5ef;   /* decorative rules only */
  --line-ui:    #4b5565;   /* input borders, 7.5:1 */
  --accent:     #2747d6;   /* bright cobalt. 7.1:1 on --paper, 6.5:1 on --paper-alt */
  --accent-ink: #ffffff;   /* 7.1:1 on --accent */
  --pen:        #d62839;   /* the red pen: strike-throughs only. 5.0:1 */
  --focus:      #c2410c;   /* 5.2:1 on --paper, distinct from the blue buttons */
  --map-line:   #a9b4c8;   /* decorative, 2.1:1; text keeps a paper halo over it */
  --glow:       rgb(39 71 214 / 0.22);
  --btn:        var(--accent);
  --btn-ink:    var(--accent-ink);

  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               Arial, sans-serif;
  /* Serif with lining figures on every platform: Charter (Apple), Sitka/Cambria
     (Windows), Noto Serif (Android). Georgia last; its numerals are old-style. */
  --font-serif: Charter, "Bitstream Charter", "Sitka Text", Cambria,
                "Noto Serif", "Iowan Old Style", Georgia, serif;

  --step--1: clamp(0.88rem, 0.85rem + 0.15vw, 0.95rem);
  --step-0:  clamp(1.05rem, 1rem + 0.25vw, 1.15rem);
  --step-1:  clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
  --step-2:  clamp(1.6rem, 1.4rem + 1vw, 2.2rem);
  --step-3:  clamp(1.9rem, 1.5rem + 2vw, 3rem);
  --figure:  clamp(3.1rem, 0.9rem + 10.5vw, 7.25rem);   /* 404 page */

  --step-4:  clamp(2.2rem, 1.4rem + 3.4vw, 4.25rem);  /* section titles */

  --section-y: clamp(3.5rem, 10vw, 8rem);   /* more air */
  /* v2: wider, at Darren's request. Text keeps a readable measure; the
     extra width goes to columns, not longer lines. */
  --wrap: 86rem;
  --gutter: clamp(1rem, 3.5vw, 3rem);
  --radius: 3px;
  --header-h: 4.25rem;
}


/* --- Reset ---------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  /* Keeps focused elements clear of the sticky header (WCAG 2.4.11) */
  scroll-padding-top: calc(var(--header-h) + 1rem);
  /* and clear of the fixed pause button */
  scroll-padding-bottom: 4.5rem;
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
h1, h2, h3 { line-height: 1.15; text-wrap: balance; }
h1, h2 { font-family: var(--font-serif); font-weight: 600; }
p { text-wrap: pretty; }
abbr[title] { text-decoration: none; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* --- Focus ---------------------------------------------------------------- */

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.75rem 1rem;
  background: var(--paper);
  color: var(--ink);
  border: 2px solid var(--ink);
}
.skip-link:focus { left: 0.5rem; top: 0.5rem; }

/* --- Links ---------------------------------------------------------------- */

a {
  color: var(--accent);
  text-underline-offset: 0.18em;
  transition: text-decoration-thickness 150ms ease, text-underline-offset 150ms ease;
}
a:hover { text-decoration-thickness: 2px; text-underline-offset: 0.26em; }

/* --- Layout --------------------------------------------------------------- */

.wrap {
  width: min(100% - 2 * var(--gutter), var(--wrap));
  margin-inline: auto;
}

.section { padding-block: var(--section-y); border-top: 1px solid var(--line); }
.section-alt { background: var(--paper-alt); }
.section h2 {
  font-size: var(--step-4);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.section p { max-width: 62ch; }
.muted-text { color: var(--ink-muted); }

/* Section opening: a big title on the left, a short plain intro on the right,
   so wide screens use their width without stretching any line of text. */
.section-head {
  display: grid;
  gap: 1rem 4rem;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}
.section-intro { color: var(--ink-muted); font-size: var(--step-1); line-height: 1.5; }
.section-intro p + p { margin-top: 0.75em; }
@media (min-width: 56rem) {
  .section-head { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: end; }
  .section-intro { max-width: 36rem; }
}

/* Small sentence-case labels. Never all caps. */
.tag {
  display: block;
  margin-bottom: 0.2rem;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 700;
  font-style: normal;
  color: var(--ink);
}

/* --- Preview banner ------------------------------------------------------- */

.preview-banner {
  background: var(--ink);
  color: var(--paper);
  text-align: center;
  padding: 0.5rem 1rem;
  font-size: var(--step--1);
  font-weight: 600;
}

/* --- Header --------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

/* Short screens (landscape phones, high zoom): don't pin the header,
   so it doesn't eat a quarter of the view. */
@media (max-height: 30rem) {
  .site-header { position: static; }
  html { scroll-padding-top: 1rem; }
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: var(--header-h);
  padding-block: 0.6rem;
}

.logo {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: var(--step-1);
  line-height: 1.15;
  white-space: nowrap;
  padding-block: 0.8rem;   /* 44px+ tap target */
  color: var(--ink);
  text-decoration: none;
  margin-right: auto;
}

/* Phone: one line for the name, beside the button. Below 360px it may wrap. */
@media (max-width: 26rem) {
  .logo { font-size: 1.05rem; }
  .btn-small { padding-inline: 0.75rem; }
}
@media (max-width: 22.4rem) {
  .logo { white-space: normal; }
}

/* Below 76rem only the name and the call button fit beside five links.
   Hide the whole nav so it doesn't add flex gaps either. */
.site-header nav { display: none; }

@media (min-width: 76rem) {
  .header-inner { column-gap: 2rem; }
  .site-header nav { display: block; }
  .nav-list {
    display: flex;
    gap: 1.75rem;
    list-style: none;
    padding: 0;
  }
  .nav-list a {
    display: inline-block;
    padding-block: 0.6rem;
    color: var(--ink-muted);
    text-decoration: none;
  }
  .nav-list a:hover { color: var(--ink); text-decoration: underline; }
}

/* --- Buttons -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0.7rem 1.4rem;
  border: 2px solid transparent;
  border-radius: var(--radius);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  gap: 0.55rem;
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.btn-primary { background: var(--btn); color: var(--btn-ink); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 20px -6px var(--glow); }
.btn-primary:active { transform: translateY(0) scale(0.98); box-shadow: none; }
.btn-arrow { display: inline-block; transition: transform 160ms ease; }
.btn:hover .btn-arrow { transform: translateX(4px); }
.btn-small { min-height: 44px; padding: 0.5rem 1rem; white-space: nowrap; }

/* Secondary text link with an underline that grows on hover and focus. */
.text-link {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.3em;
}
.text-link:hover, .text-link:focus-visible { color: var(--accent); text-decoration-thickness: 3px; }

/* --- Header button label -------------------------------------------------- */
/* The full label doesn't fit beside the name on small phones. Only one span
   is ever displayed, so the accessible name always matches what's visible. */
.label-long { display: none; }
@media (min-width: 32rem) {
  .label-long { display: inline; }
  .label-short { display: none; }
}

/* --- The film (Tier 2C) ---------------------------------------------------- */
/* One 3D world behind the whole page (film.js). The words never live in it:
   every section is real HTML on a bright sheet that scrolls over the film,
   and each scene gets a "stage" between sections where the film is the
   picture and a huge title slides across. Without the film (reduced motion,
   Save-Data, weak devices, no JavaScript) each stage shows a designed still
   frame rendered from the film itself. */

.film {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: none;
  pointer-events: none;
  overflow: hidden;
}
html.film-on .film { display: block; }
.film canvas {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 900ms ease;
}
html.film-ready .film canvas { opacity: 1; }
/* A soft lens vignette frames the film like a camera. The words never sit
   on it: they are on the white sheets or the hero's white wash. */
.film::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(130% 95% at 50% 45%, transparent 62%, rgb(40 52 90 / 0.1) 100%);
}

/* Labels the film pins to its objects. Decorative copies of words that are
   in the page; white pills with ink text, so they pass in every frame. */
.film-labels { position: fixed; inset: 0; z-index: 5; pointer-events: none; }
.film-label {
  position: absolute;
  left: 0;
  top: 0;
  max-width: min(17rem, 44vw);
  padding: 0.4rem 0.7rem 0.45rem;
  background: rgb(255 255 255 / 0.95);
  color: var(--ink);
  border-radius: var(--radius);
  box-shadow: 0 6px 18px -8px rgb(18 24 38 / 0.35);
  font-size: var(--step--1);
  font-weight: 700;
  line-height: 1.25;
  opacity: 0;
  will-change: transform, opacity;
}
.film-label b { display: block; color: var(--accent); font-family: var(--font-serif); font-size: 1.05em; }
.film-label--plain { text-align: center; }
.film-lead {
  position: absolute;
  left: 0;
  top: 0;
  height: 2px;
  background: var(--ink);
  transform-origin: 0 50%;
  opacity: 0;
}
.film-lead::after {
  content: "";
  position: absolute;
  right: -5px;
  top: -4px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px #fff;
}
@media (min-width: 48rem) {
  .film-label { font-size: var(--step-0); padding: 0.5rem 0.85rem 0.55rem; }
}

/* --- Hero: Clarity, the opening scene ------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  overflow: clip;
  /* One full screen under the banner and header. */
  min-height: calc(100svh - var(--header-h) - 2.4rem);
  display: flex;
  flex-direction: column;
  padding-block: 1.6rem clamp(11rem, 34vw, 15rem);
}
.hero-inner { position: relative; }

/* The opening frame: a picture first (it's the page's main image), then the
   live film fades in over it. Bottom-aligned, so it lines up with the film,
   which fills the whole screen behind the header. */
.hero-poster {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero-poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 100%;
}
html.film-ready .hero-poster { opacity: 0; transition: opacity 900ms ease; }

/* A soft white wash where the words are: top on phones, left on wide
   screens. With the halo below, every letter sits on near-white. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 55%, transparent 100%);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.78) 0%, rgb(255 255 255 / 0.62) 42%, rgb(255 255 255 / 0) 70%);
}
@media (min-width: 48rem) and (min-aspect-ratio: 1/1) {
  .hero { justify-content: center; padding-block: clamp(2rem, 5vw, 4rem) clamp(7rem, 12vw, 10rem); }
  .hero::before {
    background: linear-gradient(90deg, rgb(255 255 255 / 0.93) 0%, rgb(255 255 255 / 0.88) 36%, rgb(255 255 255 / 0.5) 46%, rgb(255 255 255 / 0) 60%);
  }
}

.hero-kicker {
  max-width: 34ch;
  font-size: var(--step--1);
  font-weight: 700;
  line-height: 1.45;
  color: var(--accent);
}

.hero h1 {
  margin-top: 0.6rem;
  font-size: clamp(1.95rem, 1rem + 4.6vw, 3.4rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.025em;
  max-width: 17ch;
}

.hero-lede {
  margin-top: 0.9rem;
  max-width: 40ch;
  font-size: var(--step-0);
  line-height: 1.5;
  color: var(--ink);
}

.hero-who {
  margin-top: 0.75rem;
  max-width: 40ch;
  color: var(--ink-muted);
}

.hero-action {
  margin-top: 1.4rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.75rem;
}

/* Phones: the city must show on the first screen, so the opening is compact.
   The "who it's for" line is in the services intro too. */
@media (max-width: 39.99rem) {
  .hero-who, .hero .text-link { display: none; }
}

@media (min-width: 48rem) and (min-aspect-ratio: 1/1) {
  .hero-kicker { max-width: none; }
  .hero h1 { margin-top: 0.9rem; max-width: 13ch; font-size: clamp(2.6rem, 0.6rem + 4vw, 5.2rem); }
  .hero-lede { margin-top: 1.25rem; max-width: 40ch; font-size: var(--step-1); }
  .hero-who { max-width: 46ch; }
  .hero-action { margin-top: 1.9rem; }
}

/* Short screens (landscape phones, high zoom): compact, so the main button
   is reachable without a long scroll. */
@media (max-height: 30rem) {
  .hero { min-height: 0; padding-block: 1.25rem 5.5rem; }
  .hero h1 { margin-top: 0.4rem; font-size: clamp(1.75rem, 1rem + 2.5vw, 2.4rem); max-width: 26ch; }
  .hero-lede { margin-top: 0.6rem; font-size: var(--step-0); max-width: 52ch; }
  .hero-who { display: none; }
  .hero-action { margin-top: 1.25rem; }
}

/* A halo in the page colour keeps every letter on clean background where the
   film passes behind the text, so contrast is text-on-white in every frame. */
.hero h1, .hero-kicker, .hero-lede, .hero-who, .hero .text-link {
  text-shadow: 0 0 3px var(--paper), 0 0 6px var(--paper), 0 0 12px var(--paper);
}

/* The headline lands: a short settle, never hidden (it is readable from the
   first frame). The opening picture eases in like a camera finding its mark. */
@media (prefers-reduced-motion: no-preference) {
  .hero h1 { animation: land 1100ms cubic-bezier(.2, .7, .2, 1) both; }
  .hero-poster img { animation: settle 4.5s cubic-bezier(.2, .6, .2, 1) both; transform-origin: 50% 80%; }
}
@keyframes land {
  from { transform: translateY(0.35em); }
  to { transform: none; }
}
@keyframes settle {
  from { transform: scale(1.07); }
  to { transform: none; }
}

/* --- Scene titles ------------------------------------------------------------ */
/* Huge, like a film's title card, sliding across as the scene passes
   (film-boot.js sets --p from the scroll position). Cobalt with a white
   outline, so they read over anything the film draws. */

.scene-title {
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: clamp(4rem, 15vw, 12rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
  color: var(--accent);
  white-space: nowrap;
  paint-order: stroke fill;
  -webkit-text-stroke: 0.06em #fff;
  pointer-events: none;
  user-select: none;
}
@media (prefers-reduced-motion: no-preference) {
  .scene-title {
    transform: translateX(calc((0.5 - var(--p, 0.5)) * 60vw));
    will-change: transform;
  }
}

.scene-title--hero {
  position: absolute;
  left: var(--gutter);
  /* clear of the fixed pause button */
  bottom: 4.6rem;
  z-index: -1;
  font-size: clamp(4.4rem, 22vw, 13rem);
}
@media (min-width: 48rem) and (min-aspect-ratio: 1/1) {
  /* Right of the words, never over the buttons. */
  .scene-title--hero { left: auto; right: var(--gutter); font-size: clamp(4rem, 11.5vw, 12rem); }
}

/* --- Stages: one per scene, between the sections --------------------------- */

.stage { position: relative; overflow-x: clip; }
.stage-inner { position: relative; }

/* With the film: a tall stretch of page where the scene plays as you scroll.
   The inner frame sticks under the header (plain CSS, the page scrolls
   normally the whole time) and the title slides over the film. */
html.film-on .stage { height: 175svh; }
html.film-lite .stage { height: 160svh; }
html.film-on .stage-inner {
  position: sticky;
  top: var(--header-h);
  height: calc(100svh - var(--header-h));
  overflow: clip;
  display: flex;
  flex-direction: column;
  padding-top: clamp(1rem, 4vh, 3rem);
}
/* Until the film is ready (phones start it on the first touch), each stage
   shows its still frame, so there is never an empty stage. */
html.film-on .stage-still { position: absolute; inset: 0; z-index: -1; }
html.film-on .stage-still img { height: 100%; max-height: none; }
html.film-ready .stage-still { display: none; }

/* Without the film: the still frame, full width, with its title over it. */
html:not(.film-on) .stage-inner { overflow: clip; }
.stage-still img {
  width: 100%;
  height: auto;
  max-height: 88svh;
  object-fit: cover;
}
html:not(.film-on) .stage .scene-title {
  position: absolute;
  left: var(--gutter);
  top: 1rem;
}

/* Proof: the touchpoints count down as the boxes fly off, then the time. */
.proof-count {
  margin-top: auto;
  margin-bottom: clamp(5rem, 12vh, 7rem);
  margin-inline: var(--gutter);
  align-self: flex-start;
  padding: 0.75rem 1.1rem 0.9rem;
  background: rgb(255 255 255 / 0.93);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: 0 12px 30px -16px rgb(18 24 38 / 0.35);
  font-family: var(--font-serif);
  font-variant-numeric: lining-nums tabular-nums;
}
html:not(.film-on) .proof-count {
  position: absolute;
  left: 0;
  bottom: 0;
  margin-bottom: 1.5rem;
}
.proof-row {
  display: flex;
  align-items: baseline;
  gap: 0.35em;
  font-size: clamp(2.2rem, 9vw, 4.8rem);
  line-height: 1.05;
  color: var(--ink);
}
.proof-label {
  min-width: 6.5rem;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--ink-muted);
}
.proof-arrow { font-size: 0.5em; color: var(--ink-muted); }
.proof-one, .proof-after { color: var(--accent); font-weight: 700; }
.proof-before { color: var(--ink-muted); text-decoration-color: var(--pen); text-decoration-thickness: 0.08em; }
.proof-time { font-size: clamp(1.3rem, 5.2vw, 3.2rem); }
.proof-num, .proof-one, .proof-before, .proof-after { white-space: nowrap; }
@media (max-width: 30rem) { .proof-label { min-width: 5.2rem; } }

/* While the film plays the count, only the live number shows; the arrow and
   the end figures arrive when the boxes are down to one. */
html.film-ready .proof-count:not(.is-done) .proof-arrow,
html.film-ready .proof-count:not(.is-done) .proof-one,
html.film-ready .proof-count:not(.is-done) .proof-after { opacity: 0; }
html.film-ready .proof-count:not(.is-done) .proof-before { text-decoration-color: transparent; }
html.film-ready .proof-count.is-done .proof-num { color: var(--ink-muted); text-decoration: line-through var(--pen) 0.08em; }
.proof-arrow, .proof-one, .proof-after, .proof-num { transition: opacity 300ms ease, color 300ms ease; }
.proof-before { transition: text-decoration-color 300ms ease; }

/* Pause button: fixed, always on screen and keyboard-reachable. Only shown
   while the film runs, because nothing else moves by itself. */
.motion-toggle {
  position: fixed;
  right: max(var(--gutter), env(safe-area-inset-right));
  bottom: max(0.9rem, env(safe-area-inset-bottom));
  z-index: 20;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.5rem 0.9rem;
  background: rgb(255 255 255 / 0.96);
  color: var(--ink);
  border: 1px solid var(--line-ui);
  border-radius: var(--radius);
  box-shadow: 0 8px 20px -10px rgb(18 24 38 / 0.4);
  font-size: var(--step--1);
  font-weight: 600;
  cursor: pointer;
  transition: transform 160ms ease, border-color 160ms ease;
}
.motion-toggle[hidden], html:not(.film-on) .motion-toggle { display: none; }
.motion-toggle:hover { border-color: var(--ink); transform: translateY(-1px); }
.motion-toggle:active { transform: scale(0.97); }
.motion-toggle svg { fill: currentColor; }
.motion-toggle .icon-play { display: none; }
body:has(.hero.is-paused) .motion-toggle .icon-play { display: inline; }
body:has(.hero.is-paused) .motion-toggle .icon-pause { display: none; }

@media (prefers-reduced-motion: reduce) {
  .motion-toggle { display: none; }
}

/* Sheets: with the film behind, sections are bright panes that slide over it
   (96% white or more, so text contrast is the same as on plain white). */
html.film-on .section {
  background: rgb(255 255 255 / 0.965);
  border-top: 0;
  border-radius: clamp(0.75rem, 2vw, 1.5rem) clamp(0.75rem, 2vw, 1.5rem) 0 0;
  box-shadow: 0 -28px 60px -34px rgb(18 24 38 / 0.35);
}
html.film-on .section-alt { background: rgb(242 245 251 / 0.97); }
html.film-on .section-call { border-top: 4px solid var(--accent); }
.site-footer { background: var(--paper); }

/* --- Services: a ruled index across the full width ------------------------ */
/* Four rows, numbered like steps on the map. On wide screens each row reads
   left to right: the service, the problem, how we help. */

.services {
  list-style: none;
  padding: 0;
  counter-reset: service;
}

.service {
  position: relative;
  counter-increment: service;
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  column-gap: 0.75rem;
  row-gap: 0.9rem;
  padding-block: 1.75rem 2rem;
}
/* The rule above each row is its own layer, so it can draw in. */
.service::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--ink);
  transform-origin: left center;
}
.service:last-child { border-bottom: 1px solid var(--line); }

.service::before {
  content: counter(service, decimal-leading-zero);
  grid-row: 1 / span 3;
  font-family: var(--font-serif);
  font-size: var(--step-1);
  line-height: 1.2;
  color: var(--accent);
  font-variant-numeric: lining-nums tabular-nums;
}

.service h3 {
  font-family: var(--font-serif);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.01em;
}
.service p { max-width: 46ch; }
.service-problem {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--step-0);
  line-height: 1.5;
}
.service-help { color: var(--ink-muted); }

@media (min-width: 60rem) {
  .service {
    grid-template-columns: 4.5rem minmax(0, 1.15fr) minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(1.5rem, 3vw, 3rem);
    align-items: start;
    padding-block: 2.25rem 2.5rem;
  }
  .service::before { grid-row: auto; font-size: var(--step-2); line-height: 1.1; }
  .service h3 { font-size: clamp(1.6rem, 0.9rem + 1.3vw, 2.4rem); }
}

/* --- Case study: full width ------------------------------------------------ */

.case-label {
  display: block;
  margin-bottom: 0.6rem;
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: 700;
  letter-spacing: 0;
  color: var(--accent);
}
.case-sector { margin-top: 0.6rem; color: var(--ink-muted); font-weight: 600; }

.case .section-head { align-items: start; }

.case-parts {
  margin: 0;
  display: grid;
  gap: 1.25rem;
}
.case-parts dt { font-weight: 700; }
.case-parts dd { margin: 0.25rem 0 0; max-width: 46ch; }
.case-parts q {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--step-1);
  line-height: 1.45;
}

.result {
  margin: 0;
  border-top: 2px solid var(--ink);
}
.result-title { padding-top: 0.75rem; font-weight: 700; }

.figures { margin: 0; display: grid; }

.figure-row {
  container-type: inline-size;
  padding-block: 1rem 1.5rem;
  border-bottom: 1px solid var(--line);
}

/* Side by side on wide screens, split by a fine vertical rule, so the two
   results fill the width at a size you notice from across the room. */
@media (min-width: 52rem) {
  .figures { grid-template-columns: 1fr 1fr; }
  .figure-row { border-bottom: 0; padding-block: 1rem 1.75rem; }
  .figure-row + .figure-row { border-left: 1px solid var(--line); padding-left: clamp(1.5rem, 3vw, 3rem); }
}

.figure-row dt {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--ink-muted);
}

.figure-row dd {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0.12em;
  font-family: var(--font-serif);
  /* Sized to its own column, so "40 days → 30 mins" always fills it on one
     line, from a 360px phone to a wide desktop. */
  font-size: var(--figure);
  font-size: min(9rem, 19cqi);
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
  letter-spacing: -0.03em;
}

.figure-row abbr { font-size: 0.42em; letter-spacing: 0; }

/* "Before" in muted ink, struck through in red pen. */
.before {
  position: relative;
  color: var(--ink-muted);
  font-weight: 400;
  text-decoration: none;
}
.before::after {
  content: "";
  position: absolute;
  left: -0.04em;
  right: -0.04em;
  top: 52%;
  height: 0.06em;
  min-height: 3px;
  background: var(--pen);
  transform: rotate(-4deg);
  transform-origin: left center;
}

.arrow {
  color: var(--ink-muted);
  font-size: 0.55em;
  padding-inline: 0.15em;
  align-self: center;
}

.after { color: var(--accent); font-weight: 600; }

/* --- Ways to work with us -------------------------------------------------- */
/* Three columns divided by fine vertical rules, not boxes. */

.ways {
  list-style: none;
  padding: 0;
  display: grid;
  border-top: 2px solid var(--ink);
}

.way {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding-block: 1.5rem 2rem;
  border-bottom: 1px solid var(--line);
}
.way h3 {
  font-family: var(--font-serif);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.12;
}
.way p { max-width: 40ch; }
.way-when {
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--accent);
}
.way > p:not(.way-when) { color: var(--ink-muted); }

.way-link {
  margin-top: auto;
  padding-top: 0.5rem;
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 0.35em;
  min-height: 44px;
  font-weight: 600;
  text-decoration-thickness: 1px;
}
.way-link:hover .btn-arrow,
.way-link:focus-visible .btn-arrow { transform: translateX(4px); }

@media (min-width: 52rem) {
  .ways { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .way { border-bottom: 0; padding: 1.75rem clamp(1.25rem, 2.5vw, 2.5rem) 0.5rem; }
  .way:first-child { padding-left: 0; }
  .way + .way { border-left: 1px solid var(--line); }
}

/* --- Our approach: the map, untangled -------------------------------------- */
/* Three steps on one straight cobalt line: the finished state of the hero's
   map. Vertical on phones, across the page on wide screens. */

.stages {
  --node: 1.25rem;
  position: relative;
  list-style: none;
  padding: 0;
  counter-reset: stage;
  display: grid;
  gap: 2.25rem;
}
/* The line. */
.stages::before {
  content: "";
  position: absolute;
  left: calc(var(--node) / 2 - 2px);
  top: 0.4rem;
  bottom: 0.4rem;
  width: 4px;
  border-radius: 2px;
  background: var(--accent);
  transform-origin: top center;
}

.stages li {
  position: relative;
  counter-increment: stage;
  padding-left: calc(var(--node) + 1.25rem);
}
/* The steps on the line: white with a cobalt ring, the last one solid. */
.stages li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.35rem;
  width: var(--node);
  height: var(--node);
  border-radius: 50%;
  background: var(--paper);
  border: 4px solid var(--accent);
  box-sizing: border-box;
}
.stages li:last-child::before { background: var(--accent); }

.stages h3 {
  font-family: var(--font-serif);
  font-size: var(--step-2);
  font-weight: 600;
}
.stages h3::before {
  content: counter(stage) ". ";
  color: var(--accent);
}
.stages p { color: var(--ink-muted); margin-top: 0.5rem; max-width: 40ch; }

@media (min-width: 52rem) {
  .stages {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(1.5rem, 3vw, 3rem);
    padding-top: calc(var(--node) + 1.5rem);
  }
  .stages::before {
    left: 0;
    right: calc(var(--node) / 2);
    top: calc(var(--node) / 2 - 2px);
    bottom: auto;
    width: auto;
    height: 4px;
    transform-origin: left center;
  }
  .stages li { padding-left: 0; }
  .stages li::before { top: calc(-1 * (var(--node) + 1.5rem)); }
  .stages li:last-child::before { left: auto; right: 0; }
}

/* --- About Darren ------------------------------------------------------------ */

.about-top { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 48rem) {
  .about-top { grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr); gap: clamp(2rem, 5vw, 5rem); }
}

.pull-quote { margin: 0; max-width: 52rem; }

.pull-quote blockquote p {
  font-family: var(--font-serif);
  font-size: clamp(1.7rem, 1rem + 3vw, 3.6rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
  max-width: 24ch;
  text-indent: -0.4em;   /* hangs the opening quote mark */
}
.pull-quote blockquote p::before { content: "\201C"; color: var(--accent); }
.pull-quote blockquote p::after { content: "\201D"; color: var(--accent); }

.pull-quote blockquote::after {
  content: "";
  display: block;
  width: 5rem;
  height: 4px;
  margin-top: 1.25rem;
  background: var(--accent);
  transform-origin: left;
}

.pull-quote figcaption {
  margin-top: 1.25rem;
  font-weight: 700;
}
.pull-role { display: block; font-weight: 400; color: var(--ink-muted); font-size: var(--step--1); }

.about-text { margin-top: 1.75rem; display: grid; gap: 0.9rem; }
@media (min-width: 72rem) {
  .about-text { grid-template-columns: 1fr 1fr; column-gap: 3rem; }
}

/* Portrait, like a photo pinned to a report. The hairline keeps the pale
   wall in the photo from melting into the page. */
.headshot {
  display: block;
  width: min(14rem, 60%);
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 6px;
  outline: 1px solid var(--line);
  outline-offset: -1px;
}
@media (min-width: 48rem) { .headshot { width: 100%; } }

/* --- Experience ------------------------------------------------------------ */

.experience {
  display: grid;
  gap: 2rem;
  margin-top: clamp(3rem, 7vw, 5rem);
  padding-top: 1.5rem;
  border-top: 2px solid var(--ink);
}
.experience h3 { font-size: var(--step-0); margin-bottom: 0.5rem; }

@media (min-width: 40rem) {
  .experience { grid-template-columns: 1fr 1fr; column-gap: 3rem; }
  .experience > :first-child { grid-column: 1 / -1; }
}
@media (min-width: 64rem) {
  .experience { grid-template-columns: 1.6fr 1fr 1fr; }
  .experience > :first-child { grid-column: auto; }
}

.sectors {
  list-style: none;
  padding: 0;
  font-family: var(--font-serif);
  font-size: var(--step-2);
  line-height: 1.3;
}
.sectors li { padding-block: 0.3rem; }

.plain-list { list-style: none; padding: 0; color: var(--ink-muted); }
.plain-list li { padding-block: 0.15rem; }

/* --- Tier 1 depth ---------------------------------------------------------- */
/* Layers drift at their own speed (script.js moves [data-depth] with the
   `translate` property, so scene transforms still work). Cards have real
   perspective, a deep soft shadow, and lift toward you on hover or tap. */

.card-3d {
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow:
    0 1px 2px rgb(18 24 38 / 0.06),
    0 18px 36px -18px rgb(18 24 38 / 0.28);
}
@media (prefers-reduced-motion: no-preference) {
  .card-3d {
    transform: perspective(70rem) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(var(--lift, 0px));
    transition: transform 220ms ease-out, box-shadow 220ms ease-out;
  }
  .card-3d:hover,
  .card-3d:focus-within,
  .card-3d:active {
    --lift: -6px;
    box-shadow:
      0 2px 4px rgb(18 24 38 / 0.06),
      0 30px 50px -22px rgb(39 71 214 / 0.38);
  }
}

/* The case study result becomes a lifted sheet with its rule on top. */
.result.card-3d {
  border-top: 3px solid var(--ink);
  padding: 0 clamp(1rem, 3vw, 2.5rem) 0.5rem;
}
.result.card-3d .figure-row:last-child { border-bottom: 0; }

/* --- Recommendations ------------------------------------------------------ */

.recs-block { margin-top: clamp(3rem, 7vw, 5rem); }
.recs-title { font-family: var(--font-serif); font-size: var(--step-2); font-weight: 600; }
.recs-block > .muted-text { margin-top: 0.4rem; }

/* Phones: the LinkedIn link comes after both. Wide screens: it sits under
   the shorter recommendation, filling the space beside the longer one. */
.recs-col { display: contents; }
.recs-col > p { margin: 0; order: 3; }
@media (min-width: 64rem) {
  .recs-col { display: grid; gap: 1.5rem; align-content: start; }
}
.recs {
  display: grid;
  gap: 1.5rem;
  margin-block: 1.5rem;
  align-items: start;
}
/* Side by side on wide screens, the longer one given more width so the two
   come out close in height. */
@media (min-width: 64rem) {
  .recs { grid-template-columns: minmax(0, 1fr) minmax(0, 1.55fr); gap: 2.5rem; }
}

.rec {
  margin: 0;
  padding: clamp(1.25rem, 4vw, 2rem) clamp(1.25rem, 4vw, 2.25rem);
  border-left: 3px solid var(--accent);
}
.rec blockquote p {
  font-family: var(--font-serif);
  font-size: var(--step-0);
  line-height: 1.55;
  max-width: 62ch;
}
.rec blockquote p + p { margin-top: 0.9em; }
.rec figcaption {
  margin-top: 1rem;
  display: grid;
  gap: 0.1rem;
  font-size: var(--step--1);
  color: var(--ink-muted);
}
.rec-name { color: var(--ink); font-weight: 600; font-size: var(--step-0); }

/* --- Book a discovery call -------------------------------------------------- */

.section-call { border-top: 4px solid var(--accent); }

.call-grid { display: grid; gap: 2.5rem; }
/* Phones: invitation, form, then the direct details. Wide screens: the
   invitation and direct details on the left, the form on the right. */
@media (min-width: 64rem) {
  .call-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "intro form" "direct form";
    grid-template-rows: auto 1fr;
    column-gap: clamp(3rem, 6vw, 6rem);
    row-gap: 0;
    align-items: start;
  }
  .call-intro { grid-area: intro; }
  .contact-form { grid-area: form; }
  .contact-direct { grid-area: direct; }
}

.call-intro h2 { max-width: 12ch; }
.call-lede {
  margin-top: 1.25rem;
  font-family: var(--font-serif);
  font-size: var(--step-1);
  line-height: 1.45;
  max-width: 34ch;
}
.call-intro > p + p { margin-top: 0.9rem; color: var(--ink-muted); }

.contact-form { max-width: 40rem; }
@media (min-width: 64rem) { .contact-form { margin-top: 0.5rem; } }

.field-pair { display: grid; column-gap: 1.25rem; }
@media (min-width: 40rem) { .field-pair { grid-template-columns: 1fr 1fr; } }

.field { margin-bottom: 1.1rem; }

.field label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.35rem;
}

.optional { font-weight: 400; color: var(--ink-muted); }

.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 48px;
  padding: 0.65rem 0.8rem;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--line-ui);
  border-radius: var(--radius);
}
.field textarea { min-height: 8rem; resize: vertical; }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--ink); }
.field input, .field select, .field textarea { transition: border-color 150ms ease, box-shadow 150ms ease; }
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { border-color: var(--accent); box-shadow: 0 0 0 4px var(--glow); }

.field [aria-invalid="true"] { border: 2px solid var(--accent); }

.field-error {
  margin-top: 0.35rem;
  color: var(--accent);
  font-weight: 600;
  font-size: var(--step--1);
}
.field-error::before { content: "Error: "; }

/* A brief cobalt flash on the subject box when a "way to work" link picks it. */
@media (prefers-reduced-motion: no-preference) {
  .field select.is-picked { animation: picked 900ms ease-out; }
  @keyframes picked {
    0%   { box-shadow: 0 0 0 0 var(--glow); border-color: var(--accent); }
    30%  { box-shadow: 0 0 0 6px var(--glow); border-color: var(--accent); }
    100% { box-shadow: 0 0 0 0 transparent; }
  }
}

.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status { margin-top: 1rem; font-weight: 600; }
.form-status:empty { display: none; }
.form-note { margin-top: 0.75rem; font-size: var(--step--1); color: var(--ink-muted); }

.contact-direct { margin-top: 0; }
@media (min-width: 64rem) { .contact-direct { margin-top: 2rem; } }
.contact-direct h3 { font-size: var(--step-0); }

.contact-list {
  list-style: none;
  padding: 0;
  margin-top: 0.75rem;
  border-top: 1px solid var(--line);
  max-width: 34rem;
}
.contact-list li {
  padding-block: 0.75rem;
  border-bottom: 1px solid var(--line);
  overflow-wrap: anywhere;
}
.contact-label {
  display: block;
  font-size: var(--step--1);
  color: var(--ink-muted);
}

/* --- Footer --------------------------------------------------------------- */

.site-footer {
  padding-block: 2.5rem;
  border-top: 2px solid var(--ink);
  font-size: var(--step--1);
}
.footer-inner { display: grid; gap: 0.4rem; }
.legal { color: var(--ink-muted); max-width: 70ch; }
.gap {
  padding: 0 0.25em;
  border: 1px dashed var(--line-ui);
  font-style: italic;
}

/* --- 404 ------------------------------------------------------------------ */

.not-found { padding-block: clamp(3rem, 10vw, 7rem); }
.not-found .code {
  font-family: var(--font-serif);
  font-size: var(--figure);
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: lining-nums;
}
.not-found h1 { font-size: var(--step-3); margin-top: 1rem; }
.not-found p { margin-top: 1rem; max-width: 50ch; }
.not-found .btn { margin-top: 1.5rem; }

/* --- Scroll scenes -------------------------------------------------------- */
/* Each section arrives in its own way, in the hero's language. Hidden states
   apply only once script.js adds .scenes-on, so nothing is hidden without
   JavaScript, and nothing moves with reduced motion. */

@media (prefers-reduced-motion: no-preference) {
  /* Case study, "the red pen": the old figure is struck through, then the new one
     lands. */
  /* Transitions only on arrival (.is-in): hiding is instant, so a fast scroller
     never catches a half-hidden state. */
  .scenes-on [data-scene="edit"].is-in .before::after { transition: transform 550ms cubic-bezier(.6, 0, .2, 1); }
  .scenes-on [data-scene="edit"].is-in .arrow,
  .scenes-on [data-scene="edit"].is-in .after { transition: opacity 450ms ease, transform 450ms ease; }
  .scenes-on [data-scene="edit"].is-in .figure-row:nth-child(2) .before::after { transition-delay: 250ms; }
  .scenes-on [data-scene="edit"].is-in .arrow { transition-delay: 500ms; }
  .scenes-on [data-scene="edit"].is-in .after { transition-delay: 700ms; }
  .scenes-on [data-scene="edit"].is-in .figure-row:nth-child(2) .arrow { transition-delay: 750ms; }
  .scenes-on [data-scene="edit"].is-in .figure-row:nth-child(2) .after { transition-delay: 950ms; }
  .scenes-on [data-scene="edit"]:not(.is-in) .before::after { transform: rotate(-4deg) scaleX(0); }
  .scenes-on [data-scene="edit"]:not(.is-in) .arrow { opacity: 0; transform: translateX(-0.4em); }
  .scenes-on [data-scene="edit"]:not(.is-in) .after { opacity: 0; transform: translateY(0.15em) scale(0.92); }

  /* Steps arrive one after another (ways to work, sectors) */
  .scenes-on [data-scene="steps"].is-in > * { transition: opacity 500ms ease, transform 500ms ease; }
  .scenes-on [data-scene="steps"].is-in > :nth-child(2) { transition-delay: 120ms; }
  .scenes-on [data-scene="steps"].is-in > :nth-child(3) { transition-delay: 240ms; }
  .scenes-on [data-scene="steps"].is-in > :nth-child(n+4) { transition-delay: 360ms; }
  .scenes-on [data-scene="steps"]:not(.is-in) > * { opacity: 0; transform: translateY(1.25rem); }

  /* Services, "rules": each row's rule draws left to right, like a line on
     the map, then its words settle in. One row after another. */
  .scenes-on [data-scene="rules"].is-in > *::after { transition: transform 700ms cubic-bezier(.6, 0, .2, 1); }
  .scenes-on [data-scene="rules"].is-in > * > * { transition: opacity 450ms ease 250ms, transform 450ms ease 250ms; }
  .scenes-on [data-scene="rules"].is-in > :nth-child(2)::after { transition-delay: 150ms; }
  .scenes-on [data-scene="rules"].is-in > :nth-child(2) > * { transition-delay: 400ms; }
  .scenes-on [data-scene="rules"].is-in > :nth-child(3)::after { transition-delay: 300ms; }
  .scenes-on [data-scene="rules"].is-in > :nth-child(3) > * { transition-delay: 550ms; }
  .scenes-on [data-scene="rules"].is-in > :nth-child(4)::after { transition-delay: 450ms; }
  .scenes-on [data-scene="rules"].is-in > :nth-child(4) > * { transition-delay: 700ms; }
  .scenes-on [data-scene="rules"]:not(.is-in) > *::after { transform: scaleX(0); }
  .scenes-on [data-scene="rules"]:not(.is-in) > * > * { opacity: 0; transform: translateY(0.75rem); }

  /* Approach, "connect": the straight line draws through the three steps,
     and each step lands as the line reaches it. The words never hide. */
  .scenes-on [data-scene="connect"].is-in::before { transition: transform 1100ms cubic-bezier(.6, 0, .2, 1); }
  .scenes-on [data-scene="connect"].is-in > li::before { transition: transform 350ms cubic-bezier(.3, 1.6, .5, 1), opacity 200ms ease; }
  .scenes-on [data-scene="connect"].is-in > li:nth-child(2)::before { transition-delay: 450ms; }
  .scenes-on [data-scene="connect"].is-in > li:nth-child(3)::before { transition-delay: 950ms; }
  .scenes-on [data-scene="connect"]:not(.is-in)::before { transform: scaleY(0); }
  .scenes-on [data-scene="connect"]:not(.is-in) > li::before { transform: scale(0.2); opacity: 0; }
}
@media (prefers-reduced-motion: no-preference) and (min-width: 52rem) {
  .scenes-on [data-scene="connect"]:not(.is-in)::before { transform: scaleX(0); }

  /* Underline: a cobalt rule draws beneath the pull quote as it arrives. The
     quote's words are never hidden, so if this misfires only the line is lost. */
  .scenes-on [data-scene="underline"].is-in::after { transition: transform 900ms cubic-bezier(.6, 0, .2, 1); }
  .scenes-on [data-scene="underline"]:not(.is-in)::after { transform: scaleX(0); }

  /* Rise: the photo lifts into place */
  .scenes-on [data-scene="rise"].is-in { transition: opacity 700ms ease, transform 700ms ease; }
  .scenes-on [data-scene="rise"]:not(.is-in) { opacity: 0; transform: translateY(2rem); }
}

/* --- Motion --------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Print ---------------------------------------------------------------- */

@media print {
  .scenes-on [data-scene], .scenes-on [data-scene] * { opacity: 1 !important; transform: none !important; }
  .site-header, .preview-banner, .hero-action, .contact-form, .film, .stage, .hero-poster, .scene-title, .motion-toggle { display: none; }
  .card-3d { transform: none !important; box-shadow: none; }
  body { color: #000; background: #fff; }
}

/* --- Still-frame capture (film.js ?still=J): only the film and its labels
   show, so the designed still frames can be rendered from the film itself. */
html.film-capture body > :not(.film):not(.film-labels) { visibility: hidden; }
html.film-capture .film { z-index: 1; }
html.film-capture { scrollbar-width: none; }
html.film-capture::-webkit-scrollbar { display: none; }
