/* ═══════════════════════════════════════════
   DESIGN TOKENS
   ═══════════════════════════════════════════ */
:root {
  /* Palette — Core */
  --cream: #F9F8F2;        /* §3 canonical */
  --sage-green: #8A9A90;   /* §3 canonical. Decorative/large/on-dark ONLY —
                              reads 2.78 against cream in BOTH directions,
                              so it can neither carry text on cream nor sit
                              behind cream text. Use --sage-deep for those. */
  --charcoal: #2C2C2C;     /* §3 canonical. NEVER pure black. */
  --dark-rust: #5C4033;
  --stone: #E6E4DD;

  /* ── Functional derivatives ──────────────────────────────────────────
     Added 2026-08-02. A single colour token cannot serve both a light and a
     dark background — correcting it for one direction breaks the other.
     Sage is the clearest case: #8A9A90 reads 2.78 on cream but 4.8 on
     charcoal, so text that must be read against cream needs its own value. */
  --sage-deep: #5A6457;    /* sage TEXT on cream (5.65), or a sage PANEL
                              behind cream text (5.81). */
  --sage-lifted: #A9BAB0;  /* sage TEXT on the nav dropdown's lifted panel.
                              Plain --sage-green lands at 4.51 there — a
                              hairline AA pass that the next background
                              tweak would break. This reads 6.55. */

  /* Palette — Extended (previously hardcoded) */
  --sage-muted: #7B8A7E;
  --warm-gold: #C4873B;
  --cta-green: #5E7A66;
  --cta-green-dark: #4D6B55;
  --stone-muted: #9B9590;
  --charcoal-deep: #1A1A1A;
  --charcoal-muted: #4A4540;
  --terracotta: #9A5A46;
  --terracotta-dark: #844A38;

  /* Palette — Protocol-Specific */
  --rose-muted: #C4A698;
  --sun-gold: #F4D03F;

  /* Glassmorphism — Legacy */
  --glass: rgba(44, 44, 44, 0.10);
  --glass-border-legacy: rgba(255, 255, 255, 0.08);

  /* O-P-E-N / ROSEWOOD Glassmorphism — Somatic Architecture */
  --glass-bg: rgba(249, 248, 242, 0.4);
  --glass-border-color: rgba(44, 44, 44, 0.1);
  --glass-border: 1px solid var(--glass-border-color);
  --glass-blur: blur(24px);

  /* ── Glass scale ─────────────────────────────────────────────────────────
     Added 2026-08-02. Nine distinct blur radii were live (6/8/10/12/16/18/20/
     24/28px) with no rule for choosing between them — --glass-blur existed but
     exactly one file used it. Three steps, chosen by how much the element has
     to separate from what is behind it:
       sm  small controls sitting ON media (play buttons, chips)
       md  panels and cards in the flow, and the nav pill
       lg  full-surface overlays that must fully detach (drawers, modals, menus)
     Radius follows the same idea: --glass-radius for panels, pill/circle
     shapes keep their own. Never 0 — sharp corners are against §3. */
  --glass-blur-sm: blur(8px);
  --glass-blur-md: blur(16px);
  --glass-blur-lg: blur(24px);
  --glass-radius: 16px;

  /* ── Micro-copy floor ────────────────────────────────────────────────
     Added 2026-08-02. Eyebrows and labels were rendering 8.8-11.7px on a
     390px phone — uppercase, letter-spaced, and unreadable, on the device
     ~80% of visitors use. menu-of-care.css already documented a 12px floor
     and nothing else honoured it. 0.75rem = 12px is the hard minimum for
     any text a visitor is meant to read. */
  --fs-micro: 0.75rem;

  /* Typography Families */
  --font-serif: 'Editorial New', 'Playfair Display', serif;
  --font-sans: 'Geist', 'Lato', sans-serif;
  --font-indic: 'Anek Devanagari', 'Noto Sans Devanagari', sans-serif;

  /* Fluid Typography */
  --fs-display: clamp(1.67rem, 4vw + 0.67rem, 4rem);
  --fs-h2: clamp(1.75rem, 3vw + 0.5rem, 3.5rem);
  --fs-h3: clamp(1.15rem, 1.5vw + 0.5rem, 1.5rem);

  /* -- Card-scale display serif ---------------------------------------------
     Added 2026-08-27. The scale jumps straight from --fs-h2 (56px) to --fs-h3
     (24px), and nothing sat between them. A heading set at --fs-h2 inside a
     ~340px pricing column wrapped "The Total Somatic Bundle" and "The
     Concierge Track" onto THREE lines each, which is most of the reason the
     Menu of Care cards ran 1168px from section heading to CTA and pushed all
     three buttons off a 1080p screen.

     This is the missing step: a display size for a serif heading that has to
     live in a column rather than across the page. Tops out at 38px, which
     holds every current tier name to two lines at 1024px and above.

     Use it for headings inside cards and narrow columns. Section and page
     headings keep --fs-h2. */
  --fs-card-title: clamp(1.6rem, 1.1vw + 1.05rem, 2.375rem);
  --fs-body: clamp(0.95rem, 0.8vw + 0.4rem, 1.125rem);
  --fs-small: clamp(0.8rem, 0.6vw + 0.3rem, 0.9rem);
  --fs-tag: clamp(var(--fs-micro), 0.5vw + 0.25rem, 0.8rem);   /* min was 0.7rem = 11.2px */

  /* THE ROW Typography Tokens */
  --text-h1: clamp(2.5rem, 5vw, 4.5rem);
  --text-body: clamp(1rem, 1.2vw, 1.125rem);
  --leading-body: 1.6;
  --tracking-eyebrow: 0.15em;

  /* Palette — Muted Text */
  --warm-taupe: #5A5248;   /* §3 leaves this open ("medium warm grey").
                              Was #9B9A96 here and #5A5248 in offerings.css —
                              one name, two very different values. #9B9A96 had
                              zero live uses and fails on cream (2.5); all four
                              real uses were offerings' value, so that wins. */

  /* AMAN Spatial Tokens — Massive vertical breathing room */
  /* ── Two vertical spacing systems. They are NOT interchangeable, and until
     2026-08-02 they were named --pad-section and --section-pad, which is a
     word-order collision waiting to be mis-typed.

     --pad-section  the SKILL_02 §1 "Aman void": viewport-HEIGHT driven, for
                    the big editorial gaps between major sections. Used by
                    offerings.css / faq.css.

                    svh, NOT dvh. dvh is the *dynamic* viewport height — it
                    tracks the browser's address bar, which slides away as you
                    scroll down and returns as you scroll up. Using it for
                    in-flow sizing meant the whole page physically resized
                    mid-scroll: measured on nsr-protocol, an 82px viewport
                    change moved the page 238px shorter and slid a section
                    106px up under the reader's finger. That was the "jumps
                    when I stop scrolling" reported from both an S24 Ultra and
                    an iPhone 17 Pro — and it happened only on the FIRST scroll
                    in each direction, which is exactly when the address bar
                    animates. svh is the viewport height WITH the address bar
                    showing, and never changes.

                    Still not vh: the project rule is "never vh", and svh is
                    the modern unit that rule was reaching for.
     --rhythm-unit  viewport-WIDTH driven. The base unit that sections take
                    multiples of (0.5x / 0.75x / 1x / 1.25x). Use this when
                    you want sections to relate to each other proportionally. */
  --pad-section: clamp(10svh, 15vw, 15svh);
  --pad-element: clamp(2rem, 4vw, 4rem);

  /* Spacing — Legacy (used by homepage, protocol pages) */
  /* The single vertical unit. Sections express their padding as a MULTIPLE of
     this (0.5x / 0.75x / 1x / 1.25x) so the rhythm is a ratio system rather
     than four unrelated clamps.
     Was clamp(4rem, 8vw, 8rem): the 4rem floor held until the viewport hit
     800px, so 360px and 768px got identical 64px padding — 18% of a phone's
     width but 8% of a tablet's. The 2rem + 5.5vw middle term removes that
     plateau while keeping the phone value (floor) and the 1920 value (ceiling)
     where they already were, so mobile page length is unaffected. */
  --rhythm-unit: clamp(4rem, 2rem + 5.5vw, 8rem);
  --gutter: clamp(1rem, 2vw, 2rem);

  /* ── Container ───────────────────────────────────────────────────────
     Added 2026-08-02. Content blocks were pinned to 1200 / 1100 / 1060 /
     1000px, so the footer sat 50px further in than every section above it —
     the kind of near-miss that reads as sloppy without being nameable.
     One value for full-width content; narrow measures stay explicit. */
  --container: 1200px;

  /* ── Measure ─────────────────────────────────────────────────────────
     Added 2026-08-03. Body copy ran 78-114ch at 717px and the sitewide
     footer disclaimer reached 309ch at 1920 — unconstrained full-width
     text at 12px. 68ch is the upper end of comfortable for this body face. */
  --measure: 68ch;

  /* THE ROW Shape Tokens */
  --radius-soft: 16px;
  --radius-arch: 50vw 50vw 0 0;

  /* Timing & Easing (Framer-like Physics) */
  --ease-smooth: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  --ease-framer: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-cinematic: cubic-bezier(0.8, 0, 0.1, 1);

  /* Somatic Transition — slow, fluid, no snaps */
  --transition-somatic: all 0.8s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* Scroll offsets — clear fixed nav pill on anchor scroll */
@media (max-width: 1023px) {
  section[id] {
    scroll-margin-top: 80px;
  }
}

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

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Left as `auto` deliberately. scroll.js passes behavior:'smooth' per call
     for anchors, which keeps programmatic jump-to-top (on load, and when a
     scroll lock releases) instant. Setting it globally would animate those
     too, and the page would appear to lose its place. */
  scroll-behavior: auto;
  overscroll-behavior: none;
  overflow-x: clip;
  scrollbar-gutter: stable;
}

/* The scroll lock. Owned by scroll.js — see the long note there for why this
   is on <html> and not on <body>.

   It must be <html>: body->viewport overflow propagation only happens when
   <html> computes to `visible` in both axes, and the rule above sets
   overflow-x: clip. That is why the `body { overflow: hidden }` rules in
   menu-of-care.css and style.css never actually locked anything.

   `hidden` rather than `clip` on purpose — hidden keeps <html> a scroll
   container, so scrollTop is preserved and scrollbar-gutter still reserves its
   space. Nothing moves when this turns on or off. */
html.is-scroll-locked {
  overflow-y: hidden;
}

section {
  scroll-margin-top: 100px;
}

/* The html.lenis / .lenis-smooth / [data-lenis-prevent] rules that lived here
   were removed 2026-08-05 with Lenis itself — the classes they targeted were
   applied by that library and are never set now. Scrolling is native; the
   `data-lenis-prevent` attributes still present on the modal overlays are
   inert leftovers and harmless, but they no longer do anything.

   `overscroll-behavior: contain` is what those attributes used to buy. It now
   belongs on the scroll containers themselves so a modal's inner scroll can't
   chain out to the page behind it. */
.moc-modal-scroll,
.lp-drawer__body {
  overscroll-behavior: contain;
}

body {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--charcoal);
  background: var(--cream);
  /* overflow-x: clip moved to html — keeping body clean preserves sticky */

  /* Makes <body> a PERMANENT stacking context.

     scroll.js locks the scroll with `position: fixed` on <body>, and
     position:fixed always creates a stacking context — so every modal open
     created one on the element that parents the whole page, and every close
     destroyed it, forcing the compositor to rebuild the layer tree at exactly
     the moment the modal was being torn down. Chrome does that commit
     synchronously; WebKit does not, which is why the one-frame flash was
     iOS-only. The same churn re-rooted the body::before grain blend group
     (a mix-blend-mode element blends within its nearest ancestor stacking
     context) twice per modal.

     With this, the context already exists — lock and unlock stop creating and
     destroying one, so there is no rebuild to catch mid-flight.

     `isolation` is not on the list of properties that establish a containing
     block for fixed-position descendants, so nothing moves. Verified: the
     benediction still hides mid-page and still reveals at the bottom. */
  isolation: isolate;
}

/* Organic paper texture — visible warmth across all blank areas */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: url('PageWiseAssets/Texture.webp') repeat;
  background-size: 600px;
  opacity: 0.02;
  mix-blend-mode: multiply;
}


/* ═════════════════════════════════════════════
   CURTAIN PRELOADER
   ═════════════════════════════════════════════ */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: url('PageWiseAssets/Texture.webp') repeat center;
  background-size: 600px;
  background-color: var(--cream);
  transition: transform 1s cubic-bezier(0.77, 0, 0.175, 1);
}

.curtain.is-raised {
  transform: translateY(-100%);
}

.curtain__logo-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  animation: curtainPulse 2s ease-in-out infinite;
}

.curtain__logo {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  object-fit: cover;
}

@keyframes curtainPulse {

  0%,
  100% {
    transform: scale(1);
    opacity: 0.8;
  }

  50% {
    transform: scale(1.06);
    opacity: 1;
  }
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-serif);
  font-weight: 500;
  line-height: 1.15;
  color: var(--dark-rust);
}

a {
  text-decoration: none;
  color: inherit;
}

ul {
  list-style: none;
}

img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

button {
  border: none;
  background: none;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

/* ═══════════════════════════════════════════
   UTILITIES
   ═══════════════════════════════════════════ */
.tag {
  display: inline-block;
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-tag);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--sage-green);
}


/* ═══════════════════════════════════════════
   SECTION 1 — NAVIGATION (Floating Logo + Glass Pill)
   ═══════════════════════════════════════════ */

/* --- Standalone Logo (far left, scrolls with page) --- */
.nav-logo {
  position: absolute;
  top: 1.25rem;
  left: max(1.5rem, calc((100vw - 1200px) / 2));
  z-index: 999;
  text-decoration: none;
  display: flex;
  align-items: center;
}

/* ── Mobile: Logo far-left, compact burger far-right ── */
@media (max-width: 1023px) {
  .nav-logo {
    position: fixed;
    top: 0;
    left: 0;
    padding: 16px 20px;
  }

  /* No scrim behind the fixed logo. A cream radial fade was tried here to keep
     the logo from colliding with section headings during scroll; it read as a
     smudge on the page and was removed at the founder's request (2026-08-02).
     If the overlap becomes a problem again, solve it on the logo itself — a
     subtle shadow or a solid backing shape — not with a gradient wash over the
     underlying content. */

  .nav-logo__img {
    height: 48px;
  }

  /* ─── Burger: mirror of the logo ─────────────────────────────────────────
     Three separate faults stacked up here, all verified on an iPhone.

     1. Everything below except left/right/margin was DEFEATED by the base
        .nav-pill rule further down this file — same specificity, declared
        later, so it won. `top` resolved to the desktop 2.4rem (38.4px)
        instead of 1rem, which is why the burger sat 18px lower than the
        logo. These now carry !important rather than relying on order,
        because reordering the file would switch on six other dormant mobile
        rules that have never rendered.
     2. The desktop `transform: translate3d(-50%, 0, 0)` centring survived
        into mobile, dragging the pill 34px (half its width) left of where
        `right: 20px` put it. Hence "way off".
     3. The pill measured 68x64 against a 72px logo — nearly the same visual
        weight as the brand mark, competing with it.

     Now: a 36px disc, mirrored on the logo's 20px inset and centred on the
     same 52px line. The button inside stays 44x44 and overflows the disc, so
     the touch target is untouched while the visible mark halves. */
  .nav-pill {
    top: 34px !important;          /* 52px logo centre − 18px half-height */
    left: auto !important;
    right: 20px !important;
    margin: 0 !important;
    padding: 0 !important;
    gap: 0 !important;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: none !important;
    /* The whole shorthand, with !important. `animation-name` alone lost to the
       base rule's `animation:` shorthand declared later in this file — so the
       DESKTOP keyframes kept running on mobile, and those interpolate
       translate3d(-50%, …). On a 36px pill that is an 18px leftward jump on
       every load, which is the hop reported from an iPhone: it corrected only
       once something else forced a repaint.

       The mobile keyframes move on opacity and Y only, so the pill can never
       drift horizontally regardless of what else touches transform. */
    animation: navEntranceMobile 1s var(--ease-smooth) 0.6s forwards !important;
  }

  .nav-pill__burger {
    /* Hit area stays 44x44 (WCAG 2.5.8) by overflowing the 36px disc.
       flex-shrink:0 matters — as a flex child of the 36px pill it was being
       squeezed back to 42px wide, quietly undoing the point of the override. */
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    margin: -5px;
    gap: 4px;
  }

  .nav-pill__burger span {
    width: 14px;
  }

  .nav-pill__burger.is-open span:first-child {
    transform: translate3d(0, 2.75px, 0) rotate(45deg);
  }

  .nav-pill__burger.is-open span:last-child {
    transform: translate3d(0, -2.75px, 0) rotate(-45deg);
  }
}

/* The desktop entrance animates translate3d(-50%, …); on mobile the pill is
   not centre-anchored, so it needs its own keyframes or the animation would
   reintroduce the horizontal offset the rule above just removed. */
@keyframes navEntranceMobile {
  from {
    opacity: 0;
    transform: translate3d(0, -16px, 0);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.nav-logo:hover {
  opacity: 0.8;
}

.nav-logo__img {
  height: clamp(72px, 7.2vw, 94px);
  width: auto;
  border-radius: 50%;
  object-fit: contain;
}

/* The capsule surface. Auto-sized to the pill via inset:0, so it needs no JS
   measurement and can never drift from the links it sits behind. It is a child
   of a box that never moves, so the blur region is static for the whole page
   life — only its opacity is ever touched. */
/* The travelling row. Everything visible in the nav that is NOT glass lives
   in here, so the scrub can lift it with a single `translate` on one element
   rather than N. It owns no backdrop-filter, which is the whole point. */
.nav-pill__inner {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  translate: 0 calc(var(--nav-lift-end, 0px) * var(--e-lift, 0));
}

.nav-pill::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--glass);
  border: 1px solid var(--glass-border-color);
  box-shadow: 0 4px 30px rgba(0, 0, 0, 0.03);
  backdrop-filter: var(--glass-blur-md);
  -webkit-backdrop-filter: var(--glass-blur-md);
  pointer-events: none;
  transition: box-shadow 0.4s var(--ease-smooth);
  opacity: calc(1 - var(--e-glass, 0));
}

/* --- Glass Pill Capsule (centered, fixed) --- */
.nav-pill {
  position: fixed;
  top: 2.4rem;   /* Resting: optically centered with logo */
  left: 50%;
  transform: translate3d(-50%, 0, 0);
  z-index: 999;

  display: flex;
  align-items: center;
  /* Top padding reduced, bottom padding increased to optically center text */
  padding: 0.45rem 0.7rem 0.65rem;

  /* The glass lives on ::before now, not here. .nav-pill is a transparent,
     never-moving box; its CHILDREN are what travel during the morph. Keeping
     the surface on a separate, static pseudo-element is what lets the scrub
     exist at all: the rule at :1065 forbids animating anything that owns a
     backdrop-filter, and after this the pill owns none. */
  border-radius: 999px;

  /* Entrance: slide down + fade */
  opacity: 0;
  animation: navEntrance 1s var(--ease-smooth) 0.6s forwards;
}

@keyframes navEntrance {
  from {
    opacity: 0;
    transform: translate3d(-50%, -16px, 0);
  }

  to {
    opacity: 1;
    transform: translate3d(-50%, 0, 0);
  }
}

.nav-pill:hover::before {
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.06);
}

/* Links inside pill — hidden on mobile */
.nav-pill__links {
  display: none;
}

/* Divider — hidden on mobile */
.nav-pill__divider {
  display: none;
}

/* CTA — hidden on mobile */
.nav-pill__cta-wrap {
  display: none;
}

/* Burger — visible on mobile */
.nav-pill__burger {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0;
  z-index: 1001;
}

.nav-pill__burger span {
  display: block;
  width: 20px;
  height: 1.5px;
  background: var(--charcoal);
  border-radius: 2px;
  transition: transform 0.4s var(--ease-smooth), opacity 0.3s var(--ease-smooth);
}

.nav-pill__burger.is-open span:first-child {
  transform: translate3d(0, 3.25px, 0) rotate(45deg);
}

.nav-pill__burger.is-open span:last-child {
  transform: translate3d(0, -3.25px, 0) rotate(-45deg);
}

/* When mobile menu is open: make close button highly visible */
.nav-pill__burger.is-open span {
  background: var(--cream) !important;
  width: 22px;
  height: 2px;
}

/* Nav pill stands out from dark overlay when menu is open */
.nav-pill.menu-active,
.nav-pill:has(.nav-pill__burger.is-open)::before {
  background: rgba(255, 255, 255, 0.12) !important;
  border-color: rgba(255, 255, 255, 0.18) !important;
  backdrop-filter: var(--glass-blur-lg) !important;
  -webkit-backdrop-filter: var(--glass-blur-lg) !important;
}

/* Lock body scroll when mobile menu is open (CSS-driven, no JS reflow) */
body.menu-open {
  overflow: hidden;
}

/* --- Mobile Full-Screen Menu --- */
.nav-mobile {
  position: fixed;
  inset: 0;
  z-index: 998;
  background: rgba(42, 42, 42, 0.96);
  backdrop-filter: var(--glass-blur-md);
  -webkit-backdrop-filter: var(--glass-blur-md);

  display: flex;
  flex-direction: column;
  align-items: center;
  /* flex-start + top padding, not center: the offerings block below can
     grow taller than a short viewport (landscape phones, iPhone SE), and
     centered content with overflow risks clipping the top out of reach.
     overflow-y keeps everything scrollable either way. */
  justify-content: flex-start;
  overflow-y: auto;
  gap: 2.5rem;
  padding: 6.5rem 1.5rem 3rem;

  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s var(--ease-smooth), visibility 0.5s;
}

.nav-mobile.is-open {
  opacity: 1;
  visibility: visible;
}

.nav-mobile ul {
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 2.2rem;
  padding: 0;
  margin: 0;
}

.nav-mobile a {
  font-family: 'Playfair Display', serif;
  font-size: clamp(1.6rem, 5vw, 2.4rem);
  font-weight: 400;
  color: var(--cream);
  opacity: 0.7;
  transition: opacity 0.4s var(--ease-smooth), color 0.4s var(--ease-smooth);
}

.nav-mobile a:hover {
  opacity: 1;
}

/* Offering name/description — shared by the desktop dropdown panel and the
   mobile menu's offerings section so both breakpoints render the identical
   typography instead of keeping two versions in sync by hand. */
.nav-pill__dropdown-name {
  font-family: 'Playfair Display', serif;
  font-size: 1rem;
  font-weight: 500;
  color: var(--cream);
  letter-spacing: 0.01em;
}

.nav-pill__dropdown-desc {
  font-family: 'Lato', sans-serif;
  font-size: 0.82rem;
  font-weight: 400;
  /* Was 0.4, which read 3.35:1 — under the 4.5:1 AA floor for body text.
     Raised again with the lighter panel so it stays clear of the floor. */
  color: rgba(249, 248, 242, 0.82);
  letter-spacing: 0.02em;
  line-height: 1.45;
}

/* Mobile menu's offerings block: same content as the desktop dropdown
   (section label, protocols, Library row, "view all"), laid out for a
   full-screen overlay instead of an anchored panel. */
.nav-mobile__action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  width: 100%;
  max-width: 360px;
}

.nav-mobile__section-label {
  font-family: 'Lato', sans-serif;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(249, 248, 242, 0.72);
  margin: 0;
}

.nav-mobile__protocols {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
  padding: 1rem 1.1rem;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 14px;
}

.nav-mobile__protocols a,
.nav-mobile__library {
  /* Reset the giant .nav-mobile a serif sizing — these render at the
     .nav-pill__dropdown-name/-desc sizes set on their child spans instead. */
  display: flex;
  flex-direction: column;
  gap: 3px;
  text-align: left;
  font-size: 1rem;
  opacity: 1;
}

.nav-mobile__library {
  width: 100%;
  padding: 0.9rem 1.1rem;
  background: rgba(143, 163, 150, 0.2);
  border-radius: 14px;
}

.nav-mobile__view-all {
  font-family: 'Lato', sans-serif;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sage-lifted);
  opacity: 1;
}

/* ── Current page ────────────────────────────────────────────────────────
   aria-current is the semantic marker and doubles as the styling hook, so
   the announced state and the visible one can't drift apart. Replaces the
   library-only --active class that never applied on any other page. */
.nav-pill__dropdown-item[aria-current="page"] .nav-pill__dropdown-name,
.nav-mobile__action a[aria-current="page"] .nav-pill__dropdown-name {
  font-weight: 700;
}

.nav-pill__dropdown-item[aria-current="page"]::after,
.nav-mobile__action a[aria-current="page"]::after {
  content: 'Currently viewing';
  font-family: 'Lato', sans-serif;
  /* 12px floor — see CLAUDE.md. Do not shrink to differentiate it. */
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sage-lifted);
  margin-top: 0.15rem;
}

/* --- Desktop: pill displays links + divider + CTA --- */
@media (min-width: 1024px) {
  .nav-pill {
    /* Symmetrical vertical padding; snug right edge houses the CTA pill */
    padding: 0.45rem 0.45rem 0.45rem 1.4rem;
    gap: 0;
  }


  .nav-pill__links {
    display: flex;
    align-items: center;
    gap: 1.6rem;
  }

  .nav-pill__links a {
    font-family: 'Lato', sans-serif;
    font-size: var(--fs-small);
    font-weight: 400;
    letter-spacing: 0.08em;
    color: var(--cream);
    opacity: 0.75;
    position: relative;
    transition: opacity 0.5s var(--ease-smooth);
    line-height: 1;
    display: inline-flex;
    align-items: center;
    padding: 0.45rem 0;
  }

  /* Visible cream glow underline on hover */
  .nav-pill__links a::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1.5px;
    background: rgba(253, 252, 248, 0.9);
    box-shadow: 0 0 6px rgba(253, 252, 248, 0.3);
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 0.5s var(--ease-smooth);
  }

  .nav-pill__links a:hover {
    opacity: 1;
  }

  .nav-pill__links a:hover::after {
    transform: scaleX(1);
  }

  /* Whisper-thin Divider */
  .nav-pill__divider {
    display: block;
    width: 1px;
    height: 18px;
    margin: 0 1.2rem;
    background: rgba(253, 252, 248, 0.2);
    flex-shrink: 0;
  }

  /* CTA Wrapper — houses trigger + dropdown */
  .nav-pill__cta-wrap {
    display: block;
    position: relative;
  }

  .nav-pill__cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 1.15rem;
    font-family: 'Lato', sans-serif;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--cream);
    white-space: nowrap;
    border-radius: 999px;
    background: transparent;
    border: 1px solid rgba(249, 248, 242, 0.18);
    cursor: pointer;
    text-decoration: none;
    position: relative;
    transition: background 0.5s var(--ease-smooth),
                color 0.4s var(--ease-smooth),
                border-color 0.5s var(--ease-smooth),
                transform 0.3s var(--ease-smooth);
  }

  /* Subtle bottom accent line */
  .nav-pill__cta::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 20%;
    width: 60%;
    height: 1.5px;
    background: var(--sage-green);
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 0.5s var(--ease-smooth);
  }

  .nav-pill__cta-wrap:hover .nav-pill__cta::after,
  .nav-pill__cta:hover::after {
    transform: scaleX(1);
  }

  /* Animated chevron arrow */
  .nav-pill__cta-arrow {
    display: inline-flex;
    width: 8px;
    height: 8px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
    opacity: 0.45;
    transition: transform 0.5s var(--ease-smooth), opacity 0.3s var(--ease-smooth);
    flex-shrink: 0;
  }

  .nav-pill__cta-wrap:hover .nav-pill__cta-arrow,
  .nav-pill__cta-wrap.is-open .nav-pill__cta-arrow {
    transform: rotate(225deg) translate(-1px, -1px);
    opacity: 0.85;
  }

  .nav-pill__cta:hover,
  .nav-pill__cta-wrap:hover .nav-pill__cta,
  .nav-pill__cta-wrap.is-open .nav-pill__cta {
    background: rgba(143, 163, 150, 0.18);
    border-color: rgba(143, 163, 150, 0.35);
    transform: translate3d(0, -1px, 0);
  }

  /* The page-dimming .nav-scrim that used to sit behind this panel was removed
     2026-08-05. .nav-pill lives inside .page-content (z-index:1), so the nav's
     z-index:999 is scoped to that stacking context and a body-level scrim at
     900 covered the entire nav, the panel included — every click landed on the
     scrim and the site read as frozen. See nav-dropdown.js.

     Dropdown panel — opened by JS (.is-open on the wrap) on hover or focus.
     It is a preview of offerings.html, never the only route to it: the trigger
     is a plain link, so a ≥1024px touchscreen that never opens this panel
     still reaches the same content by tapping through. */
  .nav-pill__dropdown {
    position: absolute;
    top: calc(100% + 0.75rem);
    right: -0.5rem;
    min-width: 324px;
    padding: 0.85rem;
    /* Lifted off near-black and made more opaque: the old 0.92 let dark hero
       imagery bleed through and muddy the type underneath it. */
    background: rgba(52, 50, 45, 0.96);
    /* backdrop-filter moved to the .is-open rule below. Declared here it was
       unconditional on all 11 pages: a pinned composited layer with a live
       backdrop sampler for the whole page life, on a panel that is
       visibility:hidden until opened — the same cost menu-of-care.css:845-850
       documents for the modals and fixed the same way. It was also doing
       nothing visible: at 0.96 background alpha only 4% of the blurred
       backdrop shows through. And it was the second blur inside .nav-pill,
       which is half of why the note at :1065 forbids moving the pill at all. */
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 16px;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.18),
                0 2px 8px rgba(0, 0, 0, 0.08);

    /* Hidden by default */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition:
      opacity 0.4s var(--ease-smooth),
      visibility 0.4s,
      transform 0.4s var(--ease-smooth);
  }

  .nav-pill__cta-wrap.is-open .nav-pill__dropdown {
    backdrop-filter: var(--glass-blur-lg);
    -webkit-backdrop-filter: var(--glass-blur-lg);
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }

  .nav-pill__dropdown-section-label {
    font-family: 'Lato', sans-serif;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(249, 248, 242, 0.72);
    padding: 0.4rem 0.95rem 0.5rem;
    margin: 0;
  }

  .nav-pill__dropdown-item {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.8rem 0.95rem;
    border-radius: 12px;
    text-decoration: none;
    transition: background 0.3s var(--ease-smooth);
  }

  .nav-pill__dropdown-item:hover,
  .nav-pill__dropdown-item:focus-visible {
    background: rgba(255, 255, 255, 0.07);
  }

  .nav-pill__dropdown-item:focus-visible {
    outline: 2px solid var(--cream);
    outline-offset: -2px;
  }

  .nav-pill__dropdown-divider {
    height: 1px;
    background: rgba(255, 255, 255, 0.12);
    margin: 0.4rem 0.6rem;
  }

  .nav-pill__dropdown-footer {
    padding: 0.6rem 0.95rem 0.45rem;
    text-align: center;
  }

  .nav-pill__dropdown-footer a {
    font-family: 'Lato', sans-serif;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    /* Solid, not the old opacity:0.6 sage — that read 2.57:1, the worst
       contrast in the panel on what is meant to be its primary CTA. */
    color: var(--sage-lifted);
    text-decoration: none;
    transition: letter-spacing 0.4s var(--ease-smooth);
  }

  .nav-pill__dropdown-footer a:hover {
    letter-spacing: 0.18em;
  }

  .nav-pill__dropdown-footer a:focus-visible {
    outline: 2px solid var(--cream);
    outline-offset: 2px;
    border-radius: 6px;
  }

  /* Library — grouped below the divider, apart from the one-time protocols
     under .nav-pill__dropdown-section-label, since it's the recurring
     membership rather than a protocol. Tinted row rather than a border
     stripe so it reads as its own category, not a 4th list item. */
  .nav-pill__dropdown-item--library {
    background: rgba(143, 163, 150, 0.16);
  }

  .nav-pill__dropdown-item--library:hover,
  .nav-pill__dropdown-item--library:focus-visible {
    background: rgba(143, 163, 150, 0.26);
  }

  .nav-pill__burger {
    display: none;
  }

  .nav-mobile {
    display: none;
  }
}


/* ═══════════════════════════════════════════════════
   NAV: SCROLL-AWARE DUAL-MODE (Global)
   Default = light mode (charcoal text on light backgrounds).
   .nav--dark = dark mode (cream text on dark backgrounds).
   Toggled by nav-theme.js based on [data-nav-theme] sections.
   ═══════════════════════════════════════════════════ */

/* Smooth transitions on all color-shifting elements.

   Updated 2026-08-27. The surfaces moved to .nav-pill::before, so the colour
   transition has to move with them or the nav--dark/--light swap becomes a
   hard cut. .site-nav::before (the bar) is in the list for the same reason.

   The old note here warned against ever animating .nav-pill's transform,
   because the pill owned a backdrop-filter and contained the dropdown's. Both
   are gone: the capsule's blur is on ::before, and the dropdown's is now
   scoped to .is-open. The pill still never moves — the scrub translates its
   CHILDREN — and it does so via the independent `translate` property rather
   than `transform`, which composes separately and so cannot collide with
   navEntrance's filling animation. That collision is what forced the two
   `transform: none !important` rules this change deletes. */
.nav-pill,
.nav-pill::before,
.site-nav::before,
.nav-pill__burger span {
  transition: background 0.5s var(--ease-smooth), border-color 0.5s var(--ease-smooth), box-shadow 0.4s var(--ease-smooth), transform 0.4s var(--ease-smooth), opacity 0.3s var(--ease-smooth) !important;
}

/* ── .nav--dark: Cream text for dark sections ── */
.nav--dark .nav-pill::before {
  background: rgba(32, 32, 30, 0.50);
  border-color: rgba(255, 255, 255, 0.08);
}

.nav--dark .nav-pill__burger span {
  background: var(--cream) !important;
}

/* ── .nav--light: Charcoal text for light sections ── */
.nav--light .nav-pill::before {
  background: var(--glass);
  border-color: var(--glass-border-color);
}

.nav--light .nav-pill__burger span {
  background: var(--charcoal) !important;
}

@media (min-width: 1024px) {

  /* ── Dark mode ── */
  .nav--dark .nav-pill::before {
    background: rgba(32, 32, 30, 0.50) !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
  }

  .nav--dark .nav-pill__links a {
    color: var(--cream) !important;
    opacity: 0.8;
    transition: color 0.5s var(--ease-smooth), opacity 0.5s var(--ease-smooth) !important;
  }

  .nav--dark .nav-pill__links a:hover {
    opacity: 1 !important;
  }

  .nav--dark .nav-pill__links a::after {
    background: rgba(245, 245, 240, 0.85) !important;
    box-shadow: 0 0 6px rgba(245, 245, 240, 0.25) !important;
  }

  .nav--dark .nav-pill__divider {
    background: rgba(245, 245, 240, 0.2) !important;
  }

  .nav--dark .nav-pill__cta {
    background: transparent !important;
    color: var(--cream) !important;
    border-color: rgba(249, 248, 242, 0.22) !important;
    transition: background 0.5s var(--ease-smooth), color 0.5s var(--ease-smooth), border-color 0.5s var(--ease-smooth), transform 0.3s var(--ease-smooth) !important;
  }

  .nav--dark .nav-pill__cta:hover,
  .nav--dark .nav-pill__cta-wrap:hover .nav-pill__cta,
  .nav--dark .nav-pill__cta-wrap.is-open .nav-pill__cta {
    background: rgba(143, 163, 150, 0.2) !important;
    border-color: rgba(143, 163, 150, 0.4) !important;
    color: var(--cream) !important;
  }

  .nav--dark .nav-pill__cta::after {
    background: var(--sage-green) !important;
  }

  .nav--dark .nav-pill__dropdown {
    background: rgba(30, 30, 28, 0.92) !important;
    border-color: rgba(249, 248, 242, 0.06) !important;
  }

  /* ── Light mode ── */
  .nav--light .nav-pill::before {
    background: rgba(230, 228, 221, 0.12) !important;
    border-color: rgba(230, 228, 221, 0.18) !important;
  }

  .nav--light .nav-pill__links a {
    color: var(--charcoal) !important;
    transition: color 0.5s var(--ease-smooth), opacity 0.5s var(--ease-smooth) !important;
  }

  .nav--light .nav-pill__links a:hover {
    opacity: 0.5 !important;
  }

  .nav--light .nav-pill__links a::after {
    background: rgba(42, 42, 42, 0.7) !important;
    box-shadow: 0 0 4px rgba(42, 42, 42, 0.15) !important;
  }

  .nav--light .nav-pill__divider {
    background: rgba(42, 42, 42, 0.2) !important;
  }

  .nav--light .nav-pill__cta {
    background: transparent !important;
    color: var(--charcoal) !important;
    border-color: rgba(42, 42, 42, 0.2) !important;
    transition: background 0.5s var(--ease-smooth), color 0.5s var(--ease-smooth), border-color 0.5s var(--ease-smooth), transform 0.3s var(--ease-smooth) !important;
  }

  .nav--light .nav-pill__cta:hover,
  .nav--light .nav-pill__cta-wrap:hover .nav-pill__cta,
  .nav--light .nav-pill__cta-wrap.is-open .nav-pill__cta {
    background: rgba(42, 42, 42, 0.06) !important;
    border-color: rgba(42, 42, 42, 0.3) !important;
    color: var(--charcoal) !important;
  }

  .nav--light .nav-pill__cta::after {
    background: var(--sage-green) !important;
  }

  .nav--light .nav-pill__dropdown {
    background: rgba(30, 30, 28, 0.92) !important;
    border-color: rgba(255, 255, 255, 0.06) !important;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.18), 0 2px 8px rgba(0, 0, 0, 0.08) !important;
  }

  /* Light-mode dropdown now shares the same dark glass as dark-mode — unified look */
  .nav--light .nav-pill__dropdown-item:hover,
  .nav--light .nav-pill__dropdown-item:focus-visible {
    background: rgba(255, 255, 255, 0.06) !important;
  }

  .nav--light .nav-pill__dropdown-name {
    color: var(--cream) !important;
  }

  /* 0.42 -> 0.6, matching the base-rule fix: this override was independently
     regressing the same contrast failure (2.9:1) whenever the nav sat over
     a light-themed section. */
  .nav--light .nav-pill__dropdown-desc {
    color: rgba(249, 248, 242, 0.6) !important;
  }

  .nav--light .nav-pill__dropdown-divider {
    background: rgba(255, 255, 255, 0.05) !important;
  }

  /* Same lifted sage as the base rule — the panel is the identical dark
     glass in both themes, so a plain --sage-green here would silently
     reinstate the 4.51 hairline on every light-themed section. */
  .nav--light .nav-pill__dropdown-footer a {
    color: var(--sage-lifted) !important;
  }

  .nav--light .nav-pill__dropdown-item--library {
    background: rgba(143, 163, 150, 0.16) !important;
  }

  .nav--light .nav-pill__dropdown-item--library:hover,
  .nav--light .nav-pill__dropdown-item--library:focus-visible {
    background: rgba(143, 163, 150, 0.26) !important;
  }
}


/* ════════════════════════════════════════════
   SECTION 2 — HERO (The Inhale)
   ════════════════════════════════════════•═════════ */
.hero {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100svh;
  min-height: 500px;
  overflow: hidden;
  background: var(--charcoal);
}

/* ─── Global Content Containment ───
   CONTENT wrappers only. Never a <section> that paints a background.

   .starting and .proof used to be in this list, and both are full-bleed
   sections with their own background. Capping a section at 1200px does not
   narrow its content — the inner wrappers below already do that — it narrows
   the painted box, so above 1200px the background became a band down the
   middle with .page-content's cream either side. At 1440 that is 120px of the
   wrong colour on each edge.

   Only .proof was ever visible: it paints --stone against a --cream page.
   .starting paints --cream on --cream, so it had the identical bug and looked
   perfect. Removed from this rule 2026-08-07 — .starting too, because a
   latent version of a bug you have already fixed once is worth closing while
   you are holding it.

   Each section's content stays contained by its own wrapper:
     .starting  -> .starting__header, .starting__grid  (both below)
     .proof     -> .proof__header (below), .proof__sticky (max-width 1100px) */
.starting__header,
.starting__grid,
.proof__header,
.methodology__inner,
.footer__inner {
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}

.hero__bg {
  position: absolute;
  /* Parallax needs vertical space (top/bottom -15%), but NO horizontal cropping (left/right 0) */
  inset: -15% 0;
  z-index: 1;
  will-change: transform;
}

.hero__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Mobile: keep lady on rocks visible (left side) */
  object-position: left center;
  /* "Inhale" animation: zoom-out 105% → 100%, fade in */
  opacity: 0;
  transform: scale(1.05);
  animation: heroInhale 5s var(--ease-smooth) forwards;
  will-change: transform, opacity;
}

/* ── MOBILE HERO: 3-part organic layout ────────────── */
@media (max-width: 768px) {

  /* Reset parallax overflow — not needed on mobile */
  .hero__bg {
    inset: 0 !important;
  }

  /* PART 1: Background Physics
     The woman sits at ~25% from left in the landscape original.
     On 9:16 viewport, only ~30% of image width shows.
     Position her center-frame with sky above. */
  .hero__img {
    object-position: 15% 80% !important;
  }
}

@keyframes heroInhale {
  0% {
    opacity: 0;
    transform: scale(1.05);
  }

  30% {
    /* Fade in completes by 1.5s (30% of 5s) */
    opacity: 1;
  }

  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* Hero stays left-cropped on all sizes to keep the subject visible */

/* Warm color grade overlay — removes cool blue, adds golden warmth */
.hero__warmth {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(135deg,
      rgba(200, 160, 80, 0.12) 0%,
      rgba(143, 163, 150, 0.08) 50%,
      rgba(200, 160, 80, 0.06) 100%);
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* Dark gradient overlay for text readability */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  background: linear-gradient(270deg,
      rgba(240, 238, 233, 0.85) 0%,
      rgba(240, 238, 233, 0.4) 40%,
      transparent 70%);
  pointer-events: none;
}

/* Text cascade — right side, vertically centered (no transform — GSAP-safe) */
.hero__content {
  position: absolute;
  z-index: 4;
  top: 0;
  bottom: 0;
  margin-top: auto;
  margin-bottom: auto;
  height: fit-content;
  right: max(1.5rem, calc((100vw - 1200px) / 2 - 3rem));
  max-width: 540px;
  text-align: left;
}

@media (max-width: 768px) {

  /* PART 1 (cont.): Full viewport hero */
  .hero {
    height: 100svh;
    min-height: 100svh;
    max-height: 100svh;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    overflow: hidden;
  }

  /* Desktop fades from the RIGHT edge, because the text sits on the right of a
     wide frame. On a phone the composition rotates — the text stacks at the
     bottom — so the fade rotates with it rather than being switched off.

     It is needed. Sampling the rendered pixels under the subtitle on a 375px
     iPhone: the darkest 5% of that band is luma 109, giving charcoal-at-85%
     just 2.40:1. Three cheaper fixes were measured and rejected first:
       · vertical re-crop is inert — at 1344x768 into 375x812 the cover scale
         is driven entirely by height, so there is no vertical slack at all;
       · horizontal re-crop does work (p5 rises to 177, comfortably AA) but
         pans the woman clean out of frame;
       · narrowing the subtitle barely moves it (109 -> 119 even at 52% width)
         because the dark band is the rock edge spanning the full width, not
         the subject.

     Anchored to the bottom edge so it reads as the photograph dissolving into
     the cream section below — the same device as desktop, and the reason the
     previous attempt failed: a centred ellipse floating mid-frame read as a
     smudge on the picture. */
  .hero::after {
    background: linear-gradient(to top,
        var(--cream) 0%,
        rgba(249, 248, 242, 0.94) 16%,
        rgba(249, 248, 242, 0.66) 38%,
        rgba(249, 248, 242, 0.26) 58%,
        rgba(249, 248, 242, 0) 74%);
  }

  /* PART 2: Typography Recalibration — right-aligned breathable layout */
  .hero__content {
    position: relative;
    top: auto;
    bottom: auto;
    right: auto;
    left: auto;
    transform: none;
    width: 85%;
    max-width: 100%;
    margin-left: auto;
    margin-right: 0;
    padding: 14svh 1.25rem 12svh 0;
    box-sizing: border-box;
    text-align: right;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    z-index: 4;
  }

  /* The radial "mist guard" that used to sit here was removed 2026-08-05 —
     it read as a white smudge floating over the middle of the photograph.
     Replaced by .hero::after below: an edge-anchored fade instead of a blob.
     See the note there for why the crop could not solve this on its own. */

  /* Measured 108px of dead space between the rule and the word "ROOTED" on a
     375px iPhone. The eyebrow is a flex row, the label wraps to two lines at
     this width, and the anonymous text item then stretches to fill the row —
     inherited text-align:right pulls the words to its far edge while the rule
     stays pinned at its near edge.

     Block layout with an inline-block ::before keeps the rule attached to the
     first word however the label wraps. !important because the base
     .hero__eyebrow rule is declared LATER in this file at equal specificity;
     without it `display: block` silently loses to `display: flex`. */
  .hero__eyebrow {
    display: block !important;
    text-align: right;
  }

  .hero__eyebrow::before {
    display: inline-block !important;
    width: 24px !important;
    margin-right: 0.6rem;
    vertical-align: middle;
  }

  .hero__title {
    font-size: clamp(2rem, 8vw, 3rem);
    color: var(--charcoal);
  }

  .hero__subtitle {
    font-size: clamp(0.85rem, 3.5vw, 1rem);
    max-width: 80%;
    color: rgba(42, 42, 42, 0.85);
    align-self: flex-end;
    margin-top: 0.5rem;
  }

  .hero__cta {
    align-self: flex-end;
  }
}

/* --- Eyebrow --- */
.hero__eyebrow {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-tag);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--sage-muted);
  margin-bottom: 1.2rem;

  opacity: 0;
  transform: translate3d(0, 15px, 0);
  animation: textCascade 0.8s var(--ease-smooth) 1.2s forwards;
}

.hero__eyebrow::before {
  content: '';
  display: block;
  width: 40px;
  height: 1px;
  background: var(--sage-muted);
}

/* --- Headline --- */
.hero__title {
  font-family: 'Playfair Display', serif;
  font-size: clamp(3rem, 6vw, 5rem);
  color: var(--charcoal);
  margin-bottom: 0.6em;
  line-height: 1.05;

  opacity: 0;
  transform: translate3d(0, 15px, 0);
  animation: textCascade 0.8s var(--ease-smooth) 1.4s forwards;
}

.hero__highlight {
  color: var(--warm-gold);
  font-style: italic;
  font-weight: 500;
}

/* --- Subheadline --- */
.hero__subtitle {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-body);
  font-weight: 300;
  color: rgba(42, 42, 42, 0.85);
  letter-spacing: 0.02em;
  line-height: 1.85;
  max-width: 44ch;
  margin-bottom: 2rem;

  opacity: 0;
  transform: translate3d(0, 15px, 0);
  animation: textCascade 0.8s var(--ease-smooth) 1.6s forwards;
}

/* --- CTA Button — the site's primary conversion link ──────────────────────
   It goes to offerings.html and sits on a photographic hero, so it has to
   carry real mass and separate cleanly from the image. Held inside the
   brand's own language: sage pill, cream type, somatic easing, nothing neon.

   Two fixes are baked in here. The entrance used `forwards` fill, so the
   animation's held end-state outranked `:hover` in the cascade and the lift
   never rendered; it now fills `backwards` off a visible base state, which
   leaves transform free once the animation ends. And the idle "breathing"
   scaled the button itself, compounding the same problem — the pulse now
   lives on a halo pseudo-element and animates opacity alone. */
.hero__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  padding: 1.1rem 2.4rem;
  min-height: 56px;
  font-family: 'Lato', sans-serif;
  font-size: clamp(0.95rem, 1.1vw, 1.05rem);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1;
  color: var(--cream);
  background: var(--cta-green);
  border: 1px solid rgba(249, 248, 242, 0.22);
  border-radius: 999px;
  box-shadow: 0 6px 28px rgba(42, 42, 42, 0.22),
              0 2px 8px rgba(42, 42, 42, 0.1);
  transition: background 0.8s var(--ease-smooth),
              transform 0.8s var(--ease-smooth),
              box-shadow 0.8s var(--ease-smooth);

  /* Resting state is the visible one — see the note above. */
  opacity: 1;
  transform: translate3d(0, 0, 0);
  animation: ctaRise 0.8s var(--ease-smooth) 1.8s backwards;
}

@keyframes ctaRise {
  from {
    opacity: 0;
    transform: translate3d(0, 15px, 0);
  }

  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

/* Idle halo — a slow breath of light around the pill so the eye finds it on a
   busy photograph without the button ever moving. Opacity only. */
.hero__cta::before {
  content: '';
  position: absolute;
  inset: -6px;
  border: 1px solid rgba(249, 248, 242, 0.45);
  border-radius: 999px;
  opacity: 0;
  pointer-events: none;
  animation: ctaHalo 4.5s var(--ease-smooth) 3s infinite;
}

@keyframes ctaHalo {

  0%,
  100% {
    opacity: 0;
  }

  50% {
    opacity: 0.55;
  }
}

.hero__cta-arrow {
  display: inline-block;
  font-size: 1.05em;
  line-height: 1;
  transition: transform 0.8s var(--ease-smooth);
}

.hero__cta:hover {
  background: var(--cta-green-dark);
  transform: translate3d(0, -2px, 0);
  box-shadow: 0 12px 36px rgba(42, 42, 42, 0.3),
              0 2px 10px rgba(42, 42, 42, 0.14);
}

.hero__cta:hover .hero__cta-arrow {
  transform: translate3d(4px, 0, 0);
}

.hero__cta:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 4px;
}

@keyframes textCascade {
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}


/* ═══════════════════════════════════════════
   SECTION 3 — STARTING POINT (Editorial Cards)
   ═══════════════════════════════════════════ */
.starting {
  position: relative;
  z-index: 1;
  padding: var(--rhythm-unit) var(--gutter);
  background: var(--cream);
}

/* Starting Point header — scroll-reveal entrance + layout */
.starting__header {
  text-align: center;
  margin-bottom: clamp(3rem, 6vw, 5rem);
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
  /* Scroll-reveal entrance */
  opacity: 0;
  transform: translateY(25px);
  transition: opacity 1s var(--ease-smooth), transform 1s var(--ease-smooth);
}

.starting__header.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.starting__title {
  font-size: var(--fs-h2);
  /* Dark rust / warm brown — editorial, grounding */
  color: var(--dark-rust);
  line-height: 1.15;
}

/* Mobile: horizontal snap scroll */
.starting__grid {
  display: flex;
  gap: var(--gutter);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 1rem;
  scrollbar-width: none;
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}

.starting__grid::-webkit-scrollbar {
  display: none;
}

/* --- Card Container --- */
.starting__card {
  flex: 0 0 80%;
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  position: relative;
  text-decoration: none;
  border-radius: 1rem;
  /* 16px standard card radius */
  overflow: hidden;
  background: #fff;
  box-shadow: 0 0 0 rgba(0, 0, 0, 0);
  transition: box-shadow 1.5s var(--ease-smooth),
    opacity 0.8s var(--ease-smooth),
    transform 0.8s var(--ease-smooth);

  /* Scroll entrance — staggered via JS transition-delay */
  opacity: 0;
  transform: translateY(30px);
}

.starting__card.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Warm diffused shadow bloom on hover — no heavy drop shadows */
.starting__card:hover {
  box-shadow: 0 8px 32px rgba(92, 64, 51, 0.06);
}

/* --- Image Area (Top 55%) --- */
.starting__card-img-wrap {
  position: relative;
  width: 100%;
  /* Full 4:5 portrait — no cropping of subject */
  aspect-ratio: 4 / 5;
  overflow: hidden;
  /* Soft corners matching earlier layout, overwriting parent if needed */
  border-radius: 16px 16px 0 0;
}

.starting__card-img-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  /* The "Exhale" — slow 3% scale over 1.5 seconds */
  transition: transform 0.8s var(--ease-smooth), filter 0.8s var(--ease-smooth);
  will-change: transform, filter;
  filter: saturate(1) brightness(1);
}

.hero__aura {
  position: absolute;
  top: 0;
  left: 0;
  width: 50vw;
  height: 50vw;
  background: radial-gradient(circle, rgba(230, 140, 90, 0.25) 0%, rgba(200, 90, 50, 0) 70%);
  border-radius: 50%;
  pointer-events: none;
  filter: blur(80px);
  z-index: 1;
  opacity: 0;
  mix-blend-mode: soft-light;
  will-change: transform, opacity;
}

/* Card 2 (Menstrual Days) — pull focal point down to show both hands */
.starting__card:nth-child(2) .starting__card-img-wrap img {
  object-position: center 35%;
}

.starting__card:hover .starting__card-img-wrap img {
  transform: scale(1.03);
  filter: saturate(1.1) brightness(1.03);
}

/* --- Text Area (Bottom 45%) --- */
.starting__card-body {
  padding: 1.5rem 1.5rem 2rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: 0.5rem;
  flex: 1;
}

/* Eyebrow — tiny sage-green caps */
.starting__card-eyebrow {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-tag);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--sage-deep, #5A6457);
}

/* Title — elegant serif */
.starting__card-title {
  font-family: 'Playfair Display', serif;
  font-size: var(--fs-h3);
  font-weight: 600;
  color: var(--charcoal);
  line-height: 1.25;
  margin-top: 0.2rem;
  margin-bottom: 0.2rem;
}

/* Body text — clean sans-serif, muted */
.starting__card-text {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-small);
  font-weight: 400;
  color: rgba(44, 44, 44, 0.85);
  line-height: 1.6;
  margin: 0;
}

/* Text-link CTA */
.starting__card-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--sage-deep, #5A6457);
  margin-top: auto;
  padding-top: 1rem;
  transition: color 0.8s var(--ease-smooth);
}

/* Dark Rust text fade on hover — somatic warmth */
.starting__card:hover .starting__card-link {
  color: var(--dark-rust);
}

.starting__card-arrow {
  display: inline-block;
  transition: transform 0.4s var(--ease-smooth);
}

.starting__card:hover .starting__card-arrow {
  transform: translateX(4px);
}

/* Mobile: stack cards vertically */
@media (max-width: 768px) {
  .starting__grid {
    flex-direction: column;
    overflow-x: visible;
    scroll-snap-type: none;
    gap: 2rem;
    padding: 0 1.5rem;
  }

  .starting__card {
    flex: none;
    width: 100%;
  }
}

/* Tablet portrait: two columns rather than the phone stack.
   Between 600px and 768px the cards were stacking full-width, which is the
   single biggest reason this page ran ~2x longer at 768 (14,326px) than at
   1024 (7,229px) — there is comfortably room for two cards at 736px of
   content width. Phones keep stacking; 769-1023 keeps the scroll-snap rail. */
@media (min-width: 600px) and (max-width: 768px) {
  .starting__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 2rem;
    overflow: visible;
    scroll-snap-type: none;
  }

  .starting__card {
    flex: none;
    width: auto;
  }
}

/* Desktop: 3-column grid with massive breathing room */
@media (min-width: 1024px) {
  .starting__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* 4rem ≈ 3–4 inches of visual gap at typical screen sizes */
    gap: 4rem;
    overflow: visible;
    padding-bottom: 0;
  }

  .starting__card {
    flex: none;
  }
}


/* --- Curtain Preloader --- */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: var(--cream);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.8s var(--ease-smooth);
}

.curtain.is-raised {
  transform: translate3d(0, -100%, 0);
  pointer-events: none;
}

.curtain__logo-wrap {
  width: 80px;
  opacity: 0;
  transform: scale(0.9);
  animation: logoPulse 2s ease-out forwards;
}

.curtain__logo {
  width: 100%;
  height: auto;
}

@keyframes logoPulse {
  0% {
    opacity: 0;
    transform: scale(0.9);
  }

  40% {
    opacity: 1;
    transform: scale(1);
  }

  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* ═══════════════════════════════════════════
   SECTION 4 — METHODOLOGY (Sticky Split-Screen)
   ═══════════════════════════════════════════ */
.methodology {
  position: relative;
  z-index: 1;
  background: var(--sage-deep);
  /* 1.25x the section unit — the page's biggest statement block. */
  padding: calc(var(--rhythm-unit) * 1.25) clamp(1.5rem, 4vw, 4rem);
  overflow: hidden;
}


.methodology__inner {
  display: flex;
  flex-direction: column;
  gap: clamp(3rem, 5vw, 4rem);
  max-width: 1200px;
  margin: 0 auto;
  align-items: center;
}

/* --- Left: Arch Image with Depth --- */
.methodology__media {
  position: relative;
  width: 100%;
  max-width: 440px;
}

.methodology__img-wrap {
  position: relative;
  width: 100%;
  border-radius: 220px 220px 16px 16px;
  overflow: hidden;
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.25),
    0 12px 32px rgba(0, 0, 0, 0.15),
    0 0 0 1px rgba(255, 255, 255, 0.08);
}

.methodology__img-wrap img {
  width: 100%;
  height: auto;
  display: block;
  object-fit: cover;
  aspect-ratio: 3 / 4;
}

/* Play button overlay */
.methodology__play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--charcoal);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  transition: transform 0.6s var(--ease-smooth), box-shadow 0.6s var(--ease-smooth);
  z-index: 2;
}

.methodology__play svg {
  margin-left: 3px;
}

.methodology__play:hover {
  transform: translate(-50%, -50%) scale(1.1);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
}

/* Holistic badge — bottom-left */
.methodology__badge {
  position: absolute;
  bottom: 1.5rem;
  left: -0.5rem;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: var(--glass-blur-md);
  -webkit-backdrop-filter: var(--glass-blur-md);
  border-radius: 12px;
  padding: 0.75rem 1.2rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  z-index: 2;
  max-width: 200px;
}

.methodology__badge-title {
  display: block;
  font-family: 'Lato', sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--charcoal);
  margin-bottom: 0.25rem;
}

.methodology__badge-desc {
  display: block;
  font-family: 'Lato', sans-serif;
  font-size: 0.75rem;
  font-weight: 400;
  color: rgba(42, 42, 42, 0.7);
  line-height: 1.4;
}

/* --- Right: Text Content --- */
.methodology__text {
  width: 100%;
  text-align: center;
}

.methodology__eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.methodology__eyebrow-line {
  display: block;
  width: 40px;
  height: 1px;
  background: rgba(255, 255, 255, 0.35);
}

.methodology__eyebrow-label {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-tag);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}

.methodology__title {
  font-family: 'Playfair Display', serif;
  font-size: clamp(2rem, 4vw + 0.5rem, 3.2rem);
  color: #fff;
  line-height: 1.15;
  margin-bottom: 1.5rem;
  font-weight: 500;
}

.methodology__title em {
  font-style: italic;
}

.methodology__body {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-body);
  font-weight: 300;
  color: rgba(255, 255, 255, 0.85);
  line-height: 1.7;
  max-width: 50ch;
  margin: 0 auto 3rem;
}

/* --- Three Icon Pillars --- */
/* The three methodology pillars stay on ONE row at every width — never 2+1.
   `nowrap` plus `min-width: 0` on the items lets them shrink past min-content
   so the labels wrap inside their own column instead of pushing a pillar onto
   a second row. Measured at 375px: three 98px columns, no overflow. */
.methodology__pillars {
  display: flex;
  justify-content: center;
  /* Max gap is 2.5rem, not the 4rem it was: the three labels need 543px of
     natural width and the column is 635px at 1280, so a 4rem gap left them
     10px short and forced every label onto two lines. Buying that back from
     the gap keeps them on one line each on wide screens. */
  gap: clamp(1rem, 3vw, 2.5rem);
  flex-wrap: nowrap;
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
}

.methodology__pillar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
  text-align: center;
}

.methodology__pillar-icon {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.9);
}

.methodology__pillar-label {
  font-family: 'Lato', sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.9);
}

/* --- Desktop: Side-by-side --- */
@media (min-width: 1024px) {
  .methodology {
    /* horizontal only — vertical rhythm stays on the shared ratio */
    padding-left: clamp(2rem, 5vw, 5rem);
    padding-right: clamp(2rem, 5vw, 5rem);
  }

  .methodology__inner {
    flex-direction: row;
    align-items: center;
    gap: clamp(4rem, 6vw, 6rem);
  }

  .methodology__media {
    width: 42%;
    flex-shrink: 0;
  }

  .methodology__text {
    width: 58%;
    text-align: left;
  }

  .methodology__eyebrow {
    justify-content: flex-start;
  }

  .methodology__body {
    margin-left: 0;
    margin-right: 0;
  }

  .methodology__pillars {
    justify-content: flex-start;
  }
}

/* A previous revision dropped these to a 2+1 grid on phones, because three
   ~90px columns made "INTENTION-MAPPED PROTOCOLS" break awkwardly. One row is
   now required at every width instead, so the space is recovered from tracking
   rather than from the layout: 0.15em → 0.06em is worth roughly 20px per
   label at this size. The 12px type floor set in 728468b is deliberately
   preserved — the fix is horizontal, not smaller text. */
@media (max-width: 600px) {
  .methodology__pillar-label {
    letter-spacing: 0.06em;
    hyphens: auto;
  }
}


/* ═══════════════════════════════════════════
   SECTION 5 — SOCIAL PROOF (Scroll-driven Waterfall)
   ═══════════════════════════════════════════ */

/* Outer section — must NOT have overflow:hidden/auto/scroll (breaks child sticky) */
.proof {
  position: relative;
  z-index: 1;
  background: var(--stone);
  /* Section height is set by the JS-generated .proof__scroll-height spacer div */
}

/* Spacer div — JS sets its height to create scroll distance for the waterfall */
.proof__scroll-height {
  position: relative;
  pointer-events: none;
}

/*
  Sticky viewport frame — pins to screen while parent scrolls.
  overflow:hidden on the sticky element itself is FINE (only ancestor overflow breaks sticky).
  This clips the columns as they translate upward through the frame.
*/
.proof__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--gutter);
  max-width: 1100px;
  margin: 0 auto;
}

.proof__header {
  text-align: center;
  padding: clamp(3rem, 6vw, 5rem) var(--gutter) 2rem;
}

.proof__tag {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-tag);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--stone-muted);
}

.proof__title {
  font-size: var(--fs-h2);
  color: var(--charcoal-deep);
  margin-top: 0.4rem;
  line-height: 1.12;
}

.proof__title em {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 400;
  color: var(--charcoal-muted);
  display: block;
  margin-top: 0.15em;
}

.proof__masonry {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  flex: 1;
  min-height: 0;
}

.proof__col {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  will-change: transform;
}

.proof__card {
  border-radius: 16px;
  overflow: hidden;
}

.proof__card--text {
  background: #fff;
  padding: 2rem;
}

.proof__card--text blockquote {
  font-family: 'Playfair Display', serif;
  font-size: var(--fs-body);
  font-weight: 400;
  font-style: italic;
  color: var(--charcoal);
  line-height: 1.6;
  margin: 0;
  margin-bottom: 0.8em;
}

.proof__card--text cite {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-small);
  font-style: normal;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sage-deep, #5A6457);
}

/* The surrounding quote recedes; the reviewer's one standout line stays sharp.
   filter:blur() on an inline span rasterizes only that span's own content, so
   the sharp <mark> sitting between two blurred spans is unaffected — no
   "unblur the child" trick needed. The soft bleed at each span's edge reads
   as an intentional gradient into clarity rather than a seam. */
.proof__blur {
  transition: filter 0.8s var(--ease-smooth), opacity 0.8s var(--ease-smooth);
}

.proof__highlight {
  background: none;
  color: var(--dark-rust);
  font-weight: 500;
  font-style: normal;
}

/* Blur ONLY where there is a pointer to lift it with.
   Touch devices have no hover, so a permanently softened quote is simply an
   unreadable quote — and ~80% of this site's visitors are on touch. There the
   full testimonial renders sharp and the highlight carries the emphasis on its
   colour alone, which is the same editorial intent without the legibility
   cost. Mouse users get the recede-then-reveal treatment. */
@media (hover: hover) {
  .proof__blur {
    filter: blur(1.6px);
    opacity: 0.6;
  }

  .proof__card--text:hover .proof__blur,
  .proof__card--text:focus-within .proof__blur {
    filter: blur(0);
    opacity: 1;
  }
}

/* ── Touch: the same reveal, driven by scroll position instead of a cursor ──
   Core directives §3: "Map desktop hover micro-animations to IntersectionObserver
   on mobile — trigger when centered in viewport." A card sits softened until it
   reaches the middle of the screen, then resolves — the reader's attention and
   the focus arrive together, with nothing to tap.

   Gated on .proof--focus-reveal, which main.js adds only after the observer is
   actually wired. If the script never runs, the class never lands and every
   quote stays sharp — the failure mode is plain text, never unreadable text. */
@media (hover: none) {
  .proof--focus-reveal .proof__blur {
    filter: blur(1.6px);
    opacity: 0.6;
  }

  .proof--focus-reveal .proof__card--text.is-centred .proof__blur {
    filter: blur(0);
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .proof__blur {
    transition: none;
  }
}

/* Blur is a legibility cost, not just a style choice — waive it under
   prefers-contrast rather than asking low-vision visitors to hover to read.
   Also covers the touch path above, since that blur is a filter too. */
@media (prefers-contrast: more) {
  .proof__blur,
  .proof--focus-reveal .proof__blur {
    filter: none;
    opacity: 1;
  }
}

.proof__card--image {
  aspect-ratio: 4 / 5;
}

.proof__card--image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 16px;
}

/* ── Desktop: 3-column ── */
@media (min-width: 1024px) {
  .proof__masonry {
    flex-direction: row;
    align-items: flex-start;
    gap: 1.5rem;
  }

  .proof__col {
    flex: 1;
    gap: 1.5rem;
  }
}

/* ── Mobile: plain document flow, every testimonial reachable ──
   The pinned waterfall is a desktop device: it runs three columns through a
   100dvh window, translating each by its own height on scroll. That mechanic
   has no sensible one-column form, and the previous workaround — hiding
   columns 1 and 2 — meant phone visitors saw a third of the social proof and
   never knew the rest existed. Since ~80% of traffic is phones, the majority
   platform gets the honest version: unpin the frame, stack all three columns
   in normal flow, and let the page scroll itself. main.js skips the transform
   below this width so nothing fights the layout. */
@media (max-width: 1023px) {
  .proof__sticky {
    position: static;
    height: auto;
    overflow: visible;
    padding-bottom: clamp(3rem, 8vw, 5rem);
  }

  .proof__masonry {
    flex: none;
    min-height: 0;
  }

  .proof__col {
    transform: none !important;   /* belt-and-braces against a stale inline transform */
  }

  .proof__scroll-height {
    display: none;                /* scroll distance now comes from the content itself */
  }
}


/* ═════════════════════════════════════════════
   SECTION 6 — CINEMATIC CARE CARD
   ═════════════════════════════════════════════ */
.care {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 85svh;
  min-height: 550px;
  overflow: hidden;
  background: var(--charcoal);
}

/* --- Stage: Full-bleed background image --- */
.care__bg {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.care__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* Breathing hover: slow zoom on card hover */
  transition: transform 1.5s var(--ease-smooth);
}

/* Directional gradient for card readability - darken right side where card is */
.care__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to left, rgba(42, 42, 42, 0.7), rgba(42, 42, 42, 0.1));
  pointer-events: none;
}

/* --- Floating Glass Card --- */
.care__card {
  /* Mobile: bottom-center */
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: 5%;
  transform: translateX(-50%);
  width: 90%;
  max-width: 400px;
  padding: 2rem;

  /* Material Physics */
  background: var(--glass);
  backdrop-filter: var(--glass-blur-md);
  -webkit-backdrop-filter: var(--glass-blur-md);
  border: 1px solid var(--glass-border-color);
  border-radius: 16px;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);

  /* Breathing hover */
  transition: transform 0.6s var(--ease-smooth), box-shadow 0.6s var(--ease-smooth);
}

/* Breathing effect: card scales + bg zooms */
.care__card:hover {
  transform: translateX(-50%) scale(1.02);
  box-shadow: 0 24px 50px rgba(0, 0, 0, 0.2);
}

.care__card:hover~.care__bg .care__img,
.care:has(.care__card:hover) .care__img {
  transform: scale(1.05);
}

/* --- Typography --- */
.care__eyebrow {
  display: block;
  font-family: 'Lato', sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sage-green);
  margin-bottom: 1rem;
}

.care__title {
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  color: var(--cream);
  margin-bottom: 1.5rem;
  line-height: 1.15;
}

.care__body {
  font-family: 'Lato', sans-serif;
  font-size: 1rem;
  color: rgba(253, 252, 248, 0.85);
  line-height: 1.7;
  margin-bottom: 0;
}

.care__body--signature {
  margin-top: 1.2rem;
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 1.05rem;
  color: rgba(253, 252, 248, 0.95);
}

.care__link {
  color: var(--cream);
  font-weight: 700;
  text-decoration: underline;
  text-decoration-color: var(--sage-green);
  text-underline-offset: 3px;
  transition: color 0.3s var(--ease-smooth);
}

.care__link:hover {
  color: var(--sage-green);
}

.care__footnote {
  display: block;
  margin-top: 2rem;
  font-family: 'Lato', sans-serif;
  font-size: 0.75rem;
  font-style: italic;
  color: rgba(253, 252, 248, 0.55);
}

/* Desktop: Card floats center-right */
@media (min-width: 1024px) {
  .care__card {
    /* Override mobile positioning */
    left: auto;
    bottom: auto;
    transform: translateY(-50%);
    right: 15%;
    top: 50%;
    width: 400px;
    padding: 3rem;
  }

  .care__card:hover {
    transform: translateY(-50%) scale(1.02);
  }
}


/* ═════════════════════════════════════════════
   SECTION 7 — FOOTER
   ═════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════
   SECTION — THE PRACTICE LIBRARY (Waitlist)
   ═══════════════════════════════════════════════ */
/* Theme matched to .moc-lib (menu-of-care.css:880) — the "If this isn't your
   door" section on the protocol pages. Same blurred photographic field, same
   warm veil, same cream glass panel. The two sections make the same offer, so
   they should read as the same place. Raise --practice-library-veil before touching
   anything else if the photograph starts competing for attention. */
.practice-library {
  --practice-library-veil: 0.62;
  position: relative;
  z-index: 1;
  isolation: isolate;
  /* 0.75x the section unit — a quieter closing invitation. */
  padding: calc(var(--rhythm-unit) * 0.75) var(--gutter);
  background: var(--cream);
  border-top: 1px solid rgba(44, 44, 44, 0.08);
  text-align: left;
  overflow: hidden;
}

/* Mobile-first: portrait crop. Inset bleed + scale keeps the blur from
   showing a soft edge where the image ends. */
.practice-library::before {
  content: '';
  position: absolute;
  inset: -60px;
  z-index: -2;
  background-image: url('PageWiseAssets_rs/LibrarySectionBackground-portrait.jpg');
  background-size: cover;
  background-position: center;
  filter: blur(16px) saturate(0.9) brightness(1.28);
  transform: scale(1.05);
}

/* Warm veil, not a flat one. A single cream wash over this photograph lands
   cool grey — the source is dark and blue-toned, and cool grey is the one
   neutral the palette rules out. The gradient carries a warm sand mid-stop
   so the field stays on the cream/taupe axis. (menu-of-care.css:904) */
.practice-library::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    160deg,
    rgba(249, 248, 242, calc(var(--practice-library-veil) + 0.14)) 0%,
    rgba(238, 229, 213, calc(var(--practice-library-veil) - 0.04)) 52%,
    rgba(249, 248, 242, calc(var(--practice-library-veil) + 0.10)) 100%
  );
}

@media (min-width: 768px) {
  .practice-library::before {
    background-image: url('PageWiseAssets_rs/LibrarySectionBackground-wide.jpg');
  }
}

/* The glass panel — o-p-e-n.com spec from SKILL_01 section 4. */
.practice-library__inner {
  position: relative;
  z-index: 2;
  max-width: 640px;
  margin: 0 auto;
  padding: clamp(1.75rem, 5vw, 3.25rem);
  background: rgba(249, 248, 242, 0.72);
  backdrop-filter: var(--glass-blur-lg) saturate(1.1);
  -webkit-backdrop-filter: var(--glass-blur-lg) saturate(1.1);
  border: 1px solid rgba(44, 44, 44, 0.10);
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(44, 44, 44, 0.10);
  opacity: 0;
  /* Opacity-only arrival. The old rule translated 30px, and translating an
     element that owns a backdrop-filter re-rasterises the blur every frame
     — visibly cheap on a mid-range phone. (menu-of-care.css:940) */
  transition: opacity 1s var(--ease-smooth);
}

.practice-library__inner.is-visible {
  opacity: 1;
}

.practice-library__eyebrow {
  display: block;
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-tag);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--charcoal);
  opacity: 0.7;
  /* Reduced margin */
  margin-bottom: 0.75rem;
}

.practice-library__title {
  font-family: 'Playfair Display', serif;
  font-size: clamp(2.2rem, 4vw + 1rem, 3.5rem);
  font-weight: 400;
  color: var(--charcoal);
  /* Reduced margin */
  margin-bottom: 0.5rem;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.practice-library__body {
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-body);
  font-weight: 300;
  color: var(--charcoal);
  /* 1.6 is the mandated body line-height (core directives section 3); this
     rule predated that and read looser than the .moc-lib block it now matches. */
  line-height: 1.6;
  max-width: 46ch;
  margin: 0 0 1.5rem;
  opacity: 0.85;
}




/* Library CTA replaced the practice-library form — same pill, rendered as a link */
.practice-library__action {
  display: flex;
  justify-content: flex-start;
  margin-top: 2.25rem;
}

/* The action row is a flex container with the default justify-content, so a
   single child sits hard left. Measured on a 375px iPhone: button 45→244
   inside a 45→330 row. Centred below the two-column threshold, where the row
   only ever holds this one button. */
@media (max-width: 1023px) {
  .practice-library__action {
    justify-content: center;
  }
}



@media (max-width: 500px) {

}


/* ═════════════════════════════════════════════
   FOOTER — THE ONLY DEFINITION. Do not copy this block.
   ═════════════════════════════════════════════
   The footer markup is copy-pasted into all 11 pages, so its CSS is the one
   thing holding them together. Every per-page stylesheet loads AFTER this
   file at equal specificity, which means any `.footer` / `.footer__*` rule
   in about.css, faq.css, library.css, offerings.css, privacy-policy.css,
   nsr-protocol.css, soft-cycle.css, menu-of-care.css or
   foundation-session.css silently wins — and drifts the moment this file
   changes. faq.css and privacy-policy.css both did exactly that and shipped
   a broken 3-column grid for a 4-column footer; both were deleted 2026-08-07.

   The rule, in one line: a per-page stylesheet may never contain a BARE
   .footer / .footer__* selector. Two sanctioned ways to vary the footer:

   1. Override a TOKEN (preferred — no selector at all):
        --footer-rule        mobile column hairline
        --footer-legal-ink   legal-link colour on dark backgrounds
      If a page needs something these can't express, add a new token HERE.

   2. Page-scoped, COLOUR-ONLY overrides, e.g. `.nsr-page .footer__heading`.
      nsr-protocol.css does this for the one footer rendered on charcoal.
      Scoped means it can't leak; colour-only means it can't drift the layout
      out from under this file. Never put grid, sizing, spacing or display
      properties in a page-scoped override — put them here.

   Grep before you ship:
     grep -n '\.footer' *.css | grep -v '^style.css:'
   As of 2026-08-07 that returns nothing but comments and nsr-protocol.css's
   seven .nsr-page colour rules. Anything else is the bug described above. */
.footer {
  /* max-width folded in from a second, stray `.footer` rule that sat ~1600
     lines above this one — 2026-08-05. */
  max-width: 100%;
  position: relative;
  z-index: 2;
  background: var(--cream);
  /* Bottom tracks the top at half its value instead of sitting at a flat 2rem.
     Unchanged on phones/tablets (--rhythm-unit is 4rem there, so this still
     resolves to 2rem); at 1920 it grows 32px -> 64px, which stops the footer
     from having 4x more air above its content than below it. */
  padding: var(--rhythm-unit) var(--gutter) calc(var(--rhythm-unit) * 0.5);
  border-top: 1px solid var(--stone);
}

.footer__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  max-width: var(--container, 1200px);
  margin: 0 auto;
}

.footer__logo {
  height: 72px;
  width: auto;
  border-radius: 50%;
  object-fit: contain;
  margin-bottom: 1rem;
}

.footer__heading {
  display: block;
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  margin-bottom: 0.8em;
  color: var(--charcoal);
}

.footer__text {
  font-size: var(--fs-small);
  color: rgba(42, 42, 42, 0.7);
  max-width: 30ch;
  line-height: 1.6;
}

.footer__list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.footer__list a {
  font-size: var(--fs-small);
  color: rgba(42, 42, 42, 0.65);
  position: relative;
  display: inline-block;
  transition: color 0.3s var(--ease-smooth);
}

/* Slow-exhale underline on footer links */
.footer__list a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: var(--sage-green);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.5s var(--ease-smooth);
}

.footer__list a:hover {
  color: var(--sage-green);
}

.footer__list a:hover::after {
  transform: scaleX(1);
}

.footer__bottom {
  margin-inline: auto;
  /* Was var(--measure, 68ch), which resolves to ~505px at --fs-small and left
     the disclaimer below it 60-95px short of fitting on one line. --measure is
     a READABILITY cap for body prose; this strip is three centred micro-copy
     lines, so the constraint it was borrowing did not apply to it. Widening
     only lengthens the hairline rule above -- the copyright and legal links
     are short and stay centred. */
  max-width: 38rem;
  margin-top: clamp(2rem, 4vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--stone);
  text-align: center;
  font-size: var(--fs-small);
  color: rgba(42, 42, 42, 0.67);
  letter-spacing: 0.04em;
}

/* The sitewide medical disclaimer. Was an inline style repeated on all 11
   pages (complete with a stray double semicolon); it is required copy on every
   page, so it gets a real class. */
.footer__disclaimer {
  margin-top: 0.5rem;
  font-size: 0.75rem;

  /* One line wherever there is room for it. Measured across all 11 pages: the
     91-character string needs 508-550px depending on which sans that page
     loads (Geist 508, Outfit 518, DM Sans 543, Inter 550 on
     foundation-session). 36rem = 576px clears the widest with headroom for
     webfont-swap variance.

     max-width, not width, so it still wraps on narrow viewports -- at 390px
     the footer is ~350px and this becomes three lines, which is correct. */
  max-width: 36rem;
  margin-inline: auto;
}

/* Legal links. These used to sit in the Connect column, which is for
   channels (Instagram, email) — a policy document is not a channel. Small
   print under the disclaimer is the conventional home for them.
   Flex-wrap rather than inline text so the long Terms label breaks onto
   its own line cleanly on a phone instead of splitting mid-label. */
.footer__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0 0.75rem;
  margin-top: 0.5rem;
  /* 12px floor — see CLAUDE.md; do not shrink to match the disclaimer. */
  font-size: 0.75rem;
  /* offerings.css uppercases its whole footer-bottom block. Reset here so
     this line reads the same on all 11 pages rather than shouting on one. */
  text-transform: none;
  letter-spacing: 0.04em;
}

/* inline-flex + min-height keeps the tap target at 24px (WCAG 2.5.8 AA);
   12px text alone measures ~14px tall and fails.

   Ink comes from a variable, not a fixed value and not plain inherit.
   nsr-protocol.html renders this same footer on charcoal, so a hardcoded
   dark value disappears there; but inheriting .footer__bottom's colour
   drags in its 0.67 alpha, which lands at 3.9:1 on cream and fails AA at
   12px. The variable keeps one strong value per theme — the default below
   covers every cream footer, and .nsr-page overrides it in
   nsr-protocol.css for the dark one. */
.footer__legal a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  color: var(--footer-legal-ink, rgba(42, 42, 42, 0.92));
  border-bottom: 1px solid transparent;
  transition: border-color 0.8s var(--ease-smooth);
}

/* currentColor underline rather than a fixed accent, so hover adapts too. */
.footer__legal a:hover {
  border-bottom-color: currentColor;
}

/* Decorative only (aria-hidden) — safe to sit below text contrast. */
.footer__legal-sep {
  opacity: 0.45;
}

@media (min-width: 1024px) {
  /* Four columns since 2026-08-05: brand | Pathways | contextual | Connect.
     Below 1024px they become stacked heading/links rows (see the block near
     the end of this file), so adding a column costs one more row on a phone
     rather than squeezing the grid — which is the failure mode CLAUDE.md
     warns about for `repeat(N, 1fr)`.

     Written as ONE explicit track plus implicit auto-columns rather than a
     fixed `2fr 1fr 1fr 1fr`, so the count in the CSS can never disagree with
     the count in the markup. A hardcoded track list is exactly how faq.css
     and privacy-policy.css broke: they pinned three columns while all 11
     pages shipped four, and the fourth silently wrapped onto a second row.
     Here the brand block takes the 2fr track and every remaining .footer__col
     — however many there are — gets an equal implicit column. Add or remove a
     rung and the grid follows; nothing falls off.

     minmax(0, …) on both, not bare fr: `1fr` floors at min-content, which is
     the off-screen-column hazard in CLAUDE.md. */
  .footer__inner {
    grid-template-columns: minmax(0, 2fr);
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
  }
}


/* ═════════════════════════════════════════════
   BENEDICTION — Fixed behind all page content
   ═════════════════════════════════════════════ */

/* ── Page content wrapper — sits ON TOP of the fixed benediction ── */
.page-content {
  position: relative;
  z-index: 1;
  background: var(--cream);
}

/* Transparent spacer: height set by benediction.js to match the section */
.benediction-spacer {
  height: var(--benediction-h, 400px);
  pointer-events: none;
}

/* ─── MAGNETIC GATHER ─────────────────────────────────────────────────────
   benediction.js writes two numbers per line: --bu (opacity, arrives early)
   and --bm (the magnetic curve, 0 = dispersed, 1 = home). The per-line
   dispersion signature (--bx/--by/--br/--bl) is set once at init.

   Every default is the SETTLED state, so with no JavaScript — file missing,
   script error, reduced motion, a crawler — the shloka renders exactly as it
   does today, fully assembled. A blessing must never fail to arrive.

   No `will-change`: these are six small text blocks, and pinning layers for
   the whole page life to serve one moment at the very bottom is the trade
   this codebase has made too often already. */
.benediction__verse,
.benediction__transliteration,
.benediction__meaning {
  opacity: var(--bu, 1);
  transform:
    translate3d(
      calc(var(--bx, 0px) * (1 - var(--bm, 1))),
      calc(var(--by, 0px) * (1 - var(--bm, 1))),
      0
    )
    rotate(calc(var(--br, 0deg) * (1 - var(--bm, 1))));
  /* Layout property, animated deliberately — see the header of
     benediction.js. Guarded per line by a runtime wrap probe, and 0em for
     every line the probe rejects. */
  letter-spacing: calc(var(--bl, 0em) * (1 - var(--bm, 1)));
}

@media (prefers-reduced-motion: reduce) {
  .benediction__verse,
  .benediction__transliteration,
  .benediction__meaning {
    opacity: 1;
    transform: none;
    letter-spacing: normal;
  }
}

/* While the scroll is locked (a modal or the mobile menu is open) this is the
   ONLY element on the site with a negative z-index, and it is hidden purely
   because .page-content paints over it.

   scroll.js locks by setting `position: fixed` on <body>, and position:fixed
   always creates a stacking context — so opening or closing a modal creates
   and then destroys a stacking context on the element that parents the whole
   page. The compositor has to rebuild the layer tree at that moment. Chrome
   does it synchronously (measured: zero exposure across every frame of a full
   lock/unlock cycle, exact scroll restore) which is why Android is clean.
   WebKit does not, and iOS shows this layer for a single frame — the flash of
   Devanagari reported from an iPhone 17 Pro, caught on a 120fps recording.

   Hiding it while locked is a visual no-op: it is completely covered at that
   moment anyway. It just means there is no layer left to flash. */
body.is-scroll-locked .benediction {
  visibility: hidden;
}

/* Fixed behind everything — revealed as page-content scrolls away */
.benediction {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: -1;
  background: var(--charcoal, #2C2C2C);
  color: var(--cream, #F9F8F2);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(4rem, 8vw, 6rem) var(--gutter, 2rem);
  min-height: 50svh;
}

.benediction__inner {
  max-width: 900px;
  width: 100%;
  text-align: center;
}

/* Sanskrit verses in Devanagari — ALL bold */
.benediction__sanskrit {
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.benediction__verse {
  font-family: var(--font-indic);
  font-size: clamp(1.15rem, 2.2vw, 1.6rem);
  font-weight: 700;
  color: var(--cream);
  line-height: 1.8;
  margin: 0;
}

/* Two-column layout: transliteration (left) + meaning (right) */
.benediction__translations {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  text-align: center;
}

.benediction__transliteration {
  font-family: 'Playfair Display', serif;
  font-size: clamp(0.8rem, 1.1vw, 0.95rem);
  font-style: italic;
  color: rgba(249, 248, 242, 0.65);
  line-height: 1.7;
  margin: 0;
}

.benediction__meaning {
  margin-inline: auto;
  max-width: var(--measure, 68ch);
  font-family: 'Lato', sans-serif;
  font-size: clamp(0.8rem, 1.1vw, 0.95rem);
  color: rgba(249, 248, 242, 0.65);
  line-height: 1.7;
  margin: 0;
}

.benediction__meaning--closing {
  margin-top: 1rem;
  font-style: italic;
  color: var(--sage-green);
}

@media (min-width: 768px) {
  .benediction__translations {
    grid-template-columns: 1fr 1fr;
    gap: clamp(2rem, 4vw, 4rem);
    text-align: left;
  }

  .benediction__col:last-child {
    text-align: right;
  }
}


/* ═══════════════════════════════════════════════
   SOMATIC REVEAL — Universal entrance animation
   ═══════════════════════════════════════════════ */

/* Soft Arch mask utility — semicircle top, flat bottom (cathedral window) */
.soft-arch {
  border-radius: 50% 50% 16px 16px / 35% 35% 0 0;
  overflow: hidden;
}

/* Elements with data-somatic-reveal start hidden, 15px below */
[data-somatic-reveal] {
  opacity: 0;
  transform: translate3d(0, 15px, 0);
  transition: opacity 0.8s var(--ease-smooth), transform 0.8s var(--ease-smooth);
}

/* Stagger support via data-somatic-delay */
[data-somatic-reveal][data-somatic-delay="1"] {
  transition-delay: 0.1s;
}

[data-somatic-reveal][data-somatic-delay="2"] {
  transition-delay: 0.2s;
}

[data-somatic-reveal][data-somatic-delay="3"] {
  transition-delay: 0.3s;
}

/* Revealed state — floats into place */
[data-somatic-reveal].is-revealed {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* ═══════════════════════════════════════════
   BRIDGE — Emotional transition between hero and content
   ═══════════════════════════════════════════ */
.bridge {
  position: relative;
  z-index: 1;
  background: var(--cream);
  text-align: center;
  /* 0.5x the section unit — a connective interlude, not a section. */
  padding: calc(var(--rhythm-unit) * 0.5) var(--gutter);
}

.bridge__text {
  font-family: 'Playfair Display', serif;
  font-size: clamp(1.1rem, 2vw + 0.3rem, 1.5rem);
  font-style: italic;
  font-weight: 400;
  color: rgba(42, 42, 42, 0.65);
  max-width: 42ch;
  margin: 0 auto;
  line-height: 1.6;
  letter-spacing: 0.01em;
}


/* ═══════════════════════════════════════════
   FOUNDER CALLOUT — Personal quote + portrait
   ═══════════════════════════════════════════ */
.founder-callout {
  background: var(--cream);
  padding: clamp(3rem, 6vw, 5rem) var(--gutter);
  border-top: 1px solid rgba(42, 42, 42, 0.06);
  border-bottom: 1px solid rgba(42, 42, 42, 0.06);
}

.founder-callout__inner {
  max-width: 900px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(2rem, 4vw, 3.5rem);
}

.founder-callout__portrait {
  width: clamp(80px, 12vw, 140px);
  height: clamp(80px, 12vw, 140px);
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow: 0 8px 30px rgba(42, 42, 42, 0.1);
}

.founder-callout__eyebrow {
  display: block;
  font-family: 'Lato', sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--sage-green);
  margin-bottom: 0.75rem;
}

.founder-callout__quote {
  font-family: 'Playfair Display', serif;
  font-size: clamp(1.05rem, 1.5vw + 0.3rem, 1.35rem);
  font-style: italic;
  font-weight: 400;
  color: var(--charcoal);
  line-height: 1.6;
  margin: 0 0 0.75rem 0;
}

.founder-callout__name {
  font-family: 'Lato', sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
  font-style: normal;
  letter-spacing: 0.1em;
  color: rgba(42, 42, 42, 0.5);
}

@media (max-width: 768px) {
  .founder-callout__inner {
    flex-direction: column;
    text-align: center;
  }
}


/* ═════════════════════════════════════════════
   REDUCED MOTION — authoritative, loaded by every page
   ═════════════════════════════════════════════
   Cut movement, keep arrival. The failure mode to avoid is content that
   never reveals because its reveal was animation-driven: an element stuck
   at opacity 0 is a worse bug than the motion was. So every reveal pattern
   used anywhere on the site is forced to its end state here. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0.001ms !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  [data-somatic-reveal], [data-moc-reveal], [data-reveal],
  .sr, .reveal, .somatic-reveal, .is-visible, .is-revealed,
  .faq-item, .faq-cta__glass, .policy__section, .offerings__card,
  .validation-bullet, .sc-reveal, .moc-lib__inner,
  /* Elements whose arrival is JS-driven (GSAP/ScrollTrigger). Listed
     explicitly so a reduced-motion visitor never depends on that JS
     running to see the content — verified by scrolling each page. */
  .anchor, .mirror__item, .philosophy__text, .philosophy__block,
  .architecture__intro, .timeline__phase, .pricing-card,
  .starting__header, .starting__card, .proof__title,
  .care__eyebrow, .care__title, .practice-library__inner, .practice-library__eyebrow, .practice-library__title,
  .lineage__content, .offerings-hero__body, .offerings-library__body,
  .sc-bento__card, .sc-acc, .sc-preview__micro, .sc-guide__quote,
  .sc-promise__item, .sc-faq__title {
    opacity: 1 !important;
    transform: none !important;
    visibility: visible !important;
    clip-path: none !important;
  }

  /* Final safety net. Some reveals are driven from JS on elements with no
     distinctive class (surya utility classes, a bare <p> on soft-cycle), so
     they cannot be enumerated. Scoped to readable text inside main: never
     leave a reduced-motion visitor with invisible copy. Decorative fades
     (.proof__blur, ghost numerals) are spans and stay untouched. */
  main :is(h1, h2, h3, h4, p, li, blockquote, cite) {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ═════════════════════════════════════════════
   FOCUS — visible keyboard affordance sitewide
   ═════════════════════════════════════════════ */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--sage-deep, #5A6457);
  outline-offset: 3px;
  border-radius: 4px;
}

/* On charcoal surfaces the deep sage disappears — use the on-dark sage. */
[data-nav-theme="dark"] a:focus-visible,
[data-nav-theme="dark"] button:focus-visible,
.benediction a:focus-visible,
.nav-pill a:focus-visible,
.nav-pill button:focus-visible,
.nav-mobile a:focus-visible {
  outline-color: var(--sage-green, #8A9A90);
}


/* ─── FOOTER — mobile distribution ─────────────────────────────────────────
   Everything stacked hard left and left two thirds of the width empty. Below
   the 3-column threshold each block now runs edge to edge — heading on one
   side, its links opposite — while the brand block and the legal strip stay
   centred, so the footer reads as composed rather than as a list that ran out
   of room. Desktop is untouched: the 1024px grid already fills its width. */
@media (max-width: 1023px) {
  .footer__inner {
    gap: 1.75rem;
  }

  /* Brand block (logo + name + tagline) — centred */
  .footer__col:first-child {
    text-align: center;
  }

  .footer__col:first-child .footer__logo {
    margin-inline: auto;
  }

  .footer__col:first-child .footer__text {
    margin-inline: auto;
    max-width: 30ch;
  }

  /* Link blocks — heading one side, links the other.
     These used to carry two extra selector variants: bare `<div>`s (library.html
     shipped its columns unclassed) and .offerings-footer__* (offerings.html had
     a parallel class tree). Both pages now use .footer__col like everywhere
     else, so the variants are gone — 2026-08-05. */
  .footer__col:not(:first-child) {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: start;
    column-gap: 1.5rem;
    padding-block: 0.75rem;
    /* Tokenised: nsr-protocol renders this same footer on charcoal, where a
       hardcoded charcoal hairline is invisible. The page overrides the token
       rather than the rule. */
    border-top: 1px solid var(--footer-rule, rgba(42, 42, 42, 0.14));
  }

  .footer__col:not(:first-child) .footer__heading {
    grid-column: 1;
    margin-bottom: 0;
  }

  .footer__col:not(:first-child) .footer__list {
    grid-column: 2;
    text-align: right;
    justify-self: end;
  }
}

/* The Instagram link is an inline <svg> followed by a bare text node. Once the
   list became right-aligned in a narrow column the two could break apart, so
   on some pages the icon sat on its own line above the word. inline-flex binds
   them into one unbreakable unit, and the row is reversed back to normal
   ordering so the icon always leads. */
.footer__list a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}

.footer__list a > svg {
  flex-shrink: 0;
  vertical-align: middle;
  margin-right: 0;
}

/* ─── "EXPLORE THE LIBRARY" — one gentle button, five pages ───────────────
   index · offerings · nsr-protocol · soft-cycle-landing · surya-namaskar.

   Was inconsistent per page: index and offerings rendered a solid terracotta
   pill, while nsr / soft-cycle / surya rendered a quiet underlined text link.
   Same destination, same offer, three different weights.

   OUTLINED, not filled, and that is deliberate. On the protocol pages this
   block is explicitly a downsell — its own markup comment says it "must stay
   visually quieter than everything above it" — and a filled pill would
   compete with the purchase CTA a few hundred pixels above. An outline reads
   unmistakably as a control while still yielding to it.

   NOTE — this rule was accidentally deleted on 2026-08-07 and restored the
   same day. It had been grouped with .waitlist__btn, and the sweep that
   removed the dead waitlist form CSS matched the whole selector list. The
   grouping is gone now: this rule stands alone so a future cleanup of some
   neighbouring class cannot take the site's shared button with it. */
.lib-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 52px;
  padding: 0.95rem 2rem;
  font-family: 'Lato', sans-serif;
  font-size: var(--fs-small, 0.9rem);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-decoration: none;
  white-space: nowrap;
  color: var(--dark-rust, #5C4033);

  /* OPAQUE fill, not transparent — this is what makes it read as a control.
     All five of these sections put the button on a blurred photograph under a
     warm veil whose alpha runs 0.58-0.76, so 24-42% of the photo shows
     through. A transparent button inherited whatever happened to be behind
     it, which is why it looked fine on some pages and dissolved on others.
     Filled, its interior is the same cream everywhere and the shape reads on
     its own before the border is even considered.

     Cream rather than terracotta on purpose. On the protocol pages this block
     is a downsell — its markup says it "must stay visually quieter than
     everything above it" — and a filled rust pill would compete with the
     purchase CTA a few hundred pixels up. A cream pill is unmistakably a
     button and still defers. */
  background: var(--cream, #F9F8F2);

  /* 0.65, raised from 0.42 on 2026-08-07. Measured: the old value gave the
     boundary 2.11:1 against cream, under the 3:1 that WCAG 1.4.11 asks of a
     UI component boundary, and 2.03:1 over the lightest part of the photo.
     0.65 gives 3.53:1 on cream — comfortably over, without going so dark that
     the button starts shouting. */
  border: 1.5px solid rgba(92, 64, 51, 0.65);
  border-radius: 999px;

  /* Warm-tinted, never grey: shadows on this site are rust at low alpha, so
     they read as depth in a warm room rather than as a drop shadow. Two
     layers — a tight one for the edge, a wide one for the lift. */
  box-shadow: 0 1px 2px rgba(92, 64, 51, 0.07),
              0 6px 16px rgba(92, 64, 51, 0.06);
  cursor: pointer;
  transition: background 0.8s var(--ease-smooth),
              border-color 0.8s var(--ease-smooth),
              box-shadow 0.8s var(--ease-smooth),
              transform 0.8s var(--ease-smooth);
}

/* Hover: warms rather than brightens. The fill picks up a little sand, the
   border goes to full rust (8.83:1), and the whole thing lifts 2px on the
   somatic curve. Opaque tint, not a translucent wash — a wash would let the
   photograph back in and undo the point of the fill. */
.lib-cta:hover {
  background: #F3EEE7;
  border-color: var(--dark-rust, #5C4033);
  box-shadow: 0 2px 4px rgba(92, 64, 51, 0.09),
              0 10px 24px rgba(92, 64, 51, 0.08);
  transform: translate3d(0, -2px, 0);
}

/* Press. Settles back to the resting plane and pulls the shadow in, so the
   button feels like it takes weight. Faster than the 0.8s entrance easing —
   a press should answer immediately even on a slow site. */
.lib-cta:active {
  transform: translate3d(0, 0, 0);
  box-shadow: 0 1px 2px rgba(92, 64, 51, 0.10);
  transition-duration: 0.12s;
}

.lib-cta:focus-visible {
  outline: 2px solid var(--dark-rust, #5C4033);
  outline-offset: 3px;
}

.lib-cta__arrow {
  flex-shrink: 0;
  transition: transform 0.8s var(--ease-smooth);
}

.lib-cta:hover .lib-cta__arrow {
  transform: translate3d(3px, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
  .lib-cta:hover,
  .lib-cta:hover .lib-cta__arrow { transform: none; }
}


/* ═══════════════════════════════════════════════════
   SHORT VIEWPORT — a phone held in landscape
   ═══════════════════════════════════════════════════
   THE canonical explanation. Page stylesheets carry their own small block for
   their own hero; they point here rather than repeat this.

   Keyed to HEIGHT, and deliberately not to width. A landscape phone is
   812-932px wide, so it clears every `min-width: 768px` breakpoint on this
   site and is already served the tablet layout — one built assuming ~1024px of
   height, on a device that has 375-430px. Giving landscape "more desktop" is
   the cause of the problem, not the cure.

   Two things were wrong before 2026-08-07:

   1. Every hero VSL is sized by WIDTH, with aspect-ratio: 16/9. Landscape has
      width to spare and no height, so a 16:9 box sized to the available width
      is taller than the screen once width passes ~667px. Measured on
      nsr-protocol at 812x375: the video rendered 731x411 inside a 375px
      viewport, with 9% of it on screen. Every hero on every common landscape
      phone was over by 20-67px. Capping width against svh lets HEIGHT drive
      the size; aspect-ratio then derives the width, so the ratio never breaks.

   2. min-height: 100svh, plus clamp() floors. A clamp FLOOR does not shrink:
      clamp(6rem, 14svh, 8rem) resolves to 96px at 375px tall, not 52px. So the
      vertical padding stayed desktop-sized on a screen a third the height.

   Scope note: `orientation: landscape` alone is not enough — an iPad in
   landscape is 1024x768 and wants none of this. The max-height is what makes
   it mean "phone". Portrait phones never match (they are 812px tall), and no
   laptop does either (720px tall clears it comfortably).

   Honest limit: this does not make the hero fit one landscape screen. The
   headline still pushes it past the fold. It makes the VIDEO fit, which is the
   thing someone rotates their phone for. A true single-screen landscape hero
   needs a side-by-side layout — a design change, not a media query. */
@media (max-height: 480px) and (orientation: landscape) {
  /* Homepage hero. ONLY the min-height floor comes off.
     `height: 100svh` stays, and `height: auto` is not an option here: this
     hero's children are absolutely positioned (.hero__bg and the content
     layer), so with auto there is nothing in flow to size against and the
     section collapses — measured at 40px, i.e. its padding and nothing else.
     Padding is left alone for the same reason: it does not place anything.
     The floor was the whole bug — 100svh resolves to 375px on a landscape
     phone, and min-height: 500px then forced 125px of overflow. */
  .hero {
    min-height: 0;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   CREDENTIALS STRIP — under every pricing section
   Moved here from menu-of-care.css 2026-08-27 so it can be used on
   library.html and foundation-session.html, which sell a product but do not
   load that stylesheet. Adding it to a new page is markup-only.
   ═══════════════════════════════════════════════════════════════════════════ */
/* 5B -- credentials, under the section title.
   Only the three claims the site already publishes. Nothing may be added
   here; RYT-500, Rishikesh and "trauma-informed" are specifically out. */
.moc-creds {
  margin: clamp(0.6rem, 1.2vw, 0.85rem) auto 0;
  max-width: 60rem;   /* one line at >=1024px; wraps gracefully below.
                         NOT ch -- ch resolves against this element's own
                         12px, which capped it at ~520px and forced two lines. */
  font-family: var(--f-sans, 'Lato', sans-serif);
  font-size: var(--fs-micro, 0.75rem);
  font-weight: 400;
  line-height: 1.7;
  letter-spacing: 0.11em;
  text-transform: uppercase;

  /* Dimmed with `color`, not `opacity`, and that is load-bearing rather than
     stylistic: opacity applies to the whole subtree and CANNOT be overridden
     by a child, so with `opacity: 0.62` here the figures below could never be
     brighter than the words around them however they were styled.

     It was also failing WCAG: 0.62 composited to rgb(122,122,119) on cream,
     which is 4.07:1 — under the 4.5:1 floor for 12px text. 0.72 reads 5.5:1,
     with margin for the next background change. */
  color: rgba(44, 44, 44, 0.72);
}

/* The three figures — YCB, 1,400+, 3,000+ — are the only proof this page
   carries while there are no testimonials, so they are set as numerals rather
   than as more small-caps label: the page's display serif, a step up in size,
   and full charcoal. The hierarchy is typeface and scale, not colour, which
   keeps a brand built on restraint from gaining a new hue for the sake of
   three numbers.

   YCB is treated as a figure too. Emphasising only the two numbers left the
   first of the three claims looking like an afterthought beside them.

   A literal clamp rather than a token: this is a single-use size, and the
   scale gained --fs-card-title only days ago. line-height: 1 keeps the taller
   glyphs from inflating the 20.4px line box the words sit in. */
.moc-creds__n {
  /* Two serifs across the five pages that show this strip: nsr-protocol,
     surya-namaskar and library serve Cormorant Garamond; soft-cycle and
     foundation-session serve Playfair Display. Neither serves both.

     So the stack names both, and each page resolves to the face it actually
     loads. --f-serif still wins where it is defined (nsr-protocol.css, surya
     inline). Georgia is the last resort and it was a live one: the original
     single-family stack silently fell back to it on the two Playfair pages.
     Invisible on a dev machine with Cormorant installed locally, which is why
     this needed document.fonts.check rather than getComputedStyle -- the
     latter only echoes the declared list, never what actually rendered. */
  font-family: var(--f-serif, 'Cormorant Garamond'), 'Playfair Display', Georgia, serif;
  font-size: clamp(1rem, 1.4vw, 1.15rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  color: var(--charcoal, #2C2C2C);
}

.moc-creds__sep {
  display: inline-block;
  margin: 0 0.7em;
  opacity: 0.5;
}


/* ═══════════════════════════════════════════════════════════════════════════
   SITE NAV — SCROLL-SCRUBBED PILL → BAR
   Rewritten 2026-08-27. Was a discrete flip: nav-collapse.js toggled an
   attribute at a threshold and a 280ms transition animated `height` and
   `background-color` on .site-nav. Two problems. It read as a snap rather
   than a transition, and it resized a live backdrop sampler's region every
   frame for 280ms — the exact cost this file forbids at :1065 and
   menu-of-care.css warns about twice.

   The morph is now driven by scroll position, and split so that the two
   things which must not happen together never do:

     glass   (.nav-pill::before, .site-nav::before)  never moves, never
             resizes, never changes filter — ONLY opacity
     content (.nav-pill__inner, .nav-logo)           never owns a blur —
             translates and scales freely

   A blurred surface cannot be geometrically morphed anyway: scaling a
   backdrop-filter scales its blur kernel with it, so a 16px blur stretched
   from a ~450px capsule to a 1440px bar becomes a horizontal smear. The
   dissolve is not a compromise for performance; it is the only version that
   looks right.

   Driven by three variables written by nav-collapse.js, all on .site-nav so
   one write feeds every consumer through inheritance:

     --e-glass   capsule opacity        (leads — the capsule leaves first)
     --e-lift    content travel         (the words fly)
     --e-bar     bar opacity            (trails — condenses last)

   Every fallback is the REST state (0), not the settled state. This diverges
   from benediction.js on purpose: every page here loads at scroll 0 with
   `history.scrollRestoration = 'manual'`, so rest IS correct-at-load. A
   missing or broken nav-collapse.js leaves the floating pill — the site's
   behaviour for its whole life before August — rather than a bar the visitor
   never scrolled to.
   ═══════════════════════════════════════════════════════════════════════════ */

.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 999;
  pointer-events: none;

  /* Geometry the scrub interpolates toward. Written by nav-collapse.js from
     measured offsets — never guessed, because the logo is clamp(72px,7.2vw,
     94px) and the pill's width follows the webfont's metrics. */
  --nav-bar-h: 56px;
  --nav-lift-end: 0px;
  --nav-logo-lift-end: 0px;
  --nav-logo-scale-end: 1;
}

.site-nav > * {
  pointer-events: auto;
}

/* The bar surface. Constant height, constant box — only opacity moves. */
.site-nav::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: var(--nav-bar-h);
  border-bottom: 1px solid transparent;
  pointer-events: none;
  opacity: var(--e-bar, 0);
}

.nav--light .site-nav::before {
  background-color: var(--glass);
  border-bottom-color: var(--glass-border-color);
}

.nav--dark .site-nav::before {
  background-color: rgba(32, 32, 30, 0.50);
  border-bottom-color: rgba(255, 255, 255, 0.10);
}

/* No blur without the surface. Both samplers are gated on the phase, so the
   hero pays for exactly ONE blurred layer (the capsule) and the settled bar
   pays for exactly one (the bar). Two exist only while the morph runs. */
.site-nav[data-nav-state="morph"]::before,
.site-nav[data-nav-state="collapsed"]::before {
  backdrop-filter: var(--glass-blur-md);
  -webkit-backdrop-filter: var(--glass-blur-md);
}

.site-nav[data-nav-state="collapsed"] .nav-pill::before {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  visibility: hidden;
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  /* No blur means the background alone has to separate the links from the
     page, so both surfaces go near-solid. Invisible to browsers that support
     backdrop-filter. The capsule has never had this fallback; it does now. */
  .nav--light .site-nav::before { background-color: rgba(249, 248, 242, 0.90); }
  .nav--dark  .site-nav::before { background-color: rgba(32, 32, 30, 0.85); }
  .nav--light .nav-pill::before { background-color: rgba(249, 248, 242, 0.88); }
  .nav--dark  .nav-pill::before { background-color: rgba(32, 32, 30, 0.82); }
}

/* The logo shrinks by `scale`, never by animating height — and the anchor is
   scaled, not the <img>, so the hit area shrinks with the mark instead of
   leaving a 94px link box hanging into the page under a 56px bar.
   transform-origin pins the left edge, which already sits on the container
   gutter, so the mark never moves horizontally: only the vertical lift. */
.nav-logo {
  transform-origin: left center;
  translate: 0 calc(var(--nav-logo-lift-end, 0px) * var(--e-lift, 0));
  scale: calc(1 + (var(--nav-logo-scale-end, 1) - 1) * var(--e-lift, 0));
}

/* NOTE: no `height: 32px` swap at the collapsed endpoint. Handing back to real
   layout there would re-rasterise the mark crisp — a composited layer scaled to
   0.34 has no mipmaps — but `scale` is still applied at that endpoint, so the
   two compound: 32px x 0.34 = 11px. Making it work needs a SECOND measured lift
   for the swapped box (its centre moves from 67px to 36px), and a mismatch of
   even a pixel between the two shows as a jump at the exact moment the morph
   settles. Scale alone is provably correct and has no seam. If the downscaled
   mark visibly aliases on a real Android device, that is when to add the swap —
   with `scale: 1` and its own lift variable, not without them. */

/* An open dropdown must not be scrolled through the morph: it owns a 24px
   blur, and translating its ancestor would re-rasterise it every frame. This
   is (0,4,0), so it beats the .is-open rule that reveals it at (0,3,0). */
.site-nav[data-nav-state="morph"] .nav-pill__cta-wrap.is-open .nav-pill__dropdown {
  opacity: 0;
  visibility: hidden;
}

/* will-change scoped to the phase, with no JS at all — the attribute leaving
   "morph" IS the removal, at both ends. Deliberately NOT on the two glass
   surfaces: an element with a backdrop-filter is already composited, so the
   hint buys nothing and only pins the sampler this file warns about. */
.site-nav[data-nav-state="morph"] .nav-pill__inner,
.site-nav[data-nav-state="morph"] .nav-logo {
  will-change: translate, scale;
}

/* The burger's open state repaints the capsule as a lighter panel, and it is
   the ONE case where the capsule must be visible while collapsed — which is
   always, on mobile. Without this the mobile menu opens against nothing. */
.site-nav[data-nav-state="collapsed"] .nav-pill:has(.nav-pill__burger.is-open)::before {
  visibility: visible;
  opacity: 1;
  backdrop-filter: var(--glass-blur-lg);
  -webkit-backdrop-filter: var(--glass-blur-lg);
}

/* ── Bar height per breakpoint ──────────────────────────────────────────────
   The only thing the old mobile block still needs to say. Everything else it
   used to force — `top: 0 !important`, `right: 16px !important`, and matching
   heights on pill and logo — is now arithmetic: nav-collapse.js measures the
   pill's centre and lifts its contents to the bar's centre line, which lands
   the burger correctly at every breakpoint without a single override. */
@media (max-width: 1023px) {
  .site-nav { --nav-bar-h: 52px; }
}

@media (max-height: 500px) and (orientation: landscape) {
  .site-nav { --nav-bar-h: 44px; }
}

/* ── Reduced motion ─────────────────────────────────────────────────────────
   nav-collapse.js writes only 0 or 1 for these visitors — never an
   intermediate — so there is nothing here to disable. This only stops the
   colour swap and the pathways fade from animating. */
@media (prefers-reduced-motion: reduce) {

  .nav-pill,
  .nav-pill::before,
  .site-nav::before,
  .nav-logo,
  .nav-logo__img {
    transition: none !important;
  }
}

/* ── Focus visibility ───────────────────────────────────────────────────────
   The nav never hides, so nothing has to reveal it when focus lands inside.
   This is the ring itself, which several nav items lacked. */
.site-nav a:focus-visible,
.site-nav button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
  border-radius: 4px;
}


/* ═══════════════════════════════════════════════════════════════════════════
   "SEE THE PATHWAYS" — persistent route to pricing (protocol pages only)
   Added 2026-08-27.

   Deliberately a text link and not a filled button. A bright CTA chasing her
   down a page whose whole argument is that she can stop pushing would be
   working against the copy. It is quiet, it underlines, and it leaves.

   Three conditions must all hold for it to show, and nav-collapse.js owns
   them: past the free preview, pricing not yet on screen, nav collapsed.
   ═══════════════════════════════════════════════════════════════════════════ */

.nav-pathways {
  /* A sibling of the pill, not a child. As a child it inherited the scrub's
     lift (it must not move) and `right: 100%` anchored it to the pill's LEFT
     edge — the opposite side from where it now belongs. Aligned to the bar's
     own height so it is optically centred in it. */
  position: absolute;
  top: 0;
  height: var(--nav-bar-h, 56px);
  display: flex;
  align-items: center;
  z-index: 1;
  white-space: nowrap;

  /* Desktop: the container gutter, mirroring .nav-logo's left. The links stay
     centred between the two. Verified at 1024px: a 134px link still clears the
     centred pill by 139px. */
  right: max(1.5rem, calc((100vw - 1200px) / 2));

  font-family: var(--font-sans);
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 0.35em;
  text-decoration-thickness: 1px;
  text-decoration-color: currentColor;

  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 200ms cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 200ms;
}

/* Shown only in the bar, and only when the script says she has earned it. */
.site-nav[data-nav-state="collapsed"].has-pathways .nav-pathways {
  opacity: 0.78;
  visibility: visible;
  pointer-events: auto;
  transition:
    opacity 200ms cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s;
}

.site-nav[data-nav-state="collapsed"].has-pathways .nav-pathways:hover,
.site-nav[data-nav-state="collapsed"].has-pathways .nav-pathways:focus-visible {
  opacity: 1;
}

/* Inherits the section-aware nav theme so it stays legible over cream and
   over the photographic sections alike. */
.nav--dark .nav-pathways { color: var(--cream); }
.nav--light .nav-pathways { color: var(--charcoal); }

/* Label swaps to the short form where the bar is tight. */
.nav-pathways__short { display: none; }

/* Below 1024px it centres instead of right-aligning: the right edge is the
   burger's (right:20px at 768-1023, right:16px at =<767) and the centre of the
   bar is empty in both bands — logo left, burger right. Measured at 375px:
   logo 0-88, burger 319-375, "PATHWAYS" ~75px centred at 150-225. Clear. */
@media (max-width: 1023px) {
  .nav-pathways__full { display: none; }
  .nav-pathways__short { display: inline; }

  .nav-pathways {
    right: auto;
    left: 50%;
    translate: -50% 0;   /* static, never scrubbed */
    letter-spacing: 0.06em;
    height: var(--nav-bar-h, 52px);
  }
}

@media (max-height: 500px) and (orientation: landscape) {
  .nav-pathways { height: var(--nav-bar-h, 44px); }
}

@media (prefers-reduced-motion: reduce) {
  .nav-pathways { transition: none !important; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   iOS SAFE AREA — the notch, the Dynamic Island, and the landscape bezel
   Added 2026-08-28.

   Prerequisite: every page's viewport meta carries `viewport-fit=cover`.
   Without it env(safe-area-inset-*) resolves to 0px and every rule below is
   a no-op — which is also why these are all written as additions to the
   existing value rather than replacements. On a desktop browser the insets
   are 0 and the geometry is byte-identical to what it was before.

   The shape of the fix: the nav's SURFACE grows upward through the inset so
   the colour behind the island is continuous, while everything the visitor
   reads or taps stays below it. Padding, never margin — the surface has to
   keep painting through that strip, and a margin would leave it bare.

   Appended at the end of the file on purpose. The mobile block at :438-467
   sets `top`/`right` on .nav-pill with !important — documented there as a
   workaround for the base rule being declared later at equal specificity —
   so the only way to add an inset to those without reordering the file (which
   that same comment warns switches on six dormant rules) is to come after
   them, and match the !important.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The bar surface. Height grows by the inset while its top stays at 0, so the
   colour runs unbroken from the very top of the screen down past the island.
   nav-collapse.js reads this element's RESOLVED height to find the bar's
   content centre line — it cannot read the inset any other way, because a
   custom property holding env() comes back from getComputedStyle as the
   literal token string rather than a length. */
.site-nav::before {
  height: calc(var(--nav-bar-h) + env(safe-area-inset-top, 0px));
}

/* Pill: floats below the island rather than under it. */
.nav-pill {
  top: calc(2.4rem + env(safe-area-inset-top, 0px));
}

/* Logo: desktop is absolutely positioned inside .site-nav. */
.nav-logo {
  top: calc(1.25rem + env(safe-area-inset-top, 0px));
  left: max(calc(1.5rem + env(safe-area-inset-left, 0px)),
            calc((100vw - 1200px) / 2));
}

/* "See the pathways" sits inside the bar, so it clears the inset the same way
   the bar's other contents do. */
.nav-pathways {
  top: env(safe-area-inset-top, 0px);
  right: max(calc(1.5rem + env(safe-area-inset-right, 0px)),
             calc((100vw - 1200px) / 2));
}

/* The full-screen menu already spans the insets (inset: 0), which is correct —
   its background should cover them. Only its CONTENT needs holding back, and
   it is a scroll container, so this has to be padding. */
.nav-mobile {
  padding:
    calc(6.5rem + env(safe-area-inset-top, 0px))
    calc(1.5rem + env(safe-area-inset-right, 0px))
    calc(3rem + env(safe-area-inset-bottom, 0px))
    calc(1.5rem + env(safe-area-inset-left, 0px));
}

@media (max-width: 1023px) {
  /* Matching the !important of the block at :438-467 — see the note above. */
  .nav-pill {
    top: calc(34px + env(safe-area-inset-top, 0px)) !important;
    right: calc(20px + env(safe-area-inset-right, 0px)) !important;
  }

  /* The vertical inset goes on `top`, NOT on padding-top. Padding would grow
     the box downward from a fixed top edge, moving its centre by only half the
     inset — and nav-collapse.js lifts the logo by the distance from that centre
     to the bar's, so the mark would land ~inset/2 too low in the collapsed bar.
     Shifting the whole box keeps that lift invariant, exactly as it is for the
     pill. Measured on a simulated 59px inset: lift stays -26px either way for
     the pill, but swings -26px -> +3.5px for the logo under the padding form.
     The horizontal inset is a different matter and does belong on padding. */
  .nav-logo {
    top: env(safe-area-inset-top, 0px);
    left: 0;
    padding: 16px 20px 16px calc(20px + env(safe-area-inset-left, 0px));
  }

  .nav-pathways {
    right: auto;
    left: 50%;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   FORM TOKENS
   Added 2026-08-28 for the attunement capture flow — the first form on the
   site. Every value derives from an existing token; none is a new colour.

   A second :root is deliberate. The block at the top of this file is dense and
   contains double-encoded em-dashes that must not be round-tripped, so new
   tokens are appended rather than threaded into it. Cascade order is
   irrelevant for custom properties on the same element.

   ERROR IS RUST, NOT RED. This is a page about settling a nervous system, and
   a standard #D32F2F error red is tonally wrong for it. --dark-rust measures
   8.83:1 on cream and 9.39:1 on white — AAA at body size on both — so no
   darkening was needed.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* Surfaces */
  --field-bg:            #FDFDFB;                 /* a hair lighter than --cream; pure #FFF reads harsh beside it */
  /* WCAG 1.4.11 wants 3:1 for a UI boundary, and this border IS the boundary:
     --field-bg against the cream section measures 1.03:1, so the field has no
     edge without it. 0.18 (my first pass) was 1.41:1. 0.51 is the bare minimum
     at 3.06:1; 0.55 gives 3.39:1 on the field and 3.34:1 on cream, which is
     headroom rather than a hairline pass. */
  --field-border:        rgba(44, 44, 44, 0.55);
  --field-border-hover:  rgba(44, 44, 44, 0.70);

  /* States — all four resolve to existing brand colours */
  --field-focus:         var(--sage-deep);        /* 5.81:1 on cream. NOT --sage-green, which is 2.78:1 and fails AA. */
  --field-error:         var(--dark-rust);        /* 8.83:1 on cream, 9.39:1 on --field-bg. AAA. */
  --field-success:       var(--sage-deep);
  --field-disabled-ink:  rgba(44, 44, 44, 0.38);  /* --charcoal reduced */

  /* Metrics */
  --field-height:        48px;                    /* WCAG 2.5.8 floor; .nsr-micro__begin sits at 62px */
  --field-radius:        var(--glass-radius);     /* 16px — no sharp corners, per §3 */
  --field-pad-x:         1rem;
  --field-gap:           0.5rem;                  /* label -> field -> error */
}


/* ═══════════════════════════════════════════════════════════════════════════
   PAGE-TITLE SCALE
   Added 2026-08-29 — design plan step 2 of 7, see HANDOVER.md §f.

   The three newest page types (attunement, practice, guide/unsubscribe) each
   carry exactly ONE heading. It is not a section heading with siblings above
   and below it; it is the page's hero, and it is the only thing on the screen
   competing for her eye. All three were set at --fs-h2 (or smaller), which is
   the SECTION scale, and so none of them read as a focal point.

   MEASURED IN-BROWSER off the reference pages, not picked:

                              390px                    1440px
     nsr-protocol hero     35.2 / 15.2 = 2.32     60.8 / 17.28 = 3.52
     index hero            48.0 / 15.2 = 3.16     80.0 / 17.8  = 4.49
     ---- section headings, for contrast ----
     nsr-protocol h2       28.8 / 15.2 = 1.89     48.0 / 17.6  = 2.73
     index section title   28.0 / 15.2 = 1.84     50.75 / 17.8 = 2.85

   Two things the numbers show. First, the hero band and the section band do
   not overlap — a hero is 2.3x-3.2x its body on a phone where a section
   heading is 1.8x-2.0x. Second, the ratio is NOT constant across viewports:
   every reference page compresses on mobile, because headings clamp down
   faster than body copy does. So this is a curve fitted through both measured
   ends, not one multiplier applied twice.

     390px  -> 34.0px   (2.24x over --fs-body's 15.2 floor)
     1440px -> 55.7px   (3.13x over --fs-body's 17.8 ceiling)

   Both ends sit inside the measured hero band and clear of the section band,
   which is the whole point: the reader should not have to work out which of
   these is the important one.

   Slope (56 - 34) / (1440 - 390) = 2.095vw, intercept 1.614rem. The floor and
   the ceiling meet the middle term exactly at 390 and 1440, so the curve is
   linear across the range this site actually sees and clamps outside it.

   Use for the single hero heading on a single-purpose page. Sections keep
   --fs-h2; headings inside cards and narrow columns keep --fs-card-title.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --fs-page-title: clamp(2.125rem, 2.095vw + 1.614rem, 3.5rem);
}


/* ═══════════════════════════════════════════════════════════════════════════
   FLOW SCALE — vertical rhythm for the single-purpose pages
   Added 2026-08-29 — design plan step 4 of 7, see HANDOVER.md §f.

   The three newest page types expressed every gap as its own clamp(), so the
   rendered rhythm was whatever those clamps happened to resolve to at a given
   width. Measured, attunement's element gaps came out 14 / 28 / 12 and the
   practice pages' 58 / 48 / 56 / 8 — not a scale, just arithmetic.

   The reference pages do the opposite. nsr-protocol's element gaps measure
   20 / 24 / 20 and its sections are symmetric slabs (108 over 108, 135 over
   135); index's sections at 390px are 64 / 80 / 48, all multiples of 16.

   SECTIONS take --flow-section, which is 1.25x the sitewide --rhythm-unit and
   is applied SYMMETRICALLY — equal air above and below, as on nsr-protocol.
   It resolves to 80px at 390 (a multiple of 16, matching index) and 139px at
   1440 (inside nsr-protocol's 108-144 band).

   ELEMENTS take one of the steps below. They are chosen values, not clamps:
   the two middle steps are nsr-protocol's measured 20 and 24.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --flow-section: calc(var(--rhythm-unit) * 1.25);  /* 80px @390 · 139px @1440 */

  --flow-3xs: 0.5rem;    /*  8 */
  --flow-2xs: 0.75rem;   /* 12 */
  --flow-xs:  1rem;      /* 16 */
  --flow-sm:  1.25rem;   /* 20 — nsr-protocol's measured element gap */
  --flow-md:  1.5rem;    /* 24 — nsr-protocol's measured element gap */
  --flow-lg:  2rem;      /* 32 */
  --flow-xl:  3rem;      /* 48 */
}


/* ═══════════════════════════════════════════════════════════════════════════
   PAPER AND BREATH — the art direction, 2026-08-29
   ───────────────────────────────────────────────────────────────────────────
   TWO MATERIALS. Everything derives from them.

   PAPER is what she is handed. It has grain, warmth where light falls across
   it, and a soft edge where it curves away. ONE SHEET, TWO LIGHTS: the
   attunement is that sheet in daylight, the guide is the same sheet in a
   dimmed room. Same grain, same warmth, same falloff — the light changes, not
   the material. A warm dark, never a neutral one.

   BREATH is what she is invited into, and it is what we actually sell.
   TWO SECONDS IN, THREE SECONDS OUT. The asymmetry is not a stylistic choice:
   it is Sakshi's own instruction in the practice — "let the out-breath be the
   longer of the two". The curve IS the product. A competitor can copy a
   palette in an afternoon; they cannot copy a motion curve whose shape is a
   therapeutic instruction, because they do not know why it is lopsided.

   THE DISCIPLINE THAT KEEPS BREATH FROM BECOMING DECORATION:
     · on state change, or on the one object literally about breathing
     · never on hover, never on scroll
     · never two things breathing at once in the same view — two cycles beat
       against each other and it stops being a body and becomes a screensaver
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --breath: 5s;
  /* Rises over 40% of the cycle, falls over 60%. Used for anything that
     settles; the keyframes below carry the asymmetry for anything that cycles. */
  --ease-breath: cubic-bezier(0.32, 0.06, 0.24, 1);
  --breath-in: 2s;
  --breath-out: 3s;
}

/* One cycle: in on 40%, out on the remaining 60%. */
@keyframes breathe {
  0%   { opacity: 0;    transform: scale(0.90); }
  40%  { opacity: 1;    transform: scale(1.06); }
  100% { opacity: 0;    transform: scale(0.90); }
}

/* Arriving: the page takes one breath in and holds it. */
@keyframes breathe-in {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ── THE PAPER LAYER ──────────────────────────────────────────────────────
   Applied through a pseudo-element so no page needs new markup. Three things
   stacked, in this order:

     1. WARMTH — a broad radial from the upper left. Light falling across a
        sheet, not a gradient for its own sake.
     2. FALLOFF — the sheet curving away at the lower right. Asymmetric,
        because a symmetric vignette reads as a camera effect.
     3. GRAIN — fractal noise, deliberately BELOW the threshold of noticing.
        If you can see it as texture it is at least twice too strong.

   CONTRAST IS THE CONSTRAINT, and it is not symmetric between the two lights.
   On cream, the falloff DARKENS the ground and pulls --sage-deep down: 8% is
   the floor at 5.34:1, so 8% is the cap. On the dark sheet, darkening only
   ever helps, but WARMTH lightens and threatens --sage-green — measured, 2.5%
   is the last safe step (4.52:1) and 3.5% already fails at 4.43:1. So the dark
   sheet gets 2%, and its warmth is carried in the falloff where no text sits.
   ═══════════════════════════════════════════════════════════════════════════ */
.paper-light::before,
.paper-dim::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;                 /* above the ground, beneath every word */
  pointer-events: none;
}

.paper-light::before {
  background-image:
    radial-gradient(120% 95% at 12% 4%, rgba(255, 252, 244, 0.85) 0%, rgba(255, 252, 244, 0) 55%),
    radial-gradient(105% 85% at 88% 100%, rgba(138, 126, 106, 0.08) 0%, rgba(138, 126, 106, 0) 62%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.22'/%3E%3C/svg%3E");
  background-size: cover, cover, 180px 180px;
  mix-blend-mode: multiply;
  /* 0.55 read as mottling — visibly dirty rather than like paper. The brief
     was explicit: build it under the threshold of noticing. You should only
     register that the ground is not flat. */
  opacity: 0.26;
}

.paper-dim::before {
  background-image:
    radial-gradient(115% 90% at 14% 6%, rgba(201, 169, 122, 0.020) 0%, rgba(201, 169, 122, 0) 58%),
    radial-gradient(110% 95% at 86% 100%, rgba(0, 0, 0, 0.26) 0%, rgba(0, 0, 0, 0) 66%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.16'/%3E%3C/svg%3E");
  background-size: cover, cover, 180px 180px;
  opacity: 0.55;
}

/* ── THE BOWL ─────────────────────────────────────────────────────────────
   A presence, not a person. The source frame contains a woman; the crop does
   not — object-position holds it on the bowl and the hand cradling it, which
   is an ACTION rather than a body to measure herself against. Soft-arch masked
   as the site masks its media, bleeding off one edge, and low enough to read
   as a shadow ON the paper rather than a picture placed on it.
   ═══════════════════════════════════════════════════════════════════════════ */
.paper-light::after,
.paper-dim::after {
  content: '';
  position: fixed;
  z-index: -1;
  pointer-events: none;
  background-image: url('/PageWiseAssets_rs/Home/Section6/Care_SigningBowl.webp');
  background-size: cover;
  background-position: 32% 46%;      /* the bowl and the hand, nothing above */
  border-radius: 50% 50% 16px 16px / 38% 38% 0 0;
  /* Blurred, because at 10% and sharp it was legibly a photograph of a hand
     and a bracelet — a picture ON the page. Out of focus it becomes a
     presence: the eye reads warmth and a round form and stops there.
     A soft mask fades the top edge so it never collides with reading. */
  filter: blur(3px);
  -webkit-mask-image: linear-gradient(to top, #000 32%, transparent 92%);
  mask-image: linear-gradient(to top, #000 32%, transparent 92%);
}

/* NO reduced-motion rule for the paper, deliberately — and the version that
   was here was a bug: `opacity: inherit` would have resolved to the PARENT's
   opacity (1) and shown the grain and the bowl at full strength to exactly the
   people least likely to want them.

   The paper is not motion. It does not move, so there is nothing to switch
   off, and it needs no rule at all. That is the point: with the breath
   disabled the page keeps its ground, its grain, its falloff, its bowl, its
   ghosted numeral and all of the card's material. A still page here is a
   complete page, not a degraded one. */
