/* ============================================================
   THE AURORA STANDARD — Shared Stylesheet
   Design system derived verbatim from the Brand Kit.
   Three families + accent: bone / ink / forest / clay.
   Display: Fraunces. Body/UI: Manrope.
   ============================================================ */

:root {
  /* Surfaces */
  --bone: #F6F2E9;
  --bone-deep: #ECE6D6;
  --bone-darker: #E0D8C3;

  /* Ink (text) */
  --ink: #1F1B14;
  --ink-soft: #4A443A;
  /* Nudged darker from #7C7468 to clear WCAG AA (4.5:1) for normal-size text
     on both bone and the darker bone-deep — used in .muted, .tier-sqft,
     .item-detail, .eyebrow. Now ~5.4:1 on bone, ~4.8:1 on bone-deep. */
  --ink-muted: #696257;

  /* Forest (primary action) */
  --forest: #1E3A2E;
  --forest-deep: #142820;

  /* Clay (single chromatic accent) */
  --clay: #B97548;
  --clay-soft: #C8956D;
  --clay-pale: #F2DDCB;
  --clay-deep: #8F5635;

  /* Lines */
  --line: rgba(31, 27, 20, 0.12);
  --line-soft: rgba(31, 27, 20, 0.07);

  /* Semantic (transactional) */
  --error-red: #EB5534;
  --success-green: #719673;
  --warning-amber: #E0C584;

  /* Layout */
  --container: 1180px;
  --container-narrow: 760px;
  --measure: 680px;

  /* Z-index scale. The nav sits ABOVE the drawer so the brand and the
     hamburger-turned-X stay visible (and clickable) while the drawer is open —
     the X is the drawer's close affordance. The sticky action bar sits below
     the drawer so it can never overlay an open menu. */
  --z-nav: 300;
  --z-drawer: 200;
  --z-bar: 90;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

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

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  font-family: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bone);
  color: var(--ink);
  font-size: 17px;
  line-height: 1.75;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { max-width: 100%; display: block; }

/* ---- Display type ---- */
.display {
  font-family: 'Fraunces', Georgia, serif;
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 50;
  letter-spacing: -0.015em;
}
.italic { font-style: italic; color: var(--clay); }

/* ---- Skip link (a11y) ---- */
.skip-link {
  position: absolute;
  left: 16px; top: -48px;
  z-index: 1000;
  background: var(--forest);
  color: var(--bone);
  padding: 10px 18px;
  border-radius: 2px;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  transition: top 0.2s ease;
}
.skip-link:focus { top: 16px; }

/* ---- Focus visibility (a11y) ---- */
a:focus-visible,
button:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--clay);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: var(--z-nav);
  padding: 16px 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  background: rgba(246, 242, 233, 0.90);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line-soft);
  transition: padding 0.35s var(--ease-out), background 0.3s ease, border-color 0.3s ease, box-shadow 0.35s ease;
}
/* Past the hero the bar condenses — tighter padding, a deeper hairline and a
   barely-there shadow — a quiet sense of depth as the page scrolls. Toggled
   by app.js. */
.nav.scrolled {
  padding-top: 10px;
  padding-bottom: 10px;
  background: rgba(246, 242, 233, 0.96);
  border-bottom-color: var(--line);
  box-shadow: 0 10px 30px -24px rgba(31, 27, 20, 0.5);
}
.nav-brand {
  display: inline-flex;
  align-items: baseline;
  gap: 2px;
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 400;
  font-size: 22px;
  letter-spacing: 0.01em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.nav-brand .b-standard { font-style: italic; color: var(--clay); }

.nav-links {
  display: flex;
  align-items: center;
  gap: 32px;
  list-style: none;
}
.nav-links a {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 6px 0;
  position: relative;
  transition: color 0.2s ease;
}
.nav-links a:hover { color: var(--ink); }
.nav-links a[aria-current="page"] { color: var(--ink); }
/* Underline draws in from the left on hover — a quiet luxury detail —
   and stays drawn for the current page. */
.nav-links a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: var(--clay);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s var(--ease-out);
}
.nav-links a:hover::after,
.nav-links a:focus-visible::after,
.nav-links a[aria-current="page"]::after { transform: scaleX(1); }
.nav-right { display: flex; align-items: center; gap: 24px; }

.nav-cta {
  background: var(--forest);
  color: var(--bone);
  padding: 11px 24px;
  font-family: 'Manrope', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 2px;
  white-space: nowrap;
  transition: background 0.25s ease, transform 0.25s ease;
}
.nav-cta:hover { background: var(--forest-deep); transform: translateY(-1px); }

/* Hamburger */
.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
}
.nav-toggle span {
  display: block;
  width: 22px; height: 1.5px;
  background: var(--ink);
  position: relative;
  transition: background 0.2s ease;
}
.nav-toggle span::before,
.nav-toggle span::after {
  content: '';
  position: absolute;
  left: 0;
  width: 22px; height: 1.5px;
  background: var(--ink);
  transition: transform 0.25s ease, top 0.25s ease;
}
.nav-toggle span::before { top: -7px; }
.nav-toggle span::after { top: 7px; }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after { top: 0; transform: rotate(-45deg); }

/* Mobile drawer */
.mobile-drawer {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  background: var(--bone);
  display: flex;
  flex-direction: column;
  padding: 100px 32px 48px;
  transform: translateY(-100%);
  transition: transform 0.4s var(--ease-out);
  visibility: hidden;
}
.mobile-drawer.open { transform: translateY(0); visibility: visible; }
/* Drawer list styled to the Kinfolk register (owner's reference): a larger
   serif set TIGHT — no divider hairlines, short leading — so the menu reads
   as one editorial list rather than a stack of full-width rows. */
.mobile-drawer a {
  font-family: 'Fraunces', serif;
  font-weight: 400;
  font-size: 28px;
  line-height: 1.2;
  color: var(--ink);
  text-decoration: none;
  padding: 9px 0;
  letter-spacing: -0.01em;
}
.mobile-drawer a .italic { font-style: italic; }
/* Secondary tier below the CTA — small Manrope contact links, mirroring the
   reference's quiet second block. */
.mobile-drawer .drawer-meta { margin-top: 28px; display: flex; flex-direction: column; gap: 4px; }
.mobile-drawer .drawer-meta a {
  font-family: 'Manrope', sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
  padding: 2px 0;
  letter-spacing: 0.01em;
}
/* Restate the CTA's light-on-forest colors: the generic drawer-link rule above
   (.mobile-drawer a) outspecifies .nav-cta and was inking the button text. */
.mobile-drawer .nav-cta {
  margin-top: 32px;
  text-align: center;
  font-size: 14px;
  padding: 18px 24px;
  color: var(--bone);
  border-bottom: none;
}

/* ============================================================
   BUTTONS
   ============================================================ */
.btn-primary {
  background: var(--forest);
  color: var(--bone);
  padding: 18px 38px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 2px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  transition: background 0.25s ease, transform 0.25s ease;
}
.btn-primary:hover { background: var(--forest-deep); transform: translateY(-1px); }
/* Tier II: a → glides in from nothing on hover. Pure CSS, no markup change;
   nav-cta is intentionally left without it so the bar never reflows. */
.btn-primary::after {
  content: '\2192';
  flex: none;
  min-width: 0;
  max-width: 0;
  overflow: hidden;
  opacity: 0;
  transform: translateX(-4px);
  transition: max-width 0.4s var(--ease-out), margin-left 0.4s var(--ease-out), opacity 0.3s ease, transform 0.4s var(--ease-out);
}
.btn-primary:hover::after { max-width: 1.5em; margin-left: 0.5em; opacity: 1; transform: translateX(0); }

.btn-on-dark {
  background: var(--clay);
  color: var(--bone);
}
.btn-on-dark:hover { background: var(--clay-soft); }

.btn-secondary {
  color: var(--ink);
  padding: 18px 2px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  /* Clay at rest (owner review, 2026-07-06) — matches the inline text-link
     hairline; previously ink, which read as a stray black rule. */
  border-bottom: 1px solid var(--clay);
  display: inline-block;
  transition: opacity 0.2s ease;
}
.btn-secondary:hover { opacity: 0.55; }
.btn-secondary.on-dark { color: var(--bone); border-bottom-color: var(--clay-soft); }

/* ============================================================
   SECTION SCAFFOLD
   ============================================================ */
.section { padding: 120px 40px; position: relative; }
.section.tight { padding: 88px 40px; }
.bg-bone-deep { background: var(--bone-deep); }
.bg-forest { background: var(--forest); color: var(--bone); }

.container { max-width: var(--container); margin: 0 auto; }
.container-narrow { max-width: var(--container-narrow); margin: 0 auto; }
.align-left { margin-left: 0; }

.section-label {
  font-family: 'Manrope', sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: 28px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.section-label::before {
  content: '';
  width: 32px; height: 1px;
  background: var(--clay);
}
.bg-forest .section-label { color: var(--clay-soft); }
.bg-forest .section-label::before { background: var(--clay-soft); }

h1, h2, h3 { font-family: 'Fraunces', Georgia, serif; font-optical-sizing: auto; }

h2 {
  font-weight: 350;
  font-size: clamp(34px, 4.4vw, 54px);
  line-height: 1.08;
  letter-spacing: -0.022em;
  color: var(--ink);
  margin-bottom: 32px;
  max-width: 880px;
  text-wrap: balance;
}
h2 em { font-style: italic; color: var(--clay); font-variation-settings: "SOFT" 100; }
.bg-forest h2 { color: var(--bone); }
/* Owner decision (2026-07-02): emphasized words keep the darker --clay on every
   background — do not lighten to --clay-soft. At headline sizes --clay clears
   the 3:1 large-text AA bar on FOREST (measures 3.34:1).
   ⚠️ EXCEPTION (2026-07-09, owner-approved): that reasoning holds for flat
   forest only. Over a PHOTO it fails — see `.page-hero--media h1 em`, where
   clay measured 1.42:1 against the bright part of the hero image and is now
   --clay-pale. Do not "unify" the two back together. */
.bg-forest h2 em { color: var(--clay); }

h3 {
  font-weight: 400;
  font-size: 28px;
  line-height: 1.2;
  /* Headings sit ABOVE body copy in the hierarchy, so an h3 must read at least
     as dark as the paragraph it introduces. The old translucent ink-soft made
     section sub-heads paler than their own body text — an inverted hierarchy
     that several components then patched back to --ink one by one. Default to
     --ink here and let dark backgrounds (and hover states) opt out below. */
  color: var(--ink);
  margin-bottom: 16px;
  letter-spacing: -0.012em;
}
.bg-forest h3 { color: var(--bone); }

.lead {
  font-size: 21px;
  line-height: 1.6;
  color: var(--ink-soft);
  margin-bottom: 28px;
  text-wrap: pretty;
}
/* Fraunces' x-height is well below Manrope's, so at the same nominal size an
   inline serif italic reads visibly smaller than the sentence around it —
   1.12em optically matches; line-height 1 keeps it from opening the leading. */
.lead em { font-style: italic; color: var(--clay); font-family: 'Fraunces', serif; font-size: 1.12em; line-height: 1; }
.bg-forest .lead { color: rgba(246, 242, 233, 0.80); }

p { margin-bottom: 22px; color: var(--ink-soft); max-width: var(--measure); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }
p.dark { color: var(--ink); }
.bg-forest p { color: rgba(74, 68, 58, 0.74); }
.muted { color: var(--ink-muted); font-size: 14px; }

/* ============================================================
   HERO
   ============================================================ */
.hero {
  padding: 184px 40px 110px;
  position: relative;
  overflow: hidden;
}
/* Content is constrained; the section itself spans full width so a future
   full-bleed photograph can run edge to edge behind it. */
.hero-inner { max-width: 1280px; margin: 0 auto; position: relative; z-index: 2; }
/* Hero "maker's mark" — the AS monogram, stamped above the title like a
   crest, the way a luxury house opens with its emblem. */
.hero-emblem { width: 50px; height: auto; margin-bottom: 30px; opacity: 0.92; }
.eyebrow {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 32px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.eyebrow::after { content: ''; width: 60px; height: 1px; background: var(--ink-muted); }

h1.hero-headline {
  font-weight: 350;
  font-size: clamp(40px, 6vw, 78px);
  line-height: 1.04;
  letter-spacing: -0.025em;
  max-width: 950px;
  margin-bottom: 36px;
  color: var(--ink);
  text-wrap: balance;
}
h1.hero-headline em {
  font-style: italic; font-weight: 350; color: var(--clay);
  font-variation-settings: "SOFT" 100;
}
.hero-sub {
  max-width: 600px;
  font-size: 19px;
  line-height: 1.65;
  color: var(--ink-soft);
  margin-bottom: 44px;
}
.hero-actions { display: flex; align-items: center; gap: 32px; flex-wrap: wrap; }

/* Page hero (interior pages) */
.page-hero { padding: 168px 40px 72px; }
.page-hero h1 {
  font-weight: 350;
  font-size: clamp(38px, 5.4vw, 66px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--ink);
  max-width: 920px;
  margin-bottom: 32px;
  text-wrap: balance;
}
.page-hero h1 em { font-style: italic; color: var(--clay); font-variation-settings: "SOFT" 100; }

/* Tier II — expressive headline accents. Clay italic words inside display
   headlines (h1/h2 only) switch on Fraunces' WONK axis + discretionary
   ligatures, so the wonky letterforms stay reserved for headlines and never
   leak into the small italic numerals, leads, or quote italics. */
h1.hero-headline em,
.page-hero h1 em,
h2 em {
  font-variation-settings: "SOFT" 100, "WONK" 1;
  font-feature-settings: "dlig" 1, "ss01" 1;
}

/* ---- Full-bleed media placeholder for interior-page heroes ----
   ACTIVATE a photo: put <img class="ph-fill"> inside .ph-media (or set its
   background-image) and delete .ph-media-mark. Text flips to light over a
   forest scrim, matching the home hero. */
.page-hero--media { position: relative; overflow: hidden; color: var(--bone); }
/* Overscanned like the home hero (top:-30% / height:160%) so the parallax
   drift never exposes an edge. Transform comes from --hero-shift (JS fallback,
   app.js) or the compositor scroll-driven animation (see HERO PARALLAX). */
.page-hero--media .ph-media {
  position: absolute; left: 0; top: -30%; z-index: 0;
  width: 100%; height: 160%;
  background: var(--forest-deep);
  transform: translateY(var(--hero-shift, 0px)); will-change: transform;
}
/* Descendant, not child — see the .media-slot note: <picture> now wraps this img. */
.page-hero--media .ph-media .ph-fill { width: 100%; height: 100%; object-fit: cover; display: block; }
.page-hero--media .ph-media-mark {
  position: absolute; right: 40px; bottom: 34px;
  display: flex; flex-direction: column; align-items: flex-end; text-align: right;
  gap: 7px; max-width: 300px;
}
.page-hero--media .ph-media-mark .ph-emblem { width: 38px; filter: brightness(0) invert(1); opacity: 0.5; margin-bottom: 3px; }
.page-hero--media .ph-media-mark .ph-label { font-size: 11px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--clay-soft); }
.page-hero--media .ph-media-mark .ph-desc { font-size: 12.5px; line-height: 1.5; color: rgba(246,242,233,0.66); }
.page-hero--media .ph-media-mark .ph-file { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 10.5px; color: rgba(246,242,233,0.5); }
.page-hero--media::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(90deg, rgba(20,40,32,0.92) 0%, rgba(20,40,32,0.72) 44%, rgba(20,40,32,0.36) 100%);
}
.page-hero--media > .container { position: relative; z-index: 2; }
.page-hero--media h1 { color: var(--bone); }
/* --clay-pale, NOT --clay. This is the documented exception to the §18 accent
   lock, and it is measured, not aesthetic.
   "Charged $402." sits over the bright window/drapes of system-hero.jpg. Clay
   #B97548 is a midtone (luminance 0.235); that background runs 0.079-0.151.
   Sampling the real rendered pixels behind the glyphs at 1300x900:
       clay      2.21:1 median, 1.42:1 over the bright drapes   FAIL (needs 3:1)
       clay-soft 1.98:1 over the bright drapes                  FAIL
       clay-pale 3.97:1 over the bright drapes                  PASS
   Flat-forest accents (index h2 em, .cta-band h2 em) keep --clay, where they
   measure 3.34:1 and pass; the §18 lock still governs those. Only photo heroes
   lighten. Lighthouse cannot catch this: the h1 carries .reveal (opacity:0) and
   axe skips invisible elements. */
.page-hero--media h1 em { color: var(--clay-pale); }
/* "THE AURORA SYSTEM" is SMALL uppercase text (11px), so it needs 4.5:1, not
   the 3:1 large-text bar. Measured against the photo behind it:
       clay-soft 4.88:1 median but 3.06:1 over the brighter area   FAIL
       clay-pale 9.78:1 median, 6.14:1 over the brighter area      PASS
   The ::before hairline is decoration (no contrast bar) but follows the label
   so the lockup stays one colour. --clay-soft remains correct for labels on
   FLAT forest, where there is no photo to compete with. */
.page-hero--media .section-label { color: var(--clay-pale); }
.page-hero--media .section-label::before { background: var(--clay-pale); }
.page-hero--media .lead { color: rgba(246,242,233,0.85); }
.page-hero--media p { color: rgba(246,242,233,0.74); }

/* ============================================================
   TRUST STRIP
   ============================================================ */
.trust {
  margin-top: 76px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  padding-top: 36px;
  border-top: 1px solid var(--line);
  max-width: 940px;
}
.trust-item { font-size: 13px; color: var(--ink-soft); letter-spacing: 0.01em; }
.trust-item strong {
  font-family: 'Fraunces', serif;
  font-weight: 400;
  font-size: 26px;
  display: block;
  color: var(--ink);
  margin-bottom: 6px;
  line-height: 1.05;
}

/* ============================================================
   MATH STATS
   ============================================================ */
.math-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 48px;
  margin: 72px 0 40px;
  padding: 56px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.math-stat .num {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(60px, 7vw, 88px);
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--forest);
  margin-bottom: 16px;
  display: block;
}
.math-stat .num em { font-style: italic; color: var(--clay); font-weight: 350; }
.math-stat .label { font-size: 15px; color: var(--ink-soft); line-height: 1.55; max-width: 300px; }

/* ============================================================
   FAILURES
   ============================================================ */
.failures { margin-top: 64px; }
.failure-item {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 48px;
  padding: 44px 0;
  border-top: 1px solid var(--line);
  align-items: start;
}
.failure-item:last-child { border-bottom: 1px solid var(--line); }
.failure-num {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 300;
  font-size: 44px;
  color: var(--clay);
  line-height: 1;
}
.failure-item h3 { margin-bottom: 12px; font-size: 24px; }
.failure-item p { font-size: 16px; line-height: 1.7; }

/* ============================================================
   PILLARS
   ============================================================ */
.pillars {
  margin-top: 72px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 72px 64px;
}
.pillar { padding-top: 32px; border-top: 1px solid rgba(246,242,233,0.18); }
.pillar-num {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 300;
  font-size: 16px;
  letter-spacing: 0.04em;
  color: var(--clay-soft);
  margin-bottom: 16px;
  display: block;
}
.pillar h3 { font-size: 30px; margin-bottom: 16px; font-weight: 400; }
.pillar h3 em { font-style: italic; color: var(--ink); }
.pillar p { font-size: 16px; line-height: 1.7; }

/* Compact pillar cards (home summary) */
.pillar-cards {
  margin-top: 64px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
}
.pillar-card {
  background: var(--bone);
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  padding: 36px 34px;
  border-left: 3px solid var(--clay);
}
.bg-bone-deep .pillar-card { background: var(--bone); }
.pillar-card .pillar-num { color: var(--clay); }
.pillar-card h3 { font-size: 23px; }
.pillar-card p { font-size: 15px; line-height: 1.65; margin-bottom: 0; color: var(--ink-soft); }
/* Pillar cards have a light bone background, so their text must stay dark
   even when the card sits inside a dark (forest) section. These overrides
   beat the generic ".bg-forest h3/p" light-text rules. */
.bg-forest .pillar-card h3 { color: var(--ink); }
.bg-forest .pillar-card p { color: var(--ink-soft); }
.bg-forest .pillar-card .pillar-num { color: var(--clay); }
.bg-forest .pillar-card h3 em { color: var(--clay); }

/* ============================================================
   HOW IT WORKS
   ============================================================ */
.steps {
  margin-top: 64px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 48px;
}
.step { border-top: 2px solid var(--clay); padding-top: 28px; }
.step .step-num {
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-size: 14px;
  color: var(--clay);
  margin-bottom: 14px;
  letter-spacing: 0.04em;
}
.step h3 { font-size: 24px; margin-bottom: 14px; }
.step p { font-size: 15px; line-height: 1.7; }

/* ============================================================
   PRICING CALCULATOR
   ============================================================ */
.calc {
  margin-top: 64px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
  background: var(--bone);
}
.calc-controls { padding: 48px; border-right: 1px solid var(--line); }
.calc-output {
  padding: 48px;
  background: var(--forest);
  color: var(--bone);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.field { margin-bottom: 36px; }
.field:last-child { margin-bottom: 0; }
.field-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: 16px;
}

/* Custom select */
.select-wrap { position: relative; }
.select-wrap::after {
  content: '';
  position: absolute;
  right: 18px; top: 50%;
  width: 8px; height: 8px;
  border-right: 1.5px solid var(--ink-soft);
  border-bottom: 1.5px solid var(--ink-soft);
  transform: translateY(-65%) rotate(45deg);
  pointer-events: none;
}
.calc select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  font-family: 'Manrope', sans-serif;
  font-size: 16px;
  color: var(--ink);
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 16px 44px 16px 18px;
  cursor: pointer;
  min-height: 44px;
  transition: border-color 0.2s ease;
}
.calc select:hover { border-color: var(--ink-muted); }

/* Segmented frequency control */
.segment { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.segment input { position: absolute; opacity: 0; pointer-events: none; }
.segment label {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
  min-height: 64px;
  padding: 10px 8px;
  border: 1px solid var(--line);
  border-radius: 2px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
}
.segment label .save {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--clay);
  text-transform: none;
}
.segment label:hover { border-color: var(--ink-muted); }
.segment input:checked + label {
  border-color: var(--forest);
  background: var(--forest);
  color: var(--bone);
}
.segment input:checked + label .save { color: var(--clay-soft); }
.segment input:focus-visible + label { outline: 3px solid var(--clay); outline-offset: 3px; }

/* Output */
.calc-output .out-label {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--clay-soft);
  margin-bottom: 14px;
}
.calc-output .out-price {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(56px, 8vw, 80px);
  line-height: 0.95;
  letter-spacing: -0.03em;
  color: var(--bone);
  font-variant-numeric: tabular-nums;
}
.calc-output .out-price sup {
  font-size: 0.4em;
  vertical-align: super;
  font-weight: 400;
  color: var(--clay-soft);
  margin-right: 2px;
}
.calc-output .out-cadence {
  font-size: 15px;
  color: rgba(246,242,233,0.72);
  margin-top: 8px;
  font-variant-numeric: tabular-nums;
}
/* Discount emphasis — a clay pill on the forest panel restating the active
   frequency's saving, larger than the tiny label inside the segment control. */
.calc-output .out-save {
  align-self: flex-start;
  margin-top: 18px;
  font-family: 'Manrope', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--forest-deep);
  background: var(--clay-soft);
  padding: 7px 14px;
  border-radius: 2px;
}
.calc-output .out-first {
  margin-top: 32px;
  padding-top: 28px;
  border-top: 1px solid rgba(246,242,233,0.18);
}
.calc-output .out-first .row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  font-size: 15px;
  color: rgba(246,242,233,0.82);
  padding: 6px 0;
}
.calc-output .out-first .row .v {
  font-family: 'Fraunces', serif;
  color: var(--bone);
  font-size: 18px;
  font-variant-numeric: tabular-nums;
}
.calc-output .out-note { font-size: 13px; color: rgba(246,242,233,0.55); margin-top: 22px; line-height: 1.55; }
/* Ink label on clay — see the .cta-band note (AA: 4.65:1, not bone's 3.30:1). */
.calc-output .btn-primary { margin-top: 32px; background: var(--clay); color: var(--ink); text-align: center; }
.calc-output .btn-primary:hover { background: var(--clay-soft); color: var(--ink); }

/* ============================================================
   PRICING TABLE (full reference)
   ============================================================ */
.price-table-wrap {
  margin-top: 56px;
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 4px;
  /* Scroll-shadow affordance (Lea Verou technique): a soft shadow hugs the
     right edge while there's more table to scroll, and dissolves at the end.
     The `local` cover gradient masks the `scroll`-attached shadow once you
     reach the right edge — and on desktop, where nothing overflows, it sits
     over the shadow so none ever shows. */
  background:
    linear-gradient(to left, var(--bone-deep) 38%, rgba(236, 230, 214, 0)) right center / 48px 100% no-repeat local,
    radial-gradient(farthest-side at 100% 50%, rgba(31, 27, 20, 0.16), rgba(31, 27, 20, 0)) right center / 18px 100% no-repeat scroll;
}
table.price-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  min-width: 680px;
}
/* The tier column stays pinned while the frequencies scroll past it, so you
   never lose track of which home you're reading. The solid surface lets the
   scrolling figures slide cleanly underneath. (No-op on desktop, where the
   table doesn't overflow.) */
.price-table th:first-child,
.price-table td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--bone-deep);
}
.price-table th, .price-table td { padding: 16px 18px; text-align: right; border-bottom: 1px solid var(--line-soft); font-size: 15px; }
.price-table th { font-weight: 600; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-muted); }
.price-table thead th { border-bottom: 1px solid var(--line); }
.price-table td:first-child, .price-table th:first-child { text-align: left; }
.price-table .tier-name { font-family: 'Fraunces', serif; font-size: 17px; color: var(--ink); }
.price-table .tier-sqft { display: block; font-size: 12px; color: var(--ink-muted); font-family: 'Manrope', sans-serif; }
.price-table tbody tr:hover { background: var(--bone-deep); }
.price-table .col-accent { color: var(--forest); font-weight: 600; }

/* ============================================================
   EXTRAS (specialty + add-ons)
   ============================================================ */
/* Grouped add-ons in a balanced masonry — column-count flows the five groups
   into even columns while break-inside keeps each group whole. */
.extras-grid { margin-top: 56px; column-count: 3; column-gap: 56px; }
.extras-col { break-inside: avoid; margin-bottom: 44px; }
.extras-col h3 { font-size: 20px; margin-bottom: 18px; padding-bottom: 13px; border-bottom: 1px solid var(--line); }
.extras-list { list-style: none; }
.extras-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 13px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 15px;
  color: var(--ink);
  gap: 16px;
}
.extras-list li:last-child { border-bottom: none; }
.extras-list .item-name { flex: 1; }
.extras-list .item-detail { color: var(--ink-muted); font-size: 13px; margin-left: 6px; }
.extras-list .item-price {
  font-family: 'Fraunces', serif;
  font-weight: 400;
  color: var(--clay);
  font-size: 16px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   TESTIMONIALS (placeholder styling)
   ============================================================ */
.cards-3 { margin-top: 56px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; }
.testimonial {
  background: var(--bone);
  padding: 38px 34px;
  border-radius: 4px;
  border: 1px solid var(--line-soft);
  position: relative;
}
.testimonial-quote {
  font-family: 'Fraunces', serif;
  font-weight: 350;
  font-size: 19px;
  line-height: 1.5;
  color: var(--ink);
  margin-bottom: 24px;
  letter-spacing: -0.005em;
}
.testimonial-attr { font-size: 13px; color: var(--ink-muted); padding-top: 18px; border-top: 1px solid var(--line); }
.testimonial-attr strong { display: block; color: var(--ink); font-weight: 600; font-size: 14px; margin-bottom: 2px; }

/* Placeholder marker */
.placeholder-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: 'Manrope', sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--clay-deep);
  background: var(--clay-pale);
  border: 1px dashed var(--clay);
  border-radius: 2px;
  padding: 5px 10px;
  margin-bottom: 20px;
}
.is-placeholder .testimonial-quote { color: var(--ink-soft); font-style: italic; }

/* Tier II — hanging quotation mark. Only genuine testimonial cards carry the
   .is-quote modifier (the pricing cards reuse .testimonial but aren't quotes),
   so the oversized Fraunces mark hangs into the left gutter of real quotes. */
.testimonial.is-quote { padding-left: 52px; }
.testimonial.is-quote::before {
  content: '\201C';
  position: absolute;
  left: 16px; top: 18px;
  font-family: 'Fraunces', serif;
  font-style: italic;
  font-weight: 300;
  font-size: 64px;
  line-height: 1;
  color: var(--clay-soft);
  opacity: 0.55;
  pointer-events: none;
}

/* Featured price card — pricing-teaser "Most popular" */
.testimonial.is-featured { border-color: var(--clay); box-shadow: 0 0 0 1px var(--clay); }
.pop-badge {
  position: absolute; top: -11px; left: 34px;
  font-size: 10px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--bone); background: var(--clay);
  padding: 5px 11px; border-radius: 2px;
}

/* Pricing-teaser figure — the proper Fraunces price treatment (mirrors the
   calculator's .out-price), replacing the old inline 40px Manrope hack: clay
   dollar superscript, tabular figures, a quiet Manrope cadence line beneath. */
.price-fig {
  font-family: 'Fraunces', serif;
  font-weight: 300;
  font-size: clamp(40px, 5vw, 52px);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.price-fig sup { font-size: 0.4em; vertical-align: super; font-weight: 400; color: var(--clay); margin-right: 2px; }
.price-fig .per {
  display: block;
  font-family: 'Manrope', sans-serif;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--ink-muted);
  margin-top: 12px;
}

/* ============================================================
   FOUNDER
   ============================================================ */
.founder-card {
  margin-top: 8px;
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 56px;
  align-items: center;
  background: var(--bone-deep);
  border-radius: 4px;
  border-left: 3px solid var(--clay);
  padding: 56px;
}
.founder-portrait {
  width: 100%;
  /* height:auto beats the img's height="900" attribute hint, so the CSS
     aspect-ratio (not the attribute) sets the rendered height. */
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 3px;
  background: var(--bone-darker);
}
.founder-quote {
  font-family: 'Fraunces', serif;
  font-weight: 350;
  font-size: clamp(22px, 2.4vw, 28px);
  line-height: 1.45;
  color: var(--ink);
  margin-bottom: 28px;
  letter-spacing: -0.012em;
}
.founder-quote em { font-style: italic; color: var(--clay); }
.founder-attr { font-size: 14px; color: var(--ink-soft); letter-spacing: 0.02em; }
.founder-attr strong {
  display: block;
  font-family: 'Fraunces', serif;
  font-weight: 500;
  font-size: 18px;
  color: var(--ink);
  margin-bottom: 4px;
}

/* ============================================================
   FAQ
   ============================================================ */
.faq-list { margin-top: 48px; }
.faq-item { border-top: 1px solid var(--line); padding: 4px 0; }
.faq-item:last-child { border-bottom: 1px solid var(--line); }
.faq-q {
  font-family: 'Fraunces', serif;
  font-weight: 400;
  font-size: 22px;
  color: var(--ink);
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  letter-spacing: -0.01em;
  list-style: none;
  padding: 26px 0;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after {
  content: '+';
  font-family: 'Manrope', sans-serif;
  font-weight: 300;
  font-size: 28px;
  color: var(--clay);
  transition: transform 0.3s ease;
  flex-shrink: 0;
}
details[open] .faq-q::after { content: '−'; }
.faq-a { padding: 0 0 28px; font-size: 16px; line-height: 1.7; color: var(--ink-soft); max-width: var(--measure); }

/* ============================================================
   CTA BAND
   ============================================================ */
.cta-band { background: var(--forest); color: var(--bone); text-align: center; padding: 130px 40px; }
.cta-band h2 { color: var(--bone); margin: 0 auto 28px; text-align: center; max-width: 820px; }
.cta-band h2 em { color: var(--clay); }
.cta-band .lead { color: rgba(246,242,233,0.78); max-width: 620px; margin: 0 auto 48px; text-align: center; }
/* Clay CTA label is INK, not bone. Bone on clay is 3.30:1 — below the 4.5:1 AA
   bar for a 14px uppercase label. Ink on clay is 4.65:1, and 6.51:1 on the
   clay-soft hover. Lighthouse never caught this: these buttons carry .reveal,
   which starts at opacity:0, and axe skips invisible elements. Do not revert
   to bone without raising the label to >=18.66px bold (the large-text bar). */
.cta-band .btn-primary { background: var(--clay); color: var(--ink); padding: 22px 56px; font-size: 14px; }
.cta-band .btn-primary:hover { background: var(--clay-soft); color: var(--ink); }
.cta-meta { margin-top: 32px; font-size: 13px; color: rgba(246,242,233,0.55); letter-spacing: 0.06em; }

/* ============================================================
   BOOKING / JOBBER
   ============================================================ */
/* Checkout-first layout (2026-07-02): the Jobber form is the centered focal
   point on every screen — first thing after the hero — with "What happens
   next" and contact details supporting it below, so the visitor reaches the
   form in one scroll instead of past a sidebar. */
.book-form-shell {
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 40px;
  max-width: 760px;
  margin: 0 auto;
}
.book-aside { max-width: 760px; margin: 44px auto 0; }
.book-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 32px; border-bottom: 1px solid var(--line); }
.book-contact { margin-top: 36px; }
.book-aside .marker {
  display: flex;
  gap: 16px;
  padding: 20px 0;
  border-top: 1px solid var(--line);
}
.book-aside .marker .m-i {
  font-family: 'Fraunces', serif;
  font-style: italic;
  color: var(--clay);
  font-size: 20px;
  line-height: 1.2;
  flex-shrink: 0;
  width: 28px;
}
.book-aside .marker strong { display: block; font-family: 'Fraunces', serif; font-weight: 500; font-size: 18px; color: var(--ink); margin-bottom: 2px; }
.book-aside .marker span { font-size: 14px; color: var(--ink-soft); }
.book-aside a { color: var(--clay-deep); }

/* ============================================================
   FOOTER
   ============================================================ */
.footer { background: var(--forest-deep); color: rgba(246,242,233,0.6); padding: 64px 40px 40px; font-size: 13px; }
.footer-inner {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 56px;
  padding-bottom: 40px;
  border-bottom: 1px solid rgba(246,242,233,0.1);
}
.footer-brand {
  font-family: 'Fraunces', serif;
  font-size: 26px;
  color: var(--bone);
  margin-bottom: 14px;
  display: inline-block;
  text-decoration: none;
}
.footer-brand .italic { color: var(--clay-soft); font-style: italic; }
.footer-tagline { max-width: 320px; line-height: 1.6; }
.footer-col h4 {
  font-family: 'Manrope', sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--bone);
  margin-bottom: 18px;
}
.footer-col ul { list-style: none; }
.footer-col li { margin-bottom: 10px; line-height: 1.5; }
.footer-col a { color: rgba(246,242,233,0.6); text-decoration: none; transition: color 0.2s ease; }
.footer-col a:hover { color: var(--bone); }
.footer-bottom {
  max-width: var(--container);
  margin: 24px auto 0;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  font-size: 12px;
  /* 0.55, not 0.4. At 12px on --forest-deep the old alpha composited to
     #6e7970 = 3.42:1, below the 4.5:1 WCAG AA bar (Lighthouse, 2026-07-09).
     0.55 measures 5.18:1. The §13 contrast pass fixed --ink-muted on BONE and
     missed this bone-on-forest case. Do not lower it. */
  color: rgba(246,242,233,0.55);
  letter-spacing: 0.04em;
}

/* ============================================================
   SCROLL REVEAL
   ============================================================ */
/* Base reveal — quieter than before: a shorter rise (16px) over 0.7s, so body
   copy settles in rather than sliding the old uniform 24px/1s. */
.js .reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out); }
.js .reveal.in { opacity: 1; transform: translateY(0); }

/* The hero "arrives" more slowly and travels further — a curtain rising,
   the cinematic register of a luxury brand. The stagger is set in app.js.
   The .in rule below must be restated: the hidden-state selector here ties
   .js .reveal.in on specificity and follows it in source order, so without
   the restatement every hero reveal would stay parked 34px low forever. */
.js .hero .reveal,
.js .page-hero .reveal { transform: translateY(34px); transition-duration: 1.25s; }
.js .hero .reveal.in,
.js .page-hero .reveal.in { transform: translateY(0); }

/* Tier I — headlines reveal with a curtain wipe instead of joining the uniform
   fade-up (the home-hero headline keeps its own cinematic arrival above). The
   HIDDEN state is opacity-only — NO clip-path — so the IntersectionObserver
   still sees the element's full box and fires. (A clip-path hidden state zeroes
   the intersection ratio, so the reveal deadlocks: clipped because it isn't
   .in, and never .in because it's clipped.) The clip wipe runs as a one-shot
   animation on .in; negative insets clear descenders + the WONK overshoot. */
.js h2.reveal,
.js .page-hero h1.reveal {
  opacity: 0;
  transform: translateY(0.16em);
  transition: opacity 0.9s var(--ease-out), transform 1.05s var(--ease-out);
}
.js h2.reveal.in,
.js .page-hero h1.reveal.in {
  opacity: 1;
  transform: none;
  animation: headline-curtain 1.05s var(--ease-out) both;
}
@keyframes headline-curtain {
  from { clip-path: inset(-0.12em 0 100% 0); }
  to   { clip-path: inset(-0.12em 0 -0.2em 0); }
}

/* ============================================================
   LUXURY DETAILING
   ============================================================ */
/* Inline content links — refined clay rule, never default browser blue.
   Tier II: a resting clay-soft hairline for affordance, with a clay underline
   that draws in left-to-right on hover (animated background-size). Cloned per
   line fragment so wrapped links still draw correctly. */
p a, .lead a, .faq-a a {
  color: var(--clay-deep);
  text-decoration: none;
  padding-bottom: 1px;
  background-image:
    linear-gradient(var(--clay), var(--clay)),
    linear-gradient(var(--clay-soft), var(--clay-soft));
  background-repeat: no-repeat;
  background-position: 0 100%, 0 100%;
  background-size: 0 1px, 100% 1px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size 0.45s var(--ease-out), color 0.25s ease;
}
p a:hover, .lead a:hover, .faq-a a:hover { color: var(--clay); background-size: 100% 1px, 100% 1px; }
.bg-forest p a {
  color: var(--clay-soft);
  background-image:
    linear-gradient(var(--bone), var(--bone)),
    linear-gradient(rgba(200,149,109,0.5), rgba(200,149,109,0.5));
}
.bg-forest p a:hover { color: var(--bone); }

/* Secondary text-link: underline travels with a subtle arrow on hover. */
.btn-secondary { transition: opacity 0.2s ease, letter-spacing 0.3s var(--ease-out); }
.btn-secondary:hover { opacity: 1; color: var(--clay); border-bottom-color: var(--clay); letter-spacing: 0.16em; }
.btn-secondary.on-dark:hover { color: var(--bone); border-bottom-color: var(--bone); }

/* Inline "Discover →" style links keep the arrow gliding forward. */
.text-selection { }
::selection { background: var(--clay-pale); color: var(--ink); }

/* Tier I — ultra-soft hover lift. A large-blur, low-opacity shadow and a 3px
   rise on the card surfaces. The .js-prefixed transition ties with .js .reveal
   and wins on source order, so these cards animate BOTH their reveal (opacity/
   transform) and the hover (transform/shadow) on one declaration. :hover forces
   transition-delay to 0 (!important to beat the inline one-shot stagger delay),
   so the lift never lags. The discover-card has no surface of its own — its
   media-slot already runs the Ken-Burns zoom — so it lifts without a shadow. */
.js .pillar-card,
.js .testimonial { transition: transform 0.5s var(--ease-out), box-shadow 0.5s var(--ease-out), opacity 0.7s var(--ease-out); }
.js .discover-card { transition: transform 0.5s var(--ease-out), opacity 0.7s var(--ease-out); }
.pillar-card:hover, .testimonial:hover { transform: translateY(-3px); box-shadow: 0 26px 50px -34px rgba(31, 27, 20, 0.22); }
.testimonial.is-featured:hover { box-shadow: 0 0 0 1px var(--clay), 0 26px 50px -34px rgba(31, 27, 20, 0.22); }
.discover-card:hover { transform: translateY(-3px); }
.pillar-card:hover, .testimonial:hover, .discover-card:hover { transition-delay: 0s !important; }

/* ============================================================
   IMAGERY SCAFFOLD  (ready for the professional shoot)
   ------------------------------------------------------------
   Every photo lives in a ".media-slot" with a reserved aspect
   ratio, so dropping the real image in causes ZERO layout shift.
   To place a photo: replace the inner <div class="media-ph">…</div>
   with  <img src="assets/photos/NAME.jpg" alt="…">  (see SHOT-LIST.md).
   ============================================================ */
.media-slot {
  position: relative;
  background: var(--bone-deep);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
}
.bg-forest .media-slot { background: var(--forest-deep); border-color: rgba(246,242,233,0.15); }
.media-slot[data-ratio="4x5"]  { aspect-ratio: 4 / 5; }
.media-slot[data-ratio="3x4"]  { aspect-ratio: 3 / 4; }
.media-slot[data-ratio="1x1"]  { aspect-ratio: 1 / 1; }
.media-slot[data-ratio="3x2"]  { aspect-ratio: 3 / 2; }
.media-slot[data-ratio="16x9"] { aspect-ratio: 16 / 9; }
/* Only the real photo (a direct child) gets cover styling — not the small
   emblem inside the placeholder. */
/* <picture> is a WebP-delivery wrapper only — it must never affect layout.
   display:contents removes its box so the <img> keeps its grandparent as its
   containing block (height:100% resolves, floats and aspect-ratio still work).
   The <source> rule is NOT optional: display:contents promotes picture's
   children to the parent layout, and Chromium blockifies <source> into a real
   (empty) box there. Inside a grid that empty box became a grid item — on
   about.html it took the founder card's 320px portrait column and pushed the
   img + note into the wrong cells (HANDOFF §32). */
picture { display: contents; }
picture source { display: none; }

/* Descendant, NOT child (>). Photos are wrapped in <picture> for the WebP
   source, which would otherwise sit between .media-slot and the <img> and
   silently kill the object-fit and the hover lift. */
.media-slot img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1.2s var(--ease-out); }
.media-slot:hover img { transform: scale(1.04); } /* slow Ken-Burns lift, Belmond-style */

.media-ph {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 9px; text-align: center; padding: 24px;
}
.media-ph .ph-emblem { width: 34px; opacity: 0.30; margin-bottom: 2px; }
.bg-forest .media-ph .ph-emblem { filter: brightness(0) invert(1); opacity: 0.35; }
.media-ph .ph-label { font-size: 11px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--clay-deep); }
.bg-forest .media-ph .ph-label { color: var(--clay-soft); }
.media-ph .ph-desc { font-size: 12.5px; color: var(--ink-muted); max-width: 230px; line-height: 1.5; }
.bg-forest .media-ph .ph-desc { color: rgba(246,242,233,0.6); }
.media-ph .ph-file { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 10.5px; color: var(--ink-muted); opacity: 0.7; }
.bg-forest .media-ph .ph-file { color: rgba(246,242,233,0.45); }

/* ---- Full-bleed cinematic hero (pre-wired) ----
   ACTIVATE: add class "hero--media" to <section class="hero"> and set the
   image with a ROOT-ABSOLUTE url,
   e.g.  style="--hero-img:url('/assets/photos/hero-grand-tour.jpg')".
   It must be root-absolute: engines disagree on the base URL of a relative
   url() declared in a custom property (Chromium: this stylesheet; Firefox:
   the declaring document), so any relative path 404s in one of them
   (HANDOFF §31). Text flips to light over a forest-tinted scrim automatically. */
.hero--media { color: var(--bone); background-color: var(--forest-deep); }
.hero--media::before {
  content: ''; position: absolute; left: 0; top: -30%; z-index: 0;
  width: 100%; height: 160%;
  background-image: var(--hero-img); background-size: cover; background-position: center;
  transform: translateY(var(--hero-shift, 0px)); will-change: transform;
}
/* WebP hero, with the JPEG as the fallback (2026-07-09).
   hero-grand-tour: 186 KB JPEG -> 76 KB WebP, same 1920x1072.

   Why @supports rather than putting image-set() straight into --hero-img:
   custom properties are parsed as raw tokens, so a browser without image-set()
   would still ACCEPT the value, then fail at computed-value time and paint
   background-image: none. Gating on @supports means such a browser never sees
   it and keeps the plain --hero-img JPEG. Safari 16 and older land here; that
   is exactly today's behaviour, so there is no regression.

   index.html sets BOTH --hero-img (jpg) and --hero-img-set (image-set). */
@supports (background-image: image-set(url("x.webp") type("image/webp"))) {
  .hero--media::before { background-image: var(--hero-img-set, var(--hero-img)); }
}
/* Background video sits below the scrim (::after, z1) and content (z2).
   The forest-deep fallback above keeps light text legible before it paints. */
.hero-video {
  position: absolute; left: 0; top: -30%; z-index: 0;
  width: 100%; height: 160%; object-fit: cover;
  transform: translateY(var(--hero-shift, 0px)); will-change: transform;
}
/* Honour reduced-motion: drop the video, keep the dark scrim. */
@media (prefers-reduced-motion: reduce) {
  .hero-video { display: none; }
}
/* Horizontal scrim stops were 0.88 / 0.72 / 0.34 (§15a). Deepened on the TEXT
   side so the clay-soft em ("you're failing.") clears the 3:1 large-text bar on
   the BRIGHTEST pixels behind its glyphs, not merely on average.

   Measured against a glyph-free render (the page re-rendered with
   `.hero-inner { visibility: hidden }`, so no antialiased letter edges pollute
   the background sample — that mistake produced a bogus 2.13:1 first time):

       em bounding box     median   p90    p99    MAX
       0.88 / 0.72 (old)    4.03    3.41   3.15   2.97  <- MAX fails
       0.93 / 0.84 (now)    4.78    4.35   4.18   4.03  <- passes throughout
       bone headline, same box: 7.08 -> 9.43 at MAX (also improved)

   The 100% stop stays 0.34: the em ends at ~51% of the hero width, so the
   right-hand side — the counter, the olive branch, the window light — is
   untouched. Do not flatten these three stops into one value. */
.hero--media::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(180deg, rgba(20,40,32,0) 42%, rgba(20,40,32, var(--veil, 0.08)) 100%),
    linear-gradient(90deg, rgba(20,40,32,0.93) 0%, rgba(20,40,32,0.84) 55%, rgba(20,40,32,0.34) 100%);
}
/* ---- HERO PARALLAX — compositor path ----
   app.js drives --hero-shift from scroll events, but that runs on the main
   thread and visibly stutters against native momentum scrolling on phones.
   Where the browser supports scroll-driven animations (Chrome 115+, Safari
   26+), this animation takes over the same transform on the compositor —
   pixel-synced with the scroll — and the JS-set var is simply outranked by
   the cascade (animations beat declarations). Slope matches the JS (0.3×
   scroll); past a short hero the range only overshoots after the hero has
   left the viewport, so the 30% overscan never runs out on screen. */
@supports (animation-timeline: scroll()) {
  .hero--media::before,
  .hero-video,
  .page-hero--media .ph-media {
    animation: hero-parallax linear both;
    animation-timeline: scroll(root);
    animation-range: 0svh 100svh;
  }
}
@keyframes hero-parallax {
  from { transform: translateY(0); }
  to { transform: translateY(30svh); }
}

.hero--media h1.hero-headline { color: var(--bone); }
/* Measured exception to the §18 accent lock — and NOT the same colour as the
   system.html photo hero, deliberately.
   "you're failing." sits on hero-grand-tour.jpg. Sampling the rendered pixels
   behind the glyphs at 1300x900 (reduced-motion forced so the headline paints):
       clay      2.85:1 median, 2.39:1 over the brighter area   FAIL (needs 3:1)
       clay-soft 3.99 / 3.34                                    PASS  <- shipped
       clay-pale 7.99 / 6.69                                    PASS, but reads
                                                                as bone; the
                                                                accent vanishes
   Bone reference on the same hero: 9.40 / 7.87.
   The hero scrim was then deepened (see `.hero--media::after`) so clay-soft
   also clears 3:1 on the brightest background pixel: 2.97 -> 4.03.
   This hero's scrim is dark, so clay-soft clears the bar AND keeps the orange.
   system.html's hero is bright behind its em, where clay-soft measures only
   1.98:1 — hence --clay-pale there. Two photo heroes, two colours, both
   measured. Do not "unify" them. */
.hero--media h1.hero-headline em { color: var(--clay-soft); }
.hero--media .hero-sub { color: rgba(246,242,233,0.88); }
.hero--media .eyebrow { color: rgba(246,242,233,0.75); }
.hero--media .eyebrow::after { background: rgba(246,242,233,0.5); }
.hero--media .hero-emblem { filter: brightness(0) invert(1); opacity: 0.95; }
.hero--media .trust { border-top-color: rgba(246,242,233,0.28); }
.hero--media .trust-item { color: rgba(246,242,233,0.8); }
.hero--media .trust-item strong { color: var(--bone); }
.hero--media .btn-secondary { color: var(--bone); border-bottom-color: var(--bone); }
/* The hero CTA was forest-on-forest: the default .btn-primary (forest) sat on
   the forest-tinted hero scrim at 1.26:1 against its own background — a button
   you could barely see. Clay is the brand's only accent and reads 3.35–4.21:1
   against that scrim. Label is INK (4.65:1), never bone (3.30:1, fails AA).
   Hover goes to clay-soft, which keeps the ink label at 6.51:1. */
.hero--media .btn-primary { background: var(--clay); color: var(--ink); }
.hero--media .btn-primary:hover { background: var(--clay-soft); color: var(--ink); }

/* ---- Editorial discover-card row (Belmond "1 of 5" pattern) ---- */
.discover-cards {
  margin-top: 64px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.discover-card { text-decoration: none; display: flex; flex-direction: column; height: 100%; }
.discover-card .media-slot { margin-bottom: 22px; }
.discover-card .dc-eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--clay); display: block; margin-bottom: 10px;
}
.discover-card h3 { font-size: 24px; margin-bottom: 12px; transition: color 0.25s ease; }
.discover-card p { font-size: 15px; line-height: 1.6; color: var(--ink-soft); margin-bottom: 16px; }
.discover-card .dc-cta {
  margin-top: auto; align-self: flex-start;
  font-size: 12px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink); border-bottom: 1px solid var(--clay); padding-bottom: 3px;
  transition: letter-spacing 0.3s var(--ease-out), color 0.25s ease;
}
.discover-card:hover h3 { color: var(--clay-deep); }
.discover-card:hover .dc-cta { letter-spacing: 0.18em; color: var(--clay-deep); }

/* ---- Asymmetric gallery cluster (Belmond Grand Suites pattern) ---- */
.gallery { margin-top: 8px; display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center; }
.gallery-cluster { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; gap: 20px; }
.gallery-cluster .media-slot:first-child { grid-column: 1 / 2; grid-row: 1 / 3; align-self: start; }
.gallery-cluster .media-slot:nth-child(2) { margin-top: 48px; }
.gallery-text h2 { margin-bottom: 24px; }

/* ============================================================
   MOBILE STICKY ACTION BAR  (Tier II — injected by app.js)
   Shown only <=980px, and only after the hero scrolls away. Hidden
   entirely on book.html (the visitor is already booking).
   ============================================================ */
.mobile-cta-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-bar);
  display: none;
  align-items: center; gap: 12px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  background: rgba(246, 242, 233, 0.94);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-top: 1px solid var(--line);
  transform: translateY(110%);
  visibility: hidden;
  transition: transform 0.45s var(--ease-out), visibility 0.45s;
}
.mobile-cta-bar.show { transform: translateY(0); visibility: visible; }
.mobile-cta-bar .mcb-call {
  flex: 0 0 auto;
  font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink); text-decoration: none;
  padding: 13px 20px; border: 1px solid var(--line); border-radius: 2px;
}
.mobile-cta-bar .mcb-book {
  flex: 1 1 auto; text-align: center;
  font-size: 13px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  /* Ink on clay — see the .cta-band note (AA: 4.65:1, not bone's 3.30:1). */
  color: var(--ink); background: var(--clay); text-decoration: none;
  padding: 14px 20px; border-radius: 2px;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 980px) {
  .nav-links, .nav-right .nav-cta { display: none; }
  .nav-toggle { display: flex; }
  .nav { padding: 14px 20px; }
  .mobile-cta-bar { display: flex; }
  /* Reserve clearance so the fixed action bar never covers the last content
     (the footer credential row). The clearance lives INSIDE the footer rather
     than as body padding, so no bone strip shows beneath the forest footer
     while the bar is hidden (owner review, 2026-07-06). Only pages that inject
     the bar carry the class, so book.html — which has no bar — keeps its
     natural bottom. */
  .has-cta-bar .footer { padding-bottom: calc(40px + 74px + env(safe-area-inset-bottom, 0px)); }

  /* Mobile size-down pass (2026-07-02, per owner review): the whole register
     steps down ~30% below 980px — headlines, leads, buttons, and section
     rhythm — so phones and landscape phones read like a site designed for the
     screen (Apple/Kinfolk mobile scale), not a shrunken desktop. Desktop
     (>980px) is untouched. */
  .section { padding: 64px 20px; }
  .section.tight { padding: 52px 20px; }
  .hero { padding: 116px 20px 60px; }
  .page-hero { padding: 108px 20px 44px; }

  h1.hero-headline { font-size: clamp(32px, 5vw, 46px); margin-bottom: 28px; }
  .page-hero h1 { font-size: clamp(30px, 4.6vw, 42px); margin-bottom: 24px; }
  h2 { font-size: clamp(26px, 3.8vw, 36px); margin-bottom: 24px; }
  h3 { font-size: 22px; }
  .lead { font-size: 18px; margin-bottom: 22px; }
  .hero-sub { font-size: 17px; margin-bottom: 36px; }
  .hero-emblem { width: 42px; margin-bottom: 24px; }
  .trust { margin-top: 56px; }
  .trust-item strong { font-size: 22px; }
  .founder-quote { font-size: 19px; }
  .founder-portrait { max-width: 220px; }
  .faq-q { font-size: 19px; padding: 20px 0; }
  .faq-q::after { font-size: 24px; }
  .btn-primary { padding: 16px 30px; }
  .cta-band .btn-primary { padding: 18px 42px; }
  .calc-output .out-price { font-size: clamp(44px, 7vw, 56px); }
  .price-fig { font-size: clamp(34px, 4.5vw, 40px); }
  .book-steps { grid-template-columns: 1fr; gap: 0; }

  .trust { grid-template-columns: repeat(2, 1fr); gap: 28px; }
  .math-grid { grid-template-columns: 1fr; gap: 36px; }
  .pillars { grid-template-columns: 1fr; gap: 48px; }
  .pillar-cards { grid-template-columns: 1fr; }
  .steps { grid-template-columns: 1fr; gap: 40px; }
  .calc { grid-template-columns: 1fr; }
  .calc-controls { border-right: none; border-bottom: 1px solid var(--line); }
  .extras-grid { column-count: 2; column-gap: 48px; }
  .cards-3 { grid-template-columns: 1fr; }
  .founder-card { grid-template-columns: 1fr; gap: 36px; padding: 40px 28px; text-align: left; }
  .footer-inner { grid-template-columns: 1fr 1fr; gap: 36px; }
  .failure-item { grid-template-columns: 1fr; gap: 12px; padding: 32px 0; }
  .cta-band { padding: 76px 20px; }

  .discover-cards { grid-template-columns: 1fr; gap: 44px; }
  .gallery { grid-template-columns: 1fr; gap: 36px; }
  .gallery-cluster .media-slot:nth-child(2) { margin-top: 0; }
  /* Mobile scrim is measured, like the desktop one above (§28/§29 method).
     At 0.55/0.78 the clay-soft em sampled 2.48:1 median, 2.20:1 at its worst
     pixel against the 3:1 large-text bar (Moto G emulation, glyph-free render
     — scripts/measure-mobile-contrast.mjs). The em sits ~35% down this
     gradient, so the upper stop is what matters. Still lighter than the
     desktop text-side stops (0.93/0.84). Do not lighten without re-measuring. */
  .hero--media::after { background: linear-gradient(180deg, rgba(20,40,32,0.72) 0%, rgba(20,40,32,0.86) 100%); }
  .page-hero--media::after { background: linear-gradient(180deg, rgba(20,40,32,0.62) 0%, rgba(20,40,32,0.82) 100%); }
  .page-hero--media .ph-media-mark { display: none; }
}

@media (max-width: 560px) {
  body { font-size: 16px; line-height: 1.65; }
  .hero-actions { gap: 18px; }

  /* Phone rhythm — the register steps down again so a section fits a screen
     and reading doesn't demand a scroll per sentence. */
  .section { padding: 48px 20px; }
  .section.tight { padding: 38px 20px; }
  .hero { padding: 96px 20px 44px; }
  .page-hero { padding: 92px 20px 32px; }
  .cta-band { padding: 56px 20px; }
  .trust { margin-top: 36px; gap: 20px; padding-top: 24px; }
  .math-grid { margin: 40px 0 24px; padding: 32px 0; gap: 26px; }
  .pillar-cards { margin-top: 32px; }
  .discover-cards, .steps { margin-top: 32px; }

  h1.hero-headline { font-size: 30px; line-height: 1.14; margin-bottom: 22px; }
  .page-hero h1 { font-size: 27px; margin-bottom: 18px; }
  h2 { font-size: 25px; margin-bottom: 16px; }
  h3 { font-size: 19px; margin-bottom: 12px; }
  .lead { font-size: 16.5px; margin-bottom: 18px; }
  .hero-sub { font-size: 16px; margin-bottom: 28px; }
  p { margin-bottom: 16px; }
  .section-label { margin-bottom: 18px; }
  .eyebrow { margin-bottom: 20px; }
  .hero-emblem { width: 36px; margin-bottom: 18px; }
  .trust-item strong { font-size: 19px; }
  .faq-q { font-size: 18px; padding: 18px 0; }

  /* Founder card: the portrait sits beside the note (floated, text wrapping
     around it) instead of commanding a full screen of vertical space. */
  .founder-card { display: block; padding: 26px 22px; }
  .founder-card::after { content: ''; display: block; clear: both; }
  .founder-portrait { float: left; width: 128px; margin: 4px 18px 10px 0; }
  .founder-quote { font-size: 17px; line-height: 1.55; }

  /* The eyebrow's trailing hairline only floats awkwardly once the label wraps
     on a narrow screen — drop it and let the words stand alone. */
  .eyebrow::after { display: none; }

  /* Footer: brand banner full-width on top, the two short link lists paired
     two-up, and Contact on its own full-width row so the email address has room
     to sit on one line. min-width:0 lets the paired columns share 1fr evenly
     (otherwise the longest place name would force them lopsided). */
  .footer-inner { grid-template-columns: 1fr 1fr; gap: 30px 24px; }
  .footer-inner > * { min-width: 0; }
  .footer-inner > div:first-child { grid-column: 1 / -1; }
  .footer-inner > .footer-col:last-child { grid-column: 1 / -1; }

  .calc-controls, .calc-output { padding: 32px 26px; }
  .extras-grid { column-count: 1; }

  /* Rate card: tighter cells and a shorter min-width so fewer swipes reach the
     last frequency (the tier column is pinned, so context never scrolls away). */
  table.price-table { min-width: 580px; }
  .price-table th, .price-table td { padding: 13px 12px; font-size: 14px; }

  /* Tier II — designed mobile gallery: one full-width lead image over a
     paired row of two, instead of the desktop tall-left composition. */
  .gallery-cluster { grid-template-columns: 1fr 1fr; gap: 12px; }
  .gallery-cluster .media-slot:first-child { grid-column: 1 / -1; grid-row: auto; aspect-ratio: 4 / 3; }
  .gallery-cluster .media-slot:nth-child(2) { margin-top: 0; }
}

/* ============================================================
   SHORT VIEWPORTS (landscape phones)
   With ~390px of height, a fixed header + a sticky action bar + the browser
   chrome leave no room to read. The nav scrolls away with the page and the
   action bar stays out entirely — the content gets the full height.
   ============================================================ */
@media (max-width: 980px) and (max-height: 520px) {
  .nav { position: absolute; }
  .mobile-cta-bar { display: none; }
  body.has-cta-bar { padding-bottom: 0; }
  /* No bar here, so the footer sheds the clearance and keeps its natural 40px. */
  body.has-cta-bar .footer { padding-bottom: 40px; }
  .hero { padding-top: 88px; }
  .page-hero { padding-top: 84px; }
}

/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .js h2.reveal, .js .page-hero h1.reveal { opacity: 1; transform: none; animation: none; clip-path: none; }
  /* Scroll-driven animations ignore animation-duration, so the parallax must
     be switched off explicitly (the JS path already gates on reduced-motion). */
  .hero--media::before, .hero-video, .page-hero--media .ph-media { animation: none; transform: none; }
}
