/* src/styles/mason-park.css */
/* Fluid root font-size — webzite-house-v1. Generated by scripts/fluid-root.mjs; do not hand-edit. */
:root {
  --font-from: 18;
  --font-to: 20;
  --vw-from: calc(1920 / 100);
  --vw-to: calc(2400 / 100);
  --coefficient: calc((var(--font-to) - var(--font-from)) / (var(--vw-to) - var(--vw-from)));
  --base: calc((var(--font-from) - var(--vw-from) * var(--coefficient)) / 16);
}

html {
  font-size: calc(var(--base) * 1rem + var(--coefficient) * 1vw);
}

@media screen and (max-width: 1920px) {
  :root {
    --font-from: 16;
    --font-to: 18;
    --vw-from: calc(1440 / 100);
    --vw-to: calc(1920 / 100);
  }
}

@media screen and (max-width: 1440px) {
  :root {
    --font-from: 16;
    --font-to: 16;
    --vw-from: calc(479 / 100);
    --vw-to: calc(1440 / 100);
  }
}

@media screen and (max-width: 479px) {
  :root {
    --font-from: 12;
    --font-to: 16;
    --vw-from: calc(320 / 100);
    --vw-to: calc(479 / 100);
  }
}

/* ============================================================================
   Mason Park Dental of Katy — site stylesheet  (v2, 2026-08-28)

   THIS IS THE FIGMA DESIGN SYSTEM, NOT THE OLD WORDPRESS ONE.
   Colours, type and the border vocabulary come from the client-approved Figma
   file "Mason Park" -> page "Handoff Documentation":
     - Handoff — Color Palette   (10 tokens, hex verbatim)
     - Handoff — Typography      (three-family system, sizes verbatim)
     - Handoff — Layout & Spacing / Components & Dev Notes
   The LAYOUT is deliberately *not* a tracing of the Figma comps. The comps
   compose the page as a stack of interchangeable full-width bands, which is the
   failure mode named in deliver/brandklout/docs/DESIGN-STANDARD.md. What is kept
   is the system (palette, three type families, 1px warm-beige hairlines, generous
   88px gutters); what is rebuilt is the arrangement.

   TWO LAYERS, and the split is the point:
     1. STYLE GUIDE  — utilities, hyphenated: padding-global, container-large,
        text-size-medium, heading-style-h2, button. Reused everywhere, never
        page-specific. Adding a page must not add classes here.
     2. COMPONENTS   — custom classes with the Client-First underscore:
        <component>_<element>, e.g. service-card_icon. One block per component,
        used by every page that needs it.

   Nothing is styled by bare tag name except the document defaults below, because
   a bare-tag rule collides site-wide the moment this is pasted into a builder —
   the same failure the Client-First validator flags.

   INSTATIC: this ships as one site-wide code asset. Page HTML carries classes
   only and links no stylesheet of its own.
   ========================================================================= */

/* The three families are loaded by a <link> in the document head. An @import
   cannot live here any more: the fluid root is the first rule in this sheet and
   an @import is only valid before any other rule. */

/* ---------------------------------------------------------------- variables */
/* Hex values are verbatim from Handoff — Color Palette. The three -deep / -soft
   derivations below are ours: the Figma names no hover or tint states. */
:root {
  /* --t-ui is the UI LABEL tier. Karla, uppercase, tracked: the hardest setting
     there is to read small, and this build floors it at 12px. Below 479 the
     fluid root ramps down to 12px at 320, so the labels have to grow in rem
     terms merely to hold their pixel size. 1.24 puts .75rem at 12.1px at 360
     and 12.8px at 390. --t-text does the same job for body copy.
     Both are 1 from 479 to 1440, where the root is flat, so that whole range
     renders exactly as it did before the fluid root was installed. */
  --t-ui: 1;
  --t-text: 1;

  /* --t-head and --t-sub replace the seven clamp() font-sizes this file used to
     carry. A clamp() whose middle term is vw scales a SECOND time against a
     fluid root, so it is banned outright (see deliver/process/04-design/
     fluid-root.md rule 2). The replacement is a plain rem times a multiplier
     stepped at px breakpoints, and the multipliers are a minimax fit against
     the curve each clamp() drew: solved at the midpoint of every band, so the
     rendered size stays within a few percent of the approved design across the
     whole range instead of only at 1440.

       --t-head  the three display headings (h1, h2, rich-text h2)
       --t-sub   h3, h4, .text-size-large and .hero_lede

     Neither is restated below 479. The root is already ramping down there,
     which IS the reduction a heading wants, and a tier at 478 fires where the
     root has not moved yet and puts a step UP at the breakpoint. */
  --t-head: 1;
  --t-sub: 1;

  --brand: #8c6349;        /* Primary CTA / links — buttons, links, active accents */
  --brand-deep: #6f4d38;   /* derived: hover / pressed */
  --copper: #b78668;       /* Accent Copper — icons, decorative elements */
  --beige: #e2d5c5;        /* Warm Beige — borders, dividers, card outlines */
  --beige-mid: #ccbca6;    /* Mid Beige — secondary borders, numbered steps */
  --ink: #2e3538;          /* Dark Slate — headings, primary text, nav labels */
  --body: #545f62;         /* Medium Gray — body text, descriptions, utility bar */
  --sage: #5d7a6b;         /* Sage Green — "for kids" accent */
  --white: #ffffff;        /* Background Primary */
  --warm: #fdfcfb;         /* Background Warm — alternating warm sections */
  --sage-tint: #f4f6f4;    /* Background Sage — light sage section fill */
  --sand: #ede2d5;         /* derived: the filled panel behind financing / CTA copy */
  --muted: #8b9497;        /* derived: captions, timestamps */

  --font-display: "Newsreader", Georgia, "Times New Roman", serif;
  --font-body: "Nunito Sans", "Segoe UI", system-ui, sans-serif;
  --font-ui: "Karla", "Segoe UI", system-ui, sans-serif;

  /* Figma content area is 1744px inside a 1920px page (88px gutters). Text-led
     containers are narrower than that on purpose — 1744px of 17px body copy is
     a 200-character measure. */
  --container-xlarge: 1600px;
  --container-large: 1360px;
  --container-medium: 1040px;
  --container-small: 760px;

  --gutter: clamp(1.25rem, 4.6vw, 5.5rem);   /* 88px at 1920 */
  --radius: 2px;                              /* the comps are square; a hair of softening only */
  --radius-large: 3px;
  --hairline: 1px solid var(--beige);
  --shadow: 0 24px 60px -40px rgba(46, 53, 56, .45);
  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* The two tiers, stepped once. px breakpoints, never rem: a rem media query is
   measured against the root font-size the query is about to change. */
@media (max-width: 1279px) { :root { --t-head: .965; } }
@media (max-width: 991px)  { :root { --t-head: .86; --t-sub: .97; } }
@media (max-width: 767px)  { :root { --t-head: .75; --t-sub: .94; } }
@media (max-width: 478px)  { :root { --t-ui: 1.24; --t-text: 1.193; } }

/* ------------------------------------------------------- document defaults */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--white);
  color: var(--body);
  /* 1.0625rem is 17px at the flat root, so 479 to 1440 is unchanged. */
  font: 400 calc(1.0625rem * var(--t-text))/1.7 var(--font-body);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
img, svg, video, iframe { max-width: 100%; }
img { display: block; height: auto; }
h1, h2, h3, h4, h5, h6 { margin: 0; font-family: var(--font-display); color: var(--ink); font-weight: 400; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: var(--brand); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--brand-deep); }
button { font: inherit; }
::selection { background: var(--beige); color: var(--ink); }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* ===========================================================================
   1. STYLE GUIDE
   ======================================================================== */

/* --- structure ----------------------------------------------------------- */
.page-wrapper { overflow: clip; }
.main-wrapper { display: block; }

/* The horizontal gutter. Every section gets exactly one. */
.padding-global { padding-left: var(--gutter); padding-right: var(--gutter); }

.container-xlarge { width: 100%; max-width: var(--container-xlarge); margin-left: auto; margin-right: auto; }
.container-large { width: 100%; max-width: var(--container-large); margin-left: auto; margin-right: auto; }
.container-medium { width: 100%; max-width: var(--container-medium); margin-left: auto; margin-right: auto; }
.container-small { width: 100%; max-width: var(--container-small); margin-left: auto; margin-right: auto; }

/* Vertical rhythm. Figma sections run 95px top / 97px bottom at 1920. */
.padding-section-small { padding-top: clamp(2rem, 3vw, 3rem); padding-bottom: clamp(2rem, 3vw, 3rem); }
.padding-section-medium { padding-top: clamp(2.75rem, 4vw, 4.25rem); padding-bottom: clamp(2.75rem, 4vw, 4.25rem); }
.padding-section-large { padding-top: clamp(3.25rem, 5.2vw, 6rem); padding-bottom: clamp(3.25rem, 5.2vw, 6rem); }
.padding-section-xlarge { padding-top: clamp(4rem, 7vw, 8rem); padding-bottom: clamp(4rem, 7vw, 8rem); }

/* --- spacers ------------------------------------------------------------- */
/* Empty divs that own the gap, so no component carries a margin that only makes
   sense in one arrangement. */
.spacer-xxsmall { width: 100%; padding-top: .25rem; }
.spacer-xsmall { width: 100%; padding-top: .5rem; }
.spacer-small { width: 100%; padding-top: 1rem; }
.spacer-medium { width: 100%; padding-top: 1.5rem; }
.spacer-large { width: 100%; padding-top: 2.25rem; }
.spacer-xlarge { width: 100%; padding-top: 3.25rem; }
.spacer-xxlarge { width: 100%; padding-top: 4.5rem; }

/* --- typography ---------------------------------------------------------- */
/* Newsreader for every heading. Figma: hero 52/58.24 Light, H2 38/43.2 Light,
   section 42/46.2 Regular, doctor names 24/28.8, FAQ 20/26. */
.heading-style-h1 {
  font-family: var(--font-display); font-weight: 300;
  font-size: calc(3.25rem * var(--t-head)); line-height: 1.12;
  letter-spacing: -.012em; color: var(--ink); text-wrap: balance;
}
.heading-style-h2 {
  font-family: var(--font-display); font-weight: 300;
  font-size: calc(2.625rem * var(--t-head)); line-height: 1.14;
  letter-spacing: -.01em; color: var(--ink); text-wrap: balance;
}
.heading-style-h3 {
  font-family: var(--font-display); font-weight: 400;
  font-size: calc(1.6rem * var(--t-sub)); line-height: 1.22;
  color: var(--ink); text-wrap: balance;
}
.heading-style-h4 {
  font-family: var(--font-display); font-weight: 400;
  font-size: calc(1.3rem * var(--t-sub)); line-height: 1.28; color: var(--ink);
}
.heading-style-h5 { font-family: var(--font-display); font-weight: 400; font-size: 1.1rem; line-height: 1.3; }
.heading-style-h6 {
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui)); line-height: 1.5;
  letter-spacing: .16em; text-transform: uppercase; color: var(--body);
}

.text-size-tiny { font-size: calc(.8rem * var(--t-text)); line-height: 1.55; }
.text-size-small { font-size: calc(.94rem * var(--t-ui)); line-height: 1.65; }
.text-size-regular { font-size: 1rem; line-height: 1.7; }
.text-size-medium { font-size: 1.06rem; line-height: 1.7; }
.text-size-large { font-size: calc(1.3rem * var(--t-sub)); line-height: 1.6; }

.text-weight-normal { font-weight: 400; }
.text-weight-medium { font-weight: 500; }
.text-weight-semibold { font-weight: 600; }
.text-weight-bold { font-weight: 700; }

.text-color-ink { color: var(--ink); }
.text-color-white { color: var(--white); }
.text-color-accent { color: var(--brand); }

.text-align-center { text-align: center; }
.align-center { margin-left: auto; margin-right: auto; }

.text-style-muted { color: var(--muted); }
.text-style-allcaps { text-transform: uppercase; letter-spacing: .14em; }

/* The eyebrow is the system's signature: Karla, 11px, .2em tracking, copper,
   with a short rule that ties it to the heading beneath. */
.text-style-eyebrow {
  display: flex; align-items: center; gap: .75rem;
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui)); line-height: 1.7;
  letter-spacing: .2em; text-transform: uppercase; color: var(--copper);
  margin-bottom: .9rem;
}
.text-style-eyebrow::after {
  content: ""; flex: 0 0 auto; width: 2.25rem; height: 1px; background: var(--beige-mid);
}
.is-centered .text-style-eyebrow { justify-content: center; }
.is-centered .text-style-eyebrow::before {
  content: ""; flex: 0 0 auto; width: 2.25rem; height: 1px; background: var(--beige-mid);
}

.max-width-xsmall { max-width: 22rem; }
.max-width-small { max-width: 30rem; }
.max-width-medium { max-width: 40rem; }
.max-width-large { max-width: 52rem; }
.max-width-full { max-width: 100%; }

.overflow-scroll-x { overflow-x: auto; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.visually-hidden:focus {
  position: fixed; top: .75rem; left: .75rem; width: auto; height: auto; margin: 0;
  padding: .6rem 1rem; clip: auto; background: var(--ink); color: var(--white); z-index: 200;
}

/* --- backgrounds --------------------------------------------------------- */
.background-color-white { background: var(--white); }
.background-color-paper { background: var(--warm); }
.background-color-tan { background: var(--sand); }
.background-color-sage { background: var(--sage-tint); }
.background-color-slate { background: var(--body); }
.background-color-ink { background: var(--ink); }

.background-color-ink .heading-style-h1,
.background-color-ink .heading-style-h2,
.background-color-ink .heading-style-h3,
.background-color-ink .heading-style-h4,
.background-color-slate .heading-style-h1,
.background-color-slate .heading-style-h2,
.background-color-slate .heading-style-h3,
.background-color-slate .heading-style-h4 { color: var(--white); }
.background-color-ink, .background-color-slate { color: rgba(255, 255, 255, .82); }
.background-color-ink .text-style-eyebrow,
.background-color-slate .text-style-eyebrow { color: var(--beige); }
.background-color-ink .text-style-eyebrow::after,
.background-color-ink .text-style-eyebrow::before,
.background-color-slate .text-style-eyebrow::after,
.background-color-slate .text-style-eyebrow::before { background: rgba(255, 255, 255, .28); }
.background-color-ink a, .background-color-slate a { color: var(--beige); }
.background-color-ink a:hover, .background-color-slate a:hover { color: var(--white); }

/* --- buttons ------------------------------------------------------------- */
/* Figma: primary = solid #8C6349, Karla Medium white. Secondary = 1px outline.
   Both are uppercase and tracked, matching the nav vocabulary. */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  padding: 1.05rem 1.9rem; min-height: 3.25rem;
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.76rem * var(--t-ui));
  letter-spacing: .16em; text-transform: uppercase; text-decoration: none;
  color: var(--white); background: var(--brand); border: 1px solid var(--brand);
  border-radius: var(--radius); cursor: pointer;
  transition: background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.button:hover { background: var(--brand-deep); border-color: var(--brand-deep); color: var(--white); }
.button.is-secondary,
.button.is-ghost {
  background: transparent; color: var(--ink); border-color: var(--body);
}
.button.is-secondary:hover,
.button.is-ghost:hover { background: var(--ink); border-color: var(--ink); color: var(--white); }
.button.is-slate { background: var(--brand); border-color: var(--brand); color: var(--white); }
.button.is-slate:hover { background: var(--brand-deep); border-color: var(--brand-deep); }
.background-color-ink .button.is-secondary,
.background-color-ink .button.is-ghost,
.background-color-slate .button.is-secondary,
.background-color-slate .button.is-ghost { color: var(--white); border-color: rgba(255, 255, 255, .5); }
.background-color-ink .button.is-secondary:hover,
.background-color-ink .button.is-ghost:hover,
.background-color-slate .button.is-secondary:hover,
.background-color-slate .button.is-ghost:hover { background: var(--white); color: var(--ink); border-color: var(--white); }

.button-group { display: flex; flex-wrap: wrap; gap: .75rem; }

/* The quiet text link with a rule under it — used wherever a card ends. */
.link-arrow {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .18em; text-transform: uppercase; text-decoration: none;
  color: var(--brand); padding-bottom: .35rem; border-bottom: 1px solid var(--beige-mid);
  transition: border-color .25s var(--ease), color .25s var(--ease);
}
.link-arrow:hover { color: var(--brand-deep); border-color: var(--brand); }

/* A hairline the same weight as every card outline. */
.rule { height: 1px; background: var(--beige); border: 0; }

/* --- grids and splits ---------------------------------------------------- */
.layout-grid { display: grid; gap: clamp(1.25rem, 2vw, 2rem); }
.layout-grid.is-1col { grid-template-columns: 1fr; }
.layout-grid.is-2col { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.layout-grid.is-3col { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.layout-grid.is-4col { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.layout-split {
  display: grid; gap: clamp(1.75rem, 4vw, 4.5rem); align-items: center;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.layout-split.is-text-wide { grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr); }
.layout-split.is-flipped > *:first-child { order: 2; }

/* ===========================================================================
   2. COMPONENTS
   ======================================================================== */

/* --- utility bar --------------------------------------------------------- */
/* Figma: "Full-width #2E3538 background. Address, hours, phone." Kept as a thin
   line rather than a bar — it is wayfinding, not a headline. */
.topbar_component {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .5rem 1.5rem;
  padding: .55rem var(--gutter);
  background: var(--ink); color: rgba(255, 255, 255, .78);
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .14em; text-transform: uppercase;
}
.topbar_component a { color: rgba(255, 255, 255, .92); text-decoration: none; }
.topbar_component a:hover { color: var(--white); text-decoration: underline; }
.topbar_note { color: rgba(255, 255, 255, .6); }

/* --- navbar -------------------------------------------------------------- */
.navbar_component {
  position: sticky; top: 0; z-index: 90;
  background: var(--white); border-bottom: var(--hairline);
}
.navbar_container {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  min-height: 6.25rem;
}
.navbar_logo-link { display: inline-flex; flex: 0 0 auto; }
.navbar_logo { width: clamp(9.9rem, 12.5vw, 12.5rem); height: auto; }   /* the file carries its own margin since 2026-09-16 (#3) */

.navbar_menu { flex: 1 1 auto; display: flex; justify-content: center; }
.navbar_menu-list { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2.4rem); }
.navbar_item { position: relative; }
.navbar_link {
  display: inline-block; padding: .5rem 0;
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .16em; text-transform: uppercase; text-decoration: none; color: var(--ink);
  border-bottom: 1px solid transparent;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.navbar_link:hover,
.navbar_link[aria-current="page"] { color: var(--brand); border-bottom-color: var(--copper); }

.navbar_dropdown-list {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%) translateY(.4rem);
  min-width: 16rem; padding: .65rem 0;
  background: var(--white); border: var(--hairline); box-shadow: var(--shadow);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .18s var(--ease), transform .18s var(--ease), visibility .18s;
}
.navbar_item.has-dropdown:hover > .navbar_dropdown-list,
.navbar_item.has-dropdown:focus-within > .navbar_dropdown-list {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%) translateY(0);
}
.navbar_dropdown-list .navbar_item { position: relative; }
.navbar_dropdown-list .navbar_link {
  display: block; padding: .5rem 1.15rem; letter-spacing: .06em; text-transform: none;
  font-family: var(--font-body); font-size: calc(.95rem * var(--t-text)); border-bottom: 0; color: var(--body);
}
.navbar_dropdown-list .navbar_link:hover { color: var(--brand); background: var(--warm); }
.navbar_dropdown-list .navbar_dropdown-list {
  top: -.65rem; left: 100%; transform: translateX(.4rem);
}
.navbar_item.has-dropdown:hover > .navbar_dropdown-list .navbar_dropdown-list,
.navbar_dropdown-list .navbar_item.has-dropdown:hover > .navbar_dropdown-list,
.navbar_dropdown-list .navbar_item.has-dropdown:focus-within > .navbar_dropdown-list {
  transform: translateX(0);
}

.navbar_actions { display: flex; align-items: center; gap: 1.15rem; flex: 0 0 auto; }
.navbar_phone {
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.82rem * var(--t-ui)); letter-spacing: .1em;
  color: var(--ink); text-decoration: none; white-space: nowrap;
}
.navbar_phone:hover { color: var(--brand); }
.navbar_actions .button { min-height: 2.9rem; padding: .8rem 1.6rem; }

/* The hamburger is drawn here, in three background stripes, because the button
   itself cannot hold a child: Instatic's `base.button` module takes a text label
   and no children, so an inline <svg> inside it is dropped at import and the
   live button comes out empty. Painting it on the element's own background is
   the one mechanism that renders identically locally and on Instatic. */
.navbar_toggle {
  display: none; align-items: center; justify-content: center;
  width: 2.9rem; height: 2.9rem; padding: 0;
  background: transparent; border: var(--hairline); border-radius: var(--radius);
  color: var(--ink); cursor: pointer;
  background-image: linear-gradient(currentColor, currentColor),
                    linear-gradient(currentColor, currentColor),
                    linear-gradient(currentColor, currentColor);
  background-size: 1.35rem 1.5px;
  background-repeat: no-repeat;
  background-position: center calc(50% - .42rem), center 50%, center calc(50% + .42rem);
}
.navbar_scrim {
  position: fixed; inset: 0; z-index: 80; padding: 0; border: 0;
  background: rgba(46, 53, 56, .5); opacity: 0; visibility: hidden;
  transition: opacity .25s var(--ease), visibility .25s;
}
.nav-open .navbar_scrim { opacity: 1; visibility: visible; }

/* --- section heading ----------------------------------------------------- */
.section-heading_component { max-width: 46rem; margin-bottom: clamp(2rem, 3.5vw, 3.25rem); }
.section-heading_component.is-centered { margin-left: auto; margin-right: auto; text-align: center; }
.section-heading_component .text-size-medium { margin-top: 1rem; color: var(--body); }

/* --- hero ---------------------------------------------------------------- */
/* The comps put a 50/50 hero on a white page. Ours is asymmetric, the photograph
   bleeds off the right edge behind a warm mat, and the practice facts sit under
   the buttons where they answer the first question a visitor actually has. */
.hero_component { position: relative; }

.hero_split {
  display: grid; align-items: stretch;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
  min-height: min(38rem, 74vh);
}
.hero_copy {
  display: flex; flex-direction: column; justify-content: center;
  padding: clamp(2.75rem, 6vw, 6rem) clamp(1.25rem, 4.6vw, 5.5rem);
  padding-right: clamp(1.25rem, 4vw, 4.5rem);
  max-width: calc(var(--container-large) / 2 + 5.5rem);
  margin-left: auto;
}
.hero_copy .heading-style-h1 { max-width: 15ch; }
.hero_lede { margin-top: 1.35rem; max-width: 38ch; font-size: calc(1.18rem * var(--t-sub)); }
.hero_actions { margin-top: 2.15rem; }
.hero_frame { position: relative; background: var(--sand); overflow: hidden; min-height: 22rem; }
.hero_frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 20%; }
.hero_image { width: 100%; height: 100%; object-fit: cover; }
.hero_plate {
  position: absolute; left: 0; bottom: 0; z-index: 3;
  padding: 1.15rem 1.6rem; background: var(--white); border-top: var(--hairline); border-right: var(--hairline);
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui)); letter-spacing: .13em;
  text-transform: uppercase; color: var(--body);
}
.hero_plate strong { display: block; color: var(--ink); font-weight: 700; }

/* The fact strip: three short proofs on one hairline. */
.fact-strip_component {
  display: flex; flex-wrap: wrap; gap: 0 clamp(1.5rem, 3vw, 3rem);
  margin-top: 2.5rem; padding-top: 1.5rem; border-top: var(--hairline);
}
.fact-strip_item { padding: .35rem 0; }
.fact-strip_value {
  font-family: var(--font-display); font-weight: 400; font-size: 1.35rem; color: var(--ink); line-height: 1.2;
}
.fact-strip_label {
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui)); letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); margin-top: .35rem;
}

/* Legacy heroes kept for the inner pages the generic renderers build. */
.hero_component.is-overlay { display: grid; }
.hero_component.is-overlay > * { grid-area: 1 / 1; }
.hero_component.is-overlay .hero_image { width: 100%; height: clamp(15rem, 34vw, 26rem); object-fit: cover; }
.hero_overlay {
  position: relative; display: flex; align-items: flex-end;
  padding-bottom: clamp(1.75rem, 3.5vw, 3rem); padding-top: clamp(4rem, 10vw, 8rem);
  background: linear-gradient(to top, rgba(46, 53, 56, .82) 8%, rgba(46, 53, 56, .28) 55%, rgba(46, 53, 56, .05) 100%);
}
.hero_overlay .heading-style-h1 { color: var(--white); max-width: 20ch; }
.hero_overlay .text-style-eyebrow { color: var(--beige); }
.hero_overlay .text-style-eyebrow::after { background: rgba(255, 255, 255, .4); }

.hero_component.is-plain {
  background: var(--warm); border-bottom: var(--hairline);
}
.hero_component.is-plain .heading-style-h1 { max-width: 20ch; }
.hero_component.is-plain .text-size-medium { max-width: 52ch; color: var(--body); }

.hero_media { overflow: hidden; background: var(--sand); }
.hero_media img { width: 100%; height: clamp(15rem, 34vw, 30rem); object-fit: cover; }

/* --- breadcrumb ---------------------------------------------------------- */
.breadcrumb_component {
  display: flex; flex-wrap: wrap; gap: .5rem; padding: 1.1rem 0;
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .13em; text-transform: uppercase; color: var(--muted);
  border-bottom: var(--hairline);
}
.breadcrumb_item + .breadcrumb_item::before { content: "/"; margin-right: .5rem; color: var(--beige-mid); }
.breadcrumb_item a { color: var(--body); text-decoration: none; }
.breadcrumb_item a:hover { color: var(--brand); }

/* --- credential strip ---------------------------------------------------- */
/* The five badge files the practice published are WHITE artwork on transparency
   — they only exist for a dark ground, which is why the comps run this band as a
   dark slab. Kept dark for that reason; what is added is the label, because five
   unexplained marks tell a visitor nothing. */
.badge-strip_component {
  display: grid; align-items: center; gap: clamp(1.25rem, 3vw, 3rem);
  grid-template-columns: auto repeat(5, minmax(0, 1fr));
  max-width: var(--container-xlarge); margin: 0 auto;
  padding: clamp(1.75rem, 2.8vw, 2.5rem) var(--gutter);
}
.badge-strip_component::before {
  content: "Credentialed by";
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui)); letter-spacing: .18em;
  text-transform: uppercase; color: var(--beige); white-space: nowrap;
}
.badge-strip_item { display: flex; align-items: center; justify-content: center; }
.badge-strip_logo {
  /* A forced height, not a max: the five files range from a 109px square to a
     350x97 wordmark, and left at their intrinsic sizes the square one reads as
     an afterthought beside the others. */
  height: clamp(2.4rem, 3.2vw, 3.2rem); width: auto; max-width: 100%; object-fit: contain;
  opacity: .9; transition: opacity .25s var(--ease);
}
.badge-strip_item:hover .badge-strip_logo { opacity: 1; }
.section_accreditations { background: var(--body); }

/* --- value-proposition panels ------------------------------------------- */
/* Figma "Value Prop Card": bordered #E2D5C5, heading + body + image, 858px wide.
   Ours puts the image first and hangs a tag on it, so the two audiences the
   practice serves are separated at a glance rather than read for. */
.prop-card_component {
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--white); border: var(--hairline);
}
.prop-card_media { position: relative; overflow: hidden; aspect-ratio: 16 / 9; background: var(--sand); }
.prop-card_media img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
.prop-card_component:hover .prop-card_media img { transform: scale(1.03); }
.prop-card_tag {
  position: absolute; left: 0; bottom: 0;
  padding: .55rem 1.1rem; background: var(--copper); color: var(--white);
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .2em; text-transform: uppercase;
}
.prop-card_tag.is-kids { background: var(--sage); }
.prop-card_body { display: flex; flex-direction: column; gap: 1rem; padding: clamp(1.5rem, 2.6vw, 2.5rem); }
.prop-card_body .link-arrow { margin-top: .5rem; align-self: flex-start; }

/* --- service index ------------------------------------------------------- */
/* The comps use fourteen identical bordered tiles in a 4-column grid. Fourteen
   equal boxes rank nothing, so this groups them and drops the boxes for
   hairlines: the eye reads a list of treatments, not a wall of cards. */
.svc-group_component + .svc-group_component { margin-top: clamp(2.5rem, 4vw, 4rem); }
.svc-group_label {
  display: flex; align-items: center; gap: 1rem; margin-bottom: 1.25rem;
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .2em; text-transform: uppercase; color: var(--body);
}
.svc-group_label::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--beige); }

.service-card_component {
  display: flex; flex-direction: column; gap: .85rem;
  padding: clamp(1.35rem, 2vw, 1.85rem) clamp(1.15rem, 1.8vw, 1.6rem);
  text-decoration: none; background: var(--white);
  border: 1px solid transparent; border-bottom: var(--hairline);
  transition: background .25s var(--ease), border-color .25s var(--ease), transform .25s var(--ease);
}
.service-card_component:hover {
  background: var(--warm); border-color: var(--beige); transform: translateY(-2px);
}
.service-card_icon { width: 2.6rem; height: 2.6rem; color: var(--copper); }
.service-card_icon svg { width: 100%; height: 100%; display: block; }
.service-card_name {
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .15em; text-transform: uppercase; color: var(--ink);
}
.service-card_text { font-size: calc(.94rem * var(--t-ui)); line-height: 1.6; color: var(--body); }

/* --- generic card -------------------------------------------------------- */
.card_component {
  display: flex; flex-direction: column; gap: .75rem;
  padding: clamp(1.4rem, 2.2vw, 2rem);
  background: var(--white); border: var(--hairline); border-radius: var(--radius);
}
.card_component.is-link { text-decoration: none; transition: border-color .25s var(--ease), background .25s var(--ease); }
.card_component.is-link:hover { border-color: var(--beige-mid); background: var(--warm); }
.card_meta { font-size: calc(.88rem * var(--t-ui)); color: var(--muted); }

/* --- doctor card --------------------------------------------------------- */
.doctor-card_component {
  display: flex; flex-direction: column; gap: .85rem;
  text-decoration: none; background: var(--white); border: var(--hairline);
  padding-bottom: clamp(1.35rem, 2vw, 1.85rem);
  transition: border-color .25s var(--ease);
}
.doctor-card_component:hover { border-color: var(--beige-mid); }
.doctor-card_image {
  width: 100%; aspect-ratio: 4 / 3.4; object-fit: cover; object-position: center 18%;
  background: var(--sand); margin-bottom: .5rem;
}
.doctor-card_name { padding: 0 clamp(1.35rem, 2vw, 1.85rem); font-size: 1.4rem; }
.doctor-card_role {
  padding: 0 clamp(1.35rem, 2vw, 1.85rem);
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .18em; text-transform: uppercase; color: var(--copper);
}
.doctor-card_component .text-size-small { padding: 0 clamp(1.35rem, 2vw, 1.85rem); color: var(--body); }

/* --- reviews ------------------------------------------------------------- */
/* The comps specify "Google reviews screenshot". A screenshot cannot be read by
   a screen reader, does not reflow and dates instantly, so the same information
   is rebuilt as markup with the rating lockup above it. */
.review-lockup_component {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1.25rem;
  padding: 1.1rem clamp(1.25rem, 2vw, 1.75rem); margin-bottom: 1.75rem;
  background: var(--warm); border: var(--hairline);
}
.review-lockup_score { font-family: var(--font-display); font-size: 1.5rem; color: var(--ink); }
.review-lockup_label {
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .14em; text-transform: uppercase; color: var(--body);
}
.review-list_component { display: grid; gap: clamp(1rem, 1.6vw, 1.5rem); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.review-card_component {
  display: flex; flex-direction: column; gap: .85rem;
  padding: clamp(1.4rem, 2.2vw, 2rem); background: var(--white); border: var(--hairline);
}
.review-card_stars { color: var(--copper); letter-spacing: .12em; font-size: calc(.92rem * var(--t-ui)); }
.review-card_quote {
  margin: 0; font-family: var(--font-display); font-weight: 400;
  font-size: 1.06rem; line-height: 1.55; color: var(--ink);
}
.review-card_author {
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted); font-style: normal;
}

/* --- numbered steps ------------------------------------------------------ */
/* Figma "Step List Item": numeral in Newsreader 28px + step text, 840x84.
   Kept, with the hairline running the full row so the three read as one list. */
.step-list_component { display: flex; flex-direction: column; }
.step-card_component {
  display: grid; grid-template-columns: 3.25rem minmax(0, 1fr); align-items: baseline;
  gap: 1rem; padding: 1.35rem 0; border: 0; border-bottom: 1px solid rgba(255, 255, 255, .18);
  background: transparent; border-radius: 0;
}
.step-card_component:last-child { border-bottom: 0; }
.step-card_numeral {
  font-family: var(--font-display); font-weight: 300; font-size: 1.75rem;
  line-height: 1; color: var(--beige-mid);
}
.step-card_component .heading-style-h4 { font-family: var(--font-body); font-size: 1.02rem; font-weight: 400; }

/* --- FAQ ----------------------------------------------------------------- */
.faq_layout { display: grid; gap: clamp(1.5rem, 4vw, 4rem); grid-template-columns: minmax(0, .55fr) minmax(0, 1fr); align-items: start; }
.faq_intro { position: sticky; top: 8rem; }
.faq_item { border-bottom: var(--hairline); }
.faq_item:first-child { border-top: var(--hairline); }
.faq_question {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  padding: 1.35rem 0; cursor: pointer; list-style: none;
  font-family: var(--font-display); font-weight: 400; font-size: 1.16rem; line-height: 1.35; color: var(--ink);
}
.faq_question::-webkit-details-marker { display: none; }
.faq_question::after {
  content: "+"; flex: 0 0 auto; font-family: var(--font-ui); font-size: 1.4rem;
  font-weight: 500; color: var(--copper); line-height: 1; transition: transform .25s var(--ease);
}
.faq_item[open] .faq_question::after { transform: rotate(45deg); }
.faq_answer { padding: 0 0 1.5rem; max-width: 62ch; color: var(--body); }
.faq_answer > * + * { margin-top: 1rem; }

/* --- quote / retention band --------------------------------------------- */
.quote-band_component {
  display: grid; gap: clamp(1.25rem, 3vw, 3.5rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center;
}
.quote-band_component .heading-style-h2 { max-width: 16ch; }
.quote-band_text { max-width: 46ch; font-size: 1.04rem; }

/* --- financing ----------------------------------------------------------- */
.finance_panel {
  display: flex; flex-direction: column; justify-content: center; gap: 1.15rem;
  padding: clamp(1.75rem, 3.5vw, 3.25rem); background: var(--sand);
}
.finance_logo {
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1.75rem, 3.5vw, 3.25rem); background: var(--white); border: var(--hairline);
}
.finance_logo img { max-width: 18rem; }

/* --- full-bleed CTA split ------------------------------------------------ */
.cta-split_component { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; }
.cta-split_copy {
  display: flex; flex-direction: column; justify-content: center; gap: 1.15rem;
  padding: clamp(2.25rem, 5vw, 4.5rem) clamp(1.5rem, 4.6vw, 5.5rem);
  background: var(--sand);
}
.cta-split_copy .heading-style-h2 { max-width: 18ch; }
.cta-split_copy .text-size-medium { max-width: 46ch; }
.cta-split_media { position: relative; overflow: hidden; background: var(--sand); min-height: 22rem; }
.cta-split_media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cta-split_component.is-flipped .cta-split_copy { order: 2; }

/* --- info band ----------------------------------------------------------- */
.info-band_component { align-items: start; }
.info-band_component p { margin-bottom: .35rem; }
.info-band_title {
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .2em; text-transform: uppercase; color: var(--copper);
  margin-bottom: 1rem;
}

/* --- offers -------------------------------------------------------------- */
.offer-card_component {
  display: flex; flex-direction: column; gap: .85rem;
  padding: clamp(1.5rem, 2.4vw, 2.25rem); background: var(--warm); border: var(--hairline);
}
.offer-card_price { font-family: var(--font-display); font-weight: 300; font-size: 2.4rem; line-height: 1; color: var(--brand); }
.offer-card_title { color: var(--ink); }
.offer-card_body { display: flex; flex-direction: column; gap: .6rem; color: var(--body); font-size: calc(.96rem * var(--t-text)); }

/* --- lists --------------------------------------------------------------- */
.link-list_component { display: grid; gap: 0; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.link-list_item { border-bottom: var(--hairline); }
.link-list_item a {
  display: block; padding: .9rem 0; text-decoration: none; color: var(--ink);
  font-size: calc(.98rem * var(--t-text)); transition: color .2s var(--ease), padding-left .2s var(--ease);
}
.link-list_item a:hover { color: var(--brand); padding-left: .4rem; }

.hours_list { display: flex; flex-direction: column; }
.hours_row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: .6rem 0; border-bottom: var(--hairline);
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.8rem * var(--t-ui)); letter-spacing: .08em;
  text-transform: uppercase; color: var(--body);
}
.hours_row:last-child { border-bottom: 0; }
.hours_row strong { color: var(--ink); font-weight: 700; }

/* --- sidebar ------------------------------------------------------------- */
.article_layout { display: grid; gap: clamp(1.75rem, 4vw, 4rem); grid-template-columns: minmax(0, 1fr) 20rem; align-items: start; }
.sidebar_component {
  position: sticky; top: 8rem;
  display: flex; flex-direction: column; gap: 1rem;
  padding: clamp(1.5rem, 2.4vw, 2rem); background: var(--warm); border: var(--hairline);
}
.sidebar_component .button { width: 100%; }
.sidebar_list { display: flex; flex-direction: column; }
.sidebar_list li { border-bottom: var(--hairline); }
.sidebar_list li:last-child { border-bottom: 0; }
.sidebar_list a { display: block; padding: .55rem 0; font-size: calc(.94rem * var(--t-ui)); text-decoration: none; color: var(--body); }
.sidebar_list a:hover { color: var(--brand); }
.phone-link_component {
  font-family: var(--font-display); font-size: 1.4rem; color: var(--ink); text-decoration: none;
}
.phone-link_component:hover { color: var(--brand); }

/* --- rich text ----------------------------------------------------------- */
.text-rich-text { max-width: 68ch; color: var(--body); }
.text-rich-text.is-wide { max-width: 100%; }
.text-rich-text > * + * { margin-top: 1.15rem; }
.text-rich-text h2 {
  font-family: var(--font-display); font-weight: 300;
  font-size: calc(2.1rem * var(--t-head)); line-height: 1.18; color: var(--ink);
  margin-top: 2.75rem;
}
.text-rich-text h3 {
  font-family: var(--font-display); font-weight: 400; font-size: 1.35rem; line-height: 1.25;
  color: var(--ink); margin-top: 2.25rem;
}
.text-rich-text h4 {
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.8rem * var(--t-ui)); letter-spacing: .14em;
  text-transform: uppercase; color: var(--body); margin-top: 2rem;
}
.text-rich-text ul, .text-rich-text ol { display: flex; flex-direction: column; gap: .55rem; padding-left: 1.25rem; }
.text-rich-text ul { list-style: none; }
.text-rich-text ul li { position: relative; padding-left: .35rem; }
.text-rich-text ul li::before {
  content: ""; position: absolute; left: -1rem; top: .7em;
  width: .35rem; height: 1px; background: var(--copper);
}
.text-rich-text ol { list-style: decimal; }
.text-rich-text ol li { padding-left: .35rem; }
.text-rich-text img { margin-top: 1.75rem; margin-bottom: 1.75rem; border: var(--hairline); }
.text-rich-text blockquote {
  margin: 2rem 0; padding-left: 1.5rem; border-left: 2px solid var(--copper);
  font-family: var(--font-display); font-size: 1.2rem; line-height: 1.5; color: var(--ink);
}
.text-rich-text table {
  width: 100%; border-collapse: collapse; margin-top: 1.75rem;
  font-size: calc(.94rem * var(--t-ui));
}
.text-rich-text th, .text-rich-text td {
  padding: .8rem 1rem; border: var(--hairline); text-align: left; vertical-align: top;
}
.text-rich-text th {
  background: var(--warm); font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink);
}
.text-rich-text a { color: var(--brand); }

.notice_component {
  padding: 1.25rem 1.5rem; background: var(--warm);
  border: var(--hairline); border-left: 2px solid var(--copper); font-size: calc(.96rem * var(--t-text));
}
.notice_component > * + * { margin-top: .75rem; }

/* --- embeds -------------------------------------------------------------- */
.embed_component { border: var(--hairline); background: var(--warm); }
.embed_component iframe { display: block; width: 100%; height: 26rem; border: 0; }
/* The placeholder the deferred map is swapped into. On Instatic the authored
   <iframe> is published as a bare <div data-src>, which has no intrinsic height
   -- so the block collapsed to 0 and reserved nothing. Sized here so the
   chapter's layout is the same before and after site.js swaps in the real
   frame, and so the element is big enough for IntersectionObserver to see. */
.embed_component > [data-src] { display: block; width: 100%; height: 26rem; }
.embed_component.is-form iframe { height: 42rem; }

/* --- footer -------------------------------------------------------------- */
.footer_component { background: var(--ink); color: rgba(255, 255, 255, .74); }
.footer_grid {
  display: grid; gap: clamp(1.75rem, 3vw, 3.5rem);
  grid-template-columns: minmax(0, 1.15fr) repeat(3, minmax(0, 1fr));
}
.footer_logo { width: 11rem; margin-bottom: 1.15rem; filter: brightness(0) invert(1); opacity: .92; }
.footer_component .text-size-small { color: rgba(255, 255, 255, .6); max-width: 30ch; }
.footer_heading {
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui)); letter-spacing: .2em;
  text-transform: uppercase; color: var(--beige); margin-bottom: 1.15rem;
}
.footer_list { display: flex; flex-direction: column; gap: .6rem; }
.footer_list a { color: rgba(255, 255, 255, .74); text-decoration: none; font-size: calc(.96rem * var(--t-text)); }
.footer_list a:hover { color: var(--white); }
/* The hours list is an ink-on-white component; in the footer it sits on ink. */
.footer_component .hours_row { color: rgba(255, 255, 255, .62); border-bottom-color: rgba(255, 255, 255, .14); }
.footer_component .hours_row strong { color: var(--white); }

.footer_legal {
  margin-top: clamp(2.25rem, 4vw, 3.5rem); padding-top: 1.5rem;
  border-top: 1px solid rgba(255, 255, 255, .14);
  font-family: var(--font-ui); font-weight: 500; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .1em; text-transform: uppercase; color: rgba(255, 255, 255, .5);
}
.footer_legal a { color: rgba(255, 255, 255, .72); text-decoration: none; }
.footer_legal a:hover { color: var(--white); }

/* --- sticky call bar (phones only) --------------------------------------- */
.callbar_component {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 95; display: none;
  padding: .95rem 1rem; text-align: center; text-decoration: none;
  background: var(--brand); color: var(--white);
  font-family: var(--font-ui); font-weight: 700; font-size: calc(.75rem * var(--t-ui));
  letter-spacing: .16em; text-transform: uppercase;
}

/* ===========================================================================
   3. RESPONSIVE
   ======================================================================== */

@media (max-width: 1150px) {
  .navbar_menu {
    position: fixed; inset: 0 0 0 auto; z-index: 85; width: min(24rem, 86vw);
    display: block; padding: 6.5rem 1.75rem 2.5rem; overflow-y: auto;
    background: var(--white); border-left: var(--hairline);
    /* `visibility`, not just `transform`. A drawer pushed off screen with a
       transform is still in the accessibility tree and still focusable, so a
       keyboard or switch user tabbing off the logo walked through FIFTY TWO
       invisible links, at x=415 on a 390px screen, before reaching the page.
       `visibility: hidden` takes them out of the tab order; transitioning it
       alongside the transform keeps them present for the whole slide out, which
       is the same mechanism `.navbar_scrim` above already uses. */
    transform: translateX(100%); visibility: hidden;
    transition: transform .3s var(--ease), visibility .3s;
  }
  .nav-open .navbar_menu { transform: translateX(0); visibility: visible; }
  .navbar_menu-list { flex-direction: column; align-items: stretch; gap: 0; }
  .navbar_item { border-bottom: var(--hairline); }
  .navbar_link { display: block; padding: .95rem 0; }
  .navbar_dropdown-list {
    position: static; transform: none; opacity: 1; visibility: visible; pointer-events: auto;
    min-width: 0; padding: 0 0 .75rem .9rem; border: 0; box-shadow: none;
    display: none;
  }
  .navbar_item.is-open > .navbar_dropdown-list { display: block; }
  .navbar_item.has-dropdown:hover > .navbar_dropdown-list { display: none; }
  .navbar_item.has-dropdown.is-open:hover > .navbar_dropdown-list { display: block; }
  .navbar_dropdown-list .navbar_item { border-bottom: 0; }
  .navbar_dropdown-list .navbar_link { padding: .5rem 0; }
  /* THE HEADER TRAPPING ITS OWN CLOSE BUTTON.
     The drawer is `position: fixed; z-index: 85` and the toggle was static, and
     a positioned element paints above a non-positioned one whatever the DOM
     order. The drawer's own 6.5rem of top padding is exactly the strip the
     toggle sits in, so with the menu open the point at the centre of the button
     hit-tested to a `.navbar_link`: tapping to close the drawer NAVIGATED
     instead. Both live inside the header's stacking context, so one z-index
     above the drawer is the whole fix. Found by driving the drawer, never by a
     screenshot: the button is drawn correctly, it is just not on top. */
  .navbar_toggle { display: inline-flex; position: relative; z-index: 86; }
  .navbar_phone { display: none; }
  .navbar_container { min-height: 5.25rem; }

  .badge-strip_component { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .badge-strip_component::before { grid-column: 1 / -1; text-align: center; }

  .article_layout { grid-template-columns: minmax(0, 1fr); }
  .sidebar_component { position: static; }
  .faq_intro { position: static; }
}

@media (max-width: 999px) {
  .layout-grid.is-4col { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .layout-grid.is-3col { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .review-list_component { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero_split { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .hero_copy { max-width: none; margin-left: 0; padding-bottom: clamp(2.25rem, 5vw, 3.5rem); }
  .hero_frame { min-height: 20rem; }
  .cta-split_component { grid-template-columns: minmax(0, 1fr); }
  .cta-split_media { min-height: 16rem; }
  .faq_layout { grid-template-columns: minmax(0, 1fr); }
  .quote-band_component { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 767px) {
  /* 1rem, not 16px. From 479 to 767 the root IS 16px so this renders exactly as
     it did; below 479 it now follows the fluid root down and is caught by
     --t-text, which is what keeps body copy above the 16px floor at 390. */
  body { font-size: calc(1rem * var(--t-text)); }
  .layout-grid.is-4col,
  .layout-grid.is-3col,
  .layout-grid.is-2col { grid-template-columns: minmax(0, 1fr); }
  .layout-split { grid-template-columns: minmax(0, 1fr); }
  .layout-split.is-text-wide { grid-template-columns: minmax(0, 1fr); }
  .layout-split.is-flipped > *:first-child { order: 0; }
  .review-list_component { grid-template-columns: minmax(0, 1fr); }
  .link-list_component { grid-template-columns: minmax(0, 1fr); }
  .footer_grid { grid-template-columns: minmax(0, 1fr); }
  .badge-strip_component { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .topbar_component { justify-content: center; text-align: center; }
  .topbar_note { display: none; }
  .callbar_component { display: block; }
  .footer_component { padding-bottom: 3.5rem; }
  .fact-strip_component { gap: 0 1.5rem; }
  .embed_component iframe { height: 20rem; }
  .embed_component.is-form iframe { height: 46rem; }
  .hero_plate { padding: .85rem 1.15rem; }
  .button-group { width: 100%; }
  .button-group > .button { flex: 1 1 100%; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

@media print {
  .navbar_component, .topbar_component, .callbar_component, .footer_component, .sidebar_component { display: none; }
}

/* ===========================================================================
   THE JOURNEY LAYER — Mason Park Dental
   Appended to site.css at build time, so the site still ships one stylesheet.

   WHY THIS EXISTS. The 2026-08-28 design took the Figma handoff literally and
   produced a page the team called ugly and simple, correctly: thirteen bands of
   equal weight, fourteen equal tiles, six equal review boxes, and body copy set
   at 17px everywhere so nothing on the page was louder than anything else. A
   page with no hierarchy has no voice.

   WHAT IS KEPT FROM THE HANDOFF: the ten colour tokens and the three type
   families. Nothing else. That is the standing instruction for a handed-off
   style guide, and it is the right one, because a colour palette is a brand
   asset and a section layout is not.

   WHAT IS ELEVATED:

   1. TYPE DOES THE WORK. The display face runs to 6.4rem at desktop against a
      0.7rem uppercase Karla label. That ratio is roughly 9:1. The old page's
      widest ratio was 2.5:1, which is why every section read at the same
      volume. Sizes are plain rem stepped by unitless multipliers at px
      breakpoints (the mechanism the reference build uses), never clamp() on a
      fluid root, which would scale twice.

   2. ATMOSPHERE SHIFTS. `data-theme` on the section, not a background colour
      class. Light, ink, warm, ink again. Every rule below paints from the six
      theme names, never a raw hex, so a chapter can be flipped by changing its
      scope rather than rewriting its rules.

   3. THE STONE. The old site had a plaster texture behind its editorial bands
      and it is the one thing worth carrying forward from it. Here it is drawn,
      not downloaded: a two octave fractal turbulence in an inline SVG data URI,
      multiplied over the warm ground at 4% and tinted with the beige token. It
      is under 400 bytes, resolution independent, and cannot 404.

   4. NO EQUAL GRIDS. Every chapter is a different shape: full bleed, pinned
      statement, asymmetric pair, alternating arcs, tall plates, horizontal
      track, quote, split. Two adjacent sections never share a layout.
   ======================================================================== */

/* ---------------------------------------------------------------- theme */
:root {
  --ink-deep: #1e2426;      /* derived: the ground of a dark chapter */
  --ink-mid: #262d30;       /* derived: a raised panel on that ground */
  --paper: #f7f3ee;         /* derived: the warm editorial ground */

  /* Six names. Every chapter paints from these and nothing else. */
  --bg: var(--white);
  --bg-2: var(--warm);
  --panel: var(--white);
  --fg: var(--ink);
  --fg-body: var(--body);
  --fg-soft: var(--muted);
  --rule: var(--beige);
  --rule-strong: var(--beige-mid);
  --accent: var(--brand);
  --accent-lg: var(--copper);

  /* ------------------------------------------------------------------
     THE TYPE SCALE — Dr. Nahlah's proportions, on the house fluid root.

     The root now interpolates with viewport width (theme/fluid-root.css, the
     first rule in the shipped sheet), so every rem below is viewport-relative
     for free: type, spacing, radii and the container width all move together.
     That is the answer to "the container seems too small". At 1440 the root is
     16px and the content box is 1560px, exactly as it was; at 1920 the root is
     18px and the same token resolves to 1755px, so the design fills a large
     monitor instead of being stranded in the middle of it.

     Sizes are plain rem times a unitless multiplier, stepped at px
     breakpoints. Never clamp() on a font-size: the root is already doing the
     fluid work and a clamp() with a live vw term on top of it scales twice.
     Breakpoints are Webflow's own (1279 / 991 / 767 / 478), so the scale maps
     one to one onto Designer breakpoints if this is ever converted.

     The five groups, and the ratios, are Dr. Nahlah's, measured out of
     bk-dr-nahlah/.../site-src/css/01-tokens.css rather than re-invented:

       --t-disp  the steep display slopes: the arrival headline, the numerals
       --t-lg    the moderate display slopes: chapter headings, statements
       --t-mid   card and section headings
       --t-sm    headings sitting just above body copy
       --t-text  body copy and labels

     NOTE the missing --t-disp tier at 478. Below 479 the root itself is already
     shrinking, and that IS the reduction display type wants; a tier there fires
     at 478, where the root has not yet moved, and produces a step UP at the
     breakpoint. Only the text group needs that tier, to stop body copy
     following the root down past the 16px floor.
     ------------------------------------------------------------------ */
  /* --t-text and --t-ui are NOT declared here. site.css owns them, and this
     file is concatenated after it: re-declaring either at equal specificity
     would win at every width and silently disable the phone tier across the
     whole site. Only the display groups belong to the journey layer. */
  --t-disp: 1; --t-lg: 1; --t-mid: 1; --t-sm: 1;

  --f-d1: calc(6.66rem * var(--t-disp));   /* arrival headline. 107px at 1440 */
  --f-d2: calc(4.68rem * var(--t-disp));   /* chapter headlines */
  --f-d3: calc(3.24rem * var(--t-lg));     /* the pinned statement, the quote */
  --f-h3: calc(1.71rem * var(--t-mid));    /* arc and card headings */
  --f-h4: calc(1.25rem * var(--t-sm));
  --f-lede: calc(1.125rem * var(--t-text)); /* the one paragraph per chapter */
  --f-body: calc(.975rem * var(--t-text));
  --f-label: calc(.75rem * var(--t-ui));    /* Karla, uppercase. FLOORED at 12px */

  /* Spacing and the container, in rem so they ride the root too. 97.5rem is
     1560px at the flat root, which is Dr. Nahlah's --maxw exactly. */
  --maxw: 97.5rem;
  --ch-pad: 9rem;     /* the vertical rhythm of a chapter */
  --bleed: 4.5rem;    /* the outer gutter, Dr. Nahlah's --gutter ceiling */
}

@media (max-width: 1279px) { :root { --t-disp: .816; --t-lg: .816; --t-mid: .812; --t-sm: .834; --ch-pad: 7.5rem; --bleed: 3.5rem } }
@media (max-width: 991px)  { :root { --t-disp: .688; --t-lg: .678; --t-mid: .75;  --t-sm: .82;  --ch-pad: 6.5rem; --bleed: 2.5rem } }
@media (max-width: 767px)  { :root { --t-disp: .534; --t-lg: .594; --ch-pad: 5.25rem; --bleed: 1.5rem } }
/* No --t-disp here, deliberately. See the note above. */
@media (max-width: 478px)  { :root { --t-lg: .691; --t-mid: .872; --t-sm: .95; --ch-pad: 4.5rem } }

.ch[data-theme="dark"] {
  --bg: var(--ink-deep); --bg-2: var(--ink-mid); --panel: var(--ink-mid);
  --fg: #ffffff;
  --fg-body: rgba(255, 255, 255, .76);
  --fg-soft: rgba(255, 255, 255, .55);
  --rule: rgba(255, 255, 255, .14);
  --rule-strong: rgba(255, 255, 255, .3);
  --accent: #d9b79c;      /* the brand, taken light enough to clear AA on ink */
  --accent-lg: var(--copper);
  background: var(--bg);
  color: var(--fg-body);
}
.ch[data-theme="warm"] {
  --bg: var(--paper); --bg-2: var(--white); --panel: var(--white);
  background: var(--bg);
}

/* ------------------------------------------------------------- chapter shell */
.ch {
  position: relative;
  background: var(--bg);
  color: var(--fg-body);
  padding: var(--ch-pad) 0;
  overflow: clip;
}
.ch .wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--bleed);
  padding-right: var(--bleed);
}
.ch h2 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d2);
  line-height: 1.04;
  letter-spacing: -.018em;
  color: var(--fg);
  max-width: 17ch;
}
.ch h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--f-h3);
  line-height: 1.16;
  color: var(--fg);
}
.ch p { color: var(--fg-body); }
.ch em { font-style: italic; color: var(--accent-lg); }

/* The warm and dark grounds carry the plaster. Applied on a pseudo element so
   it never tints the content, and pinned to the section so it does not scroll
   against it. */
.ch[data-theme="warm"]::before,
.ch[data-theme="dark"]::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--stone);
  background-size: 240px 240px;
  opacity: .045;
  pointer-events: none;
  z-index: 0;
}
.ch[data-theme="dark"]::before { opacity: .07; }
.ch > * { position: relative; z-index: 1; }

/* ------------------------------------------------------------- chapter tag */
/* The continuity device. Named and animated in from the left, so a visitor
   always knows which beat they are in. The numeral was removed site-wide on
   client feedback: see the `tag` helper in site/chapters.mjs. */
.chapter-tag {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin: 0 0 1.6rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.chapter-tag i {
  width: 2.6rem;
  height: 1px;
  background: var(--accent);
  flex: none;
  transform-origin: left center;
}
.chapter-tag b { font-weight: 500; color: var(--accent); }

/* ------------------------------------------------------------------ buttons */
/* The style guide button is 13px Karla in a 2px box. At the sizes this page
   works in it disappeared, so the journey layer has its own scale. */
.ch .button,
.ch a.button {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  padding: 1.05rem 1.9rem;
  border: 1px solid var(--brand);
  border-radius: 2px;
  background: var(--brand);
  color: #fff;
  font-family: var(--font-ui);
  font-size: calc(.8rem * var(--t-text));
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  position: relative;
  overflow: hidden;
  transition: color .35s var(--ease), border-color .35s var(--ease);
}
/* The fill wipes up from the bottom rather than cross fading, so the hover has
   a direction. */
.ch .button::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform .45s var(--ease);
  /* BEHIND the label. The labels are bare text nodes, which `> *` never
     lifts, so at z-index 0 the fill covered the words: white on ink and ink
     on white both vanished on hover (BugHerd #54, #55, 2026-09-16). */
  z-index: -1;
}
.ch .button { isolation: isolate; }
.ch .button > * { position: relative; z-index: 1; }
.ch .button:hover { color: #fff; border-color: var(--ink); }
.ch .button:hover::after { transform: translateY(0); }
.ch .button.is-lg { padding: 1.2rem 2.3rem; }
.ch .button.is-ghost-light {
  background: transparent;
  border-color: rgba(255, 255, 255, .45);
  color: #fff;
}
.ch .button.is-ghost-light::after { background: #fff; }
.ch .button.is-ghost-light:hover { color: var(--ink); border-color: #fff; }

.ch .link-arrow {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--rule-strong);
  padding-bottom: .45rem;
  transition: gap .3s var(--ease), border-color .3s var(--ease);
}
.ch .link-arrow:hover { gap: 1.1rem; border-color: var(--accent); color: var(--accent); }
.ch .link-arrow.is-light { color: #fff; }

/* ===========================================================================
   CHAPTER 00 — ARRIVAL
   Full bleed, the practice's own team photograph, one sentence set very large.
   The old hero put the photo in a box beside a paragraph. A box beside a
   paragraph is a brochure.
   ======================================================================== */
.ch-arrival {
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding: calc(var(--jr-nav-h, 5.5rem) + 1.5rem) 0 clamp(3rem, 7vh, 6rem);
  color: #fff;
}
.ch-arrival::before { display: none; }   /* the photograph is the texture here */
.ar-bg { position: absolute; inset: -6% 0; z-index: 0; }
.ar-bg img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 32%; }
/* Two scrims. A vertical one so the copy has a floor and the header has a
   ceiling, and a horizontal one so the left column always reads regardless of
   what the photograph is doing on that side. */
.ar-veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(30, 36, 38, .72) 0%, rgba(30, 36, 38, .25) 34%, rgba(30, 36, 38, .55) 68%, rgba(30, 36, 38, .93) 100%),
    linear-gradient(94deg, rgba(30, 36, 38, .82) 0%, rgba(30, 36, 38, .45) 46%, rgba(30, 36, 38, .08) 82%);
}
.ar-in {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed);
}
.ar-in .chapter-tag { color: rgba(255, 255, 255, .72); }
.ar-in .chapter-tag i { background: var(--copper); }
.ar-in .chapter-tag b { color: #fff; }
.ar-title {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d1);
  line-height: .98;
  letter-spacing: -.028em;
  color: #fff;
  margin: 0 0 1.6rem;
  max-width: 15ch;
}
.ar-title em { font-style: italic; color: #e3c3a8; }
.ar-lede {
  max-width: 46ch;
  font-size: var(--f-lede);
  line-height: 1.62;
  color: rgba(255, 255, 255, .84);
  margin: 0 0 2.4rem;
}
.ar-actions { display: flex; flex-wrap: wrap; gap: .9rem; margin-bottom: 3.2rem; }
.ar-meta {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 5vw, 4.5rem);
  padding-top: 1.7rem;
  border-top: 1px solid rgba(255, 255, 255, .22);
}
.ar-meta div { display: grid; gap: .2rem; }
.ar-meta b {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--f-h4);
  color: #fff;
}
.ar-meta span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .6);
}
.ar-cue {
  position: absolute;
  right: var(--bleed);
  bottom: clamp(3rem, 7vh, 6rem);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: .8rem;
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .6);
}
.ar-cue i {
  width: 1px;
  height: 3.5rem;
  background: linear-gradient(180deg, rgba(255, 255, 255, .7), transparent);
  animation: cue 2.4s var(--ease) infinite;
  transform-origin: top center;
}
@keyframes cue { 0%, 100% { transform: scaleY(.35); opacity: .4 } 50% { transform: scaleY(1); opacity: 1 } }
@media (max-width: 767px) {
  .ar-cue { display: none; }
  /* The sticky call bar is fixed to the bottom edge below 768, so the hero has
     to end above it or the last row of the fact strip is permanently covered.
     `min-height: auto` because the content is what sets the height on a phone;
     a viewport unit only ever clipped it. */
  .ch-arrival { min-height: auto; padding-bottom: 5.5rem; }
  .ar-lede { margin-bottom: 1.8rem; }
  .ar-actions { margin-bottom: 2.2rem; gap: .7rem; }
  /* Full width stacked buttons pushed the fact strip off the first screen.
     They sit side by side and wrap only if they have to. */
  .ar-actions .button { flex: 1 1 auto; justify-content: center; padding-inline: 1.1rem; }
  .ar-meta { gap: 1rem 2rem; padding-top: 1.2rem; }
}

/* ===========================================================================
   CHAPTER 01 — THE RELAY
   The pain, named. The statement is written word by word as you scroll, which
   is the first of the three places scroll does work rather than trigger.
   ======================================================================== */
.ch-relay { padding: calc(var(--ch-pad) * 1.15) 0; background: var(--white); }
/* Both chapters restate their own rhythm rather than inheriting it: The Range
   ends on a link rather than an element, so it closes tighter, and Under One
   Roof opens directly under a stacked chapter at narrow widths, where two full
   measures of air read as a gap rather than a break. */
.ch-together { padding-top: var(--ch-pad); padding-bottom: 0; }
.ch-range { padding-bottom: calc(var(--ch-pad) * .8); }
@media (max-width: 899px) {
  .ch-relay { padding-bottom: calc(var(--ch-pad) * .7); }
  .ch-together { padding-top: calc(var(--ch-pad) * .8); }
}
/* `min-width: 0` on both columns, not decoration: a grid child defaults to
   min-content width, and one very long unbreakable word in a review or a URL
   is enough to push a column past its track and give the page a horizontal
   scrollbar at 390. audit.mjs also flags any class with no rule at all, which
   is what caught these four being pure JS hooks. */
.re-grid { display: grid; gap: 3rem; }
.re-copy { min-width: 0; }
.re-img { display: block; }
@media (min-width: 900px) {
  .re-grid { grid-template-columns: 1.15fr .85fr; gap: clamp(3rem, 6vw, 6rem); align-items: start; }
  /* The photograph HOLDS while the statement is written beside it. That
     pairing is the whole point of the chapter: the room stays still, the
     sentence arrives. */
  .re-side { position: sticky; top: 7rem; }
}
.ch .re-big {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1.24;
  letter-spacing: -.012em;
  color: var(--jr-unwritten);   /* the unwritten state; the scrub darkens it. Readable on its own: BugHerd #50, #64 */
  margin: 0;
}
.re-after {
  display: grid;
  gap: 1.1rem;
  max-width: 46ch;
  margin-top: 2.75rem;
  padding-top: 2rem;
  border-top: 1px solid var(--rule);
}
.re-after p { font-size: calc(1.02rem * var(--t-text)); line-height: 1.78; }
/* The turn of the chapter. It sits under the photograph rather than at the end
   of the paragraph, so the answer lands on the picture of the room it is
   describing. */
.re-turn {
  margin: 2.25rem 0 0;
  padding-top: 1.75rem;
  border-top: 2px solid var(--copper);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--f-h3);
  line-height: 1.22;
  color: var(--ink);
  max-width: 18ch;
}
.re-media { margin: 0; }
/* This photograph is 2.33:1. Cropped to a portrait frame it is a picture of a
   wall, so the frame follows the picture rather than the column. */
.re-media img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; object-position: 50% 72%; }

.re-media figcaption {
  padding-top: .9rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .08em;
  color: var(--fg-soft);
  line-height: 1.6;
}

/* ===========================================================================
   CHAPTER 02 — UNDER ONE ROOF
   The answer, argued. Figures that count, a pair of photographs that are not
   the same size, and the comparison the visitor is running in their head.
   ======================================================================== */
.tg-head { display: grid; gap: 1.75rem; margin-bottom: 4rem; }
@media (min-width: 900px) { .tg-head { grid-template-columns: 1.05fr .95fr; gap: 4rem; align-items: end; } }
.tg-lede { font-size: var(--f-lede); line-height: 1.72; max-width: 48ch; margin: 0; }

.tg-figures {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-bottom: 5rem;
}
.tg-fig { background: var(--bg); padding: 2.2rem 1.6rem; display: grid; gap: .5rem; }
.tg-fig b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(3.4rem * var(--t-lg));
  line-height: 1;
  color: var(--accent-lg);
}
.tg-fig span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
@media (max-width: 899px) { .tg-figures { grid-template-columns: repeat(2, 1fr) } }

/* Deliberately unequal: the pediatric photograph is the taller one, because the
   pediatric dentist is the differentiator. */
.tg-pair { display: grid; gap: 1.6rem; margin-bottom: 5.5rem; }
@media (min-width: 900px) {
  .tg-pair { grid-template-columns: 1.12fr .88fr; align-items: stretch; gap: clamp(2rem, 4vw, 3.5rem); }
  .tg-pair > .tg-shot { display: flex; flex-direction: column; }
  /* A FIXED ratio, not `auto`. With `aspect-ratio: auto` a PORTRAIT frame (the
     album's kid-exam, 3:4, since 2026-09-02) sized the grid row from its own
     width/height attributes and ran 370px taller than the column beside it,
     while Instatic, which drops those attributes, rendered it at 5:4 filling
     the row. 5:4 here makes the two agree, and it is what the row wants: the
     left frame lands within a line of the right column's height. */
  .tg-pair > .tg-shot img { flex: 0 0 auto; height: auto; aspect-ratio: 5 / 4; min-height: 0; }
  .tg-side { display: flex; flex-direction: column; justify-content: flex-end; }
}
/* The right column used to be two thirds dead space beside a taller
   photograph. It now carries the line that earns the picture. */
.tg-aside {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-h3);
  line-height: 1.34;
  color: var(--fg);
  max-width: 22ch;
  margin-bottom: 2.2rem;
  padding-left: 1.3rem;
  border-left: 2px solid var(--copper);
}
.tg-shot { margin: 0; }
.tg-shot img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.tg-shot figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .9rem;
  padding-top: 1.1rem;
  font-size: var(--f-body);
  line-height: 1.6;
  color: var(--fg-body);
}
.tg-pill {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--copper);
  border: 1px solid currentColor;
  padding: .35rem .7rem;
}
.tg-pill.is-kids { color: var(--sage); }

.tg-versus h3 { margin-bottom: 2rem; max-width: 24ch; }
.vs-table { border-top: 1px solid var(--rule-strong); }
.vs-row {
  display: grid;
  grid-template-columns: 1fr 3.5rem 1fr;
  align-items: center;
  gap: 1rem;
  padding: 1.35rem 0;
  border-bottom: 1px solid var(--rule);
}
.vs-row.is-head { padding: .9rem 0; }
.vs-row.is-head span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.vs-row.is-head .vs-a { color: var(--brand); }
.vs-row.is-head .vs-b { color: var(--fg-soft); }
.vs-a { color: var(--ink); font-weight: 600; font-size: calc(1rem * var(--t-text)); line-height: 1.55; }
.vs-b { color: var(--fg-soft); font-size: var(--f-body); line-height: 1.55; }
.vs-mid { display: grid; place-items: center; color: var(--rule-strong); font-size: calc(.7rem * var(--t-text)); }
.vs-mid i { width: 6px; height: 6px; border: 1px solid var(--beige-mid); transform: rotate(45deg); }
@media (max-width: 767px) {
  .vs-row { grid-template-columns: 1fr; gap: .5rem; padding: 1.1rem 0; }
  .vs-mid { display: none; }
  .vs-row.is-head { display: none; }
  .vs-a::before, .vs-b::before {
    display: block;
    font-family: var(--font-ui);
    font-size: calc(.75rem * var(--t-text));
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    margin-bottom: .3rem;
  }
  /* THE COLUMN NAMES ARE MARKUP, NOT STYLE. Below 767 the header row is
     hidden and each cell restates which column it is, and those two strings
     used to be literals here — the homepage's own headers, baked into a
     component every other page reuses. The Invisalign page's table compares
     Invisalign with traditional braces and rendered "At Mason Park / Two
     practices" over its five rows on every phone, correct on the desktop it
     was reviewed at and wrong on the width most people read it at.
     `data-label` on the cell carries it now. The literals stay underneath as
     a fallback so a row that forgets the attribute degrades to the old
     behaviour instead of to no label at all. */
  .vs-a::before { content: "At Mason Park"; color: var(--brand); }
  .vs-b::before { content: "Two practices"; color: var(--muted); }
  .vs-a[data-label]::before { content: attr(data-label); }
  .vs-b[data-label]::before { content: attr(data-label); }
}

/* The marquee. Velocity reactive, so a fast scroll visibly speeds it up. */
.tg-marquee {
  margin-top: 4rem;
  padding: 1.5rem 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  overflow: hidden;
  white-space: nowrap;
}
.mq-row { display: inline-flex; align-items: center; gap: 1.6rem; will-change: transform; }
.mq-row span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.mq-row b { color: var(--copper); font-size: calc(.5rem * var(--t-text)); }

/* ===========================================================================
   CHAPTER 03 — THE RANGE
   Three alternating arcs. Each leads with a photograph and sets its treatments
   as a hairline index with a thumbnail, so a visitor finds theirs in one pass
   instead of reading fourteen equal labels.
   ======================================================================== */
.rg-head { margin-bottom: 1.5rem; }
.rg-arc {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 3.5rem var(--bleed);
}
@media (min-width: 900px) {
  /* `start`, never `center`. Centring two columns of different heights parks a
     block of empty ground under the shorter one, which is what made the three
     arcs read as loose rather than composed. */
  .rg-arc { grid-template-columns: .92fr 1.08fr; gap: clamp(2.5rem, 5vw, 5rem); padding-block: 4.5rem; align-items: start; }
  .rg-arc.is-flipped .rg-media { order: 2; }
}
.rg-media { position: relative; overflow: hidden; }
.rg-media img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; transform: scale(1.06); }
@media (max-width: 899px) { .rg-media img { aspect-ratio: 4 / 3; } }
.rg-numeral {
  position: absolute;
  right: .12em;
  bottom: -.2em;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(11rem * var(--t-disp));
  line-height: 1;
  color: #fff;
  opacity: .95;
  letter-spacing: -.04em;
  pointer-events: none;
  /* The photographs behind this run from near white to near black, so the
     numeral carries its own shadow rather than trusting any one of them. */
  text-shadow: 0 2px 24px rgba(30, 36, 38, .55);
}
.rg-label {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .9rem;
}
.rg-body h3 { max-width: 18ch; }
.rg-text { font-size: var(--f-lede); line-height: 1.68; max-width: 46ch; margin: 1rem 0 2rem; }

.rg-index { border-top: 1px solid var(--rule); }
.rg-item { border-bottom: 1px solid var(--rule); }
.rg-item > a, .rg-item-plain {
  display: grid;
  grid-template-columns: 4.2rem minmax(0, 1fr) 1.5rem;
  align-items: center;
  gap: 1.15rem;
  padding: .7rem .4rem;
  text-decoration: none;
  color: inherit;
  transition: padding-left .35s var(--ease), background-color .35s var(--ease);
}
.rg-item > a:hover { padding-left: 1.1rem; background: var(--bg-2); }
.rg-thumb { width: 4.2rem; height: 3.4rem; overflow: hidden; background: var(--bg-2); }
.rg-thumb img {
  width: 100%; height: 100%; object-fit: cover;
  transition: filter .45s var(--ease), transform .6s var(--ease);
}
.rg-item > a:hover .rg-thumb img { filter: none; transform: scale(1.08); }
.rg-name {
  display: block;
  font-family: var(--font-display);
  font-size: calc(1.2rem * var(--t-text));
  font-weight: 400;
  color: var(--fg);
  line-height: 1.3;
}
.rg-blurb { display: block; grid-column: 2; font-size: calc(.875rem * var(--t-text)); color: var(--fg-soft); line-height: 1.45; margin-top: .15rem; }
.rg-go { color: var(--accent); opacity: 0; transform: translateX(-.5rem); transition: all .35s var(--ease); }
.rg-item > a:hover .rg-go { opacity: 1; transform: none; }
.rg-foot { margin-top: 3rem; }
@media (max-width: 899px) {
  .rg-numeral { font-size: calc(7rem * var(--t-disp)); }
  .rg-item > a, .rg-item-plain { grid-template-columns: 3.4rem minmax(0, 1fr) 1.2rem; }
  .rg-thumb { width: 3.4rem; height: 2.8rem; }
}

/* ===========================================================================
   CHAPTER 04 — THE PEOPLE
   Tall editorial plates on ink, with the one line that matters about each
   doctor pulled out ABOVE the name. The old build ran three bordered cards
   with the credential buried in the fourth line of a bio.
   ======================================================================== */
.pe-head { max-width: 52rem; margin-bottom: 4rem; }
.pe-lede { font-size: var(--f-lede); line-height: 1.7; max-width: 50ch; margin-top: 1.4rem; }
.pe-grid {
  display: grid;
  gap: 2.5rem;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed);
}
@media (min-width: 1024px) { .pe-grid { grid-template-columns: repeat(3, 1fr); gap: 2.2rem; } }
.pe-plate { display: block; position: relative; overflow: hidden; margin-bottom: 1.5rem; }
.pe-plate img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: 50% 22%;
  transform: scale(1.02);
  transition: filter .6s var(--ease), transform .8s var(--ease);
}
.pe-plate:hover img { filter: none; transform: scale(1.06); }
.pe-veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 45%, rgba(30, 36, 38, .55) 100%);
  pointer-events: none;
}
.pe-note {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .7rem;
  min-height: 2.2em;
}
.pe-card h3 { font-size: var(--f-h3); }
.pe-card h3 a { color: var(--fg); text-decoration: none; }
.pe-card h3 a:hover { color: var(--accent); }
.pe-role {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
  margin: .4rem 0 .9rem;
}
.pe-blurb { font-size: var(--f-body); line-height: 1.68; max-width: 62ch; }

/* Three columns need real width. Between 700 and 1023 they gave each bio a 33
   character measure, which is a column of confetti rather than a paragraph, so
   in that band each doctor becomes a ROW: portrait left, credential and bio
   right. Three across returns at 1024.

   Placement is explicit, not automatic. Five children auto-placed into two
   columns interleave, and the first attempt put the bio in the portrait's
   208px column while the 630px column held the role. This block also sits
   AFTER the .pe-* base rules on purpose: a later declaration of equal
   specificity beats one inside a media query, which is why the plate kept its
   bottom margin the first time. */
@media (min-width: 700px) and (max-width: 1023px) {
  .pe-card {
    display: grid;
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
    column-gap: 2rem;
    align-content: center;
  }
  .pe-plate { grid-column: 1; grid-row: 1 / span 4; align-self: start; margin-bottom: 0; }
  .pe-plate img { aspect-ratio: 4 / 5; }
  .pe-note { grid-column: 2; grid-row: 1; min-height: 0; }
  .pe-card h3 { grid-column: 2; grid-row: 2; }
  .pe-role { grid-column: 2; grid-row: 3; }
  .pe-blurb { grid-column: 2; grid-row: 4; }
}


/* The band closes the chapter, so the chapter has no padding left under it. */
.ch-people { padding-bottom: 0; }
.pe-band { position: relative; margin-top: 5rem; }
.pe-band img { width: 100%; height: clamp(20rem, 42vh, 30rem); object-fit: cover; object-position: 50% 30%; }
.pe-band-in {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 3.5rem var(--bleed) 2.2rem;
  background: linear-gradient(180deg, transparent, rgba(30, 36, 38, .9));
}
/* The fixed chapter readout lives in the bottom right corner from 992 up, and
   this band's link sits in exactly that spot. The band gives way, not the
   readout: the readout is chrome and has to stay where the eye learns to find
   it. */
@media (min-width: 900px) { .pe-band-in { padding-bottom: 5rem; } }
.pe-band-in p { color: #fff; font-size: var(--f-lede); max-width: 34ch; margin: 0; }

/* ===========================================================================
   CHAPTER 05 — THE PATH
   Pinned horizontal. The second place scroll does work. The financing answer
   is inside step three, where the objection actually lands.
   ======================================================================== */
.ch-path { padding: 0; background: var(--bg); }
/* A PINNED SCENE MUST FIT THE VIEWPORT, and after the fluid root went in this
   one did not: at 1920 the root is 18px, every rem in it grew 12.5%, and the
   scene measured 1239px inside a 1000px window. Pinned, that puts the progress
   bar and the bottom of every card permanently off screen, which is exactly
   what "the animation should work when they are in the viewport" describes.
   A scene that is 100svh tall always reports scrollHeight === clientHeight, so
   the overflow is invisible to the obvious check; verify-journey.mjs measures
   the contents against the box instead.

   The fix is to size the scene in svh rather than rem, so it is bound to the
   window instead of to the type scale. Everything inside it that would
   otherwise grow without limit is capped the same way. */
.pa-pin {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: clamp(2rem, 5svh, 4.5rem);
}
.pa-head { max-width: var(--maxw); margin: 0 auto clamp(1.5rem, 4svh, 3rem); padding: 0 var(--bleed); }
/* One step down from the other chapter headings. A scene that has to fit the
   window cannot afford the full display size, and a two line heading at --f-d2
   was 175px of the budget on its own at 1920. */
.pa-head h2 { font-size: var(--f-d3); }
.pa-head h2 { max-width: 20ch; }
.pa-track {
  display: flex;
  gap: 1.6rem;
  padding: 0 var(--bleed);
  width: max-content;
}
.pa-card {
  width: clamp(17rem, 27vw, 24rem);
  flex: none;
  border: 1px solid var(--rule);
  padding: 1.4rem;
  background: var(--panel);
  display: flex;
  flex-direction: column;
  gap: .85rem;
  transition: border-color .45s var(--ease);
}
.pa-shot { overflow: hidden; margin-bottom: .4rem; }
.pa-shot img {
  width: 100%;
  /* Height, not aspect-ratio: the card is inside a scene with a fixed height
     budget, so the photograph is the thing that has to give. */
  height: clamp(8rem, 20svh, 14rem);
  object-fit: cover;
  transition: filter .6s var(--ease);
}
.pa-card.is-on .pa-shot img { filter: none; }
.pa-no {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.6rem * var(--t-lg));
  line-height: 1;
  color: var(--accent-lg);
  opacity: .7;
}
.pa-card h3 { font-size: var(--f-h4); }
.pa-card p { font-size: var(--f-body); line-height: 1.68; }
.pa-card h3 + p { color: var(--fg-body); }
.pa-card.is-cta { background: var(--sand); border-color: var(--beige-mid); justify-content: center; }
.pa-card.is-cta h3 { font-size: var(--f-h3); }
.pa-card.is-cta .button { align-self: flex-start; margin-top: .5rem; }
.pa-call { font-size: calc(.85rem * var(--t-text)); color: var(--fg-soft); }
.pa-bar { max-width: var(--maxw); margin: clamp(1.25rem, 3svh, 2.5rem) auto 0; padding: 0 var(--bleed); }
.pa-bar i { display: block; height: 2px; background: var(--accent); transform: scaleX(0); transform-origin: left center; }
.pa-bar::before { content: ""; display: block; height: 2px; background: var(--rule); margin-bottom: -2px; }
/* Above the width where the whole track fits, pinning would hold the reader
   still while nothing moved, so the chapter becomes an ordinary row. */
.ch-path.is-static .pa-track { flex-wrap: wrap; width: auto; }
.ch-path.is-static .pa-card { width: auto; flex: 1 1 17rem; }
.ch-path.is-static .pa-bar { display: none; }
.ch-path.is-static .pa-pin { min-height: 0; display: block; padding-block: var(--ch-pad); }
.ch-path.is-static .pa-shot img { height: auto; aspect-ratio: 4 / 3; }
@media (max-width: 899px) {
  /* Below 900 there is no pin at all, so the scene goes back to document flow
     and the photograph goes back to its own proportions. */
  .pa-pin { min-height: 0; display: block; padding-block: var(--ch-pad); }
  .pa-track { overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-left: var(--bleed); -webkit-overflow-scrolling: touch; width: auto; padding-bottom: 1rem; }
  .pa-card { width: 78vw; scroll-snap-align: start; }
  .pa-shot img { filter: none; height: auto; aspect-ratio: 4 / 3; }
  /* The bar reports the pin's progress, and below 900 there is no pin: the
     track is a scroll region the reader swipes. It rendered as a hairline that
     could never fill. `.ch-path.is-static` already hides it for the same
     reason on a wide reduced-motion desktop; this is the other case. */
  .pa-bar { display: none; }
}

/* ===========================================================================
   CHAPTER 06 — THE PROOF
   One quote at display size, scrubbed word by word, then the rest as a rail.
   The old build ran six equal boxes of ninety word reviews, which nobody reads.
   ======================================================================== */
.pr-head { display: grid; gap: 2rem; margin-bottom: 4.5rem; }
@media (min-width: 900px) { .pr-head { grid-template-columns: 1.1fr .9fr; align-items: end; gap: 4rem; } }
.pr-note {
  font-size: var(--f-body);
  line-height: 1.75;
  color: var(--fg-soft);
  max-width: 42ch;
  padding-left: 1.3rem;
  border-left: 1px solid var(--rule-strong);
}

.pr-lead { display: grid; gap: 2.5rem; margin-bottom: 4.5rem; }
@media (min-width: 900px) { .pr-lead { grid-template-columns: 1.15fr .85fr; gap: clamp(2.5rem, 5vw, 5rem); align-items: center; } }
.pr-quote { position: relative; margin: 0; }
.pr-portrait { overflow: hidden; }
.pr-portrait img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; transform: scale(1.04); }
.pr-mark {
  position: absolute;
  left: -.35rem;
  top: -2.6rem;
  font-family: var(--font-display);
  font-size: calc(9rem * var(--t-lg));
  line-height: 1;
  color: var(--beige);
  z-index: 0;
}
.ch .pr-quote blockquote {
  position: relative;
  z-index: 1;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.35rem * var(--t-lg));
  line-height: 1.34;
  letter-spacing: -.008em;
  color: var(--jr-unwritten);
  max-width: 30ch;
}
.pr-quote figcaption {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-top: 2rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink);
}
.pr-rule { width: 2.5rem; height: 1px; background: var(--beige-mid); flex: none; }
.pr-quote figcaption b { font-weight: 500; color: var(--fg-soft); }
.pr-quote figcaption b::before { content: "/ "; opacity: .5; }

.pr-rail { overflow: hidden; padding: .5rem 0 1rem; }
@media (prefers-reduced-motion: reduce) {
  .pr-rail { overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-left: var(--bleed); }
  .pr-chip { scroll-snap-align: start; }
}
.pr-rail-in { display: flex; gap: 1.4rem; padding: 0 var(--bleed); will-change: transform; }
/* SIZED TO THE REVIEWS, not the other way round. This card used to be 21rem
   wide with `-webkit-line-clamp: 6`, and the practice's seven Google reviews run
   244 to 491 characters — so every single one of them rendered with an ellipsis
   that led nowhere, on a page whose own standfirst says "nothing is trimmed to
   change what it says". A clamp is a promise that the rest is somewhere else,
   and there was no somewhere else.
   The chip is wider now and has no clamp: a review is shown whole or it is not
   shown. Uneven text lengths are absorbed by the flex row, which stretches every
   chip to the tallest. */
.pr-chip {
  flex: none;
  display: flex;
  flex-direction: column;
  width: clamp(17rem, 27vw, 25rem);
  margin: 0;
  padding: 1.6rem;
  background: var(--white);
  border: 1px solid var(--rule);
}
.pr-chip p {
  font-size: var(--f-body);
  line-height: 1.68;
  color: var(--fg-body);
}
/* The row stretches every chip to the tallest, so a short review would leave
   its attribution floating in the middle of a tall card. `auto` puts it on the
   floor of the card instead and the names line up across the rail. */
.pr-chip cite {
  display: block;
  margin-top: auto;
  padding-top: 1.1rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  font-style: normal;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
}
.pr-foot { margin-top: 2.5rem; }

/* The credential strip. Ink ground, because the five marks are white artwork
   on transparency and only exist for one. */
.ch-proof { padding-bottom: 0; }
.pr-badges { margin-top: 5rem; background: var(--ink); }
.pr-badges-in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem clamp(1.5rem, 4vw, 3.5rem);
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 2rem var(--bleed);
}
.pr-badges-label {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .55);
  margin: 0;
}
.pr-badges ul { display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem clamp(1.5rem, 4vw, 3.5rem); flex: 1; justify-content: space-between; }
/* One forced height. Five marks at five intrinsic sizes told a visitor
   nothing, which is what the previous build shipped. */
.pr-badges img { height: 2.6rem; width: auto; object-fit: contain; opacity: .9; }
@media (max-width: 767px) { .pr-badges img { height: 2rem; } }

/* ===========================================================================
   CHAPTER 07 — THE INVITATION
   Everything needed to act, in one place. Nothing after it but the footer, so
   the page cannot dead end.
   ======================================================================== */
.iv-top { display: grid; gap: 3rem; }
@media (min-width: 900px) { .iv-top { grid-template-columns: 1.05fr .95fr; gap: 4.5rem; align-items: start; } }
.iv-copy { min-width: 0; }
.iv-lede { font-size: var(--f-lede); line-height: 1.7; max-width: 44ch; margin: 1.4rem 0 2.2rem; }
.iv-actions { display: flex; flex-wrap: wrap; gap: .9rem; margin-bottom: 3rem; }
.iv-facts { display: grid; gap: 1.5rem; margin: 0; padding-top: 2rem; border-top: 1px solid var(--rule); }
.iv-facts { grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 2rem 1.75rem; }
.iv-facts dt {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .6rem;
}
.iv-facts dd { margin: 0; font-size: var(--f-body); line-height: 1.7; color: var(--fg-body); }
.iv-facts dd a { color: var(--fg-body); text-decoration: none; border-bottom: 1px solid var(--rule-strong); }
.iv-facts dd a:hover { color: #fff; }
.iv-facts b { color: var(--fg); font-weight: 600; }
/* The right column leads with a PHOTOGRAPH and follows with the map. The map
   alone was a blank white rectangle on an ink ground for as long as the iframe
   took to arrive, and a permanently blank one wherever it is blocked. The
   picture is the content; the map is the wayfinding. */
.iv-aside { display: grid; gap: 1.5rem; }
.iv-shot { margin: 0; }
.iv-shot img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.iv-shot figcaption {
  padding-top: .8rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .08em;
  color: var(--fg-soft);
}
/* The embed component paints a warm background and a 26rem iframe by default.
   Both are wrong on an ink ground and against a photograph that is already
   carrying the column, so the frame is restated here rather than inherited. */
.iv-map, .iv-map .embed_component {
  background: var(--ink-mid);
  border: 1px solid var(--rule);
}
.iv-map .embed_component { border: 0; }
.iv-map .embed_component iframe {
  display: block;
  width: 100%;
  height: 15rem;
  border: 0;
  filter: grayscale(.5) contrast(1.05) brightness(.92);
}
.iv-aside .link-arrow { justify-self: start; }

.iv-faq { margin-top: 0; padding-top: 3.5rem; border-top: 1px solid var(--rule); }
.iv-top { padding-bottom: 4.5rem; }
.iv-faq h3 { margin-bottom: 1.5rem; }
.iv-faq-list { border-top: 1px solid var(--rule); margin-bottom: 2rem; }
.ch-invitation .faq_item { border-bottom: 1px solid var(--rule); }
.ch-invitation .faq_question {
  display: block;
  cursor: pointer;
  list-style: none;
  padding: 1.25rem 2.5rem 1.25rem 0;
  position: relative;
  font-family: var(--font-display);
  font-size: var(--f-h4);
  color: var(--fg);
}
.ch-invitation .faq_question::-webkit-details-marker { display: none; }
.ch-invitation .faq_question::after {
  content: "";
  position: absolute;
  right: .4rem;
  top: 50%;
  width: .7rem;
  height: .7rem;
  margin-top: -.5rem;
  border-right: 1px solid var(--accent);
  border-bottom: 1px solid var(--accent);
  transform: rotate(45deg);
  transition: transform .35s var(--ease);
}
.ch-invitation .faq_item[open] .faq_question::after { transform: rotate(-135deg); margin-top: -.2rem; }
.ch-invitation .faq_answer { padding: 0 3rem 1.5rem 0; font-size: var(--f-body); line-height: 1.75; color: var(--fg-body); }
.ch-invitation .faq_answer a { color: var(--accent); }

/* ===========================================================================
   READING PROGRESS
   Pinned to the bottom edge of the header, with the chapter readout beside it.
   ======================================================================== */
.jr-progress {
  position: fixed;
  left: 0;
  top: 0;
  height: 2px;
  width: 100%;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: left center;
  z-index: 1200;
  pointer-events: none;
}
.jr-readout {
  position: fixed;
  right: 1.1rem;
  bottom: 1.1rem;
  z-index: 1150;
  display: none;
  align-items: center;
  gap: .55rem;
  padding: .55rem .85rem;
  background: rgba(30, 36, 38, .88);
  backdrop-filter: blur(6px);
  color: #fff;
  font-family: var(--font-ui);
  font-size: calc(.75rem * var(--t-text));
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  border-radius: 2px;
}
@media (min-width: 900px) { .jr-readout.is-on { display: flex } }

/* ===========================================================================
   MOTION GUARDS
   Elements the timeline reveals start hidden, and they are revealed by CSS the
   moment the runtime says it cannot animate. `visibility` rather than
   `display`, so the layout is measured correctly before the reveal.
   ======================================================================== */
html.jr-ready [data-anim="hide"] { visibility: hidden; }
html.jr-fail [data-anim="hide"] { visibility: visible !important; }

@media (prefers-reduced-motion: reduce) {
  html [data-anim="hide"] { visibility: visible !important; }
  .ch .re-big, .ch .pr-quote blockquote { color: var(--ink) !important; }
  .ar-cue i { animation: none; }
  /* Photographs are in colour at rest everywhere since 2026-09-16 (BugHerd
     #67, #75: portraits turning colour on scroll read as inconsistent). This
     rule is kept for the scroll class it used to pair with. */
  .pa-shot img { filter: none !important; }
  * { scroll-behavior: auto !important; }
}

/* ===========================================================================
   THE CHROME, OVER A FULL BLEED HERO
   Scoped to `.has-journey`, which only a page built as chapters carries, so
   the other seventy keep the white sticky header exactly as it is.

   The old homepage put a white bar and a dark utility strip ABOVE the hero,
   which cost the top 120px of every screen and made the photograph look like
   an illustration inside a document. Here the header floats over it: the mark
   and the links invert to white, and the bar resolves to solid the moment the
   hero is behind you. `--jr-nav-h` is measured by journey.js.
   ======================================================================== */
html.jr-ready .has-journey .main-wrapper { margin-top: calc(-1 * var(--jr-nav-h, 5.5rem)); }
.has-journey .topbar_component {
  position: relative;
  z-index: 95;
  background: var(--ink-deep);
}
.has-journey .navbar_component {
  position: sticky;
  top: 0;
  z-index: 94;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .45s var(--ease), border-color .45s var(--ease);
}
.has-journey .navbar_component .navbar_logo { filter: brightness(0) invert(1); transition: filter .45s var(--ease); }
.has-journey .navbar_component .navbar_link,
.has-journey .navbar_component .navbar_phone { color: #fff; transition: color .45s var(--ease); }
/* The three bars are painted as background gradients in `currentColor`, so the
   toggle inverts by changing `color` and nothing else. Setting background-image
   here would erase them. */
.has-journey .navbar_component .navbar_toggle { color: #fff; border-color: rgba(255, 255, 255, .45); transition: color .45s var(--ease), border-color .45s var(--ease); }

/* Solid state. Applied by journey.js once the arrival chapter is behind you,
   and by the CSS fallback whenever the motion layer never boots. */
.has-journey .navbar_component.is-solid,
html:not(.jr-ready) .has-journey .navbar_component {
  background: var(--white);
  border-bottom-color: var(--beige);
}
.has-journey .navbar_component.is-solid .navbar_logo,
html:not(.jr-ready) .has-journey .navbar_component .navbar_logo { filter: none; }
.has-journey .navbar_component.is-solid .navbar_link,
html:not(.jr-ready) .has-journey .navbar_component .navbar_link { color: var(--ink); }
.has-journey .navbar_component.is-solid .navbar_phone,
html:not(.jr-ready) .has-journey .navbar_component .navbar_phone { color: var(--brand); }
.has-journey .navbar_component.is-solid .navbar_toggle,
html:not(.jr-ready) .has-journey .navbar_component .navbar_toggle { color: var(--ink); border-color: var(--beige); }

/* The mobile drawer is white on every page, so its contents must not stay
   inverted once it is open. */
body.nav-open.has-journey .navbar_component { background: var(--white); border-bottom-color: var(--beige); }
body.nav-open.has-journey .navbar_component .navbar_logo { filter: none; }
body.nav-open.has-journey .navbar_component .navbar_link { color: var(--ink); }
body.nav-open.has-journey .navbar_component .navbar_toggle { color: var(--ink); border-color: var(--beige); }

/* THE DROPDOWN IS NOT PART OF THE INVERSION. Every rule above reaches
   `.navbar_component .navbar_link` -- which includes the links inside the
   dropdown panel, and that panel is an opaque white card in all three states.
   So over the hero the panel painted white text on white: invisible, and
   invisible in a screenshot too, because a closed navbar looks correct.
   Restate the panel's own colours last, after all three states, so the card
   reads the same wherever it is opened. */
.has-journey .navbar_component .navbar_dropdown-list .navbar_link,
.has-journey .navbar_component.is-solid .navbar_dropdown-list .navbar_link,
html:not(.jr-ready) .has-journey .navbar_component .navbar_dropdown-list .navbar_link,
body.nav-open.has-journey .navbar_component .navbar_dropdown-list .navbar_link {
  color: var(--body);
}
.has-journey .navbar_component .navbar_dropdown-list .navbar_link:hover,
.has-journey .navbar_component.is-solid .navbar_dropdown-list .navbar_link:hover,
html:not(.jr-ready) .has-journey .navbar_component .navbar_dropdown-list .navbar_link:hover,
body.nav-open.has-journey .navbar_component .navbar_dropdown-list .navbar_link:hover {
  color: var(--brand);
}

/* ===========================================================================
   THE INNER PAGE PARTS
   Added with the first core page. Everything above this line was written for
   the homepage and is reused unchanged; these two are what an inner page needs
   that a homepage does not.
   ======================================================================== */

/* The compact arrival. Same shell, about two thirds the height, no scroll cue.
   An inner page's hero has to hand over quickly: the visitor arrived wanting
   the thing the page is named after, not an overture. */
.ch-arrival.is-compact { min-height: 62svh; }
.ch-arrival.is-compact .ar-title { font-size: var(--f-d2); max-width: 18ch; }
.ch-arrival.is-compact .ar-lede { margin-bottom: 2rem; }
.ch-arrival.is-compact .ar-actions { margin-bottom: 0; }
@media (max-width: 767px) { .ch-arrival.is-compact { min-height: auto; } }

/* THE SPREAD. One subject at full width, alternating down the page.
   A card is a thing in a grid of like things; a spread is a subject that gets
   the page to itself for as long as it takes to read. The measure is capped at
   58 characters because this column is wide enough to run past comfortable. */
.sp-row {
  display: grid;
  gap: 2.5rem;
  /* `start`, never `center`. Centring two columns of different heights parks a
     block of empty ground above the shorter one: a long bio next to a portrait
     left 250px of nothing above the photograph. The arcs learned this first. */
  align-items: start;
  max-width: var(--maxw);
  margin-left: auto;
  margin-right: auto;
  padding: clamp(2.5rem, 5vw, 4rem) var(--bleed);
}
@media (min-width: 900px) {
  .sp-row { grid-template-columns: .85fr 1.15fr; gap: clamp(2.5rem, 5vw, 5rem); }
  .sp-row.is-flipped .sp-media { order: 2; }
  /* The portrait holds while the bio is read past it. A face is the thing a
     nervous patient is actually here for, so it should not scroll away first. */
  .sp-media { position: sticky; top: 7rem; }
}
.sp-media { overflow: hidden; }
.sp-media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 22%;
  transform: scale(1.02);
  transition: filter .6s var(--ease), transform .8s var(--ease);
}
.sp-row:hover .sp-media img { filter: none; transform: scale(1.05); }
@media (max-width: 899px) { .sp-media img { aspect-ratio: 4 / 3; } }
.sp-eyebrow {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .8rem;
}
.sp-body h3 { font-size: var(--f-d3); font-weight: 300; letter-spacing: -.012em; max-width: 16ch; }
.sp-role {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
  margin: .7rem 0 1.4rem;
}
.sp-text { font-size: var(--f-lede); line-height: 1.75; max-width: 58ch; margin-bottom: 1rem; }
/* The one line that is about the person rather than the credential. It reads
   as an aside because that is what it is, and it is the reason a nervous
   patient picks one name over another. */
.sp-note {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-h3);
  line-height: 1.35;
  color: var(--fg);
  max-width: 30ch;
  margin: 1.75rem 0 0;
  padding-left: 1.3rem;
  border-left: 2px solid var(--copper);
}
.sp-body .link-arrow { margin-top: 1.75rem; }

/* The doctors page's three chapters. Each restates its own rhythm, because each
   ends on a different kind of element and inheriting one measure everywhere is
   what made the old build's spacing read as arbitrary. The spreads carry their
   own vertical padding, so a chapter that is nothing but spreads gives most of
   its own back. */
.ch-specialist { padding-bottom: calc(var(--ch-pad) * .45); }
.ch-generalists { padding-top: calc(var(--ch-pad) * .8); padding-bottom: calc(var(--ch-pad) * .45); }
/* Closes on the full bleed credential strip, so nothing under it. */
.ch-standard { padding-bottom: 0; }
.ch-standard .pr-badges { margin-top: clamp(2rem, 4vw, 3.5rem); }

/* A doctor's own words, as distinct from the biography written about them. The
   crawler hands these over jammed onto the end of the personal line; they are
   separated in site/pages.mjs and set here at reading size rather than at the
   aside's display size, because ninety words of Newsreader at --f-h3 is a wall. */
.sp-quote {
  margin: 1.75rem 0 0;
  padding-left: 1.3rem;
  border-left: 1px solid var(--rule-strong);
  max-width: 56ch;
}
.sp-quote p {
  font-family: var(--font-display);
  font-weight: 300;
  font-style: italic;
  font-size: var(--f-lede);
  line-height: 1.72;
  color: var(--fg-body);
}
.sp-quote p::before { content: "\201C"; color: var(--accent-lg); }
.sp-quote p::after { content: "\201D"; color: var(--accent-lg); }

/* THE COMPLETE INDEX. Cards make you read a box per item; a column of hairlines
   lets the eye run down a list the way it does in a book, which is what a page
   whose job is "show me everything" actually owes a visitor. */
.cx-index {
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem);
  max-width: var(--maxw);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--bleed);
  padding-right: var(--bleed);
}
@media (min-width: 700px) { .cx-index { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); } }
.cx-label {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--rule-strong);
  margin-bottom: .3rem;
}
.cx-group li { border-bottom: 1px solid var(--rule); }
.cx-group a, .cx-group span {
  display: block;
  padding: .7rem 0;
  font-family: var(--font-display);
  font-size: calc(1.05rem * var(--t-text));
  color: var(--fg);
  text-decoration: none;
  transition: padding-left .3s var(--ease), color .3s var(--ease);
}
.cx-group a:hover { padding-left: .6rem; color: var(--accent); }
.cx-group span { color: var(--fg-soft); }

/* The services page's two index chapters. Both end on a column index, which
   carries no trailing rule of its own, so each gives back part of its own
   measure rather than leaving a hairline stranded above a full one. */
.ch-catalogue { padding-bottom: calc(var(--ch-pad) * .75); }
.ch-cost { padding-bottom: calc(var(--ch-pad) * .75); }
.ch-catalogue .rg-head, .ch-cost .rg-head { margin-bottom: clamp(2rem, 4vw, 3.25rem); }

/* A group with many more items than its neighbours spans the row and flows in
   its own columns instead. Twenty one entries in one track beside three tracks
   of four left most of the section empty and made the long list look like an
   afterthought rather than the majority of what the practice does. */
.cx-group.is-wide { grid-column: 1 / -1; }
.cx-group.is-wide ul { columns: 3; column-gap: clamp(2rem, 4vw, 3.5rem); }
.cx-group.is-wide li { break-inside: avoid; }
@media (max-width: 999px) { .cx-group.is-wide ul { columns: 2; } }
@media (max-width: 699px) { .cx-group.is-wide ul { columns: 1; } }

/* ===========================================================================
   LONG FORM — the treatment pages
   A median of 1,958 words per page. The measure and the rail are the two things
   that turn that from a wall into something readable.
   ======================================================================== */
.lf-layout {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
  max-width: var(--maxw);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--bleed);
  padding-right: var(--bleed);
}
@media (min-width: 900px) {
  .lf-layout { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); gap: clamp(3rem, 6vw, 6rem); align-items: start; }
  .lf-rail { position: sticky; top: 7rem; }
}
/* THE MEASURE. 68 characters, and it is the single biggest thing that can be
   done for a two thousand word clinical page. */
.lf-body { max-width: 68ch; }

.lf-rail-box { border-top: 1px solid var(--rule-strong); padding-top: 1rem; }
.lf-rail-title {
  cursor: pointer;
  list-style: none;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .9rem;
}
.lf-rail-title::-webkit-details-marker { display: none; }
.lf-toc { display: grid; gap: .1rem; }
.lf-toc a {
  display: block;
  padding: .45rem 0 .45rem .9rem;
  border-left: 2px solid var(--rule);
  font-size: calc(.92rem * var(--t-text));
  line-height: 1.45;
  color: var(--fg-soft);
  text-decoration: none;
  transition: color .3s var(--ease), border-color .3s var(--ease), padding-left .3s var(--ease);
}
.lf-toc a:hover { color: var(--fg); border-color: var(--rule-strong); }
/* Set by journey.js from scroll POSITION, not from a one-shot trigger: on a
   page this long the reader needs to know where they are, continuously. */
.lf-toc a.is-here { color: var(--accent); border-color: var(--accent); padding-left: 1.15rem; }

/* The lede: the practice's own opening paragraphs, set larger than the body so
   the page starts with a voice rather than with a wall. */
.lf-lede { margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.lf-lede p {
  font-size: var(--f-lede);
  line-height: 1.75;
  color: var(--fg);
}
.lf-section { scroll-margin-top: 7rem; }
.lf-section + .lf-section { margin-top: clamp(2.25rem, 4vw, 3.25rem); }
/* THE PROSE INSIDE A SECTION. `.text-rich-text > * + *` is a DIRECT child
   selector, and the direct children of `.lf-body` are the sections, not the
   paragraphs inside them. So two consecutive <p> in one section rendered with
   no space between them at all — the paragraph break, the one piece of
   structure a wall of text still has, was invisible. It reads as one block,
   which is the exact failure "No wall of text" exists to stop.
   Found on the first service page built by hand rather than by the generator;
   `.lf-more-in > p:first-child { margin-top: 0 }` further down was already
   written as if this rule existed. */
.lf-section > * + * { margin-top: 1.15rem; }
.lf-section h2 {
  font-size: var(--f-h3);
  font-weight: 400;
  max-width: 24ch;
  margin-bottom: 1rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}
@media (max-width: 899px) {
  .lf-rail-box { border-bottom: 1px solid var(--rule); padding-bottom: 1rem; }
  .lf-toc { max-height: 17rem; overflow-y: auto; }
}

/* ===========================================================================
   THE TREATMENT PAGE CHAPTERS
   The beats of the reference flow, each restating its own rhythm because each
   holds a different amount: the treatment chapter carries most of a 2,000 word
   page, the cost chapter often carries two paragraphs.
   ======================================================================== */
.ch-qualify { padding-bottom: calc(var(--ch-pad) * .7); }
.ch-treatment { padding-bottom: calc(var(--ch-pad) * .8); }
.ch-why { padding-bottom: calc(var(--ch-pad) * .8); }
.ch-process { padding-bottom: calc(var(--ch-pad) * .8); }
.ch-compare { padding-bottom: calc(var(--ch-pad) * .8); }
.ch-questions { padding-bottom: calc(var(--ch-pad) * .85); }

/* A beat with no contents rail: one column at the same measure, so a short
   chapter does not sit in a two column frame with an empty rail beside it. */
.lf-layout.is-solo { grid-template-columns: minmax(0, 1fr); }
.lf-layout.is-solo .lf-body { max-width: 72ch; }
/* The section heading, in BOTH frames. It was written for `is-solo` only, so
   in the split frame — which is what every beat with fewer than four sections
   uses, and therefore most of a service page — the heading fell back to bare
   `.ch h3`: no rule above it, no space under it, sitting hard on its own first
   paragraph. `.lf-split .lf-section:first-child h3` further down already
   cancels a border-top that nothing was setting, which is the tell. */
.lf-layout.is-solo .lf-section h3,
.lf-split .lf-section h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--f-h3);
  color: var(--fg);
  max-width: 26ch;
  margin-bottom: .9rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}
.lf-layout.is-solo .lf-section + .lf-section { margin-top: clamp(2rem, 3.5vw, 3rem); }

/* Related treatments, in the invitation's aside rather than as a chapter of
   their own: at the end of a page about one treatment, the neighbouring ones
   are a way out, not a beat in the argument. */
.iv-related { border-top: 1px solid var(--rule); padding-top: 1.5rem; }
.iv-related .sidebar_component, .iv-related .card_component { background: transparent; border: 0; padding: 0; }
.iv-related a { color: #fff; }

/* The trust strip belongs UNDER the hero, touching it. It inherits a 5rem top
   margin from its use as the closer of The Proof on the homepage, which left it
   floating in a band of white on a treatment page. Beat two of the reference
   flow is trust, immediately, before the visitor has scrolled at all. */
.ch-arrival + .pr-badges { margin-top: 0; }
/* The breadcrumb then sits on its own line rather than adding a second measure
   of air on top of the first chapter's. */
.pr-badges + .padding-global { padding-top: 1.25rem; padding-bottom: 0; }
.ch-arrival + .pr-badges + .padding-global + .ch { padding-top: calc(var(--ch-pad) * .7); }

/* A beat with no contents rail still gets the system's asymmetric frame: the
   chapter tag and heading hold the left column and stay there while the prose
   runs past them on the right. Set as one narrow column it hugged the left edge
   with sixty percent of the page empty beside it, which reads as unfinished
   rather than as spare. */
.lf-layout.lf-split .lf-aside { min-width: 0; }
@media (min-width: 900px) {
  .lf-layout.lf-split { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); }
  .lf-layout.lf-split .lf-aside { position: sticky; top: 7rem; }
}
.lf-split .lf-aside h2 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d2);
  line-height: 1.04;
  letter-spacing: -.018em;
  color: var(--fg);
  max-width: 15ch;
}
.lf-split .lf-aside .pe-lede { margin-top: 1.25rem; max-width: 40ch; }
.lf-split .lf-body { max-width: 66ch; }
.lf-split .lf-section:first-child h3 { padding-top: 0; border-top: 0; }

/* `relatedServices` emits `<h2 class="heading-style-h4">`, and inside a chapter
   `.ch h2` is (0,1,1) against that class's (0,1,0), so it won the cascade and
   set "More services" at the chapter display size in the invitation's aside.
   Same shape as every other cascade bug in this file: order and specificity,
   not the value. Here it is a label, because that is what it is. */
.iv-related h2 {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
  max-width: none;
  margin-bottom: .9rem;
}
.iv-related .sidebar_list { display: grid; gap: .1rem; }
.iv-related .sidebar_list a {
  display: block;
  padding: .5rem 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-display);
  font-size: calc(1rem * var(--t-text));
  text-decoration: none;
}
.iv-related .sidebar_list a:hover { color: var(--accent); }
.iv-related > p { margin-top: 1rem; }
.iv-related > p a {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
}

/* A list the editor typed as paragraphs with a glyph in front of each line.
   The glyph was the bullet; this is the same list with a real marker and a
   hanging indent, so the eye can run down the labels instead of reading a block
   that only looks like prose. */
.lf-ticks { display: grid; gap: .55rem; margin: 1rem 0 1.25rem; }
.lf-ticks li {
  position: relative;
  padding-left: 1.6rem;
  line-height: 1.7;
}
.lf-ticks li::before {
  content: "";
  position: absolute;
  left: .15rem;
  top: .62em;
  width: .5rem;
  height: .5rem;
  border-left: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg);
}
.lf-ticks strong, .lf-ticks b { color: var(--fg); font-weight: 600; }

/* ---------------------------------------------------------------------------
   THE SAME LIST, SCANNED RATHER THAN READ.
   A treatment page's selling list is written as "Label. Two sentences saying
   what the label means." Six of those is 200 words and 620px of one column,
   and the reader who is deciding whether this treatment is for them wants the
   six labels, not the twelve sentences. So the label IS the row and the
   practice's own explanation is one click under it.

   Client note, 2026-09-01: "Users don't scroll to a page that has that much
   text." The answer is NOT to cut the explanation -- these pages earn search
   traffic and the copy is the practice's. Every word is still in the HTML,
   indexed, one interaction away. That is the same trade `.lf-more` makes, per
   row instead of per run.

   Native <details>: no JavaScript, works before site.js loads, and Ctrl+F
   inside a closed <details> still finds the text in current browsers.
   ------------------------------------------------------------------------ */
.lf-ticks.is-compact { gap: 0; margin-top: .75rem; }
.lf-ticks.is-compact > li { padding-left: 0; }
/* The tick moves off the row and onto the summary, because the row is now a
   control with its own padding and the marker has to line up with the label,
   not with the top of the disclosure. */
.lf-ticks.is-compact > li::before { display: none; }
.lf-ticks.is-compact summary {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  list-style: none;
  cursor: pointer;
  padding: .7rem 0 .7rem 1.6rem;
  border-bottom: 1px solid var(--rule);
  font-weight: 600;
  color: var(--fg);
  line-height: 1.45;
  transition: color .25s var(--ease);
}
.lf-ticks.is-compact summary::-webkit-details-marker { display: none; }
.lf-ticks.is-compact summary::before {
  content: "";
  position: absolute;
  left: .15rem;
  top: 1.15em;
  width: .5rem;
  height: .5rem;
  border-left: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg);
}
.lf-ticks.is-compact summary::after {
  content: "+";
  flex: 0 0 auto;
  font-family: var(--font-ui);
  font-size: 1.15rem;
  font-weight: 500;
  line-height: 1;
  color: var(--accent);
  transition: transform .25s var(--ease);
}
.lf-ticks.is-compact details[open] > summary::after { transform: rotate(45deg); }
.lf-ticks.is-compact summary:hover { color: var(--accent); }
.lf-ticks.is-compact summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lf-ticks.is-compact details > p {
  padding: .8rem 1.5rem 1rem 1.6rem;
  border-bottom: 1px solid var(--rule);
  color: var(--fg-soft);
  line-height: 1.7;
}

/* A label the editor typed as a heading because there was no other button for
   it: "Invisalign is ideal for:" above four bullets. Rendered as a heading it
   put a type-scale jump and 36px of margin between a list and the four words
   that name it, which is what made the two flagged sections read as two
   sections each. It is a lead-in, so it is set as one. */
.lf-lead {
  margin: 1.4rem 0 .2rem;
  color: var(--fg);
  font-weight: 600;
}
.lf-lead + ul, .lf-lead + ol { margin-top: .5rem; }

/* ------------------------------------------------------- the prose ceiling */
/* The tail of an over-long run of paragraphs, folded away. See site/prose.mjs
   for the rule and why the tail is kept rather than deleted: it is the
   practice's own clinical copy and it still ranks. Closed by default, so what
   the page SHOWS is never a wall, and open in one click with no script. */
.lf-more { margin: 1.1rem 0 0; }
.lf-more > summary {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  width: fit-content;
  padding: .45rem 0;
  color: var(--accent);
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}
.lf-more > summary::-webkit-details-marker { display: none; }
.lf-more > summary::after {
  content: "";
  width: .42rem;
  height: .42rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-.15em) rotate(45deg);
  transition: transform .25s ease;
}
.lf-more[open] > summary::after { transform: translateY(.1em) rotate(-135deg); }
.lf-more > summary:hover { color: var(--fg); }
.lf-more > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.lf-more-in { padding-top: .35rem; }
/* Same direct-child trap as `.lf-section`, one level deeper: the folded tail is
   always two or more paragraphs and they ran together into the block the fold
   exists to prevent. The `:first-child` reset below was already written as if
   this rule were here. */
.lf-more-in > * + * { margin-top: 1.15rem; }
.lf-more-in > p:first-child { margin-top: 0; }

/* ------------------------------------------------------ pictures in a column */
/* Until this existed a treatment page carried no photograph at all between the
   hero and the footer, for a median of 1,958 words. It breaks the measure
   deliberately — wider than the 66ch column it sits in — so the page has a
   change of rhythm and not just a picture. See site/photos.mjs for what may be
   pictured on a treatment page and what may not. */
.lf-figure {
  margin: clamp(2rem, 4vw, 3rem) 0;
  width: min(100%, 46rem);
}
.lf-figure img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: 2px;
}
.lf-figure figcaption {
  margin-top: .7rem;
  padding-left: .9rem;
  border-left: 1.5px solid var(--accent);
  color: var(--fg-soft);
  font-family: var(--font-ui);
  font-size: calc(.8125rem * var(--t-ui));
  line-height: 1.5;
}
/* The split frame's body column is narrower than the rail frame's, so the
   figure is allowed to reach past it on a wide screen. Below the stack
   breakpoint everything is one column and it stays in the measure. */
@media (min-width: 900px) {
  .lf-split .lf-figure { width: min(118%, 46rem); }
}

/* ===========================================================================
   THE SERVICE PAGE'S OWN FURNITURE — cards, not bullets
   Added 2026-09-01 on the client's note: "Let's use more cards instead of
   bullet points. Let's have more uncommon layouts and more images please.
   Remember this is for the services page. The home page is currently great."

   THE CONSTRAINT THAT SHAPES ALL OF IT: the homepage is approved and must not
   move. Every selector below is either a NEW class the homepage does not use,
   or is scoped to a chapter class that only exists on a treatment page
   (`ch-qualify`, `ch-treatment`, `ch-why`, `ch-cost`, and `.ch-arrival`'s
   `is-compact` variant). Nothing here is a bare element or a shared component.
   Check that before adding to this block.
   ======================================================================== */

/* --- the compact hero's veil ---------------------------------------------
   THE NAVBAR WAS NEVER DIFFERENT. The client read the service page's header as
   changed; it is byte-identical markup and pixel-identical geometry, colour,
   transparency and logo treatment. What changed is the PHOTOGRAPH BEHIND IT.
   The homepage's team shot is mid-dark across the top, so the veil's .72 band
   is plenty; the Invisalign featured image is a bright close-up whose blown
   highlight sits exactly under "CONTACTS" and the phone number, and white
   links on it wash out.

   The right fix is not a darker photograph, because there are 34 more
   treatment pages and 34 more featured images nobody has seen. The compact
   hero guarantees its own contrast under the chrome instead: same gradient,
   first stop taken to .88 and the falloff pushed past the header's height, so
   the top ~20% is always dark enough for white text no matter what is behind
   it. The homepage's full-height hero keeps its own veil untouched. */
.ch-arrival.is-compact .ar-veil {
  background:
    linear-gradient(180deg, rgba(30, 36, 38, .88) 0%, rgba(30, 36, 38, .66) 20%, rgba(30, 36, 38, .34) 44%, rgba(30, 36, 38, .60) 74%, rgba(30, 36, 38, .94) 100%),
    linear-gradient(94deg, rgba(30, 36, 38, .82) 0%, rgba(30, 36, 38, .45) 46%, rgba(30, 36, 38, .08) 82%);
}

/* --- the grid -------------------------------------------------------------
   `is-stagger` is the uncommon one and the reason this is not `layout-grid`:
   the even cards drop half a card, so the row reads as two overlapping ranks
   rather than a tidy line of boxes. It is a TRANSFORM, not a margin, so it
   costs no layout height and the cards below are unaffected — and it is
   confined to >=900 because a stagger in one column is just a gap. */
.svc-grid {
  display: grid;
  gap: clamp(1rem, 1.8vw, 1.75rem);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
}
@media (min-width: 900px) {
  .svc-grid.is-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .svc-grid.is-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* One card carries the argument and the rest support it. */
  .svc-grid.is-lead > *:first-child { grid-column: span 2; }
  .svc-grid.is-stagger > *:nth-child(even) { transform: translateY(2.75rem); }
  /* The stagger leaves a hole at the bottom of the odd column; the grid's own
     bottom padding closes it rather than a margin on the cards. */
  .svc-grid.is-stagger { padding-bottom: 2.75rem; }
}
@media (max-width: 599px) { .svc-grid { grid-template-columns: minmax(0, 1fr); } }

/* --- the card ------------------------------------------------------------
   Deliberately NOT `prop-card_component`: that one hardcodes `background:
   var(--white)`, which is right on paper and wrong on the warm and dark
   grounds these chapters use. This reads `--panel`, so the same card is white
   on warm and ink-mid on dark without a second rule. */
.svc-card {
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--rule);
  overflow: hidden;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
}
.svc-card:hover { border-color: var(--rule-strong); }
.svc-card_media { overflow: hidden; background: var(--sand); }
.svc-card_media img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  /* Grayscale at rest, like every other photograph in the system: these are
     stock frames shot on different days against different grounds, and one
     treatment is what makes a grid of them read as one set. */
  transition: filter .6s var(--ease), transform .6s var(--ease);
}
.svc-card:hover .svc-card_media img { filter: none; transform: scale(1.04); }
.svc-card_body {
  display: grid;
  gap: .5rem;
  padding: clamp(1.15rem, 1.9vw, 1.6rem);
}
.svc-card_no {
  font-family: var(--font-display);
  font-size: calc(1.5rem * var(--t-mid));
  font-weight: 300;
  line-height: 1;
  color: var(--accent-lg);
}
.svc-card_name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--f-h4);
  line-height: 1.25;
  color: var(--fg);
  margin: 0;
}
.svc-card_text {
  font-size: var(--f-body);
  line-height: 1.65;
  color: var(--fg-soft);
  margin: 0;
}
/* A tile that is only a photograph, dropped into the grid between the cards so
   the run of text boxes is broken by an image at card size rather than by a
   full-width figure. */
.svc-card.is-shot { border: 0; background: none; }
.svc-card.is-shot .svc-card_media img { aspect-ratio: 3 / 4; }
.svc-card.is-shot figcaption {
  margin-top: .6rem;
  padding-left: .8rem;
  border-left: 1.5px solid var(--accent);
  font-family: var(--font-ui);
  font-size: calc(.78rem * var(--t-ui));
  line-height: 1.45;
  color: var(--fg-soft);
}

/* --- the overlap ---------------------------------------------------------
   The uncommon layout the note asked for: one grid, two children, SAME ROW.
   The photograph runs 1..8 and the copy panel starts at 7, so the panel sits
   on top of the image instead of beside it. Below 900 they simply stack, which
   is why both children declare their own grid-row only inside the query. */
.svc-overlap {
  display: grid;
  gap: 1.5rem;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed);
}
.svc-overlap_media img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.svc-overlap_panel {
  background: var(--panel);
  border: 1px solid var(--rule);
  padding: clamp(1.5rem, 3vw, 2.75rem);
}
.svc-overlap_panel > * + * { margin-top: 1.15rem; }
@media (min-width: 900px) {
  .svc-overlap {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    align-items: center;
    gap: 0;
  }
  .svc-overlap_media { grid-column: 1 / span 8; grid-row: 1; }
  .svc-overlap_panel { grid-column: 7 / span 6; grid-row: 1; z-index: 1; }
  .svc-overlap.is-flipped .svc-overlap_media { grid-column: 5 / span 8; }
  .svc-overlap.is-flipped .svc-overlap_panel { grid-column: 1 / span 6; }
}

/* --- the ledger ----------------------------------------------------------
   "What is included" is five short facts. As a bulleted list it is five lines
   of body copy; as hairline-separated tiles it is a receipt, which is what it
   actually is. The 1px gap on a ruled ground draws the dividers, so there is
   no per-cell border to double up at the seams. */
/* `.lf-lead` is a lead-in for a list inside a column of prose: 1.4rem of top
   margin and body weight. Above a full-width ledger that sits directly under a
   photograph it read as an orphaned sentence touching the image. The ledger
   names itself with a label, and owns the air above it. */
.svc-ledger-label {
  margin: clamp(2.75rem, 5vw, 4.5rem) 0 0;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.svc-ledger {
  display: grid;
  gap: 1px;
  /* The hairline grid used to be the CONTAINER's background showing through
     the 1px gaps. That works until the last row is short -- an 87-item list
     in a 6-up grid ends with four empty cells, and those show the rule colour
     as one large tan block that reads as a rendering bug. So the container is
     panel-coloured and each <li> paints its own hairline into the gap with a
     spread shadow instead. Identical result on a full row, nothing at all
     where there is no item, and no layout change: box-shadow does not affect
     the box model, so the frozen pages do not move. */
  background: var(--panel);
  border: 1px solid var(--rule);
  grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}
.svc-ledger > li {
  background: var(--panel);
  box-shadow: 0 0 0 1px var(--rule);
  padding: 1.05rem 1.15rem;
  display: grid;
  gap: .3rem;
  align-content: start;
  padding-left: 1.15rem;
}
.svc-ledger > li::before { content: none; }
.svc-ledger b {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.svc-ledger span {
  font-size: var(--f-body);
  line-height: 1.5;
  color: var(--fg);
}

/* --- the provider band ---------------------------------------------------
   Dr. Sung is named ten times in this page's copy and appeared nowhere on it.
   His portrait is the ONLY asset the practice publishes of him and it exists
   at exactly 230x300 — so the column is capped at 15rem rather than given a
   spread's 44vw, which would upscale a 230px file across 600px of screen. Size
   the component to the asset, not the asset to the component. */
.svc-provider {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.75rem);
  align-items: center;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed);
}
@media (min-width: 768px) {
  .svc-provider { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }
}
.svc-provider_shot {
  margin: 0;
  max-width: 15rem;
  border: 1px solid var(--rule);
  background: var(--sand);
  overflow: hidden;
}
/* Grayscale at rest, colour on hover — the same treatment the homepage gives
   its three doctor portraits. Without it his was the only colour photograph in
   a page of grayscale supporting imagery, which read as an oversight. */
.svc-provider_shot img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 23 / 30;
  object-fit: cover;
  transition: filter .6s var(--ease);
}
.svc-provider:hover .svc-provider_shot img { filter: none; }
.svc-provider_body > * + * { margin-top: 1rem; }
.svc-provider_body h3 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1.06;
  letter-spacing: -.012em;
  color: var(--fg);
  max-width: 18ch;
}
.svc-provider_role {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.svc-provider_body p {
  font-size: var(--f-lede);
  line-height: 1.7;
  color: var(--fg-body);
  max-width: 54ch;
}
/* Three numbers the copy already states, set as facts rather than buried in a
   sentence. Not `tg-figures`: that one is a counted tween bound to the
   homepage's chapter and carries its own background. */
.svc-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem clamp(1.5rem, 4vw, 3rem);
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  list-style: none;
}
.svc-stats li { display: grid; gap: .15rem; }
.svc-stats b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.1rem * var(--t-mid));
  line-height: 1;
  color: var(--fg);
}
.svc-stats span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

/* --- the price card ------------------------------------------------------
   The cost chapter's lead card. `is-lead` above makes it span two columns;
   this gives it the sand ground so the money is the one filled panel on an
   otherwise hairline page. */
.svc-card.is-price { background: var(--sand); border-color: var(--beige-mid); }
.svc-card.is-price .svc-card_body { gap: .75rem; }
.svc-price {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.6rem * var(--t-mid));
  line-height: 1;
  letter-spacing: -.015em;
  color: var(--ink);
}
.svc-price small {
  display: block;
  margin-top: .5rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--copper);
}

/* --- chapter heads on a card chapter -------------------------------------
   A chapter whose body is a grid rather than a column of prose does not use
   `lf-split`, so it needs the ordinary chapter head above it. Same rhythm as
   `rg-head`, one step tighter because a grid starts with a hard edge. */
.svc-head { margin-bottom: clamp(1.75rem, 3.5vw, 3rem); }
.svc-head .pe-lede {
  margin-top: 1.1rem;
  max-width: 48ch;
  font-size: var(--f-lede);
  line-height: 1.7;
  color: var(--fg-body);
}
@media (min-width: 900px) {
  .svc-head.is-split {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: end;
  }
  .svc-head.is-split .pe-lede { margin-top: 0; }
}

/* ===========================================================================
   THE PRACTICE PAGES' OWN FURNITURE — /about-us/ and /our-team/
   Added 2026-09-01 on the client's note: "Make variations to the sections so
   we make sure they are not equal throughout the site."

   THE SAME CONSTRAINT THE svc- BLOCK WORKS UNDER: the homepage and the
   Invisalign page are approved and must not move a pixel. Every selector below
   is either a NEW class those two pages do not use, or is scoped to a chapter
   class that exists only on these two pages — `ch-dateline`, `ch-premise`,
   `ch-family`, `ch-kit`, `ch-siblings`, `ch-word`, `ch-visit`, `ch-leads`,
   `ch-schools`, `ch-named`, `ch-outside`. Nothing here is a bare element or a
   shared component. Check that before adding to this block, and re-render both
   approved pages afterwards: their four heights are the test, not a look.

   WHAT IS DELIBERATELY *NOT* VARIED. The arrival chapter, the credential
   strip, the breadcrumb, the invitation, the header and the footer are the
   same on every page and are meant to be. Varying the chrome is not variety,
   it is a site that looks like four different sites. What varies is the body
   of each chapter, and no two chapters across the four pages now share a
   layout.
   ======================================================================== */

/* --- the missing button variant ------------------------------------------
   The journey layer restyles `.ch .button` at two-class specificity, which
   lands AFTER `.button.is-ghost` in the sheet and therefore beats it: an
   outline button inside any chapter came out solid brand. The layer only ever
   defined `is-ghost-light`, for dark grounds, because until now no chapter had
   a secondary action on a light one. Neither approved page uses `is-ghost` at
   all, so this cannot move them - checked before adding. */
.ch .button.is-ghost {
  background: transparent;
  color: var(--fg);
  border-color: var(--rule-strong);
}
.ch .button.is-ghost::after { background: var(--ink); }
.ch .button.is-ghost:hover { color: #fff; border-color: var(--ink); }

/* --- the masthead ---------------------------------------------------------
   ABOUT, CHAPTER 1. A dateline, not a chapter: four ruled cells across the
   full width, no heading, no lede. It sits directly under the breadcrumb and
   states what the practice IS before the page starts arguing. Every other
   chapter on the site opens with a tag and an h2; this one deliberately opens
   with neither, so the page starts on a different note from the other three.
   `tg-figures` is the near neighbour and is wrong here: it is a counted tween
   bound to the homepage's chapter and paints its own ground. */
.ch-dateline { padding: 0; background: var(--white); }
.ab-dateline {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed);
  border-top: 1px solid var(--beige);
  border-bottom: 1px solid var(--beige);
}
@media (min-width: 768px) { .ab-dateline { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.ab-dateline > div {
  padding: clamp(1.5rem, 3vw, 2.4rem) clamp(1rem, 2vw, 1.75rem) clamp(1.5rem, 3vw, 2.4rem) 0;
  display: grid;
  gap: .5rem;
  align-content: start;
  border-left: 1px solid var(--beige);
  padding-left: clamp(1rem, 2vw, 1.75rem);
}
/* The first cell in each row loses its rule, so the outer edge is the
   container's own and not a stray hairline in the gutter. */
.ab-dateline > div:nth-child(odd) { border-left: 0; padding-left: 0; }
@media (min-width: 768px) {
  .ab-dateline > div:nth-child(odd) { border-left: 1px solid var(--beige); padding-left: clamp(1rem, 2vw, 1.75rem); }
  .ab-dateline > div:first-child { border-left: 0; padding-left: 0; }
}
.ab-dateline dt {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--copper);
}
.ab-dateline dd {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(1.9rem * var(--t-mid));
  line-height: 1.1;
  letter-spacing: -.012em;
  color: var(--ink);
}
.ab-dateline dd small {
  display: block;
  margin-top: .4rem;
  font-family: var(--font-body);
  font-size: var(--f-body);
  line-height: 1.55;
  color: var(--muted);
}

/* --- the opener ----------------------------------------------------------
   ABOUT, CHAPTER 2. The one place on the site with a drop cap, and the one
   figure that runs off the right edge of the container instead of sitting
   inside it. The measure is deliberately narrow (54ch) against a tall 3:4
   frame, so the chapter reads as a page from a magazine rather than as a
   two-column split. `layout-split` and `svc-overlap` are the two existing
   pair layouts and neither breaks the container edge. */
.ab-open {
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
}
/* `stretch`, not `end`. The first cut bottom-aligned a short text column
   against a fixed 3:4 frame and left 440px of nothing under the heading, on
   the widest part of the page. The figure now takes whatever height the copy
   column has, which is why the chapter tag and the h2 live INSIDE that column
   here rather than in their own wrap above it. */
@media (min-width: 900px) {
  .ab-open { grid-template-columns: minmax(0, 1fr) minmax(0, .82fr); align-items: stretch; }
}
.ab-open_col > * + * { margin-top: 1.15rem; }
.ab-open_col p {
  font-size: var(--f-lede);
  line-height: 1.75;
  max-width: 54ch;
}
/* The drop cap. `initial-letter` is still not in Firefox, so this is the
   float, which needs an explicit line-height to sit on the third baseline
   rather than wherever the font's own leading puts it. */
.ab-open_col .ab-dropcap::first-letter {
  float: left;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(4.1rem * var(--t-mid));
  line-height: .84;
  padding: .06em .14em 0 0;
  color: var(--copper);
}
.ab-open_fig { margin: 0; position: relative; display: flex; flex-direction: column; }
.ab-open_fig img {
  display: block;
  width: 100%;
  /* 4:5 on one column. 3:4 was too deep a crop for a 3:2 source: the subject
     is centre-right in the frame and a centred portrait crop cut the face in
     half. `object-position` holds the subject; the ratio stops it needing to. */
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 40% 32%;
}
.ab-open_fig figcaption {
  margin-top: .7rem;
  padding-left: .8rem;
  border-left: 1.5px solid var(--accent);
  font-family: var(--font-ui);
  font-size: calc(.78rem * var(--t-ui));
  line-height: 1.45;
  color: var(--muted);
}
/* Off the edge. `.ch .wrap` caps at --maxw and pads by --bleed; pulling the
   figure by the bleed puts its right edge on the viewport, which no other
   figure on the site does. Only above 900, where there are two columns for it
   to be the right-hand one of. */
@media (min-width: 900px) {
  .ab-open_fig { margin-right: calc(-1 * var(--bleed)); }
  /* Fill the column rather than dictate its height. `aspect-ratio` has to be
     cleared explicitly or it keeps winning over the flexed height. */
  .ab-open_fig img { flex: 1; aspect-ratio: auto; height: 100%; min-height: 27rem; }
}

/* --- the vignettes -------------------------------------------------------
   ABOUT, CHAPTER 3. The practice's own three headings for its own three
   doctors, kept verbatim. NOT a card grid and NOT the homepage's dark plates:
   three columns hung under one hairline, each with a small round portrait
   inset beside the name. The round crop exists nowhere else in the system and
   is the point — it is the one component that reads as a masthead byline. */
.ab-vignettes {
  display: grid;
  gap: clamp(2rem, 4vw, 3.25rem);
  border-top: 1px solid var(--rule-strong);
  padding-top: clamp(1.75rem, 3vw, 2.75rem);
}
@media (min-width: 860px) { .ab-vignettes { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ab-vignette { display: grid; gap: .9rem; align-content: start; }
.ab-vig_head { display: flex; align-items: center; gap: .9rem; }
.ab-vig_face {
  width: 3.4rem;
  height: 3.4rem;
  flex: none;
  border-radius: 50%;
  overflow: hidden;
  background: var(--sand);
  border: 1px solid var(--rule);
}
.ab-vig_face img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
  transition: filter .6s var(--ease);
}
.ab-vignette:hover .ab-vig_face img { filter: none; }
.ab-vig_name {
  display: grid;
  gap: .1rem;
  font-family: var(--font-ui);
  font-size: calc(.95rem * var(--t-text));
  font-weight: 700;
  color: var(--fg);
}
.ab-vig_name span {
  font-weight: 500;
  font-size: var(--f-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.ch .ab-vignette h3 {
  font-size: var(--f-h3);
  line-height: 1.14;
  max-width: 16ch;
}
.ab-vignette p {
  font-size: var(--f-body);
  line-height: 1.7;
  color: var(--fg-body);
  margin: 0;
}

/* --- the spec sheet ------------------------------------------------------
   ABOUT, CHAPTER 4. Six instruments, each with real copy from the practice's
   own technology page. A sticky INDEX on the left with the detail beside it —
   the reader can see the whole list while reading any one of them, which a
   stack of six headings cannot do. `lf-split` is the existing sticky column
   and it holds the chapter head, not a navigable index; this one is a list of
   in-page links, which is why it is its own component. */
.ab-spec { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
@media (min-width: 900px) {
  .ab-spec { grid-template-columns: minmax(0, .34fr) minmax(0, 1fr); }
  .ab-spec_index { position: sticky; top: 7.5rem; }
}
.ab-spec_index ol {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
  counter-reset: spec;
}
.ab-spec_index li { border-bottom: 1px solid var(--rule); counter-increment: spec; }
.ab-spec_index li::before { content: none; }
.ab-spec_index a {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  padding: .8rem 0;
  font-family: var(--font-ui);
  font-size: calc(.85rem * var(--t-text));
  font-weight: 600;
  color: var(--fg-body);
  text-decoration: none;
  transition: color .3s var(--ease), padding-left .3s var(--ease);
}
.ab-spec_index a::before {
  content: counter(spec, decimal-leading-zero);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--accent);
  flex: none;
}
.ab-spec_index a:hover { color: var(--accent); padding-left: .5rem; }
/* A picture under the index, because the index is six short rows against six
   long entries and left a column of nothing for most of the chapter - on a
   page the client asked to carry more images. Hidden below 900, where the
   index is not sticky and the photograph would just push the list down. */
.ab-spec_shot { display: none; }
@media (min-width: 900px) {
  .ab-spec_shot { display: block; margin: 2rem 0 0; }
  .ab-spec_shot img {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    transition: filter .6s var(--ease);
  }
  .ab-spec_shot:hover img { filter: none; }
  .ab-spec_shot figcaption {
    margin-top: .6rem;
    padding-left: .8rem;
    border-left: 1.5px solid var(--accent);
    font-family: var(--font-ui);
    font-size: calc(.78rem * var(--t-ui));
    line-height: 1.45;
    color: var(--fg-soft);
  }
}
.ab-spec_body { display: grid; gap: clamp(1.75rem, 3vw, 2.5rem); }
.ab-spec_item {
  display: grid;
  gap: .7rem;
  padding-bottom: clamp(1.75rem, 3vw, 2.5rem);
  border-bottom: 1px solid var(--rule);
  /* The sticky index is 7.5rem from the top; an anchor jump has to clear the
     floating header by at least that much or the heading lands under it. */
  scroll-margin-top: 7.5rem;
}
.ab-spec_item:last-child { border-bottom: 0; padding-bottom: 0; }
.ch .ab-spec_item h3 { font-size: var(--f-h4); max-width: 24ch; }
.ab-spec_item p {
  font-size: var(--f-body);
  line-height: 1.72;
  max-width: 66ch;
  margin: 0;
}
.ab-spec_tag {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--copper);
}

/* --- the diptych ---------------------------------------------------------
   ABOUT, CHAPTER 5. Two practices at one address, so: two equal halves, each
   a photograph with its panel sitting on the base of it. `svc-overlap` is one
   image and one panel offset sideways; this is a matched pair, and the
   symmetry is the argument — neither practice is the junior one. */
.ab-diptych {
  display: grid;
  gap: 1.25rem;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed);
}
@media (min-width: 860px) { .ab-diptych { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem; } }
.ab-half { position: relative; display: block; overflow: hidden; }
.ab-half img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transform: scale(1.03);
  transition: filter .7s var(--ease), transform .7s var(--ease);
}
.ab-half:hover img { filter: none; transform: scale(1.07); }
/* The veil starts at 28%, not 40%, and reaches .6 by the midpoint. At the
   first setting the "FOR ADULTS" kicker sat on the grandmother's white hair at
   about .35 opacity and was unreadable. A photograph the panel has to sit on
   cannot be trusted to be dark where the text lands. */
.ab-half::after {
  content: "";
  position: absolute;
  inset: 28% 0 0;
  background: linear-gradient(180deg, rgba(30, 36, 38, 0) 0%, rgba(30, 36, 38, .6) 46%, rgba(30, 36, 38, .88) 76%, rgba(30, 36, 38, .96) 100%);
  pointer-events: none;
}
.ab-half_panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: clamp(1.25rem, 2.6vw, 2.25rem);
  display: grid;
  gap: .5rem;
}
.ab-half_kicker {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #e3c3a8;
}
.ch .ab-half_panel h3 { color: #fff; font-size: var(--f-h3); max-width: 15ch; }
.ab-half_panel p {
  color: rgba(255, 255, 255, .8);
  font-size: var(--f-body);
  line-height: 1.6;
  max-width: 34ch;
  margin: 0;
}
.ab-half_go {
  margin-top: .35rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #fff;
}

/* --- the single quote ----------------------------------------------------
   ABOUT, CHAPTER 6. ONE review, centred, at display size, with no portrait
   and no rail. The homepage and the service page both run a lead quote beside
   a photograph and then a drifting rail of chips; the reviews page will do
   more of that again. About gets a full stop instead — one voice, nothing
   else in the chapter. */
.ab-oneword { max-width: 46rem; margin: 0 auto; text-align: center; }
.ch .ab-oneword blockquote {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1.2;
  letter-spacing: -.014em;
  color: var(--fg);
  margin: 0;
  text-wrap: balance;
}
.ab-oneword figcaption {
  margin-top: 1.75rem;
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.ab-oneword figcaption i {
  width: 2.2rem;
  height: 1px;
  background: var(--accent);
  flex: none;
}
.ab-oneword .ab-stars {
  display: block;
  margin-bottom: 1.5rem;
  font-size: calc(.95rem * var(--t-text));
  letter-spacing: .35em;
  color: var(--copper);
}
/* A class rather than an inline style: Instatic stores a node graph, and an
   inline `style` attribute is not one of the four props `base.*` carries
   through the converter. It would be dropped on import with nothing reported,
   exactly as `alt` was. */
.ab-oneword-foot { text-align: center; }

/* --- the visit strip -----------------------------------------------------
   ABOUT, CHAPTER 7. A full-bleed map with a card standing on it. The
   homepage's invitation puts the map in a bordered box in a side column; this
   runs it edge to edge with the hours card overlapping its left side, so the
   two are not the same component doing the same job twice. */
/* The two chapters an in-page link from a hero lands on. There is no global
   scroll-padding on this site -- components carry their own scroll-margin
   (`.lf-section`, `.ab-spec_item`) -- so without these the header floats over
   the top ~95px of whatever the anchor lands on. */
.ch-visit, .ch-named { scroll-margin-top: 7rem; }

.ch-visit { padding: 0; }
.ab-visit { position: relative; }
/* The frame has to stay `.embed_component`, because that is the selector
   site.js defers the map behind — and on Instatic the authored <iframe> is
   published as a bare <div data-src>, which only the `.embed_component >
   [data-src]` half of that selector catches. So the wrapper is the shared
   component and everything visual is overridden here, scoped to this chapter.
   Both shapes are sized, or the strip collapses to nothing on the live page
   before the swap and IntersectionObserver never sees it. */
.ab-visit .embed_component { border: 0; background: var(--sand); }
.ab-visit .embed_component iframe,
.ab-visit .embed_component > [data-src] {
  display: block;
  width: 100%;
  /* Tall enough to CONTAIN the card, which is absolutely centred on it: at
     34rem the card was 560px against a 468px strip and hung out of both ends.
     If the card gains a row, re-check this number - nothing else will. */
  height: clamp(28rem, 68vh, 44rem);
  border: 0;
  /* Desaturated to sit with the palette, not to grayscale — a map is the one
     image on the site a visitor has to actually read. */
  filter: grayscale(.55);
}
.ab-visit_card {
  background: var(--white);
  border: 1px solid var(--beige);
  padding: clamp(1.5rem, 3vw, 2.5rem);
  display: grid;
  gap: .95rem;
}
/* The grid gap already spaces the tag; its own 1.6rem bottom margin on top of
   that was 26px of the ~40px by which the card outgrew the strip it is
   centred on. Measured, not guessed - see probe-tag.mjs. */
.ab-visit_card .chapter-tag { margin-bottom: 0; }
@media (min-width: 900px) {
  .ab-visit_card {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    left: var(--bleed);
    width: min(28rem, 38vw);
    box-shadow: 0 24px 60px rgba(30, 36, 38, .16);
  }
}
.ch .ab-visit_card h3 { font-size: var(--f-h3); max-width: 14ch; }
.ab-visit_card address {
  font-style: normal;
  font-size: var(--f-body);
  line-height: 1.7;
  color: var(--body);
}
.ab-visit_hours { display: grid; gap: .35rem; margin: 0; padding: 0; list-style: none; }
.ab-visit_hours li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .3rem 0;
  border-bottom: 1px solid var(--beige);
  font-size: calc(.875rem * var(--t-text));
  color: var(--body);
}
.ab-visit_hours li::before { content: none; }
.ab-visit_hours li b { color: var(--ink); font-weight: 600; }
.ab-visit_hours li.is-shut b { color: var(--muted); font-weight: 500; }
.ab-visit_note {
  font-size: calc(.85rem * var(--t-text));
  line-height: 1.6;
  color: var(--muted);
  margin: 0;
}

/* --- the roster ----------------------------------------------------------
   TEAM, CHAPTER 1. Full-width rows, one doctor each, hairline separated: a
   fixed small portrait, then the name, the role, one sentence, and a
   horizontal strip of facts. The homepage runs the same three people as tall
   dark plates in a three-up; this is the opposite shape on purpose, and it is
   the shape that can carry facts, which the plates cannot.

   THE PORTRAITS DO NOT MATCH AND THE COMPONENT HAS TO ABSORB THAT. Dr. Cho
   and Dr. Nguyen were shot on the same day, studio, black scrubs, and exist up
   to 1024x1536. Dr. Sung's only published portrait is outdoors, blue shirt,
   and exists at exactly 230x300 and nothing larger. So the column is capped at
   13rem — under his intrinsic width, so nothing upscales — and all three are
   grayscale at rest, which is what makes two shoots read as one set. Size the
   component to the worst asset, not to the best. */
.tm-roster { border-top: 1px solid var(--rule-strong); }
.tm-row {
  display: grid;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  padding: clamp(2rem, 4vw, 3.25rem) 0;
  border-bottom: 1px solid var(--rule);
  align-items: start;
}
@media (min-width: 768px) { .tm-row { grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); } }
.tm-row_shot {
  margin: 0;
  max-width: 13rem;
  overflow: hidden;
  background: var(--sand);
  border: 1px solid var(--rule);
}
.tm-row_shot img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 23 / 30;
  object-fit: cover;
  object-position: 50% 18%;
  transition: filter .6s var(--ease), transform .6s var(--ease);
}
.tm-row:hover .tm-row_shot img { filter: none; transform: scale(1.03); }
.tm-row_body > * + * { margin-top: .85rem; }
.tm-row_role {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.ch .tm-row_body h3 {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1.05;
  letter-spacing: -.014em;
  max-width: 16ch;
}
.ch .tm-row_body h3 a { color: var(--fg); text-decoration: none; }
.ch .tm-row_body h3 a:hover { color: var(--accent); }
.tm-row_lede {
  font-size: var(--f-lede);
  line-height: 1.7;
  color: var(--fg-body);
  max-width: 58ch;
}
/* The facts strip. Not `svc-stats`: that one sets a numeral at 2.1rem display
   for three counted figures. These are short phrases, several per doctor, and
   they want to read as a row of labelled cells. */
.tm-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.1rem clamp(1.25rem, 3vw, 2.5rem);
  margin: 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}
.tm-facts dt {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-soft);
  margin-bottom: .3rem;
}
.tm-facts dd {
  margin: 0;
  font-size: calc(.9rem * var(--t-text));
  line-height: 1.55;
  color: var(--fg);
}

/* --- the schools index ---------------------------------------------------
   TEAM, CHAPTER 2. Where the three of them actually trained, which the
   practice's own bios state and no page currently uses. A ruled index: the
   institution set at display size on the left, the people and the degree on
   the right. `svc-ledger` is the near neighbour and is a grid of equal tiles;
   this is a two-column dictionary with a real hierarchy between the halves. */
.tm-schools { border-top: 1px solid var(--rule-strong); }
.tm-school {
  display: grid;
  gap: .5rem clamp(1.5rem, 4vw, 3.5rem);
  padding: clamp(1.1rem, 2.4vw, 1.9rem) 0;
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}
@media (min-width: 768px) { .tm-school { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); } }
.tm-school_name {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.1rem * var(--t-mid));
  line-height: 1.08;
  letter-spacing: -.012em;
  color: var(--fg);
  margin: 0;
}
.tm-school_name em { font-style: italic; color: var(--accent-lg); }
.tm-school_who {
  margin: 0;
  font-size: var(--f-body);
  line-height: 1.65;
  color: var(--fg-body);
}
.tm-school_who b { color: var(--fg); font-weight: 600; }
.tm-school_where {
  display: block;
  margin-top: .3rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

/* --- the name wall -------------------------------------------------------
   TEAM, CHAPTER 3, and the honest centre of the page.

   THE PRACTICE PUBLISHES NO STAFF ROSTER. No names, no roles, no portraits
   for anyone but the three doctors — checked across the whole crawl. The two
   dishonest ways to fill that gap are both already on this client's record:
   the old site ran four awards it had not won, and a smile gallery of theme
   stock presented as its own results. So nothing here is invented. These are
   the people the practice's OWN patients name in their OWN Google reviews,
   each one carrying the review it came from, and no role is asserted for
   anybody the reviews do not give one to.

   The layout follows from that: names at display size in an unequal flow, each
   opening the quote beneath it. It is a `<details>`, so it works with no
   JavaScript at all and the quotes are in the HTML for indexing whether or not
   anybody opens one. */
.tm-wall {
  display: flex;
  flex-wrap: wrap;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.tm-name {
  background: var(--panel);
  flex: 1 1 16rem;
  min-width: 0;
}
/* The unequal flow: three of the seven ask for more room, so the row breaks
   in a different place at every width instead of settling into a tidy grid. */
.tm-name.is-wide { flex-grow: 2.1; flex-basis: 24rem; }
.tm-name > summary {
  list-style: none;
  cursor: pointer;
  padding: clamp(1.25rem, 2.6vw, 2rem);
  display: grid;
  gap: .45rem;
  transition: background .35s var(--ease);
}
.tm-name > summary::-webkit-details-marker { display: none; }
.tm-name > summary:hover { background: var(--bg-2); }
.tm-name_first {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.6rem * var(--t-mid));
  line-height: 1;
  letter-spacing: -.016em;
  color: var(--fg);
}
.tm-name_role {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.tm-name_cue {
  font-family: var(--font-ui);
  font-size: calc(.78rem * var(--t-ui));
  letter-spacing: .1em;
  color: var(--fg-soft);
}
.tm-name[open] > summary { background: var(--bg-2); }
/* `display: none`, not `opacity: 0`. Hiding it kept its line box and left a
   40px hole between the role and the quote in every open cell. */
.tm-name[open] .tm-name_cue { display: none; }
.tm-name_body {
  padding: 0 clamp(1.25rem, 2.6vw, 2rem) clamp(1.25rem, 2.6vw, 2rem);
  background: var(--bg-2);
}
.tm-name_body blockquote {
  margin: 0;
  padding-left: 1rem;
  border-left: 1.5px solid var(--accent);
  font-size: var(--f-body);
  line-height: 1.7;
  color: var(--fg-body);
}
.tm-name_body cite {
  display: block;
  margin-top: .7rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-style: normal;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
/* The disclosure this chapter owes the reader, stated in the chapter and not
   only in a commit message. */
.tm-wall-note {
  margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
  padding-left: 1rem;
  border-left: 1.5px solid var(--rule-strong);
  font-size: calc(.85rem * var(--t-text));
  line-height: 1.65;
  color: var(--fg-soft);
  max-width: 62ch;
}

/* --- the margin notes ----------------------------------------------------
   TEAM, CHAPTER 4. What the three of them do when they are not here, all of
   it from their own published bios. Notes hung off a vertical rule rather than
   put in boxes: the chapter before it is a wall of hard-edged cells and the
   chapter after it is the invitation, so this one wants no border at all. */
.tm-notes { display: grid; gap: clamp(1.75rem, 3.5vw, 3rem); }
@media (min-width: 860px) { .tm-notes { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.tm-note {
  padding-left: clamp(1rem, 2vw, 1.5rem);
  border-left: 1px solid var(--rule-strong);
  display: grid;
  gap: .7rem;
  align-content: start;
}
.tm-note_who {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.tm-note p {
  margin: 0;
  font-size: var(--f-body);
  line-height: 1.75;
  color: var(--fg-body);
}
/* One pulled line per note, set larger, so the three columns are not three
   identical grey paragraphs. */
.tm-note_pull {
  font-family: var(--font-display) !important;
  font-weight: 300;
  font-size: var(--f-h3) !important;
  line-height: 1.2 !important;
  letter-spacing: -.01em;
  color: var(--fg) !important;
  max-width: 18ch;
}


/* ===========================================================================
   THE CORE PAGES' FURNITURE — the nine practice pages
   Added 2026-09-01 for the Asana "Build Core Pages" set: /about-us/,
   /our-doctors/, /our-team/, /our-services/, /new-patients/, /financing/,
   /dental-savings-plan/, /patient-reviews/ and /thank-you/. Client note:
   "Make sure to have variation on the sections between the pages."

   THE SAME CONSTRAINT THE svc- AND ab-/tm- BLOCKS WORK UNDER. The homepage
   and the Invisalign page are approved and must not move a pixel. Every
   selector below is a NEW `cp-` class, a NEW `jr-` runtime hook, or is scoped
   to a chapter class that exists only on these nine pages. Nothing here is a
   bare element or a shared component. `probe-heights.mjs --diff base` is the
   test, not a look.

   WHAT VARIES AND WHAT DOES NOT. The chrome is constant: the compact arrival,
   the credential strip, the breadcrumb, the invitation, the header and the
   footer are the same on all eleven pages. The BODY of every chapter varies,
   and each page carries at least two layouts that appear on no other page.
   The shared scrubbed scenes (the pinned path, the proof rail, the written
   statement) are system components and recur, never in the same sequence.
   ======================================================================== */

/* --- the generic runtime hooks -------------------------------------------
   journey.js binds these by ATTRIBUTE, not by chapter class, so a new page
   gets a scrubbed scene by authoring markup rather than by editing the
   runtime. Each has the same three states the homepage's own scenes have:
   unwritten (the tween's start), written (its end), and failed (no GSAP or
   reduced motion), where the CSS alone has to leave the page readable.

   `.ch [data-write]` is (0,2,0) on purpose: `.ch p` is (0,1,1) and beat the
   relay's start colour once already (JOURNEY-2026-09-01.md, bug 2). */
/* THE UNWRITTEN STATE IS READABLE. It was .18 / .22 alpha, about 1.3:1, and
   the agency flagged it as an accessibility problem on every page it appears
   (BugHerd #50, #64, 2026-09-16). At .66 the unwritten words are ~4.5:1 on
   the warm and white grounds and ~7:1 on ink; the scrub still reads as ink
   being laid down, it just never hides the sentence. */
.ch { --jr-unwritten: rgba(46, 53, 56, .66); }
.ch[data-theme="dark"] { --jr-unwritten: rgba(255, 255, 255, .66); }
.ch [data-write] { color: var(--jr-unwritten); }
html.jr-fail .ch [data-write],
html:not(.jr-ready) .ch [data-write] { color: var(--fg); }
@media (prefers-reduced-motion: reduce) { .ch [data-write] { color: var(--fg) !important; } }

/* A stagger group's children start in place; the runtime moves them only once
   it knows it can move them back. Nothing to reveal here in the failed state. */
[data-wipe] { overflow: hidden; }

/* --- the chapter head, on a chapter that is not a card grid -------------- */
.cp-head { margin-bottom: clamp(1.75rem, 3.5vw, 3rem); }
.cp-head .pe-lede { margin-top: 1.1rem; max-width: 48ch; font-size: var(--f-lede); line-height: 1.7; color: var(--fg-body); }
@media (min-width: 900px) {
  .cp-head.is-split { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: end; }
  .cp-head.is-split .pe-lede { margin-top: 0; }
}
.cp-kicker {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.cp-note {
  font-size: calc(.85rem * var(--t-text));
  line-height: 1.65;
  color: var(--fg-soft);
  max-width: 62ch;
  padding-left: 1rem;
  border-left: 1.5px solid var(--rule-strong);
}
.cp-foot { margin-top: clamp(1.75rem, 3.5vw, 3rem); }

/* ===========================================================================
   ABOUT — /about-us/
   ======================================================================== */

/* --- the manifesto -------------------------------------------------------
   ABOUT, CHAPTER 1. The practice's own opening paragraph, centred, at the
   statement size, written word by word as the reader scrolls. The homepage's
   relay does the same trick beside a sticky photograph; this one has nothing
   beside it at all, which is the point: one voice, one column, then a strip
   of facts under it. */
.cp-manifesto { max-width: 56rem; margin: 0 auto; text-align: center; }
.cp-manifesto .cp-kicker { display: block; margin-bottom: 1.5rem; }
.ch .cp-manifesto p {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1.24;
  letter-spacing: -.012em;
  margin: 0;
  text-wrap: balance;
}
.cp-facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.5rem clamp(2rem, 5vw, 4.5rem);
  margin: clamp(2.5rem, 5vw, 4rem) auto 0;
  padding: 1.5rem 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  max-width: 62rem;
}
.cp-facts div { display: grid; gap: .25rem; text-align: center; }
.cp-facts b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(1.7rem * var(--t-mid));
  line-height: 1.05;
  color: var(--fg);
}
.cp-facts span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

/* --- the mosaic ----------------------------------------------------------
   ABOUT, CHAPTER 2. Three photographs of the building at three sizes with
   one caption panel, on a twelve column grid. Not the homepage's unequal pair
   (two frames and an aside) and not a card grid: the frames overlap the row
   boundary so the chapter reads as a spread from a magazine rather than a
   gallery. Stacks to one column below 900. */
.cp-mosaic { display: grid; gap: 1.25rem; }
.cp-mosaic figure { margin: 0; position: relative; }
.cp-mosaic img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 4 / 3;
  transition: filter .7s var(--ease);
}
.cp-mosaic figure:hover img { filter: none; }
.cp-mosaic figcaption {
  margin-top: .65rem;
  padding-left: .8rem;
  border-left: 1.5px solid var(--accent);
  font-family: var(--font-ui);
  font-size: calc(.78rem * var(--t-ui));
  line-height: 1.45;
  color: var(--fg-soft);
}
.cp-mosaic_panel {
  background: var(--panel);
  border: 1px solid var(--rule);
  padding: clamp(1.5rem, 3vw, 2.5rem);
  display: grid;
  gap: 1rem;
  align-content: center;
}
.ch .cp-mosaic_panel h3 { font-size: var(--f-h3); max-width: 16ch; }
.cp-mosaic_panel p { font-size: var(--f-body); line-height: 1.7; margin: 0; max-width: 40ch; }
@media (min-width: 900px) {
  .cp-mosaic { grid-template-columns: repeat(12, minmax(0, 1fr)); grid-auto-rows: minmax(0, auto); gap: 1.5rem; }
  .cp-mosaic .is-a { grid-column: 1 / span 7; grid-row: 1; }
  .cp-mosaic .is-a img { aspect-ratio: 16 / 10; }
  .cp-mosaic .is-b { grid-column: 8 / span 5; grid-row: 1 / span 2; }
  .cp-mosaic .is-b img { aspect-ratio: auto; min-height: 100%; }
  .cp-mosaic_panel { grid-column: 1 / span 4; grid-row: 2; }
  .cp-mosaic .is-c { grid-column: 5 / span 3; grid-row: 2; }
  .cp-mosaic .is-c img { aspect-ratio: 1; }
}

/* --- the people rail -----------------------------------------------------
   ABOUT, CHAPTER 3. The practice's own three headings for its own three
   doctors, verbatim, on a rail that the page scrolls sideways: the reader
   moves through the three by scrolling down, and a phone gets a snapping
   scroller instead. The homepage runs the same three as dark plates in a
   grid; this is a single row that travels. */
.cp-rail { position: relative; }
.cp-rail_in {
  display: flex;
  gap: clamp(1.25rem, 2.5vw, 2rem);
  width: max-content;
  padding-left: var(--bleed);
  padding-right: var(--bleed);
  will-change: transform;
}
@media (min-width: 900px) {
  .cp-rail { overflow: hidden; }
  .cp-rail_in { padding-left: max(var(--bleed), calc((100vw - var(--maxw)) / 2 + var(--bleed))); }
}
@media (max-width: 899px) {
  .cp-rail { overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-left: var(--bleed); scrollbar-width: none; }
  .cp-rail::-webkit-scrollbar { display: none; }
  .cp-person { scroll-snap-align: start; }
}
.cp-person {
  width: min(30rem, 80vw);
  flex: none;
  display: grid;
  gap: 1rem;
  align-content: start;
}
.cp-person_shot { margin: 0; overflow: hidden; background: var(--sand); border: 1px solid var(--rule); }
.cp-person_shot img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 20%;
  transition: filter .6s var(--ease), transform .8s var(--ease);
}
.cp-person:hover .cp-person_shot img { filter: none; transform: scale(1.04); }
.cp-person_who {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.cp-person_who span { color: var(--fg-soft); font-weight: 500; }
.ch .cp-person h3 { font-size: var(--f-h3); line-height: 1.14; max-width: 18ch; }
.cp-person p { font-size: var(--f-body); line-height: 1.7; margin: 0; }

/* --- the instrument sheet ------------------------------------------------
   ABOUT, CHAPTER 4. Six instruments from the practice's own technology page,
   on ink. Each is a `<details>` row: numeral, name and the one line that
   says what it is for on the summary, the practice's own paragraphs under
   it. A sticky photograph holds the right column. The service page's ledger
   is a grid of equal tiles and the About draft's spec sheet was an index of
   links; this is a list you open. */
.cp-spec { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
@media (min-width: 900px) {
  .cp-spec { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); }
  .cp-spec_shot { position: sticky; top: 7rem; }
}
.cp-spec_list { border-top: 1px solid var(--rule-strong); }
.cp-spec_item { border-bottom: 1px solid var(--rule); }
.cp-spec_item > summary {
  list-style: none;
  cursor: pointer;
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr) auto;
  gap: 1rem;
  align-items: baseline;
  padding: 1.1rem 0;
  transition: color .3s var(--ease);
}
.cp-spec_item > summary::-webkit-details-marker { display: none; }
.cp-spec_no {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(1.4rem * var(--t-mid));
  color: var(--accent);
}
.cp-spec_name { display: grid; gap: .2rem; }
.cp-spec_name b {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--f-h4);
  line-height: 1.2;
  color: var(--fg);
}
.cp-spec_name span { font-size: var(--f-body); color: var(--fg-soft); line-height: 1.5; }
.cp-spec_item > summary::after {
  content: "+";
  font-family: var(--font-ui);
  font-size: 1.3rem;
  font-weight: 500;
  color: var(--accent);
  transition: transform .3s var(--ease);
}
.cp-spec_item[open] > summary::after { transform: rotate(45deg); }
.cp-spec_item > summary:hover .cp-spec_name b { color: var(--accent); }
.cp-spec_item > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cp-spec_body { padding: 0 0 1.4rem 4rem; display: grid; gap: .9rem; }
.cp-spec_body p { margin: 0; font-size: var(--f-body); line-height: 1.72; max-width: 60ch; }
@media (max-width: 599px) { .cp-spec_body { padding-left: 0; } }
.cp-spec_shot { margin: 0; }
.cp-spec_shot img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: filter .7s var(--ease);
}
.cp-spec_shot:hover img { filter: none; }
.cp-spec_shot figcaption {
  margin-top: .7rem;
  padding-left: .8rem;
  border-left: 1.5px solid var(--accent);
  font-family: var(--font-ui);
  font-size: calc(.78rem * var(--t-ui));
  line-height: 1.45;
  color: var(--fg-soft);
}

/* ===========================================================================
   MEET THE DOCTORS — /our-doctors/
   ======================================================================== */

/* --- the split ground ----------------------------------------------------
   DOCTORS, CHAPTER 1. Dr. Nguyen gets the page to herself first, because
   the board certification is the practice's whole argument. Half the width
   is ink and holds her portrait edge to edge; half is warm and holds her own
   words, written word by word. Two grounds in one chapter exists nowhere
   else on the site. */
.ch-specialist { padding: 0; }
.cp-split { display: grid; }
@media (min-width: 900px) { .cp-split { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); } }
.cp-split_ink { background: var(--ink-deep); position: relative; overflow: hidden; margin: 0; }
.cp-split_ink img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 18%;
  aspect-ratio: 4 / 5;
  transition: filter .8s var(--ease);
}
.cp-split:hover .cp-split_ink img { filter: none; }
/* Above 900 the portrait FILLS the ink half, whatever height the copy beside
   it needs. `height: 100%` on an image in an auto-height grid cell resolves
   to auto, which left a band of bare ink under the photograph on the first
   render; absolute positioning inside the cell is what actually fills it. */
@media (min-width: 900px) {
  .cp-split_ink { min-height: 42rem; }
  .cp-split_ink img { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
}
/* Held by elevate.js holdSplit() while a fold is open: the height it had
   closed, pinned under the header, over an ink ground (BugHerd #73, #74). */
@media (min-width: 900px) {
  .cp-split:has(.cp-split_ink.is-held) { background: var(--ink-deep); }
  .cp-split_ink.is-held { align-self: start; position: sticky; top: var(--jr-nav-h, 5.5rem); min-height: 0; }
}
.cp-split_ink figcaption {
  position: absolute;
  left: var(--bleed);
  bottom: 1.5rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .7);
}
.cp-split_warm {
  background: var(--paper);
  padding: clamp(3rem, 6vw, 6rem) var(--bleed);
  display: grid;
  gap: 1.25rem;
  align-content: center;
}
.ch .cp-split_warm h2 { font-size: var(--f-d2); max-width: 14ch; }
.cp-split_role { margin-top: -.5rem; }
.ch .cp-split_warm .cp-split_quote {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-h3);
  line-height: 1.32;
  margin: .5rem 0 0;
  max-width: 34ch;
}
.cp-split_warm > p:not(.cp-split_quote) { font-size: var(--f-lede); line-height: 1.7; max-width: 54ch; margin: 0; }

/* The dossier facts. A small definition grid used by the three doctors. */
.cp-dl {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 1rem clamp(1.25rem, 3vw, 2.5rem);
  margin: .5rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}
.cp-dl dt {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-soft);
  margin-bottom: .3rem;
}
.cp-dl dd { margin: 0; font-size: calc(.9rem * var(--t-text)); line-height: 1.55; color: var(--fg); }

/* --- the two dossiers ----------------------------------------------------
   DOCTORS, CHAPTER 2. Dr. Cho and Dr. Sung side by side, each a column:
   portrait capped at the smallest published asset (Dr. Sung exists at
   230x300 and nothing larger), the name at statement size, the practice's
   own biography folded past the first paragraph, and the facts grid. */
.cp-duo { display: grid; gap: clamp(2.5rem, 5vw, 4.5rem); }
@media (min-width: 860px) { .cp-duo { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.cp-dossier { display: grid; gap: 1.1rem; align-content: start; }
.cp-dossier_shot { margin: 0; max-width: 15rem; border: 1px solid var(--rule); background: var(--sand); overflow: hidden; }
.cp-dossier_shot img {
  display: block;
  width: 100%;
  aspect-ratio: 23 / 30;
  object-fit: cover;
  object-position: 50% 18%;
  transition: filter .6s var(--ease);
}
.cp-dossier:hover .cp-dossier_shot img { filter: none; }
.ch .cp-dossier h3 {
  font-size: var(--f-d3);
  line-height: 1.06;
  max-width: 14ch;
}
.cp-dossier > p { font-size: var(--f-lede); line-height: 1.7; margin: 0; max-width: 52ch; }
.cp-dossier .lf-more { margin-top: 0; }

/* --- the measure ---------------------------------------------------------
   DOCTORS, CHAPTER 4. The numbers the biographies state, set large and
   counted up on ink. The homepage's figures are four white cells that paint
   their own ground; these sit directly on the chapter with hairlines between
   them and a sentence under each. */
.cp-figures {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--rule);
}
@media (min-width: 900px) { .cp-figures { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.cp-figure {
  display: grid;
  gap: .6rem;
  align-content: start;
  padding: clamp(1.5rem, 3vw, 2.5rem) clamp(1rem, 2vw, 1.75rem) clamp(1.5rem, 3vw, 2.5rem) 0;
  border-bottom: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
  padding-left: clamp(1rem, 2vw, 1.75rem);
}
.cp-figure:nth-child(odd) { border-left: 0; padding-left: 0; }
@media (min-width: 900px) {
  .cp-figure:nth-child(odd) { border-left: 1px solid var(--rule); padding-left: clamp(1rem, 2vw, 1.75rem); }
  .cp-figure:first-child { border-left: 0; padding-left: 0; }
}
.cp-figure b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d2);
  line-height: .95;
  letter-spacing: -.02em;
  color: var(--fg);
}
.cp-figure b small { font-size: .45em; letter-spacing: 0; color: var(--accent); margin-left: .1em; }
/* The DIRECT child only. The numeral inside <b> is a <span> too (the counter
   binds to [data-count]), and an unscoped `.cp-figure span` set the digits at
   label size while the unit beside them stayed at display size -- "100 hrs"
   with the 100 the small half. BugHerd #87, 2026-09-18, and the same defect
   the README warns about for .cp-score_num b. */
.cp-figure > span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.cp-figure p { margin: 0; font-size: var(--f-body); line-height: 1.6; max-width: 26ch; }

/* --- the voices ----------------------------------------------------------
   DOCTORS, CHAPTER 5. One review per doctor, the reviewer's own words under
   the doctor's name. Three columns, no rail, no portrait: the reviews page
   runs the rail, the homepage runs the quote and portrait, About runs one
   line. */
.cp-voices { display: grid; gap: clamp(2rem, 4vw, 3rem); border-top: 1px solid var(--rule-strong); padding-top: clamp(1.75rem, 3vw, 2.5rem); }
@media (min-width: 860px) { .cp-voices { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.cp-voice { display: grid; gap: .9rem; align-content: start; }
.cp-voice_about {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.cp-voice blockquote {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(1.2rem * var(--t-mid));
  line-height: 1.5;
  color: var(--fg);
}
.cp-voice cite {
  display: block;
  font-family: var(--font-ui);
  font-style: normal;
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.cp-voice cite b { color: var(--accent); font-weight: 700; }
.cp-voice cite b::before { content: " / "; color: var(--rule-strong); }

/* ===========================================================================
   MEET THE TEAM — /our-team/
   ======================================================================== */

/* --- the bylines ---------------------------------------------------------
   TEAM, CHAPTER 1. The three doctors as one line of bylines, because they
   have their own page: a round face, a name, a role, a link. The About
   draft's vignettes were three columns with headings; this is a strip. */
.cp-bylines {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem clamp(2rem, 5vw, 4rem);
  padding: 1.5rem 0;
  border-top: 1px solid var(--rule-strong);
  border-bottom: 1px solid var(--rule);
}
.cp-byline { display: flex; align-items: center; gap: .9rem; text-decoration: none; color: inherit; }
.cp-byline_face { width: 3.6rem; height: 3.6rem; border-radius: 50%; overflow: hidden; flex: none; border: 1px solid var(--rule); background: var(--sand); }
.cp-byline_face img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%; transition: filter .5s var(--ease); }
.cp-byline:hover .cp-byline_face img { filter: none; }
.cp-byline b { display: block; font-family: var(--font-display); font-size: calc(1.15rem * var(--t-mid)); font-weight: 400; color: var(--fg); transition: color .3s var(--ease); }
.cp-byline:hover b { color: var(--accent); }
.cp-byline span { display: block; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); margin-top: .15rem; }
.cp-bylines .link-arrow { margin-left: auto; align-self: center; }

/* --- the ticker ----------------------------------------------------------
   TEAM, CHAPTER 2's opening band. The first names patients use in their own
   reviews, at display size, drifting, faster when the page is scrolled
   fast. The homepage's marquee is a row of labels on ink; this is names on
   the warm ground with the tag rule as the divider. */
.cp-ticker { overflow: hidden; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 1.25rem 0; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.cp-ticker_row { display: flex; align-items: center; white-space: nowrap; width: max-content; will-change: transform; }
.cp-ticker_row span {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  letter-spacing: -.012em;
  color: var(--fg);
  padding: 0 1.5rem;
}
.cp-ticker_row i { width: 2.6rem; height: 1px; background: var(--accent); flex: none; }

/* --- the named ------------------------------------------------------------
   TEAM, CHAPTER 2. The practice publishes no staff roster, and the two
   dishonest ways to fill that gap are both on this client's record. So this
   names only the people the practice's OWN patients name in their OWN Google
   reviews, each row carrying the review it came from, and asserts a role
   only where a review gives one. Name on the left at statement size, the
   evidence on the right. */
.cp-people { border-top: 1px solid var(--rule-strong); }
.cp-people_row {
  display: grid;
  gap: .75rem clamp(1.5rem, 4vw, 3.5rem);
  padding: clamp(1.5rem, 3vw, 2.5rem) 0;
  border-bottom: 1px solid var(--rule);
  align-items: start;
}
@media (min-width: 768px) { .cp-people_row { grid-template-columns: minmax(0, .7fr) minmax(0, 1.3fr); } }
.cp-people_name { display: grid; gap: .3rem; align-content: start; }
.cp-people_name b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1;
  letter-spacing: -.016em;
  color: var(--fg);
}
.cp-people_name span {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.cp-people_name small { font-family: var(--font-ui); font-size: calc(.78rem * var(--t-ui)); letter-spacing: .08em; color: var(--fg-soft); }
.cp-people_quotes { display: grid; gap: 1rem; }
.cp-people_quotes blockquote {
  margin: 0;
  padding-left: 1rem;
  border-left: 1.5px solid var(--accent);
  font-size: var(--f-body);
  line-height: 1.7;
  color: var(--fg-body);
}
.cp-people_quotes cite {
  display: block;
  margin-top: .5rem;
  font-family: var(--font-ui);
  font-style: normal;
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

/* --- the statement, on ink -----------------------------------------------
   TEAM, CHAPTER 3. Why the same faces: one sentence written word by word,
   left aligned on a dark ground with a watermark numeral behind it. About's
   manifesto is centred on white; this is the same mechanism in the opposite
   room. */
.cp-statement { position: relative; max-width: 60rem; }
.cp-statement_mark {
  position: absolute;
  right: 0;
  top: -1.5rem;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(12rem * var(--t-disp));
  line-height: 1;
  color: rgba(255, 255, 255, .05);
  pointer-events: none;
  user-select: none;
}
.ch .cp-statement p {
  position: relative;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d3);
  line-height: 1.22;
  letter-spacing: -.012em;
  margin: 0;
  max-width: 24ch;
}
.cp-statement_after { margin-top: 1.75rem; font-size: var(--f-lede); line-height: 1.7; max-width: 50ch; }

/* --- the asides ----------------------------------------------------------
   TEAM, CHAPTER 4. What the three of them do when they are not here, from
   their own bios, as six short notes each opening on a large initial. The
   team draft's notes hung three paragraphs off a rule; these are cells with
   a drop initial and one line each. */
.cp-asides { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
@media (min-width: 700px) { .cp-asides { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cp-asides { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.cp-aside { background: var(--bg); padding: clamp(1.25rem, 2.6vw, 2rem); display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 1rem; align-items: start; }
.cp-aside b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(3.2rem * var(--t-mid));
  line-height: .8;
  color: var(--accent);
}
.cp-aside p { margin: 0; font-size: var(--f-body); line-height: 1.7; }
.cp-aside p small { display: block; margin-top: .4rem; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); }

/* --- the band ------------------------------------------------------------
   TEAM, the close of CHAPTER 4. The practice's own team photograph, full
   bleed, with one sentence and a link on it. */
.cp-band { position: relative; margin-top: clamp(2.5rem, 5vw, 4rem); }
.cp-band img { display: block; width: 100%; height: clamp(20rem, 46vh, 32rem); object-fit: cover; object-position: 50% 30%; }
.cp-band::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(30, 36, 38, 0) 20%, rgba(30, 36, 38, .82) 100%); pointer-events: none; }
.cp-band_in {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 1;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--bleed) clamp(1.75rem, 4vw, 3.5rem);
  display: grid;
  gap: 1rem;
}
.cp-band_in p { color: #fff; font-size: var(--f-lede); max-width: 38ch; margin: 0; }
.ch-offduty { padding-bottom: 0; }

/* ===========================================================================
   SERVICES OVERVIEW — /our-services/
   ======================================================================== */

/* --- the departments -----------------------------------------------------
   SERVICES, CHAPTER 1. Eight groups on a twelve column sheet, tiles sized by
   how much they hold, every treatment a chip inside its group. The homepage
   shows a curated dozen in three arcs; this is the whole tree, findable in
   one screen. A one pixel gap on a ruled ground draws the dividers. */
.cp-depts { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
@media (min-width: 600px) { .cp-depts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px) { .cp-depts { grid-template-columns: repeat(12, minmax(0, 1fr)); } .cp-dept { grid-column: span 3; } .cp-dept.is-wide { grid-column: span 6; } }
.cp-dept { background: var(--panel); padding: clamp(1.25rem, 2.4vw, 1.9rem); display: grid; gap: .8rem; align-content: start; transition: background .35s var(--ease); }
.cp-dept:hover { background: var(--bg-2); }
.cp-dept_top { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.cp-dept_top b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(2.2rem * var(--t-mid));
  line-height: 1;
  color: var(--accent-lg);
}
.cp-dept_top span { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); }
.ch .cp-dept h3 { font-size: var(--f-h4); line-height: 1.2; }
.ch .cp-dept h3 a { color: var(--fg); text-decoration: none; }
.ch .cp-dept h3 a:hover { color: var(--accent); }
.cp-dept_list { display: flex; flex-wrap: wrap; gap: .4rem; margin: .2rem 0 0; padding: 0; list-style: none; }
.cp-dept_list li::before { content: none; }
.cp-dept_list a {
  display: inline-block;
  padding: .38rem .7rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--font-ui);
  font-size: calc(.78rem * var(--t-ui));
  font-weight: 500;
  color: var(--fg-body);
  text-decoration: none;
  transition: border-color .3s var(--ease), color .3s var(--ease), background .3s var(--ease);
}
.cp-dept_list a:hover { border-color: var(--accent); color: var(--accent); }
.cp-dept.is-kids .cp-dept_top b { color: var(--sage); }

/* --- the finder ----------------------------------------------------------
   SERVICES, CHAPTER 2. Nobody arrives wanting "restorative dentistry"; they
   arrive with a broken tooth. Left, what is wrong, at heading size; right,
   where the practice would start. The comparison table on the homepage is
   two columns of claims; this is a two column index of problems. */
.cp-finder { margin: 0; border-top: 1px solid var(--rule-strong); }
.cp-finder_row {
  display: grid;
  gap: .5rem clamp(1.5rem, 4vw, 3.5rem);
  padding: clamp(1.1rem, 2.4vw, 1.75rem) 0;
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}
@media (min-width: 768px) { .cp-finder_row { grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); } }
.cp-finder dt {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(1.55rem * var(--t-mid));
  line-height: 1.15;
  letter-spacing: -.01em;
  color: var(--fg);
}
.cp-finder dt::before { content: "\2192"; color: var(--accent-lg); margin-right: .6rem; font-size: .8em; }
.cp-finder dd { margin: 0; font-size: var(--f-body); line-height: 1.7; color: var(--fg-body); }
.cp-finder dd a { color: var(--fg); text-decoration: none; border-bottom: 1px solid var(--rule-strong); transition: color .3s var(--ease), border-color .3s var(--ease); }
.cp-finder dd a:hover { color: var(--accent); border-color: var(--accent); }

/* --- the price list ------------------------------------------------------
   SERVICES, CHAPTER 4. The practice's published offers as a menu: item,
   dotted leader, price. The service page's cost chapter is three cards with
   one filled panel; this is one ruled list, because six offers in six boxes
   is the equal-tiles failure the whole system exists to avoid. */
.cp-menu { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule-strong); max-width: 60rem; }
.cp-menu li { border-bottom: 1px solid var(--rule); padding: 1.1rem 0; display: grid; gap: .35rem; }
.cp-menu li::before { content: none; }
.cp-menu_line { display: flex; align-items: baseline; gap: .75rem; }
.cp-menu_name { font-family: var(--font-display); font-weight: 400; font-size: var(--f-h4); color: var(--fg); flex: none; max-width: 70%; }
.cp-menu_lead { flex: 1; border-bottom: 1px dotted var(--rule-strong); transform: translateY(-.35em); min-width: 2rem; }
.cp-menu_price { font-family: var(--font-display); font-weight: 300; font-size: calc(1.6rem * var(--t-mid)); line-height: 1; color: var(--fg); flex: none; white-space: nowrap; }
.cp-menu_price s { color: var(--fg-soft); font-size: .6em; margin-right: .4em; }
.cp-menu_note { font-size: calc(.85rem * var(--t-text)); line-height: 1.55; color: var(--fg-soft); margin: 0; max-width: 60ch; }
.ch-offers { padding-bottom: calc(var(--ch-pad) * .8); }

/* ===========================================================================
   NEW PATIENTS — /new-patients/
   ======================================================================== */

/* --- the ticket ----------------------------------------------------------
   NEW PATIENTS, CHAPTER 1. The offer as a ticket: the number at the arrival
   headline size, what it buys as a receipt, and the two smaller offers torn
   off beside it on a dashed edge. The site's one page where a number is the
   biggest thing on the screen. */
.cp-ticket-row { display: grid; gap: 1.5rem; align-items: start; }
@media (min-width: 900px) { .cp-ticket-row { grid-template-columns: minmax(0, 1.25fr) minmax(0, .75fr); gap: 2rem; } }
.cp-ticket { background: var(--sand); border: 1px solid var(--beige-mid); padding: clamp(1.5rem, 3.5vw, 3rem); display: grid; gap: 1.25rem; position: relative; }
.cp-ticket_price {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d1);
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}
.cp-ticket_price small { display: block; margin-top: .8rem; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: var(--brand); }
.cp-ticket_list { margin: 0; padding: 0; list-style: none; display: grid; border-top: 1px solid var(--beige-mid); }
.cp-ticket_list li { display: flex; justify-content: space-between; gap: 1rem; padding: .7rem 0; border-bottom: 1px solid var(--beige-mid); font-size: var(--f-body); color: var(--ink); }
.cp-ticket_list li::before { content: none; }
.cp-ticket_list li b { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .12em; text-transform: uppercase; color: var(--copper); font-weight: 700; white-space: nowrap; }
.cp-ticket_note { font-size: calc(.85rem * var(--t-text)); line-height: 1.6; color: var(--body); margin: 0; }
.cp-ticket_stubs { display: grid; gap: 1.5rem; }
.cp-ticket.is-stub { background: var(--panel); border: 1px solid var(--rule); border-left: 2px dashed var(--beige-mid); gap: .6rem; }
.cp-ticket.is-stub .cp-ticket_price { font-size: var(--f-d3); }
.cp-ticket.is-stub p { margin: 0; font-size: var(--f-body); line-height: 1.6; color: var(--fg-body); }

/* --- the checklist -------------------------------------------------------
   NEW PATIENTS, CHAPTER 3. What to bring, as a list with a box in front of
   each line, beside a photograph and the offer of a tour. A tick list
   (`lf-ticks`) is a list of claims; this is a list of things to do. */
.cp-bring { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
@media (min-width: 900px) { .cp-bring { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); } }
.cp-checklist { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule-strong); }
.cp-checklist li { display: grid; grid-template-columns: 1.4rem minmax(0, 1fr); gap: 1rem; padding: 1.1rem 0; border-bottom: 1px solid var(--rule); align-items: start; }
.cp-checklist li::before { content: ""; width: 1.1rem; height: 1.1rem; margin-top: .35em; border: 1.5px solid var(--accent); position: static; transform: none; left: auto; top: auto; }
.cp-checklist b { display: block; font-family: var(--font-display); font-weight: 400; font-size: var(--f-h4); line-height: 1.25; color: var(--fg); }
.cp-checklist p { margin: .3rem 0 0; font-size: var(--f-body); line-height: 1.65; color: var(--fg-soft); }
.cp-bring_aside { display: grid; gap: 1.25rem; }
.cp-bring_aside figure { margin: 0; }
.cp-bring_aside img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; transition: filter .7s var(--ease); }
.cp-bring_aside figure:hover img { filter: none; }
.cp-bring_aside figcaption { margin-top: .65rem; padding-left: .8rem; border-left: 1.5px solid var(--accent); font-family: var(--font-ui); font-size: calc(.78rem * var(--t-ui)); line-height: 1.45; color: var(--fg-soft); }
.cp-bring_tour { background: var(--panel); border: 1px solid var(--rule); padding: clamp(1.25rem, 2.5vw, 2rem); display: grid; gap: .6rem; }
.ch .cp-bring_tour h3 { font-size: var(--f-h4); }
.cp-bring_tour p { margin: 0; font-size: var(--f-body); line-height: 1.65; }

/* --- the open Q and A ----------------------------------------------------
   NEW PATIENTS, CHAPTER 4. The questions first visits ask, open on the page
   rather than folded: question at heading size on the left, the practice's
   answer on the right. The Invisalign page folds its questions into an
   accordion because it has seven; these are five and the answers are the
   content. */
.cp-qa { margin: 0; border-top: 1px solid var(--rule-strong); }
.cp-qa_row { display: grid; gap: .6rem clamp(1.5rem, 4vw, 3.5rem); padding: clamp(1.25rem, 2.6vw, 2rem) 0; border-bottom: 1px solid var(--rule); align-items: start; }
@media (min-width: 900px) { .cp-qa_row { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); } }
.cp-qa dt { font-family: var(--font-display); font-weight: 300; font-size: var(--f-h3); line-height: 1.2; letter-spacing: -.01em; color: var(--fg); max-width: 22ch; }
.cp-qa dd { margin: 0; display: grid; gap: .9rem; }
.cp-qa dd p { margin: 0; font-size: var(--f-body); line-height: 1.72; max-width: 60ch; }

/* ===========================================================================
   INSURANCE AND FINANCING — /financing/
   ======================================================================== */

/* --- the promises --------------------------------------------------------
   FINANCING, CHAPTER 1. Three lines, each written word by word, each
   stepped further in than the one above it so the chapter reads down and
   across like a staircase. Nothing else on the site indents. */
.cp-promises { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); }
.cp-promise { display: grid; grid-template-columns: 3.5rem minmax(0, 1fr); gap: 1rem; align-items: baseline; }
.cp-promise b { font-family: var(--font-display); font-weight: 300; font-size: calc(1.6rem * var(--t-mid)); color: var(--accent-lg); }
.ch .cp-promise p { font-family: var(--font-display); font-weight: 300; font-size: var(--f-d3); line-height: 1.22; letter-spacing: -.012em; margin: 0; max-width: 26ch; }
@media (min-width: 900px) {
  .cp-promise:nth-child(2) { padding-left: 9%; }
  .cp-promise:nth-child(3) { padding-left: 18%; }
}

/* --- the matrix ----------------------------------------------------------
   FINANCING, CHAPTER 2. The four ways to pay, as a real table: one column
   each, one row per question. On a phone the columns become stacked cards,
   each cell restating its row's label through `data-label`, the lesson the
   comparison table taught (DESIGN-STANDARD.md, the second canary). */
.cp-matrix { width: 100%; border-collapse: collapse; border-top: 1px solid var(--rule-strong); }
.cp-matrix th, .cp-matrix td { text-align: left; vertical-align: top; padding: 1rem clamp(.75rem, 1.5vw, 1.25rem) 1rem 0; border-bottom: 1px solid var(--rule); font-size: var(--f-body); line-height: 1.6; color: var(--fg-body); }
.cp-matrix thead th { font-family: var(--font-display); font-weight: 400; font-size: var(--f-h4); color: var(--fg); padding-top: 1.25rem; }
.cp-matrix thead th small { display: block; margin-top: .3rem; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--accent); }
.cp-matrix tbody th { font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--fg-soft); width: 11rem; }
.cp-matrix td b { color: var(--fg); font-weight: 600; }
.cp-matrix td a { color: var(--fg); border-bottom: 1px solid var(--rule-strong); text-decoration: none; }
.cp-matrix td a:hover { color: var(--accent); border-color: var(--accent); }
@media (max-width: 767px) {
  .cp-matrix, .cp-matrix thead, .cp-matrix tbody, .cp-matrix tr, .cp-matrix th, .cp-matrix td { display: block; }
  .cp-matrix thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .cp-matrix tbody tr { padding: 1rem 0; border-bottom: 1px solid var(--rule); }
  .cp-matrix tbody th { width: auto; padding: 0 0 .6rem; border: 0; }
  .cp-matrix td { padding: .45rem 0 .45rem 0; border: 0; }
  .cp-matrix td::before { content: attr(data-label); display: block; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--accent); margin-bottom: .15rem; }
}

/* --- the callout band ----------------------------------------------------
   FINANCING, CHAPTER 3, and the close of the reviews page. A full bleed
   sand panel with one line at statement size, a sentence and a button.
   Sand is the filled ground the handoff's financing panel sampled; this is
   the only full width use of it. */
.ch-plan, .ch-write { padding: 0; }
.cp-callout { background: var(--sand); border-top: 1px solid var(--beige-mid); border-bottom: 1px solid var(--beige-mid); position: relative; }
.cp-callout::before { content: ""; position: absolute; inset: 0; background-image: var(--stone); background-size: 240px 240px; opacity: .05; pointer-events: none; }
.cp-callout_in { position: relative; max-width: var(--maxw); margin: 0 auto; padding: clamp(3rem, 6vw, 5.5rem) var(--bleed); display: grid; gap: 1.5rem; align-items: center; }
@media (min-width: 900px) { .cp-callout_in { grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); gap: clamp(2rem, 5vw, 4.5rem); } }
.ch .cp-callout_in h2 { font-size: var(--f-d3); line-height: 1.1; max-width: 18ch; color: var(--ink); }
.cp-callout_in p { font-size: var(--f-lede); line-height: 1.7; max-width: 48ch; color: var(--body); margin: 1rem 0 0; }
.cp-callout_side { display: grid; gap: 1.25rem; justify-items: start; }
.cp-callout_side ul { margin: 0; padding: 0; list-style: none; display: grid; gap: .4rem; }
.cp-callout_side li { padding-left: 1.4rem; position: relative; font-size: var(--f-body); color: var(--ink); line-height: 1.5; }
.cp-callout_side li::before { content: ""; position: absolute; left: .1rem; top: .55em; width: .45rem; height: .45rem; border-left: 1.5px solid var(--brand); border-bottom: 1.5px solid var(--brand); transform: rotate(-45deg); }

/* The accordion, in a light chapter that is not the invitation. The
   invitation scopes its own accordion rules to `.ch-invitation`; the base
   `.faq_item` component is what renders here, on the page ground. */
.ch-ways .iv-faq, .ch-questions .iv-faq { max-width: 60rem; }

/* ===========================================================================
   MEMBERSHIP PLAN — /dental-savings-plan/
   ======================================================================== */

/* --- the card ------------------------------------------------------------
   MEMBERSHIP, CHAPTER 1. The plan drawn as the card it is: credit card
   proportions, sand, the practice name, what it holds, a chip. It sits
   tilted beside the practice's own paragraph and straightens on hover. An
   object, not a panel, and the only object on the site. */
.cp-card-row { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: center; }
@media (min-width: 900px) { .cp-card-row { grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); } }
.cp-card { perspective: 1200px; }
.cp-card_face {
  aspect-ratio: 1.586;
  max-width: 30rem;
  margin: 0 auto;
  background: linear-gradient(135deg, var(--sand) 0%, #e6d9c9 60%, var(--beige) 100%);
  border: 1px solid var(--beige-mid);
  border-radius: 14px;
  padding: clamp(1.25rem, 2.6vw, 2rem);
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: .75rem;
  position: relative;
  overflow: hidden;
  transform: rotate(-3deg);
  box-shadow: 0 24px 50px rgba(30, 36, 38, .14);
  transition: transform .6s var(--ease), box-shadow .6s var(--ease);
}
.cp-card:hover .cp-card_face { transform: rotate(0deg) translateY(-4px); box-shadow: 0 30px 60px rgba(30, 36, 38, .18); }
.cp-card_face::before { content: ""; position: absolute; inset: 0; background-image: var(--stone); background-size: 240px 240px; opacity: .06; pointer-events: none; }
.cp-card_face::after { content: ""; position: absolute; right: clamp(1.25rem, 2.6vw, 2rem); top: clamp(1.25rem, 2.6vw, 2rem); width: 2.4rem; height: 1.8rem; border-radius: 4px; background: linear-gradient(135deg, var(--copper), var(--brand)); opacity: .85; }
.cp-card_brand { font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .2em; text-transform: uppercase; color: var(--brand); position: relative; }
.cp-card_title { align-self: end; font-family: var(--font-display); font-weight: 300; font-size: var(--f-d3); line-height: 1; letter-spacing: -.015em; color: var(--ink); position: relative; }
.cp-card_title small { display: block; margin-top: .5rem; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--body); }
.cp-card_lines { display: flex; flex-wrap: wrap; gap: .4rem 1.25rem; font-family: var(--font-ui); font-size: calc(.78rem * var(--t-ui)); letter-spacing: .08em; text-transform: uppercase; color: var(--ink); position: relative; }
.cp-card_copy { display: grid; gap: 1.1rem; }
.cp-card_copy p { font-size: var(--f-lede); line-height: 1.72; max-width: 54ch; margin: 0; }
.cp-card_copy .lf-more { margin-top: 0; }

/* --- the situations ------------------------------------------------------
   MEMBERSHIP, CHAPTER 3. Who the plan is for, as three numbered situations
   beside one photograph. Not personas in photo tiles: the people in the
   practice's stock frames are not its members, and a caption cannot say
   they are. */
.cp-situations { display: grid; gap: clamp(1.75rem, 3.5vw, 3rem); align-items: start; }
@media (min-width: 700px) { .cp-situations { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cp-situations { grid-template-columns: minmax(0, 1.1fr) repeat(3, minmax(0, 1fr)); } }
.cp-situations_shot { margin: 0; grid-column: 1 / -1; }
@media (min-width: 1024px) { .cp-situations_shot { grid-column: auto; } }
.cp-situations_shot img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; transition: filter .7s var(--ease); }
@media (max-width: 1023px) { .cp-situations_shot img { aspect-ratio: 16 / 7; } }
.cp-situations_shot:hover img { filter: none; }
.cp-situations_shot figcaption { margin-top: .65rem; padding-left: .8rem; border-left: 1.5px solid var(--accent); font-family: var(--font-ui); font-size: calc(.78rem * var(--t-ui)); line-height: 1.45; color: var(--fg-soft); }
.cp-situation { display: grid; gap: .8rem; align-content: start; padding-top: 1.25rem; border-top: 1px solid var(--rule-strong); }
.cp-situation b { font-family: var(--font-display); font-weight: 300; font-size: calc(2.4rem * var(--t-mid)); line-height: .9; color: var(--accent-lg); }
.ch .cp-situation h3 { font-size: var(--f-h4); line-height: 1.25; max-width: 18ch; }
.cp-situation p { margin: 0; font-size: var(--f-body); line-height: 1.68; color: var(--fg-body); }

/* --- the inline steps ----------------------------------------------------
   MEMBERSHIP, CHAPTER 4. Three steps on one hairline, the numeral in a
   ring on the line. The pinned path is for a process that needs a screen
   per step; joining a plan needs one line. */
.cp-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 2rem; position: relative; counter-reset: cps; }
@media (min-width: 768px) { .cp-steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1.5rem, 3vw, 2.5rem); } .cp-steps::before { content: ""; position: absolute; left: 0; right: 0; top: 1.4rem; height: 1px; background: var(--rule-strong); } }
.cp-steps li { position: relative; display: grid; gap: .8rem; align-content: start; counter-increment: cps; padding-left: 0; }
.cp-steps li::before {
  content: counter(cps, decimal-leading-zero);
  position: static;
  transform: none;
  width: 2.8rem;
  height: 2.8rem;
  border-radius: 50%;
  border: 1px solid var(--accent);
  background: var(--bg);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(1rem * var(--t-text));
  color: var(--accent);
  z-index: 1;
}
.cp-steps b { font-family: var(--font-display); font-weight: 400; font-size: var(--f-h4); line-height: 1.25; color: var(--fg); }
.cp-steps p { margin: 0; font-size: var(--f-body); line-height: 1.65; color: var(--fg-body); max-width: 30ch; }

/* ===========================================================================
   PATIENT REVIEWS — /patient-reviews/
   ======================================================================== */

/* --- the score -----------------------------------------------------------
   REVIEWS, CHAPTER 1. One number at the arrival headline size, counted up,
   five stars under it, and the count beside it with the line that says
   where the number comes from. */
.cp-score { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 900px) { .cp-score { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); gap: clamp(2rem, 6vw, 6rem); } }
.cp-score_num { display: grid; gap: .5rem; justify-items: start; }
/* `> b`, not `b`: the chapter tag's own <b> sits in this column and took
   the score size on the first render. */
.cp-score_num > b {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(var(--f-d1) * 1.35);
  line-height: .85;
  letter-spacing: -.04em;
  color: var(--fg);
}
.cp-score_stars { font-size: calc(1.3rem * var(--t-mid)); letter-spacing: .3em; color: var(--copper); }
.cp-score_side { display: grid; gap: 1rem; }
.cp-score_side .cp-score_count { font-family: var(--font-display); font-weight: 300; font-size: var(--f-d3); line-height: 1.05; letter-spacing: -.014em; color: var(--fg); margin: 0; max-width: 16ch; }
.cp-score_side p { font-size: var(--f-lede); line-height: 1.7; margin: 0; max-width: 50ch; }
.cp-score_side .cp-note { max-width: 50ch; }

/* --- the wall ------------------------------------------------------------
   REVIEWS, CHAPTER 3. Every review whole, in columns that pack by height,
   because a review is as long as the person wrote it and a grid of equal
   boxes would have to trim them (which DESIGN-STANDARD.md forbids). Nothing
   else on the site uses columns. */
.cp-wall { columns: 3; column-gap: clamp(1rem, 1.8vw, 1.5rem); }
@media (max-width: 999px) { .cp-wall { columns: 2; } }
@media (max-width: 599px) { .cp-wall { columns: 1; } }
.cp-review { break-inside: avoid; background: var(--panel); border: 1px solid var(--rule); padding: clamp(1.15rem, 2vw, 1.5rem); margin: 0 0 clamp(1rem, 1.8vw, 1.5rem); display: grid; gap: .7rem; transition: border-color .4s var(--ease); }
.cp-review:hover { border-color: var(--rule-strong); }
.cp-review_head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.cp-review_head cite { font-family: var(--font-ui); font-style: normal; font-size: var(--f-label); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--fg); }
.cp-review_head time { font-family: var(--font-ui); font-size: calc(.75rem * var(--t-ui)); letter-spacing: .08em; color: var(--fg-soft); white-space: nowrap; }
.cp-review_stars { font-size: calc(.85rem * var(--t-text)); letter-spacing: .25em; color: var(--copper); }
.cp-review p { margin: 0; font-size: var(--f-body); line-height: 1.7; color: var(--fg-body); }
.cp-review p[lang] { font-style: italic; }
.cp-review_tag { font-family: var(--font-ui); font-size: calc(.72rem * var(--t-ui)); letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }

/* --- the kids ------------------------------------------------------------
   REVIEWS, CHAPTER 4. The reviews parents leave, on ink, in two columns of
   italic display type with the sage pill the homepage uses for the
   pediatric practice. */
.cp-kids { display: grid; gap: clamp(2rem, 4vw, 3.5rem); }
@media (min-width: 860px) { .cp-kids { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.cp-kid { display: grid; gap: 1rem; align-content: start; padding-top: 1.5rem; border-top: 1px solid var(--rule); }
.cp-kid blockquote { margin: 0; font-family: var(--font-display); font-weight: 300; font-style: italic; font-size: calc(1.3rem * var(--t-mid)); line-height: 1.45; color: var(--fg); }
.cp-kid blockquote[lang] { font-style: normal; }
.cp-kid cite { display: block; font-family: var(--font-ui); font-style: normal; font-size: var(--f-label); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); }
.cp-kid .tg-pill { align-self: start; justify-self: start; }

/* ===========================================================================
   THANK YOU — /thank-you/
   ======================================================================== */

/* --- the call box --------------------------------------------------------
   THANK YOU, CHAPTER 1. The phone number at chapter headline size, because
   the one thing a person in pain needs from a thank you page is the number,
   not a paragraph. Hours beside it. */
.cp-callbox { display: grid; gap: 2rem; align-items: center; border-top: 1px solid var(--rule-strong); border-bottom: 1px solid var(--rule); padding: clamp(2rem, 4vw, 3.5rem) 0; }
@media (min-width: 900px) { .cp-callbox { grid-template-columns: minmax(0, 1.3fr) minmax(0, .7fr); gap: clamp(2rem, 5vw, 5rem); } }
.cp-callbox_main { display: grid; gap: .9rem; justify-items: start; }
.cp-callbox_main a.cp-callbox_tel {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--f-d2);
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--fg);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
  padding-bottom: .1em;
  transition: color .3s var(--ease);
}
.cp-callbox_main a.cp-callbox_tel:hover { color: var(--accent); }
.cp-callbox_main p { margin: 0; font-size: var(--f-lede); line-height: 1.65; max-width: 44ch; }
.cp-callbox_hours { margin: 0; padding: 0; list-style: none; display: grid; gap: .35rem; }
.cp-callbox_hours li { display: flex; justify-content: space-between; gap: 1rem; padding: .4rem 0; border-bottom: 1px solid var(--rule); font-size: calc(.9rem * var(--t-text)); color: var(--fg-body); }
.cp-callbox_hours li::before { content: none; }
.cp-callbox_hours li b { color: var(--fg); font-weight: 600; }
.cp-callbox_hours li.is-shut b { color: var(--fg-soft); font-weight: 500; }

/* --- the timeline --------------------------------------------------------
   THANK YOU, CHAPTER 2. What happens next, as three moments down a vertical
   rule. Not the pinned path: nothing here is long enough to pin, and the
   reader has already acted. */
.cp-timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; position: relative; max-width: 52rem; }
.cp-timeline::before { content: ""; position: absolute; left: .55rem; top: .6rem; bottom: .6rem; width: 1px; background: var(--rule-strong); }
.cp-timeline li { position: relative; padding: 0 0 clamp(1.75rem, 3.5vw, 2.75rem) 2.75rem; display: grid; gap: .5rem; }
.cp-timeline li:last-child { padding-bottom: 0; }
.cp-timeline li::before { content: ""; position: absolute; left: 0; top: .35rem; width: 1.1rem; height: 1.1rem; border-radius: 50%; border: 1.5px solid var(--accent); background: var(--bg); transform: none; }
.cp-timeline_when { font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--accent); }
.ch .cp-timeline h3 { font-size: var(--f-h3); line-height: 1.15; max-width: 22ch; }
.cp-timeline p { margin: 0; font-size: var(--f-body); line-height: 1.7; max-width: 56ch; }

/* A card that is a link. The Invisalign page's cards are <article>, so this
   cannot reach them; the thank you page's are <a>, and the base anchor rule
   was underlining every word inside them. */
a.svc-card { text-decoration: none; color: inherit; }
a.svc-card .svc-card_name, a.svc-card .svc-card_text { text-decoration: none; }


/* ===========================================================================
   THE ELEVATION LAYER — 2026-09-02, second cut. See home/assets/elevate.js.

   The first cut ported the Stone Surgical Arts components one for one and
   the client said so: "You practically cloned the stone site structure.
   None of our client sites should be the same." These are different shapes
   for the same brief (more images, less text, more animation), none of
   which the Stone build has: the stack, the columns, the tabs, the finder
   with a side panel, the deck, the pair, the pillars, the pane, the sheet,
   the seal. Kept from the first cut because they are this site's own or
   generic technique: the mosaic (Mason Park's cp-mosaic, elevated), the
   trio, mask reveals, parallax frames, el-head and el-fold.

   TOKENS. Nothing new at :root. Six chapter colours, the rem type tiers,
   --ch-pad and --bleed. Newsreader / Nunito Sans / Karla, untouched.

   NAMESPACE `.el-*`, attributes `[data-el="mask"]` and `[data-parallax]`.
   Hidden states are scoped to `html.el-ready`; `html.el-reduce` is the
   reduced-motion branch. LAST in the sheet on purpose; keep it last.
   ======================================================================== */

/* --- image mask reveal ---------------------------------------------------- */
html.el-ready:not(.el-reduce) [data-el="mask"] { clip-path: inset(100% 0 0 0); transition: clip-path 1.3s var(--ease); }
html.el-ready:not(.el-reduce) [data-el="mask"] img { transform: scale(1.16); transition: transform 1.5s var(--ease); }
html.el-ready:not(.el-reduce) [data-el="mask"].is-in { clip-path: inset(0 0 0 0); }
html.el-ready:not(.el-reduce) [data-el="mask"].is-in img { transform: none; }
[data-el="mask"] { overflow: clip; }
[data-parallax] { overflow: clip; }
[data-parallax] img { height: 100%; width: 100%; object-fit: cover; display: block; }
html.el-ready [data-parallax] img { will-change: transform; }
[data-parallax] [data-el="mask"] { height: 100%; }
.el-fill { height: 100%; }

/* --- the stack ------------------------------------------------------------
   Three frames of the practice on each other at the hero's right edge,
   fanned by a few degrees. elevate.js spreads them as the page scrolls.
   Below 992 they sit as a small row under the copy. */
.el-stack { position: absolute; right: calc(var(--bleed) + 4rem); bottom: calc(clamp(3rem, 7vh, 6rem) + 5rem); z-index: 2; width: 14rem; aspect-ratio: 4 / 5; }
.el-stack_frame { position: absolute; inset: 0; margin: 0; overflow: clip; border: 4px solid rgba(255, 255, 255, .92); box-shadow: 0 30px 60px -30px rgba(0, 0, 0, .7); background: var(--ink-mid); transform-origin: 50% 110%; }
.el-stack_frame:nth-child(1) { transform: rotate(-6deg); }
.el-stack_frame:nth-child(2) { transform: rotate(0deg); }
.el-stack_frame:nth-child(3) { transform: rotate(6deg); }
.el-stack_frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.el-stack_frame figcaption { position: absolute; left: 0; right: 0; bottom: 0; padding: .5rem .7rem; background: linear-gradient(180deg, rgba(30, 36, 38, 0), rgba(30, 36, 38, .8)); color: #fff; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .12em; text-transform: uppercase; }
.ch-arrival.is-compact .el-stack { display: none; }
@media (max-width: 1279px) { .el-stack { width: 11rem; right: calc(var(--bleed) + 3rem); } }
@media (max-width: 991px) { .el-stack { display: none; } }

/* The rating, as a fourth fact in the hero's strip rather than a pill. */
.ar-meta .el-rating b { display: inline-flex; align-items: baseline; gap: .5rem; }
.ar-meta .el-rating b i { font-style: normal; font-size: .8em; letter-spacing: .08em; color: #e3c3a8; }

/* --- the columns ----------------------------------------------------------
   A photo wall: three columns, each a stack of frames, moving at three
   speeds against the scroll. The wall is clipped a little shorter than
   its columns so the travel never shows an edge. Below 900 it is one
   snapping row. */
.el-columns { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; height: 52rem; overflow: clip; align-items: start; }
.el-columns_col { display: grid; gap: 1.25rem; }
.el-columns_col:nth-child(2) { margin-top: -5rem; }
.el-columns_col:nth-child(3) { margin-top: -2rem; }
.el-columns_tile { margin: 0; overflow: clip; background: var(--bg-2); }
.el-columns_tile.is-tall { aspect-ratio: 3 / 4; }
.el-columns_tile.is-wide { aspect-ratio: 4 / 3; }
.el-columns_tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .8s var(--ease); }
.el-columns_tile:hover img { transform: scale(1.04); }
@media (max-width: 899px) {
  .el-columns { display: flex; height: auto; overflow-x: auto; gap: .9rem; scroll-snap-type: x mandatory; scroll-padding-left: var(--bleed); padding-bottom: .5rem; margin: 0 calc(var(--bleed) * -1); padding-left: var(--bleed); padding-right: var(--bleed); }
  .el-columns_col { display: contents; }
  .el-columns_tile { flex: 0 0 68vw; scroll-snap-align: start; aspect-ratio: 4 / 3; }
  .el-columns_tile.is-tall { flex-basis: 52vw; aspect-ratio: 3 / 4; }
}

/* --- the tabs -------------------------------------------------------------
   Service groups as a row of names in the display face. The active one is
   copper with a rule under it; its frame is a big photograph on the left,
   its chips sit in a panel on the right. */
.el-tabs_row { display: flex; flex-wrap: wrap; gap: .4rem 2rem; margin: 0 0 2.4rem; padding: 0; list-style: none; border-bottom: 1px solid var(--rule-strong); }
.el-tabs_tab { display: inline-block; padding: .4rem 0 .9rem; margin-bottom: -1px; font-family: var(--font-display); font-weight: 300; font-size: calc(2rem * var(--t-lg)); line-height: 1; color: var(--fg-soft); text-decoration: none; border-bottom: 2px solid transparent; transition: color .3s var(--ease), border-color .3s var(--ease); }
.el-tabs_tab:hover, .el-tabs_tab.is-active { color: var(--accent); border-color: var(--accent); }
.el-tabs_body { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: clamp(1.5rem, 4vw, 4rem); align-items: stretch; }
.el-tabs_frames { position: relative; margin: 0; min-height: 30rem; overflow: clip; background: var(--bg-2); }
.el-tabs_frames img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transform: scale(1.05); transition: opacity .7s var(--ease), transform 1.3s var(--ease); }
.el-tabs_frames img.is-active { opacity: 1; transform: none; }
html:not(.el-ready) .el-tabs_frames img:first-child { opacity: 1; transform: none; }
.el-tabs_count { position: absolute; left: 0; bottom: 0; z-index: 2; margin: 0; padding: .7rem 1.1rem; background: var(--panel); border-top: 1px solid var(--accent-lg); font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .16em; text-transform: uppercase; color: var(--fg-soft); }
.el-tabs_panels { position: relative; display: grid; }
.el-tabs_panel { grid-area: 1 / 1; opacity: 0; transform: translateY(.6rem); transition: opacity .5s var(--ease), transform .5s var(--ease); pointer-events: none; display: flex; flex-direction: column; justify-content: center; padding: 1.5rem 0; }
.el-tabs_panel.is-active { opacity: 1; transform: none; pointer-events: auto; }
html:not(.el-ready) .el-tabs_panel { position: static; opacity: 1; transform: none; pointer-events: auto; }
.el-tabs_panel h3 { margin: 0 0 .6rem; }
.el-tabs_text { margin: 0 0 1.4rem; color: var(--fg-body); font-size: var(--f-lede); line-height: 1.6; max-width: 32rem; }
.el-tabs_chips { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: .5rem .6rem; }
.el-tabs_chip { display: inline-flex; align-items: center; padding: .5rem .95rem; border: 1px solid var(--rule-strong); border-radius: 2px; font-family: var(--font-ui); font-size: calc(.8rem * var(--t-ui)); letter-spacing: .04em; color: var(--fg); text-decoration: none; background: var(--panel); transition: background-color .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease); }
a.el-tabs_chip:hover, a.el-tabs_chip:focus-visible { background: var(--accent); border-color: var(--accent); color: #fff; }
span.el-tabs_chip { color: var(--fg-soft); background: transparent; border-style: dashed; }
.el-tabs_panel .link-arrow { margin-top: 1.4rem; align-self: flex-start; }
@media (max-width: 899px) {
  .el-tabs_row { gap: .2rem 1.2rem; }
  .el-tabs_tab { font-size: calc(1.5rem * var(--t-lg)); padding-bottom: .6rem; }
  .el-tabs_body { grid-template-columns: 1fr; }
  .el-tabs_frames { min-height: 0; aspect-ratio: 4 / 3; margin: 0 calc(var(--bleed) * -1); }
}

/* --- the finder -----------------------------------------------------------
   What is wrong on the left, where the practice would start under it, and a
   sticky panel on the right showing the room where that happens. */
.el-finder_layout { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); gap: clamp(2rem, 5vw, 5rem); align-items: start; }
.el-finder_list { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule-strong); }
.el-finder_item { border-bottom: 1px solid var(--rule-strong); }
.el-finder_row { display: grid; grid-template-columns: 3rem minmax(0, 1fr); gap: .35rem 1.2rem; padding: 1.2rem 0; color: var(--fg); text-decoration: none; transition: padding-left .45s var(--ease), background-color .45s var(--ease); }
.el-finder_row:hover, .el-finder_row.is-current { padding-left: .8rem; }
.el-finder_num { grid-row: span 2; font-family: var(--font-display); font-size: var(--f-h4); color: var(--accent); letter-spacing: .06em; padding-top: .35rem; }
.el-finder_text { font-family: var(--font-display); font-weight: 300; font-size: calc(1.9rem * var(--t-lg)); line-height: 1.08; transition: color .3s var(--ease); }
.el-finder_row.is-current .el-finder_text { color: var(--accent); }
.el-finder_to { font-family: var(--font-body); font-size: var(--f-body); color: var(--fg-body); line-height: 1.5; max-width: 40rem; }
.el-finder_to b { font-family: var(--font-ui); font-weight: 500; font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); margin-right: .6rem; }
.el-finder_panel { position: sticky; top: 7rem; margin: 0; aspect-ratio: 4 / 5; overflow: clip; background: var(--bg-2); }
.el-finder_panel img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transform: scale(1.04); transition: opacity .6s var(--ease), transform 1.2s var(--ease); }
.el-finder_panel img.is-active { opacity: 1; transform: none; }
html:not(.el-ready) .el-finder_panel img:first-child { opacity: 1; transform: none; }
.el-finder_caption { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; margin: 0; padding: .8rem 1.1rem; background: linear-gradient(180deg, rgba(30, 36, 38, 0), rgba(30, 36, 38, .82)); color: #fff; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; }
@media (max-width: 899px) {
  .el-finder_layout { grid-template-columns: 1fr; gap: 1.5rem; }
  .el-finder_panel { position: relative; top: auto; order: -1; aspect-ratio: 16 / 10; margin: 0 calc(var(--bleed) * -1); }
  .el-finder_text { font-size: calc(1.5rem * var(--t-lg)); }
  .el-finder_row { grid-template-columns: 2.2rem minmax(0, 1fr); }
}

/* --- the deck -------------------------------------------------------------
   Reviews as cards that pile up. Each card is sticky at the same offset,
   so the next one slides over the last as the page scrolls; elevate.js
   scales the covered ones back. A photograph card sits in the pile too. */
.el-deck { display: grid; gap: 1.5rem; }
.el-deck_card { position: sticky; top: 7rem; margin: 0; background: var(--panel); border: 1px solid var(--rule); padding: clamp(1.5rem, 3vw, 2.6rem); display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1.2rem 2rem; align-items: end; transform-origin: 50% 0; box-shadow: 0 30px 50px -40px rgba(46, 53, 56, .5); }
.el-deck_card blockquote { grid-column: 1 / -1; margin: 0; font-family: var(--font-display); font-weight: 300; font-size: calc(1.9rem * var(--t-lg)); line-height: 1.22; color: var(--fg); letter-spacing: -.005em; text-wrap: pretty; }
.el-deck_card.is-long blockquote { font-size: calc(1.45rem * var(--t-lg)); line-height: 1.32; }
.el-deck_card figcaption { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .16em; text-transform: uppercase; color: var(--fg); }
.el-deck_card figcaption span { color: var(--fg-soft); }
.el-deck_card figcaption span::before { content: ""; display: inline-block; width: 1.5rem; height: 1px; background: var(--accent-lg); vertical-align: middle; margin: 0 .8rem; }
.el-deck_stars { font-size: .85rem; letter-spacing: .12em; color: var(--accent-lg); }
.el-deck_card.is-photo { padding: 0; border: 0; aspect-ratio: 16 / 7; overflow: clip; display: block; }
.el-deck_card.is-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.el-deck_card.is-photo figcaption { position: absolute; left: 0; bottom: 0; padding: .8rem 1.2rem; background: rgba(253, 252, 251, .92); color: var(--fg-soft); }
.el-deck_foot { display: flex; align-items: center; flex-wrap: wrap; gap: 1rem 1.5rem; margin-top: 2.4rem; }
.el-deck_score { font-family: var(--font-display); font-weight: 300; font-size: calc(3rem * var(--t-disp)); line-height: 1; color: var(--fg); }
.el-deck_score-label { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); margin-right: auto; }
@media (max-width: 767px) { .el-deck_card { top: 5.5rem; } .el-deck_card.is-photo { aspect-ratio: 4 / 3; } }

/* --- the live reviews (rv-) ----------------------------------------------
   The practice's own Google reviews widget (Elfsight All-in-One 32926aff, the
   one from the old site), where the homepage deck and the reviews wall were
   (2026-09-30). On Instatic the slot is a brandklout.embed-origins Embed and
   comes back as `.rv-embed.wz-embed` with the widget inside; locally it is an
   empty panel that says so. The min-height holds the chapter open until
   platform.js boots, so the scenes below do not jump. */
.rv-embed { display: block; width: 100%; min-height: 26rem; }
.rv-embed.wz-embed > * { width: 100%; max-width: 100%; }
.rv-embed:not(.wz-embed) { display: grid; place-content: center; text-align: center; border: 1px solid var(--rule); background: var(--panel); font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); }
.rv-embed:not(.wz-embed)::before { content: "Google reviews, live from the practice's profile"; }

/* --- the pair -------------------------------------------------------------
   Two half-bleed photographs, one from each edge, and a line between them. */
.el-pair { position: relative; display: grid; grid-template-columns: 1fr 1fr; gap: 0; padding: 0; overflow: clip; background: var(--bg); }
.el-pair_frame { margin: 0; aspect-ratio: 4 / 3; overflow: clip; background: var(--bg-2); }
.el-pair_frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.el-pair_line { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 2; margin: 0; padding: 1.1rem 1.8rem; background: var(--panel); border: 1px solid var(--rule); font-family: var(--font-display); font-weight: 300; font-size: var(--f-d3); line-height: 1.1; color: var(--fg); text-align: center; white-space: nowrap; box-shadow: 0 30px 60px -40px rgba(46, 53, 56, .5); }
.el-pair_line em { font-style: italic; color: var(--accent-lg); }
@media (max-width: 767px) { .el-pair_frame { aspect-ratio: 3 / 4; } .el-pair_line { white-space: normal; padding: .8rem 1rem; font-size: var(--f-h3); max-width: 70%; } }

/* --- the pillars ----------------------------------------------------------
   Three tall portraits in a row, each with a name, a role and one line.
   elevate.js reveals them left to right on the scroll. */
.el-pillars { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1rem, 3vw, 2.5rem); align-items: start; }
.el-pillar { margin: 0; }
.el-pillar_frame { aspect-ratio: 3 / 4; overflow: clip; background: var(--bg-2); }
.el-pillar_frame img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 15%; display: block; }
.el-pillar_frame.is-small img { object-fit: contain; object-position: 50% 100%; background: var(--paper); }
.el-pillar_copy { padding: 1.2rem 0 0; }
.el-pillar_copy h3 { margin: 0 0 .25rem; }
.el-pillar_role { margin: 0 0 .8rem; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--accent); }
.el-pillar_line { margin: 0; color: var(--fg-body); font-size: var(--f-body); line-height: 1.6; }
.el-pillar_copy .el-fold { margin-top: .8rem; }
@media (max-width: 767px) { .el-pillars { grid-template-columns: 1fr; gap: 2.5rem; } .el-pillar_frame { max-width: 22rem; } }

/* --- the pane -------------------------------------------------------------
   A dark chapter split with a tall photograph in a narrow column. The copy
   keeps the ink; the picture keeps its colour. */
.el-pane_layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, .42fr); gap: clamp(2rem, 5vw, 5rem); align-items: stretch; }
.el-pane { position: relative; margin: 0; overflow: clip; background: var(--bg-2); min-height: 28rem; }
.el-pane img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.el-pane figcaption { position: absolute; left: 0; right: 0; bottom: 0; padding: .8rem 1.1rem; background: linear-gradient(180deg, rgba(30, 36, 38, 0), rgba(30, 36, 38, .85)); color: #fff; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; }
@media (max-width: 899px) { .el-pane_layout { grid-template-columns: 1fr; } .el-pane { min-height: 0; aspect-ratio: 16 / 10; } }

/* --- the sheet ------------------------------------------------------------
   A contact sheet: uniform tiles, grayscale at rest and colour under the
   pointer, the same treatment the homepage gives its small imagery. One
   caption line under the sheet says what the tile under the pointer shows. */
.el-sheet_grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .75rem; }
.el-sheet_tile { margin: 0; aspect-ratio: 1; overflow: clip; background: var(--bg-2); display: block; }
.el-sheet_tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: filter .5s var(--ease), transform .8s var(--ease); }
.el-sheet_tile:hover img, .el-sheet_tile:focus-visible img { filter: none; transform: scale(1.04); }
html.el-reduce .el-sheet_tile img { filter: none; }
.el-sheet_line { margin: 1.2rem 0 0; min-height: 1.5em; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); }
@media (max-width: 767px) { .el-sheet_grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* --- the seal -------------------------------------------------------------
   A ring of type built by elevate.js from data-text, turning with the
   scroll, with a mark in the middle. Sits in a chapter's corner. */
.el-seal { position: absolute; z-index: 2; width: 9rem; height: 9rem; right: var(--bleed); top: var(--ch-pad); pointer-events: none; }
.el-seal.is-low { top: auto; bottom: var(--ch-pad); }
.el-seal.is-left { right: auto; left: var(--bleed); }
.el-seal_ring { position: absolute; inset: 0; }
.el-seal_ring i { position: absolute; left: 50%; top: 0; width: 1ch; height: 50%; margin-left: -.5ch; transform-origin: 50% 100%; font-style: normal; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); text-align: center; }
.el-seal_mark { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--font-display); font-weight: 300; font-size: var(--f-h3); color: var(--fg); }
.el-seal::before { content: ""; position: absolute; inset: 1.6rem; border: 1px solid var(--rule-strong); border-radius: 50%; }
.ch[data-theme="dark"] .el-seal_ring i { color: var(--accent); }
@media (max-width: 767px) { .el-seal { width: 6.5rem; height: 6.5rem; top: 1.5rem; } .el-seal::before { inset: 1.2rem; } .el-seal.is-low { bottom: 1.5rem; } }

/* --- the mosaic -----------------------------------------------------------
   Photographs at three sizes on a twelve column grid, one sentence in the
   cell that is not a picture. This site's own cp-mosaic, elevated. */
.el-mosaic { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); grid-auto-rows: 9rem; gap: 1rem; }
.el-mosaic_tile { margin: 0; overflow: clip; background: var(--bg-2); position: relative; }
.el-mosaic_tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .8s var(--ease); }
.el-mosaic_tile:hover img { transform: scale(1.04); }
.el-mosaic_tile.is-a { grid-column: 1 / 8; grid-row: span 3; }
.el-mosaic_tile.is-b { grid-column: 8 / 13; grid-row: span 2; }
.el-mosaic_tile.is-e { grid-column: 1 / 5; grid-row: span 2; }
.el-mosaic_tile.is-f { grid-column: 5 / 9; grid-row: span 2; }
.el-mosaic_tile.is-g { grid-column: 9 / 13; grid-row: span 2; }
.el-mosaic_copy { grid-column: 8 / 13; grid-row: span 1; display: flex; align-items: center; padding: 0 1.4rem; background: var(--panel); border: 1px solid var(--rule); margin: 0; font-family: var(--font-display); font-weight: 300; font-size: var(--f-h4); line-height: 1.3; color: var(--fg); }
.el-mosaic_tile figcaption { position: absolute; left: 0; right: 0; bottom: 0; padding: .6rem .9rem; background: linear-gradient(180deg, rgba(30, 36, 38, 0) 0%, rgba(30, 36, 38, .7) 100%); color: #fff; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .12em; text-transform: uppercase; opacity: 0; transform: translateY(.4rem); transition: opacity .35s var(--ease), transform .35s var(--ease); }
.el-mosaic_tile:hover figcaption { opacity: 1; transform: none; }
@media (max-width: 767px) {
  .el-mosaic { grid-auto-rows: 7rem; gap: .6rem; }
  .el-mosaic_tile.is-a { grid-column: 1 / 13; grid-row: span 3; }
  .el-mosaic_tile.is-b { grid-column: 1 / 8; grid-row: span 2; }
  .el-mosaic_tile.is-e { grid-column: 1 / 7; grid-row: span 2; }
  .el-mosaic_tile.is-f { grid-column: 7 / 13; grid-row: span 2; }
  .el-mosaic_tile.is-g { grid-column: 1 / 13; grid-row: span 2; }
  .el-mosaic_copy { grid-column: 1 / 13; }
}

/* --- the trio -------------------------------------------------------------
   Photograph cards with one line each, leaning toward the pointer. */
.el-trio { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.5rem; }
.el-trio_card { margin: 0; position: relative; overflow: clip; background: var(--bg-2); aspect-ratio: 3 / 4; transition: transform .6s var(--ease); transform-style: preserve-3d; }
.el-trio_card img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1s var(--ease); }
.el-trio_card:hover img { transform: scale(1.05); }
.el-trio_card figcaption { position: absolute; left: 0; right: 0; bottom: 0; padding: 1.4rem 1.4rem 1.2rem; background: linear-gradient(180deg, rgba(30, 36, 38, 0) 0%, rgba(30, 36, 38, .82) 100%); color: #fff; }
.el-trio_card figcaption b { display: block; font-family: var(--font-ui); font-weight: 500; font-size: var(--f-label); letter-spacing: .16em; text-transform: uppercase; color: #e3c3a8; margin-bottom: .35rem; }
.el-trio_card figcaption span { display: block; font-family: var(--font-display); font-weight: 400; font-size: var(--f-h3); line-height: 1.15; }
.el-trio_card figcaption small { display: block; margin-top: .5rem; font-family: var(--font-body); font-size: var(--f-body); color: rgba(255, 255, 255, .8); line-height: 1.5; }
.el-trio.is-four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 991px) { .el-trio, .el-trio.is-four { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; } }
@media (max-width: 599px) { .el-trio, .el-trio.is-four { grid-template-columns: 1fr; } .el-trio_card { aspect-ratio: 4 / 3; } }

/* --- the chapter head, shared by the new chapters ------------------------ */
.el-head { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .6fr); gap: 2rem 3rem; align-items: end; margin-bottom: 3.2rem; }
.el-head h2 { margin: 0; }
.el-head .chapter-tag { margin-bottom: 1.2rem; }
.el-head_lede { margin: 0; font-size: var(--f-lede); line-height: 1.6; max-width: 34rem; color: var(--fg-body); }
@media (max-width: 899px) { .el-head { grid-template-columns: 1fr; align-items: start; margin-bottom: 2.2rem; } }

/* --- the scroll cue, light variant, for the compact arrival ---------------- */
.el-cue { display: flex; align-items: center; gap: .8rem; margin: 2rem 0 0; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .22em; text-transform: uppercase; color: rgba(255, 255, 255, .6); }
.el-cue i { position: relative; width: 3.5rem; height: 1px; background: rgba(255, 255, 255, .3); overflow: hidden; }
.el-cue i::after { content: ""; position: absolute; inset: 0; background: #e3c3a8; transform: translateX(-100%); animation: el-cue 2.2s var(--ease) infinite; }
@keyframes el-cue { 0% { transform: translateX(-100%); } 60% { transform: translateX(0); } 100% { transform: translateX(100%); } }
html.el-reduce .el-cue i::after { animation: none; transform: none; }
@media (max-width: 767px) { .el-cue { display: none; } }

/* --- the prose that stayed: shorter, and folded -------------------------- */
.el-fold { margin-top: 1rem; }
.el-fold summary { cursor: pointer; list-style: none; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--accent); display: inline-flex; align-items: center; gap: .6rem; padding-bottom: .45rem; border-bottom: 1px solid var(--rule-strong); }
.el-fold summary::-webkit-details-marker { display: none; }
.el-fold summary::after { content: "+"; font-family: var(--font-display); font-size: 1.1rem; line-height: 1; transition: transform .3s var(--ease); }
.el-fold[open] summary::after { transform: rotate(45deg); }
.el-fold > *:not(summary) { margin-top: 1.2rem; }
.el-fold p { font-size: var(--f-body); line-height: 1.65; max-width: 62ch; }
.el-fold p + p { margin-top: .8rem; }

/* --- photographs between the reviews on the wall ------------------------- */
.cp-wall .el-wall_photo { break-inside: avoid; margin: 0 0 1.25rem; overflow: clip; background: var(--bg-2); aspect-ratio: 4 / 5; }
.cp-wall .el-wall_photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ===========================================================================
   THE BLOG GRID  (bl-)
   ---------------------------------------------------------------------------
   The index of 161 articles. Deliberately a TYPE grid and not a photo grid:
   the posts' original hero images still sit on the WordPress host this build
   replaces, and hotlinking them would make the new site depend on the old one.
   Cards carry a topic, a date and the practice's own description instead.

   Three columns above 1080, two above 700, one below. The breakpoint order
   matters -- see the Instatic note in process 22 about custom conditions
   emitting in array order, which once flattened this grid from three columns
   to two on the live site.
   =========================================================================== */
.bl-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
@media (min-width: 700px)  { .bl-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .bl-grid { grid-template-columns: repeat(3, 1fr); } }

.bl-card { background: var(--panel); }
.bl-card_link {
  display: flex; flex-direction: column; gap: .55rem; height: 100%;
  padding: 1.6rem 1.5rem 1.5rem; text-decoration: none; color: inherit;
  transition: background-color .25s var(--ease);
}
.bl-card_link:hover, .bl-card_link:focus-visible { background: var(--warm); }

.bl-card_meta {
  display: flex; flex-wrap: wrap; gap: .5rem .75rem; align-items: baseline;
  font-family: var(--font-ui); font-size: calc(.68rem * var(--t-ui));
  letter-spacing: .09em; text-transform: uppercase; color: var(--fg-soft);
}
.bl-card_meta b { color: var(--accent); font-weight: 700; }

/* `.bl-card_title` is an h3 inside a link. Scope the reset tightly: the base
   sheet underlines every word of an anchor, and a card that is an <a> inherits
   that on all of its text -- the same trap `a.svc-card` documents. */
.bl-card_link .bl-card_title { margin: 0; font-size: calc(1.05rem * var(--t-ui)); line-height: 1.25; text-decoration: none; }
.bl-card_link .bl-card_text { margin: 0; color: var(--fg-soft); font-size: calc(.86rem * var(--t-ui)); line-height: 1.5; text-decoration: none; }

.bl-card_more { margin-top: auto; padding-top: .5rem; font-family: var(--font-ui); font-size: calc(.72rem * var(--t-ui)); letter-spacing: .06em; color: var(--accent); }
.bl-card_link:hover .bl-card_more { text-decoration: underline; }

/* The article body reuses lf-layout is-solo, which is already the site's 72ch
   prose column. Only the heading rhythm inside a generated article needs
   setting, because extract-posts.mjs emits bare <h2> and <p>. */
.lf-body h2 { margin: 2rem 0 .6rem; font-size: calc(1.15rem * var(--t-ui)); line-height: 1.3; }
.lf-body h2:first-child { margin-top: 0; }

/* --- the blog pager ------------------------------------------------------ */
.bl-pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; margin-top: 2rem; }
.bl-pager_nums { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; margin: 0; padding: 0; }
.bl-page {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.4rem; padding: .5rem .7rem; border: 1px solid var(--rule-strong);
  font-family: var(--font-ui); font-size: calc(.78rem * var(--t-ui));
  color: var(--fg); text-decoration: none; background: var(--panel);
  transition: background-color .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
a.bl-page:hover, a.bl-page:focus-visible { background: var(--accent); border-color: var(--accent); color: #fff; }
.bl-page.is-current { background: var(--fg); border-color: var(--fg); color: #fff; }
.bl-page.is-off { opacity: .35; }

/* ---------------------------------------------------------------------------
   Instatic's loop "Load more" button.

   The blog listing is a `base.loop` in `infinite` mode, and loop-runtime.js
   creates this button at runtime and appends it INSIDE the loop element -- so
   a <button> lands as a direct child of `ul.bl-grid` and takes a grid cell.
   Left alone it is an unstyled browser button sitting in a card slot. It
   spans the full row instead and reads as the last panel in the grid, which
   is what it is: the way to see the next 24 articles.

   The class name is the runtime's, not ours (`instatic-loop-load-more`), and
   this rule is the only thing standing between a 161-article blog and a
   24-article one -- there is no numeric paginator module in Instatic yet.
--------------------------------------------------------------------------- */
.instatic-loop-load-more {
  grid-column: 1 / -1;
  appearance: none; -webkit-appearance: none;
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  width: 100%; padding: 1.35rem 1.5rem;
  background: var(--panel); border: 0; cursor: pointer;
  font-family: var(--font-ui); font-size: calc(.78rem * var(--t-ui));
  letter-spacing: .09em; text-transform: uppercase; color: var(--fg);
  transition: background-color .25s var(--ease), color .25s var(--ease);
}
.instatic-loop-load-more:hover:not(:disabled),
.instatic-loop-load-more:focus-visible { background: var(--warm); }
.instatic-loop-load-more:disabled { cursor: default; color: var(--fg-soft); }


/* ===========================================================================
   THE SECOND ELEVATION — services, blog listing, articles. 2026-09-10.

   Client, reviewing staging: "There are some layouts that look messy" on the
   services pages, the blog overview and the articles. What was messy, and
   what this block does about it:

     the grids     A svc-grid mixed photo cards with text cards and let each
                   card take its own height, so a 4-up read as four boxes at
                   four heights with holes under the short ones -- and the
                   stagger, drawn to make two ranks, made it worse. Rows are
                   now equal height, and a card WITHOUT a photograph is a
                   tonal plate: sand ground, the numeral large, the copy at
                   the foot. Photo and plate alternate and the set reads as
                   one mosaic instead of a shelf of uneven boxes.
     the ledger    A long uppercase label ("Porcelain-fused-to-metal") ran out
                   of its cell and was clipped. Labels wrap, and a ledger
                   inside an overlap panel is two columns, not auto-fit.
     the provider  Dr. Sung's only portrait was 230x300, so the band was sized
                   to hide that. His own practice site publishes a 3703x4000
                   portrait (see album-manifest `dr-sung`); the band is now a
                   proper feature: a tall frame on an offset plate, in colour.
     the blog      A WordPress-shaped grid of 161 identical white cards. Now an
                   editorial index: a topic strip with counted numbers, the
                   newest article as a featured plate, an ink card every ninth
                   to break the run, a numeral on every card.
     the article   A 72ch column with two thirds of the screen empty beside it.
                   Now a reading frame: a sticky rail (contents built from the
                   headings by elevate.js, the facts, the booking button, one
                   photograph) beside the prose; a lede paragraph, a drop cap,
                   ruled headings, and related articles as cards.

   Every selector here is either new (`sv-`, `bl-`) or scoped to a services
   chapter; the homepage carries none of these classes and its four heights
   must not move (`probe-heights.mjs --diff base`). The Invisalign page DOES
   move, deliberately -- re-save the baseline after this is approved.
   =========================================================================== */

/* --- equal rows, and the tonal plate ------------------------------------ */
.svc-grid { align-items: stretch; }
.svc-card { height: 100%; }
/* The photograph grows with the row. Its box is at least 4:3 (the aspect
   ratio on the WRAPPER, so it has a size before the image loads) and the
   image is absolute inside it, so a taller row gives a taller photograph
   rather than a band of empty panel under a fixed one. */
.svc-card_media { position: relative; flex: 1 1 auto; min-height: 0; aspect-ratio: 4 / 3; }
.svc-card_media img { position: absolute; inset: 0; width: 100%; height: 100%; aspect-ratio: auto; }
.svc-card.is-shot .svc-card_media { aspect-ratio: 3 / 4; }
/* The why grid's rows are set by its photo cards; a 16:10 frame there keeps
   the plates beside them from towering over their own two lines of copy. */
.ch-why .svc-card_media { aspect-ratio: 16 / 10; }
.svc-card_body { flex: 0 0 auto; }

.ch-qualify .svc-card:not(:has(.svc-card_media)),
.ch-why .svc-card:not(:has(.svc-card_media)) {
  background: var(--sand);
  border-color: transparent;
}
.ch[data-theme="dark"] .svc-card:not(:has(.svc-card_media)) { background: rgba(255, 255, 255, .06); }
.ch-qualify .svc-card:not(:has(.svc-card_media)) .svc-card_body,
.ch-why .svc-card:not(:has(.svc-card_media)) .svc-card_body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .5rem;
  min-height: 15rem;
}
.ch-qualify .svc-card:not(:has(.svc-card_media)) .svc-card_no,
.ch-why .svc-card:not(:has(.svc-card_media)) .svc-card_no {
  margin-bottom: auto;
  font-size: calc(3.4rem * var(--t-mid));
  color: var(--accent-lg);
  opacity: .85;
}
/* A plate with no numeral (the why grid) opens on the copper diamond the
   cost cards use, drawn rather than typed so no glyph is at the mercy of a
   font subset. */
.ch-why .svc-card:not(:has(.svc-card_media)):not(:has(.svc-card_no)) .svc-card_body::before {
  content: "";
  display: block;
  width: .7rem;
  height: .7rem;
  margin: .2rem 0 auto .2rem;
  background: var(--accent);
  transform: rotate(45deg);
}
.ch-qualify .svc-card:not(:has(.svc-card_media)) .svc-card_text,
.ch-why .svc-card:not(:has(.svc-card_media)) .svc-card_text { color: var(--fg-body); }
/* Hover on a plate: the diamond and numeral warm up, the plate lifts a hair. */
.svc-card:not(:has(.svc-card_media)):hover { transform: translateY(-3px); }
@media (min-width: 900px) {
  .svc-grid.is-stagger > *:nth-child(even):hover { transform: translateY(calc(2.75rem - 3px)); }
}
@media (max-width: 599px) {
  .ch-qualify .svc-card:not(:has(.svc-card_media)) .svc-card_body,
  .ch-why .svc-card:not(:has(.svc-card_media)) .svc-card_body { min-height: 0; }
  .ch-qualify .svc-card:not(:has(.svc-card_media)) .svc-card_no { margin-bottom: .25rem; }
}

/* --- the ledger label that ran out of its cell --------------------------- */
.svc-ledger b { overflow-wrap: anywhere; hyphens: manual; }
.svc-overlap_panel .svc-ledger { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 479px) { .svc-overlap_panel .svc-ledger { grid-template-columns: minmax(0, 1fr); } }

/* --- the provider band, now that there is a portrait --------------------- */
.svc-provider {
  gap: clamp(2rem, 5vw, 5.5rem);
  padding-top: clamp(2.5rem, 5vw, 4.5rem);
}
@media (min-width: 768px) {
  .svc-provider { grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); }
}
.svc-provider_shot {
  position: relative;
  max-width: 24rem;
  margin: 0 1.25rem 1.25rem 0;
  border: 0;
  background: var(--sand);
  overflow: visible;
}
/* The plate: a hairline frame offset down and right, the same device the
   arrival's stacked frames use. Drawn behind the photograph. */
.svc-provider_shot::before {
  content: "";
  position: absolute;
  inset: 1.25rem -1.25rem -1.25rem 1.25rem;
  border: 1px solid var(--rule-strong);
  z-index: 0;
}
.svc-provider_shot img {
  position: relative;
  z-index: 1;
  aspect-ratio: 3 / 4;
  filter: none;
}
.svc-provider_body h3 { font-size: calc(var(--f-d3) * 1.05); }
.svc-provider_role { padding-bottom: .1rem; }
.svc-stats b { font-size: calc(2.5rem * var(--t-mid)); }

/* ===========================================================================
   THE BLOG INDEX, second cut  (bl-)
   =========================================================================== */
/* The topic strip: one tile per topic, the count as a counted numeral, a
   photograph from the practice's album, and the whole tile a filter for the
   grid below it (elevate.js). */
.bl-topics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1rem, 1.8vw, 1.75rem);
  margin: 0 0 clamp(2.5rem, 4vw, 3.5rem);
  padding: 0;
  list-style: none;
}
@media (max-width: 991px) { .bl-topics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px) { .bl-topics { grid-template-columns: minmax(0, 1fr); } }
.bl-topic {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--panel);
  border: 1px solid var(--rule);
  color: inherit;
  text-decoration: none;
  overflow: hidden;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
}
.bl-topic:hover, .bl-topic:focus-visible { border-color: var(--rule-strong); transform: translateY(-3px); }
.bl-topic.is-on { border-color: var(--accent); }
.bl-topic_shot { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--sand); }
.bl-topic_shot img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
  transition: filter .6s var(--ease), transform .8s var(--ease);
}
.bl-topic:hover .bl-topic_shot img, .bl-topic.is-on .bl-topic_shot img { filter: none; transform: scale(1.04); }
.bl-topic_body {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: .25rem 1.1rem;
  align-items: end;
  padding: 1.25rem 1.4rem 1.35rem;
}
.bl-topic_num {
  grid-row: span 2;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(3.4rem * var(--t-mid));
  line-height: .9;
  letter-spacing: -.02em;
  color: var(--fg);
}
.bl-topic_name {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  align-self: end;
}
.bl-topic_hint {
  font-family: var(--font-ui);
  font-size: calc(.72rem * var(--t-ui));
  letter-spacing: .06em;
  color: var(--fg-soft);
}
.bl-topic.is-on .bl-topic_hint { color: var(--fg); }

/* The grid: hairline cells, a numeral on every card, the first as a plate. */
.bl-grid { counter-reset: post; }
.bl-card { counter-increment: post; }
.bl-card_link {
  position: relative;
  min-height: 17rem;
  padding: 1.75rem 1.6rem 1.5rem;
  gap: .7rem;
}
.bl-card_link::before {
  content: counter(post, decimal-leading-zero);
  position: absolute;
  top: 1.45rem;
  right: 1.5rem;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(1.35rem * var(--t-mid));
  line-height: 1;
  color: var(--accent-lg);
  opacity: .8;
}
.bl-card_link .bl-card_title {
  font-size: calc(1.32rem * var(--t-ui));
  line-height: 1.2;
  max-width: 24ch;
  padding-right: 2.5rem;
  transition: color .3s var(--ease);
}
.bl-card_link:hover .bl-card_title { color: var(--brand); }
.bl-card_link .bl-card_text { font-size: calc(.88rem * var(--t-ui)); line-height: 1.55; max-width: 40ch; }
.bl-card_more {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-size: var(--f-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  font-weight: 700;
}
.bl-card_more::after {
  content: "";
  display: block;
  width: 2rem;
  height: 1px;
  background: currentColor;
  transform-origin: 0 50%;
  transform: scaleX(.5);
  transition: transform .4s var(--ease);
}
.bl-card_link:hover .bl-card_more { text-decoration: none; }
.bl-card_link:hover .bl-card_more::after { transform: scaleX(1); }

/* The newest article is the plate: the whole first row, sand ground, the
   title at statement size beside its own excerpt. */
@media (min-width: 700px) {
  .bl-card:first-child { grid-column: 1 / -1; }
  .bl-card:first-child .bl-card_link {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    grid-template-rows: auto 1fr auto;
    gap: 1.25rem clamp(2rem, 4vw, 4rem);
    align-items: start;
    padding: clamp(2rem, 3.5vw, 3rem);
    background: var(--sand);
  }
  .bl-card:first-child .bl-card_link:hover { background: var(--beige); }
  .bl-card:first-child .bl-card_meta { grid-column: 1 / -1; }
  .bl-card:first-child .bl-card_title {
    grid-row: 2 / span 2;
    font-size: calc(2.15rem * var(--t-mid));
    line-height: 1.12;
    letter-spacing: -.01em;
    max-width: 22ch;
    padding-right: 0;
  }
  .bl-card:first-child .bl-card_text { font-size: var(--f-lede); line-height: 1.65; max-width: 44ch; color: var(--fg-body); }
  .bl-card:first-child .bl-card_more { align-self: end; }
  .bl-card:first-child .bl-card_link::before { font-size: calc(2rem * var(--t-mid)); top: 1.6rem; right: 1.8rem; }
}
/* Every ninth card after the plate is ink, so a long run of white has a beat. */
.bl-card:nth-child(9n + 5) .bl-card_link { background: var(--ink); color: #fff; }
.bl-card:nth-child(9n + 5) .bl-card_link:hover { background: var(--ink-mid); }
.bl-card:nth-child(9n + 5) .bl-card_link .bl-card_title { color: #fff; }
.bl-card:nth-child(9n + 5) .bl-card_link:hover .bl-card_title { color: #e3c3a8; }
.bl-card:nth-child(9n + 5) .bl-card_link .bl-card_text { color: rgba(255, 255, 255, .7); }
.bl-card:nth-child(9n + 5) .bl-card_meta { color: rgba(255, 255, 255, .55); }
.bl-card:nth-child(9n + 5) .bl-card_meta b, .bl-card:nth-child(9n + 5) .bl-card_more { color: #d9b79c; }
/* A card the topic filter has hidden. `hidden` is the attribute, this is the
   class the filter sets, so the runtime's own attribute is never fought. */
.bl-card.is-filtered { display: none; }
.bl-empty { padding: 2rem 0; color: var(--fg-soft); font-size: var(--f-body); }
.bl-empty[hidden] { display: none; }

/* ===========================================================================
   THE ARTICLE  (bl-art)
   =========================================================================== */
.bl-article { padding-top: calc(var(--ch-pad) * .45); }
.bl-art { display: grid; gap: clamp(2rem, 4vw, 3rem); align-items: start; }
@media (min-width: 1024px) {
  .bl-art { grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); gap: clamp(3rem, 6vw, 6.5rem); }
  .bl-art_sticky { position: sticky; top: 6.5rem; }
}
.bl-art_sticky { display: grid; gap: 1.5rem; }
.bl-art_label {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.bl-art_toc {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: toc;
  border-top: 1px solid var(--rule-strong);
}
.bl-art_toc:empty { display: none; }
.bl-art_toc li { counter-increment: toc; }
.bl-art_toc a {
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr);
  gap: .6rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-body);
  font-size: calc(.86rem * var(--t-ui));
  line-height: 1.4;
  color: var(--fg-soft);
  text-decoration: none;
  transition: color .3s var(--ease);
}
.bl-art_toc a::before {
  content: counter(toc, decimal-leading-zero);
  font-family: var(--font-display);
  font-size: calc(.95rem * var(--t-mid));
  color: var(--accent-lg);
  padding-top: .05em;
}
.bl-art_toc a:hover, .bl-art_toc a.is-active { color: var(--fg); }
.bl-art_toc a.is-active::before { color: var(--brand); }
.bl-art_toc li.is-sub a { padding-left: 1.6rem; grid-template-columns: minmax(0, 1fr); }
.bl-art_toc li.is-sub a::before { content: none; }
.bl-art_facts { margin: 0; display: grid; gap: .8rem; padding-top: .25rem; }
.bl-art_facts div { display: grid; gap: .15rem; }
.bl-art_facts dt {
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-soft);
}
.bl-art_facts dd { margin: 0; font-size: var(--f-body); color: var(--fg); }
.bl-art_sticky .button { justify-self: start; }
.bl-art_shot { margin: 0; position: relative; aspect-ratio: 4 / 5; overflow: hidden; background: var(--sand); }
.bl-art_shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.bl-art_shot figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1rem 1.1rem .9rem;
  background: linear-gradient(180deg, rgba(30, 36, 38, 0) 0%, rgba(30, 36, 38, .78) 100%);
  color: rgba(255, 255, 255, .85);
  font-family: var(--font-ui);
  font-size: calc(.72rem * var(--t-ui));
  letter-spacing: .06em;
  line-height: 1.4;
}
@media (max-width: 1023px) {
  .bl-art_sticky { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .bl-art_label, .bl-art_toc { grid-column: 1 / -1; }
  .bl-art_shot { display: none; }
}
@media (max-width: 599px) { .bl-art_sticky { grid-template-columns: minmax(0, 1fr); } }

/* The prose. 66 characters, a lede, a drop cap, ruled headings. */
.bl-art_body { max-width: 66ch; }
.bl-art_body > p:first-of-type {
  font-size: var(--f-lede);
  line-height: 1.7;
  color: var(--fg);
}
.bl-art_body > p:first-of-type::first-letter {
  float: left;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: 3.9em;
  line-height: .78;
  padding: .08em .14em 0 0;
  color: var(--accent);
}
.bl-art_body h2, .bl-art_body h3 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--fg);
  max-width: 28ch;
}
.bl-art_body h2 {
  font-size: var(--f-h3);
  line-height: 1.15;
  margin: 2.6rem 0 .9rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}
.bl-art_body h3 { font-size: var(--f-h4); line-height: 1.25; margin: 2rem 0 .6rem; }
.bl-art_body h2:first-child, .bl-art_body h3:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.bl-art_body p, .bl-art_body li { line-height: 1.75; }
.bl-art_body blockquote {
  margin: 1.75rem 0;
  padding: .25rem 0 .25rem 1.4rem;
  border-left: 2px solid var(--accent);
  font-family: var(--font-display);
  font-size: calc(1.3rem * var(--t-mid));
  line-height: 1.4;
  color: var(--fg);
}
.bl-art_body img { display: block; width: 100%; height: auto; }
.bl-art_body table { font-size: var(--f-body); }

/* Related articles: three cards, not a ledger. */
.bl-related { margin-top: clamp(3rem, 6vw, 5rem); }
.bl-related .svc-ledger-label { margin-top: 0; margin-bottom: 1.25rem; }
.bl-grid.is-related .bl-card_link { min-height: 12rem; }
.bl-grid.is-related .bl-card:first-child { grid-column: auto; }
.bl-grid.is-related .bl-card:first-child .bl-card_link { display: flex; background: var(--panel); padding: 1.75rem 1.6rem 1.5rem; }
.bl-grid.is-related .bl-card:first-child .bl-card_link:hover { background: var(--warm); }
.bl-grid.is-related .bl-card:first-child .bl-card_title { font-size: calc(1.32rem * var(--t-ui)); line-height: 1.2; grid-row: auto; padding-right: 2.5rem; max-width: 24ch; }
.bl-grid.is-related .bl-card:first-child .bl-card_link::before { font-size: calc(1.35rem * var(--t-mid)); top: 1.45rem; right: 1.5rem; }
.bl-grid.is-related .bl-card:first-child .bl-card_text { font-size: calc(.88rem * var(--t-ui)); line-height: 1.55; max-width: 40ch; color: var(--fg-soft); }
.bl-grid.is-related .bl-card:first-child .bl-card_more { align-self: auto; }
.bl-grid.is-related .bl-card:nth-child(9n + 5) .bl-card_link { background: var(--panel); color: inherit; }

/* ===========================================================================
   THE 2026-09-10 REVIEW ROUND — the agency's 48 BugHerd notes on staging.
   Every rule here answers a numbered note in
   .tmp/bugherd/tasks-2026-09-10.json; the number is in the comment. Placed at
   the end so equal-specificity rules above lose to these.
   ======================================================================== */

/* #5  The relay's caption sat on the photograph's edge. The mask reveal
   scales the image 1.16 inside a clipped figure, so before the reveal settles
   the picture overlaps its own caption. The caption now paints over it and
   has room. */
.re-media figcaption { position: relative; z-index: 1; background: var(--white); padding-top: 1.25rem; }

/* #6  Two full measures of air between The Relay and Under One Roof read as
   a hole, not a break: the relay's own bottom padding plus the next chapter's
   top. Tightened; the chapters still breathe. */
.ch-relay { padding-bottom: calc(var(--ch-pad) * .55); }
.ch-together { padding-top: calc(var(--ch-pad) * .7); }

/* #24-#26  The credential strip: the label was too faint to read, and two of
   the five marks (Seattle Study Club, AAPD) are square artwork that a single
   forced height made tiny beside the wide wordmarks. */
.pr-badges-label { color: rgba(255, 255, 255, .82); }
.pr-badges img { height: 3rem; }
.pr-badges li.is-mark img { height: 4.6rem; }
@media (max-width: 767px) { .pr-badges img { height: 2.2rem; } .pr-badges li.is-mark img { height: 3.4rem; } }

/* #37/#41  The strip left every inner page, so the breadcrumb now follows the
   arrival directly. Same rhythm the strip used to set. */
.ch-arrival + .padding-global { padding-top: 1.25rem; padding-bottom: 0; }
.ch-arrival + .padding-global + .ch { padding-top: calc(var(--ch-pad) * .7); }

/* #41  "Change up the home design from the rest of the pages." Every inner
   page opened exactly like the homepage: a full-bleed photograph under a
   veil, the headline bottom-left. The compact arrival is now a SPLIT — copy
   on ink in the left column, the photograph held to the right 46% with a
   soft fade into the ink and a copper rule under the whole band. Same
   markup on all 44 pages, so no page changed for this; the homepage's own
   arrival (no `is-compact`) is untouched. */
.ch-arrival.is-compact {
  min-height: 0;
  align-items: center;
  padding: calc(var(--jr-nav-h, 5.5rem) + 3.5rem) 0 4rem;
  background: var(--ink);
  border-bottom: 3px solid var(--copper);
}
.ch-arrival.is-compact .ar-bg { inset: 0 0 0 auto; width: 46%; }
.ch-arrival.is-compact .ar-bg img { object-position: 50% 30%; }
.ch-arrival.is-compact .ar-veil {
  background:
    linear-gradient(90deg, var(--ink) 0%, var(--ink) 53%, rgba(30, 36, 38, .6) 58%, rgba(30, 36, 38, .12) 70%, rgba(30, 36, 38, 0) 100%),
    linear-gradient(180deg, rgba(30, 36, 38, .82) 0%, rgba(30, 36, 38, 0) 34%);
}
.ch-arrival.is-compact .ar-in { padding-right: 48%; }
.ch-arrival.is-compact .ar-title { max-width: 14ch; }
@media (max-width: 767px) {
  .ch-arrival.is-compact { display: grid; padding-top: calc(var(--jr-nav-h, 5.5rem) + 2rem); padding-bottom: 0; }
  .ch-arrival.is-compact .ar-in { order: 1; padding-right: var(--bleed); }
  .ch-arrival.is-compact .ar-bg { order: 2; position: relative; inset: auto; width: 100%; aspect-ratio: 16 / 10; margin-top: 2rem; }
  .ch-arrival.is-compact .ar-veil { display: none; }
}

/* #42  The two dossiers on the Doctors page were two independent stacks, so
   the names, facts and folds sat at different heights. The columns now share
   their rows (subgrid; browsers without it keep the old behaviour), and both
   portraits are the same frame now that Dr. Sung has a full-size one. */
@media (min-width: 860px) {
  .cp-duo { align-items: stretch; }
  .cp-dossier { grid-template-rows: subgrid; grid-row: span 6; }
}
.cp-dossier_shot { max-width: 20rem; }
.cp-dossier_shot img { aspect-ratio: 4 / 5; object-position: 50% 0; }

/* #36/#48  The seal's mark is the practice's tree, as an <img>. */
.el-seal_mark img { width: 30%; height: auto; display: block; }

/* #2  The hero stack is a link, and its top frame flips. */
a.el-stack { display: block; text-decoration: none; cursor: pointer; }
/* ...but not below 992, where the stack is hidden: this rule's specificity
   had put it back over the phone hero's buttons (seen 2026-09-16). */
@media (max-width: 991px) { a.el-stack { display: none; } }
.el-stack_frame { transition: opacity .42s var(--ease); }
.el-stack_frame.is-flipping { opacity: 0; }

/* #46  Lead with the doctors: the team page's byline strip carries more
   weight now that it is the page's first chapter in fact and not only in
   order. */
.cp-byline_face { width: 4.8rem; height: 4.8rem; }
.cp-byline b { font-size: calc(1.3rem * var(--t-mid)); }

/* #47  A lighter line under the emergency fact on the team page. */
.iv-fun { display: block; margin-top: .6rem; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .05em; color: #e3c3a8; line-height: 1.6; }
.iv-fun a { color: #fff; border-bottom-color: rgba(255, 255, 255, .5); }

/* ===========================================================================
   THE 2026-09-15 REVIEW ROUND — the same 48 notes, re-checked where the
   reviewer stands: Safari 26 at 1512x735. Export and screenshots in
   .tmp/bugherd/tasks-2026-09-15.json; the number is in the comment.
   ======================================================================== */

/* #3  "The bottom of the logo is being cut off" (Safari 26, 1512x652). The
   artwork has two source pixels under DENTAL, under one CSS pixel at this
   size, and Safari composites the filtered logo on a layer cut at the box's
   fractional edge. Air inside the box keeps the letters off that edge. */
/* Superseded 2026-09-16: the air is now inside the logo file itself
   (mp-logo-nav-422x180.png, .tmp/bugherd/logo-pad.mjs), which no rounding of
   the box can cut. The note was reopened after the padding fix. */

/* #6  The relay's closing sentence hung alone beside a column of air. A
   photograph of the front counter now sits beside it. */
.re-inset { margin: 0; max-width: 14rem; }
.re-inset img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 42%; }
.re-inset figcaption { padding-top: .7rem; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .08em; color: var(--fg-soft); line-height: 1.5; }
@media (min-width: 900px) {
  .re-after { grid-template-columns: minmax(0, 1fr) minmax(0, 12rem); column-gap: clamp(1.5rem, 3vw, 2.75rem); align-items: start; max-width: none; }
  .re-inset { max-width: none; }
}

/* #21 and #45  Framing for the frames this round brought in. Keyed on the
   file, which survives the import's /uploads/<id>- rename, so each rule
   follows its picture and not a slot. */
.pe-band img[src*="mp-team-huddle-smile-"] { object-position: 50% 44%; }
.el-pane img[src*="mp-hygienist-loupes-"] { object-position: 68% 28%; }
.el-pair_frame img[src*="mp-clinical-pair-chair-"] { object-position: 50% 30%; }
.cp-band img[src*="mp-checkin-screen-"] { object-position: 50% 40%; }
.iv-shot img[src*="mp-desk-phone-"] { object-position: 50% 40%; }
.el-sheet_tile img[src*="mp-desk-laugh-"] { object-position: 50% 30%; }
.el-sheet_tile img[src*="mp-dentist-assistant-"] { object-position: 72% 0%; }


/* ===========================================================================
   BUGHERD, 2026-09-16 — the agency's third round (#50-#77, #1, #43).
   Site-wide: photographs in colour at rest, unwritten words readable, the
   hover fill behind button labels, triggers re-measured when the page grows.
   Export: .tmp/bugherd/tasks-2026-09-16.json.
   ======================================================================== */

/* #1  The family on the home hero. Faces sit in the top half of the frame. */
.ar-bg img[src*="mp-family-nguyen-sung-"] { object-position: 50% 38%; }
/* The agency's headline (#51) is three times the old one's length, and the
   family sat under it. On wide screens the headline steps down a size and the
   photograph is laid 18% wider than the hero from its left edge, which puts
   the family in the right half, clear of the copy. */
@media (min-width: 992px) {
  .ch-arrival:has(img[src*="mp-family-nguyen-sung-"]) .ar-title { font-size: var(--f-d2); max-width: 17ch; }
  .ar-bg img[src*="mp-family-nguyen-sung-"] { width: 118%; max-width: none; object-position: 0% 62%; }
}

/* #63  Dr. Nguyen's portrait on the pediatric half: a tall frame in a 4:3 box. */
.ab-half img.is-portrait { object-position: 50% 16%; }

/* #43  THE TEAM. The agency's studio portraits, one set, grouped by role: a
   label column that holds its place while the group's portraits pass, and
   square frames with the name and role under each. */
.tm-roll { display: grid; gap: clamp(3rem, 6vw, 5rem); }
.tm-group { display: grid; gap: 1.5rem; }
.tm-group_head { border-top: 1px solid var(--rule-strong); padding-top: 1rem; }
.ch .tm-group_head h3 { font-family: var(--font-display); font-weight: 300; font-size: var(--f-h3); line-height: 1.15; margin: 0; }
.ch .tm-group_head p { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase; color: var(--fg-soft); margin: .6rem 0 0; }
.tm-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem 1rem; }
.tm-card { margin: 0; }
.tm-card_face { margin: 0; overflow: hidden; background: var(--sand); aspect-ratio: 1; }
.tm-card_face img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; transition: transform .8s var(--ease); }
.tm-card:hover .tm-card_face img { transform: scale(1.04); }
.ch .tm-card_name { margin: .9rem 0 0; display: grid; gap: .3rem; }
.ch .tm-card_name b { font-family: var(--font-display); font-weight: 400; font-size: calc(1.3rem * var(--t-mid)); line-height: 1.2; color: var(--fg); }
.ch .tm-card_name span { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .1em; text-transform: uppercase; line-height: 1.5; color: var(--fg-soft); }
@media (min-width: 768px) {
  .tm-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.5rem 1.5rem; }
}

/* ===========================================================================
   PAID TRAFFIC, second cut, 2026-09-18  —  /ads-landing-pages/*

   The first cut (2026-09-17) was the organic service page with a form chapter
   added near the bottom, and the agency said so: it did not convince. These
   six routes now run the information flow of the agency's own reference set
   (Livewell's ads-landing-pages): the form is IN the arrival, then the journey,
   why here, the dentist, the path, the proof and the rooms, the questions, and
   the invitation with the offer, the credentials and the disclaimer. The
   consultation page is the form first and the thank-you page is the phone first.

   Everything here is either scoped to `.is-lp-page` / `.ch-arrival.is-lp` or is
   a new `ad-*` class, so no organic page can move. The shared scenes the pages
   reuse (ch-path, ch-proof, cp-split, cp-duo, cp-figures, cp-timeline,
   cp-callbox, el-mosaic, el-seal) are untouched.
   ======================================================================== */
.is-lp-page .navbar_menu { display: none; }
.is-lp-page .navbar_toggle { display: none; }
.is-lp-page .navbar_actions { margin-left: auto; }
.is-lp-page .footer_grid { grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, .8fr)); }
.is-lp-page .footer_grid > div:nth-child(3) { display: none; }
.is-lp-page .callbar_component { display: none; }
.lp-cta_short { display: none; }

/* --- the arrival with the form in it -------------------------------------
   Livewell's hero carries the lead form beside the promise. The photograph and
   the two scrims are the site's own arrival; what changes is that the copy
   shares the row with the form card, so the headline drops a tier. */
.ch-arrival.is-lp {
  min-height: 0;
  align-items: center;
  padding-top: calc(var(--jr-nav-h, 5.5rem) + 3.5rem);
  padding-bottom: 4.5rem;
}
.ch-arrival.is-lp .ar-bg img { object-position: 50% 38%; }
.ch-arrival.is-lp .ar-veil {
  background:
    linear-gradient(180deg, rgba(30, 36, 38, .8) 0%, rgba(30, 36, 38, .5) 40%, rgba(30, 36, 38, .82) 100%),
    linear-gradient(94deg, rgba(30, 36, 38, .86) 0%, rgba(30, 36, 38, .6) 52%, rgba(30, 36, 38, .42) 100%);
}
.ar-in.lp-hero { display: grid; gap: 3rem; align-items: center; }
.ch-arrival.is-lp .ar-title { font-size: var(--f-d2); max-width: 15ch; }
.ch-arrival.is-lp .ar-lede { margin-bottom: 2rem; }
.ch-arrival.is-lp .ar-actions { margin-bottom: 2.4rem; }
.ch-arrival.is-lp .ar-meta { gap: 1.5rem 3rem; }
.ch-arrival.is-lp .ar-meta div { max-width: 13rem; }
.ch .lp-hero_area {
  margin: 1.5rem 0 0;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .62);
}
.ch .lp-hero_note { margin: 1.4rem 0 0; font-size: var(--f-body); line-height: 1.6; color: rgba(255, 255, 255, .74); max-width: 46ch; }
.lp-hero_note a { color: #fff; text-decoration: none; border-bottom: 1px solid var(--copper); }
.ch-arrival.is-thanks { min-height: 78svh; align-items: flex-end; }
.ch-arrival.is-thanks .ar-actions { margin-bottom: 0; }

.lp-chips { list-style: none; margin: 0 0 2rem; padding: 0; display: flex; flex-wrap: wrap; gap: .6rem; }
.lp-chips li {
  padding: .6rem .95rem;
  border: 1px solid rgba(255, 255, 255, .38);
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
}
.lp-chips li::before { content: none; }
.lp-byline { display: flex; align-items: center; gap: 1rem; padding-top: 1.6rem; border-top: 1px solid rgba(255, 255, 255, .22); }
.lp-byline_face { width: 4.2rem; height: 4.2rem; border-radius: 50%; overflow: hidden; flex: none; border: 1px solid rgba(255, 255, 255, .4); }
.lp-byline_face img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 16%; }
.lp-byline b { display: block; font-family: var(--font-display); font-weight: 400; font-size: var(--f-h4); line-height: 1.2; color: #fff; }
.lp-byline small { display: block; margin-top: .25rem; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .1em; text-transform: uppercase; color: rgba(255, 255, 255, .62); }

/* --- the form card --------------------------------------------------------
   The slot is what place-ad-embeds.mjs swaps for the GHL Embed module after
   conversion; locally it is a labelled placeholder of the form's real height. */
.lp-form-card {
  background: var(--paper);
  color: var(--ink);
  padding: 2rem;
  border-top: .25rem solid var(--copper);
  box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, .3);
}
.ch .lp-form-card p { color: var(--ink); }
.ch .lp-form-card .lp-form-kicker { margin: 0 0 .6rem; font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--brand-deep); }
.ch .lp-form-card .lp-form-title { margin: 0 0 .5rem; font-size: var(--f-h3); line-height: 1.15; color: var(--ink); }
.ch .lp-form-card .lp-form-lede { margin: 0 0 1.25rem; font-size: var(--f-body); line-height: 1.6; color: var(--body); }
/* The placeholder look is for the LOCAL slot only. After import the slot node IS
   the Embed module (it keeps the class and gains `wz-embed`), and a centring
   grid shrank the published form to the iframe's 300px intrinsic width in the
   corner of its card. Published, it is a plain full-width block. */
.lp-form-slot:not(.wz-embed) { min-height: 45.2rem; display: grid; place-content: center; text-align: center; border: 1px solid var(--beige-mid); background: var(--sand); }
/* The height is reserved up front: the GHL frame arrives at 150px and grows
   to about 800 to 900 a few seconds later, which otherwise shoves the whole
   page down under a visitor who has already started reading. */
.lp-form-slot.wz-embed { display: block; width: 100%; min-height: 50rem; }
.lp-form-slot.wz-embed > *, .lp-form-slot.wz-embed iframe { width: 100%; max-width: 100%; }
.lp-form-slot > p { margin: 0; font-family: var(--font-display); font-size: var(--f-h3); }
.lp-form-slot > small { display: block; max-width: 24ch; margin: .6rem auto 0; color: #5f6667; }
.ch .lp-form-card .lp-form-note { margin: 1rem 0 0; font-size: var(--f-label); line-height: 1.5; color: #5f6667; }

/* --- the journey -----------------------------------------------------------
   Four moves and four photographs. Above 900 journey.js pins the stage and the
   scroll crossfades the frames while each move lights in turn; below 900 the
   frame holds under the header and the moves pass beneath it. With no runtime
   at all the first frame shows and every move reads at full strength. */
.ch-journey { padding-bottom: 0; }
.lp-journey_head { margin-bottom: 3rem; }
.lp-journey_stage { position: relative; }
.lp-journey_frames { position: relative; overflow: clip; background: var(--ink-mid); }
.lp-journey_frame { position: absolute; inset: 0; margin: 0; opacity: 0; transition: opacity .6s var(--ease); }
.lp-journey_frame.is-on { opacity: 1; }
.lp-journey_stage.is-pinned .lp-journey_frame { transition: none; }
.lp-journey_frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
.lp-journey_frame figcaption {
  position: absolute; left: 1.2rem; right: 1.2rem; bottom: 1.1rem;
  font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255, 255, 255, .82); text-shadow: 0 1px 10px rgba(0, 0, 0, .6);
}
.lp-journey_steps { list-style: none; margin: 0; padding: 0; display: grid; border-top: 1px solid var(--rule); }
.lp-journey_step {
  display: grid;
  grid-template-columns: 3.2rem minmax(0, 1fr);
  gap: 1rem;
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--rule);
  opacity: .42;
  transition: opacity .5s var(--ease);
}
.lp-journey_step::before { content: none; }
.lp-journey_step.is-on { opacity: 1; }
html.jr-fail .lp-journey_step, html:not(.jr-ready) .lp-journey_step { opacity: 1; }
.lp-journey_no { font-family: var(--font-display); font-weight: 300; font-size: calc(1.9rem * var(--t-lg)); line-height: 1; color: var(--accent-lg); }
.ch .lp-journey_step h3 { margin: 0 0 .45rem; font-size: var(--f-h3); }
.ch .lp-journey_step p { margin: 0; font-size: var(--f-body); line-height: 1.65; max-width: 46ch; }
.lp-journey_quote { margin: .9rem 0 0; padding-left: .9rem; border-left: 1.5px solid var(--accent); }
.ch .lp-journey_quote p { font-family: var(--font-display); font-style: italic; font-size: var(--f-h4); line-height: 1.4; color: var(--fg); }
.lp-journey_quote cite { display: block; margin-top: .4rem; font-family: var(--font-ui); font-style: normal; font-size: var(--f-label); letter-spacing: .12em; text-transform: uppercase; color: var(--fg-soft); }
/* In the two-column stage only the lit move is open, so four moves and their
   review lines fit one window. `is-live` is set by journey.js; without it
   every move stays open. One column keeps them all open: there the moves ARE
   the scroll. */
.lp-journey_more > div { padding-top: .05rem; }
.lp-journey_bar { height: 2px; background: var(--rule); }
.lp-journey_bar i { display: block; height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: left center; }

/* --- why here --------------------------------------------------------------
   The head holds in the left column (journey.js pins it, desktop only) while
   four reasons pass on the right. They are ROWS, one under the other, on
   purpose: as a two by two the column was shorter than the head beside it and
   the pin had nothing to hold the head through (measured: a range of 0px). */
.lp-why { display: grid; gap: 2.5rem; }
.lp-why_head .pe-lede { margin-top: 1.2rem; }
.lp-why_head .button { margin-top: 1.8rem; }
.lp-why_grid { display: grid; gap: 1.25rem; }
.lp-why_card {
  display: grid;
  grid-template-columns: 4.2rem minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
  padding: 2.2rem 2rem;
  background: var(--panel);
  border: 1px solid var(--rule);
  transition: border-color .4s var(--ease), box-shadow .4s var(--ease);
}
.lp-why_card:hover { border-color: var(--rule-strong); box-shadow: var(--shadow); }
.lp-why_no { font-family: var(--font-display); font-weight: 300; font-size: calc(2.2rem * var(--t-lg)); line-height: 1; color: var(--accent-lg); }
.ch .lp-why_card h3 { font-size: var(--f-h3); line-height: 1.2; margin-bottom: .55rem; }
.ch .lp-why_card p { margin: 0; font-size: var(--f-body); line-height: 1.65; max-width: 52ch; }

.lp-doors_wrap { position: relative; margin-top: 5rem; padding-top: 3.5rem; border-top: 1px solid var(--rule-strong); }
.lp-doors_wrap .el-seal { top: 3rem; right: var(--bleed); }
.lp-doors_head, .lp-place_head { display: grid; gap: .7rem; margin-bottom: 2.2rem; max-width: 62ch; }
.ch .lp-doors_head h3, .ch .lp-place_head h3 { font-size: var(--f-d3); font-weight: 300; line-height: 1.08; letter-spacing: -.012em; }
.ch .lp-doors_head p, .ch .lp-place_head p { margin: 0; font-size: var(--f-lede); line-height: 1.65; }
.lp-doors { display: grid; gap: 2rem 1.5rem; }
.lp-door figure { margin: 0 0 1.1rem; }
.lp-door img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.ch .lp-door h3 { font-size: var(--f-h4); margin-bottom: .4rem; }
.ch .lp-door p { margin: 0; font-size: var(--f-body); line-height: 1.65; }

/* --- the dentist -------------------------------------------------------- */
.ch .lp-dentist_name { font-size: var(--f-d2); font-weight: 300; line-height: 1.04; letter-spacing: -.018em; max-width: 14ch; }
.lp-dentist_figures { margin-top: 4rem; }
/* His coat is white and so was his caption. A floor under it, this chapter only. */
.ch-dentist .cp-split_ink::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 9rem; background: linear-gradient(180deg, rgba(30, 36, 38, 0) 0%, rgba(30, 36, 38, .78) 100%); pointer-events: none; }
.ch-dentist .cp-split_ink figcaption { z-index: 1; color: #fff; }
.ch-dentist .cp-duo { margin-bottom: 0; }

/* --- the rooms, inside the proof ---------------------------------------- */
.lp-place { margin-top: 5rem; padding-top: 3.5rem; border-top: 1px solid var(--rule-strong); }
.ch-proof .pr-foot .pr-note { margin-top: 1.5rem; }

/* --- the credentials and the small print --------------------------------- */
.ch-invitation .pr-badges { margin-top: 4.5rem; background: transparent; border-top: 1px solid var(--rule); }
.pr-badges.is-on-warm { background: var(--ink); margin-top: 4.5rem; }
.lp-legal { margin-top: 2.2rem; display: grid; gap: 1rem; }
.ch .lp-disclaimer { margin: 0; max-width: 96ch; font-size: calc(.8rem * var(--t-text)); line-height: 1.65; color: var(--fg-soft); }
.lp-legal_links { margin: 0; font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .1em; text-transform: uppercase; }
.ch .lp-legal_links, .lp-legal_links a { color: var(--fg-soft); }
.lp-legal_links a { text-decoration: none; border-bottom: 1px solid var(--rule-strong); }
.lp-legal_links a:hover { color: #fff; }

/* --- the thank-you page's own two ---------------------------------------- */
.lp-call { display: grid; gap: 2.5rem; }
.lp-risks { padding: 2rem; background: var(--panel); border: 1px solid var(--rule); }
.ch .lp-risks h3 { font-size: var(--f-h3); margin-bottom: 1rem; }
.lp-risks ul { list-style: none; margin: 0; padding: 0; }
.lp-risks li { display: grid; grid-template-columns: 2.2rem minmax(0, 1fr); gap: .8rem; padding: .95rem 0; border-top: 1px solid var(--rule); font-size: var(--f-body); line-height: 1.6; color: var(--fg-body); }
.lp-risks li::before { content: none; }
.lp-risks li b { font-family: var(--font-display); font-weight: 300; font-size: calc(1.4rem * var(--t-mid)); line-height: 1.1; color: var(--accent-lg); }
.lp-pillars { display: grid; border-top: 1px solid var(--rule-strong); }
.lp-pillar { display: grid; gap: .7rem; align-content: start; padding: 2rem 0; border-bottom: 1px solid var(--rule); }
.lp-pillar_no { font-family: var(--font-display); font-weight: 300; font-size: var(--f-d3); line-height: 1; color: var(--accent-lg); }
.ch .lp-pillar h3 { font-size: var(--f-h3); }
.ch .lp-pillar p { margin: 0; font-size: var(--f-body); line-height: 1.65; max-width: 40ch; }
.ch-invitation .cp-callbox { margin-bottom: 3.5rem; }
.ch-invitation .cp-head .pe-lede { color: var(--fg-body); }

/* --- the rail: the offer, the phone and the next step, at every depth ---- */
.lp-rail { position: fixed; z-index: 95; left: 50%; bottom: 1rem; transform: translateX(-50%); width: min(calc(100% - 2rem), 54rem); display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 1rem; padding: .65rem .65rem .65rem 1.25rem; background: rgba(30, 36, 38, .95); color: var(--paper); border: 1px solid rgba(255, 255, 255, .15); box-shadow: 0 .8rem 2.5rem rgba(0, 0, 0, .24); backdrop-filter: blur(1rem); }
.lp-rail.is-single { grid-template-columns: 1fr auto; }
html.lp-rail-ready .lp-rail { transition: transform .5s var(--ease), opacity .4s var(--ease); }
html.lp-rail-ready .lp-rail:not(.is-in) { transform: translate(-50%, 140%); opacity: 0; pointer-events: none; }
.lp-rail span { font-family: var(--font-ui); font-size: var(--f-label); letter-spacing: .08em; text-transform: uppercase; }
.lp-rail > a:not(.button) { color: var(--paper); font-family: var(--font-ui); }
.lp-rail .button { min-height: 2.8rem; padding: .65rem 1rem; }

@media (min-width: 1024px) {
  .ar-in.lp-hero { grid-template-columns: minmax(0, 1.05fr) minmax(24rem, .95fr); gap: 5rem; }
}
@media (min-width: 900px) {
  .lp-journey_stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1.5rem 5rem;
    align-items: center;
    align-content: center;
    min-height: 100svh;
    max-width: var(--maxw);
    margin: 0 auto;
    padding: calc(var(--jr-nav-h, 5.5rem) + 1rem) var(--bleed) 2rem;
  }
  .lp-journey_frames { aspect-ratio: 4 / 5; max-height: 74svh; justify-self: stretch; }
  .lp-journey_stage.is-live .lp-journey_more { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .55s var(--ease); }
  .lp-journey_stage.is-live .lp-journey_more > div { overflow: hidden; }
  .lp-journey_stage.is-live .lp-journey_step.is-on .lp-journey_more { grid-template-rows: 1fr; }
  .lp-journey_stage.is-live .lp-journey_step { opacity: .55; }
  .lp-journey_stage.is-live .lp-journey_step.is-on { opacity: 1; }
  .lp-journey_bar { grid-column: 1 / -1; }
  .lp-why { grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: 5rem; align-items: start; }
  .lp-call { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 5rem; align-items: start; }
}
@media (min-width: 760px) {
  .lp-doors { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .lp-pillars { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .lp-pillar { border-bottom: 0; padding: 2.5rem 2rem 2.5rem 0; }
  .lp-pillar + .lp-pillar { border-left: 1px solid var(--rule); padding-left: 2rem; }
}
@media (max-width: 899px) {
  .ch-journey { padding-bottom: var(--ch-pad); }
  .lp-journey_frames { position: sticky; top: var(--jr-nav-h, 4.5rem); z-index: 2; height: 40svh; }
  .lp-journey_steps { padding: 0 var(--bleed); border-top: 0; }
  .lp-journey_step { min-height: 46svh; align-content: center; }
  .lp-journey_bar { display: none; }
  .is-lp-page .footer_grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 599px) {
  .is-lp-page { padding-bottom: 5.2rem; }
  .is-lp-page .topbar_note, .is-lp-page .navbar_phone { display: none; }
  .is-lp-page .navbar_actions .button { display: inline-flex; }
  .lp-cta_long { display: none; }
  .lp-cta_short { display: inline; }
  .ch-arrival.is-lp .ar-meta { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
  .ch-arrival.is-lp { padding-top: calc(var(--jr-nav-h, 4.5rem) + 2rem); padding-bottom: 3rem; }
  .lp-form-card { padding: 1.25rem; }
  .lp-form-slot:not(.wz-embed) { min-height: 42rem; }
  .lp-why_card, .lp-risks { padding: 1.5rem; }
  .lp-why_card { grid-template-columns: 1fr; gap: .6rem; }
  .lp-doors_wrap .el-seal { display: none; }
  .lp-rail { bottom: .5rem; width: calc(100% - 1rem); grid-template-columns: 1fr auto; gap: .5rem; padding: .5rem; }
  .lp-rail.is-single { grid-template-columns: 1fr; }
  .lp-rail span { display: none; }
  .lp-rail a { min-height: 3.7rem; }
  .lp-rail .button { min-height: 3.7rem; justify-content: center; }
  .lp-rail > a:not(.button) { display: inline-flex; align-items: center; justify-content: center; }
  .is-lp-page .footer_grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .lp-rail { backdrop-filter: none; }
  .lp-journey_frame, .lp-journey_step, .lp-journey_more, html.lp-rail-ready .lp-rail { transition: none !important; }
}
@media (min-width: 992px) {
  .tm-group { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); column-gap: clamp(2rem, 4vw, 4rem); align-items: start; }
  .tm-group_head { position: sticky; top: calc(var(--jr-nav-h, 5.5rem) + 1.5rem); }
  .tm-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ===========================================================================
   BUGHERD, 2026-09-21 — the agency's fourth round (#78-#109), filed from
   Windows 10 / Chrome at 2560x1305. Export and screenshots in
   .tmp/bugherd/tasks-2026-09-21.json; the number is in the comment. The page
   edits are .tmp/bugherd/apply-2026-09-21.mjs, the photographs
   .tmp/bugherd/import-2026-09-21.sh.
   ======================================================================== */

/* #93  "The titles are not all aligned on the same line." The seven service
   group names wrapped at every width. Locally the row needed 1819px of 1829
   at 2560 and just fitted; on the published page the same names measure
   1831px, because Instatic installs static font instances of Newsreader and
   they set a fraction wider than the variable font does here. Two pixels is
   not a margin. From the desktop breakpoint up the names are set smaller and
   the column gap is fluid, which leaves 13-20% of the row empty at every
   width the reviewer or the house uses. Below 1280 the row is genuinely too
   narrow for seven display-size names and still wraps, which is correct.
   probe-tabs.mjs is the measurement, and it reads the LIVE page by URL. */
@media (min-width: 900px) {
  .el-tabs_row { gap: .4rem clamp(.9rem, 1.1vw, 2rem); }
}
@media (min-width: 1280px) {
  .el-tabs_tab { font-size: calc(1.6rem * var(--t-lg)); white-space: nowrap; }
}
@media (min-width: 1600px) {
  .el-tabs_tab { font-size: calc(1.8rem * var(--t-lg)); }
}

/* #90  "When hovering over the photos, it doesn't show where they were
   taken." It did: elevate.js writes the hovered tile's data-caption into
   .el-sheet_line, which sits under the whole grid, several hundred pixels
   from the pointer. A caption that far from the thing it describes is a
   caption nobody sees. It now also appears on the tile itself, from the same
   attribute, in CSS alone -- no second source of truth, and nothing for the
   Instatic export to drop. The line under the grid stays: it is what a
   keyboard reader and a touch reader get. */
.el-sheet_tile { position: relative; }
.el-sheet_tile::after {
  content: attr(data-caption);
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: .75rem .9rem;
  background: linear-gradient(180deg, rgba(30, 36, 38, 0), rgba(30, 36, 38, .86));
  color: #fff;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  line-height: 1.35;
  opacity: 0;
  transform: translateY(.5rem);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
  pointer-events: none;
}
.el-sheet_tile:hover::after,
.el-sheet_tile:focus-visible::after { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .el-sheet_tile::after { transition: none; transform: none; }
}

/* #86 and #91  "The photo is not centered." Both are the same 4:3 frame of
   two of the team reading a chart, and in both slots the crop is taller or
   squarer than the file, so it cuts sideways. The pair stands right of the
   middle of the frame, so a 50% centre clips the second person at the edge.
   Keyed on the file, which survives the import's /uploads/<id>- rename. */
.el-pane img[src*="mp-team-reading-chart-"] { object-position: 62% 42%; }
.el-sheet_tile img[src*="mp-team-plaques-2-"] { object-position: 58% 45%; }

/* #85 #88 #92 #106  The same note against Dr. Sung's portrait in four places.
   This one was not a crop rule: the FILE had him off centre, and his frame
   and its slot are both 3:4, so object-fit had nothing to move. The picture
   is re-cut from the Grand Mission source (album-manifest.json records the
   box and why it is the box it is) and every slot picks the new file up. No
   rule here -- that is the point. */

/* #103  Every card of the preventative "Is this you" grid now carries a
   photograph. Two of the six are the practice's own frames rather than the
   agency's attachments, and they are portraits going into 4:3 boxes. */
.ch-qualify .svc-card_media img[src*="mp-hygienist-loupes-"] { object-position: 62% 30%; }
.ch-qualify .svc-card_media img[src*="mp-checkin-counter-"] { object-position: 50% 32%; }
.ch-qualify .svc-card_media img[src*="mp-dentist-assistant-"] { object-position: 50% 22%; }

/* #79 #80 #81 #82 #84 #97 #100  "The button is enabled, but it doesn't
   redirect to any page", seven times, for seven different phone numbers that
   are all the same tel: link. probe-tel.mjs proves nothing cancels the click:
   a desktop with no handler registered for the tel: scheme simply does
   nothing, and the reviewer cannot tell that apart from a dead button. The
   links are unchanged -- a phone number has to stay a tel: link for the
   readers who are on a phone -- and site.js now copies the number on a fine
   pointer and says so here. */
.phone-copied {
  position: fixed;
  z-index: 9999;
  transform: translate(-50%, .55rem);
  padding: .55rem .85rem;
  background: rgba(30, 36, 38, .95);
  color: #fff;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  border-radius: 2px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity .28s var(--ease);
}
.phone-copied.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .phone-copied { transition: none; } }

/* ========================================================================
   BugHerd round five (2026-09-23). Export: .tmp/bugherd/tasks-2026-09-23.json.
   ======================================================================== */

/* #201  Implant restorations hero: the patient is in the chair at the foot of
   the frame; the default 30% kept the ceiling and cut the chair off. */
.ch-arrival.is-compact .ar-bg img[src*="mp-scanner-screen-2-"] { object-position: 50% 85%; }

/* #158  Blog topic tiles: one height across the row, and the topic name on
   one line. The <li> is the grid item, so the <a> inside has to be told to
   fill it; the name wrapped at 4-up because of its .16em tracking. */
.bl-topics > li { display: flex; }
.bl-topics > li > .bl-topic { flex: 1 1 auto; }
@media (min-width: 992px) { .bl-topic_name { white-space: nowrap; letter-spacing: .08em; } }

/* #159  The article grid drew its rules as its own background showing
   through a 1px gap, so an unfilled last row was a solid sand block. The
   rules are now each card's outline, and an empty cell is the page. */
.bl-grid { background: transparent; border: 0; }
.bl-grid > .bl-card { outline: 1px solid var(--rule); }

/* ========================================================================
   BugHerd round six (2026-09-24). Export: .tmp/bugherd/tasks-2026-09-24.json.
   ======================================================================== */

/* #66  Financing: Cherry links to the practice's own Cherry page (the account
   is Grand Mission Dentistry's; Mason Park Dental is one of its locations).
   `.cp-matrix td a` draws inline links as underlined ink, which would flatten
   the Apply button, so the button gets its own colours back. */
.cp-matrix thead th a.cp-lender { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule-strong); }
.cp-matrix thead th a.cp-lender:hover { color: var(--accent); border-color: var(--accent); }
.cp-matrix td a.button.cp-apply { display: flex; width: fit-content; margin-top: .9rem; color: var(--white); border: 1px solid var(--brand); }
.cp-matrix td a.button.cp-apply:hover { color: var(--white); background: var(--brand-deep); border-color: var(--brand-deep); }

/* Launch (2026-09-24): this stylesheet now also reaches the six Webflow-port ad
   pages still live at the root slugs (/invisalign, /new-patient-special and their
   consultation and thank-you pages), which wrap their body in div.lp-page.
   type-diff.mjs against Webflow found two rules leaking onto them: the h6 style's
   uppercase and the buttons' centring. The rebuilt ad pages carry
   body.is-lp-page instead, so `.lp-page` reaches only the old ports. */
.lp-page .heading-style-h6 { text-transform: none; }
.lp-page .button { justify-content: normal; }

/* ========================================================================
   Dr. Cho leads (2026-09-24). "Dr. Dave Cho needs to be more prominent; Dr.
   Sung should be mentioned only beside Dr. Cho." Every provider band is Dr.
   Cho's; Dr. Sung is the smaller card inside it, linking to Our Doctors.
   ======================================================================== */
.svc-provider_body > .svc-provider_also { margin-top: 1.5rem; }
.svc-provider_also {
  display: flex; align-items: center; gap: 1rem;
  max-width: 26rem; padding: .75rem 1.1rem .75rem .75rem;
  border: 1px solid var(--rule); background: var(--paper);
  color: inherit; text-decoration: none;
  transition: border-color .25s var(--ease);
}
.svc-provider_also:hover { border-color: var(--rule-strong); }
.svc-provider_also img { flex: none; width: 3.5rem; height: auto; aspect-ratio: 3 / 4; object-fit: cover; object-position: 50% 12%; }
.svc-provider_also-body { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.svc-provider_also-role {
  font-family: var(--font-ui); font-size: var(--f-label); font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase; color: var(--accent);
}
.svc-provider_also b { font-family: var(--font-display); font-weight: 400; font-size: calc(1.2rem * var(--t-sub)); line-height: 1.2; color: var(--fg); }
.svc-provider_also-body > span:last-child { font-size: calc(.9rem * var(--t-ui)); line-height: 1.45; color: var(--fg-body); }

/* ========================================================================
   Contact is the hero and the form (2026-09-25). Every "Book" button on the
   site lands here, so the page does one job. The card reuses the ad pages'
   .lp-form-card; on this light ground it needs a lighter shadow and a
   readable width, centred.
   ======================================================================== */
.ch-contact-form .lp-form-card { max-width: 48rem; margin: 0 auto; box-shadow: 0 1rem 3rem rgba(46, 53, 56, .12); }
.ch-contact-form .lp-form-lede a { color: var(--brand-deep); }
.ch-contact-form .lp-form-slot:not(.wz-embed) { min-height: 60rem; }
/* The client's own campaign forms (2026-09-25) settle at about 715px on the
   ad pages, against the 800 to 900 of the Google Ads forms they replaced;
   the 50rem reservation left an empty band under the Submit button. */
.ch-arrival .lp-form-slot.wz-embed { min-height: 44rem; }

/* ========================================================================
   BugHerd round seven (2026-10-01): the /ads-landing-pages/ set.
   ======================================================================== */
/* #258 The $189 offer's limits beside the first price, CTA and form. */
.ch .lp-form-card .lp-terms,
.ch .lp-terms {
  margin: 0 0 1.25rem;
  font-family: var(--font-ui);
  font-size: var(--f-label);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brand-deep);
}
.ch-arrival.is-lp .lp-terms.is-on-dark { margin: -1.2rem 0 2.4rem; color: rgba(255, 255, 255, .82); }
/* #255 "Form" in the header and "What happens next" land under the floating
   header (73px at 864 wide). The site's anchor targets carry their own
   scroll-margin; these two did not. */
.lp-form-card, .ch-call { scroll-margin-top: 7rem; }
/* #260 Termly's consent banner (z-index 999999) sits over the bottom rail on
   production. The rail steps aside while the banner is in the DOM; Termly
   removes the banner node on Accept, Decline or a saved preference. */
body:has([class*="termly-styles-termly-banner"]) .lp-rail { transform: translate(-50%, 140%); opacity: 0; pointer-events: none; }
/* #257 Dr. Dave Cho's portrait is the practice's 750px headshot, cut 562x750.
   Full-bleed at 864 wide it was stretched about 3x on a retina screen. It now
   stops at 480px under 900, framed by the ink, and the ink column stops at
   560px above it. In px on purpose: the limit is the photograph's own pixels,
   and the fluid root made 36rem 668px at 1440. */
@media (max-width: 899px) {
  .ch-dentist .cp-split_ink { display: flex; justify-content: center; }
  .ch-dentist .cp-split_ink img { width: min(100%, 480px); }
}
@media (min-width: 900px) {
  .ch-dentist .cp-split { grid-template-columns: minmax(0, 560px) minmax(0, 1fr); }
}
