/* ==========================================================================
   SprigHouse — stylesheet
   --------------------------------------------------------------------------
   Order of this file:
     1. Design tokens
     2. Reset and base elements
     3. Layout (shell, panels, section heads)
     4. Type scale
     5. Motion (hero entrance, sky, marquee, scroll reveals)
     6. Components (button, eyebrow, cards, chips, tooltip, form, carousel)
     7. Header (desktop nav, mega panels, mobile menu)
     8. Page sections, top to bottom
     9. Responsive
    10. Reduced motion

   Naming follows BEM: .block, .block__element, .block--variant.
   Change a colour or a size once in section 1 and the whole page follows.

   Three rules worth knowing before editing:
   - Only ONE group of blocks is hidden before it appears: the case-study
     cards. That hidden state is written under `html.js`, so a page whose
     scripts never run shows everything. See section 5.
   - Font sizes are fluid clamp() values declared once in section 1. A heading
     therefore never carries its own media query — change --fs-h2 and every
     h2 on the page follows, at every width.
   - The lime is a background colour, not a text colour. On the cream it only
     works with the ink outline you will find on .hero__accent. Read the
     contrast note in the README before turning it into plain text.
   ========================================================================== */

/* ==========================================================================
   1. Design tokens
   ========================================================================== */

:root {
  /* --- Palette. These nine lines are the whole colour system. ---
     Contrast ratios (WCAG 2.1) are in the README; two values were darkened
     from the reference to clear 4.5:1 — see --muted and --accent. */
  --bg: #f7f0e6; /* page background, cream paper */
  --surface: #f3ebdd; /* sections that step forward, one shade down */
  --text: #1d2b1f; /* ink: type, borders, dark panels */
  --muted: #5c6b5e; /* secondary type on cream — 4.8:1 on --surface */
  --primary: #bfea4b; /* lime: buttons, highlights, dots */
  --on-primary: #1d2b1f; /* type laid on the lime */
  --accent: #b8331b; /* required-field marks, errors — 5.0:1 on --surface */
  --on-accent: #ffffff;
  --border: #1d2b1f;
  --focus: #1e5bff; /* focus ring, deliberately not in the palette */

  /* Type on the ink panels. Never write a raw rgba() for text: pick one of
     these three, they are the ones that pass contrast. */
  --on-ink: #f7f0e6; /* 13.1:1 */
  --on-ink-soft: color-mix(in srgb, #f7f0e6 72%, var(--text)); /* 7.5:1 */
  --on-ink-faint: color-mix(in srgb, #f7f0e6 60%, var(--text)); /* 5.7:1 */
  --on-ink-line: color-mix(in srgb, #f7f0e6 15%, transparent);
  --on-ink-wash: color-mix(in srgb, #f7f0e6 6%, transparent);

  /* --- Typography --- */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Fluid type scale, measured on the reference at 390 / 768 / 1440 px.
     clamp() replaces the usual breakpoint ladder: one declaration, every
     width. Left number = floor, right number = ceiling. */
  --fs-display: clamp(3.25rem, 2rem + 4.5vw, 5.75rem); /* 52 → 92px */
  --fs-h1: clamp(2.5rem, 1.8rem + 2.5vw, 3.75rem); /* 40 → 60px */
  --fs-h2: clamp(2rem, 1.5rem + 1.8vw, 2.75rem); /* 32 → 44px */
  --fs-h3: clamp(1.375rem, 1.15rem + 0.8vw, 1.875rem); /* 22 → 30px */
  --fs-body: clamp(1.0625rem, 0.95rem + 0.35vw, 1.1875rem); /* 17 → 19px */
  --fs-small: clamp(0.875rem, 0.82rem + 0.18vw, 1rem); /* 14 → 16px */
  --fs-label: clamp(0.6875rem, 0.65rem + 0.15vw, 0.8125rem); /* 11 → 13px */

  /* --- Spacing ladder, straight from the reference --- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;

  /* Vertical rhythm of a full-width section. Redefined in section 9. */
  --section-y: 112px;

  /* --- Shape --- */
  --radius-card: 0.875rem;
  --radius-pill: 9999px;
  --radius-sm: 0.375rem;

  /* Hard shadows: no blur, no spread. That single choice carries most of the
     look. Changing the offsets changes the whole page. */
  --shadow-hard: 4px 4px 0 0 var(--border);
  --shadow-hard-sm: 2px 2px 0 0 var(--border);
  --shadow-hard-lg: 6px 6px 0 0 var(--border);

  /* --- Motion --- */
  --ease-out-soft: cubic-bezier(0.22, 1, 0.36, 1);
  --header-height: 80px;
}

/* ==========================================================================
   2. Reset and base elements
   ========================================================================== */

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

/* `clip`, not `hidden`: `hidden` would turn <html> into a scroll container and
   break every sticky element further down the page. The hero house and the
   marquee both stick out sideways, which is what makes this necessary. */
html {
  overflow-x: clip;
  scroll-behavior: smooth;
  /* The header is fixed and 80px tall: without this, an anchor lands under it. */
  scroll-padding-top: calc(var(--header-height) + var(--space-4));
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  /* Pushes the page below the fixed header. */
  padding-top: var(--header-height);
}

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

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

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

img {
  height: auto;
}

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

button,
input,
textarea {
  font: inherit;
  color: inherit;
}

/* One focus ring for the whole page, and it is always visible. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 200;
  padding: var(--space-3) var(--space-5);
  background: var(--primary);
  color: var(--on-primary);
  border: 2px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: translateY(-160%);
  transition: transform 0.18s ease-out;
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* ==========================================================================
   3. Layout
   ========================================================================== */

/* The one container of the page. 92vw keeps a gutter on small screens without
   a single media query. */
.shell {
  width: min(1200px, 92vw);
  margin-inline: auto;
}

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

.panel--paper {
  background: var(--bg);
}

.panel--surface {
  background: var(--surface);
}

/* z-index 10, and it matters: the hero house is pushed 28% past the bottom of
   its own section. Without a stacking order the green hill would spill over
   the top of the ink panel. */
.panel--ink {
  position: relative;
  z-index: 10;
  background: var(--text);
  color: var(--on-ink);
}

.panel--lime {
  background: var(--primary);
  color: var(--on-primary);
}

/* Heading on the left, supporting paragraph on the right. Collapses to one
   column below 1024px. */
.section-head {
  display: grid;
  gap: var(--space-6);
  margin-bottom: var(--space-8);
}

.section-head > div {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}

.section-head p {
  color: var(--muted);
}

/* ==========================================================================
   4. Type scale
   ========================================================================== */

.display {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 700;
  line-height: 0.92;
  letter-spacing: -0.025em;
}

.h1 {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: -0.025em;
}

.h2 {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.h3,
.support {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.015em;
}

.lead {
  font-size: var(--fs-body);
  line-height: 1.6;
}

/* Small uppercase type: eyebrows, indexes, tags, footer column titles. */
.label {
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ==========================================================================
   5. Motion
   --------------------------------------------------------------------------
   Two kinds live here:
   - Ambient loops (clouds, bird, marquee). Pure CSS, they need no script and
     never hide anything.
   - Scroll reveals. Only the case-study cards use them. The hidden state is
     under `html.js` so the content survives a missing script.
   ========================================================================== */

/* --- Hero entrance. Plays on load, staggered like the reference (0.1s
       between children, 0.05s before the first one). Pure CSS: no script
       involved, so nothing can leave it stuck at opacity 0. --- */
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

[data-hero] {
  animation: rise 0.5s var(--ease-out-soft) backwards;
}

[data-hero="1"] {
  animation-delay: 0.05s;
}
[data-hero="2"] {
  animation-delay: 0.15s;
}
[data-hero="3"] {
  animation-delay: 0.25s;
}
[data-hero="4"] {
  animation-delay: 0.35s;
}

/* --- Scroll reveals. `html.js` is set by enhance.js before the first paint;
       .is-in is added by the observer in main.js. --- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
}

.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.42s ease-out var(--reveal-delay, 0ms),
    transform 0.42s ease-out var(--reveal-delay, 0ms);
}

/* The stagger lives in the stylesheet, not in a style="" attribute: a strict
   CSP blocks inline styles, and a blocked delay would land every card at
   once. Three cards, 50ms apart, same figures as the reference. */
.cases__grid > li:nth-child(2) {
  --reveal-delay: 50ms;
}

.cases__grid > li:nth-child(3) {
  --reveal-delay: 100ms;
}

/* --- The sky: five clouds bobbing on their own clock, one bird crossing
       every 30 seconds. Percentages are relative to .sky. --- */
.sky {
  position: relative;
  width: 100%;
  min-height: min(360px, 46svh);
  justify-self: end;
  /* The bird flies out of this box on both sides; the hero clips it. */
  overflow: visible;
}

.sky__cloud {
  position: absolute;
  translate: -50% -50%;
  will-change: transform;
  filter: drop-shadow(0 1px 2px rgb(31 42 31 / 0.07));
  animation-name: bob;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

/* Four keyframes, not two: the cloud drifts up, overshoots down, settles.
   Same shape as the reference, whose y track was [0, -bob, 2, -0.4bob, 0]. */
@keyframes bob {
  0% {
    transform: translateY(0);
  }
  25% {
    transform: translateY(calc(var(--bob) * -1));
  }
  50% {
    transform: translateY(2px);
  }
  75% {
    transform: translateY(calc(var(--bob) * -0.4));
  }
  100% {
    transform: translateY(0);
  }
}

.sky__cloud--1 {
  left: 6%;
  top: 6%;
  width: 42%;
  --bob: 5px;
  animation-duration: 18s;
  animation-delay: 0s;
}
.sky__cloud--2 {
  left: 52%;
  top: 2%;
  width: 36%;
  --bob: 6px;
  animation-duration: 22s;
  animation-delay: -4s;
}
.sky__cloud--3 {
  left: 68%;
  top: 38%;
  width: 48%;
  --bob: 4px;
  animation-duration: 20s;
  animation-delay: -8s;
}
.sky__cloud--4 {
  left: 2%;
  top: 52%;
  width: 38%;
  --bob: 5px;
  animation-duration: 24s;
  animation-delay: -14s;
}
.sky__cloud--5 {
  left: 44%;
  top: 62%;
  width: 34%;
  --bob: 5px;
  animation-duration: 19s;
  animation-delay: -2s;
}

/* Two clouds are mirrored so the five shapes do not read as one repeated
   sticker. */
.sky__cloud--2 svg,
.sky__cloud--4 svg {
  transform: scaleX(-1);
}

.sky__bird {
  position: absolute;
  top: 44%;
  width: clamp(72px, 14vw, 120px);
  translate: 0 -50%;
  color: #1f2a1f;
  pointer-events: none;
  will-change: transform;
  animation:
    fly 30s linear infinite,
    fade 30s linear infinite;
}

.sky__bird-bob {
  display: block;
  animation: flap 3.2s ease-in-out infinite;
}

@keyframes fly {
  from {
    left: -42%;
  }
  to {
    left: 142%;
  }
}

/* Fades in over the first 7% of the crossing and out over the last 7%, so the
   bird never pops in at the edge of the box. */
@keyframes fade {
  0% {
    opacity: 0;
  }
  7% {
    opacity: 1;
  }
  93% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes flap {
  0% {
    transform: translateY(0);
  }
  25% {
    transform: translateY(-6px);
  }
  50% {
    transform: translateY(2px);
  }
  75% {
    transform: translateY(-4px);
  }
  100% {
    transform: translateY(0);
  }
}

/* --- The partner marquee. The track holds the same eight logos twice and
       slides to -50%, which lands the copy exactly where the original was. --- */
@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* ==========================================================================
   6. Components
   ========================================================================== */

/* --- Button. One base, four variants. The hard shadow moves under the
       button on hover, which reads as the button being pressed down. --- */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding-inline: var(--space-5);
  border: 2px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg);
  color: var(--text);
  box-shadow: var(--shadow-hard);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transform: translate(0);
  transition:
    transform 0.12s ease-out,
    box-shadow 0.12s ease-out,
    background-color 0.12s ease-out;
}

.button:hover {
  transform: translate(2px, 2px);
  box-shadow: var(--shadow-hard-sm);
}

.button:active {
  transform: translate(3px, 3px);
  box-shadow: 1px 1px 0 0 var(--border);
}

.button--primary {
  background: var(--primary);
  color: var(--on-primary);
}

.button--primary:hover {
  background: color-mix(in srgb, var(--primary) 90%, var(--text));
}

.button--ghost {
  background: transparent;
}

.button--ghost:hover {
  background: color-mix(in srgb, var(--bg) 88%, var(--text));
}

/* On the ink panels the shadow has to be cream, not ink — an ink shadow on an
   ink background is invisible. */
.button--outline {
  background: transparent;
  color: var(--on-ink);
  border-color: color-mix(in srgb, var(--bg) 40%, transparent);
  box-shadow: 4px 4px 0 0 color-mix(in srgb, var(--bg) 20%, transparent);
}

.button--outline:hover {
  background: color-mix(in srgb, var(--bg) 8%, transparent);
  box-shadow: 2px 2px 0 0 color-mix(in srgb, var(--bg) 25%, transparent);
}

.button--ink {
  background: var(--text);
  color: var(--on-ink);
  border-color: var(--text);
  box-shadow: 4px 4px 0 0 color-mix(in srgb, var(--text) 35%, transparent);
}

.button--ink:hover {
  background: color-mix(in srgb, var(--text) 90%, var(--bg));
  box-shadow: 2px 2px 0 0 color-mix(in srgb, var(--text) 35%, transparent);
}

.button--small {
  min-height: 40px;
  padding-inline: var(--space-5);
}

/* --- Eyebrow: the small pill above every heading. --- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  padding: 0.375rem 0.875rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: transparent;
  color: var(--text);
}

.eyebrow--lime {
  background: var(--primary);
  color: var(--on-primary);
}

.eyebrow--ink {
  background: var(--text);
  color: var(--on-ink);
  border-color: var(--text);
}

.eyebrow--paper {
  color: var(--on-ink);
  border-color: color-mix(in srgb, var(--bg) 45%, transparent);
}

/* --- Card: cream box, ink border, hard shadow. Lifts towards the top-left
       on hover, so the shadow grows. --- */
.card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--space-5);
  border: 2px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--bg);
  box-shadow: var(--shadow-hard-lg);
  transition:
    transform 0.18s ease-out,
    box-shadow 0.18s ease-out;
}

.card:hover {
  transform: translate(-2px, -2px);
  box-shadow: 8px 8px 0 0 var(--border);
}

.card__index {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  margin-bottom: var(--space-4);
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--primary);
}

.card p {
  margin-top: var(--space-3);
  color: var(--muted);
}

/* --- Chip: the small outlined links under the process grid. --- */
.chip {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-5);
  border: 2px solid color-mix(in srgb, var(--border) 30%, transparent);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition:
    border-color 0.2s ease-out,
    background-color 0.2s ease-out;
}

.chip:hover {
  border-color: var(--border);
  background: var(--bg);
}

/* --- Tooltip over a partner logo. Opens on hover and on focus, so it is
       reachable with the keyboard and with a tap (a tap focuses the button). --- */
.tip {
  position: absolute;
  bottom: calc(100% + 0.65rem);
  left: 50%;
  z-index: 30;
  width: max-content;
  max-width: min(260px, 78vw);
  translate: -50% 0;
  padding: 0.625rem 1rem;
  border: 2px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--bg);
  color: var(--text);
  box-shadow: var(--shadow-hard);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
  text-transform: none;
  letter-spacing: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease-out;
}

/* The little arrow under the bubble. */
.tip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-top: -1px;
  translate: -50% 0;
  border-inline: 7px solid transparent;
  border-top: 8px solid var(--bg);
}

/* --- Form --- */
.form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.form__row label {
  display: block;
  margin-bottom: var(--space-2);
}

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

.form input,
.form textarea {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border: 2px solid color-mix(in srgb, var(--border) 25%, transparent);
  border-radius: var(--radius-card);
  background: var(--bg);
  font-size: var(--fs-body);
  transition:
    border-color 0.15s ease-out,
    box-shadow 0.15s ease-out;
}

.form textarea {
  min-height: 140px;
  resize: vertical;
}

.form input:hover,
.form textarea:hover {
  border-color: color-mix(in srgb, var(--border) 45%, transparent);
}

.form input:focus,
.form textarea:focus {
  border-color: var(--border);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 55%, transparent);
}

/* Native validation styling, applied only once the field has been touched.
   :user-invalid, not :invalid — the latter marks empty required fields red
   before anyone has typed anything. */
.form input:user-invalid,
.form textarea:user-invalid {
  border-color: var(--accent);
}

.form__note {
  margin-top: 0.375rem;
  color: var(--muted);
  font-size: var(--fs-small);
}

.form__status {
  font-size: var(--fs-small);
  color: var(--muted);
}

.form__status:empty {
  display: none;
}

.form__status--error {
  color: var(--accent);
  font-weight: 600;
}

.form__submit {
  min-height: 52px;
  padding-inline: var(--space-7);
  width: 100%;
}

/* ==========================================================================
   7. Header
   ========================================================================== */

.site-header {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: 2px solid var(--border);
  transition:
    background-color 0.2s ease-out,
    border-color 0.2s ease-out;
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  height: var(--header-height);
  background: inherit;
  position: relative;
  z-index: 60;
}

.brand {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

.brand__mark {
  height: 44px;
  width: auto;
  object-fit: contain;
  object-position: left;
}

.nav {
  display: none; /* desktop only, see section 9 */
}

.nav__list {
  display: flex;
  align-items: stretch;
  height: var(--header-height);
  gap: var(--space-1);
}

.nav__item {
  display: flex;
  align-items: stretch;
}

.nav__link {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.nav__label {
  position: relative;
  display: inline-block;
}

/* The underline is not scaled or translated: it is clipped. A clip-path grows
   from the left, which keeps the 3px bar crisp at any width. */
.nav__label::after {
  content: "";
  position: absolute;
  left: 0;
  top: 100%;
  margin-top: 2px;
  width: 100%;
  height: 3px;
  border-radius: var(--radius-sm);
  background: var(--primary);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.5s var(--ease-out-soft);
}

.nav__link:hover .nav__label::after,
.nav__link:focus-visible .nav__label::after {
  clip-path: inset(0 0 0 0);
}

.site-header__cta {
  display: none; /* desktop only */
}

/* --- Mega panel. Opens on hover and on keyboard focus, in CSS only.
       Two delays, as the reference had: none on the way in, 200ms on the way
       out, so the pointer can cross the gap between the link and the panel
       without the panel vanishing under it. --- */
.mega {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  z-index: 55;
  background: var(--primary);
  color: var(--on-primary);
  border-bottom: 2px solid var(--border);
  opacity: 0;
  visibility: hidden;
  /* content-visibility, and not only visibility: it also keeps the six
     thumbnails from being downloaded before anyone opens a panel — 74 Ko off
     the first screen. `allow-discrete` lets the fade still play on the way
     out; a browser without it just cuts, which is no worse than nothing. */
  content-visibility: hidden;
  transition:
    opacity 0.18s ease-out 0.2s,
    visibility 0s linear 0.38s,
    content-visibility 0s linear 0.38s allow-discrete;
}

.nav__item--mega:hover .mega,
.nav__item--mega:focus-within .mega {
  opacity: 1;
  visibility: visible;
  content-visibility: visible;
  transition:
    opacity 0.18s ease-out,
    visibility 0s,
    content-visibility 0s;
}

/* main.js sets this attribute to force the panel shut on scroll and on
   Escape; without it, a hovered panel would follow the page down. */
.site-header[data-mega="closed"] .mega {
  opacity: 0;
  visibility: hidden;
  transition: none;
}

/* When a panel is open the whole bar turns lime, so the header and the panel
   read as one surface. :has() does what the reference did with React state. */
.site-header:has(.nav__item--mega:hover) ,
.site-header:has(.nav__item--mega:focus-within) {
  background: var(--primary);
  border-bottom-color: transparent;
}

.site-header:has(.nav__item--mega:hover) .site-header__cta,
.site-header:has(.nav__item--mega:focus-within) .site-header__cta {
  background: var(--text);
  color: var(--on-ink);
  border-color: var(--text);
  box-shadow: 4px 4px 0 0 color-mix(in srgb, var(--text) 35%, transparent);
}

.site-header:has(.nav__item--mega:hover) .nav__label::after,
.site-header:has(.nav__item--mega:focus-within) .nav__label::after {
  background: var(--text);
}

.mega__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 40px;
  padding-block: var(--space-6) var(--space-7);
}

.mega__side {
  padding-right: 40px;
  border-right: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
}

.mega__title {
  color: color-mix(in srgb, var(--text) 65%, transparent);
  margin-bottom: var(--space-4);
}

.mega__lead {
  display: block;
  padding-bottom: var(--space-4);
  border-bottom: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
}

.mega__lead-title {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: -0.025em;
}

.mega__lead-note {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--fs-small);
}

.mega__links a {
  display: block;
  padding-block: var(--space-3);
  border-bottom: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.015em;
  transition: padding-left 0.2s ease-out;
}

.mega__links a:hover {
  padding-left: var(--space-2);
}

.mega__main-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.mega__main-head .mega__title {
  margin-bottom: 0;
}

.mega__cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
}

.mega__thumb {
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  border: 2px solid var(--text);
  border-radius: var(--radius-card);
  background: var(--bg);
  box-shadow: 3px 3px 0 0 var(--text);
}

.mega__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.5s ease-out;
}

.mega__card:hover .mega__thumb img {
  transform: scale(1.03);
}

.mega__card-title {
  display: block;
  margin-top: var(--space-3);
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.015em;
}

.mega__card-note {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-small);
  line-height: 1.35;
}

/* --- Mobile menu. A <details>, so it opens with the scripts removed. --- */
.menu {
  flex-shrink: 0;
}

.menu__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding-inline: var(--space-4);
  border: 2px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
  transition:
    background-color 0.2s ease-out,
    color 0.2s ease-out;
}

/* Chromium keeps the default triangle unless both of these are set. */
.menu__button::-webkit-details-marker {
  display: none;
}

.menu__button::marker {
  content: "";
}

.menu__button:hover {
  background: var(--primary);
  color: var(--on-primary);
}

.menu__button-close {
  display: none;
}

.menu[open] .menu__button-open {
  display: none;
}

.menu[open] .menu__button-close {
  display: inline;
}

.menu__panel {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--primary);
  border-bottom: 6px solid var(--text);
  padding-bottom: max(var(--space-4), env(safe-area-inset-bottom));
}

/* A closing <details> keeps its content in the DOM but hidden, so keyframes
   attached to it fire once and never again. main.js toggles `is-opening` on
   every open, which is what restarts the slide. */
.menu__panel.is-opening {
  animation: menu-open 0.42s cubic-bezier(0.32, 0.72, 0, 1);
}

@keyframes menu-open {
  from {
    clip-path: inset(0 0 100% 0);
    opacity: 0;
  }
  to {
    clip-path: inset(0 0 0 0);
    opacity: 1;
  }
}

.menu__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-shrink: 0;
  padding-top: max(1.35rem, env(safe-area-inset-top));
  padding-bottom: var(--space-4);
  border-bottom: 2px solid color-mix(in srgb, var(--text) 15%, transparent);
}

.menu__logo {
  height: 36px;
  width: auto;
  object-fit: contain;
  object-position: left;
}

.menu__close {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-5);
  border: 2px solid color-mix(in srgb, var(--text) 35%, transparent);
  border-radius: var(--radius-pill);
  background: transparent;
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    border-color 0.2s ease-out,
    background-color 0.2s ease-out;
}

.menu__close:hover {
  border-color: var(--text);
  background: color-mix(in srgb, var(--bg) 30%, transparent);
}

.menu__nav {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-block: var(--space-3);
}

.menu__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Each row is a cream card with the same hard shadow as the rest of the page. */
.menu__group,
.menu__solo {
  display: block;
  border: 2px solid var(--text);
  border-radius: var(--radius-card);
  background: var(--bg);
  box-shadow: 4px 4px 0 0 var(--text);
  overflow: hidden;
}

.menu__group > summary,
.menu__solo {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  cursor: pointer;
  list-style: none;
}

.menu__group > summary::-webkit-details-marker {
  display: none;
}

.menu__group > summary::marker {
  content: "";
}

.menu__index {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.55rem;
  border-radius: var(--radius-pill);
  background: var(--primary);
  border: 1.5px solid var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
}

.menu__title {
  flex: 1;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.015em;
}

.menu__chevron {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  transition: rotate 0.2s ease-out;
}

.menu__group[open] .menu__chevron {
  rotate: 180deg;
}

.menu__sublist {
  padding: 0 var(--space-5) var(--space-4) calc(var(--space-5) + 2.6rem);
}

.menu__sublist a {
  display: block;
  padding-block: var(--space-2);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--muted);
}

.menu__sublist a:hover {
  color: var(--text);
}

.menu__foot {
  flex-shrink: 0;
  padding-top: var(--space-4);
  border-top: 2px solid color-mix(in srgb, var(--text) 15%, transparent);
  text-align: center;
}

.menu__cta {
  width: 100%;
  min-height: 52px;
}

.menu__tagline {
  margin-top: var(--space-3);
  font-size: var(--fs-small);
  color: color-mix(in srgb, var(--text) 75%, transparent);
}

/* ==========================================================================
   8. Page sections, top to bottom
   ========================================================================== */

/* --- 8.1 Hero ----------------------------------------------------------- */

.hero {
  position: relative;
  background: var(--bg);
  /* The house sticks out to the right on purpose. */
  overflow-x: clip;
  overflow-y: visible;
  /* The 2px rule that separates the hero from the ink panel below. */
  border-bottom: 2px solid #000;
}

.hero__grid {
  position: relative;
  z-index: 10;
  display: grid;
  align-items: start;
  gap: var(--space-3);
  padding-top: var(--space-5);
  padding-bottom: 0;
}

.hero__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.hero__title {
  max-width: 16ch;
  line-height: 1.05;
}

/* Lime on cream is a 1.2:1 pair — unreadable on its own. The ink outline is
   what carries the word, and the 4px offset copy gives it the same hard
   shadow as the buttons. Remove the outline and the word disappears. */
.hero__accent {
  display: inline-block;
  color: var(--primary);
  text-shadow:
    0 -1.5px 0 var(--text),
    0 1.5px 0 var(--text),
    -1.5px 0 0 var(--text),
    1.5px 0 0 var(--text),
    -1.5px -1.5px 0 var(--text),
    1.5px -1.5px 0 var(--text),
    -1.5px 1.5px 0 var(--text),
    1.5px 1.5px 0 var(--text),
    4px 4px 0 var(--text);
}

.hero__lead {
  max-width: 46ch;
  color: var(--muted);
  line-height: 1.375;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

/* 24px of side padding, not 32: below 400px it is the difference between the
   two buttons sitting on one line, as in the reference, and stacking. */
.hero__actions .button {
  min-height: 48px;
  padding-inline: var(--space-5);
}

/* The wide illustration, desktop only. It is pinned to the bottom-right of
   the section and allowed to run past the shell. */
.hero__house {
  display: none;
}

.hero__house-small {
  position: relative;
  z-index: 5;
  width: 100%;
  margin-top: -144px;
  translate: 0 16%;
  padding-bottom: var(--space-2);
  pointer-events: none;
}

.sky {
  display: none; /* desktop only */
}

/* --- 8.2 About ---------------------------------------------------------- */

/* flex, not grid: the figure is sized by its own text (22vmin, up to 200px
   tall) and must never be squeezed by the column next to it — a grid with two
   equal tracks pushes the "+" straight through the sentence. */
.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  align-items: center;
  text-align: center;
  padding: var(--space-6);
  border: 1px solid var(--on-ink-line);
  border-radius: var(--radius-card);
  margin-bottom: var(--space-8);
}

.stat__figure {
  flex-shrink: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(5.5rem, 22vmin, 12.5rem);
  line-height: 0.82;
  letter-spacing: -0.025em;
  color: var(--primary);
}

.stat__side {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.stat__claim {
  line-height: 1.1;
  text-wrap: balance;
}

.stat__note {
  color: var(--on-ink-faint);
}

.about__grid {
  display: grid;
  gap: var(--space-8);
}

.about__intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}

.about__intro p {
  color: var(--on-ink-soft);
}

.about__points {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.point {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1px solid var(--on-ink-line);
  border-radius: var(--radius-card);
}

.point__index {
  flex-shrink: 0;
  margin-top: 0.15rem;
  color: var(--primary);
}

.point__text {
  margin-top: var(--space-2);
  color: var(--on-ink-soft);
}

/* --- 8.3 Testimonial carousel ------------------------------------------- */

.quotes {
  margin-top: var(--space-8);
}

.quotes__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  text-align: center;
}

.quotes__stars {
  display: flex;
  gap: var(--space-1);
  color: var(--primary);
  font-size: clamp(1.5rem, 4vw, 2.25rem);
  line-height: 1;
}

.quotes__sub {
  color: var(--on-ink-faint);
}

.quotes__frame {
  padding: var(--space-5);
  border: 1px solid var(--on-ink-line);
  border-radius: 1rem;
  background: var(--on-ink-wash);
}

/* scroll-snap, not a JS slider: the track slides, swipes and reaches the last
   quote with the scripts removed. main.js only adds the arrows, the dots and
   the 7.2s auto-advance. */
.quotes__track {
  display: flex;
  gap: var(--space-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  padding-bottom: var(--space-2);
}

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

.quotes__slide {
  flex: 0 0 100%;
  /* `start`, not `center`: with slides as wide as the track, the first and the
     last one can never reach the centre, and the browser would refuse to snap
     to them. */
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: min(14rem, 42vw);
  text-align: center;
}

.quotes__slide blockquote {
  max-width: 48rem;
}

.quotes__slide p {
  color: color-mix(in srgb, var(--bg) 85%, var(--text));
  line-height: 1.625;
}

.quotes__slide footer {
  margin-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.quotes__slide cite {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 600;
  font-style: normal;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--on-ink);
}

.quotes__slide footer span {
  font-size: var(--fs-small);
  color: var(--on-ink-faint);
}

/* The row of controls. It is empty in the HTML: main.js fills it, because
   arrows that do nothing without JavaScript are worse than no arrows. */
.quotes__bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

.quotes__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border: 2px solid color-mix(in srgb, var(--bg) 25%, transparent);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--on-ink);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  transition:
    border-color 0.2s ease-out,
    color 0.2s ease-out;
}

.quotes__arrow:hover {
  border-color: var(--primary);
  color: var(--primary);
}

.quotes__dots {
  display: flex;
  flex: 1;
  min-width: 0;
  justify-content: center;
  flex-wrap: nowrap;
  gap: var(--space-2);
  overflow-x: auto;
  scrollbar-width: none;
  padding-block: var(--space-1);
}

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

.quotes__dot {
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  padding: 0;
  border: none;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--bg) 25%, transparent);
  cursor: pointer;
  transition: background-color 0.2s ease-out;
}

.quotes__dot:hover {
  background: color-mix(in srgb, var(--bg) 45%, transparent);
}

.quotes__dot[aria-current="true"] {
  background: var(--primary);
}

.quotes__foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  text-align: center;
}

.quotes__position {
  font-size: var(--fs-small);
  color: var(--on-ink-faint);
}

.quotes__all {
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--primary);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--primary) 40%, transparent);
  text-underline-offset: 4px;
  transition: text-decoration-color 0.2s ease-out;
}

.quotes__all:hover {
  text-decoration-color: var(--primary);
}

/* --- 8.4 Who we serve --------------------------------------------------- */

.audience {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

/* --- 8.5 Partners ------------------------------------------------------- */

.partners {
  margin-top: var(--space-8);
  padding-top: var(--space-7);
  border-top: 1px solid color-mix(in srgb, var(--border) 12%, transparent);
}

.partners__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
}

.marquee {
  padding: var(--space-5) var(--space-5);
  border: 2px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--text);
  box-shadow: var(--shadow-hard);
}

/* `clip` on X only: the tooltips have to escape upwards. */
.marquee__clip {
  overflow-x: clip;
  overflow-y: visible;
  margin-inline: -0.25rem;
  padding-inline: 0.25rem;
  padding-top: var(--space-2);
}

.marquee__track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: marquee-scroll 55s linear infinite;
}

/* Pausing on hover is what makes the tooltips usable: a moving target cannot
   be hovered long enough to read. */
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track {
  animation-play-state: paused;
}

.marquee__row {
  display: flex;
  align-items: center;
}

.marquee__cell {
  position: relative;
  flex-shrink: 0;
  padding: var(--space-2) var(--space-5);
}

.marquee__button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 0;
  border: none;
  border-radius: var(--radius-card);
  background: transparent;
  cursor: pointer;
  transition: background-color 0.2s ease-out;
}

button.marquee__button:hover {
  background: color-mix(in srgb, var(--bg) 8%, transparent);
}

.marquee__cell:hover .tip,
.marquee__cell:focus-within .tip {
  opacity: 1;
}

/* Each logo gets a fixed box so the row keeps a steady rhythm whatever the
   logo's own proportions are. object-fit does the rest. */
.marquee__button img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}

.marquee__cell--sm .marquee__button {
  height: 2.85rem;
  width: 8.5rem;
}
.marquee__cell--md .marquee__button {
  height: 3.25rem;
  width: 10.5rem;
}
.marquee__cell--mdlg .marquee__button {
  height: 3.55rem;
  width: 12.25rem;
}
.marquee__cell--lg .marquee__button {
  height: 4.1rem;
  width: 14.25rem;
}
.marquee__cell--xl .marquee__button {
  height: 4.65rem;
  width: 16.25rem;
}

.partners__foot {
  display: flex;
  justify-content: center;
  margin-top: var(--space-5);
}

.partners__foot .button {
  min-height: 48px;
  padding-inline: var(--space-7);
}

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

/* Text and sprout share the first row; the button sits centred underneath.
   At 1024px the three move onto one line — see section 9. */
.cases__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-5);
  margin-bottom: var(--space-8);
}

.cases__intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}

.cases__text {
  max-width: 36rem;
  color: var(--on-ink-soft);
}

.cases__sprout {
  width: 112px;
  justify-self: end;
}

.cases__all {
  grid-column: 1 / -1;
  justify-self: center;
  min-height: 48px;
  padding-inline: var(--space-6);
}

.cases__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}

.case {
  height: 100%;
}

.case__link {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--on-ink-wash);
}

.case__media {
  position: relative;
  display: block;
  aspect-ratio: 380 / 238;
  overflow: hidden;
}

.case__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  transition: transform 0.7s ease-out;
}

.case__link:hover .case__media img {
  transform: scale(1.04);
}

.case__badge {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  padding: 0.25rem var(--space-3);
  border: 1px solid var(--primary);
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--primary);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.case__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--space-4);
}

.case__category {
  display: block;
  margin-bottom: var(--space-2);
  color: var(--on-ink-faint);
}

.case__name {
  display: block;
  flex: 1;
  color: var(--on-ink);
}

.case__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.case__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.case__tag {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.625rem;
  border: 1px solid color-mix(in srgb, var(--bg) 20%, transparent);
  border-radius: var(--radius-pill);
  color: var(--on-ink-faint);
  font-family: var(--font-body);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.case__read {
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--primary);
  transition: transform 0.2s ease-out;
}

.case__link:hover .case__read {
  transform: translateX(4px);
}

.cases__foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid var(--on-ink-line);
  text-align: center;
}

.cases__foot .h3 {
  max-width: 32rem;
}

.cases__link {
  flex-shrink: 0;
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--primary);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--primary) 40%, transparent);
  text-underline-offset: 4px;
  transition: text-decoration-color 0.2s ease-out;
}

.cases__link:hover {
  text-decoration-color: var(--primary);
}

/* --- 8.7 Process -------------------------------------------------------- */

/* The 1px gap over an ink background IS the border between two steps: one
   grid, one rounded frame, no doubled lines at the joins. */
.steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  border: 2px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--border);
  overflow: hidden;
}

.step {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--space-5);
  background: var(--bg);
}

.step__index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  width: 36px;
  height: 36px;
  margin-bottom: var(--space-5);
  border: 2px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--on-primary);
}

.step h3 {
  margin-bottom: var(--space-3);
}

.step p {
  flex: 1;
  color: var(--muted);
}

.services {
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid color-mix(in srgb, var(--border) 12%, transparent);
}

.services__title {
  margin-bottom: var(--space-5);
  color: var(--muted);
}

.services__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* --- 8.8 Contact -------------------------------------------------------- */

.contact {
  display: grid;
  gap: var(--space-8);
}

.contact__intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}

.contact__intro > p {
  max-width: 32rem;
  color: var(--muted);
}

.contact__aside {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-5);
  width: 100%;
  padding-top: var(--space-5);
  border-top: 1px solid color-mix(in srgb, var(--border) 15%, transparent);
}

.checks {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: 100%;
  font-size: var(--fs-small);
  color: var(--muted);
}

.checks li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.checks__dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--on-primary);
  font-size: 0.65rem;
  font-weight: 700;
}

.contact__call {
  margin-top: var(--space-5);
  font-size: var(--fs-small);
  color: var(--muted);
}

.contact__call a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--border) 30%, transparent);
  text-underline-offset: 2px;
  transition: text-decoration-color 0.2s ease-out;
}

.contact__call a:hover {
  text-decoration-color: var(--border);
}

/* 96px on a phone, 112px on a tablet, 220px on a desktop — the same three
   steps the reference takes. */
.contact__illustration {
  width: 96px;
}

/* --- 8.9 Closing call to action ----------------------------------------- */

.cta {
  position: relative;
  overflow: hidden;
}

.cta__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}

.cta__title {
  max-width: 18ch;
  color: var(--on-primary);
}

/* No min-height: the height comes from padding + a line-height of 1, which
   is what gives the reference its 64px bar on a phone and 68px on a desktop.
   Forcing 5.5rem here would make it half as tall again. */
.cta__button {
  width: 100%;
  padding-block: 20px;
  padding-inline: var(--space-7);
  font-size: 1.125rem;
  line-height: 1;
  letter-spacing: 0.08em;
}

/* --- 8.10 Footer -------------------------------------------------------- */

.site-footer {
  background: var(--text);
  color: var(--on-ink);
  border-top: 2px solid var(--on-ink-line);
}

.site-footer__top {
  display: grid;
  gap: var(--space-7);
  padding-top: var(--space-8);
}

.site-footer__brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-6);
}

.site-footer__logo {
  width: 100%;
  max-width: 240px;
}

.site-footer__tagline {
  max-width: 20rem;
  font-size: var(--fs-small);
  line-height: 1.625;
  color: var(--on-ink-faint);
}

.site-footer__contact {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.site-footer__contact .label {
  color: var(--on-ink-faint);
}

.site-footer__contact a {
  font-size: var(--fs-small);
  color: var(--on-ink-soft);
  transition: color 0.2s ease-out;
}

.site-footer__contact a:hover {
  color: var(--primary);
}

.site-footer__cta {
  min-height: 48px;
  padding-inline: var(--space-6);
}

.site-footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.site-footer__social a {
  display: inline-flex;
  align-items: center;
  padding: 0.375rem 0.875rem;
  border: 1px solid color-mix(in srgb, var(--bg) 20%, transparent);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-ink-faint);
  transition:
    color 0.2s ease-out,
    border-color 0.2s ease-out;
}

.site-footer__social a:hover {
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 50%, transparent);
}

.site-footer__columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-7) var(--space-5);
}

.site-footer__column-title {
  margin-bottom: var(--space-4);
  color: var(--on-ink-faint);
}

.site-footer__columns ul {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.site-footer__columns a {
  font-size: var(--fs-small);
  line-height: 1.375;
  color: var(--on-ink-faint);
  transition: color 0.2s ease-out;
}

.site-footer__columns a:hover {
  color: var(--on-ink);
}

.site-footer__lead-link {
  font-weight: 600;
  color: var(--on-ink-soft) !important;
}

.site-footer__lead-link:hover {
  color: var(--primary) !important;
}

.site-footer__legal {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-7);
  padding-block: var(--space-5);
  border-top: 1px solid color-mix(in srgb, var(--bg) 10%, transparent);
  font-size: var(--fs-small);
  color: var(--on-ink-faint);
}

.site-footer__legal nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem var(--space-5);
}

.site-footer__legal a {
  transition: color 0.2s ease-out;
}

.site-footer__legal a:hover {
  color: var(--on-ink);
}

/* ==========================================================================
   9. Responsive
   --------------------------------------------------------------------------
   Only layout changes live here. Font sizes never do: they are clamp() values
   declared in section 1.
   ========================================================================== */

@media (min-width: 640px) {
  .audience {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .form__submit {
    width: auto;
  }

  .cta__button {
    font-size: 1.25rem;
  }

  .site-footer__columns {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-7) var(--space-6);
  }

  .contact__illustration {
    width: 112px;
  }

  .quotes__foot {
    flex-direction: row;
    justify-content: space-between;
    text-align: left;
  }
}

@media (min-width: 768px) {
  :root {
    --section-y: 112px;
  }

  .stat {
    padding: var(--space-7);
  }

  .marquee {
    padding: var(--space-6) var(--space-7);
  }

  .cta__button {
    font-size: 1.5rem;
    padding-inline: var(--space-8);
  }

  .site-footer__logo {
    max-width: 280px;
  }

  .site-footer__legal {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

@media (max-width: 767.98px) {
  :root {
    --section-y: 80px;
  }
}

@media (min-width: 1024px) {
  /* --- Hero switches to two columns and grows the house. --- */
  .hero__grid {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.68fr);
    gap: var(--space-8);
    padding-block: var(--space-9);
    min-height: calc(100svh - var(--header-height));
    max-height: 960px;
  }

  .hero__text {
    gap: var(--space-5);
  }

  .hero__lead {
    line-height: 1.6;
  }

  .hero__actions .button {
    min-height: 52px;
    padding-inline: var(--space-7);
  }

  .sky {
    display: block;
    width: min(300px, 38vw);
  }

  /* Pinned to the bottom-right corner of the section. The `right` value walks
     back from the shell's own gutter, so the house keeps the same distance to
     the text column at every width. */
  .hero__house {
    display: block;
    position: absolute;
    z-index: 0;
    bottom: 40px;
    right: calc(max(0px, (100vw - min(1200px, 92vw)) / 2 - 6rem) - 4.75rem);
    width: min(520px, 38vw);
    max-width: none;
    translate: 0 28%;
    pointer-events: none;
    user-select: none;
  }

  .hero__house-small {
    display: none;
  }

  /* --- Navigation moves out of the <details> and into the bar. --- */
  .nav {
    display: block;
  }

  .site-header__cta {
    display: inline-flex;
  }

  .menu {
    display: none;
  }

  /* --- Two-column layouts. --- */
  /* 1.25 and 1.22, not 1 and 1: measured on the reference. The heading column
     has to be wide enough for "Websites, fundraising systems, and growth
     infrastructure for nonprofits." to break in five lines, not six. */
  .section-head {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    gap: var(--space-8);
    align-items: end;
  }

  /* The figure only sits beside the sentence from 1024px up. Below that it
     would not shrink (it is sized in vmin) and would widen the page. */
  .stat {
    flex-direction: row;
    text-align: left;
  }

  .stat__side {
    min-width: 0;
  }

  .about__grid {
    grid-template-columns: minmax(0, 1.22fr) minmax(0, 1fr);
  }

  .audience {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .steps {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .step {
    padding: var(--space-6);
  }

  .cases__head {
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: var(--space-6);
  }

  .cases__sprout {
    width: 224px;
    justify-self: end;
    align-self: start;
  }

  .cases__all {
    grid-column: auto;
    justify-self: end;
    align-self: start;
  }

  .cases__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-6);
  }

  .cases__foot {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    text-align: left;
  }

  .contact {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: var(--space-8);
  }

  .contact__aside {
    grid-template-columns: minmax(0, 1fr);
  }

  .contact__illustration {
    width: 220px;
  }

  .quotes__frame {
    padding: 40px;
  }

  .quotes__slide {
    min-height: 11.5rem;
  }

  .quotes__arrow {
    width: 56px;
    height: 56px;
    font-size: 1.5rem;
  }

  /* A grid, not a wrapping flex row: a flex item with flex-basis: 100% would
     stretch the eyebrow pill across the whole panel. */
  .cta__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--space-8);
    row-gap: var(--space-6);
  }

  .cta__inner .eyebrow {
    grid-column: 1 / -1;
    justify-self: start;
  }

  .site-footer__top {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 2.6fr);
    gap: var(--space-8);
  }
}

@media (min-width: 1280px) {
  .hero__house {
    width: min(600px, 42vw);
    right: calc(max(0px, (100vw - min(1200px, 92vw)) / 2 - 6rem) - 5.75rem);
  }

  .site-footer__top {
    gap: 80px;
  }
}

@media (min-width: 1536px) {
  .hero__house {
    width: min(640px, 44vw);
  }
}

/* ==========================================================================
   10. Reduced motion
   --------------------------------------------------------------------------
   Every loop stops, every entrance lands on its final state, and every delay
   goes to zero — a delay is movement spread over time.
   ========================================================================== */

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

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
  }

  /* The reveals must not depend on the observer here: they land visible. */
  .js [data-reveal] {
    opacity: 1;
    transform: none;
  }

  /* The marquee stops mid-slide otherwise, cutting a logo in half. The
     reference dropped it for a static wrapped row; so do we. */
  .marquee__clip {
    overflow-x: visible;
  }

  .marquee__track {
    width: 100%;
    flex-wrap: wrap;
    justify-content: center;
    transform: none;
  }

  .marquee__row[aria-hidden="true"] {
    display: none;
  }

  .marquee__row {
    flex-wrap: wrap;
    justify-content: center;
  }

  .quotes__track {
    scroll-behavior: auto;
  }

  .sky__bird {
    display: none;
  }
}
