/* ======================================================
   01-hero.css
   ====================================================== */
/* ============================================================================
   01 — HERO
   Owns every selector prefixed .hero-. Uses the shared utilities from
   base.css (.container, .eyebrow, .lead, .btn, .rule,
   .reveal, .icon, .bg-layer) and never redefines one.
   Colour comes only from tokens.css.
   ============================================================================ */

.hero {
  position: relative;
  isolation: isolate;          /* keeps the bg-layers and the bloom inside     */
  overflow: clip;              /* the bloom must never bleed into section 02   */
  padding-block: var(--space-12) var(--section-y-tight);
}

/* Stacked on phones. The height is content-driven here — never fixed — so the
   hero cannot clip itself on a 390 x 740 screen. */
.hero-inner {
  display: grid;
  /* minmax(0, …) everywhere: a wide child can never widen the track and put a
     horizontal scrollbar on the page. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0;                      /* vertical rhythm is set per block, below      */
}

.hero-copy {
  min-width: 0;                /* long mono strings must not widen the grid    */
}


/* ── Eyebrow ──────────────────────────────────────────────────────────────
   .eyebrow supplies mono / uppercase / tracking / trailing hairline. The hero
   carries no index number: it has no nav entry and no section number. */
.hero-eyebrow {
  --reveal-delay: 0ms;
}


/* ── Headline — the only h1 on the page ──────────────────────────────────
   The two spans hold the clause break from the content file: "others hand
   back" is a block of its own at every width, so line one can rag but the
   closing clause can never leave an orphaned word behind. */
.hero-title {
  --reveal-delay: 60ms;
  margin-top: var(--space-6);
  font-family: var(--ff-display);
  font-size: var(--fs-display);
  font-weight: var(--fw-bold);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  color: var(--text-primary);
  text-wrap: balance;
}

.hero-title__line {
  display: block;
}


/* ── Subheadline ────────────────────────────────────────────────────────── */
.hero-lead {
  --reveal-delay: 120ms;
  margin-top: var(--space-6);
  max-width: var(--measure-tight);
}

/* Machine facts only: 15+ years, and the two trust-strip numerals. */
.hero-fig {
  font-family: var(--ff-mono);
  font-weight: var(--fw-regular);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--ls-mono);
  font-size: 0.95em;           /* optical match: mono runs large beside Inter  */
  color: var(--text-primary);
}


/* ── Calls to action ────────────────────────────────────────────────────── */
.hero-actions {
  --reveal-delay: 180ms;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-8);
}

.hero-action .icon {
  width: 1.125em;
  height: 1.125em;
}

.hero-note {
  --reveal-delay: 220ms;
  margin-top: var(--space-4);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.hero-email {
  color: var(--text-brand);
  text-decoration: underline;
  text-decoration-color: var(--border-brand);
  text-decoration-thickness: var(--hairline);
  text-underline-offset: 0.22em;
  transition: text-decoration-color var(--dur-fast) var(--ease-out);
}

.hero-email:hover {
  text-decoration-color: currentColor;
}


/* ── Trust strip ────────────────────────────────────────────────────────── */
.hero-rule {
  --reveal-delay: 260ms;
  margin-top: var(--space-8);
}

/* Under 480px this stacks to three lines and the dots go, rather than the
   type shrinking. That is the mobile rule from the content file. */
.hero-trust {
  --reveal-delay: 300ms;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-5);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  color: var(--text-muted);
}

.hero-trust__sep {
  display: none;
}

@media (min-width: 30em) {
  .hero-trust {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
  }

  .hero-trust__sep {
    display: inline;
    margin-left: var(--space-3);
    color: var(--border-control);
  }
}


/* ── The visual ─────────────────────────────────────────────────────────── */
.hero-visual {
  --reveal-delay: 140ms;
  position: relative;
  isolation: isolate;
  margin-top: var(--block-gap);
}

/* The single soft radial bloom, in brand blue, behind the composition. */
.hero-visual::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -14% -10%;
  pointer-events: none;
  background: radial-gradient(closest-side at 54% 46%,
    color-mix(in srgb, var(--brand) 26%, transparent) 0%,
    var(--brand-subtle) 44%,
    transparent 78%);
}

.hero-visual__img {
  width: 100%;
  max-width: 30rem;
  height: auto;
}

/* Stacked but wide: the board moves to the right edge so the tablet layout keeps
   the same left-type / right-art diagonal as the desktop one. */
@media (min-width: 40em) {
  .hero-visual__img {
    margin-inline-start: auto;
  }
}


/* ── Scroll cue — desktop only, where there is height to spare ──────────── */
.hero-foot {
  display: none;
}

.hero-scroll {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  width: max-content;
  color: var(--text-muted);
}

.hero-scroll__rail {
  position: relative;
  width: var(--hairline);
  height: 2rem;
  overflow: hidden;
  background: linear-gradient(180deg, transparent, var(--border-strong));
}

/* One short pulse travelling down the rail. Three passes, then it rests —
   nothing on this page loops forever. */
.hero-scroll__rail::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: -45%;
  height: 45%;
  background: linear-gradient(180deg, transparent, var(--cyan));
  animation: hero-scroll-pulse 2.4s var(--ease-inout) 3 both;
}

@keyframes hero-scroll-pulse {
  from { transform: translateY(0); }
  to   { transform: translateY(340%); }
}

.hero-scroll__chevron {
  width: 1rem;
  height: 1rem;
  opacity: 0.75;
}


/* ── Asymmetric two-column from 1024px: type in 7, visual in 5 ──────────── */
@media (min-width: 64em) {
  .hero {
    display: grid;
    grid-template-rows: 1fr auto;
    /* At least 88vh, and exactly the screen that is left under the sticky
       header. min-height only: taller content grows the section, never clips. */
    min-height: calc(100vh - var(--header-h));
    min-height: calc(100svh - var(--header-h));
    padding-block: var(--space-10) var(--space-8);
  }

  /* Type in the left seven columns, the board in the right five. The hairline
     and the proof strip break out under both of them, so the rule runs the full
     width of the container the way a datasheet footer does. */
  .hero-inner {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    column-gap: var(--grid-gap-lg);
    row-gap: 0;
    align-self: center;
  }

  .hero-copy   { grid-column: 1;      grid-row: 1; }
  .hero-visual { grid-column: 2;      grid-row: 1; align-self: center; margin-top: 0; }
  .hero-rule   { grid-column: 1 / -1; grid-row: 2; margin-top: var(--space-12); }
  .hero-trust  { grid-column: 1 / -1; grid-row: 3; }

  .hero-visual__img {
    max-width: none;
  }

  /* 40px of clearance above a 48px rail left the cue stranded in an empty band
     of its own, which is what made it read as leftover scaffolding rather than
     as the closing mark of the hero. Tightened to 24 above a 32px rail so it
     sits with the trust strip. Note it is still below the fold on a 900px-tall
     laptop — the hero is simply taller than that viewport — so treat the cue as
     decoration, not as the affordance that gets people down the page. */
  .hero-foot {
    display: block;
    align-self: end;
    margin-top: var(--space-6);
  }
}

/* The hero is taller than a 900px-tall laptop viewport, so on short screens the
   cue lands past the fold and renders as an orphaned 1px rail with its chevron
   cut in half — worse than no cue at all. Show it only where the whole thing
   fits. Above 960px of viewport height it appears complete, as intended. */
@media (min-width: 64em) and (max-height: 59.99rem) {
  .hero-foot { display: none; }
}


/* ── Reduced motion: no entrance, no cue animation ─────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .hero-scroll__rail::after {
    animation: none;
  }
}

/* ======================================================
   02-about.css
   ====================================================== */
/* ==========================================================================
   02 — WHO WE ARE  ·  section id="about"
   Owns the .abt-* namespace only. The shared utilities (.container .section
   .section-head .eyebrow .lead .rule .reveal .sr-only .icon) are
   defined once in assets/css/base.css and are never redefined here.
   Colour comes exclusively from tokens.css custom properties.
   ========================================================================== */

.abt {
  position: relative;
}

/* --- section head ------------------------------------------------------- */
/* The eyebrow index numeral is base.css's .eyebrow__num for every section. Nine
   sections had invented six different names for it, four of which were styled
   by nothing and therefore inherited .eyebrow's cyan; the numbers rendered
   muted in two sections and cyan in seven, at three different spacings. The
   spacing comes free from .eyebrow's own flex `gap`. */

.abt-title {
  margin: var(--space-3) 0 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-h2);
  color: var(--text-primary);
  text-wrap: balance;
}

/* --- prose + rail ------------------------------------------------------- */
.abt-body {
  display: grid;
  gap: var(--block-gap);
  align-items: start;
  margin-top: clamp(1.75rem, 1.25rem + 2.2vw, 3rem);
}

.abt-prose {
  min-width: 0;
  max-width: 62ch;
}

.abt-para {
  margin: var(--space-6) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  color: var(--text-secondary);
  max-width: 62ch;
}

/* The rail: a barely-elevated panel, hairline edge, one 1px cyan top-edge
   highlight. No shadow — elevation is drawn, not dropped. */
.abt-rail {
  position: relative;
  min-width: 0;
  overflow: hidden;
  padding: var(--space-5) var(--space-6) var(--space-6);
  background: var(--surface-1);
  border: var(--hairline) solid var(--border-hairline);
  border-radius: var(--radius-lg);
}

.abt-rail::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: var(--hairline);
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--cyan) 55%, transparent) 18%,
    color-mix(in srgb, var(--cyan) 55%, transparent) 72%,
    transparent 100%
  );
  opacity: 0.75;
  pointer-events: none;
}

.abt-disc {
  margin: 0;
  padding: 0;
  list-style: none;
}

.abt-disc__item {
  display: grid;
  grid-template-columns: 1.25rem minmax(0, 1fr);
  column-gap: var(--space-3);
  row-gap: var(--space-1);
  padding-block: var(--space-4);
  border-top: var(--hairline) solid var(--border-hairline);
}

.abt-disc__item:first-child {
  padding-block-start: var(--space-1);
  border-top: 0;
}

.abt-disc__item .abt-disc__icon {
  grid-column: 1;
  grid-row: 1 / span 2;
  width: 1.25rem;
  height: 1.25rem;
  margin-block-start: 0.15em;
  color: var(--text-muted);
}

.abt-disc__title {
  grid-column: 2;
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
}

.abt-disc__desc {
  grid-column: 2;
  margin: 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  line-height: 1.55;
  color: var(--text-secondary);
}

.abt-rail__note {
  margin: var(--space-5) 0 0;
  padding-block-start: var(--space-5);
  border-top: var(--hairline) solid var(--border-hairline);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

/* --- stat band ----------------------------------------------------------
   Four figures in a hairline-ruled band, like a spec table. Two-up at every
   width below 62rem — including 390px, where it stays scannable rather than
   collapsing into a column of four. */
.abt-stats {
  margin: var(--block-gap) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-bottom: var(--hairline) solid var(--border-hairline);
}

.abt-stat {
  min-width: 0;
  padding: var(--space-5) var(--space-4) var(--space-6);
  border-top: var(--hairline) solid var(--border-hairline);
  border-left: var(--hairline) solid var(--border-hairline);
}

.abt-stat:nth-child(2n + 1) {
  padding-left: 0;
  border-left: 0;
}

.abt-stat__num {
  margin: 0;
  font-family: var(--ff-mono);
  font-size: var(--fs-stat);
  font-weight: var(--fw-medium);
  line-height: var(--lh-flat);
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  white-space: nowrap;
  /* only "24 h" carries a space; a full mono space at 60px reads as two
     separate figures, so it is pulled back to a unit gap. */
  word-spacing: -0.5em;
}

.abt-stat__unit {
  font-size: 0.62em;
  color: var(--text-muted);
}

.abt-stat__label {
  margin: var(--space-4) 0 0;
  font-family: var(--ff-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1.45;
  color: var(--text-secondary);
  text-wrap: balance;
}

/* The honest footnote under each figure. Always visible on purpose: a claim a
   buyer has to hover to verify reads as a claim being hidden. */
.abt-stat__note {
  margin: var(--space-2) 0 0;
  max-width: 34ch;
  font-family: var(--ff-body);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
  line-height: 1.45;
  color: var(--text-muted);
}

/* --- entrance stagger ---------------------------------------------------
   60ms inside the group. .reveal itself is base.css / app.js; only the
   per-item offset belongs to this section. */
.abt-stat:nth-child(2) { transition-delay: 60ms;  animation-delay: 60ms;  }
.abt-stat:nth-child(3) { transition-delay: 120ms; animation-delay: 120ms; }
.abt-stat:nth-child(4) { transition-delay: 180ms; animation-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
  .abt-stat:nth-child(n) {
    transition-delay: 0s;
    animation-delay: 0s;
  }
}

/* --- 768px: the rail is still full width, the prose gets its measure ----- */
@media (min-width: 48rem) {
  .abt-stat {
    padding-right: var(--space-6);
    padding-left: var(--space-8);
  }

  .abt-stat:nth-child(2n + 1) {
    padding-left: 0;
  }
}

/* --- 992px: prose left, compact rail right, stats four-up --------------- */
@media (min-width: 62rem) {
  .abt-body {
    grid-template-columns: minmax(0, 1fr) minmax(17rem, 24rem);
    column-gap: clamp(2rem, 3.5vw, 4rem);
  }

  .abt-stats {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .abt-stat:nth-child(2n + 1) {
    padding-left: var(--space-6);
    border-left: var(--hairline) solid var(--border-hairline);
  }

  .abt-stat:first-child {
    padding-left: 0;
    border-left: 0;
  }
}

/* --- 1200px: the rail can take its full width without starving the measure */
@media (min-width: 75rem) {
  .abt-body {
    grid-template-columns: minmax(0, 1fr) minmax(20rem, 30rem);
  }
}

/* ======================================================
   03-services.css
   ====================================================== */
/* =============================================================================
   03 — SERVICES   #services
   Owned by the services section builder. Everything here is scoped to .svc or a
   svc- prefixed class; no bare element selectors, no redefinition of the shared
   utilities from base.css (.container .section .section-head .eyebrow .lead
   .btn .icon .reveal .sr-only). Colour comes from tokens only — no raw hex.
   ============================================================================= */

.svc {
  position: relative;
  isolation: isolate;
}

/* Instrument grid, drawn from the hairline token so no asset is required.
   It is masked to fade at both ends and sits behind opaque cards, so no
   pattern ever runs under body copy. */
.svc::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to right,  var(--border-hairline) 0 1px, transparent 1px 72px),
    repeating-linear-gradient(to bottom, var(--border-hairline) 0 1px, transparent 1px 72px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, var(--text-primary) 18%, var(--text-primary) 52%, transparent 88%);
          mask-image: linear-gradient(to bottom, transparent 0, var(--text-primary) 18%, var(--text-primary) 52%, transparent 88%);
}

/* ---- head -------------------------------------------------------------- */

.svc-positioning {
  margin: var(--space-6) 0 0;
  padding-left: var(--space-5);
  border-left: var(--hairline) solid var(--border-strong);
  max-width: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-primary);
  text-wrap: pretty;
}

/* ---- grid -------------------------------------------------------------- */

.svc-grid {
  list-style: none;
  margin: var(--block-gap) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}

@media (min-width: 680px) {
  .svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); }
}
/* No 3-column step: there are 8 cards, and 8 divides by 2 and by 4 but never
   by 3 — a 3-column band left cards 07 and 08 alone on the last row beside a
   full card-width void. 2 columns at 1024 gives ~490px cards, which this copy
   reads well at; 4 columns there would give 240px, which it does not. */
@media (min-width: 1280px) {
  .svc-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---- card -------------------------------------------------------------- */

.svc-card {
  --svc-pad: var(--space-5);
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--svc-pad);
  background: var(--surface-1);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  overflow-wrap: break-word;
  transition:
    transform    var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out),
    box-shadow   var(--dur-base) var(--ease-out);
}

@media (min-width: 680px) {
  .svc-card { --svc-pad: var(--space-6); }
}

/* Resting 1px top-edge highlight. */
.svc-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--svc-pad);
  right: var(--svc-pad);
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--border-strong) 24%, var(--border-strong) 76%, transparent);
}

/* The same edge, brightened to light on hover. Two layers, because a gradient
   cannot be transitioned — only its opacity can. */
.svc-card::after {
  content: "";
  position: absolute;
  top: 0;
  left: var(--svc-pad);
  right: var(--svc-pad);
  height: 1px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(90deg, transparent, var(--cyan) 26%, var(--brand) 74%, transparent);
  transition: opacity var(--dur-base) var(--ease-out);
}

.svc-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-brand);
  box-shadow: var(--shadow-2);
}

.svc-card:hover::after,
.svc-card:focus-within::after {
  opacity: 0.7;
}

/* ---- card head --------------------------------------------------------- */

.svc-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.svc-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  border: var(--hairline) solid var(--border-hairline);
  color: var(--text-secondary);
  transition:
    color        var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

.svc-card__icon .icon {
  width: 1.375rem;
  height: 1.375rem;
}

.svc-card:hover .svc-card__icon {
  color: var(--text-cyan);
  border-color: var(--border-cyan);
}

.svc-card__index {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  line-height: var(--lh-flat);
  letter-spacing: var(--ls-eyebrow);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

/* ---- card body --------------------------------------------------------- */

.svc-card__title {
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
  text-wrap: balance;
}

.svc-card__value {
  margin: var(--space-3) 0 0;
  max-width: none;
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  color: var(--text-primary);
  text-wrap: pretty;
}

.svc-card__body {
  margin: var(--space-4) 0 var(--space-5);
  max-width: none;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-secondary);
  text-wrap: pretty;
}

/* S8 footnote — the authorization test, always rendered with the card. */
.svc-card__note {
  margin: calc(var(--space-4) * -1) 0 var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--hairline) solid var(--border-hairline);
  max-width: none;
  font-size: var(--fs-micro);
  line-height: 1.55;
  color: var(--text-muted);
}

/* Typical request. Mono, small, set apart by a cyan hairline.
   It used to be pinned to the card foot with `margin: auto 0 0` so the quotes
   lined up across a row. That reasoning holds while the bodies are within a
   line or two of each other and collapses when they are not: measured gaps
   between the body's last line and this rule ran 294px, 228px, 205px and 115px
   at 1440 — a bordered box with eight lines of text, then a void, then a
   hairline clinging to the bottom edge. The slack now falls into the card's
   bottom padding, where it reads as padding rather than as a hole. */
.svc-card__quote {
  margin: var(--space-6) 0 0;
  padding: var(--space-5) 0 0 var(--space-4);
  border-top: var(--hairline) solid var(--border-hairline);
  border-left: var(--hairline) solid var(--border-cyan);
}

.svc-card__quote p {
  margin: 0;
  max-width: none;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
  line-height: 1.65;
  letter-spacing: var(--ls-mono);
  color: var(--text-muted);
}

/* ---- section foot ------------------------------------------------------ */

.svc-foot {
  margin-top: var(--block-gap);
  padding-top: var(--space-8);
  border-top: var(--hairline) solid var(--border-hairline);
}

.svc-cta {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-primary);
  text-wrap: pretty;
}

.svc-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-6);
}

.svc-boundary {
  margin: var(--space-6) 0 0;
  max-width: var(--measure);
  font-size: var(--fs-micro);
  line-height: 1.6;
  color: var(--text-muted);
}

/* ---- reveal stagger ---------------------------------------------------- */
/* base.css owns .reveal itself; this only offsets the start of each card by
   60ms so a row enters as a sequence, not as a block. Both properties are set
   because base.css may drive .reveal with a transition or with an animation. */

.svc-grid > .reveal:nth-child(1) { --reveal-delay:   0ms; transition-delay:   0ms; animation-delay:   0ms; }
.svc-grid > .reveal:nth-child(2) { --reveal-delay:  60ms; transition-delay:  60ms; animation-delay:  60ms; }
.svc-grid > .reveal:nth-child(3) { --reveal-delay: 120ms; transition-delay: 120ms; animation-delay: 120ms; }
.svc-grid > .reveal:nth-child(4) { --reveal-delay: 180ms; transition-delay: 180ms; animation-delay: 180ms; }
.svc-grid > .reveal:nth-child(5) { --reveal-delay: 240ms; transition-delay: 240ms; animation-delay: 240ms; }
.svc-grid > .reveal:nth-child(6) { --reveal-delay: 300ms; transition-delay: 300ms; animation-delay: 300ms; }
.svc-grid > .reveal:nth-child(7) { --reveal-delay: 360ms; transition-delay: 360ms; animation-delay: 360ms; }
.svc-grid > .reveal:nth-child(8) { --reveal-delay: 420ms; transition-delay: 420ms; animation-delay: 420ms; }

@media (prefers-reduced-motion: reduce) {
  .svc-grid > .reveal {
    --reveal-delay: 0ms;
    transition-delay: 0ms;
    animation-delay: 0ms;
  }
  .svc-card,
  .svc-card::after,
  .svc-card__icon {
    transition: none;
  }
  .svc-card:hover {
    transform: none;
  }
}

/* ======================================================
   04-expertise.css
   ====================================================== */
/* ==========================================================================
   04 — Expertise / capabilities.  Section id="expertise".
   Class prefix: exp-

   Owns exactly these selectors:
     .exp  .exp-grid  .exp-col  .exp-col-title  .exp-list  .exp-mono
     .exp-notes  .exp-note
   Uses, never redefines, the shared utilities from base.css:
     .section  .container  .section-head  .eyebrow  .lead  .reveal

   Treatment: a datasheet, not a marketing block. Four capability columns
   separated by vertical hairlines on desktop, two at 640px, one below that,
   where the vertical hairlines become horizontal rules. Dense, small, tight.
   The PCB trace field behind it is inlined as a data URI so the partial works
   whether its CSS is <link>ed from /partials or inlined into index.html.
   ========================================================================== */

.exp {
  position: relative;
  isolation: isolate;
  background: var(--surface-0);
}

/* PCB trace field — images/bg-pcb-traces.svg, 320px tile, 0.06 opacity. */
.exp::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* The tile carries its own stroke-opacity (0.14-0.42), so the layer opacity
     is raised to land the rendered field at the intended low end of the 0.05-0.12 band. */
  opacity: 0.12;
  /* The same tile as the footer's, which base.css already loads — so it is
     cached by the time this section paints. It shipped inline as 5.1KB of
     URL-encoded text for no gain. */
  background-image: url("../img/bg-pcb-traces.svg");
  background-repeat: repeat;
  background-size: 320px 320px;
}

/* Fades the tile into the page ground at the top and bottom seams. */
.exp::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: linear-gradient(
    180deg,
    var(--surface-0) 0,
    transparent 16%,
    transparent 84%,
    var(--surface-0) 100%
  );
}

/* --------------------------------------------------------------------------
   The four capability columns
   -------------------------------------------------------------------------- */

.exp-grid {
  list-style: none;
  margin: var(--block-gap) 0 0;
  padding: 0;
  display: grid;
  gap: 0;
  grid-template-columns: minmax(0, 1fr);
}

/* Mobile: one column, hairlines become horizontal rules between the groups. */
.exp-col {
  min-width: 0;
  padding: var(--space-8) 0 0;
  border-top: var(--hairline) solid var(--border-hairline);
}

.exp-col:first-child {
  padding-top: 0;
  border-top: 0;
}

/* Two of the four headings wrap to a second line, which started their lists
   19px lower than the other two across an otherwise perfectly ruled row.
   Reserve two lines for every heading so the lists start level. */
.exp-col-title {
  position: relative;
  margin: 0 0 var(--space-5);
  padding-top: var(--space-4);
  min-block-size: calc(var(--space-4) + 2em * var(--lh-snug));
  font-family: var(--ff-mono);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-mono);
  color: var(--text-primary);
  text-wrap: balance;
}

/* A short cyan tick above each column title. Cyan as light, not as fill. */
.exp-col-title::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 36px;
  block-size: 2px;
  background-image: linear-gradient(90deg, var(--cyan), transparent);
}

.exp-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}

.exp-list > li {
  position: relative;
  max-width: var(--measure-tight);
  padding-inline-start: var(--space-5);
  font-size: var(--fs-small);
  line-height: 1.45;
  color: var(--text-secondary);
}

/* The datasheet marker: a 9px cyan hyphen on the reading line. */
.exp-list > li::before {
  content: "";
  position: absolute;
  inset-block-start: 0.63em;
  inset-inline-start: 0;
  inline-size: 9px;
  block-size: var(--hairline);
  background: var(--cyan);
}

/* Inline machine facts: protocol, platform, architecture and interface names.
   Never a whole bullet — a fully monospaced list reads as a code block. */
.exp-mono {
  font-family: var(--ff-mono);
  font-size: 0.94em;
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-mono);
  color: var(--text-primary);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   The three notes under the grid. Three separate answers to three separate
   objections — never merged into one paragraph.
   -------------------------------------------------------------------------- */

.exp-notes {
  margin-top: var(--block-gap);
  padding-top: var(--space-8);
  border-top: var(--hairline) solid var(--border-hairline);
  display: grid;
  gap: var(--space-6);
}

.exp-note {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-secondary);
}

.exp-note + .exp-note {
  padding-top: var(--space-6);
  border-top: var(--hairline) solid var(--border-hairline);
}

/* --------------------------------------------------------------------------
   640px — two columns, vertical hairline between the pair, horizontal rule
   between the two rows.
   -------------------------------------------------------------------------- */

@media (min-width: 40em) {
  .exp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .exp-col {
    padding: var(--space-8) var(--space-6);
    border-top: 0;
  }
  .exp-col:nth-child(-n + 2)  { padding-top: 0; }
  .exp-col:nth-child(n + 3)   { border-top: var(--hairline) solid var(--border-hairline); }
  .exp-col:nth-child(2n + 1)  { padding-inline-start: 0; }
  .exp-col:nth-child(2n)      { padding-inline-end: 0;
                                border-inline-start: var(--hairline) solid var(--border-hairline); }
}

/* --------------------------------------------------------------------------
   1024px — the full four-column datasheet.
   -------------------------------------------------------------------------- */

@media (min-width: 64em) {
  .exp-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* reset the two-column rules at equal specificity, then rebuild */
  .exp-col                    { padding: 0 var(--space-5); }
  .exp-col:nth-child(n + 3)   { border-top: 0; }
  .exp-col:nth-child(2n)      { border-inline-start: 0; }
  .exp-col:nth-child(2n + 1)  { padding-inline-start: var(--space-5); }
  .exp-col:nth-child(2n)      { padding-inline-end: var(--space-5); }

  .exp-col + .exp-col         { border-inline-start: var(--hairline) solid var(--border-hairline); }
  .exp-col:first-child        { padding-inline-start: 0; }
  .exp-col:last-child         { padding-inline-end: 0; }

  .exp-notes {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
  }
  .exp-note                   { padding-inline: var(--space-6); }
  .exp-note + .exp-note       { padding-top: 0;
                                border-top: 0;
                                border-inline-start: var(--hairline) solid var(--border-hairline); }
  .exp-note:first-child       { padding-inline-start: 0; }
  .exp-note:last-child        { padding-inline-end: 0; }
}

/* --------------------------------------------------------------------------
   Entrance stagger, 60ms within the group. .reveal itself lives in base.css;
   this only offsets the members of this section's groups.
   -------------------------------------------------------------------------- */

.exp-col.reveal:nth-child(2) { transition-delay:  60ms; animation-delay:  60ms; }
.exp-col.reveal:nth-child(3) { transition-delay: 120ms; animation-delay: 120ms; }
.exp-col.reveal:nth-child(4) { transition-delay: 180ms; animation-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
  .exp-col.reveal { transition-delay: 0s; animation-delay: 0s; }
}

/* ======================================================
   05-process.css
   ====================================================== */
/* ==========================================================================
   05 — How we work.  Section id="process".
   Class prefix: prc-

   Owns exactly these selectors:
     .prc  .prc-steps  .prc-step  .prc-step-title  .prc-step-body
     .prc-spec  .prc-spec-label  .prc-spec-value
     .prc-terms  .prc-terms-head  .prc-terms-icon  .prc-terms-title
     .prc-terms-list  .prc-term  .prc-term-body  .prc-terms-note
   Uses, never redefines, the shared utilities from base.css:
     .section  .container  .section-head  .eyebrow  .lead  .reveal  .icon

   Treatment: a numbered track. Below 640px it is a vertical timeline with the
   hairline running down the left of the numerals; at 640px and above the track
   turns horizontal — the numeral sits at the head of a hairline that carries a
   blue-to-cyan gradient and runs on through the column gap into the next step.
   The step numerals come from the <ol> counter, never from the markup.
   ========================================================================== */

.prc {
  position: relative;
  background: var(--surface-0);
}

/* --------------------------------------------------------------------------
   The six steps — vertical timeline (mobile default)
   -------------------------------------------------------------------------- */

.prc-steps {
  --prc-num-size: clamp(1.75rem, 1.3rem + 1.9vw, 2.5rem);   /* 28 -> 40 */
  --prc-rail: 2.5rem;
  --prc-col-gap: var(--space-3);
  --prc-row-gap: var(--space-10);

  list-style: none;
  margin: var(--block-gap) 0 0;
  padding: 0;
  counter-reset: prc-step;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--prc-row-gap) var(--prc-col-gap);
}

.prc-step {
  counter-increment: prc-step;
  position: relative;
  min-width: 0;
  display: grid;
  grid-template-columns: var(--prc-rail) minmax(0, 1fr);
  column-gap: var(--space-4);
  align-content: start;
}

/* The numeral. Mono, tabular, --text-brand: raw --brand fails body contrast
   on the raised surfaces this section sits next to. */
.prc-step::before {
  content: counter(prc-step, decimal-leading-zero);
  grid-column: 1;
  grid-row: 1;
  justify-self: center;
  font-family: var(--ff-mono);
  font-size: var(--prc-num-size);
  font-weight: var(--fw-medium);
  line-height: var(--lh-flat);
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-brand);
}

/* The connecting track, running down the rail between the numerals. */
.prc-step::after {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--prc-num-size) + var(--space-3));
  inset-block-end: calc(-1 * var(--prc-row-gap));
  inset-inline-start: calc(var(--prc-rail) / 2 - var(--hairline) / 2);
  inline-size: var(--hairline);
  background-image: linear-gradient(
    180deg,
    color-mix(in srgb, var(--brand) 70%, transparent),
    color-mix(in srgb, var(--cyan) 55%, transparent)
  );
}

.prc-step:last-child::after {
  inset-block-end: var(--space-6);
  background-image: linear-gradient(
    180deg,
    color-mix(in srgb, var(--cyan) 50%, transparent),
    transparent
  );
}

.prc-step > * {
  grid-column: 2;
  min-width: 0;
}

.prc-step-title {
  grid-row: 1;
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
  text-wrap: balance;
}

.prc-step-body {
  margin: var(--space-4) 0 0;
  max-width: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   The Time / You receive block. This is the part of the section no competitor
   publishes; it never gets compressed away.
   -------------------------------------------------------------------------- */

.prc-spec {
  margin: var(--space-5) 0 0;
  padding: var(--space-4);
  background: var(--surface-1);
  border: var(--hairline) solid var(--border-hairline);
  border-radius: var(--radius-sm);
}

.prc-spec-label {
  display: inline-block;
  padding: 0.25em 0.55em;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-brand);
  background: var(--brand-subtle);
  border: var(--hairline) solid var(--border-brand);
  border-radius: var(--radius-xs);
}

.prc-spec-value {
  margin: var(--space-2) 0 0;
  max-width: var(--measure);
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-secondary);
}

.prc-spec-value + .prc-spec-label {
  margin-top: var(--space-4);
}

/* --------------------------------------------------------------------------
   640px — the track turns horizontal, two steps across.
   -------------------------------------------------------------------------- */

@media (min-width: 40em) {
  .prc-steps {
    --prc-col-gap: var(--grid-gap);
    --prc-row-gap: var(--space-12);
    grid-template-columns: repeat(2, minmax(0, 1fr));
    overflow: hidden;                 /* clips the track where it leaves a row */
  }

  /* rows: numeral+track / title / body / spec.
     Each step used to distribute its own slack (grid-template-rows with a 1fr
     body row), which bottom-aligned the spec panels but let their TOPS land up
     to 67px apart — and the top is the edge the eye reads, because the panel
     has a border and a chip just inside it. Row subgrid shares one set of row
     tracks across the whole row of steps, so numeral, title, body and panel
     align on all four edges structurally rather than by coincidence. */
  .prc-steps { grid-auto-rows: auto auto 1fr auto; }

  .prc-step {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto 1fr auto;
    align-content: stretch;
    column-gap: var(--space-4);
  }

  @supports (grid-template-rows: subgrid) {
    .prc-step {
      grid-template-rows: subgrid;
      grid-row: span 4;
      align-content: initial;
    }
  }

  .prc-step::before { justify-self: start; }

  .prc-step::after,
  .prc-step:last-child::after {
    position: static;
    inset: auto;
    grid-column: 2;
    grid-row: 1;
    align-self: center;
    inline-size: auto;
    block-size: var(--hairline);
    margin-inline-end: calc(-1 * var(--prc-col-gap));
    background-image: linear-gradient(
      90deg,
      color-mix(in srgb, var(--brand) 70%, transparent),
      color-mix(in srgb, var(--cyan) 55%, transparent)
    );
  }

  .prc-step > *      { grid-column: 1 / -1; }
  .prc-step-title    { grid-row: auto; margin-top: var(--space-5); }
  .prc-step-body     { font-size: var(--fs-small); line-height: 1.6; }
}

/* --------------------------------------------------------------------------
   1024px — three steps across, two rows.
   -------------------------------------------------------------------------- */

@media (min-width: 64em) {
  .prc-steps {
    --prc-col-gap: var(--grid-gap-lg);
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* --------------------------------------------------------------------------
   NDA, ownership and confidentiality. A bordered panel with real weight —
   this is the section's argument, not a footnote.
   -------------------------------------------------------------------------- */

.prc-terms {
  position: relative;
  overflow: hidden;
  margin-top: var(--block-gap);
  padding: clamp(1.5rem, 0.9167rem + 2.593vw, 3rem);       /* 24 -> 48 */
  background: var(--surface-2);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-lg);
}

/* 1px top-edge highlight. Blue and cyan used as light, not as fill. */
.prc-terms::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: var(--hairline);
  background-image: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--cyan) 85%, transparent) 18%,
    color-mix(in srgb, var(--brand) 85%, transparent) 62%,
    transparent
  );
}

.prc-terms-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.prc-terms-head .prc-terms-icon {
  flex: none;
  inline-size: 1.75rem;
  block-size: 1.75rem;
  color: var(--text-cyan);
}

.prc-terms-title {
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
}

.prc-terms-list {
  margin: var(--space-6) 0 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.prc-term {
  margin: 0;
  padding: var(--space-4) 0 var(--space-1);
  border-top: var(--hairline) solid var(--border-hairline);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  color: var(--text-primary);
}

/* Border on the element so the row rule reaches the panel's content edge;
   reading measure on the text inside it. With both on the dd the rule stopped
   257px short and the panel read as having a dead strip down its right side. */
.prc-term-body {
  margin: 0;
  padding: 0 0 var(--space-4);
  max-width: none;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-secondary);
}
.prc-term-body > span { display: block; max-width: var(--measure); }

/* The border-top is a panel rule and must reach the panel's content edge; the
   reading measure goes on the text, not on the element carrying the border.
   With both on one element the rule stopped 481px short of the panel edge. */
.prc-terms-note {
  margin: 0;
  padding-top: var(--space-5);
  border-top: var(--hairline) solid var(--border-hairline);
  max-width: none;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-muted);
}
.prc-terms-note > span { display: block; max-width: var(--measure); }

@media (min-width: 48em) {
  .prc-terms-list { grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); }

  .prc-term {
    padding: var(--space-4) var(--space-8) var(--space-4) 0;
  }
  .prc-term-body {
    padding: var(--space-4) 0;
    border-top: var(--hairline) solid var(--border-hairline);
  }
  .prc-terms-note { padding-top: var(--space-6); }
}

/* --------------------------------------------------------------------------
   Entrance stagger, 60ms within the group. .reveal itself lives in base.css.
   -------------------------------------------------------------------------- */

.prc-step.reveal:nth-child(2) { transition-delay:  60ms; animation-delay:  60ms; }
.prc-step.reveal:nth-child(3) { transition-delay: 120ms; animation-delay: 120ms; }
.prc-step.reveal:nth-child(4) { transition-delay: 180ms; animation-delay: 180ms; }
.prc-step.reveal:nth-child(5) { transition-delay: 240ms; animation-delay: 240ms; }
.prc-step.reveal:nth-child(6) { transition-delay: 300ms; animation-delay: 300ms; }

@media (prefers-reduced-motion: reduce) {
  .prc-step.reveal { transition-delay: 0s; animation-delay: 0s; }
}

/* ======================================================
   06-cases.css
   ====================================================== */
/* ============================================================================
   06 — CASES  ·  #cases
   Owns the .cas- prefix only. Reads tokens from assets/css/tokens.css and the
   shared utilities (.container .section .section-head .eyebrow .lead .reveal)
   from assets/css/base.css. Redefines none of them.
   ========================================================================== */

.cas {
  position: relative;
}

/* ---------------------------------------------------------------------------
   Placeholder notice — the four cards below are illustrative and this banner
   must be impossible to ship by accident. Warning token, not brand blue.
   --------------------------------------------------------------------------- */
.cas-notice {
  margin-bottom: var(--block-gap);
  padding: var(--space-5) var(--space-6);
  background: var(--warning-subtle);
  border: var(--hairline) solid var(--border-default);
  border-left: 3px solid var(--warning);
  border-radius: var(--radius-sm);
}

.cas-notice__title {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-mono);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--warning);
}

.cas-notice__body p {
  margin: 0 0 var(--space-3);
  max-width: var(--measure);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

.cas-notice__body p:last-child {
  margin-bottom: 0;
}

.cas-notice__body strong {
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}

/* ---------------------------------------------------------------------------
   Grid — one up on phones, two up from 58rem.
   --------------------------------------------------------------------------- */
.cas-grid {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--block-gap);
}

@media (min-width: 58rem) {
  .cas-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }
}

/* ---------------------------------------------------------------------------
   Card — barely elevated, hairline edge, 1px cyan light along the top edge.
   Not a drop-shadowed marketing card.
   --------------------------------------------------------------------------- */
.cas-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 1.1rem + 1.7vw, 2.25rem);
  background: var(--surface-1);
  border: var(--hairline) solid var(--border-hairline);
  border-radius: var(--radius-lg);
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.cas-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: var(--hairline);
  background: linear-gradient(90deg, var(--cyan-ring), transparent 62%);
  opacity: 0.8;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.cas-card:hover {
  border-color: var(--border-default);
  background: var(--surface-2);
}

.cas-card:hover::before {
  opacity: 1;
}

/* Ghosted index, clipped by the card. Technical marking, not decoration. */
.cas-card__index {
  position: absolute;
  top: -0.34em;
  right: 0.06em;
  font-family: var(--ff-display);
  font-weight: var(--fw-bold);
  font-size: clamp(4.5rem, 3rem + 8vw, 8rem);
  line-height: var(--lh-flat);
  letter-spacing: var(--ls-display);
  color: var(--text-primary);
  opacity: 0.05;
  pointer-events: none;
  user-select: none;
}

/* Category tag — the one repeating chip component. Sentence case in the
   markup, uppercased here. */
.cas-tag {
  position: relative;
  align-self: flex-start;
  margin: 0;
  padding: 0.25rem 0.5rem;
  font-family: var(--ff-mono);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-secondary);
  background: var(--surface-3);
  border: var(--hairline) solid var(--border-hairline);
  border-radius: var(--radius-sm);
}

.cas-title {
  position: relative;
  margin: var(--space-4) 0 0;
  max-width: 30ch;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
  overflow-wrap: break-word;
}

/* Challenge / Approach / Result */
.cas-blocks {
  margin: var(--space-6) 0 var(--space-6);
  display: grid;
  gap: var(--space-5);
}

.cas-block {
  display: grid;
  gap: var(--space-2);
}

@media (min-width: 40rem) {
  .cas-block {
    grid-template-columns: 5.75rem minmax(0, 1fr);
    gap: var(--space-4);
  }
}

.cas-label {
  padding-top: 0.3em;
  font-family: var(--ff-mono);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}

.cas-body {
  margin: 0;
  max-width: 62ch;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  overflow-wrap: break-word;
}

/* Protocol and standard names read as machine facts. */
.cas-mono {
  font-family: var(--ff-mono);
  font-size: 0.92em;
  letter-spacing: var(--ls-mono);
  color: var(--text-cyan);
  white-space: nowrap;
}

/* The metric, pulled out at the foot of every card in the display face. */
.cas-metric {
  margin: auto 0 0;
  padding-top: var(--space-5);
  border-top: var(--hairline) solid var(--border-hairline);
  max-width: 52ch;
  font-family: var(--ff-display);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
}

/* Small print under the grid. */
.cas-smallprint {
  margin: var(--space-8) 0 0;
  max-width: var(--measure);
  font-size: var(--fs-micro);
  line-height: var(--lh-body);
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
   Entrance stagger. .reveal itself belongs to base.css; only the delays are
   set here, on this section's own children.
   --------------------------------------------------------------------------- */
.cas-grid > .reveal:nth-child(2) { transition-delay: 60ms; animation-delay: 60ms; }
.cas-grid > .reveal:nth-child(3) { transition-delay: 120ms; animation-delay: 120ms; }
.cas-grid > .reveal:nth-child(4) { transition-delay: 180ms; animation-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
  .cas-grid > .reveal:nth-child(n) {
    transition-delay: 0s;
    animation-delay: 0s;
  }
  .cas-card,
  .cas-card::before {
    transition: none;
  }
}

/* ======================================================
   07-why.css
   ====================================================== */
/* ============================================================================
   07 — WHY US (#why) + TESTIMONIALS (#testimonials)
   Owns the .why- and .tst- prefixes only. Reads tokens from
   assets/css/tokens.css and the shared utilities (.container .section
   .section-head .eyebrow .lead .reveal) from assets/css/base.css.
   Redefines none of them.

   Deliberately quieter than the services and cases grids: no card chrome here,
   just a cyan hairline, a display-face title and the copy. The page needs a
   flat stretch between two dense ones.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   A. Why us
   --------------------------------------------------------------------------- */
.why-list {
  list-style: none;
  margin: var(--block-gap) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-10) var(--space-8);
}

@media (min-width: 44rem) {
  .why-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 66rem) {
  .why-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-12) var(--space-10);
  }
}

/* The only chrome: a short cyan hairline used as light, not as fill. */
.why-item::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: var(--hairline);
  margin-bottom: var(--space-5);
  background: var(--cyan);
  box-shadow: 0 0 10px var(--cyan-ring);
}

.why-title {
  margin: 0;
  max-width: 22ch;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
}

.why-body {
  margin: var(--space-3) 0 0;
  max-width: 46ch;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  overflow-wrap: break-word;
}

/* ---------------------------------------------------------------------------
   B. Testimonials
   --------------------------------------------------------------------------- */

/* Placeholder notice — no invented quote ships without this banner above it. */
.tst-notice {
  margin-bottom: var(--block-gap);
  padding: var(--space-5) var(--space-6);
  background: var(--warning-subtle);
  border: var(--hairline) solid var(--border-default);
  border-left: 3px solid var(--warning);
  border-radius: var(--radius-sm);
}

.tst-notice__title {
  margin: 0 0 var(--space-3);
  font-family: var(--ff-mono);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--warning);
}

.tst-notice__body p {
  margin: 0 0 var(--space-3);
  max-width: var(--measure);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

.tst-notice__body p:last-child {
  margin-bottom: 0;
}

.tst-notice__body strong {
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}

.tst-grid {
  display: grid;
  gap: var(--space-8);
  margin-top: var(--block-gap);
}

/* A table rule above each quote instead of a card, and no quotation-mark
   glyph anywhere: the brand voice rules treat that as template chrome. */
.tst-item {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding-top: var(--space-5);
  border-top: var(--hairline) solid var(--border-strong);
}

.tst-quote {
  flex: 1 1 auto;
  margin: 0;
}

/* Space Grotesk ships 600 and 700 to this page, so 600 is the lightest weight
   available: the quote is lightened with size and leading instead. 1.35 sits
   between --lh-snug (too tight once a quote runs to four lines) and --lh-lead
   (at this size it stops reading as display type). */
.tst-quote p {
  margin: 0;
  max-width: 42ch;
  font-family: var(--ff-display);
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  font-weight: var(--fw-semibold);
  line-height: 1.35;
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
  overflow-wrap: break-word;
}

.tst-attrib {
  margin: var(--space-6) 0 0;
  max-width: 40ch;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
  line-height: var(--lh-lead);
  letter-spacing: var(--ls-mono);
  color: var(--text-muted);
}

@media (min-width: 62rem) {
  .tst-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Three across, the attributions have to start on one line however long the
   quote above them runs, or the row reads as three unrelated blocks. Subgrid
   aligns the two rows across all three figures. Without it the flex column
   above still lays out correctly, it just aligns the attributions on their
   last line instead of their first. Declared last so nothing overrides it. */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 62rem) {
    .tst-grid {
      grid-template-rows: auto auto;
      row-gap: var(--space-6);
    }

    .tst-item {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 2;
    }

    .tst-attrib {
      margin-top: 0;
    }
  }
}


/* ---------------------------------------------------------------------------
   Entrance stagger. .reveal itself belongs to base.css; only the delays are
   set here, on these sections' own children.
   --------------------------------------------------------------------------- */
.why-list > .reveal:nth-child(2) { transition-delay: 60ms;  animation-delay: 60ms; }
.why-list > .reveal:nth-child(3) { transition-delay: 120ms; animation-delay: 120ms; }
.why-list > .reveal:nth-child(4) { transition-delay: 180ms; animation-delay: 180ms; }
.why-list > .reveal:nth-child(5) { transition-delay: 240ms; animation-delay: 240ms; }
.why-list > .reveal:nth-child(6) { transition-delay: 300ms; animation-delay: 300ms; }

.tst-grid > .reveal:nth-child(2) { transition-delay: 60ms;  animation-delay: 60ms; }
.tst-grid > .reveal:nth-child(3) { transition-delay: 120ms; animation-delay: 120ms; }

@media (prefers-reduced-motion: reduce) {
  .why-list > .reveal:nth-child(n),
  .tst-grid > .reveal:nth-child(n) {
    transition-delay: 0s;
    animation-delay: 0s;
  }
}

/* ======================================================
   08-faq.css
   ====================================================== */
/* ==========================================================================
   08 — FAQ  ·  section id="faq"
   Owns the prefix .faq-  (the eyebrow index numeral is base.css's .eyebrow__num).
   Shared utilities used and NOT redefined here:
     .section .container .section-head .eyebrow .reveal .icon
   Colour: tokens only.
   ========================================================================== */

.faq {
  position: relative;
  background-color: var(--surface-0);
}

/* --------------------------------------------------------------------------
   The list. Hairlines only — no card chrome, no shadow, no radius.
   -------------------------------------------------------------------------- */
.faq-list {
  margin-block-start: var(--space-10);
  border-block-start: var(--hairline) solid var(--border-strong);
}

.faq-item {
  --faq-indent: 2.5rem;                 /* index column + its gap */
  position: relative;
  scroll-margin-block-start: calc(var(--header-h) + var(--space-4));
  isolation: isolate;                   /* keeps the row tint behind the text */
  border-block-end: var(--hairline) solid var(--border-hairline);
}

.faq-item:last-child {
  border-block-end: var(--hairline) solid var(--border-strong);
}

/* --------------------------------------------------------------------------
   The trigger row. Padding is identical in both states, so opening the answer
   never moves the question.
   -------------------------------------------------------------------------- */
.faq-summary {
  position: relative;
  display: grid;
  grid-template-columns: var(--faq-indent) minmax(0, 1fr) auto;
  align-items: start;
  column-gap: var(--space-3);
  padding-block: var(--space-5);
  cursor: pointer;
  list-style: none;
}

/* Kill the default marker in every engine. */
.faq-summary::-webkit-details-marker { display: none; }
.faq-summary::marker { content: ""; }

/* Row tint. Bleeds a little past the text on both sides without touching
   layout, so the hover reads as a row and not as a highlighted paragraph. */
.faq-summary::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset-block: 0;
  inset-inline: calc(var(--space-3) * -1);
  background-color: var(--brand-subtle);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.faq-summary:hover::before { opacity: 1; }
.faq-summary:focus-visible { border-radius: var(--radius-sm); }

.faq-idx {
  margin-block-start: 0.5rem;
  font-family: var(--ff-mono);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--ls-mono);
  line-height: var(--lh-flat);
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease-out);
}

.faq-q {
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
  text-wrap: pretty;
}

.faq-chev {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  inline-size: 1.75rem;
  block-size: 1.75rem;
  margin-block-start: 0.125rem;
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  transition:
    transform var(--dur-base) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.faq-chev .icon {
  inline-size: 1rem;
  block-size: 1rem;
}

.faq-summary:hover .faq-chev {
  color: var(--text-primary);
  border-color: var(--border-control);
}

.faq-item[open] > .faq-summary .faq-idx { color: var(--text-cyan); }

.faq-item[open] > .faq-summary .faq-chev {
  transform: rotate(180deg);
  color: var(--text-cyan);
  border-color: var(--border-cyan);
}

/* --------------------------------------------------------------------------
   The answer. Hangs off a cyan hairline, aligned under the question.
   -------------------------------------------------------------------------- */
.faq-panel {
  min-block-size: 0;
  overflow: hidden;
}

.faq-body {
  padding-inline-start: var(--faq-indent);
  padding-block-end: var(--space-6);
}

.faq-a {
  margin: 0;
  max-inline-size: var(--measure);
  padding-inline-start: var(--space-4);
  border-inline-start: var(--hairline) solid var(--border-cyan);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  text-wrap: pretty;
}

/* Real height transition. ::details-content leaves the open/closed state to the
   browser — the closed answer stays out of the tab order and out of the
   accessibility tree — and only animates it. Engines without the pseudo drop
   this block and get the native instant open, which is also correct. */
@supports selector(::details-content) {
  .faq-item::details-content {
    display: grid;
    grid-template-rows: 0fr;
    transition:
      grid-template-rows var(--dur-base) var(--ease-inout),
      content-visibility var(--dur-base) allow-discrete;
  }

  .faq-item[open]::details-content {
    grid-template-rows: 1fr;
  }
}

/* --------------------------------------------------------------------------
   Closing line. Not a seventh item — micro, muted, hung under the list.
   -------------------------------------------------------------------------- */
.faq-note {
  margin-block: var(--space-6) 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-micro);
  line-height: 1.45;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Wider viewports: more air in the row, wider index column.
   -------------------------------------------------------------------------- */
@media (min-width: 48em) {
  .faq-item { --faq-indent: 3.5rem; }

  .faq-summary {
    column-gap: var(--space-4);
    padding-block: var(--space-6);
  }

  .faq-body { padding-block-end: var(--space-8); }
}

/* --------------------------------------------------------------------------
   Reduced motion: no height animation, no rotation sweep. State still changes.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .faq-summary::before,
  .faq-chev,
  .faq-idx {
    transition: none;
  }
}

@supports selector(::details-content) {
  @media (prefers-reduced-motion: reduce) {
    .faq-item::details-content { transition: none; }
  }
}

/* ======================================================
   09-contact.css
   ====================================================== */
/* ==========================================================================
   09 — Contact  ·  section id="contact"
   Owns the prefix .cnt-  (the eyebrow index numeral is base.css's .eyebrow__num).
   Shared utilities used and NOT redefined here:
     .section .container .section-head .eyebrow .lead .btn .btn--primary
     .btn--ghost .btn--lg .reveal .sr-only .icon
   Colour: tokens only. The two url() assets are exposed as custom properties.
   This file now lives at assets/css/, so both resolve as url("../img/…").
   ========================================================================== */

.cnt {
  --cnt-wave:  url("../img/bg-signal-wave.svg");
  --cnt-noise: url("../img/noise.svg");

  position: relative;
  isolation: isolate;
  overflow: hidden;
  scroll-margin-block-start: var(--header-h);
  padding-block-end: calc(var(--section-y) + var(--space-10));
  border-block-start: var(--hairline) solid var(--border-strong);

  /* The page's last and strongest ground: blue bloom off the top-left corner,
     falling through the page ground into the sunken step at the bottom edge. */
  background-color: var(--surface-0);
  background-image:
    radial-gradient(88% 62% at 6% -8%,
      color-mix(in srgb, var(--brand) 20%, transparent) 0%,
      transparent 68%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--brand) 5%, var(--surface-0)) 0%,
      var(--surface-0) 40%,
      var(--surface-sunken) 100%);
}

/* Grain over the gradient — kills the banding, adds no colour. */
.cnt::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background-image: var(--cnt-noise);
  background-repeat: repeat;
  background-size: 240px 240px;
  opacity: 0.035;
  pointer-events: none;
}

/* The scope trace along the bottom edge, faded up into the ground. */
.cnt::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: clamp(150px, 20vw, 300px);
  background-image: var(--cnt-wave);
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: cover;
  opacity: 0.11;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, black 60%);
          mask-image: linear-gradient(180deg, transparent 0%, black 60%);
}

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */
.cnt-grid {
  display: grid;
  /* minmax(0, 1fr), NOT the implicit `auto`. An auto track carries
     min-width: min-content, and .cnt-tg is a .btn (white-space: nowrap) whose
     33-character label has a 390px min-content width — so at 360px the track
     resolved to 390px, every child stretched to 390px, and body{overflow-x:clip}
     silently amputated 50px of the page's only conversion point. Every other
     section already carries this guard. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--block-gap);
  margin-block-start: var(--space-12);
  align-items: start;
}

@media (min-width: 60em) {
  .cnt-grid {
    grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
    gap: var(--grid-gap-lg);
  }
}

.cnt-h3 {
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
}

/* --------------------------------------------------------------------------
   LEFT — direct contact rail
   -------------------------------------------------------------------------- */
.cnt-direct {
  font-style: normal;                 /* <address> defaults to italic */
}

.cnt-tg {
  inline-size: 100%;
  box-shadow: var(--glow-brand);
  /* .btn sets white-space: nowrap, which is right for a short label and wrong
     for this one. Let it wrap rather than dictate the grid's min-content. */
  white-space: normal;
  text-align: center;
}

.cnt-tg .icon {
  inline-size: 1.25rem;
  block-size: 1.25rem;
}

.cnt-help {
  margin-block: var(--space-2) 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-muted);
}

.cnt-help--tg {
  margin-block-start: var(--space-3);
}

.cnt-email {
  margin-block-start: var(--space-8);
  padding-block-start: var(--space-6);
  border-block-start: var(--hairline) solid var(--border-hairline);
}

.cnt-tag {
  margin: 0 0 var(--space-2);
  font-family: var(--ff-mono);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-mono);
  color: var(--text-muted);
}

.cnt-email__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: var(--text-brand);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}

.cnt-email__link .icon {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  flex: none;
}

.cnt-email__link span {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.22em;
  text-decoration-color: color-mix(in srgb, var(--text-brand) 40%, transparent);
  transition: text-decoration-color var(--dur-fast) var(--ease-out);
}

.cnt-email__link:hover span,
.cnt-email__link:focus-visible span {
  text-decoration-color: currentColor;
}

.cnt-response {
  margin-block: var(--space-8) 0;
  padding-block-start: var(--space-6);
  border-block-start: var(--hairline) solid var(--border-hairline);
  max-inline-size: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  text-wrap: pretty;
}

.cnt-include {
  margin-block-start: var(--space-10);
}

.cnt-list {
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-4);
  max-inline-size: var(--measure);
}

.cnt-list__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-3);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
  text-wrap: pretty;
}

.cnt-list__item strong {
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}

.cnt-tick {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  margin-block-start: 0.34em;
  color: var(--text-cyan);
}

.cnt-micro {
  margin-block: var(--space-5) 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-micro);
  line-height: 1.45;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   RIGHT — the written route
   -------------------------------------------------------------------------- */
.cnt-formcol {
  scroll-margin-block-start: calc(var(--header-h) + var(--space-6));
}

.cnt-panel {
  padding: clamp(1.25rem, 0.7rem + 2.4vw, 2rem);
  background-color: var(--surface-1);
  border: var(--hairline) solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}

.cnt-panel__intro {
  margin-block: var(--space-3) 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

/* Failure block — sits above the form, which stays on screen and populated. */
.cnt-alert {
  display: block;
  margin-block-start: var(--space-6);
  padding: var(--space-4) var(--space-5);
  background-color: var(--danger-subtle);
  border: var(--hairline) solid color-mix(in srgb, var(--red) 34%, transparent);
  border-radius: var(--radius-sm);
}

.cnt-alert[hidden] { display: none; }

.cnt-alert__title {
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  color: var(--text-danger);
}

.cnt-alert__body {
  margin-block: var(--space-2) 0;
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-secondary);
}

.cnt-alert__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
}

/* --------------------------------------------------------------------------
   Form
   -------------------------------------------------------------------------- */
.cnt-form {
  position: relative;
  display: grid;
  gap: var(--space-5);
  margin-block-start: var(--space-6);
}

.cnt-legend {
  margin: 0;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.cnt-row {
  display: grid;
  gap: var(--space-5);
}

@media (min-width: 76em) {
  .cnt-row--2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

.cnt-field {
  display: grid;
  gap: var(--space-2);
  align-content: start;
}

.cnt-label {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1.4;
  color: var(--text-primary);
}

.cnt-optional {
  display: inline-block;
  margin-inline-start: var(--space-2);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-mono);
  color: var(--text-muted);
  padding: 0.1em 0.5em;
  border: var(--hairline) solid var(--border-hairline);
  border-radius: var(--radius-pill);
}

.cnt-input {
  inline-size: 100%;
  min-inline-size: 0;
  padding: 0.7rem 0.75rem;
  font-family: var(--ff-body);
  font-size: var(--fs-body);      /* 16px floor: a smaller value zooms iOS */
  line-height: 1.45;
  color: var(--text-primary);
  background-color: var(--surface-sunken);
  border: var(--hairline) solid var(--border-control);
  border-radius: var(--radius-sm);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}

.cnt-input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}

.cnt-input:hover {
  border-color: var(--border-control-hover);
}

.cnt-input[aria-invalid="true"] {
  border-color: var(--text-danger);
}

.cnt-textarea {
  min-block-size: 9.5rem;
  resize: vertical;
}

.cnt-selectwrap {
  position: relative;
  display: grid;
}

.cnt-select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 2.75rem;
  cursor: pointer;
}

/* The native popup is drawn by the OS; give it the surface it belongs on. */
.cnt-select option {
  background-color: var(--surface-3);
  color: var(--text-primary);
}

.cnt-selectwrap__chev {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0.75rem;
  display: flex;
  align-items: center;
  color: var(--text-muted);
  pointer-events: none;
}

.cnt-selectwrap__chev .icon {
  inline-size: 1.125rem;
  block-size: 1.125rem;
}

.cnt-error {
  margin: 0;
  font-size: var(--fs-micro);
  line-height: 1.45;
  color: var(--text-danger);
}

.cnt-error[hidden] { display: none; }

/* Spam trap: clipped, not display:none, out of the tab order. */
.cnt-hp {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

.cnt-submitrow {
  margin-block-start: var(--space-2);
}

.cnt-submit {
  inline-size: 100%;
  justify-content: center;
}

@media (min-width: 40em) {
  .cnt-submit { inline-size: auto; }
}

.cnt-submit[aria-busy="true"] {
  cursor: progress;
}

.cnt-submit__spinner {
  display: none;
  inline-size: 0.9em;
  block-size: 0.9em;
  border: 2px solid color-mix(in srgb, var(--text-inverse) 28%, transparent);
  border-block-start-color: var(--text-inverse);
  border-radius: var(--radius-round);
  animation: cnt-spin 720ms linear infinite;
}

.cnt-submit[aria-busy="true"] .cnt-submit__spinner {
  display: inline-block;
}

@keyframes cnt-spin {
  to { transform: rotate(360deg); }
}

.cnt-consent {
  margin: 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-micro);
  line-height: 1.5;
  color: var(--text-muted);
}

.cnt-consent a {
  color: var(--text-brand);
  text-underline-offset: 0.2em;
}

/* Success block — replaces the form. */
.cnt-ok {
  display: block;
  margin-block-start: var(--space-6);
  padding: var(--space-6);
  background-color: var(--success-subtle);
  border: var(--hairline) solid color-mix(in srgb, var(--success) 30%, transparent);
  border-radius: var(--radius-sm);
}

.cnt-ok[hidden] { display: none; }

.cnt-ok__title {
  margin: 0;
  font-family: var(--ff-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h3);
  color: var(--text-primary);
}

.cnt-ok__body {
  margin-block: var(--space-3) 0;
  max-inline-size: var(--measure);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   Reduced motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .cnt-input,
  .cnt-email__link,
  .cnt-email__link span {
    transition: none;
  }

  .cnt-submit__spinner {
    animation: none;
  }
}


/* ======================================================
   ZZ — CROSS-SECTION RECONCILIATION
   Seams between sections that no single section owns. Everything here was
   written after all nine partials were assembled, which is the only point at
   which these were visible. Keep it last; it is deliberately the only place in
   this file that reaches across section prefixes.
   ====================================================== */

/* --- Phone: 12.3px is a label size, not a prose size ----------------------
   Nine styles resolve to --fs-micro, and several of them are three- and
   four-line paragraphs rather than labels — the footer disclaimer wraps to four
   lines of 12.3px at 360. Genuine labels (eyebrow numerals, chips, .cas-tag,
   .prc-spec-label) keep 12.3px; sentences go up one step to ~14px. */
@media (max-width: 48em) {
  .faq-note,
  .cnt-micro,
  .cnt-consent,
  .svc-boundary,
  .svc-card__quote p {
    font-size: var(--fs-small);
  }
}

/* --- Phone: touch targets ------------------------------------------------
   These were 17px-tall targets at 360. The line box is unchanged; the padding
   is what the finger gets. The matching rule for the shared footer lives in
   base.css beside .site-footer__list, because privacy.html loads base.css but
   not this file, and its footer needs the same target size. */
@media (max-width: 48em) {
  .hero-email,
  .cnt-email__link {
    display: inline-block;
    padding-block: var(--space-2);
  }
  .cnt-email__link { display: inline-flex; }
}


/* ══ Hero photograph ═══════════════════════════════════════════════════════
   Added after the photo shoot replaced the stand-in SVG composition. The frame
   is composed with its subject in the right 45% and clean falloff on the left,
   so it slots under the existing 7/5 grid without moving any type. */
.hero-bg {
  position: absolute;
  inset: 0;
  z-index: -3;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Hold the board in the right column as the viewport narrows. */
  object-position: 78% 50%;
}

/* Pins the left third to the page ground so body and display contrast stay
   exactly the measured token values, then releases across the board and fades
   the bottom edge into section 02. */
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    linear-gradient(90deg,
      var(--surface-0) 0%,
      var(--surface-0) 30%,
      color-mix(in srgb, var(--surface-0) 78%, transparent) 52%,
      color-mix(in srgb, var(--surface-0) 30%, transparent) 72%,
      transparent 88%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--surface-0) 55%, transparent) 0%,
      transparent 18%,
      transparent 62%,
      var(--surface-0) 100%);
}

/* Below the two-column breakpoint the type runs the full width, so the photo
   would sit directly under it. Drop it back to a quiet texture. */
@media (max-width: 63.999em) {
  .hero-bg { object-position: 70% 42%; opacity: 0.5; }
  .hero-scrim {
    background:
      linear-gradient(180deg,
        color-mix(in srgb, var(--surface-0) 72%, transparent) 0%,
        color-mix(in srgb, var(--surface-0) 88%, transparent) 45%,
        var(--surface-0) 92%);
  }
}


/* ══ Contact closing band photograph ═══════════════════════════════════════
   Underneath every existing .cnt layer (bloom, signal wave, noise), pinned to
   the bottom edge and masked upward so it never reaches the form or the copy.
   Low opacity by design: this is ground, not a subject. */
.cnt-photo {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: -4;
  width: 100%;
  height: clamp(14rem, 34%, 26rem);
  object-fit: cover;
  object-position: 50% 42%;
  opacity: 0.34;
  mask-image: linear-gradient(180deg, transparent 0%, #000 46%, #000 82%, transparent 100%);
}

@media (max-width: 47.999em) {
  /* On a phone the form runs nearly the full section, so pull the band right
     down and quieten it further — it must never sit behind an input. */
  .cnt-photo { height: 11rem; opacity: 0.22; }
}

@media (prefers-reduced-motion: no-preference) {
  /* no motion here — declared only to keep this block beside its siblings */
}
