/* ═══════════════════════════════════════════════════════════════════
   ARC — scrollcraft build. One unbroken world: the page is the facility.
   Grammar: continuous descent, centred symmetry, one signal blue.
   Companion to BRIEF.md — change decisions there first.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  /* Components as well as colours. The scrim and the header are this ground at
     partial alpha, and they were written out longhand —
     thirteen copies of rgba(10, 16, 23, …) that a change to --ground would have
     silently left behind. rgb(<components> / <alpha>) has been supported
     everywhere since 2017, so nothing is traded for this. */
  --ground-rgb:   10 16 23;
  --ground-2-rgb: 18 28 38;
  --rule-rgb:     31 46 60;
  --accent-rgb:   59 143 224;

  --ground:   rgb(var(--ground-rgb));
  --ink:      #EDF2F7;
  --ink-2:    #AEBECC;
  --ink-3:    #7E8FA0;
  --rule:     rgb(var(--rule-rgb));
  --accent:   rgb(var(--accent-rgb));

  --sans: "Public Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --serif: "Instrument Serif", Georgia, serif;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* Carried over with the treatment pages when scrollcraft became the site.
     Values are the control's, unchanged, so nothing in those pages shifted by
     a pixel while its shell and its media grammar were replaced. */
  --ease-entrance: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-state:    cubic-bezier(0.4, 0, 0.2, 1);
  --ground-2:      #121C26;
  --s2:            .5rem;
  --s3:            .75rem;
  --s4:            1rem;
  --s5:            1.5rem;
  --s6:            2rem;
  --s7:            2.5rem;
  --s8:            3.5rem;
  --s9:            5rem;
  --step--2:       0.711rem;
  --step--1:       0.8rem;
  --step-1:        1.25rem;
  --step-2:        1.563rem;
  --step-3:        1.953rem;
  --t-small:       220ms;
  --t-media:       720ms;
  --col: 720px;
}

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

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

body {
  background: var(--ground);
  color: var(--ink);
  font: 400 18px/1.65 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img, video { display: block; max-width: 100%; }
a { color: inherit; }

.tnum { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }

.skip {
  position: absolute; left: 16px; top: -72px; z-index: 100;
  background: var(--ink); color: var(--ground);
  padding: 10px 16px; border-radius: 2px; text-decoration: none;
}
.skip:focus { top: 16px; }

/* ─── Reading column ────────────────────────────────────────────── */
.col { max-width: var(--col); margin-inline: auto; padding-inline: 24px; }

h1, h2, h3 { font-weight: 700; line-height: 1.12; letter-spacing: -0.015em; text-wrap: balance; }
h1 em, h2 em { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: 0; }

.sec-lead { color: var(--ink-2); font-size: 1.16rem; max-width: 60ch; }

.btn {
  display: inline-block;
  background: var(--accent); color: var(--ground);
  font: 600 1rem/1 var(--sans);
  padding: 16px 28px; border-radius: 2px;
  text-decoration: none;
  transition: background-color 180ms ease, transform 180ms var(--ease-out);
}
.btn:hover { background: #5AA2E8; }
.btn:active { transform: translateY(1px); }
.btn--lg { padding: 18px 32px; font-size: 1.05rem; }
.btn--sm { padding: 11px 18px; font-size: 0.89rem; }
.cta-row { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }

/* ─── Header — persistent, translucent, carries the one action ──── */
.top {
  position: fixed; inset: 0 0 auto 0; z-index: 40;
  /* 0.95 floor: the white hyperbaric portal passes under this bar while a room
     enters — at lower alpha, composited ink-2 drops below 4.5:1 on that frame */
  background: rgb(var(--ground-rgb) / 0.95);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-bottom: 1px solid rgb(var(--rule-rgb) / 0.6);
}
.top__inner {
  max-width: 1200px; margin-inline: auto;
  display: flex; align-items: center; gap: 20px;
  padding: 10px 24px;
}
/* The real lockup, not a reconstruction. This was the 128px mark beside the
   words "Active Recovery Center" set in Public Sans — close, but not the
   practice's actual wordmark. logo-footer.webp is the artwork itself. */
.brand {
  display: flex; align-items: center;
  text-decoration: none; margin-right: auto;
}
.brand img { height: 34px; width: auto; display: block; }
.top__tel { color: var(--ink-2); text-decoration: none; font-size: 0.95rem; }
.top__tel:hover { color: var(--ink); }

/* ─── Arrival — inside the chamber ──────────────────────────────── */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex; align-items: flex-end;
  overflow: clip;
}
.hero__media, .hero__media picture { position: absolute; inset: 0; }
.hero__media img,
.hero__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.hero__video { opacity: 0; transition: opacity 1200ms ease; }
.hero__video.is-playing { opacity: 1; }
.hero__scrim {
  position: absolute; inset: 0;
  /* Load-bearing: measured at the brightest frame under each line — see verify.mjs.
     Left ramp carries the copy; the bottom anchor dissolves the chamber into the
     page's ground so the world never breaks; the top anchor carries the header. */
  background:
    linear-gradient(to right,
      rgb(var(--ground-rgb) / 0.92) 0%,
      rgb(var(--ground-rgb) / 0.62) 44%,
      rgb(var(--ground-rgb) / 0.16) 100%),
    linear-gradient(to top,
      var(--ground) 0%,
      rgb(var(--ground-rgb) / 0.55) 26%,
      rgb(var(--ground-rgb) / 0.05) 55%,
      rgb(var(--ground-rgb) / 0.55) 100%);
}
@media (orientation: portrait) {
  .hero__scrim {
    /* the portrait cut puts the bright plume and shoe directly beneath the
       type, so the ground has to rise much further up the frame; the chamber
       stays visible through the top half */
    background:
      linear-gradient(rgb(var(--ground-rgb) / 0.25), rgb(var(--ground-rgb) / 0.25)),
      linear-gradient(to top,
        var(--ground) 0%,
        rgb(var(--ground-rgb) / 0.92) 30%,
        rgb(var(--ground-rgb) / 0.9) 52%,
        rgb(var(--ground-rgb) / 0.35) 72%,
        rgb(var(--ground-rgb) / 0.55) 100%);
  }
}
/* Opaque ground over the media only. It sits under .hero__body, so the headline
   — the LCP candidate — is never behind it and paints at full strength from the
   first frame; only the chamber comes up out of the dark. */
.hero__open {
  position: absolute; inset: 0; pointer-events: none;
  background: var(--ground); opacity: 0;
}
.hero__body {
  position: relative; z-index: 1;
  width: 100%; max-width: 1200px; margin-inline: auto;
  padding: 0 24px clamp(88px, 16svh, 168px);
}
.hero h1 { font-size: clamp(2.5rem, 5.6vw, 4.5rem); max-width: 14ch; }
/* each line rises out of its own mask; the padding keeps the italic's descender
   and overhang from being clipped by the very box that does the masking */
.hero h1 .ln { display: block; overflow: hidden; padding-bottom: 0.14em; margin-bottom: -0.14em; }
.hero__lead { color: var(--ink-2); font-size: clamp(1.05rem, 1.4vw, 1.22rem); max-width: 44ch; margin-top: 22px; }
.hero__cta { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; margin-top: 34px; }
.hero__tel { color: var(--ink-2); text-decoration: none; font-size: 1rem; }
.hero__tel:hover { color: var(--ink); }

/* ─── Proof — one quiet reading as the vapour settles ───────────── */
.proof { text-align: center; padding: 118px 24px 30px; }
.proof__score { font: 600 clamp(3.4rem, 6vw, 4.8rem)/1 var(--sans); color: var(--accent); letter-spacing: -0.02em; }
.proof__src { color: var(--ink-2); margin-top: 10px; }
.proof__stack { color: var(--ink-3); font-size: 0.89rem; margin-top: 34px; letter-spacing: 0.02em; }

/* ─── The problem — the held breath ─────────────────────────────── */
.problem {
  min-height: 122svh;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  text-align: center;
  padding: 96px 24px;
}
.problem h2 { font-size: clamp(2.4rem, 5vw, 4rem); }
.problem p { color: var(--ink-2); max-width: 46ch; margin-top: 40px; font-size: 1.16rem; }
.problem .problem__turn { color: var(--ink); margin-top: 28px; font-weight: 600; }

/* ─── Beliefs ───────────────────────────────────────────────────── */
.beliefs { padding: 40px 0 150px; }
.beliefs h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); }
.beliefs__list { list-style: none; margin-top: 72px; display: grid; gap: 64px; }
.belief h3 { font-size: 1.42rem; max-width: 24ch; }
.belief p { color: var(--ink-2); margin-top: 14px; max-width: 58ch; }

/* ─── Protocol — the descent begins ─────────────────────────────── */
.protocol { padding: 108px 0 176px; }
.protocol h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); }
.protocol .sec-lead { margin-top: 20px; }
.phases { list-style: none; margin-top: 80px; position: relative; display: grid; gap: 64px; }
.phases::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 1px; background: var(--rule);
  transform-origin: top;
}
.phase { display: grid; grid-template-columns: 130px 1fr; gap: 24px; padding-left: 32px; }
.phase__when {
  font: 600 0.78rem/1.4 var(--sans);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-3); padding-top: 6px;
  font-variant-numeric: tabular-nums;
}
.phase h3 { font-size: 1.25rem; }
.phase p { color: var(--ink-2); margin-top: 10px; max-width: 52ch; }
.protocol .cta-row { margin-top: 88px; }

/* ─── The rooms — travel through the facility ───────────────────── */
.rooms-intro { padding: 40px 0 26vh; }
.rooms-intro h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); }
.rooms-intro .sec-lead { margin-top: 20px; }

.rooms { position: relative; }
.room {
  position: sticky; top: 0;
  height: 100svh;
  background: var(--ground);
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  overflow: clip;
  /* each room is opaque and later in paint order, so it covers the one before:
     the chamber gives way to the laser room without a seam */
  margin-bottom: 38svh; /* dwell: a room rests fully visible before the next arrives */
}
.room:last-child { margin-bottom: 22svh; }
/* Full bleed. The portal used to sit in the 880px column, which made each room
   a picture ON a page; edge to edge it is the page. The scale factor this costs
   is real and bounded by the sources: the four loops are 1472x800 and the stills
   1792x1008, so a 1440px viewport at 2x is a 2x enlargement of the loops. Going
   wider than the source is the whole reason the old 736x400 encodes looked
   blocky, so the sources were re-cut rather than the CSS asked to hide it. */
.room__portal {
  align-self: end;
  width: 100vw;
  height: min(64svh, 660px);
  margin-top: max(48px, 7svh);
  overflow: hidden;
}
.room__portal { position: relative; }
/* One unbroken world: as the next room rises over this one, this one recedes
   rather than simply being covered. The room's own ground stays fully opaque —
   only its contents dim, so no text is ever composited over other text, and the
   dim does not begin until the caption band is already occluded from below. */
.room__portal, .room__caption {
  position: relative; z-index: 1;
  transform: scale(var(--recede-s, 1)) translateY(var(--recede-y, 0px));
  opacity: var(--recede-o, 1);
}
/* Each room is lit by its own equipment. The colours are not chosen: they are
   sampled from the photographs themselves by scripts/bloom.mjs, which bins the
   high-chroma pixels by hue and takes the strongest bin — averaging across hues
   would return purple for a red handpiece against blue ambient, a colour in
   neither photograph. The halo swells as a room settles and dies as the next
   takes over, and it is centred high and falls to nothing well above the
   caption band, so no body copy is ever read against tinted ground. */
.room::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(56% 33% at 50% 29%,
    rgb(var(--bloom, 59 143 224) / calc(var(--lit, 0) * 0.30)),
    rgb(var(--bloom, 59 143 224) / 0) 72%);
}
.room__portal img,
.room__video { width: 100%; height: 100%; object-fit: cover; }
/* the still is the floor; the loop layers over it and only fades up once playing */
.room__video {
  position: absolute; inset: 0;
  opacity: 0; transition: opacity 900ms ease;
}
.room__video.is-playing { opacity: 1; }
.room__caption {
  width: min(880px, calc(100vw - 48px));
  padding: 26px 0 max(40px, 6svh);
}
.room__spec {
  font: 600 0.78rem/1.4 var(--sans);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-3);
}
.room__caption h3 { font-size: clamp(1.5rem, 2.6vw, 2.1rem); margin-top: 8px; }
.room__caption h3 a { color: inherit; text-decoration: none; }
.room__caption h3 a:hover,
.room__caption h3 a:focus-visible { color: var(--accent); }
.room__caption p { color: var(--ink-2); margin-top: 10px; max-width: 56ch; }

/* ─── Evidence — the drop into silence ──────────────────────────── */
.evidence { padding: 190px 0 176px; }
.evidence h2 { font-size: clamp(2rem, 3.8vw, 3rem); }
.evidence .sec-lead { margin-top: 20px; }
.meter-list { margin-top: 76px; display: grid; gap: 30px; }
.meter { display: grid; grid-template-columns: 130px 1fr; align-items: center; gap: 24px; }
.meter dt {
  font: 600 0.78rem/1.4 var(--sans);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-2);
}
.meter dd { display: flex; align-items: center; gap: 12px; }

/* A 0–10 clinical scale carrying an example course, NOT a progress bar: there
   is no fill and no percentage, just two readings marked on a scale that runs
   the same distance for every row. An earlier draft drew an empty rule with a
   tick at each end, which read as a gauge waiting for a needle — reported twice
   as "supposed to move but doesn't". The honest fix was content, not motion:
   the row now shows where a course starts and where it ends. */
.meter__end { color: var(--ink-3); font-size: 0.78rem; }
.meter__track {
  position: relative; flex: 1; height: 22px;
}
.meter__track::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 1px; margin-top: -0.5px; background: var(--rule);
}
/* the distance travelled, drawn between the two readings */
.meter__span {
  position: absolute; top: 50%; height: 1px; margin-top: -0.5px;
  left: calc(min(var(--from), var(--to)) * 1%);
  width: calc((max(var(--from), var(--to)) - min(var(--from), var(--to))) * 1%);
  background: var(--accent); opacity: .3;
  /* grows from the intake mark toward day 30, so --origin is whichever end
     the course started at: right when a reading falls, left when it rises */
  transform: scaleX(0); transform-origin: var(--origin) 50%;
}
/* intake: a hollow mark, where the course began */
.meter__from {
  position: absolute; top: 50%; left: calc(var(--from) * 1%);
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border: 1px solid var(--ink-3); border-radius: 50%;
  background: var(--ground);
}
/* day 30: the filled reading, which travels from intake to here */
.meter__to {
  position: absolute; top: 50%; left: calc(var(--from) * 1%);
  width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px;
  border-radius: 50%; background: var(--accent);
}
.meter__read {
  color: var(--ink-2); font-size: 0.89rem; min-width: 6.5ch; text-align: right;
}
.meter__read span { color: var(--ink-3); }

.meter-note {
  margin-top: 30px; color: var(--ink-3);
  font-size: 0.89rem; max-width: 54ch;
}

/* The travel. Slower and later than the old hairline draw, because this one
   carries meaning: each reading walks from where it started to where it ended. */
html.js .meter-list.in .meter__to {
  left: calc(var(--to) * 1%);
  transition: left 1400ms var(--ease-out);
}
html.js .meter-list.in .meter__span {
  transform: scaleX(1);
  transition: transform 1400ms var(--ease-out);
}
html.js .meter-list.in .meter:nth-child(1) .meter__to,
html.js .meter-list.in .meter:nth-child(1) .meter__span { transition-delay: 120ms; }
html.js .meter-list.in .meter:nth-child(2) .meter__to,
html.js .meter-list.in .meter:nth-child(2) .meter__span { transition-delay: 320ms; }
html.js .meter-list.in .meter:nth-child(3) .meter__to,
html.js .meter-list.in .meter:nth-child(3) .meter__span { transition-delay: 520ms; }
html.js .meter-list.in .meter:nth-child(4) .meter__to,
html.js .meter-list.in .meter:nth-child(4) .meter__span { transition-delay: 720ms; }

.evidence__method { color: var(--ink-2); margin-top: 64px; max-width: 58ch; }
.evidence .cta-row { margin-top: 84px; }

/* ─── Results — small controlled lift ───────────────────────────── */
.results { padding: 108px 0 150px; }
.results h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); }
.results__proof { color: var(--ink-2); margin-top: 18px; }
.results__proof .tnum { color: var(--accent); font-weight: 600; font-size: 1.3em; }
.quote { margin-top: 56px; padding-left: 28px; border-left: 1px solid var(--rule); }
.quote p { font-size: 1.16rem; color: var(--ink); max-width: 54ch; }
.quote footer { margin-top: 14px; color: var(--ink-3); font-size: 0.95rem; }
.quote cite { font-style: normal; font-weight: 600; color: var(--ink-2); }

/* ─── Team ──────────────────────────────────────────────────────── */
.team { padding: 96px 0 140px; }
.team h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); max-width: 18ch; }
.team__body { margin-top: 40px; max-width: 60ch; }
.team__names { font-weight: 600; color: var(--ink); }
.team__body p + p { margin-top: 20px; color: var(--ink-2); }

/* ─── FAQ ───────────────────────────────────────────────────────── */
.faq { padding: 96px 0 170px; }
.faq h2 { font-size: clamp(1.9rem, 3.6vw, 2.8rem); }
.faq__list { margin-top: 56px; border-top: 1px solid var(--rule); }
.faq__list details { border-bottom: 1px solid var(--rule); }
.faq__list summary {
  cursor: pointer; list-style: none;
  font: 600 1.11rem/1.4 var(--sans);
  padding: 22px 44px 22px 0;
  position: relative;
}
.faq__list summary::-webkit-details-marker { display: none; }
.faq__list summary::after {
  content: "+"; position: absolute; right: 4px; top: 50%;
  transform: translateY(-50%);
  color: var(--ink-3); font-weight: 400; font-size: 1.4rem;
  transition: transform 220ms var(--ease-out), color 220ms ease;
}
.faq__list details[open] summary::after { transform: translateY(-50%) rotate(45deg); color: var(--accent); }
.faq__list summary:hover { color: var(--ink); }
.faq__list details p { color: var(--ink-2); max-width: 60ch; padding: 0 0 26px; }

/* ─── Close — back out of the building ──────────────────────────── */
.close {
  min-height: 108svh;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  text-align: center;
  padding: 140px 24px 120px;
}
.close h2 { font-size: clamp(2.4rem, 5vw, 4rem); }
.close__lead { color: var(--ink-2); max-width: 48ch; margin-top: 36px; font-size: 1.16rem; }
/* The bordered FREE card read as a coupon: display type, three labels, a
   price. This is only the invitation. The visit itself is the dialog, which
   is closed until this is pressed, so nothing covers the hero on first paint.
   Type stays at or above 1rem — the old strip went under the 15px floor. */
.invite {
  margin-top: 48px;
  width: min(36rem, 100%);
  padding: 4px 8px 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: center;
  cursor: pointer;
}
.invite__name {
  display: block;
  font-weight: 700;
  font-size: clamp(1.55rem, 3.2vw, 1.9rem);
  letter-spacing: -0.015em;
  line-height: 1.15;
}
.invite__name em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0;
}
.invite__line {
  display: block;
  margin-top: 14px;
  color: var(--ink-2);
  font-size: 1.05rem;
}
.invite__go {
  display: inline-block;
  margin-top: 16px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--accent);
  color: var(--accent);
  font-weight: 600;
  font-size: 1rem;
}
.invite:hover .invite__go,
.invite:focus-visible .invite__go { color: #5AA2E8; border-bottom-color: #5AA2E8; }
.invite:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; }
.close .cta-row { margin-top: 64px; justify-content: center; }
.close__tel { color: var(--ink-2); text-decoration: none; }
.close__tel:hover { color: var(--ink); }

/* ─── Footer ────────────────────────────────────────────────────── */
.foot { padding: 40px 24px 56px; }
.foot__inner { max-width: var(--col); margin-inline: auto; text-align: center; }
.foot__logo { width: 180px; height: auto; margin-inline: auto; opacity: 0.9; }
.foot__addr { color: var(--ink-2); margin-top: 22px; font-size: 0.95rem; }
.foot__addr a { text-decoration: none; }
.foot__addr a:hover { color: var(--ink); }
.foot__legal { color: var(--ink-3); font-size: 0.84rem; margin-top: 26px; }

/* The fixed visit readout used to live here. Do not put that sticky counter
   back: the phone clearance it needed left with it, and a panel that returns
   without that clearance covers the book button. The free visit is a dialog
   now, and it is not on screen until the invitation opens it. */

/* ─── New Client FREE Experience ──────────────────────────────────
   A dialog, not a coupon. User-agent dialog chrome is a white box with a
   thick border; left alone it would flash that over the dark page the
   moment it opened. Everything visual is set here. It starts closed in
   the markup. showModal puts it in the top layer, above the fixed header,
   which is why it does not need a z-index of its own. */
/* Author `display` beats the user-agent rule that hides a closed dialog.
   Without this, the visit renders in the page flow under the footer and
   the first paint is no longer just the hero. */
.free-visit:not([open]) { display: none; }
.free-visit[open] { display: flex; flex-direction: column; }
.free-visit {
  width: min(40rem, calc(100vw - 32px));
  max-height: calc(100svh - 32px);
  margin: auto;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--ground-2);
  color: var(--ink);
  font: inherit;
  overflow: hidden;
  box-shadow: 0 28px 80px rgb(0 0 0 / 0.5);
}
.free-visit::backdrop {
  background: rgb(var(--ground-rgb) / 0.78);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
/* The form is the height of the dialog and the sheet is the part that
   scrolls, so Close stays on screen on a phone. min-height: 0 is what
   lets a flex child shrink below its content and actually scroll. */
.free-visit__form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  max-height: calc(100svh - 34px);
  margin: 0;
  overflow: hidden;
}
.free-visit__close {
  align-self: flex-end;
  margin: 14px 14px 0;
  padding: 10px 16px;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: transparent;
  color: var(--ink);
  font: 600 1rem/1 var(--sans);
  cursor: pointer;
}
.free-visit__close:hover { border-color: var(--accent); color: var(--accent); }
.free-visit__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.free-visit__sheet {
  overflow: auto;
  min-height: 0;
  padding: 8px 36px 36px;
  text-align: left;
}
.free-visit h2 {
  font-size: clamp(1.8rem, 4vw, 2.35rem);
  max-width: 16ch;
}
.free-visit h2 em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0;
}
.free-visit__lead {
  margin-top: 16px;
  font-size: 1.16rem;
  color: var(--ink);
}
.free-visit__picks {
  list-style: none;
  margin-top: 28px;
  display: grid;
  gap: 0;
}
.free-visit__picks li {
  padding: 18px 0;
  border-top: 1px solid var(--rule);
}
.free-visit__pick {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  font-weight: 600;
  font-size: 1.1rem;
}
.free-visit__pick .tnum {
  color: var(--accent);
  font-weight: 600;
  white-space: nowrap;
}
.free-visit__picks li p + p {
  margin-top: 8px;
  color: var(--ink-2);
  font-size: 1.05rem;
  max-width: 52ch;
}
.free-visit__why {
  margin-top: 8px;
  padding-top: 22px;
  border-top: 1px solid var(--rule);
  font-size: 1.16rem;
  max-width: 38ch;
}
.free-visit__then {
  margin-top: 14px;
  color: var(--ink-2);
  font-size: 1.05rem;
  max-width: 42ch;
}
.free-visit__then .tnum { color: var(--ink); font-weight: 600; }
.free-visit .btn { margin-top: 28px; }
.free-visit .btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
/* No entrance transform. A dialog is centered by the top layer, and a
   transform on it drops that centering — the sheet lands in the corner
   instead of in front of the page. */

/* ─── Entrances (JS-gated; page reads complete without them) ────── */
html.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms var(--ease-out), transform 520ms var(--ease-out);
}
html.js .reveal.in { opacity: 1; transform: none; }

/* ─ Arrival ───────────────────────────────────────────────────────
   The camera settles rather than cutting: the chamber comes up out of the
   dark and drifts to rest over two and a half seconds while the headline
   rises line by line out of its masks and the fixed chrome fades in last.
   Transform and opacity only — nothing here can delay a paint. */
html.js .hero__media img, html.js .hero__video {
  animation: heroin 2600ms var(--ease-out) backwards;
}
html.js .hero__open { animation: heroopen 1700ms var(--ease-out) backwards; }
/* The lift is kept short and undelayed on purpose. A masked line is not painted
   until it clears its mask, so the headline — the LCP element on this page —
   cannot rise for longer than we are willing to wait for it. At 1150ms it cost
   LCP 1596ms against a 196ms baseline; at 720ms it costs 745ms, and the copy
   below no longer fades from zero for the same reason. */
html.js .hero h1 .ln > span { display: block; animation: lift 720ms var(--ease-out) backwards; }
html.js .hero h1 .ln:nth-child(2) > span { animation-delay: 110ms; }
html.js .hero__lead { animation: settle 820ms var(--ease-out) 240ms backwards; }
html.js .hero__cta { animation: settle 820ms var(--ease-out) 360ms backwards; }
/* `backwards` holds the from-keyframe through the delay, so the header stays
   out until it is meant to arrive. `both` would also fill forwards, which is
   harmless on the header and was only forbidden when a readout shared this
   rule and needed to retire. */
html.js .top { animation: chromein 900ms var(--ease-out) 760ms backwards; }
@keyframes heroin { from { transform: scale(1.11); } to { transform: none; } }
@keyframes heroopen { from { opacity: 0.92; } to { opacity: 0; } }
@keyframes lift { from { transform: translateY(108%); } to { transform: none; } }
@keyframes chromein { from { opacity: 0; } to { opacity: 1; } }
@keyframes settle { from { transform: translateY(18px); } to { transform: none; } }

/* ─── Scroll-linked (compositor-only, progressive enhancement) ──── */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .room__portal img {
      animation: roomscale linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 100%;
    }
    .phases::before {
      animation: spinedraw linear both;
      animation-timeline: view();
      animation-range: entry 10% contain 60%;
    }
    .hero__media {
      animation: heroexit linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 100%;
    }
  }
}
@keyframes roomscale { from { transform: scale(1.07); } to { transform: scale(1); } }
@keyframes spinedraw { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes heroexit { from { transform: none; } to { transform: scale(1.05); } }

/* ─── Reduced motion: the designed page, settled ────────────────── */
@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  /* must carry .in to out-specify the travel rule above — a media query adds
     no specificity of its own, so `.meter-list .meter__to` silently loses to
     `.meter-list.in .meter__to` and the reading animates anyway */
  html.js .meter-list.in .meter__to { left: calc(var(--to) * 1%); transition: none; }
  html.js .meter-list.in .meter__span { transform: scaleX(1); transition: none; }
  html.js .hero__lead, html.js .hero__cta { animation: none; }
  .room__portal, .room__caption { transform: none; opacity: 1; }
  .room::before { display: none; }
  html.js .hero__media img, html.js .hero__video,
  html.js .hero__open, html.js .hero h1 .ln > span,
  html.js .top { animation: none; }
  html.js .hero__open { opacity: 0; }
  .hero__video, .room__video { transition: none; }
  .faq__list summary::after { transition: none; }
  .btn { transition: background-color 180ms ease; }
}

/* ─── Phones — most of this practice's traffic ──────────────────── */
@media (max-width: 700px) {
  body { font-size: 17px; }

  .top__tel { display: none; }
  .top__inner { padding: 9px 16px; gap: 12px; }
  .brand img { height: 27px; }

  .hero__body { padding-bottom: 120px; }
  .hero h1 { font-size: clamp(2.2rem, 10vw, 2.9rem); }

  .problem { min-height: 106svh; }

  .phase { grid-template-columns: 1fr; gap: 6px; }
  .meter { grid-template-columns: 1fr; gap: 8px; }
  .meter dd { gap: 9px; }
  .meter__read { font-size: 0.84rem; min-width: 6ch; }
  .phase { padding-left: 24px; }

  .room__portal { height: min(46svh, 420px); width: 100vw; }
  .room__caption { width: calc(100vw - 40px); }

  .free-visit { width: calc(100vw - 24px); }
  .free-visit__sheet { padding: 4px 20px 28px; }
  .free-visit__pick { font-size: 1.05rem; }
}

/* Short phones — a 100svh room still has to fit a portal and three lines of
   caption. On a 700px-tall viewport that does not add up, so the portal
   gives up the room. The old readout strip is not part of this sum anymore. */
@media (max-width: 700px) and (max-height: 760px) {
  .room__portal { height: min(38svh, 340px); margin-top: max(38px, 5svh); }
  .room__caption { padding-top: 18px; }
}

/* ── Ported with the treatment pages ─────────────────────────────
   Labels, readings, the forest plot, the unit block and the session timings,
   lifted from the control's stylesheet unchanged. Only the tokens beneath
   them changed hands.

   Extracted with a brace-aware pass, the second time. A regex that matches
   `selector { body }` cannot see @media blocks: it reads the query's own
   opening brace as the end of a selector, so rules inside a query escape it
   and land at top level, and base rules preceding one get dropped entirely.
   That silently deleted `.ev-row__plot { position: relative }` — which left
   the forest plot's null line positioning against the viewport and drawing a
   1px rule straight down the middle of every hero on the site. ── */
.label {
  margin: 0;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.4;
}
.label--accent { color: var(--accent); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.readout--row { margin-top: var(--s9); }
.reading::before {
  content: ""; position: absolute; inset-inline: 0; top: 0;
  height: 1px; background: var(--rule);
}
.reading dt { margin-bottom: var(--s2); }
.reading__fig {
  margin: 0;
  font-family: "Public Sans", sans-serif;
  font-size: var(--step-3); font-weight: 700; line-height: 1;
  letter-spacing: -0.03em; color: var(--accent);
}
.reading__fig span { font-size: var(--step-1); color: var(--ink-2); }
.reading__fig--text { color: var(--ink); font-size: var(--step-2); }
.readout--band {
  margin-top: var(--s9); padding-top: var(--s7);
  border-top: 1px solid var(--rule);
}
.readout--band .reading { padding-top: 0; }
.readout--band .reading::before { display: none; }
.evidence__grid { display: grid; gap: var(--s9); margin-top: var(--s9); }
.readout--stack .reading { border-top: 1px solid var(--rule); padding-top: var(--s3); min-width: 0; }
.readout--stack .reading__fig--text {
  font-size: var(--step-1); line-height: 1.3; color: var(--ink);
  overflow-wrap: break-word;
}
.dev-sec--lead { padding-block: var(--s9) var(--s7); }
.dev-sec--siblings { padding-block: var(--s9); border-top: 1px solid var(--rule); }
.dev-narrow { max-width: 46rem; }
.dev-note { margin-top: var(--s6); color: var(--ink-2); max-width: 62ch; }
.visit .sec-head { max-width: 46rem; }
.visit__list { margin-top: var(--s8); max-width: 46rem; }
.visit__list--apart { margin-top: var(--s7); }
.visit__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s5); padding: var(--s4) 0; border-bottom: 1px solid var(--rule);
}
.visit__row dt { color: var(--ink); }
.visit__row dt span {
  display: block; margin-top: var(--s2);
  font-size: var(--step--1); color: var(--ink-3);
}
.visit__row dd { color: var(--accent); font-weight: 600; white-space: nowrap; }
.visit__row--sum dt { color: var(--ink-2); }
.visit__row--sum dd { font-size: var(--step-2); }
.visit__note { margin-top: var(--s6); max-width: 62ch; color: var(--ink-2); font-size: var(--step--1); }
.dev-unit__body { margin-top: var(--s6); display: grid; gap: var(--s5); max-width: 62ch; }
.dev-unit__body p { color: var(--ink-2); }
.dev-unit__body em { color: var(--ink); font-style: normal; font-weight: 600; }
.dev-unit__src { margin-top: var(--s7); color: var(--ink-3); font-size: var(--step--1); max-width: 62ch; }
.dev-note + .cta-row { margin-top: var(--s7); }
.dev-shot {
  margin: var(--s7) 0 0;
  overflow: hidden; border-radius: 2px;
}
.dev-shot img {
  width: 100%; border-radius: 2px; border: 1px solid var(--rule);
  aspect-ratio: 16 / 10; object-fit: cover;
}
.dev-siblings a {
  display: grid; gap: var(--s3);
  text-decoration: none; color: inherit;
}
.dev-siblings img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
  border: 1px solid var(--rule); border-radius: 2px;
  transition: transform var(--t-media) var(--ease-entrance);
}
.dev-siblings a:hover img { transform: scale(1.03); }
.dev-siblings__name { font-weight: 600; }
.dev-siblings__spec { color: var(--ink-3); }
.dev-siblings li { overflow: hidden; }
.reading__unit { font-size: .42em; font-weight: 500; letter-spacing: 0; }
.ev__cap { max-width: 60ch; }
.ev__cap h2 { margin: var(--s3) 0 var(--s4); }
.ev__key {
  display: flex; flex-wrap: wrap; gap: var(--s5);
  margin-top: var(--s7); padding-bottom: var(--s4);
  border-bottom: 1px solid var(--rule);
  font-size: var(--step--1); color: var(--ink-3);
}
.ev__key-item { display: inline-flex; align-items: center; gap: var(--s3); }
.ev__key-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); }
.ev__key-bar { width: 30px; height: 2px; background: var(--ink-3); }
.ev__key-null { width: 1px; height: 14px; background: var(--ink-2); }
.ev__rows { list-style: none; margin: 0; padding: 0; }
.ev-row { border-bottom: 1px solid var(--rule); }
.ev-row__hit {
  display: grid; align-items: center; gap: var(--s4);
  grid-template-columns: minmax(11rem, 1.1fr) minmax(8rem, 1.6fr) minmax(6.5rem, auto);
  width: 100%; padding: var(--s5) 0;
  background: none; border: 0; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
  transition: opacity var(--t-small) var(--ease-state);
}
.ev-row__hit:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.ev__rows:hover .ev-row:not(:hover) .ev-row__hit { opacity: .45; }
.ev-row__measure { font-size: var(--step--1); line-height: 1.4; color: var(--ink); }
.ev-row--ns .ev-row__measure { color: var(--ink-2); }
.ev-row__null {
  position: absolute; left: 50%; top: 0; bottom: 0;
  width: 1px; background: var(--ink-2);
}
.ev-row__ci::before,
.ev-row__ci::after {
  content: ""; position: absolute; top: -4px; width: 1px; height: 10px;
  background: var(--ink-3);
}
.ev-row__ci::before { left: 0; }
.ev-row__ci::after { right: 0; }
.ev-row--ns .ev-row__ci,
.ev-row--ns .ev-row__ci::before,
.ev-row--ns .ev-row__ci::after { background: var(--ink-3); opacity: .6; }
.ev-row--ns .ev-row__dot { background: var(--ink-2); }
.ev-row__val {
  font-weight: 600; font-size: var(--step--1); text-align: right;
  display: grid; gap: 2px;
}
.ev-row--ns .ev-row__val { color: var(--ink-2); font-weight: 500; }
.ev-row__ci-text {
  font-weight: 400; font-size: var(--step--2); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.ev__rows.is-drawn .ev-row__dot {
  transform: scale(1);
  transition: transform 420ms var(--ease-entrance);
  transition-delay: calc(var(--i) * 110ms + 620ms);
}
.ev-row__detail {
  padding: 0 0 var(--s5);
  max-width: 62ch; color: var(--ink-2); font-size: var(--step--1);
}
.ev-row__detail p + p { margin-top: var(--s3); }
.ev-row__design { display: flex; flex-wrap: wrap; gap: var(--s4); align-items: center; }
.ev-row__dir { color: var(--ink-3); }
.ev-flag {
  color: var(--ink); background: var(--ground-2);
  border: 1px solid var(--rule); border-radius: 2px;
  padding: 2px 8px; font-size: var(--step--2);
  text-transform: uppercase; letter-spacing: .1em;
}
.ev__scale-note,
.ev__also,
.ev__disclaimer { max-width: 66ch; color: var(--ink-2); font-size: var(--step--1); }
.ev__scale-note { margin-top: var(--s5); color: var(--ink-3); }
.ev__also { margin-top: var(--s6); }
.ev__disclaimer {
  margin-top: var(--s6); padding-top: var(--s5);
  border-top: 1px solid var(--rule); color: var(--ink-3);
}
.ev__src { margin-top: var(--s7); }
.ev__src-meta { color: var(--ink-3); font-size: var(--step--2); display: block; margin-top: 2px; }
.ev__src .srcs li + li { margin-top: var(--s4); }
.ev-table { margin-top: var(--s6); }
.ev-table summary { cursor: pointer; color: var(--ink-2); font-size: var(--step--1); }
.ev-table summary:hover { color: var(--ink); }
.ev-table table { width: 100%; border-collapse: collapse; margin-top: var(--s5); font-size: var(--step--2); }
.ev-table th, .ev-table td { text-align: left; padding: var(--s3) var(--s4) var(--s3) 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
.ev-table thead th { color: var(--ink-3); text-transform: uppercase; letter-spacing: .1em; }
@media (prefers-reduced-motion: reduce) {
  .dev-siblings img { transition: none; }
  .ev-row__ci { transform: scaleX(1); }
  .ev-row__dot { transform: scale(1); }
  .ev__rows.is-drawn .ev-row__ci,
    .ev__rows.is-drawn .ev-row__dot { transition: none; }
  .ev-row__hit { transition: none; }
  .ev__rows:hover .ev-row:not(:hover) .ev-row__hit { opacity: 1; }
}
@media (max-width: 40rem) {
  .ev-row__hit { grid-template-columns: 1fr auto; gap: var(--s3) var(--s4); }
  .ev-row__measure { grid-column: 1 / -1; }
  .ev-row__plot { grid-column: 1; }
  .ev-row__val { grid-column: 2; }
}


/* Base rules the extraction missed on both earlier attempts, recovered by
   diffing the two stylesheets rule-for-rule rather than trusting the parser.
   `.ev-row__plot { position: relative }` is the one that mattered: without it
   the forest plot's null line had no positioning context and drew itself down
   the middle of the viewport, straight through every hero on the site. */
.readout { display: grid; gap: var(--s6); margin: 0; }
.reading { position: relative; padding-top: var(--s3); }
  display: grid; gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.ev { margin: 0; }
.ev-row__plot { position: relative; height: 26px; }
.ev-row__ci { position: absolute; top: 50%; left: var(--left); width: var(--w);
  height: 2px; margin-top: -1px; background: var(--ink-3);
  transform: scaleX(0);
  transform-origin: calc((var(--mid) - var(--left)) / var(--w) * 100%) 50%; }
.ev-row__dot { position: absolute; top: 50%; left: var(--mid);
  width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px;
  border-radius: 50%; background: var(--accent);
  transform: scale(0); }
.ev__rows.is-drawn .ev-row__ci { transform: scaleX(1);
  transition: transform 760ms var(--ease-entrance);
  transition-delay: calc(var(--i) * 110ms + 60ms); }
.ev-row--noci .ev-row__dot { box-shadow: 0 0 0 4px rgb(var(--accent-rgb) / .16); }
@media (min-width: 40rem) {
  .readout--row { grid-template-columns: repeat(3, auto); justify-content: start; gap: var(--s8); }
}

@media (prefers-reduced-motion: reduce) {
  .ev__rows.is-drawn .ev-row__ci,
    .ev__rows.is-drawn .ev-row__dot { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   TREATMENT PAGES
   The six device pages, rebuilt on scrollcraft's shell when it became the
   site. Their content is unchanged — the same verified equipment figures,
   the same forest plot, the same session lengths — but the page is now
   built around its media rather than around its text, with full-bleed
   plates carrying the video and the photographs between every block.
   ═══════════════════════════════════════════════════════════════════ */

.crumb { display: flex; gap: 10px; align-items: center; font-size: 0.86rem; color: var(--ink-3); margin-bottom: 20px; }
.crumb a { color: var(--ink-2); text-decoration: none; }
.crumb a:hover { color: var(--ink); }

/* the hero is the device's own loop, full bleed, exactly as the home page's is */
.hero--device .hero__body { max-width: var(--col); margin-inline: auto; }
.hero--device h1 { font-size: clamp(2.2rem, 5vw, 3.9rem); max-width: 16ch; }
.hero__spec {
  font: 600 0.78rem/1.4 var(--sans);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--accent); margin-bottom: 14px;
}

/* ── The plate: media as the spine of the page ───────────────────
   A full-bleed band that holds a still or a loop. This is the change of
   design the treatment pages were rebuilt for: the old layout set photographs
   inside a text column, so the equipment was an illustration of the copy.
   Here the media is the structure and the copy sits between plates. */
.plate {
  position: relative;
  margin: clamp(72px, 12svh, 132px) 0;
  height: min(78svh, 720px);
  overflow: clip;
  background: var(--ground);
}
.plate img, .plate video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the loop layers over its own still and only fades up once it is playing,
   the same contract the hero and the rooms use */
.plate video { opacity: 0; transition: opacity 900ms ease; }
.plate video.is-playing { opacity: 1; }
.plate__edge {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom,
    rgb(var(--ground-rgb) / .55) 0%,
    rgb(var(--ground-rgb) / 0) 22%,
    rgb(var(--ground-rgb) / 0) 62%,
    rgb(var(--ground-rgb) / .92) 100%);
}
.plate__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 0 24px max(28px, 4svh);
  width: min(var(--col), calc(100vw - 48px)); margin-inline: auto;
}
.plate__cap p { color: var(--ink-2); font-size: 0.95rem; max-width: 52ch; }
.plate__cap .label { color: var(--accent); margin-bottom: 8px; }

/* ── The unit, the evidence, the timings ─────────────────────── */
.dsec { padding: clamp(64px, 9svh, 108px) 0; }
.dsec--tight { padding-block: clamp(40px, 6svh, 72px); }
.dsec h2 { font-size: clamp(1.8rem, 3.4vw, 2.7rem); }
.dsec .sec-lead { margin-top: 18px; }
.dbody { margin-top: 26px; display: grid; gap: 20px; max-width: 62ch; }
.dbody p { color: var(--ink-2); }
.dbody p:first-child { color: var(--ink); font-size: 1.12rem; }
.dbody em { color: var(--ink); font-style: normal; font-weight: 600; }
.dsrc { margin-top: 30px; color: var(--ink-3); font-size: 0.86rem; max-width: 62ch; }
.dsrc a { color: var(--ink-2); }

.dspec { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px 28px; margin-top: 36px; max-width: 46rem; }
.dspec .reading { padding-top: 12px; }

/* ── The other five, as media rather than a list ─────────────── */
.kin { padding-block: clamp(64px, 9svh, 108px); border-top: 1px solid var(--rule); }
.kin__grid { margin-top: 34px; display: grid; gap: 18px; grid-template-columns: 1fr; list-style: none; }
.kin__grid a {
  display: block; position: relative; text-decoration: none;
  height: 190px; overflow: clip; border-radius: 2px; background: var(--ground-2);
}
.kin__grid img { width: 100%; height: 100%; object-fit: cover; opacity: .62; transition: opacity 420ms var(--ease-out), transform 620ms var(--ease-out); }
.kin__grid a:hover img, .kin__grid a:focus-visible img { opacity: .82; transform: scale(1.04); }
.kin__body {
  position: absolute; inset: auto 0 0 0; padding: 18px 20px;
  background: linear-gradient(to top, rgb(var(--ground-rgb) / .92), rgb(var(--ground-rgb) / 0));
}
.kin__name { display: block; color: var(--ink); font-weight: 600; }
.kin__time { display: block; margin-top: 4px; color: var(--accent); font-size: 0.82rem; font-weight: 600; letter-spacing: .04em; }

@media (min-width: 700px) {
  .kin__grid { grid-template-columns: repeat(3, 1fr); }
  .kin__grid a { height: 220px; }
  .dspec { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 700px) {
  .plate { height: min(62svh, 520px); margin: clamp(56px, 9svh, 88px) 0; }
}
@media (prefers-reduced-motion: reduce) {
  .plate video { transition: none; }
  .kin__grid img { transition: none; }
}
