/* ═══════════════════════════════════════════════════════════════════════════
   Rooted Within Health — Global Stylesheet
   Mobile-first. Accessible (WCAG 2.1 AA). Self-hosted fonts only.
   Brand: deep forest green, warm gold, warm cream. Spa meets aesthetic fitness.
   Authoring order: font-face → :root tokens → reset/base → layout → components → utilities.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Self-hosted fonts ───────────────────────────────────────────────────── */
/* Fraunces — variable (optical size + weight). Headers. */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces/fraunces-latin-var.woff2') format('woff2-variations');
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url('/assets/fonts/fraunces/fraunces-latin-var-italic.woff2') format('woff2-variations');
}
/* Inter — body. */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
             src: url('/assets/fonts/inter/inter-latin-400.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
             src: url('/assets/fonts/inter/inter-latin-500.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
             src: url('/assets/fonts/inter/inter-latin-600.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap;
             src: url('/assets/fonts/inter/inter-latin-700.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap;
             src: url('/assets/fonts/inter/inter-latin-800.woff2') format('woff2'); }

/* ─── Tokens ───────────────────────────────────────────────────────────────── */
:root {
  /* Brand — Clay Track, the client-selected palette (chosen 2026-07-31).
     Derived from her reference photo: field green + terracotta clay + sky-cream.
     Keeps the §6 direction (deep anchor, warm accent, warm background, no
     sage/mint/teal). Forest & Gold and Coastal Dusk remain as alternates below. */
  --forest:        #35502F;   /* logo, headers, nav */
  --forest-dark:   #24391F;
  --forest-soft:   #E6EBDD;
  --forest-deep:   #1E2E1A;   /* darkest section backgrounds */

  /* Clay Track's accent as the client approved it was #C55A34. At that value NO
     ink passes WCAG AA for normal text on it: dark green lands at 2.91:1 and
     cream at 3.75:1, and button labels (16.8px/600) do not qualify as large
     text. Deepened to #A84E22, which carries cream at 4.85:1 and reads 4deg
     less red, which is also the direction she asked for on 07-31. Same
     terracotta family, one line to revert. */
  --gold:          #A84E22;   /* buttons, icons, callouts */
  --gold-dark:     #8E3F1B;
  --gold-soft:     #F3D9CB;

  --cream:         #F7F1E4;   /* page background */
  --cream-2:       #EEE6D4;   /* alt section background */
  /* Raised surfaces (cards, dropdowns, chips, embeds). Section 6 lists pure
     white under Avoid, and eight rules were using #fff, which read cold against
     the warm cream everywhere else. This is the same value the admin panel
     already uses, so the two stay consistent. */
  --surface:       #FFFDF8;
  --charcoal:      #2B2B26;   /* body text */
  --charcoal-soft: #4C4C44;
  --muted:         #6F6E62;
  --line:          #E1DAC9;   /* hairlines on cream */

  /* Ink on a filled accent button. Terracotta is far darker than the original
     gold, so dark-green label text on it lands at 2.19:1 (WCAG fail). Cream
     text on terracotta is 4.95:1 and passes AA. Palettes with a LIGHT accent
     override this back to --forest-dark. */
  --btn-ink:       var(--on-dark);

  /* The deep accent that passes AA on cream drops to 2.59:1 on forest, so dark
     surfaces use a light clay for accent text instead. Same family, legible
     both ways. Palettes with an already-light accent just reuse it. */
  --accent-on-dark: #E8A87C;

  /* --muted is a mid grey tuned for cream backgrounds. On the dark footer it
     lands at 2.79:1, so de-emphasised text there uses a dimmed cream instead. */
  --muted-on-dark: rgba(245, 239, 226, .70);

  /* Semantic surface tokens */
  --color-bg:        var(--cream);
  --color-bg-alt:    var(--cream-2);
  --color-bg-dark:   var(--forest);
  --color-ink:       var(--charcoal);
  --color-ink-soft:  var(--charcoal-soft);
  --color-heading:   var(--forest);
  --color-accent:    var(--gold);
  --on-dark:         #F5EFE2;   /* text on forest */
  --on-dark-soft:    rgba(245,239,226,.82);

  /* Typography */
  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-heading: 'Fraunces', Georgia, 'Times New Roman', serif;

  /* Radii */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 18px;
  --radius-pill: 999px;

  /* Shadows (warm-tinted) */
  --shadow-1: 0 2px 10px rgba(27, 58, 31, 0.06);
  --shadow-2: 0 10px 24px rgba(27, 58, 31, 0.10);
  --shadow-3: 0 28px 56px rgba(27, 58, 31, 0.16);

  /* Layout */
  --container: 1180px;
  --container-narrow: 900px;
  --header-h: 84px;
}

/* ─── Color themes (alternate palettes) ─────────────────────────────────────────
   Alternate palettes derived from Dr. Quevedo's reference photos. Each overrides
   only the raw brand tokens; every component reads through them, so the whole site
   recolors from one <html data-palette="…"> switch. All keep the §6 direction:
   a deep anchor for headers/nav + a warm accent for CTAs, warm (never pure-white)
   backgrounds, no sage/mint/teal. Default (no attribute) = Clay Track, the palette
   the client selected on 2026-07-31. Cedar Sauna and Twilight Cedar were dropped
   in that same review; only the two alternates she kept remain. */

/* The original brand pairing from CLAUDE.md §6. Its accent is light enough that
   dark-green button text is correct (5.31:1), so --btn-ink reverts. */
:root[data-palette="forest-gold"] {
  --forest: #1B3A1F; --forest-dark: #12280F; --forest-soft: #E7EEE7; --forest-deep: #0E1F10;
  --gold: #D4A017; --gold-dark: #B4860F; --gold-soft: #F6EBCB;
  --cream: #FAF7F0; --cream-2: #F2ECE0; --surface: #FFFEFA; --charcoal: #2B2B2B; --charcoal-soft: #4A4A46;
  --muted: #6E6C64; --line: #E3DDD0; --on-dark: #F6F2E8; --on-dark-soft: rgba(246,242,232,.82);
  --btn-ink: var(--forest-dark); --accent-on-dark: var(--gold);
}
/* REF-06 — beach kickboxing at dusk: indigo-navy + coral/peach sunset + lavender-cream.
   Light peach accent, so dark-green button text is correct here too (5.2:1). */
:root[data-palette="coastal-dusk"] {
  --forest: #38415F; --forest-dark: #262C45; --forest-soft: #E4E5EE; --forest-deep: #20233A;
  --gold: #E0966A; --gold-dark: #C4744A; --gold-soft: #F6E1D3;
  --cream: #F1EEF3; --cream-2: #E7E3EC; --surface: #FCFBFD; --charcoal: #2C2E38; --charcoal-soft: #4E505C;
  --muted: #6E6F7B; --line: #DDDAE4; --on-dark: #F1ECF0; --on-dark-soft: rgba(241,236,240,.82);
  --btn-ink: var(--forest-dark); --accent-on-dark: var(--gold);
}

/* ─── Reset / base ───────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; overflow-x: clip; scroll-padding-top: calc(var(--header-h) + 16px); }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.7;
  color: var(--color-ink);
  background: var(--color-bg);
  /* Fraunces (the only variable font here) has ornate, high-contrast display
     glyphs (g, &, Q, y, j) that read as "melting" at large sizes. Pin a low
     optical size + no soft/wonk quirks for streamlined, conventional letterforms.
     Inter is loaded as static weights, so it ignores this and is unaffected.
     Inherited by all Fraunces text (headings, wordmark, blockquote, intro). */
  font-variation-settings: "opsz" 12, "SOFT" 0, "WONK" 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}
img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: var(--forest); text-decoration: none; transition: color .15s ease; }
a:hover { color: var(--gold-dark); }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  color: var(--color-heading);
  font-weight: 600;
  line-height: 1.12;
  margin: 0 0 .5em;
  letter-spacing: -0.005em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.25rem, 5.2vw, 3.5rem); font-weight: 600; }
h2 { font-size: clamp(1.75rem, 3.6vw, 2.5rem); }
h3 { font-size: 1.4rem; }
h4 { font-size: 1.15rem; }
p  { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
ul, ol { margin: 0 0 1em; padding-left: 1.2em; }
hr { border: 0; border-top: 1px solid var(--line); margin: 2.5rem 0; }
strong { font-weight: 600; color: var(--color-ink); }
:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; border-radius: 3px; }

/* ─── Layout ─────────────────────────────────────────────────────────────────── */
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  /* Responsive gutter: scales up on mid-size windows so content isn't slammed
     to the edge between mobile and the max-width cap; 22px floor on phones. */
  padding: 0 clamp(22px, 4vw, 44px);
}
/* Narrow reading column. Do NOT shrink the container itself — that re-centers
   it and leaves body copy indented ~140px from the left-aligned hero text
   directly above, which reads as a layout mistake. Instead keep the full
   container and cap each child's measure, so left edges line up down the page
   while long-form text keeps a comfortable line length. */
.container-narrow > * { max-width: var(--container-narrow); }
section { padding: 80px 0; }
section.tight { padding: 52px 0; }
.bg-alt   { background: var(--color-bg-alt); }
.bg-dark  { background: var(--forest); color: var(--on-dark); }
.bg-dark h1, .bg-dark h2, .bg-dark h3, .bg-dark h4 { color: var(--on-dark); }
.bg-dark p, .bg-dark li { color: var(--on-dark-soft); }
.bg-deep  { background: var(--forest-deep); color: var(--on-dark); }

/* ─── Photo bands ─── full-bleed photo w/ palette-aware overlay so cream/gold
   text stays legible and the tint tracks whatever <html data-palette> is set. */
.photo-band {
  position: relative;
  isolation: isolate;
  background-color: var(--forest-deep);   /* fallback + fills letterbox */
  background-size: cover;
  background-position: center;
  color: var(--on-dark);
}
.photo-band > * { position: relative; z-index: 1; }
.photo-band::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--forest-deep) 40%, transparent) 0%,
      color-mix(in srgb, var(--forest-deep) 64%, transparent) 100%);
}
/* lighter treatment for bright/airy photos that can carry more image */
.photo-band--soft::after {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--forest-deep) 28%, transparent) 0%,
      color-mix(in srgb, var(--forest-deep) 52%, transparent) 100%);
}
/* stronger wash for text-heavy bands (paragraphs need more contrast) */
.photo-band--dim::after {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--forest-deep) 66%, transparent) 0%,
      color-mix(in srgb, var(--forest-deep) 82%, transparent) 100%);
}
.photo-band h1, .photo-band h2, .photo-band h3, .photo-band blockquote { color: var(--on-dark); }
.photo-band .eyebrow { color: var(--gold); }
.text-center { text-align: center; }

.grid { display: grid; gap: 28px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }

/* ─── Eyebrow / section heading ─────────────────────────────────────────────── */
.eyebrow {
  display: inline-block;
  font-family: var(--font-body);
  font-size: .84rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold-dark);
  margin-bottom: .6rem;
}
.bg-dark .eyebrow, .bg-deep .eyebrow { color: var(--accent-on-dark); }
.section-heading { max-width: 720px; margin: 0 auto 48px; text-align: center; }
.section-heading p { color: var(--color-ink-soft); font-size: 1.08rem; }
.bg-dark .section-heading p { color: var(--on-dark-soft); }

/* ─── Skip link ─────────────────────────────────────────────────────────────── */
.skip-link {
  position: absolute; left: -9999px; top: 8px; z-index: 10000;
  padding: 12px 18px; background: var(--forest); color: var(--on-dark);
  border-radius: var(--radius-md); font-weight: 600;
}
.skip-link:focus { left: 16px; }

/* ─── Buttons ───────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  white-space: nowrap;
  padding: 13px 26px;
  border-radius: var(--radius-pill);
  /* Longhand to match the rest of the file. Inter is static so the shorthand
     caused no visible problem here, but it would the day --font-body becomes a
     variable face. */
  font-weight: 600; font-size: .98rem; line-height: 1;
  font-family: var(--font-body);
  letter-spacing: .01em;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform .12s ease, background .15s ease, color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn-primary { background: var(--gold); color: var(--btn-ink); border-color: var(--gold); }
.btn-primary:hover { background: var(--gold-dark); border-color: var(--gold-dark); color: #fff; }
.btn-outline { background: transparent; color: var(--forest); border-color: var(--forest); }
.btn-outline:hover { background: var(--forest); color: var(--on-dark); }
.btn-light { background: var(--cream); color: var(--forest); border-color: var(--cream); }
.btn-light:hover { background: var(--surface); color: var(--forest-dark); }
.bg-dark .btn-outline, .bg-deep .btn-outline, .hero .btn-outline { color: var(--on-dark); border-color: rgba(246,242,232,.85); }
.bg-dark .btn-outline:hover, .bg-deep .btn-outline:hover, .hero .btn-outline:hover { background: var(--on-dark); color: var(--forest); border-color: var(--on-dark); }
.btn-lg { padding: 16px 34px; font-size: 1.05rem; }

.link-more { font-weight: 600; color: var(--gold-dark); }
.link-more:hover { color: var(--forest); }

/* ─── Site header / nav ─────────────────────────────────────────────────────── */
.site-header {
  position: sticky; top: 0; z-index: 1000;
  background: color-mix(in srgb, var(--cream) 92%, transparent);
  backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--line);
}
/* Older engines without color-mix() fall back to an opaque cream bar. */
@supports not (background: color-mix(in srgb, red, blue)) {
  .site-header { background: var(--cream); }
}
.header-inner { display: flex; align-items: center; gap: 16px; min-height: var(--header-h); }
.logo-link { display: inline-flex; align-items: center; flex: none; }
.logo-link:hover, .brand-title:hover { text-decoration: none; }
.logo-link svg { height: 150px; width: auto; }
.logo-link img { height: 150px; width: 150px; }
.brand-title { display: inline-flex; align-items: center; flex: none; }
.header-actions { display: inline-flex; align-items: center; gap: 14px; margin-left: auto; }
.logo-wordmark { font-family: var(--font-heading); font-weight: 600; font-size: 3rem; color: var(--forest); letter-spacing: -0.01em; line-height: 1.02; }
/* The wordmark grows in alongside the animated mark. Slight delay so the mark
   starts drawing first and the name arrives with it rather than ahead of it.
   Origin is the left edge so it grows out from the mark, not from its centre.
   Runs once per page load. */
@keyframes wordmark-grow-in {
  from { opacity: 0; transform: scale(.92); }
  to   { opacity: 1; transform: none; }
}
.logo-wordmark {
  transform-origin: left center;
  animation: wordmark-grow-in .85s cubic-bezier(.2, .75, .25, 1) .3s both;
}
@media (prefers-reduced-motion: reduce) {
  .logo-wordmark { animation: none; }
}
/* Tablet: ease the mark + wordmark so the full name doesn't crowd the controls. */
@media (max-width: 1159px) {
  .logo-link img, .logo-link svg { height: 110px; width: 110px; }
  .logo-wordmark { font-size: 2.4rem; }
}
/* Phones: the bar carries mark + lang toggle + theme switcher + hamburger, so the
   enlarged wordmark has nowhere to go — show the (still-large) mark on its own. */
@media (max-width: 620px) {
  .logo-link img, .logo-link svg { height: 64px; width: 64px; }
  .logo-wordmark { display: none; }
}

.nav-desktop { display: none; }
.nav-list { display: flex; align-items: center; gap: 26px; list-style: none; margin: 0; padding: 0; }
.nav-link { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; font-weight: 500; color: var(--charcoal); font-size: .98rem; padding: 6px 0; position: relative; }
.nav-link:hover, .nav-link.active { color: var(--forest); }
.nav-link.active::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
  background: var(--gold); border-radius: 2px;
}
.has-menu { position: relative; }
.nav-caret { width: 11px; height: 11px; display: inline-block; vertical-align: middle; margin-top: 1px; flex: none; }
.nav-submenu {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%) translateY(8px);
  min-width: 280px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); box-shadow: var(--shadow-2);
  padding: 10px; list-style: none; margin: 0;
  opacity: 0; visibility: hidden; transition: opacity .16s ease, transform .16s ease;
}
.has-menu:hover .nav-submenu, .has-menu:focus-within .nav-submenu {
  opacity: 1; visibility: visible; transform: translateX(-50%) translateY(6px);
}
.nav-submenu a { display: block; padding: 9px 12px; border-radius: var(--radius-sm); color: var(--charcoal); font-size: .94rem; }
.nav-submenu a:hover { background: var(--forest-soft); color: var(--forest); }

/* min-height, not height: the target grows to 44px without changing the text
   size or the visual weight of the switcher (CLAUDE.md 16.17). Measured at 22px
   before this. */
.lang-toggle { display: inline-flex; align-items: center; min-height: 44px; gap: 6px; font-size: .82rem; font-weight: 600; color: var(--muted); }
.lang-toggle .is-active { color: var(--forest); }
/* --line is a hairline colour and lands at 1.24:1 on cream, so the separator
   between EN and ES was effectively invisible. It carries aria-hidden, so this
   is not a WCAG failure, but it made the language switcher read as two
   unrelated words. --muted is the lightest token that stays legible here. */
.lang-toggle-sep { color: var(--muted); }
/* Visible at every width. It used to appear only in the two-row desktop header,
   which left phones and tablets with no booking button outside the hamburger
   menu. Compact below the desktop breakpoint so the header still fits. */
/* The most-tapped control on the site measured 35px tall on a 360px viewport.
   min-height plus centring reaches 44px without making the pill look chunky;
   the padding longhands stay so the .btn shorthand is not reset (16.13). */
.nav-cta { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; font-size: .82rem; padding-block: 9px; padding-inline: 14px; }
@media (min-width: 700px) { .nav-cta { font-size: .9rem; padding: 11px 18px; } }

/* ─── Style switcher (color-theme preview) ──────────────────────────────────── */
.nav-toggle {
  display: inline-flex; flex-direction: column; gap: 5px; justify-content: center;
  width: 44px; height: 44px; margin-left: auto; padding: 0;
  background: transparent; border: 0; cursor: pointer;
}
.hamburger-line { display: block; width: 24px; height: 2px; background: var(--forest); border-radius: 2px; transition: transform .2s ease, opacity .2s ease; }
/* The panel lists every program, so it is taller than a phone screen. Cap it to
   the space under the header and let it scroll INTERNALLY; overscroll-behavior
   stops the scroll chaining out to the page. .nav-open freezes the page behind
   it, which is what previously made the lower menu items unreachable: a swipe
   moved the site instead of the menu. */
.nav-mobile {
  border-top: 1px solid var(--line); background: var(--cream);
  max-height: calc(100vh - var(--header-h));
  max-height: calc(100dvh - var(--header-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
html.nav-open, html.nav-open body { overflow: hidden; }
/* overflow:hidden on the html element DISABLES position:sticky, so the header
   above stopped sticking the moment the lock was applied and fell back to its
   document position at the top of the page. Opened after any scrolling, the
   menu and the button that closes it were both above the viewport while the
   page was frozen, so neither could be reached (bead 5uu). Measured at 390px
   after a 566px scroll: header top -1200, menu bottom -482. Pinning the header
   for as long as the nav is open keeps both on screen, and the padding replaces
   the height the header gives up by leaving normal flow. */
html.nav-open .site-header { position: fixed; top: 0; left: 0; right: 0; }
html.nav-open body { padding-top: var(--header-h); }
.nav-mobile[hidden] { display: none; }
.mobile-nav-list { list-style: none; margin: 0; padding: 12px 24px 24px; }
.mobile-nav-link { display: block; padding: 12px 0; font-weight: 500; color: var(--charcoal); border-bottom: 1px solid var(--line); }
.mobile-nav-link:hover { color: var(--forest); }
.mobile-nav-group { font-size: .78rem; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); padding: 18px 0 4px; }

/* Programs accordion inside the mobile menu. Native <details>, so it collapses
   without JS. The summary keeps .mobile-nav-link styling so it sits flush with
   its siblings; the default disclosure triangle is suppressed in favour of the
   same caret the desktop nav uses. */
.mobile-nav-details summary.mobile-nav-summary {
  display: flex; align-items: center; justify-content: space-between;
  cursor: pointer; list-style: none;
}
.mobile-nav-summary::-webkit-details-marker { display: none; }
.mobile-nav-summary::marker { content: ''; }
.mobile-nav-summary .nav-caret { width: 13px; height: 13px; transition: transform .18s ease; flex: none; }
.mobile-nav-details[open] .mobile-nav-summary .nav-caret { transform: rotate(180deg); }
.mobile-sublist { list-style: none; margin: 0; padding: 0 0 8px 14px; }
.mobile-nav-sub { font-size: .95rem; color: var(--charcoal-soft); }
.mobile-sublist li:last-child .mobile-nav-sub { border-bottom: 0; }
.mobile-cta-btn { margin-top: 16px; text-align: center; background: var(--gold); color: var(--btn-ink); border-radius: var(--radius-pill); border-bottom: 0; font-weight: 600; }
/* Desktop: two-row header so the enlarged logo gets its own breathing room.
   Row 1 = big logo (left) + CTA and language controls (right).
   Row 2 = full nav on its own line. Achieved by letting .header-inner wrap and
   forcing the nav to a full-width flex row — no markup change needed. */
@media (min-width: 1160px) {
  .header-inner {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-rows: 1fr auto;
    grid-template-areas:
      "mark title actions"
      "mark nav   nav";
    column-gap: 22px;
    row-gap: 0;
    padding: 12px 0;
    min-height: 0;
  }
  .logo-link      { grid-area: mark;    align-self: center; }
  /* Title + actions vertically centered against the logo mark (not pinned top). */
  .brand-title    { grid-area: title;   align-self: center; }
  .header-actions { grid-area: actions; align-self: center; justify-self: end; margin-left: 0; }
  /* Nav on its own row, dropped to the base of the logo; a rule separates it. */
  .nav-desktop {
    grid-area: nav; display: block; align-self: end;
    border-top: 1px solid var(--line); padding-top: 10px;
  }
  .nav-cta   { display: inline-flex; }
  .nav-list  { justify-content: flex-start; gap: 28px; }
  .nav-list > li:first-child .nav-link { padding-left: 0; }
  .nav-toggle, .nav-mobile { display: none; }
}

/* ─── Hero ──────────────────────────────────────────────────────────────────── */
/* Base hero = compact page-title band (interior pages). Home overrides via .hero-home. */
.hero {
  position: relative;
  overflow: hidden;
  background: linear-gradient(155deg, var(--forest) 0%, var(--forest-deep) 100%);
  color: var(--on-dark);
  padding: clamp(56px, 8vw, 104px) 0;
}
.hero h1 { color: var(--on-dark); margin-bottom: .3em; }
.hero p { color: var(--on-dark-soft); font-size: 1.5rem; max-width: 680px; margin-bottom: 2rem; }
.hero .eyebrow {
  color: var(--accent-on-dark);
  font-size: 1.22rem;
  letter-spacing: .16em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .5), 0 2px 14px color-mix(in srgb, var(--forest-deep) 82%, transparent);
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; }
.hero-inner { position: relative; z-index: 1; max-width: 760px; }
.hero-text { max-width: 620px; }

/* Interior hero with a faded photo behind the band (palette-aware wash keeps
   the left-aligned text legible while the image adds warmth on the right). */
.hero-photo { isolation: isolate; background-color: var(--forest-deep); background-size: cover; background-position: center; }
.hero-photo::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(115deg,
    color-mix(in srgb, var(--forest-deep) 88%, transparent) 0%,
    color-mix(in srgb, var(--forest-deep) 72%, transparent) 55%,
    color-mix(in srgb, var(--forest-deep) 52%, transparent) 100%);
}
.hero-photo > .container { position: relative; z-index: 1; }

/* ─── Home hero: full-bleed photo slideshow ─────────────────────────────────── */
.hero-home {
  isolation: isolate;
  background: var(--forest-deep);   /* fallback; slides paint the image */
  display: flex;
  align-items: flex-end;
  min-height: min(82vh, 760px);
  padding: 0 0 clamp(48px, 7vw, 88px);
}
.hero-home > .container { position: relative; z-index: 2; }
.hero-home .hero-text { text-shadow: 0 1px 12px color-mix(in srgb, var(--forest-deep) 55%, transparent); }
.hero-home .eyebrow { text-shadow: 0 1px 3px rgba(0, 0, 0, .5), 0 2px 14px color-mix(in srgb, var(--forest-deep) 82%, transparent); }
/* Palette wash: above the slides, below the text; anchors the headline. */
.hero-home::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--forest-deep) 34%, transparent) 0%,
      color-mix(in srgb, var(--forest-deep) 8%, transparent) 34%,
      color-mix(in srgb, var(--forest-deep) 58%, transparent) 74%,
      color-mix(in srgb, var(--forest-deep) 88%, transparent) 100%);
}
.hero-slides { position: absolute; inset: 0; z-index: 0; }
.hero-slide {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  opacity: 0; transition: opacity .9s ease;
}
.hero-slide.is-active { opacity: 1; }
.hero-controls {
  position: absolute; z-index: 3;
  right: clamp(16px, 4vw, 44px); bottom: clamp(20px, 4vw, 40px);
  display: flex; align-items: center; gap: 12px;
}
.no-js .hero-controls { display: none; }   /* controls need JS */
.hero-arrow {
  width: 42px; height: 42px; border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--on-dark); cursor: pointer;
  border: 1px solid rgba(246, 242, 232, .5);
  background: color-mix(in srgb, var(--forest-deep) 42%, transparent);
  backdrop-filter: blur(4px);
  transition: background .15s ease, border-color .15s ease;
}
.hero-arrow:hover { background: color-mix(in srgb, var(--forest-deep) 70%, transparent); border-color: var(--gold); }
.hero-arrow svg { width: 20px; height: 20px; }
.hero-dots { display: flex; align-items: center; gap: 9px; }
.hero-dot {
  width: 10px; height: 10px; padding: 0; border: 0; border-radius: 50%;
  background: rgba(246, 242, 232, .5); cursor: pointer;
  transition: background .15s ease, transform .15s ease;
}
.hero-dot:hover { background: rgba(246, 242, 232, .8); }
.hero-dot.is-active { background: var(--gold); transform: scale(1.2); }

/* Touch targets. The dots are 10px visually, which is unhittable with a finger
   (WCAG asks for 44px). box-sizing + background-clip let the button grow to a
   44px target while the coloured dot stays small: padding extends the hit area,
   background-clip keeps the paint on the content box. Arrows go to 48px. */
@media (pointer: coarse), (max-width: 620px) {
  .hero-dot {
    box-sizing: content-box;
    width: 12px; height: 12px;
    padding: 17px;                 /* 12 + 34 = 46px target */
    background-clip: content-box;
  }
  /* The desktop active state scales the element, which here would inflate the
     46px hit area over its neighbours so an edge tap selects the wrong slide.
     Colour alone marks the active dot on touch.
     background-clip must be re-asserted: .hero-dot.is-active sets the `background`
     SHORTHAND, which resets background-clip to border-box and made the active dot
     paint across the whole 46px target as a giant circle. */
  .hero-dot.is-active { transform: none; background-clip: content-box; }
  .hero-dots { gap: 0; }
  .hero-arrow { width: 48px; height: 48px; }
}

/* Mobile home hero. Two problems the desktop layout hides:
   1. .hero-controls is absolutely pinned bottom-right, but on a phone the CTAs
      stack and grow into exactly that space, so the prev arrow lands on top of
      the "Explore Programs" button. On mobile the controls join the normal flow
      underneath instead.
   2. The enlarged eyebrow (raised 25% for desktop) wrapped "FUNCTIONAL HEALTH,
      DFW" onto two lines at phone widths, so it comes back a step here.
   Alignment stays LEFT, matching desktop. */
@media (max-width: 620px) {
  /* Vertically centred with breathing room top and bottom, so the eyebrow is not
     pressed against the header. The hero paragraph also comes down from the
     desktop 1.5rem: at phone width that size filled almost the whole band. */
  /* Restores the original tall, bottom-anchored hero: photo above, copy and CTAs
     low in the band. Two things make it behave this time.
     1. dvh, not vh. On iOS, vh measures the viewport WITHOUT the browser
        toolbars, so an 82vh band is taller than what you can actually see and
        bottom-anchored content sits below the fold, hidden behind the browser
        chrome. That is why the CTAs and carousel controls kept disappearing.
        dvh tracks the real visible height. vh stays as a fallback first.
     2. min-height is only a floor, so if the copy is taller than the band the
        section grows instead of overflowing. */
  .hero-home {
    flex-direction: column; align-items: stretch; justify-content: flex-end;
    padding-top: 44px; padding-bottom: 30px;
    min-height: min(82vh, 760px);
    min-height: min(82dvh, 760px);
  }
  /* Left justified, as the desktop layout is. Centring was tried and read as
     less professional. Only the spacing above and the copy size change here. */
  .hero-home .hero-text { max-width: none; text-align: left; }
  .hero-home .hero-text p { font-size: 1.2rem; line-height: 1.6; margin-bottom: 1.6rem; }
  .hero-home .hero-actions { justify-content: flex-start; }
  .hero-home .eyebrow { font-size: 1.02rem; letter-spacing: .1em; }
  /* No carousel controls on a phone. The band is short, the CTAs already own the
     bottom of it, and the dots/arrows were competing with them for the same
     space. The slideshow still auto-advances, so the photos just rotate.
     Desktop and tablet keep the full controls. */
  .hero-controls { display: none; }
}

/* Homepage split hero: headline + logo animation. Scoped to .hero-split so
   interior-page heroes (eyebrow + h1 only) keep their normal stacked layout.
   The animation sits in a light panel so the forest-green linework stays
   legible against the forest hero. */
.hero-split {
  max-width: none;
  display: grid; grid-template-columns: 1fr; gap: clamp(32px, 5vw, 56px);
  align-items: center;
}
.hero-media { justify-self: center; width: 100%; max-width: 380px; }
.hero-logo-video {
  width: 100%; height: auto; display: block;
  background: var(--cream);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  border: 1px solid rgba(212, 160, 23, 0.28);
}
@media (min-width: 900px) {
  .hero-split { grid-template-columns: 1.15fr 0.85fr; }
  .hero-split .hero-text { max-width: none; }
  .hero-media { max-width: 420px; }
}

/* ─── Cards ─────────────────────────────────────────────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 30px;
  box-shadow: var(--shadow-1); transition: transform .16s ease, box-shadow .16s ease;
}
.feature-card { display: block; color: inherit; height: 100%; }
.feature-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); text-decoration: none; }
/* Matches h2 and h3, with the size pinned. Card titles are the top-level
   sections of their page and are marked up as h2 so the outline does not jump
   h1 to h3; without the explicit font-size they would inherit the much larger
   base h2 (clamp up to 2.5rem) and visibly change (16.13, 16.14). */
.card h2, .card h3 { font-size: 1.4rem; color: var(--forest); margin-bottom: .4em; }
.card p { color: var(--color-ink-soft); }
.card-icon {
  width: 46px; height: 46px; border-radius: var(--radius-md);
  background: var(--forest-soft); color: var(--forest);
  display: inline-flex; align-items: center; justify-content: center; margin-bottom: 16px;
}
.card-icon svg { width: 24px; height: 24px; }

/* ─── Media split (editorial image + text) ──────────────────────────────────── */
.media-split { display: grid; grid-template-columns: 1fr; gap: clamp(28px, 5vw, 60px); align-items: center; }
.media-split-img { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-2); aspect-ratio: 4 / 5; }
.media-split-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.media-split-body h2 { margin-bottom: .35em; }
@media (min-width: 900px) {
  .media-split { grid-template-columns: 0.9fr 1.1fr; gap: clamp(40px, 5vw, 72px); }
  .media-split.is-reverse .media-split-img { order: 2; }
  .media-split-img { aspect-ratio: 5 / 6; }
}
/* Point list used beside a media-split */
.point-list { list-style: none; margin: 1.4em 0 0; padding: 0; display: grid; gap: 20px; }
.point-list li { padding-left: 34px; position: relative; }
.point-list li::before {
  content: ''; position: absolute; left: 0; top: 3px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--gold-soft); box-shadow: inset 0 0 0 5px var(--gold);
}
.point-list strong { display: block; color: var(--forest); font-size: 1.08rem; margin-bottom: 3px; }
.point-list span { color: var(--color-ink-soft); }

/* ─── Step list ─── numbered process band (home "how it works") ─────────────── */
.step-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 28px; grid-template-columns: repeat(4, 1fr);
  counter-reset: step;
}
.step-list li { counter-increment: step; position: relative; padding-top: 52px; }
.step-list li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute; top: 0; left: 0;
  /* Longhand, NOT the `font:` shorthand. The shorthand resets
     font-variation-settings to normal, which discarded the "WONK" 0 pinning set
     on body and rendered these numerals in Fraunces' ornate default forms. */
  font-weight: 600;
  font-size: 2.1rem;
  line-height: 1;
  font-family: var(--font-heading);
  color: var(--gold-dark);
}
/* hairline connecting the numerals, desktop only */
.step-list li::after {
  content: ''; position: absolute; top: 18px; left: 56px; right: -28px;
  height: 1px; background: var(--line);
}
.step-list li:last-child::after { display: none; }
.step-list h3 { font-size: 1.1rem; color: var(--forest); margin-bottom: .4em; }
.step-list p { color: var(--color-ink-soft); font-size: .97rem; margin: 0; }
@media (max-width: 980px) {
  .step-list { grid-template-columns: repeat(2, 1fr); gap: 34px; }
  .step-list li::after { display: none; }
}
@media (max-width: 620px) { .step-list { grid-template-columns: 1fr; } }
/* dark / photo-band context */
.bg-dark .step-list li::before, .photo-band .step-list li::before { color: var(--gold); }
.bg-dark .step-list h3,        .photo-band .step-list h3        { color: var(--on-dark); }
.bg-dark .step-list p,         .photo-band .step-list p         { color: var(--on-dark-soft); }
.bg-dark .step-list li::after, .photo-band .step-list li::after { background: rgba(246, 242, 232, .22); }

/* ─── Check list ─── "what's included" bullets inside service cards ─────────── */
.check-list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 9px; }
.check-list li { position: relative; padding-left: 26px; font-size: .95rem; color: var(--color-ink-soft); }
.check-list li::before {
  content: ''; position: absolute; left: 1px; top: .32em;
  width: 13px; height: 7px;
  border-left: 2px solid var(--gold-dark); border-bottom: 2px solid var(--gold-dark);
  transform: rotate(-45deg);
}

/* ─── Service-area chips (local SEO band) ───────────────────────────────────── */
.area-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.area-chip {
  display: inline-flex; align-items: baseline; gap: 9px;
  padding: 10px 17px; border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--line);
  font-size: .96rem; font-weight: 500; color: var(--forest);
}
.area-chip .area-mode {
  font-size: .7rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--gold-dark);
}
.area-chip.is-remote { background: var(--forest-soft); }

/* ─── FAQ accordion (FAQ page + home teaser) ────────────────────────────────── */
.faq-item {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); padding: 18px 20px; margin-bottom: 12px;
}
.faq-item > summary {
  cursor: pointer; list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  /* Longhand for the same reason as .step-list li::before: the `font:`
     shorthand would reset font-variation-settings and un-pin the Fraunces axes,
     which is what made FAQ questions render with wonky letterforms. */
  font-weight: 600; font-size: 1.1rem; line-height: 1.35;
  font-family: var(--font-heading); color: var(--forest);
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary svg { flex-shrink: 0; color: var(--gold-dark); transition: transform .16s ease; }
.faq-item[open] > summary svg { transform: rotate(180deg); }
.faq-item p { margin: 12px 0 0; color: var(--color-ink-soft); }

/* ─── Photo cards (service snapshot with imagery) ───────────────────────────── */
.photo-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  overflow: hidden; box-shadow: var(--shadow-1); display: flex; flex-direction: column;
  transition: transform .16s ease, box-shadow .16s ease;
}
.photo-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); }
.photo-card-media { aspect-ratio: 16 / 10; overflow: hidden; }
.photo-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-card-body { padding: 24px 26px 28px; display: flex; flex-direction: column; flex: 1; }
.photo-card-body h2, .photo-card-body h3 { font-size: 1.4rem; color: var(--forest); margin-bottom: .35em; }
.photo-card-body > p { color: var(--color-ink-soft); }
.photo-card .price-row:first-of-type { margin-top: 16px; }

/* Price list inside service cards */
.price-row { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px dashed var(--line); }
.price-row:last-child { border-bottom: 0; }
.price-row .price { font-weight: 700; color: var(--forest); white-space: nowrap; }
.price-note { font-size: .88rem; color: var(--muted); margin-top: 10px; }

/* ─── Protocol chips ────────────────────────────────────────────────────────── */
.program-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (max-width: 620px) { .program-list { grid-template-columns: 1fr; } }
.program-chip {
  display: flex; align-items: baseline; gap: 10px;
  padding: 14px 18px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); color: var(--charcoal); font-weight: 500;
}
.program-chip:hover { border-color: var(--gold); color: var(--forest); text-decoration: none; transform: translateX(2px); transition: transform .12s ease; }

/* ─── Philosophy strip ──────────────────────────────────────────────────────── */
.philosophy { text-align: center; }
.philosophy blockquote {
  font-family: var(--font-heading); font-size: clamp(1.6rem, 3.4vw, 2.3rem);
  font-style: italic; font-weight: 400; line-height: 1.25;
  color: var(--on-dark); max-width: 820px; margin: 0 auto 1.2em; border: 0; padding: 0;
}

/* NOTE: elements carrying .container must never set shorthand `padding` — it
   resets the container's horizontal gutter to 0 and slams text to the screen
   edge on mobile. Use padding-block for vertical spacing instead. */
/* ─── Footer ────────────────────────────────────────────────────────────────── */
.footer-cta-band { background: var(--gold); color: var(--btn-ink); }
/* Eyebrow defaults to the accent colour, which vanishes on the accent band.
   Force the accent-safe ink: cream on terracotta, dark green on light gold. */
.footer-cta-band .eyebrow { color: var(--btn-ink); }
.footer-cta-inner { display: flex; align-items: center; justify-content: space-between; gap: 32px; padding-block: 52px; flex-wrap: wrap; }
.footer-cta-text h2 { color: var(--btn-ink); margin-bottom: .3em; }
.footer-cta-text p { color: var(--btn-ink); max-width: 520px; }
.footer-cta-actions { display: flex; gap: 14px; flex-wrap: wrap; }
.footer-cta-band .btn-primary { background: var(--forest); border-color: var(--forest); color: var(--on-dark); }
.footer-cta-band .btn-primary:hover { background: var(--forest-dark); border-color: var(--forest-dark); }
/* Outline button inherits forest green, which lands at 2.91:1 on terracotta.
   Track the accent-safe ink instead so it passes AA in every palette. */
.footer-cta-band .btn-outline { color: var(--btn-ink); border-color: var(--btn-ink); }
.footer-cta-band .btn-outline:hover { background: var(--btn-ink); color: var(--gold-dark); border-color: var(--btn-ink); }

.site-footer { background: var(--forest-deep); color: var(--on-dark-soft); }
.footer-main { padding: 64px 0 40px; }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: 40px; }
@media (max-width: 860px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: 32px; } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-col h2, .footer-col h3 { color: var(--on-dark); font-size: 1rem; margin-bottom: 1em; font-family: var(--font-body); font-weight: 600; letter-spacing: .02em; }
.footer-brand .logo-wordmark { color: var(--on-dark); font-size: 1.4rem; }
.footer-tagline { margin-top: 12px; max-width: 320px; }
.footer-nav { list-style: none; margin: 0; padding: 0; }
.footer-nav li { margin-bottom: 10px; }
.footer-nav a { color: var(--on-dark-soft); font-size: .95rem; }
.footer-nav a:hover { color: var(--gold); }
.footer-contact a { color: var(--on-dark-soft); }
.footer-contact a:hover { color: var(--gold); }
.footer-hours-row { display: flex; justify-content: space-between; gap: 12px; font-size: .9rem; padding: 3px 0; }
.footer-hours-row .day { color: var(--on-dark-soft); }
.footer-hours-row .hrs { color: var(--on-dark); }
.footer-hours-row.is-closed .hrs { color: var(--muted-on-dark); }

.footer-bottom { border-top: 1px solid rgba(246,242,232,.12); }
.footer-bottom-inner { display: flex; justify-content: space-between; align-items: center; gap: 20px; padding-block: 22px; flex-wrap: wrap; }
.footer-copyright { font-size: .86rem; margin: 0; }
.footer-legal { font-size: .86rem; margin: 0; }
.footer-legal a { color: var(--on-dark-soft); }
.footer-legal a:hover { color: var(--gold); }
.footer-disclaimer { font-size: .8rem; color: var(--muted-on-dark); max-width: 900px; margin: 14px auto 0; padding-bottom: 28px; text-align: center; }

/* ─── Reveal-on-scroll ──────────────────────────────────────────────────────── */
/* Only hide when JS is present (html.js). With JS off, content stays visible. */
.js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
.js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* ─── Embed placeholders (forms / booking) ──────────────────────────────────── */
.embed-frame { width: 100%; min-height: 620px; border: 0; border-radius: var(--radius-md); background: var(--surface); }
/* Microsoft Bookings iframe. Microsoft's snippet ships height:100%, which
   collapses to nothing without a sized parent, so the height lives here.
   dvh not vh: on iOS vh excludes the browser chrome, which pushed the booking
   controls behind the toolbar the last time this pattern was used. */
.booking-embed {
  width: 100%;
  height: clamp(640px, 82dvh, 1040px);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--cream-2);
}
.booking-embed iframe { display: block; width: 100%; height: 100%; border: 0; }

/* Phone fallback for the Bookings embed (bead 0sv). The iframe is 82dvh tall
   and full width, so on a phone it covered nearly the whole viewport, and a
   touch-drag inside a cross-origin iframe scrolls that iframe rather than the
   page, leaving /contact and /get-started with no scrollable area at all.
   Below 900px the iframe is hidden and this card takes its place, which also
   avoids Bookings rendering as a narrow column in its own grey box at phone
   widths. Card is hidden by default so the desktop path is unchanged. */
.booking-card { display: none; }

@media (max-width: 899px) {
    .booking-embed { display: none; }
    .booking-newtab { display: none; }
    .booking-card {
        display: block;
        text-align: center;
        padding: 32px 24px;
        border: 1px solid var(--line);
        border-radius: var(--radius-md);
        background: var(--cream-2);
    }
    .booking-card-lead { margin: 0 0 20px; }
}

/* Video-visit joining instructions below the booking embed (bead mgq). Sits
   outside the 899px media query above deliberately: the phone path swaps the
   iframe for a card but still needs these instructions, since the phone is the
   case that actually breaks (Teams cannot be joined from a mobile browser).
   Longhand padding, never the shorthand, so nothing here resets a container. */
.booking-prep {
  margin-top: 24px;
  padding: 20px 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--cream-2);
}
.booking-prep h3 {
  font-weight: 600;
  font-size: 1.05rem;
  line-height: 1.3;
  margin: 0 0 10px;
  color: var(--forest);
}
.booking-prep ul { margin: 0; padding-left: 20px; }
.booking-prep li {
  margin-bottom: 8px;
  font-size: .95rem;
  line-height: 1.55;
  color: var(--charcoal-soft);
}
.booking-prep li:last-child { margin-bottom: 0; }

/* Microsoft Forms iframe (includes/form_embed.php). Same shape as the Bookings
   embed above and for the same reasons: Microsoft's snippet ships height:100%,
   which collapses to nothing without a sized parent, and dvh not vh because on
   iOS vh excludes the browser chrome, which hides whatever sits at the bottom
   of the frame. Shorter than the booking embed: Forms paginates by section, so
   it does not need the full viewport. */
.form-embed {
  width: 100%;
  height: clamp(560px, 72dvh, 900px);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--cream-2);
}
.form-embed iframe { display: block; width: 100%; height: 100%; border: 0; }

/* Phone fallback, the lesson from bead 0sv applied to Forms. A touch-drag
   inside a cross-origin iframe scrolls the iframe and never the page beneath
   it, so a form tall enough to be usable leaves the page unscrollable. Below
   900px the iframe is hidden and this card takes its place. It matters more
   here than on Bookings: the nutrition form is 27 questions over seven pages,
   which is not something to complete inside a trapped frame. Card is hidden by
   default so the desktop path is unchanged. */
.form-card { display: none; }

@media (max-width: 899px) {
    .form-embed   { display: none; }
    .form-newtab  { display: none; }
    .form-card {
        display: block;
        text-align: center;
        padding: 32px 24px;
        border: 1px solid var(--line);
        border-radius: var(--radius-md);
        background: var(--cream-2);
    }
    .form-card-lead { margin: 0 0 20px; }
}

/* Wrapper for a full-width booking embed (Contact). Deliberately NOT capped.
   Microsoft's Bookings page switches its service cards from one column to two
   somewhere between 1060px and 1092px, and below that breakpoint it centres a
   narrow column inside its own grey background, which reads as a broken embed
   sitting in a grey box. Measured in the browser on the live dev site, not
   guessed: at 1092, the width our container actually gives it, the cards are
   two-up and the business name fits on one line. Any cap under ~1100px undoes
   that, so if this ever needs constraining, re-measure first. */
.booking-block { width: 100%; }
/* ...including inside .container-narrow, whose `.container-narrow > *` 900px cap
   would otherwise apply. 900px is under Microsoft's two-column breakpoint, so on
   /get-started.php Step 3 the Bookings page rendered as a skinny single column in
   a grey box. Client-reported 2026-08-19. This rule is the whole fix; do not
   re-cap it without re-measuring in the browser. */
.container-narrow > .booking-block { max-width: none; }

/* ─── Centred embeds ─── /get-started.php and /consent.php ────────────────────
   The client asked for the third-party embed boxes to be centred while the COPY
   stays left aligned like the rest of the site. A first pass centred the text as
   well and was rejected for exactly that reason: it made these two pages read as
   a different site.

   So the step wrapper is uncapped to create room to centre inside it, and the
   900px measure is then re-applied to the copy so line length is unchanged and
   every heading keeps the same left edge as the hero above it. Only the embed
   boxes move.

   margin-inline, NEVER the margin shorthand: .container supplies the horizontal
   padding these blocks sit inside and the shorthand silently resets it, which is
   the trap that once put footer body text flush against the screen edge on every
   page.

   The trailing note paragraph is re-capped explicitly. It is a direct .reveal
   child of the container, so the uncapping rule would otherwise let one line of
   small print run the full 1180px. */
.page-centered .container-narrow > .reveal        { max-width: none; }
.page-centered .container-narrow > p.reveal       { max-width: var(--container-narrow); }
.page-centered .container-narrow > .reveal > h2,
.page-centered .container-narrow > .reveal > p    { max-width: var(--container-narrow); }
.page-centered .form-embed,
.page-centered .form-card {
  max-width: var(--container-narrow);
  margin-inline: auto;
}

.embed-placeholder {
  border: 2px dashed var(--gold); border-radius: var(--radius-md);
  background: var(--gold-soft); color: var(--forest-dark);
  padding: 40px; text-align: center; font-weight: 500;
}

/* ─── Program detail page ───────────────────────────────────────────────────── */
/* Question-phrased section headings. Deliberately smaller than the page h1 so
   the hero still leads, while each answer below stays a self-contained passage
   an answer engine can quote (see the AEO bead). */
.program-q {
  font-size: 1.5rem; margin-bottom: .55em;
  padding-top: .2em; border-top: 1px solid var(--line);
}
.program-q:first-child, .reveal:first-child > .program-q { border-top: 0; padding-top: 0; }
.program-lede { font-size: 1.32rem; line-height: 1.6; color: var(--color-ink); }

.program-addresses { margin-top: 4px; }
.program-addresses li { font-size: 1.02rem; }

/* Client-supplied statistic. The source is rendered visibly rather than kept in
   a comment, so nothing on the page reads as an unattributed health claim. */
.program-stat {
  margin: 40px 0 0; padding: 22px 26px;
  background: var(--forest-soft); border-radius: var(--radius-md);
}
.program-stat p {
  margin: 0 0 8px; font-family: var(--font-heading);
  font-size: 1.22rem; line-height: 1.4; color: var(--forest);
}
.program-stat figcaption { font-size: .82rem; color: var(--charcoal-soft); }

.benefit-list { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 12px; }
.benefit-list li {
  position: relative; padding-left: 30px;
  font-size: 1.06rem; color: var(--color-ink);
}
.benefit-list li::before {
  content: ''; position: absolute; left: 0; top: .55em;
  width: 14px; height: 2px; border-radius: 2px; background: var(--gold);
}

/* ─── Legal body ────────────────────────────────────────────────────────────── */
.legal-body h2 { font-size: 1.3rem; margin-top: 1.8em; }
.legal-body h2:first-child { margin-top: 0; }
.legal-body p { color: var(--color-ink-soft); }

/* ─── Breadcrumb ────────────────────────────────────────────────────────────── */
.breadcrumb { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 1.1rem; color: var(--muted); margin-bottom: 18px; }
.breadcrumb a { color: var(--muted); }
.breadcrumb a:hover { color: var(--forest); }
.breadcrumb-sep { color: var(--line); }

/* ─── Contact form ──────────────────────────────────────────────────────────── */
.contact-form-wrap { max-width: 680px; margin: 0 auto; }
.contact-form-wrap h2 { font-size: 1.4rem; }

.form-field { margin-bottom: 18px; }
.form-field label {
  display: block;
  font-weight: 600;
  font-size: .95rem;
  color: var(--color-heading);
  margin-bottom: 6px;
}
.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form textarea {
  width: 100%;
  box-sizing: border-box;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--color-ink);
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding-block: 12px;
  padding-inline: 14px;
  min-height: 48px;                      /* comfortably past the 44px target */
}
.contact-form textarea { min-height: 150px; resize: vertical; }
.contact-form input:focus,
.contact-form textarea:focus {
  outline: 3px solid var(--color-accent);
  outline-offset: 2px;
  border-color: var(--color-accent);
}

.form-note {
  border-radius: var(--radius-md);
  padding-block: 14px;
  padding-inline: 18px;
  margin-block: 0 20px;
  font-size: .95rem;
}
.form-note-ok  { background-color: #E2F0E4; color: #2F6B3A; }
.form-note-bad { background-color: #FBE4E0; color: #9B2C1F; }

.form-privacy {
  font-size: .9rem;
  color: var(--color-ink-soft);
  background-color: var(--cream);
  border-left: 4px solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding-block: 12px;
  padding-inline: 16px;
}

/* The honeypot must be invisible to people but still filled in by a bot, so it
   cannot use display:none or hidden, which most bots skip. Positioned off
   screen and taken out of the tab order instead. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Turnstile widget wrapper (bead dc3). Cloudflare renders a fixed-size iframe
   inside this, so the only job here is spacing and letting it shrink on a narrow
   phone. Do NOT set a background or border: the widget draws its own card, and a
   second one around it reads as a broken embed. */
.form-challenge { margin-bottom: 22px; }
.form-challenge iframe { max-width: 100%; }

/* ─── Touch targets, footer and standalone links (bead xyw) ──────────────────
   All 17 footer links measured 19 to 20px tall at 390px, with a ~29px pitch, so
   a thumb aiming at one link could land on its neighbour. Breaks rule 16.17
   (targets are 44px) and WCAG 2.2 SC 2.5.8's 24px floor. The
   inline-links-in-prose exception does not apply: this is a stacked nav list.

   min-height plus centring rather than guessed padding. Rule 16.17 says padding
   is how you grow a target, and that is right when an element has an explicit
   size to preserve, as .hero-dot does. These links have no set height, so the
   padding needed depends on the resolved line-height, and guessing it is how you
   end up at 43px. min-height states the requirement outright.

   No box-sizing here on purpose. .hero-dot needs content-box because it sets an
   explicit width and height; for an auto-height element, padding adds to the box
   under border-box too, so content-box would be cargo cult.

   Scoped to the same query the header CTA and language toggle used in bead 80i,
   so touch rules stay in one place. */
@media (pointer: coarse), (max-width: 620px) {
  .footer-nav a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
  /* The padding now supplies the separation. Left at 10px the pitch would be
     54px and 17 links would add ~400px of footer on a phone. */
  .footer-nav li { margin-bottom: 0; }

  /* Standalone links: .link-more is always its own anchor after a block, never
     mid-sentence (verified across all 17 uses), and .footer-legal sits in a
     middot-separated row, so neighbours are horizontal. inline-flex therefore
     grows the target vertically without overlapping anything. */
  .footer-contact a,
  .footer-legal a,
  .link-more {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}
