/* ==========================================================================
   Composed page sections.
   ========================================================================== */

/* --- Hero -----------------------------------------------------------------
 * Layered back to front: painted gradient, the practice's own footage, the
 * contrast scrim, grain, content.
 *
 * The gradient underneath is not a placeholder — it is what a visitor sees
 * whenever the loop is withheld (reduced motion, Save-Data, a slow connection,
 * a low-memory device, no JavaScript), and behind the video's own poster frame
 * while it buffers. Removing the video from this stack at any layer still
 * leaves a finished hero.
 * -------------------------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  /*
   * 52rem was 832px, which on the common 900px window left a band of the next
   * section showing above the fold and made the whole opening read as short and
   * wide — 2.3:1 on an ultrawide monitor. The hero now takes the viewport it is
   * given, capped so a very tall window does not get an absurd one.
   */
  min-height: min(100svh, 62rem);
  /* --s-xl above, not --s-2xl. The header is fixed and overlays the hero, so the
     first number only has to clear it; 5rem of additional air on top of that was
     24px the composition could not spare once the credential plane had to fit
     above the fold as well. */
  padding-block: calc(var(--header-h) + var(--s-xl)) var(--s-2xl);
  overflow: clip;
  background: oklch(0.148 0.058 264);
}

.hero__stage {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.hero__poster {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 78% 18%,
      oklch(0.44 0.10 88 / 0.42) 0%,
      transparent 55%),
    radial-gradient(90% 80% at 18% 82%,
      oklch(0.42 0.09 235 / 0.34) 0%,
      transparent 58%),
    radial-gradient(70% 60% at 55% 45%,
      oklch(0.30 0.09 264) 0%,
      oklch(0.148 0.058 264) 70%),
    oklch(0.148 0.058 264);
}

/*
 * The still and the loop occupy the same box, and neither fades.
 *
 * These rules once carried the aurora's `opacity: 0` until JavaScript added
 * `is-live`. Inherited by the video that replaced it, that was a real bug: the
 * fallback frame only rendered through that element, so every visitor who never
 * got the loop — no JavaScript, reduced motion, Save-Data, a slow connection —
 * was shown an invisible video over a bare gradient while the template claimed
 * they were being shown the practice.
 *
 * Now the still is its own <img> and is simply always visible; the video is
 * inserted above it and paints over it. No cross-fade is needed in either
 * direction, because the still IS frame zero of the loop (scripts/build_video.py
 * cuts it from the encode) — the swap is between two identical images.
 */
.hero__still,
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
 * The scrim, and why these numbers are what they are.
 *
 * This is the only part of the site where type sits over footage we do not
 * control frame to frame, and the loop cuts between a dim corridor and a
 * sunlit reception desk — so the scrim has to hold against the BRIGHTEST
 * frame at every position, not the average one.
 *
 * It is now SYMMETRIC, because the composition is centred. It used to be a
 * two-part wash — heavy left where the copy sat, thinning to 0.18 on the right
 * so the footage read as a window. Centring inverts that completely: the type
 * moved onto the middle of the frame, which is the brightest part of every
 * shot in the loop (white walls, measured up to Y 0.777), and the old gradient
 * was at its lightest exactly there.
 *
 * scripts/hero_scrim.py models the composite and puts the binding requirement
 * at alpha 0.67 for the lead. The first centred version overshot badly — it
 * measured 12.7:1 where 5.5 is the gate, ground luminance 0.026, which is very
 * nearly flat navy with the practice invisible behind it. These values are the
 * corrected ones: enough cover for the type, and the rooms still legible down
 * both sides, which is the entire reason there is footage here at all.
 *
 * tools/video-check.mjs measures the rendered page at ten points across the
 * loop and gates at 5.5:1 where WCAG asks 4.5. Do not adjust these by eye.
 */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(115% 90% at 50% 44%,
      oklch(0.148 0.058 264 / 0.80) 0%,
      oklch(0.148 0.058 264 / 0.76) 42%,
      oklch(0.148 0.058 264 / 0.62) 78%,
      oklch(0.148 0.058 264 / 0.54) 100%),
    linear-gradient(180deg,
      oklch(0.148 0.058 264 / 0.34) 0%,
      transparent 24%,
      transparent 68%,
      oklch(0.148 0.058 264 / 0.44) 100%);
}

@media (min-width: 64rem) {
  /* Wider viewport, so the copy occupies a smaller share of the frame and the
     falloff can start sooner and go further — more of the practice is visible
     down both sides without the centre losing any cover. */
  .hero__scrim {
    background:
      radial-gradient(74% 90% at 50% 46%,
        oklch(0.148 0.058 264 / 0.79) 0%,
        oklch(0.148 0.058 264 / 0.74) 48%,
        oklch(0.148 0.058 264 / 0.38) 82%,
        oklch(0.148 0.058 264 / 0.22) 100%),
      linear-gradient(180deg,
        oklch(0.148 0.058 264 / 0.34) 0%,
        transparent 26%,
        transparent 66%,
        oklch(0.148 0.058 264 / 0.44) 100%);
  }
}

.hero__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: radial-gradient(oklch(1 0 0 / 0.16) 0.5px, transparent 0.5px);
  background-size: 3px 3px;
  mix-blend-mode: overlay;
}

/*
 * Centred.
 *
 * Two earlier versions of this were a two-column split — first a faceted
 * portrait beside the copy, then copy left with the footage open on the right.
 * Both put the type against one edge of a full-bleed frame, and against
 * moving footage that reads as the content having been pushed aside rather
 * than composed. Centred, the frame becomes a stage: the copy sits on the axis
 * of the shot, the practice is visible down both sides, and the credential
 * plane below spans the same axis.
 */
.hero__inner {
  position: relative;
  display: grid;
  justify-items: center;
  text-align: center;
  gap: clamp(var(--s-xl), 5vw, var(--s-3xl));
  align-items: center;
}

/*
 * Sized to the tagline, then centred.
 *
 * "Our art, your smile." needs about 640px at display size; below that it
 * breaks after the comma and turns the practice's own line into two fragments.
 * The block is capped rather than left to fill the container because a centred
 * measure that runs the full width of a 2000px screen is unreadable however
 * well it is scrimmed.
 */
.hero__copy {
  max-width: min(100%, 34rem);
  margin-inline: auto;
}
@media (min-width: 48rem) { .hero__copy { max-width: min(92%, 44rem); } }

.hero__actions { justify-content: center; }
.hero__badges { justify-content: center; }

/*
 * The badge row is allowed to be wider than the copy.
 *
 * There are five of them now that both offices joined the row, and inside the
 * 44rem copy column the fifth wrapped alone onto a second line — a centred
 * orphan, which is the ragged edge this build keeps having to design out. They
 * carry their own opaque grounds, so unlike the type around them they stay
 * legible further out where the scrim thins.
 */
@media (min-width: 64rem) {
  .hero__badges {
    width: max-content;
    /*
     * vw, not %. A percentage max-width resolves against the containing block —
     * `.hero__copy` — so a percentage here comes out SMALLER than the width the
     * row already had and breaks every badge onto its own line. Only vw asks
     * the viewport.
     *
     * This rule existed twice for a while, once here and once further down the
     * file at 48rem, and the later one silently won. One rule, one number.
     */
    /* 80vw, not 88. The row grows past the copy column on both sides, so at 1024px
       88vw put its edges outside the viewport and the guard flagged an overflow. */
    max-width: min(62rem, 80vw);
    /*
     * `margin-inline: auto` does NOT centre this, and that is not a subtlety — it is why
     * the row sat 100px right of everything above it. Auto margins resolve to zero once a
     * box is wider than its containing block, and then the overflow all goes one way (the
     * end side, so right in LTR). Measured: the mark, the heading and the buttons all
     * centred on 720; the badges centred on 820.
     *
     * Shifting the left edge to the parent's centre and pulling back half the row's OWN
     * width centres it on that same axis whatever its width, overflow included.
     */
    position: relative;
    inset-inline-start: 50%;
    transform: translateX(-50%);
  }
}

.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  margin-block-end: var(--s-md);
  font-size: var(--t-small);
  font-weight: 500;
  color: var(--gold-ink);
}
.hero__eyebrow .sparkle { width: 0.8em; height: 0.8em; }

/* --- The mark, and the one line under it ---------------------------------
 * The logo is the focal point; the H1 beneath it is small on purpose. It is
 * there to say what the mark cannot — what this practice does and where it is —
 * and to remain a real heading for search and for screen readers.
 * -------------------------------------------------------------------------- */

.hero__mark { margin-block-end: var(--s-md); }

.hero__logo {
  display: block;
  width: auto;
  height: auto;
  max-width: min(100%, 22rem);
  max-height: 7.5rem;
  margin-inline: auto;
}
@media (max-width: 47.99rem) { .hero__logo { max-width: min(100%, 15rem); } }

/* No display size here any more: the mark is the display element, and the two
   spans inside set their own. */
.hero__title {
  letter-spacing: var(--ls-display);
}
.hero__tagline,
.hero__what { display: block; }

/* Their own tagline, and the reason the practice has the name it has. */
.hero__tagline {
  font-size: clamp(1.5rem, 1.1rem + 1.5vw, 2.25rem);
  line-height: 1.15;
  color: var(--gold-ink);
}

/* Small, and doing the heavy lifting anyway: category and both cities, which a
   wordmark reading "Dental artistry" states neither of. */
.hero__what {
  margin-block-start: var(--s-2xs);
  font-family: var(--font-text);
  font-size: var(--t-lead);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.45;
  color: var(--ink-soft);
}

.hero__lead {
  margin-block-start: var(--s-md);
  max-width: 46ch;
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--ink-soft);
}

.hero__actions { margin-block-start: var(--s-lg); }

.hero__note {
  margin-block-start: var(--s-md);
  font-size: var(--t-small);
  color: var(--ink-soft);
  max-width: 44ch;
}

/* --- The bottom edge ------------------------------------------------------
 * Two things used to live down here and neither survived.
 *
 * `.hero__badge` was a box reading "2021 & 2024 / Top Doctor: Dr. Romero",
 * floated at the bottom right, alone in an otherwise empty half of the frame —
 * while the credential strip said the same award again a hundred pixels below
 * it. `.hero__scroll` was a 1px animated line centred on the bottom edge.
 *
 * Both are now replaced by one object that does the job properly: the
 * credential plane in `.trust`, which runs the full container width across
 * this edge, states the award once, and joins the hero to the page instead of
 * floating on it. The hero's only remaining job here is to leave it room.
 * -------------------------------------------------------------------------- */

@media (min-width: 64rem) {
  /* Exactly the half of the plane that overlaps upward. `--bridge-h` is defined
     in tokens.css precisely so this number and the plane's cannot drift apart. */
  /* --s-xl, because half the plane is already sitting in this padding. Together
     they still leave ~56px of clear air between the badges and the plane's top
     edge, and the 5rem version cost the composition ~25px it needed at 1920,
     where the root font-size steps to 16.5px and everything grows 3%. */
  .hero { padding-block-end: calc(var(--s-xl) + var(--bridge-h) / 2); }

  /*
   * And the hero gives that same half back out of its height.
   *
   * At a flat 100svh the plane straddles the fold as well as the seam, so the
   * bottom half of every credential sits below it and "Top Doctor" reads as
   * text clipped by the viewport rather than as a deliberate peek. Subtracting
   * the overlap makes the hero and the whole plane add up to exactly one
   * screen: the last thing above the fold is a complete row of credentials.
   */
  .hero { min-height: min(calc(100svh - var(--bridge-h) / 2), 62rem); }
}

/* The hero stops trying to fill the viewport on a phone — the person in pain still has the
   action bar pinned regardless, and the headline is the one sentence the page exists to
   say. It should not need a scroll. */
@media (max-width: 47.99rem) {
  .hero { min-height: 0; padding-block-start: calc(var(--header-h) + var(--s-lg)); }
}

/* --- Closing CTA ----------------------------------------------------------- */

.cta {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: oklch(0.148 0.058 264);
  text-align: center;
  padding-block: var(--s-3xl);

  --ink: oklch(0.984 0.005 250);
  --ink-soft: oklch(0.820 0.032 250);
  --gold-ink: oklch(0.860 0.100 90);
  --rule-strong: oklch(0.460 0.080 261);
  color: var(--ink);
}

/*
 * The stage is a PAINTED gold-leaf ground, and the canvas is an enhancement over it.
 *
 * This was a bare `position: absolute` box behind a canvas that starts at `opacity: 0` and
 * is only lit by app.js, which gates on `deviceMemory >= 4` AND `min-width: 48rem`. So the
 * closing panel — the emotional peak of the page, "No matter how long it has been, you are
 * welcome here" — was flat navy plus a vignette for every phone, every reduced-motion
 * visitor and everyone with JavaScript off. That is the majority of this practice's
 * audience, and Design Principle 5 says in as many words that the static fallback is a
 * design deliverable, not a failure mode. The hero honours that exactly; this abandoned it.
 *
 * Two soft gold pools and a warm sweep, composed to sit where the aurora's own light sits,
 * so the canvas fading in over them reads as the same material coming alive rather than as
 * a different picture replacing a placeholder.
 */
.cta__stage {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    /* `.cta__veil` sits over this and pulls everything toward navy at 55% from 75% out, so
       these read at roughly half the alpha written here. Measured against the veil, not
       chosen on the swatch. Both pools sit in opposite CORNERS — the type is centred, which
       is where the veil is clearest, so the light never crosses a letter. */
    radial-gradient(58% 78% at 20% 16%,
      oklch(0.780 0.112 85 / 0.42) 0%,
      oklch(0.640 0.100 84 / 0.20) 42%,
      transparent 72%),
    radial-gradient(52% 70% at 84% 88%,
      oklch(0.860 0.100 90 / 0.32) 0%,
      oklch(0.600 0.095 84 / 0.15) 46%,
      transparent 74%),
    linear-gradient(146deg,
      oklch(0.212 0.084 264) 0%,
      oklch(0.176 0.070 264) 46%,
      oklch(0.148 0.058 264) 100%);
}

.cta__canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 1400ms var(--ease-out); }
.cta__canvas.is-live { opacity: 0.85; }
.cta__veil {
  position: absolute;
  inset: 0;
  background: radial-gradient(70% 120% at 50% 50%,
    transparent 0%, oklch(0.148 0.058 264 / 0.55) 75%);
}

.cta__inner { display: flex; flex-direction: column; align-items: center; gap: var(--s-md); }

.cta__kicker {
  font-family: var(--font-display);
  font-size: 1.2rem;
  color: var(--gold-ink);
}
.cta__title { max-width: 20ch; }
.cta__body { color: var(--ink-soft); font-size: var(--t-lead); }
.cta__actions { justify-content: center; margin-block-start: var(--s-sm); }
.cta__meta { font-size: var(--t-small); color: var(--ink-soft); }

/* --- Inner-page masthead ----------------------------------------------------
 * The composed alternative to eight identical text-on-flat page heads.
 * -------------------------------------------------------------------------- */

/*
 * NOT clipped.
 *
 * The figure is pulled 5rem below the masthead so the photograph overlaps the section
 * beneath it and the two read as one composition — but `overflow: clip` here cut exactly
 * that overhang off, which chopped the bottom point of the crown facet straight through
 * the faces in the photograph. The two decorative layers are both `inset: 0` and cannot
 * overflow, so nothing here needs clipping in the first place.
 */
.masthead {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: calc(var(--header-h) + var(--s-2xl)) var(--s-2xl);
  min-height: min(34rem, 68svh);
  display: flex;
  align-items: center;
  background: oklch(0.148 0.058 264);
  color: oklch(0.984 0.005 250);

  --ink: oklch(0.984 0.005 250);
  --ink-soft: oklch(0.820 0.032 250);
  --gold-ink: oklch(0.860 0.100 90);
  --rule: oklch(0.360 0.070 262);
  --rule-strong: oklch(0.460 0.080 261);
}
.masthead--deep { background: oklch(0.118 0.048 264); }

/* --- The stage ------------------------------------------------------------
 * Painted gradient, the page's photograph, the contrast scrim, grain. Same
 * order as the home hero, and the same rule: remove any layer and what is left
 * is still a finished band, never a hole.
 * -------------------------------------------------------------------------- */

.masthead__stage {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.masthead__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Slightly cooled and dimmed at source so the scrim above it has less to do and the
     photograph sits inside the navy palette rather than fighting it. */
  filter: saturate(0.86) contrast(1.04) brightness(0.92);
}

/*
 * The scrim, and the same discipline as the hero's.
 *
 * Interior mastheads carry a DIFFERENT photograph per page, so this cannot be tuned to one
 * image the way scripts/hero_scrim.py tunes the loop. It is therefore heavier and
 * directional: near-opaque where the copy is, easing off to the right where nothing is set
 * over it. tools/masthead-check.mjs measures every page against the actual image it ships.
 */
.masthead__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      oklch(0.148 0.058 264 / 0.86) 0%,
      oklch(0.148 0.058 264 / 0.82) 50%,
      oklch(0.148 0.058 264 / 0.88) 100%);
}
@media (min-width: 64rem) {
  .masthead__scrim {
    background:
      linear-gradient(96deg,
        oklch(0.148 0.058 264 / 0.93) 0%,
        oklch(0.148 0.058 264 / 0.88) 46%,
        oklch(0.148 0.058 264 / 0.62) 74%,
        oklch(0.148 0.058 264 / 0.44) 100%),
      linear-gradient(180deg,
        oklch(0.148 0.058 264 / 0.30) 0%,
        transparent 24%,
        transparent 70%,
        oklch(0.148 0.058 264 / 0.42) 100%);
  }
}

/* The same light the hero's shader casts, painted rather than computed — an
   interior page does not need a second WebGL context to feel part of the site. */
.masthead__wash {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(80% 120% at 88% 0%,
      oklch(0.46 0.10 88 / 0.30) 0%, transparent 58%),
    radial-gradient(70% 100% at 5% 100%,
      oklch(0.44 0.09 235 / 0.22) 0%, transparent 60%);
}
.masthead__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.4;
  background-image: radial-gradient(oklch(1 0 0 / 0.14) 0.5px, transparent 0.5px);
  background-size: 3px 3px;
  mix-blend-mode: overlay;
}

.masthead__inner {
  display: grid;
  gap: clamp(var(--s-lg), 4vw, var(--s-2xl));
  align-items: center;
}
/* One column now: the photograph is behind the copy, not beside it. */
.masthead__copy { max-width: 60ch; }
@media (min-width: 64rem) { .masthead__copy { max-width: min(58%, 44rem); } }

.masthead__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  margin-block: var(--s-md) 0;
  font-size: var(--t-small);
  font-weight: 500;
  color: var(--gold-ink);
}
.masthead__eyebrow .sparkle { width: 0.8em; height: 0.8em; }

.masthead__title {
  margin-block-start: var(--s-sm);
  font-size: clamp(2.5rem, 1.6rem + 4vw, 4.75rem);
  line-height: 1.03;
  letter-spacing: var(--ls-display);
  max-width: 17ch;
}
.masthead--wide .masthead__title { max-width: 20ch; }

.masthead__lead {
  margin-block-start: var(--s-md);
  max-width: 52ch;
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--ink-soft);
}
.masthead__actions { margin-block-start: var(--s-lg); }

/* One interval under every masthead, on every page, whatever the section below is. */
.masthead + * { padding-block-start: var(--s-2xl); }


.masthead .breadcrumbs__list { color: var(--ink-soft); }

/* --- Page heads (legacy, text-only templates) ------------------------------ */

.page-head { padding-block-start: calc(var(--header-h) + var(--s-xl)); }
.page-head__title { margin-block: var(--s-sm) 0; }
.page-head__sub {
  margin-block-start: var(--s-sm);
  font-size: var(--t-lead);
  color: var(--ink-soft);
  max-width: 52ch;
}
.page-head .leaf-rule { margin-block-start: var(--s-md); width: min(9rem, 40%); }

.breadcrumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--t-micro);
  color: var(--ink-soft);
}
.breadcrumbs__item + .breadcrumbs__item::before {
  content: "/";
  margin-inline-end: 0.5rem;
  opacity: 0.5;
}
.breadcrumbs a { text-decoration: none; }
.breadcrumbs a:hover { color: var(--gold-ink); }

/* --- Blog listing ---------------------------------------------------------- */

.post-grid {
  display: grid;
  gap: var(--s-xl) var(--s-lg);
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}

.post-card__link { display: flex; flex-direction: column; gap: var(--s-md); text-decoration: none; height: 100%; }
.post-card__media { overflow: clip; }
.post-card__media img,
.post-card__placeholder {
  width: 100%;
  transition: transform var(--dur-slow) var(--ease-out);
}
.post-card__link:hover .post-card__media img { transform: scale(1.035); }
.post-card__placeholder {
  display: grid;
  place-items: center;
  background: var(--bg-raised);
  color: var(--gold);
  font-size: 2rem;
}
.post-card__meta { font-size: var(--t-micro); color: var(--ink-soft); }
.post-card__title { font-size: var(--t-h4); font-family: var(--font-display); }
.post-card__link:hover .post-card__title { color: var(--gold-ink); }
.post-card__excerpt { color: var(--ink-soft); font-size: var(--t-small); }
.post-card__more {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  margin-block-start: auto;
  padding-block-start: var(--s-2xs);
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--gold-ink);
}
.post-card__link:hover .btn__arrow { transform: translateX(0.25rem); }

.empty-state { padding-block: var(--s-2xl); }

.pagination {
  margin-block-start: var(--s-2xl);
  display: flex;
  justify-content: center;
}
.pagination .nav-links { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding-inline: 0.6rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  text-decoration: none;
  font-size: var(--t-small);
}
.pagination .page-numbers:hover { border-color: var(--gold); color: var(--gold-ink); }
.pagination .page-numbers.current { background: var(--gold); color: oklch(0.148 0.058 264); border-color: var(--gold); font-weight: 600; }

/* --- Trust: the bridge between the hero and the page ----------------------
 * Five credentials, and the seam they sit on.
 *
 * This was a flat navy band with the items floated in a row: the least
 * designed thing on the site, in the most valuable position on it. Butting a
 * dark hero against a light page with a hairline between them is what made the
 * whole top of the home page read as two unrelated slabs.
 *
 * So the credentials became the join. One cut plane, half of it over the
 * footage and half over the reading surface, pulled up by exactly half its own
 * height at both ends — the hero reserves that half in its bottom padding, so
 * nothing is ever covered by it.
 *
 * The faces are the page's own near-white, which is what makes this read as
 * the light surface rising into the hero rather than as five badges parked on
 * a line. Gold hairlines between them, the diamond taken out of both outer
 * corners, and a shadow that follows those cuts.
 * -------------------------------------------------------------------------- */

.trust {
  position: relative;
  /* Above the hero it overlaps AND above the light section that follows, both
     of which are `position: relative` with z-index auto. */
  z-index: 2;
}

/*
 * `clip-path` clips a box-shadow away completely, exactly as it clips a focus
 * ring (see surfaces.css). `filter: drop-shadow` on the parent traces the
 * clipped silhouette instead, so the shadow follows the two diagonal cuts
 * rather than the rectangle they were taken out of. That is the whole reason
 * the plane reads as a solid object lifted off the footage.
 */
.trust__bridge {
  /* Two shadows: a tight one that gives the silhouette a defined bottom edge
     against the near-white page — where the faces are almost the same colour as
     the ground behind them — and a wide soft one for the lift off the footage. */
  filter:
    drop-shadow(0 0.15rem 0.4rem oklch(0.148 0.058 264 / 0.18))
    drop-shadow(0 1rem 2.25rem oklch(0.148 0.058 264 / 0.34));
}

/*
 * A light island on a dark ground, so the plane restates the full token set
 * rather than inheriting navy values it would then have to fight. Same rule
 * the ground modifiers follow in tokens.css, for the same reason.
 */
.trust__plane {
  --face:      var(--bg-page);
  --edge:      var(--gold-deep);          /* 5.02:1 on the faces — a real seam */
  --ink:       var(--ink-dark);
  --ink-soft:  var(--ink-dark-soft);
  --gold-ink:  var(--gold-deep);
  --ring:      var(--gold-deep);
  --ring-halo: oklch(0.535 0.104 82 / 0.28);
  color: var(--ink);
}

/*
 * The award is the one credential a stranger can go and verify, so it is the
 * one face that is lit rather than the first of five identical ones.
 *
 * `.trust` in the selector is load-bearing, not decoration. surfaces.css has
 * `.t-dark .plane > .face--lit { --face: var(--bg-raised-2) }` at (0,3,0), and
 * the home page's body IS `.t-dark` — so a two-class selector here lost, and
 * this face rendered navy with dark ink on it, unreadable. Matching the
 * specificity and arriving later in the cascade is what wins it.
 */
.trust .trust__plane > .face--lit { --face: oklch(0.960 0.032 92); }

.trust__plane .trust__item {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 0.3rem;
  padding: var(--s-md) var(--s-sm);
  text-align: center;
  text-wrap: balance;
  cursor: default;
}

/*
 * The word you are scanning for, at display size.
 *
 * Every face used to be one line of 15px grey sans, centred, under a 12px
 * speck — five identical captions, which is why they read as five blank boxes
 * rather than as the five reasons somebody books. Setting the lead in the
 * display serif gives the run an actual hierarchy and lets "Same-day" land in
 * a glance instead of having to be read.
 */
.trust__lead {
  font-family: var(--font-display);
  font-size: clamp(1.125rem, 0.95rem + 0.45vw, 1.375rem);
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: var(--ink);
}

.trust__note {
  font-size: var(--t-micro);
  line-height: 1.35;
  color: var(--ink-soft);       /* --ink-dark-soft here: 8.3:1 on the faces */
}

/* A gold hairline draws in under the lead on hover — the leaf catching the one
   you are pointing at. It is the only thing that moves; the run stays a run. */
.trust__lead {
  position: relative;
  padding-block-end: 0.18em;
}
.trust__lead::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  height: 1px;
  background: var(--gold-deep);
  transform: scaleX(0);
  transition: transform var(--dur-mid) var(--ease-out);
}
.trust__plane .trust__item:hover .trust__lead::after { transform: scaleX(1); }

/*
 * Stacked, each face is a row: mark and text side by side, left aligned, sized
 * to its content.
 *
 * The centred column above is a bridge across a seam and needs a fixed height
 * to be centred ON — but `min-height: var(--bridge-h)` on five stacked faces is
 * 600px of credential strip on a 390px phone, which is what it was. Down here
 * there is no seam and no maths, so the height comes off and the layout becomes
 * what it should have been on a narrow screen anyway: a short checklist.
 */
@media (max-width: 63.99rem) {
  .trust__plane .trust__item {
    grid-template-columns: auto 1fr;
    grid-template-areas: "mark lead" "mark note";
    align-items: center;
    align-content: center;
    justify-items: start;
    text-align: start;
    column-gap: 0.7rem;
    row-gap: 0.1rem;
    padding: var(--s-sm) var(--s-md);
  }
  .trust__mark { grid-area: mark; }
  .trust__lead { grid-area: lead; }
  .trust__note { grid-area: note; }
}

@media (min-width: 64rem) {
  /* The height the lift is half of. See --bridge-h in tokens.css. */
  .trust__plane .trust__item { min-height: var(--bridge-h); }
}

/* 1rem, not 0.8. At 12.8px above a centred line in a tall face the mark read as
   a stray speck rather than as the wordmark's own sparkle. */
.trust__mark {
  width: 1rem;
  height: 1rem;
  color: var(--gold-deep);
  flex: none;
  transition: transform var(--dur-slow) var(--ease-out),
              color var(--dur-mid) var(--ease-out);
}

/* The sparkle turns a quarter and brightens. Nothing moves position, so a run
   of five stays a run of five. */
.trust__plane .trust__item:hover .trust__mark {
  transform: rotate(90deg) scale(1.25);
  color: var(--gold);
}

/* --- The overlap ---------------------------------------------------------- */

/*
 * Stacked, there is no seam to bridge — the hero, the plane and the page are
 * one column on one ground — so below the wide layout it is simply a block in
 * the flow with air around it.
 */
@media (max-width: 63.99rem) {
  .trust { padding-block: var(--s-xl) var(--s-lg); }
}

@media (min-width: 64rem) {
  /*
   * Negative at BOTH ends. The top margin lifts the plane into the hero; the
   * bottom margin pulls the following section up under it by the same amount,
   * which puts the hero/page boundary exactly through the plane's middle. One
   * value, applied twice, and the maths cannot drift.
   */
  .trust {
    margin-block-start: calc(var(--bridge-h) / -2);
    margin-block-end: calc(var(--bridge-h) / -2);
  }
}

@media (prefers-reduced-motion: reduce) {
  .trust__mark { transition: none; }
  .trust__plane .trust__item:hover .trust__mark { transform: none; }
}

/* --- Welcome --------------------------------------------------------------- */

.welcome__title { max-width: 18ch; }
.welcome__body { margin-block-start: var(--s-lg); max-width: 54ch; --flow: var(--s-md); }
.welcome__actions { margin-block-start: var(--s-lg); }

/* WELL: hours are read, not acted on. Recessed, no border, light falling in
   from the top edge — see .well in surfaces.css. */
.hours-card {
  padding: var(--s-lg);
  background: var(--bg-page-2);
  box-shadow: inset 0 1px 0 var(--edge);
  clip-path: var(--facet-soft);
  position: relative;
}
/* Gold leaf catching the top edge of the card. */
.hours-card::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: var(--s-md);
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}
.hours-card__title { font-family: var(--font-display); font-size: var(--t-h4); margin-block-end: var(--s-md); }
.hours-card__list { display: flex; flex-direction: column; }
.hours-card__row {
  display: flex;
  justify-content: space-between;
  gap: var(--s-sm);
  padding-block: 0.55rem;
  font-size: var(--t-small);
  border-block-end: 1px solid var(--rule-light);
}
.hours-card__row:last-child { border-block-end: 0; }
.hours-card__row span:last-child { color: var(--ink-dark-soft); }
.hours-card__row.is-today { font-weight: 600; }
/*
 * Gold marks TODAY'S HOURS, not today.
 *
 * `is-today` is set on whichever row is today, and the value column was painted gold
 * unconditionally — so on a Saturday and a Sunday, two days in seven, the most emphasised
 * line in the card was a bold gold "Closed". Gold is the affirmative material everywhere
 * else on this site: it is the booking button, the lit face, the chip that says "Se habla
 * español". Using it to say "no" inverts the one colour signal the page has, at the moment
 * the person reading is most likely to be the one in pain.
 *
 * A closed day today keeps the weight — it is still the row you want — and drops the gold.
 */
.hours-card__row.is-today span:last-child { color: var(--gold-deep); }
.hours-card__row.is-today.is-closed span:last-child { color: var(--ink-dark-soft); }
.hours-card__note {
  margin-block: var(--s-md);
  max-width: 46ch;
  font-size: var(--t-small);
  color: var(--ink-dark-soft);
}

/* --- Services grid ---------------------------------------------------------
 * Even three-across. The two feature cards previously ran double width, which
 * left the remaining three sitting on a row of a different rhythm. */

/* --- Services: one cut plane -------------------------------------------- */

/* Any plane that follows something gets the interval; a plane that opens its
   section does not. Scoping this to `.section-head + .plane` missed every
   section with its own heading class — the testimonials wall sat flush against
   its title with a 0px gap. `* + .plane` cannot miss one. */
* + .plane { margin-block-start: var(--s-xl); }

.services__item > .face__link { gap: var(--s-md); }

.service-card__media { overflow: clip; }
.service-card__media img {
  width: 100%;
  transition: transform var(--dur-slow) var(--ease-out);
}
.face--link:hover .service-card__media img { transform: scale(1.04); }

.service-card__title { font-family: var(--font-display); font-size: var(--t-h4); }
.face--link:hover .service-card__title { color: var(--gold-ink); }
.service-card__blurb { color: var(--ink-soft); font-size: var(--t-small); }
.service-card__more {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  margin-block-start: auto;
  padding-block-start: var(--s-2xs);
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--gold-ink);
}
.face--link:hover .btn__arrow { transform: translateX(0.25rem); }

/* --- Urgent band ----------------------------------------------------------- */

/* Painted by .inlay in surfaces.css — this only lays it out. The border/radius
   recipe that used to identify it is gone; the navy ground identifies it now. */
.urgent {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-lg);
  margin-block-start: var(--s-xl);
}
.urgent__body { max-width: 48ch; }
.urgent__title { font-family: var(--font-display); font-size: var(--t-h3); margin-block-end: var(--s-2xs); }
.urgent__body p { color: var(--ink-soft); font-size: var(--t-small); }

/* --- Values: bare, not boxed ---------------------------------------------
 * Previously five equal columns with a gold hairline each — five identical
 * cards in a row wearing a different hat. Layout and the rule now come from
 * .bare-set in surfaces.css; only the type is set here.                     */


.values__name {
  font-family: var(--font-display);
  font-size: var(--t-h4);
  margin-block-end: var(--s-2xs);
}
.values__body { color: var(--ink-soft); font-size: var(--t-small); }

/* --- Doctors --------------------------------------------------------------- */

.doctors__grid {
  display: grid;
  gap: var(--s-2xl) var(--s-xl);
  margin-block-start: var(--s-xl);
  grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr));
}
.doctor { display: grid; gap: var(--s-md); }
@media (min-width: 34rem) and (max-width: 59.99rem) {
  .doctor { grid-template-columns: 0.8fr 1.2fr; align-items: start; }
}
.doctor__media .facet { width: 100%; aspect-ratio: 4 / 5; }
.doctor__role { font-size: var(--t-small); color: var(--gold-ink); font-weight: 600; }
.doctor__name { font-family: var(--font-display); font-size: var(--t-h3); margin-block: 0.15rem var(--s-2xs); }
.doctor__name a { text-decoration: none; }
.doctor__name a:hover { color: var(--gold-ink); }
.doctor__bio { max-width: 68ch; color: var(--ink-soft); font-size: var(--t-small); }
.doctor__langs {
  margin-block-start: var(--s-sm);
  font-size: var(--t-small);
  color: var(--ink-soft);
}
.doctor .btn--quiet { margin-block-start: var(--s-sm); align-self: start; }

/* --- First visit ------------------------------------------------------------
 * A real sequence, so it is built as one: a single rail running behind the four
 * markers, and every row of the four columns sharing a baseline. Previously each
 * column was an independent flex stack, so a two-line title in column 3 pushed
 * its body out of alignment with the other three and the whole band read as
 * unfinished. Subgrid ties the rows together.
 * -------------------------------------------------------------------------- */

.steps {
  position: relative;
  display: grid;
  gap: var(--s-lg);
  margin-block-start: var(--s-2xl);
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  /* FOUR named rows so every column hands its marker, title, body and sensory
     line to the same shared baseline. This was three, and adding the "what you
     feel" line gave each item a fourth child with no row to occupy — so it was
     placed in an implicit row and printed straight on top of the body copy.
     A subgrid row count is not decoration; it has to match the children. */
  grid-template-rows: auto auto auto auto;
}

/* Two layers, not one. The dim track is always the full width so the sequence is
   legible before any scrolling happens; the bright fill sits on top and is what
   motion.css scrubs. A single animated line meant the rail simply stopped short
   of step 4 whenever the scrub had not completed. */
.steps::before,
.steps::after {
  content: "";
  position: absolute;
  inset-block-start: 1.4rem;
  inset-inline-start: 1.4rem;
  /* Ends at the centre of the LAST marker, not at the grid's right edge. The
     markers sit at the start of each column, so the final one is a whole column
     short of the end — insetting equally on both sides overshot it and left the
     line running off into empty space past step 4. */
  inset-inline-end: calc((100% - 3 * var(--s-lg)) / 4 - 1.4rem);
  height: 1px;
  z-index: 0;
  display: none;
}
/* Only drawn where the four steps are genuinely on one row; the calc above
   assumes four columns. */
@media (min-width: 64rem) {
  .steps { grid-template-columns: repeat(4, 1fr); }
  .steps::before,
  .steps::after { display: block; }
}
/*
 * The track has to be VISIBLE, which gold on a near-white ground is not.
 *
 * This was `--gold` at 22% alpha. Gold is 1.93:1 against this section's reading
 * surface at full strength, so at 22% it is nothing at all — and the whole
 * point of a two-layer rail is that the dim track shows the full sequence
 * before any scrolling happens. What a visitor actually saw was the bright
 * fill alone, stopped wherever the scrub had reached (measured mid-page at
 * scaleX 0.87), with bare page between it and step 4. The rail read as broken
 * rather than as in progress.
 *
 * `--edge` is the structural edge token and is defined per ground, so this
 * stays correct on the navy variants too.
 */
.steps::before {
  background: color-mix(in oklch, var(--edge) 60%, transparent);
}
.steps::after {
  background: linear-gradient(90deg, var(--gold-bright), var(--gold));
  transform-origin: left center;
}
.steps__item {
  position: relative;
  z-index: 1;
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  gap: var(--s-sm);
  align-content: start;
}

.steps__marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.8rem;
  height: 2.8rem;
  font-family: var(--font-display);
  font-size: 1.05rem;
  line-height: 1;
  border: 1px solid var(--edge-lit);
  border-radius: 50%;
  background: var(--bg-raised);
  /* --gold-ink on navy, --gold-deep on light. Plain --gold here measured 1.93:1
     against the reading surface, which is illegal for a numeral that carries the
     sequence. */
  color: var(--gold-ink);
  flex: none;
}

.steps__title { font-family: var(--font-display); font-size: var(--t-h4); }
.steps__body { color: var(--ink-soft); font-size: var(--t-small); line-height: 1.6; }

/* --- Reassurance ------------------------------------------------------------
 * This used to be a small muted footnote under a 1px rule that started at the
 * left edge and stopped dead under column two — a rule to nowhere, and the
 * single reason the band read as unfinished. It is now the emotional close of
 * the section: a face, the doctors' own words, and the phone number.
 * -------------------------------------------------------------------------- */

.reassure {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-md) var(--s-lg);
  margin-block-start: var(--s-2xl);
  padding: var(--s-lg);
  background: var(--bg-raised-2);
  box-shadow: inset 0 1px 0 var(--edge);
  clip-path: var(--facet-soft);
}
.reassure__portrait { flex: none; width: clamp(5rem, 9vw, 7.5rem); }
.reassure__portrait .facet {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  /* The source is a two-person studio shot on a dark grey backdrop; centred and
     cropped square it lands on lab coats and reads as a muddy rectangle. Pulling
     the crop up puts both faces in frame, which is the entire point of showing
     it next to a quote from them. */
  object-position: 50% 18%;
  filter: saturate(1.05) brightness(1.06);
}
.reassure__body { flex: 1 1 22rem; }
.reassure__quote {
  max-width: 54ch;          /* display face, so the measure is tighter than body copy */
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 0.95rem + 0.5vw, 1.3rem);
  line-height: 1.45;
  text-wrap: pretty;
}
.reassure__attrib {
  margin-block-start: var(--s-2xs);
  font-size: var(--t-small);
  color: var(--gold-ink);
}
.reassure__cta { flex: none; }

/* --- Testimonials ----------------------------------------------------------- */

.testimonials__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-md);
}
.rating-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-size: var(--t-small);
  color: var(--ink-soft);
}
.rating-badge strong { color: var(--ink); font-size: 1.05rem; }
.stars { display: inline-flex; gap: 0.12em; color: var(--gold); }
.stars .star { width: 1em; height: 1em; fill: currentColor; }

/* An even three-across grid. Mixed spans produced a ragged 2 / 3 / 1 stack with an
   orphan on the last row, which read as broken rather than as composition. The
   personality comes from the facet cut and the display face, not from uneven boxes.
   `grid-auto-rows: 1fr` keeps every card in a row the same height regardless of
   quote length, so the row edges line up. */
/* Grid and surface now come from .plane / .face in surfaces.css: six voices are
   one wall, not six cards floating apart. */


/*
 * A voice, not a box.
 *
 * These were six identical navy rectangles: stars, five lines of display serif, a
 * hairline, a name. Nothing said "somebody said this" — which on the one section
 * where real patients speak is the entire job. Three things changed:
 *
 *   1. An oversized quotation mark, set in the display face, in gold at low alpha,
 *      bled off the top-left corner of every face. It is the mark the brand already
 *      owns doing the one job a testimonial card needs done.
 *   2. The quote is set in the TEXT face. Young Serif is beautiful at display size and
 *      hard work at 16px over five lines, and these are the longest passages of small
 *      type on the page. Readability wins; the display face keeps the attribution.
 *   3. The attribution reads as a person: name in the display face, place beneath it,
 *      and a short gold rule instead of a full-width hairline.
 */
.quote { position: relative; overflow: clip; }

/*
 * Top RIGHT, and at an alpha that survives a dark ground.
 *
 * Placed top-left at 16% it was invisible twice over: gold at 0.16 on navy is barely a
 * shade, and `overflow: clip` on the face cut away the part of the glyph that sat above
 * the box. Moved into the empty corner opposite the stars, sized to fit inside the face,
 * and taken to an alpha that actually reads as a watermark rather than a smudge.
 */
.quote::before {
  content: "\201C";
  position: absolute;
  /*
   * Wholly inside the face. Hung above the top edge it was cut by `overflow: clip` down to
   * the two tails of the glyph, which read as a rendering artifact rather than as a
   * quotation mark — worse than not having one. A serif open-quote carries its ink in the
   * top third of the em box, so at 4.5rem the visible mark sits roughly 12–34px below this
   * offset, clear of the edge.
   */
  inset-block-start: 0.4rem;
  inset-inline-end: 1rem;
  font-family: var(--font-display);
  font-size: 4.5rem;
  line-height: 1;
  color: var(--gold);
  opacity: 0.3;
  pointer-events: none;
  transition: opacity var(--dur-mid) var(--ease-out);
}
.quote:hover::before { opacity: 0.48; }

.quote figure {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-sm);
  height: 100%;
}

.quote__body {
  font-family: var(--font-text);
  font-size: var(--t-small);
  line-height: 1.65;
  color: var(--ink);
}
.quote__body p + p { margin-block-start: 0.7em; }

.quote__meta {
  margin-block-start: auto;
  padding-block-start: var(--s-sm);
  display: grid;
  gap: 0.05rem;
  font-size: var(--t-small);
  /* A short gold rule, not a full-width hairline: it marks the turn from the words to
     the person who said them rather than drawing a table row. */
  border-block-start: none;
  position: relative;
}
.quote__meta::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 2.25rem;
  height: 2px;
  background: var(--gold);
  transition: width var(--dur-mid) var(--ease-out);
}
.quote:hover .quote__meta::before { width: 3.5rem; }

.quote__author {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  line-height: 1.2;
  color: var(--ink);
}
.quote__where {
  color: var(--ink-soft);
  font-size: var(--t-micro);
}

@media (prefers-reduced-motion: reduce) {
  .quote::before,
  .quote__meta::before { transition: none; }
  .quote:hover::before { transform: none; }
}

/* --- Fees ------------------------------------------------------------------- */

/* Its own measure: this column is half of a container that now tracks the viewport, so at
   2560 it reached 86ch without one. */
.fees__body { margin-block-start: var(--s-lg); --flow: var(--s-md); max-width: 62ch; }
.fees__actions { margin-block-start: var(--s-lg); }

.insurers {
  padding: var(--s-lg);
  background: var(--bg-page-2);
  box-shadow: inset 0 1px 0 var(--edge);
  clip-path: var(--facet-soft);
}
.insurers__title { font-family: var(--font-text); font-size: var(--t-small); font-weight: 600; }
.insurers__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-block: var(--s-md);
}
.insurers__item {
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--edge);
  border-radius: 100px;
  background: var(--bg-page);
  font-size: var(--t-small);
  font-weight: 500;
}
.insurers__note { font-size: var(--t-small); color: var(--ink-dark-soft); }

/* --- FAQ -------------------------------------------------------------------- */

.faq .accordion { margin-block-start: var(--s-xl); }

/* --- Locations -------------------------------------------------------------- */

.locations__grid {
  display: grid;
  gap: var(--s-lg);
  margin-block-start: var(--s-xl);
  grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
}
.location {
  padding: var(--s-lg);
  background: var(--bg-page-2);
  box-shadow: inset 0 1px 0 var(--edge);
  clip-path: var(--facet-soft);
}
.location__name { font-family: var(--font-display); font-size: var(--t-h4); }
.location__address {
  font-style: normal;
  margin-block: var(--s-sm);
  font-size: var(--t-lead);
  line-height: 1.4;
}
.location__meta {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: var(--t-small);
  color: var(--ink-dark-soft);
  margin-block-end: var(--s-md);
}
.location__meta a { color: var(--ink-dark); font-weight: 600; }

/* --- FAQ: answered in the open, on a cut plane ---------------------------
 * Open was right; open AND unstructured was a wall of grey. The plane gives
 * each pair a face with a shared cut edge, so one question can be found without
 * reading the seven around it.                                              */

.faq__plane { margin-block-start: var(--s-xl); }

.faq__item { display: flex; flex-direction: column; gap: var(--s-2xs); }

.faq__q {
  display: flex;
  align-items: baseline;
  gap: 0.5em;
  font-family: var(--font-display);
  font-size: var(--t-h4);
  /*
   * Looser than `--lh-heading`, which computes to 1.14 here.
   *
   * That is right for a heading you scan past. These are questions somebody reads, most of
   * them run to two lines, and several are the sentence that decides whether the reader
   * believes the answer under it — "I haven't been to a dentist in years. Will you lecture
   * me?" is not a label.
   */
  line-height: 1.26;
  text-wrap: balance;
}
.faq__mark {
  width: 0.6em;
  height: 0.6em;
  flex: none;
  color: var(--gold-ink);
  transition: transform var(--dur-slow) var(--ease-out);
}
.faq__item:hover .faq__mark { transform: rotate(90deg) scale(1.2); }

.faq__a {
  color: var(--ink-soft);
  font-size: var(--t-small);
  line-height: 1.6;
  max-width: 46ch;
}
.faq__a p + p { margin-block-start: 0.55em; }

/* The lit face carries the question everything else hangs on, so its answer is
   allowed to be the one set at reading size. */
.faq__item.face--lit .faq__q { font-size: var(--t-h3); }
.faq__item.face--lit .faq__a { font-size: var(--t-body); color: var(--ink); }

.faq__tail {
  margin-block-start: var(--s-lg);
  /* Its own measure. This ran the full width of the container — 126ch at 1280 and 212ch
     at 2560 — because nothing between the paragraph and the shell ever capped it. Widening
     the container did not create that; it made an existing defect impossible to ignore. */
  max-width: 62ch;
  font-size: var(--t-small);
  color: var(--ink-soft);
}
.faq__tail a { color: var(--gold-ink); font-weight: 600; white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .faq__mark { transition: none; }
  .faq__item:hover .faq__mark { transform: none; }
}

/* --- The switchboard: indexed by what a patient would say ---------------- */

.switchboard__tools {
  display: flex;
  flex-direction: column;
  gap: var(--s-2xs);
  margin-block-start: var(--s-xl);
  max-width: 28rem;
}
.switchboard__label { font-size: var(--t-small); font-weight: 600; }
.switchboard__field {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  background: var(--bg-page-2);
  box-shadow: inset 0 1px 0 var(--edge);
  clip-path: var(--facet-soft);
  color: var(--ink-soft);
}
.switchboard__field:focus-within { box-shadow: inset 0 0 0 2px var(--ring); }
.switchboard__field input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--t-small);
  color: var(--ink);
}
.switchboard__field input:focus { outline: none; }
.switchboard__count { font-size: var(--t-small); color: var(--ink-soft); min-height: 1.2em; }

/* A run of phrases, not a grid of boxes. The only geometry is the hairline
   between one and the next. */
.switchboard__list {
  margin-block-start: var(--s-lg);
  border-block-start: 1px solid var(--edge-dim);
}
@media (min-width: 56rem) {
  .switchboard__list { columns: 2; column-gap: var(--s-2xl); }
  .switchboard__item { break-inside: avoid; }
}
/* A third column past 1600px. Each row is a phrase on the left and its service on the
   right, so a half-container column put 1060px of empty space between the two at 2560 and
   the pair stopped reading as one line. */
@media (min-width: 100rem) {
  .switchboard__list { columns: 3; }
}

.switchboard__link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2xs) var(--s-md);
  padding-block: 0.8rem;
  border-block-end: 1px solid var(--edge-dim);
  text-decoration: none;
  color: inherit;
  transition: color var(--dur-fast) var(--ease-out);
}
.switchboard__say { font-size: var(--t-small); }
.switchboard__to {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--gold-ink);
  white-space: nowrap;
}
.switchboard__link:hover .switchboard__say { color: var(--gold-ink); }

/* The ones that mean "go now" say so, and are not dressed as a browsing choice.
   These rows are `tel:` links: the destination reads as the number and the glyph is a
   handset, because an arrow promises navigation and these do not navigate. */
.switchboard__item--urgent .switchboard__say { font-weight: 600; }
.switchboard__item--urgent .switchboard__to { color: var(--ink); }
.switchboard__icon { flex: none; }
/* The arrow steps forward on hover because it is going somewhere; the handset lifts
   instead, so the two gestures cannot be mistaken for each other. */
.switchboard__link:hover .switchboard__icon,
.switchboard__link:focus-visible .switchboard__icon { transform: translateY(-1.5px) rotate(-8deg); }
.switchboard__icon { transition: transform var(--dur-mid) var(--ease-out); }
@media (prefers-reduced-motion: reduce) {
  .switchboard__icon { transition: none; }
  .switchboard__link:hover .switchboard__icon,
  .switchboard__link:focus-visible .switchboard__icon { transform: none; }
}
.switchboard__item--urgent .switchboard__to::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--gold);
}

.switchboard__none {
  margin-block-start: var(--s-lg);
  font-size: var(--t-small);
  color: var(--ink-soft);
}
.switchboard__none a { color: var(--gold-ink); font-weight: 600; }

/* --- First visit: the sensory line ---------------------------------------
 * Set apart from the step body because it answers a different question —
 * "will it hurt?" — and that is the one the reader actually carries.       */

.steps__feel {
  padding-block-start: var(--s-sm);
  border-block-start: 1px solid var(--edge-dim);
  font-size: var(--t-small);
  line-height: 1.55;
  color: var(--ink-soft);
}
.steps__feel-label {
  display: block;
  margin-block-end: 0.2rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--gold-ink);
}

/* --- The video tour -------------------------------------------------------
 * Three clips on the cut plane. The player runs flush to the plane's own
 * edges rather than floating inside a padded card, so the corner cut lands on
 * the footage itself — the one place on the site where the brand's shape is
 * taken out of a moving image.
 *
 * Native controls are left entirely alone. See the note in the template for
 * why: replacing the most recognised control on the web with a nicer-looking
 * one is a straight downgrade for the audience this section exists for.     */

.tour__plane .face {
  /* .plane > * pads every face; this one is a frame, and the padding moves
     inward to the caption where it belongs. */
  padding: 0;
  display: grid;
  grid-template-rows: auto 1fr;
  align-content: start;
}

.tour__frame {
  position: relative;
  /* Shows through while the poster decodes, and behind any letterboxing.
     Navy rather than the browser's default black keeps it in the palette. */
  background: oklch(0.148 0.058 264);
}

/*
 * The play control. A real button now, not a decorative span.
 *
 * It was `pointer-events: none` with clicks passing through to a `<video controls>`
 * underneath — so the visible affordance and the actual control were two different things,
 * both on screen at once, and a keyboard user had only the native bar. tour.js now removes
 * `controls` while this button is present and restores it the moment the button is pressed,
 * so there is exactly one control at every point in time. The native bar is still what you
 * watch with; it just stops competing with the poster.
 *
 * Large because the native bar draws a 14px triangle in the corner of a 380px poster, and
 * this section is written for people the client describes as not confident with technology.
 */
.tour__play {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  display: grid;
  place-items: center;
  width: 3.75rem;
  height: 3.75rem;
  padding-inline-start: 0.2rem;   /* optical centring for a triangle */
  border-radius: 50%;
  cursor: pointer;
  color: oklch(0.148 0.058 264);
  background: var(--gold);
  box-shadow: 0 0.5rem 1.5rem oklch(0.148 0.058 264 / 0.45);
  transition:
    scale var(--dur-mid) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}
.tour__item:hover .tour__play,
.tour__play:hover { scale: 1.06; background: var(--gold-bright); }
.tour__play:focus-visible { outline: 3px solid var(--ring); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .tour__play { transition: background-color var(--dur-fast) linear; scale: 1; }
  .tour__item:hover .tour__play,
  .tour__play:hover { scale: 1; }
}

.tour__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.tour__body {
  display: grid;
  gap: var(--s-2xs);
  align-content: start;
  padding: var(--s-lg);
}

.tour__title { font-size: var(--t-h4); }
.tour__note  { color: var(--ink-soft); font-size: var(--t-small); }

/* The length is a reassurance, not a stat: "this asks twelve seconds of you"
   is the difference between pressing play and scrolling past. */
.tour__len {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  margin-block-start: var(--s-2xs);
  font-size: var(--t-micro);
  font-weight: 500;
  color: var(--gold-ink);
}
.tour__mark { width: 0.75em; height: 0.75em; }

.section--light .tour__plane .face:hover { background: var(--bg-page-2); }

/*
 * Stacked, the rows size to their content.
 *
 * `.plane` sets `grid-auto-rows: 1fr` so shared edges line up across a row — which is worth
 * paying for side by side, and buys nothing in a single column where there is no sibling to
 * line up with. Here it made every caption as tall as the longest one, on the screen with
 * the least room to spare, under a player that is already a fixed 16:9.
 */
@media (max-width: 59.99rem) {
  .tour__plane { grid-auto-rows: auto; }
}

/* --- Payer marks: insurers, cards, financing -----------------------------
 * Real logos when the files exist, set wordmarks until then. Either way the
 * rail reads as a row of marks rather than a list of words.                */

/*
 * Rendered inside the fees column, not as a band of its own.
 *
 * As a standalone section directly under fees it restated the same six insurer names the
 * fees column had just listed as chips, 250px lower, with empty page in between. The rail
 * is now the fees column, and the duplicate well is gone.
 */
.payers--inline { align-self: start; }
.payers--inline .payers__group + .payers__group { margin-block-start: var(--s-md); }

.payers__group + .payers__group { margin-block-start: var(--s-lg); }

.payers__label {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--gold-ink);
  margin-block-end: var(--s-2xs);
}

/*
 * A grid with a track count that DIVIDES, not auto-fill.
 *
 * Two bugs in one line before this. `flex: 1 1 9rem` let the last item of a wrapped row
 * stretch into the leftover space, so "Medicare" rendered nearly twice as wide as "Cigna";
 * and `auto-fill` then fitted four columns to six marks and left two cells empty, showing
 * the rail's own grey background as holes in the grid — the ragged edge the client
 * rejected everywhere else.
 *
 * The counts are known (six insurers, five ways to pay), so the columns are chosen to
 * divide them and the odd one out spans the remainder. Every mark sits in an identical
 * cell, which is the whole point of a logo wall: the eye scans for a shape it recognises
 * and can only do that if the cells do not move.
 */
.payers__rail {
  --cols: 3;
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  gap: 2px;
  background: var(--edge-dim);
  padding: 2px;
}

/* Five marks never divide by 2 or 3, so the last one takes the empty cell beside it.
   Correct at both track counts: 3 + (1+2), and 2 + 2 + (2). */
.payers__rail[data-count="5"] > :last-child { grid-column: span 2; }

@media (max-width: 30rem) { .payers__rail { --cols: 2; } }

/* Standing alone the rail has the full container, so it runs on one line. */
@media (min-width: 60rem) {
  .payers:not(.payers--inline) .payers__rail { --cols: 6; }
}

.payer {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3.75rem;
  padding: var(--s-xs) var(--s-sm);
  background: var(--bg-page);
  transition: background-color var(--dur-mid) var(--ease-out);
}

.payers__note {
  margin-block-start: var(--s-sm);
  font-size: var(--t-micro);
  color: var(--ink-soft);
  max-width: 44ch;
}
.section--deep .payer,
.section--navy .payer { background: var(--bg-raised); }
.payer:hover { background: var(--bg-page-2); }
.section--deep .payer:hover,
.section--navy .payer:hover { background: var(--bg-raised-2); }

/*
 * Optical sizing, not arithmetic sizing.
 *
 * "Cap every logo at the same height" is the obvious rule and it is wrong: these marks
 * run from a 1:1 American Express box to a 6:1 Discover wordmark, and at equal height the
 * square one carries roughly six times the ink and shouts over the row. Bounding BOTH
 * axes and letting each mark hit whichever limit it reaches first is what makes a mixed
 * set sit on one visual line.
 */
.payer__logo {
  width: auto;
  height: auto;
  max-height: 1.9rem;
  max-width: 100%;
  object-fit: contain;
}

/*
 * The compact marks need MORE height, not less.
 *
 * I capped these lower first, reasoning that a solid square carries more ink than a
 * wordmark at equal height. Measured, that is backwards for this set: the wide marks are
 * bounded by WIDTH here, not height, so Visa lands at 102x30 while a 1.5rem American
 * Express box came out 24x24 and read as a mistake. A square has to be taller than a
 * wordmark to look the same size, not shorter.
 */
.payer__logo--american-express { max-height: 2.4rem; }
.payer__logo--mastercard { max-height: 2.1rem; }

/* The fallback. Set in the display face so a row of names reads as a considered
   set of marks rather than as body copy that failed to load. */
.payer__name {
  font-family: var(--font-display);
  font-size: var(--t-small);
  line-height: 1.2;
  text-align: center;
  color: var(--ink);
}

/* --- The jump line --------------------------------------------------------
 * A sentence offering three anchors, not a tab strip. See jump.php for why.
 *
 * It sits between the credential plane and the welcome copy, so it has to read as an
 * aside the eye can skip, not as a section competing with either. Hence: no heading,
 * no rule above it, tight vertical rhythm, and the links carrying all the colour.
 * ------------------------------------------------------------------------- */

.jump {
  padding-block: var(--s-lg);
}

/*
 * Clear the bridge.
 *
 * `.trust` carries `margin-block-end: calc(var(--bridge-h) / -2)` at this breakpoint — it
 * pulls whatever follows up underneath itself so the hero/page seam runs through the
 * plane's middle — and `z-index: 2` so it paints on top. `welcome` used to follow it and
 * absorbed the overlap in its own section padding without anyone noticing the contract.
 *
 * This line does not have that much padding, so the plane simply covered it: caught by
 * nav-check, where clicking a jump link timed out with `li.face.trust__item intercepts
 * pointer events`. Not a link that looked wrong — a link that could not be clicked.
 *
 * Same expression, same token, opposite sign. Anything else placed after `.trust` owes the
 * same amount.
 */
@media (min-width: 64rem) {
  .jump { padding-block-start: calc(var(--bridge-h) / 2 + var(--s-md)); }
}

.jump__line {
  font-size: var(--t-small);
  color: var(--ink-soft);
  line-height: 1.6;
  text-wrap: pretty;
  /* Wide enough to sit on one line at desktop — at 62ch it broke after "who you", leaving
     "will see." alone on a second line, which turns a sentence back into a control strip.
     Narrower viewports wrap it as prose, which is what `text-wrap: pretty` is for. */
  max-width: 94ch;
}

/* The one piece of emphasis, because "in a hurry" is the state this line is written for
   and it has to be recognisable before the sentence is read. */
.jump__lead {
  font-weight: 600;
  color: var(--ink);
}

.jump__to {
  color: var(--gold-ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: color-mix(in oklch, var(--gold-ink) 40%, transparent);
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1.5px;
  transition: text-decoration-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.jump__to:hover,
.jump__to:focus-visible {
  text-decoration-color: currentColor;
}

/* The band below the hero is dense — credential plane, then this, then the welcome
   heading. On a phone the line gets its own breathing room instead of being read as the
   tail of the plane above it. */
@media (max-width: 47.99rem) {
  .jump { padding-block: var(--s-md) var(--s-lg); }
}

/* --- The price band -------------------------------------------------------
 * Three figures answering the heading directly above them, on the reading surface
 * rather than in a panel: a container would make the section's own answer read as a
 * sidebar to itself. The number is the object; the label is its caption.
 * ------------------------------------------------------------------------- */

.fees__prices {
  display: grid;
  gap: var(--s-md) var(--s-lg);
  /*
   * Authored, never auto-fit. There are exactly three figures and this column is roughly
   * 600px, so `auto-fit` resolved to two tracks and dropped the third onto a row of its
   * own beside a hole — the ragged edge the client rejected sitewide. One row of three or
   * one column of three; no third state.
   */
  grid-template-columns: 1fr;
  margin-block: var(--s-lg) var(--s-sm);
  padding-block: var(--s-md);
  border-block: 1px solid var(--rule);
}
@media (min-width: 30rem) {
  .fees__prices { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.fees__price-label {
  font-size: var(--t-small);
  color: var(--ink-soft);
  margin-block-end: 0.15rem;
  text-wrap: balance;
}

.fees__price-value {
  font-family: var(--font-display);
  /* Large enough to be the thing you see, capped well under the section heading so the
     band supports the claim rather than shouting over it. */
  font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.15rem);
  line-height: 1.1;
  color: var(--ink);
  display: flex;
  align-items: baseline;
  gap: 0.35em;
}

/* "from" is the word that keeps a starting price honest, so it is always attached to the
   number and never dropped for tidiness. */
.fees__from {
  font-family: var(--font-text);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  color: var(--ink-soft);
}


.fees__note {
  font-size: var(--t-small);
  color: var(--ink-soft);
  max-width: var(--measure);
}

.fees__term {
  display: flex;
  align-items: baseline;
  gap: 0.5em;
  margin-block-start: var(--s-md);
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--ink);
  max-width: var(--measure);
}
.fees__term-mark { width: 0.75em; height: 0.75em; flex: none; color: var(--gold-deep); }

/* --- The services mosaic ---------------------------------------------------
 * `DESIGN.md:140` asks for two large faces and four medium, and the plane shipped as a
 * flat 3 x 2 of equals. The earlier attempt at unevenness pulled one face out of the
 * plane, which left five in three columns and a hole in the second row — the ragged edge
 * the client rejected — so it was flattened and the claim stayed in the docblock.
 *
 * Four columns closes the arithmetic: 2+1+1 and 1+1+2 are both exactly four, so the block
 * is a perfect rectangle with unequal faces inside it. Uneven composition, square edge.
 * ------------------------------------------------------------------------- */

.services__plane--mosaic { grid-template-columns: 1fr; }

/* Two columns is the honest intermediate: at this width a large face spans both and the
   mediums pair up, which still leaves no hole (2 + 2 + 2 across three rows). */
@media (min-width: 40rem) {
  .services__plane--mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .services__plane--mosaic .services__item--large { grid-column: span 2; }
}

@media (min-width: 64rem) {
  .services__plane--mosaic { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .services__plane--mosaic .services__item--large { grid-column: span 2; }
}

/*
 * A large face earns its size by showing more PHOTOGRAPH, not by growing its type. The
 * heading scale stays the section's — a card that sets its own display size is how a grid
 * ends up with six competing type systems.
 *
 * And the photograph has to take the slack, or the mosaic makes the problem it was meant
 * to fix worse. `grid-auto-rows: 1fr` sizes a row to its tallest face; a large face has the
 * same three lines of text as a medium one in twice the width, so it ran out of content
 * early and left roughly 170px of empty page under it — measured, and one of the reasons
 * this section read as unfinished. Letting the media absorb the remaining height turns that
 * dead space into the image the large cell exists for.
 */
/*
 * Fixed media heights, not an aspect ratio, and not `flex: 1`.
 *
 * A ratio makes the picture's height a function of the cell's width, and a large cell is
 * twice as wide — so at 16/9 its photograph came out twice as tall as a medium one, which
 * `grid-auto-rows: 1fr` then imposed on the whole row. The trapped white did not go away,
 * it moved from the large faces into the medium ones, about 500px of it.
 *
 * `flex: 1` was worse and I measured it: the media grew to fill a row whose height was
 * itself content-derived, and the cells settled at 1040px each. A feedback loop, not a
 * layout.
 *
 * Heights that do not depend on width break the loop. The large face still shows
 * materially more photograph — 17rem against 11rem, over twice the area once the extra
 * width is counted — and the two rows land within about 90px of each other.
 */
@media (min-width: 64rem) {
  .services__plane--mosaic .service-card__media .facet {
    aspect-ratio: auto;
    height: 11rem;
  }
  .services__item--large .service-card__media .facet { height: 17rem; }
  .services__plane--mosaic .service-card__media img {
    height: 100%;
    object-fit: cover;
  }
  .services__item--large .service-card__blurb { max-width: 46ch; }
  /* The action sits at the foot of the cell rather than floating under the blurb, so all
     six faces agree with each other across both rows. */
  .services__plane--mosaic .service-card__more { margin-block-start: auto; }
}


/*
 * The duplicate play affordance is NOT fixed here, deliberately.
 *
 * Each tour clip renders the custom gold cue and the browser's own control bar at the same
 * time, and the native bar covers the bottom fifth of every poster. The tempting fix is to
 * hide the native controls until first interaction — but the <video> stays focusable while
 * they are hidden, which turns a duplicated button into an invisible focus target, and this
 * section exists precisely because the native control is the one a nervous visitor already
 * knows. Doing it properly means withholding the `controls` ATTRIBUTE until interaction and
 * keeping a real button in the markup for the no-JS path, which is a rebuild of tour.js
 * rather than a polish item. Left as-is and recorded.
 */

/*
 * Short phones: the badges must clear the action bar.
 *
 * Measured at 360x640 and 375x667 with the bar rendered. The bar is `position: fixed` at
 * the foot of the viewport, and `.site { padding-block-end: var(--actionbar-h) }` only
 * keeps it off the FOOTER — nothing stopped it covering the hero while you are still at the
 * top of the page. At 360x640 it sat over "Same-day emergencies", and PRODUCT.md names that
 * phrase specifically as a must-have above the fold for the visitor who is in pain right
 * now and will not read anything.
 *
 * Height-based, not width-based: a 390x844 phone has the room and should keep the
 * composition. Only the screens that are actually short give any of it up, and what they
 * give up is air, not content.
 */
@media (max-width: 47.99rem) and (max-height: 46rem) {
  .hero { padding-block-start: calc(var(--header-h) + var(--s-xs)); }
  .hero__mark { max-width: 12rem; }
  .hero__title { margin-block-start: var(--s-xs); }
  .hero__actions { margin-block-start: var(--s-md); }
  .hero__badges { margin-block-start: var(--s-md); gap: var(--s-2xs); }
  .hero__badges .badge__face { padding: 0.42rem 0.8rem; }
}

/* --- Values: the plane ----------------------------------------------------
 * Five named values as five faces of one cut surface, on navy. See values.php for why
 * this stopped being a BARE set: it is the only object on its page and it was rendering
 * as a 192px caption strip along the foot of it.
 * ------------------------------------------------------------------------- */

.values__plane { margin-block-start: var(--s-xl); }

.values__plane .values__item {
  display: grid;
  align-content: start;
  gap: 0.35rem;
  padding: var(--s-lg) var(--s-md);
}

.values__mark {
  width: 0.85rem;
  height: 0.85rem;
  color: var(--gold);
  margin-block-end: var(--s-2xs);
}

/* On the plane the name is the object, so it steps up from the section's h4 scale. */
.values__plane .values__name { font-size: var(--t-h4); margin-block-end: 0; }
.values__plane .values__body { line-height: 1.6; }

/* A face lights on hover like every other face in the system. Nothing translates. */
.values__plane .values__item { transition: background-color var(--dur-mid) var(--ease-out); }
.values__plane .values__item:hover { background: var(--bg-raised-2); }

/* The "there is more of this elsewhere" links. A selection has to say it is a selection,
   or the count reads as the whole set. */
.testimonials__more,
.faq__more,
.first-visit__more { margin-block-start: var(--s-lg); }


/*
 * Where one group of symptoms ends and the next begins.
 *
 * Twenty-six rows carry six semantic groups and had no boundary between any of them, so the
 * list read as one undifferentiated run — and because it is set in two CSS columns, which
 * flow column-major, a reader scanning a grid of aligned equal-weight rows has no cue that
 * a column is a set rather than half a list.
 *
 * The groups are NOT labelled, and that is the section's whole premise: naming them would
 * mean printing "Restorative" and "Prosthodontics" over the one list on the site written so
 * nobody has to know those words. Space does the work instead.
 */
.switchboard__item--group-start:not(:first-child) {
  margin-block-start: var(--s-md);
}
/*
 * No `break-before: column` here, and that was the first thing I reached for.
 *
 * Six groups in a two-column layout cannot each start a column: the browser honours the
 * first break, pushes everything after it into column two, and the rest overflow the block.
 * The margin is the whole mechanism — it survives one column and two, and it does not fight
 * the multi-column algorithm for control of where a group lands.
 */
