/**
 * app.css · layout + components for the Mould Detect homepage.
 *
 * WHY: tokens.css declares the design language, base.css sets element ground,
 * and this file spends both on structure. Rules of the house (design.md §4,
 * §6, §10): asymmetry is the default, hairlines are the primary structure
 * device, shadows are near-banned, only transform/opacity animate, and every
 * colour and size resolves to a token (locals below are composed from tokens,
 * never from raw values).
 *
 * Order: locals · primitives · reveal · nav · wordmark · buttons · hero ·
 * proof · how-it-works · personas · why · live conditions · cta · footer.
 */

:root {
  /* Locals composed only from tokens, so the scale stays single-sourced. */
  --nav-h: calc(var(--sp-5) + var(--sp-4));       /* 4rem */
  --rise: var(--sp-4);                            /* 24px reveal travel */
}

/* ====================================================================== */
/*  PRIMITIVES                                                            */
/* ====================================================================== */

.shell {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-margin);
}

/* Half padding per section so two adjacent sections total one --section-pad;
   full-bleed bands keep the whole measure because their ground is visible. */
.section {
  padding-block: calc(var(--section-pad) * 0.5);
  scroll-margin-top: var(--nav-h);
  position: relative;
}

.section--band { padding-block: var(--section-pad); }

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

.skip-link {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  z-index: 200;
  transform: translateY(calc(-100% - var(--sp-5)));
  background: var(--surface-0);
  color: var(--ink-0);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease-out);
}

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

/* mono voice: eyebrows, specimen labels, readouts, legal */
.mono {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  line-height: 1.5;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-1);
  margin-block-end: var(--sp-3);
}

.section-head { max-width: 34rem; }

.section-head h2 { margin-block-end: var(--sp-3); }

.lede {
  font-size: var(--text-body-lg);
  color: var(--ink-1);
  max-width: 55ch;
}

.accent-word {
  font-family: var(--font-display);
  font-style: italic;
  color: var(--accent);
}

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

/* ====================================================================== */
/*  REVEAL (IntersectionObserver adds .is-revealed once)                   */
/* ====================================================================== */

.reveal {
  opacity: 0;
  transform: translateY(var(--rise));
  transition: opacity var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
  will-change: opacity, transform;
}

.reveal.is-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
}

.reveal-child {
  opacity: 0;
  transform: translateY(var(--rise));
  transition: opacity var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}

.is-revealed .reveal-child { opacity: 1; transform: none; }
.is-revealed .reveal-child:nth-child(2) { transition-delay: 90ms; }
.is-revealed .reveal-child:nth-child(3) { transition-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal-child,
  .reveal.is-revealed,
  .is-revealed .reveal-child {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ====================================================================== */
/*  NAV                                                                   */
/* ====================================================================== */

#scroll-sentinel {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 1px;
  height: var(--sp-5);                            /* 40px scroll trigger */
  pointer-events: none;
}

.site-header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
}

/* The blurred plate is a pseudo-element, not the header itself: backdrop-filter
   on the header would become the containing block for the fixed mobile panel. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: transparent;
  border-block-end: 1px solid transparent;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.site-header.is-stuck::before {
  background-color: color-mix(in srgb, var(--surface-0) 92%, transparent);
  border-block-end-color: var(--line);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
}

.nav {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--nav-h);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}

.nav__link {
  color: var(--ink-0);
  text-decoration: none;
  font-size: var(--text-small);
  font-weight: 500;
  padding-block: var(--sp-1);
  position: relative;
  /* design.md §6/§10: nav labels never wrap. The bar collapses to the
     hamburger before a label is allowed to break (see the 1180px query). */
  white-space: nowrap;
}

.nav__link::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--dur-fast) var(--ease-out);
}

.nav__link:hover::after,
.nav__link:focus-visible::after { transform: scaleX(1); }

/* The page you are standing on keeps its rule drawn and takes the accent, in
   the bar and in the mobile panel alike. Added with the Specialists and
   Pricing nav items (client direction 2026-08-19): with six links, a visitor
   deserves to see which door they came through. */
.nav__link[aria-current="page"] { color: var(--accent); }
.nav__link[aria-current="page"]::after { transform: scaleX(1); }
.nav__panel a[aria-current="page"] { color: var(--accent); }

.nav__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

/* theme switch ------------------------------------------------------- */
.theme-switch {
  display: grid;
  place-items: center;
  width: var(--sp-5);
  height: var(--sp-5);
  border-radius: var(--r-1);
  border: 1px solid transparent;
  color: var(--ink-0);
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.theme-switch:hover {
  background-color: var(--surface-2);
  border-color: var(--line);
}

.theme-switch svg {
  width: var(--sp-4);
  height: var(--sp-4);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.theme-switch__moon { display: none; }

:root[data-theme="dark"] .theme-switch__sun { display: none; }
:root[data-theme="dark"] .theme-switch__moon { display: block; }

/* hamburger ---------------------------------------------------------- */
.nav__burger {
  display: none;
  width: var(--sp-5);
  height: var(--sp-5);
  /* Pack the three line rows to content height and centre the stack:
     stretched auto rows would spread the lines so the open-state X
     degenerates into a chevron. */
  grid-auto-rows: min-content;
  place-content: center;
  justify-items: center;
  border-radius: var(--r-1);
  border: 1px solid var(--line);
  color: var(--ink-0);
}

.nav__burger span {
  display: block;
  width: var(--sp-4);
  height: 1px;
  background: currentColor;
  transition: transform var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}

.nav__burger span + span { margin-block-start: 5px; }

.nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* mobile panel -------------------------------------------------------- */
.nav__panel {
  position: fixed;
  inset: 0;
  z-index: 1;                 /* below .nav so the burger stays clickable */
  background: var(--surface-0);
  display: grid;
  align-content: center;
  gap: var(--sp-4);
  padding: var(--page-margin);
  opacity: 0;
  transform: translateY(calc(var(--sp-2) * -1));
  pointer-events: none;
  visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out),
              visibility 0s linear var(--dur-fast);
}

.nav__panel.is-open {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  visibility: visible;
  transition-delay: 0s;
}

.nav__panel a {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: 400;
  letter-spacing: var(--track-display);
  color: var(--ink-0);
  text-decoration: none;
  padding-block: var(--sp-2);
  border-block-end: 1px solid var(--line);
}

.nav__panel a:hover { color: var(--accent); }

.nav__panel__utility {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding-block-start: var(--sp-3);
}

.nav__panel__utility .mono { color: var(--ink-2); }

/*
 * Collapse point, moved from 820px to 1180px (client direction 2026-08-19).
 * The bar now carries six primary links (Specialists and Pricing joined it
 * with the audience router), and six labels plus the 185px wordmark, the
 * theme switch and the early-access button need roughly 1110px of shell
 * before anything has to give. Rather than shrink type or wrap a label,
 * which design.md §6 and §10 both forbid, the whole row hands over to the
 * hamburger panel until the width is genuinely there.
 */
@media (max-width: 1179px) {
  .nav__links { display: none; }
  .nav__burger { display: grid; }
  /* The bar keeps only wordmark + CTA + burger; the switch moves to the panel. */
  .nav__actions > .theme-switch { display: none; }
}

@media (min-width: 1180px) {
  .nav__panel { display: none; }
}

/* Between the collapse point and the page-margin cap the shell is at its
   tightest for six links, so the row spends the smaller gap. Above 1280px
   the margins stop growing and the standard rhythm returns. */
@media (min-width: 1180px) and (max-width: 1319px) {
  .nav__links { gap: var(--sp-3); }
}

/* Below 560px the bar is genuinely out of room: shrink the mark and use the
   compact button register so the row never overflows 375px. */
@media (max-width: 559px) {
  .nav { gap: var(--sp-3); }
  .nav .wordmark__img { height: 18px; }
  .nav__actions .btn {
    padding: 10px var(--sp-3);
    font-size: var(--text-mono);
    letter-spacing: 0;
  }
}

/* ====================================================================== */
/*  WORDMARK                                                              */
/* ====================================================================== */

/* PNG lockup pair (client direction 2026-08-15): white artwork for dark
   surfaces, generated forest-ink twin for light. Exactly one is shown per
   theme; the guards mirror tokens.css so a manual choice always wins. */
.wordmark {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.wordmark__img {
  display: block;
  width: auto;
  height: 24px;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.wordmark:hover .wordmark__img { opacity: 0.82; }

.wordmark__img--dark { display: none; }

:root[data-theme="dark"] .wordmark__img--light { display: none; }
:root[data-theme="dark"] .wordmark__img--dark { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .wordmark__img--light { display: none; }
  :root:not([data-theme="light"]) .wordmark__img--dark { display: block; }
}

.wordmark--footer .wordmark__img { height: 30px; }

/* ====================================================================== */
/*  BUTTONS                                                               */
/* ====================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 12px 24px;
  border-radius: var(--r-1);
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.btn--primary {
  background-color: var(--accent);
  color: var(--accent-ink);
}

.btn--primary:hover {
  background-color: var(--accent-deep);
  color: var(--accent-ink);
  transform: translateY(-2px);
}

.btn--secondary {
  border-color: var(--line);
  color: var(--ink-0);
}

.btn--secondary:hover {
  background-color: var(--surface-2);
  color: var(--ink-0);
  transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
  .btn:hover { transform: none; }
}

/* ====================================================================== */
/*  HERO                                                                  */
/* ====================================================================== */

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: calc(var(--nav-h) + var(--sp-4)) var(--sp-5);
  overflow: hidden;
  isolation: isolate;
}

/* Short-and-wide laptops are the hero's real constraint: the fluid display
   token is sized by width, so cap it by height too. Never larger than the
   token, and on phones the token's floor wins, so this is a no-op there. */
.hero__title { font-size: min(var(--text-display), 9.5svh); }

/* Small phones in landscape-ish heights: reclaim the vertical air. */
@media (max-width: 700px) and (max-height: 720px) {
  .hero { padding-block: calc(var(--nav-h) + var(--sp-2)) var(--sp-4); }
  .hero__text { gap: var(--sp-2); }
  .hero__readout { margin-block-start: var(--sp-2); }
}

.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-out);
}

.hero__canvas.is-live { opacity: 1; }

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

.hero__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
}

.hero__text {
  grid-column: 1 / 7;
  max-width: 34rem;
  display: grid;
  gap: var(--sp-3);
}

.hero__eyebrow { color: var(--ink-1); margin: 0; }

.hero__title { margin: 0; }

.hero__standfirst {
  font-size: var(--text-body-lg);
  color: var(--ink-1);
  max-width: 65ch;
}

.hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-block-start: var(--sp-2);
}

.hero__readout {
  color: var(--ink-2);
  margin-block-start: var(--sp-3);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.hero__pulse {
  width: var(--sp-2);
  height: var(--sp-2);
  border-radius: 50%;
  background: var(--accent);
  flex: none;
  animation: md-pulse 2.6s var(--ease-out) infinite;
}

/* WHY animated: the readout is a live instrument; the pulse says "reading". */
@keyframes md-pulse {
  0%, 100% { opacity: 0.35; transform: scale(0.8); }
  50%      { opacity: 1;    transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__pulse { animation: none; opacity: 1; }
}

/* static fallback (reduced motion · no WebGL · low memory) -------------- */
.hero__spores {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.hero__spores span {
  position: absolute;
  opacity: 0.05;
  filter: blur(6px);
}

.hero__spores svg { width: 100%; height: 100%; fill: var(--accent); }

.hero__spores span:nth-child(1) { width: 44vmin; height: 44vmin; inset-block-start: 6%;  inset-inline-end: 4%; }
.hero__spores span:nth-child(2) { width: 30vmin; height: 30vmin; inset-block-end: 12%;   inset-inline-end: 26%; transform: rotate(24deg); }
.hero__spores span:nth-child(3) { width: 20vmin; height: 20vmin; inset-block-start: 46%; inset-inline-end: 40%; transform: rotate(-38deg); }

.hero--static .hero__canvas { display: none; }
.hero--static .hero__spores { display: block; }

.hero--static {
  background-image:
    radial-gradient(70% 60% at 78% 34%,
      color-mix(in srgb, var(--accent) 8%, transparent) 0%,
      color-mix(in srgb, var(--accent) 0%, transparent) 70%),
    radial-gradient(50% 50% at 20% 80%,
      color-mix(in srgb, var(--accent) 6%, transparent) 0%,
      color-mix(in srgb, var(--accent) 0%, transparent) 72%);
  background-color: var(--surface-0);
}

@media (max-width: 900px) {
  .hero__text { grid-column: 1 / -1; }
}

/* ====================================================================== */
/*  PROOF BAND                                                            */
/* ====================================================================== */

.band-deep {
  background-color: var(--accent-deep);
  --band-ink: var(--surface-0);
  --band-ink-soft: color-mix(in srgb, var(--surface-0) 74%, transparent);
  --band-line: color-mix(in srgb, var(--surface-0) 22%, transparent);
  color: var(--band-ink);
}

:root[data-theme="dark"] .band-deep {
  background-color: var(--surface-1);
  --band-ink: var(--ink-0);
  --band-ink-soft: var(--ink-1);
  --band-line: var(--line);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .band-deep {
    background-color: var(--surface-1);
    --band-ink: var(--ink-0);
    --band-ink-soft: var(--ink-1);
    --band-line: var(--line);
  }
}

.proof {
  display: grid;
  grid-template-columns: 1.15fr 1fr 1fr;
  gap: 0;
}

.proof__stat {
  padding-inline: var(--sp-5);
  border-inline-start: 1px solid var(--band-line);
}

.proof__stat:first-child { padding-inline-start: 0; border-inline-start: 0; }

/* Aligned baseline (client direction 2026-08-15: consistency over stagger;
   the band's character comes from asymmetric column widths, not offsets). */

.proof__figure {
  font-family: var(--font-display);
  font-size: var(--text-stat);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
  color: var(--band-ink);
}

.proof__caption {
  color: var(--band-ink-soft);
  margin-block-start: var(--sp-3);
  max-width: 22ch;
  text-transform: none;
  letter-spacing: 0.04em;
}

@media (max-width: 819px) {
  .proof { grid-template-columns: 1fr; }
  .proof__stat {
    padding-inline: 0;
    border-inline-start: 0;
    transform: none;
  }
  .proof__stat + .proof__stat {
    border-block-start: 1px solid var(--band-line);
    padding-block-start: var(--sp-4);
    margin-block-start: var(--sp-4);
  }
}

/* ====================================================================== */
/*  HOW IT WORKS                                                          */
/* ====================================================================== */

.how__motif {
  color: var(--ink-2);
  margin-block-start: var(--sp-4);
  padding-block-start: var(--sp-3);
  border-block-start: 1px solid var(--line);
  max-width: 34rem;
}

.how__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
  align-items: start;
  margin-block-start: var(--sp-6);
}

.how__steps {
  grid-column: 1 / 8;
  display: grid;
  gap: var(--sp-5);
}

/* Client mockup 2026-08-19: the circle sits large, pulled left to col 8,
   and vertically centred against the three steps (so sticky-top yields to
   centring). */
.how__media {
  grid-column: 8 / 13;
  align-self: center;
}

.how__media img {
  /* The artwork carries its own circular alpha mask, so no frame radius —
     and no box-shadow, which would draw a rectangle around the
     transparent box. Percentage width keeps scaling proportional. */
  width: min(100%, 34rem);
  height: auto;
  display: block;
  margin-inline: auto;
}

.how__media figcaption {
  color: var(--ink-2);
  margin-block-start: var(--sp-3);
  text-transform: none;          /* keeps "iOS" cased correctly */
  letter-spacing: 0.04em;
  text-align: center;
}

.step {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-4);
  align-items: start;
}

/* Asymmetric ladder: each step steps further in (design.md §4). */
.step:nth-child(2) { margin-inline-start: var(--sp-5); }
.step:nth-child(3) { margin-inline-start: var(--sp-3); }

.step__num {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: 700;
  color: var(--accent);
  line-height: 1.15;
  padding-block-start: var(--sp-1);
}

.step__title { margin-block-end: var(--sp-2); }

.step__body { color: var(--ink-1); max-width: 46ch; }

@media (max-width: 900px) {
  .how__steps { grid-column: 1 / -1; }
  .how__media {
    grid-column: 1 / -1;
    order: -1;
    justify-self: center;
  }
  /* Proportional on small screens: the circle tracks the viewport width
     between sensible floors and ceilings instead of a fixed box. */
  .how__media img { width: clamp(14rem, 72vw, 24rem); }
  .step:nth-child(2),
  .step:nth-child(3) { margin-inline-start: 0; }
}

/* ====================================================================== */
/*  PERSONAS                                                              */
/* ====================================================================== */

.personas {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
  margin-block-start: var(--sp-6);
  align-items: start;
}

/* ---- bio texture ----------------------------------------------------- */
/* The app's panel texture, ported from the Mould Detect React application
   (Clerk-vite-react-app, src/index.css) at the client's direction,
   2026-08-26: near-white organism silhouettes on a transparent ground,
   tiling. The asset's alpha was reduced by 40% on 2026-08-26 (client:
   "knock the opacity back slightly"), because CSS cannot dim a
   background-image without pseudo-element plumbing; the subtlety is baked
   into the PNG itself, so one factor serves both themes.

   Sprite mapping (client direction 2026-08-26): the 600px tile is treated
   as a sprite sheet, and each numbered class opens a DIFFERENT window into
   it, with a slight per-class tile scale. The app's own offsets all sat on
   one diagonal (10% 10% .. 50% 50%), sixty-pixel hops that left
   neighbouring panels showing the same blobs; these x/y pairs are
   deliberately decorrelated and the sizes break the repeat further, so no
   two panels read alike. Utility, additive, one class per panel: removing
   the class is the whole rollback. Neighbouring panels take different
   numbers; reuse a number only across panels that never sit side by side. */
.bio-bg {
  background-image: url("/assets/bio-bg.png");
  background-repeat: repeat;
}
.bio-bg-10 { background-position: 13% 71%; background-size: 560px; }
.bio-bg-20 { background-position: 47% 9%;  background-size: 620px; }
.bio-bg-30 { background-position: 82% 44%; background-size: 540px; }
.bio-bg-40 { background-position: 25% 33%; background-size: 660px; }
.bio-bg-50 { background-position: 66% 88%; background-size: 580px; }
.bio-bg-60 { background-position: 5% 18%;  background-size: 640px; }
.bio-bg-70 { background-position: 91% 62%; background-size: 600px; }
.bio-bg-80 { background-position: 38% 57%; background-size: 520px; }

.persona {
  position: relative;                    /* ground for the router link overlay */
  background-color: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  padding: var(--sp-5) var(--sp-4);
  display: grid;
  /* photo · label · title · body · router link. The body row takes the slack
     so the five rows stay level across the three cards AND the router links
     sit on one line at the foot of the row (client direction 2026-08-19). */
  grid-template-rows: auto auto auto 1fr auto;
  gap: var(--sp-3);
  transition: border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

/* Aligned and equal-height (client direction 2026-08-15): grid stretch
   keeps the three cards consistent; identity comes from the specimen
   labels and copy, not from vertical offsets. align-content pins each
   card's rows to the top — otherwise the default stretch distributes a
   shorter card's surplus BETWEEN its rows and misaligns the row tops. */
.personas { align-items: stretch; }
.persona { align-content: start; }

.persona:hover { border-color: var(--accent); transform: translateY(-2px); }

/* Supporting photo (client direction 2026-08-18): fixed aspect so the three
   cards stay level; --r-2 matches the card's own corner geometry. */
.persona__photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 694 / 375;
  object-fit: cover;
  border-radius: var(--r-2);
}

.persona__label { color: var(--ink-2); }

/* At three-across, the label row reserves two lines on every card so a
   longer specimen label can wrap without knocking the headings out of
   alignment (client rule 2026-08-15: rows stay level). The title row
   reserves two lines for the same reason (Occupational Hygienists &
   Laboratories wraps where the other titles do not). */
@media (min-width: 901px) {
  .persona__label { min-height: 3em; }
  .persona h3 { min-height: 2.3em; }
}

.persona__body { color: var(--ink-1); }

/* ---- the audience router (client direction 2026-08-19) ----------------- */

/*
 * One card, one destination, one interactive child. The link row is the only
 * anchor in the card; its ::after overlay stretches over the whole card, so
 * the pointer target is the card while the accessible name stays the short
 * mono label. Nothing is nested inside anything interactive, and the focus
 * ring is drawn by outlining the overlay, which means keyboard focus
 * outlines the CARD rather than a two-word label at its foot.
 */
.persona__cta {
  align-self: end;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--accent);
  text-decoration: none;
  padding-block-start: var(--sp-1);
}

.persona__cta::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-2);
}

/* The overlay carries the ring, so focus reads as "this card" (base.css sets
   the 2px accent outline; only the radius needs to match the card here). */
.persona__cta:focus-visible { outline: none; }
.persona__cta:focus-visible::after {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.persona__cta-mark {
  transition: transform var(--dur-fast) var(--ease-out);
}

.persona:hover .persona__cta { color: var(--accent-deep); }
.persona:hover .persona__cta-mark { transform: translateX(3px); }
.persona__cta:hover,
.persona__cta:focus-visible { text-decoration: underline; }

/* The footline under the grid: one quiet mono route to the tier truth. */
.personas__foot {
  margin-block-start: var(--sp-4);
  color: var(--ink-2);
  text-align: center;
}

.personas__foot a {
  color: inherit;
  text-decoration: none;
  border-block-end: 1px solid var(--line);
  padding-block-end: 2px;
}

.personas__foot a:hover,
.personas__foot a:focus-visible {
  color: var(--accent);
  border-block-end-color: var(--accent);
}

@media (max-width: 900px) {
  .personas { grid-template-columns: 1fr; }
  /* Stacked, the cards size to their own copy, so the slack row would only
     add dead space between the body and its router link. */
  .persona { grid-template-rows: none; }
}

@media (prefers-reduced-motion: reduce) {
  .persona,
  .personas .persona:nth-child(2),
  .personas .persona:nth-child(3) { transition: border-color var(--dur-fast) linear; }
  .persona__cta-mark { transition: none; }
  .persona:hover .persona__cta-mark { transform: none; }
}

/* ====================================================================== */
/*  WHY BAND                                                              */
/* ====================================================================== */

.why__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
  align-items: start;
  margin-block-start: var(--sp-6);
}

.why__media {
  grid-column: 1 / 7;
  border-radius: var(--r-3);
  overflow: hidden;
  border: 1px solid var(--line);
  background-color: var(--surface-1);
}

.why__media video {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

.why__claims { grid-column: 8 / 13; }

.claim {
  padding-block: var(--sp-4);
  border-block-start: 1px solid var(--line);
  color: var(--ink-1);
  max-width: 52ch;
}

.claim:first-child { border-block-start: 0; padding-block-start: 0; }

.claim b {
  font-weight: 700;
  color: var(--ink-0);
}

@media (max-width: 900px) {
  .why__media { grid-column: 1 / -1; }
  .why__claims { grid-column: 1 / -1; }
}

/* ====================================================================== */
/*  LIVE CONDITIONS                                                       */
/* ====================================================================== */

.conditions__mount {
  margin-block-start: var(--sp-5);
  min-height: var(--sp-8);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background-color: var(--surface-1);
}

/* ====================================================================== */
/*  FINAL CTA                                                             */
/* ====================================================================== */

.cta {
  background-color: var(--surface-1);
  border-block: 1px solid var(--line);
}

.cta__inner {
  text-align: center;
  display: grid;
  justify-items: center;
  gap: var(--sp-3);
}

.cta__inner p {
  color: var(--ink-1);
  max-width: 48ch;
}

.cta__live {
  width: 100%;
  display: grid;
  justify-items: center;
}

.cta__form {
  display: flex;
  gap: var(--sp-2);
  margin-block-start: var(--sp-3);
  width: 100%;
  max-width: 32rem;
}

.cta__input {
  flex: 1 1 auto;
  min-width: 0;
  background-color: var(--surface-0);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  padding: 12px var(--sp-3);
  color: var(--ink-0);
  font-size: var(--text-small);
}

.cta__input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}

.cta__done {
  color: var(--accent);
  margin-block-start: var(--sp-4);
}

.cta__hp { position: absolute; left: -10000px; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.cta__status {
  color: var(--ink-2);
  margin-block-start: var(--sp-2);
}

@media (max-width: 559px) {
  .cta__form { flex-direction: column; }
  .cta__form .btn { width: 100%; }
}

/* ====================================================================== */
/*  FOOTER                                                                */
/* ====================================================================== */

.footer { border-block-start: 1px solid var(--line); }

.footer__inner {
  padding-block: var(--sp-6) var(--sp-5);
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: var(--sp-5);
  align-items: start;
}

.footer__mission {
  color: var(--ink-1);
  margin-block-start: var(--sp-3);
  max-width: 34ch;
}

.footer__links {
  display: grid;
  gap: var(--sp-2);
  justify-items: start;
}

.footer__links a {
  color: var(--ink-0);
  text-decoration: none;
  font-size: var(--text-small);
}

.footer__links a:hover { color: var(--accent); }

.footer__credit {
  font-size: 0.6875rem;          /* smaller than the legal line (client ask) */
}

.footer__credit a {
  color: inherit;
  text-decoration-color: var(--line);
}

.footer__bottom {
  border-block-start: 1px solid var(--line);
  padding-block: var(--sp-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  justify-content: space-between;
  color: var(--ink-2);
  text-transform: none;          /* the legal line is set as written */
  letter-spacing: 0.04em;
}

@media (max-width: 700px) {
  .footer__inner { grid-template-columns: 1fr; }
  .footer__links { justify-items: start; }
}

/* ====================================================================== */
/*  PHOTO-TO-ACTION FLOW (HowItWorks, below the steps)                    */
/* ====================================================================== */

.flow {
  margin-block-start: var(--sp-6);
  padding-block-start: var(--sp-5);
  border-block-start: 1px solid var(--line);
  display: grid;
  gap: var(--sp-3);
}

.flow__benefit {
  margin: 0;
  font-family: var(--font-display);
  font-size: min(var(--text-h3), 1.35rem);
  font-weight: 700;
  line-height: 1.2;
  color: var(--ink-0);
}

.flow__how {
  margin: 0;
  max-width: 65ch;
  color: var(--ink-1);
}

/* Wide diagram scrolls inside itself; the page never scrolls sideways. */
.flow__scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}

.flow__canvas { min-width: 760px; }

.flow__svg { display: block; width: 100%; height: auto; }

/* Every paint below resolves a token: the diagram themes itself. */
.flow__svg text {
  font-family: var(--font-body);
  font-size: 17px;
  font-weight: 500;
  fill: var(--ink-0);
}

.flow__svg .t-dest { font-weight: 600; }

.flow__svg .t-mono {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.08em;
  fill: var(--ink-1);
}

.flow__svg .t-accent { fill: var(--accent); }

.flow__svg .ph-body   { fill: var(--surface-1); stroke: var(--ink-1); stroke-width: 1.5; }
.flow__svg .ph-screen { fill: var(--surface-2); }
.flow__svg .ph-ring   { fill: none; stroke: var(--accent); stroke-width: 2; }
.flow__svg .ph-dot    { fill: var(--accent); }
.flow__svg .ph-home   { fill: none; stroke: var(--ink-1); stroke-width: 1.5; }

.flow__svg .n-out {
  fill: color-mix(in srgb, var(--accent) 10%, var(--surface-1));
  stroke: color-mix(in srgb, var(--accent) 45%, transparent);
  stroke-width: 1.5;
}

.flow__svg .n-dest { fill: var(--surface-1); stroke: var(--line); stroke-width: 1.5; }

.flow__svg .k-arrow   { fill: none; stroke: var(--accent); stroke-width: 1.75; }
.flow__svg .k-head    { fill: var(--accent); }
/* Bracket joins carry the same accent as the fan curves: one continuous
   flow from readings to destinations, in both themes. */
.flow__svg .k-bracket { fill: none; stroke: var(--accent); stroke-width: 1.5; }

/* Coming-soon stamp on the marketplace card (PhotoToAction). */
.flow__svg .tag { fill: var(--accent); }
.flow__svg .tag__text {
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.12em;
  fill: var(--accent-ink);
}

/* Ecosystem diagram (HowItWorks, below PhotoToAction). */
.flow__svg .eco-grp {
  fill: color-mix(in srgb, var(--surface-1) 55%, transparent);
  stroke: var(--line);
  stroke-width: 1.5;
}

.flow__svg .t-pill { font-size: 16px; }

.flow__svg .eco-app {
  fill: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
  stroke: color-mix(in srgb, var(--accent) 55%, transparent);
  stroke-width: 2;
}

.flow__svg .t-app {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 400;
  fill: var(--ink-0);
}

.flow__svg .eco-live { fill: var(--accent); }

/* The two flow figures each ship two drawings, chosen by width alone (client
   direction 2026-08-17: a diagram must FIT, not crop). Scoped to their own
   wrappers rather than to .flow__scroll, which both wide drawings still use.

   The swap sits at 1100px, which is where the wide drawings stop being
   readable: below it they are squeezed under about 990px of measure and their
   labels fall through 12px, which is worse than the portrait drawings manage
   on a phone. Past their caps the portrait drawings stop growing rather than
   becoming posters.

   width: 100% is load-bearing beside margin-inline: auto. Where one of these
   wrappers is a grid item, an auto inline margin makes it size to its content
   instead of stretching, and for an SVG carrying no width attribute that means
   the replaced-element default of 300px. The explicit width keeps a cap a cap. */
.eco-fit,
.pta-fit {
  display: none;
  width: 100%;
  margin-inline: auto;
}

.eco-fit { max-width: 28rem; }

.pta-fit { max-width: 26rem; }

@media (max-width: 1099px) {
  .eco-desktop,
  .pta-desktop { display: none; }

  .eco-fit,
  .pta-fit { display: block; }
}

/* The portrait drawing's own paint. Its viewBox is 460 units wide, so at the
   350px measure a 390px phone gives the figure a 17-unit mono label lands at
   12.9px and a 34-unit app title at 25.9px. Strokes are thickened in the same
   proportion so no hairline is lost on the way down. */
.flow__svg--eco-fit .t-mono { font-size: 17px; }
.flow__svg--eco-fit .eco-grp { stroke-width: 2; }
.flow__svg--eco-fit .eco-app { stroke-width: 2.5; }
.flow__svg--eco-fit .k-bracket { stroke-width: 2.4; }
.flow__svg--eco-fit .k-arrow { stroke-width: 2.4; }

/* The journey drawing's portrait paint. Its viewBox is 460 units wide, so at
   the 350px measure a 390px phone gives the figure, the 17-unit card labels
   land at 12.9px and the 16.5-unit mono labels at 12.6px. The body text needs
   no override: 17 units is already what .flow__svg text sets, and it happens
   to be exactly the size this viewBox wants. Strokes are thickened in the same
   proportion so no hairline is lost on the way down. */
.flow__svg--pta-fit .t-mono { font-size: 16.5px; }
.flow__svg--pta-fit .tag__text { font-size: 16.5px; }
.flow__svg--pta-fit .n-out { stroke-width: 2; }
.flow__svg--pta-fit .n-dest { stroke-width: 2; }
.flow__svg--pta-fit .k-arrow { stroke-width: 2.4; }
.flow__svg--pta-fit .k-bracket { stroke-width: 2.4; }
.flow__svg--pta-fit .ph-body { stroke-width: 2; }
.flow__svg--pta-fit .ph-ring { stroke-width: 2.6; }
.flow__svg--pta-fit .ph-home { stroke-width: 2; }

.eco__stats {
  list-style: none;
  margin: 0;
  padding: var(--sp-3) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-5);
  border-block-start: 1px solid var(--line);
}

.eco__stat {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
}

.eco__num {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--accent-deep);
}

:root[data-theme="dark"] .eco__num { color: var(--accent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .eco__num { color: var(--accent); }
}

.eco__text {
  font-family: var(--font-mono);
  font-size: var(--text-mono);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-1);
}

/* Stats strip title (Ecosystem): the hairline moves up to the title so the
   strip reads as one captioned block. */
.eco__stats-title {
  margin: var(--sp-2) 0 0;
  padding-block-start: var(--sp-3);
  border-block-start: 1px solid var(--line);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--ink-0);
}

.eco .eco__stats {
  border-block-start: none;
  padding-block-start: var(--sp-2);
}

/* Partner logos in the Ecosystem app card: Cloud Assembly's ink artwork
   swaps for its bone twin on dark surfaces (same pattern as the wordmark). */
.flow__svg .eco-logo--dark { display: none; }
:root[data-theme="dark"] .flow__svg .eco-logo--light { display: none; }
:root[data-theme="dark"] .flow__svg .eco-logo--dark { display: inline; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .flow__svg .eco-logo--light { display: none; }
  :root:not([data-theme="light"]) .flow__svg .eco-logo--dark { display: inline; }
}

/* Inside-the-app showcase (HowItWorks, between flow diagram and ecosystem). */
.inside__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--sp-5);
  align-items: start;
}

.inside__card {
  margin: 0;
  display: grid;
  gap: var(--sp-3);
  align-content: start;
}

.inside__lead {
  margin: 0;
  font-weight: 700;
  color: var(--ink-0);
}

.inside__body {
  margin: 0;
  color: var(--ink-1);
  max-width: 48ch;
}

.inside__card img {
  width: 100%;
  height: auto;
  max-width: 34rem;
  border-radius: var(--r-3);
  border: 1px solid var(--line);
  background-color: var(--surface-1);
  box-shadow: var(--shadow-1);
}

.inside__caption { color: var(--ink-1); }

@media (max-width: 820px) {
  .inside__grid { grid-template-columns: 1fr; }
}

/* Screens whose artwork carries its own card get no CSS frame on top. */
.inside__card--bare img {
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}

/* ====================================================================== */
/*  VISION BAND (AI Vision promo · docs/ai-vision-brief.md §2)            */
/* ====================================================================== */

/* Asymmetric text (design.md §4): the copy keeps cols 1-7 and its short
   measure, and the diagram takes the full twelve beneath it. The band's figure
   is the article's real topology (client direction 2026-08-17), which is a wide
   drawing: squeezed into a five-column side well its labels stop being legible,
   so it gets a row of its own rather than a column. */
.vision__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gutter);
  align-items: start;
}

/* min-width: 0 on every track (design.md §10 ship gate). A grid item defaults
   to min-width: auto, so anything wide inside one can push its track past the
   viewport and carry the whole band sideways with it. The floor makes the
   tracks obey the grid instead of their contents. */
.vision__text,
.vision__diagram,
.vision__ctas { min-width: 0; }

.vision__text { grid-column: 1 / 8; }

.vision__text h2 { margin-block-end: var(--sp-3); }

/* The how-to-read line comes BEFORE the motif (design.md §6 panel anatomy):
   the reader is told what they are looking at before they are asked to look. */
.vision__how {
  color: var(--ink-0);
  max-width: 46ch;
  margin-block-end: var(--sp-3);
}

.vision__body {
  color: var(--ink-1);
  max-width: 52ch;
}

/* The band's closing element (client direction 2026-08-17): the reader gets the
   promise, then the drawing, and only then the two ways onward. A full-measure
   row of its own, below the framed diagram, still wrapping to two lines when
   the measure runs out. */
.vision__ctas {
  grid-column: 1 / -1;
  margin-block-start: var(--sp-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
}

.vision__link {
  color: var(--accent);
  font-size: var(--text-small);
  font-weight: 500;
  text-decoration: none;
  border-block-end: 1px solid var(--line);
  padding-block-end: 2px;
  transition: border-color var(--dur-fast) var(--ease-out);
}

.vision__link:hover { border-block-end-color: var(--accent); }

/* Full width, one row below the text. A card in the design.md §6 sense:
   hairline, --r-2, surface-1, no shadow. */
.vision__diagram {
  grid-column: 1 / -1;
  margin-block-start: var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background-color: var(--surface-1);
  padding: var(--sp-4);
}

/* Two renderings of one drawing, chosen by width alone: the wide one above
   1100px, the compact portrait one below it. No listener, no measurement, no
   JavaScript (design.md §9). The hidden variant is display:none, so it leaves
   the accessibility tree too and the description is announced once.

   The swap sits at 1100px, not at the band's own 860px stacking break, because
   the wide drawing needs close to the full page measure to stay readable: at
   860px it has 774px and its labels fall to 9.8px, at 1024px it has 922px and
   they reach only 11.7px. Both are worse than the compact drawing manages on a
   phone, so the compact drawing keeps the whole tablet range.

   The compact drawing is drawn for a phone, so past a certain width it stops
   growing rather than becoming a poster: capped at 32rem its answer labels sit
   at 15px, close to the wide drawing's own 14px at full measure. */
.net-fit {
  display: none;
  width: 100%;
  max-width: 32rem;
  margin-inline: auto;
}

.vision__diagram .net__svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The topology's paint. These rules exist twice by necessity: content.css owns
   them for the /ai-vision/ article, and the homepage does not load content.css.
   Scoped to the band so the two copies can never collide. Identical rules,
   identical tokens, not one literal colour. */
.vision__diagram .net__svg .k-edge { fill: none; stroke: var(--line); stroke-width: 1; }

/* The single lit path: one decision travelling input to answer. */
.vision__diagram .net__svg .k-lit { fill: none; stroke: var(--accent); stroke-width: 2.25; }

.vision__diagram .net__svg .n-node {
  fill: var(--surface-1);
  stroke: var(--ink-2);
  stroke-width: 1.5;
}

.vision__diagram .net__svg .n-lit {
  fill: color-mix(in srgb, var(--accent) 22%, var(--surface-1));
  stroke: var(--accent);
  stroke-width: 2.25;
}

.vision__diagram .net__svg .n-ellipsis { fill: var(--ink-2); }

.vision__diagram .net__svg .t-out {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0.08em;
  fill: var(--ink-0);
}

/* The lit row is emphasised by weight, never by colour: label text wears ink
   tokens only, and the accent stays a mark. */
.vision__diagram .net__svg .t-out--lit { font-weight: 500; }

.vision__diagram .net__svg .t-foot {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.08em;
  fill: var(--ink-2);
}

/* Under 860px the copy takes the full measure; the diagram already does, so
   the twelve columns have nothing left to divide. Collapsing them to one is
   not cosmetic: eleven column gaps of --sp-5 come to 440px, which is wider
   than the whole 350px measure a 390px phone offers, and the band was being
   dragged sideways by its own gutters. One track, and the gap becomes what it
   was always meant to be here, the space between the copy and the drawing. */
@media (max-width: 859px) {
  .vision__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-5);
  }

  .vision__text,
  .vision__diagram,
  .vision__ctas { grid-column: 1 / -1; }
}

/* The compact rendering's own paint. Larger type and heavier strokes are not a
   style choice: inside this frame at a 390px viewport the drawing is shown at
   316/580 of its own units, so a 17-unit answer label lands at 9.3px, a
   16-unit foot label at 8.7px, and a 2.2-unit mesh line at 1.2px. Anything
   lighter would disappear on the way down. */
.vision__diagram .net__svg--fit .k-edge { stroke-width: 2.2; }
.vision__diagram .net__svg--fit .k-lit { stroke-width: 3.2; }
.vision__diagram .net__svg--fit .n-node { stroke-width: 2; }
.vision__diagram .net__svg--fit .n-lit { stroke-width: 3; }
.vision__diagram .net__svg--fit .t-out { font-size: 17px; letter-spacing: 0.06em; }
.vision__diagram .net__svg--fit .t-foot { font-size: 16px; }

/* Below 1100px the wide drawing steps aside for the compact one, which fits the
   viewport whole. Nothing scrolls sideways: not the band, not the frame, not
   the page (client direction 2026-08-17, replacing the earlier scroller). */
@media (max-width: 1099px) {
  .net-desktop { display: none; }
  .net-fit { display: block; }
}

/* The frame tightens once the band has stacked, which is its own break. */
@media (max-width: 859px) {
  .vision__diagram { padding: var(--sp-3); }
}

/* ====================================================================== */
/*  ORGANIC LAYER (experiment, client direction 2026-08-19)               */
/*  Earthy wave strata around the full-bleed bands + organic specimen     */
/*  cutouts at the page margins. All colour comes from theme tokens, so   */
/*  the layer follows both themes and every daypart untouched.            */
/* ====================================================================== */

.wave { line-height: 0; pointer-events: none; }

.wave svg {
  display: block;
  width: 100%;
  height: clamp(2.5rem, 6vw, 4.5rem);
}

.wave--flip svg { transform: scaleY(-1); }

/* The deep wave mirrors .band-deep's theme behaviour exactly: canopy in
   light, moss-shadow surface in dark. */
.wave--deep { color: var(--accent-deep); }

:root[data-theme="dark"] .wave--deep { color: var(--surface-1); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .wave--deep { color: var(--surface-1); }
}

.wave--soft { color: var(--surface-1); }

/* The waves ARE the band's edges now, so the band's own hairlines would
   read as seams through them. Applies to every surface-1 band anatomy
   sitewide (.cta, the content pages' .help-band, learn's .miss). */
.wave--soft + .cta,
.wave--soft + .help-band,
.wave--soft + .miss { border-block-start: 0; }

.cta:has(+ .wave--soft),
.help-band:has(+ .wave--soft),
.miss:has(+ .wave--soft) { border-block-end: 0; }

/* Hero base: the page ground laps over the organism's bottom edge. Kept
   shallow so it never reaches the hero's trust line, and z-index 0 so it
   paints over the canvas but under the copy (.hero__inner is z1). */
.wave--ground { color: var(--surface-0); }

.wave--hero {
  position: absolute;
  inset-inline: 0;
  bottom: -1px;
  z-index: 0;
}

.wave--hero svg { height: clamp(1.5rem, 2.5vw, 2.5rem); }

/* ---------------------------------------------------- contour motif ---- */

/* Survey contours: the field-instrument's map register, scattered down both
   page edges (client direction 2026-08-19). Ground, not content; margin
   space only. Three colour gradings: hairline (default), moss-tinted, and
   band-ink for the dark band. Rotation and mirroring vary the three base
   shapes so no two instances read alike. */
.contour {
  position: absolute;
  z-index: -1;
  aspect-ratio: 1;
  color: var(--line);
  pointer-events: none;
}

.contour svg { display: block; width: 100%; height: 100%; }

.contour--how {
  top: var(--sp-4);
  right: -5rem;
  width: clamp(18rem, 26vw, 26rem);
}

/* The overlapping pair: c laps under b's smaller moss-tinted rings. */
.contour--how-left {
  bottom: -2rem;
  left: -7rem;
  width: clamp(12rem, 16vw, 16rem);
  transform: rotate(18deg);
  opacity: 0.75;
}

.contour--how-left-2 {
  bottom: 3rem;
  left: 2.5rem;
  width: clamp(8rem, 10vw, 10rem);
  color: color-mix(in srgb, var(--accent) 38%, var(--surface-0));
  transform: rotate(-30deg);
}

/* On the deep band: bone-ink rings at whisper opacity, the reference-image
   register. z 0 because the band paints its own ground; the shell lifts. */
.contour--proof {
  z-index: 0;
  top: 1.5rem;
  left: -5rem;
  width: clamp(20rem, 28vw, 28rem);
  color: var(--band-ink);
  opacity: 0.12;
  transform: scaleX(-1) rotate(-14deg);
}

.band-deep { overflow: clip; }

.band-deep > .shell {
  position: relative;
  z-index: 1;
}

.contour--personas {
  bottom: calc(var(--sp-6) - 2.5rem);
  left: -6rem;
  width: clamp(13rem, 17vw, 17rem);
  color: color-mix(in srgb, var(--accent) 40%, var(--surface-0));
  transform: scaleX(-1) rotate(8deg);
}

.contour--why {
  bottom: -3rem;
  right: -6.5rem;
  width: clamp(13rem, 17vw, 17rem);
  transform: rotate(24deg);
  opacity: 0.8;
}

.contour--vision {
  top: 34%;
  left: -5.5rem;
  width: clamp(10rem, 13vw, 13rem);
  transform: rotate(-22deg);
  opacity: 0.85;
}

/* Generic edge placements for the sub-pages (top-right, mid-left,
   mid-right, bottom-left): same vocabulary, reusable anywhere a section
   has true margin. All hidden below 1100px by the blanket rule. */
.contour--tr {
  top: var(--sp-5);
  right: -5rem;
  width: clamp(14rem, 20vw, 20rem);
}

.contour--ml {
  top: 38%;
  left: -5.5rem;
  width: clamp(11rem, 15vw, 15rem);
  transform: scaleX(-1) rotate(14deg);
  opacity: 0.85;
}

.contour--mr {
  top: 30%;
  right: -6rem;
  width: clamp(12rem, 16vw, 16rem);
  transform: rotate(-18deg);
  opacity: 0.8;
}

.contour--bl {
  bottom: -2.5rem;
  left: -6.5rem;
  width: clamp(12rem, 16vw, 16rem);
  transform: rotate(22deg);
  opacity: 0.75;
}

/* Purely decorative (client direction 2026-08-19), so most contours yield
   to content on small screens. Two survive where empty ground exists —
   the deep band and the why band's closing corner — resized against the
   viewport and pushed further off-canvas so only arcs show at the edge. */
@media (max-width: 1099px) {
  .contour { display: none; }

  .contour--proof,
  .contour--why { display: block; }

  .contour--proof {
    width: clamp(13rem, 52vw, 20rem);
    left: -6rem;
  }

  .contour--why {
    width: clamp(11rem, 42vw, 16rem);
    right: -6rem;
    bottom: -2rem;
    opacity: 0.6;
  }
}

/* --------------------------------------------------------- cutouts ---- */

/* (The photo cutouts were tried and rolled back, client direction
   2026-08-19: the personas/CTA magnifier crops read too loud as page-edge
   decoration, and the vision-band pebble mask never resolved because the
   template engine cannot author SVG clipPath nodes. The team portrait now
   lives as the how-it-works media figure instead.) */

/* (The solid blobs were rolled back too, client direction 2026-08-19:
   filled shapes fought the hairline register. The surviving organic layer
   is waves + contour rings — and the fallen-leaf drift below.) */

/* ------------------------------------------------------ leaf drift ---- */

/* Leaf glyph by Maria Karina Putri, Noun Project (CC BY 3.0), credited in
   the footer. Three muted autumnal tints — a client-directed pictorial
   exception to the one-accent rule (§2): foliage colour only, never UI or
   data colour. Mixing toward --surface-0 keeps each tint native to both
   themes. Per-placement custom props carry position, rotation, scale,
   tint and opacity, so each leaf reads individually "fallen". */
.leaf {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  width: var(--leaf-size, 3rem);
  aspect-ratio: 1;
  opacity: var(--leaf-alpha, 0.7);
  transform: rotate(var(--leaf-rot, 0deg));
  color: var(--leaf-tint, var(--accent));
}

.leaf svg { display: block; width: 100%; height: 100%; }

/* Cluster anchors (contents are generated — see LeafCluster in
   OrganicWaves.js; tints live there too). The wrapper is a zero-size
   origin; leaves position themselves around it, and the gust direction is
   chosen per anchor so the drift follows empty ground. */
.leaf-cluster {
  position: absolute;
  z-index: -1;
  pointer-events: none;
}

/* The how cluster hugs the top-left gutter, above the headline and mostly
   off-canvas, so it never sits under copy (client legibility direction
   2026-08-19). */
.leaf-cluster--how { top: 0.5rem; left: -2.2rem; }
.leaf-cluster--personas { top: 2.5rem; right: 8vw; }
.leaf-cluster--why { bottom: 3rem; left: -0.5rem; }
.leaf-cluster--vision { top: 18%; right: 6vw; }

/* Anchored inside the "Inside the app" block's bottom-left corner. */
.inside { position: relative; }
.leaf-cluster--inside { bottom: 0.5rem; left: -1.5rem; }

/* Generic corner anchors for the sub-pages (same idea as the contour
   placements): gutters and corners only, drift direction chosen per call
   so gusts travel along empty ground. */
.leaf-cluster--tl { top: 1rem; left: -2rem; }
.leaf-cluster--tr { top: 1.5rem; right: 2vw; }
.leaf-cluster--bl { bottom: 2rem; left: -1.5rem; }
.leaf-cluster--br { bottom: 2.5rem; right: 3vw; }

/* Leaves are small enough to keep on mobile; the scatter just thins so
   the single-column layout stays calm. */
@media (max-width: 759px) {
  .leaf-cluster--personas,
  .leaf-cluster--vision,
  .leaf-cluster--tr,
  .leaf-cluster--br { display: none; }
}
