/* ==========================================================================
   THE WEALTH SCHOOL · site.css — shared chrome for the section pages.
   Component styles (nav, pills, footer, Knock form, section furniture) for the
   NEW pages Home + the seven sections. Reads ALL colour/type/motion from
   tokens.css (the design lock) — never hard-codes a hue. The approved
   index.html keeps its own inline copy; both read the same tokens, so nothing
   can drift. Consolidate the two into one later (see RESUME).
   ========================================================================== */

*{box-sizing:border-box}
/* text-size-adjust: without it iOS Safari "helpfully" inflates text it deems
   small — by its own heuristic, per block — so the phone renders sizes the
   emulator never shows. Every size on this site is deliberate (the 11px floor
   in tokens.css is the legibility answer); Safari must not re-decide them. */
html{scroll-behavior:smooth; -webkit-text-size-adjust:100%; text-size-adjust:100%}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0; background:var(--ground-1); color:var(--ink);
  font-family:var(--font-body); font-size:16px; line-height:var(--lh-body);
  letter-spacing:-.003em; font-weight:450;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  transition:background var(--dur-theme) ease, color var(--dur-theme) ease;
  overflow-x:hidden;
}
/* -- what may be selected (U3) --
   user-select:none used to sit on <body>, which stopped a visitor long-pressing
   to copy ANY prose: the Montreux address, the contact line, faculty names,
   quotes, PDF titles. On a phone that is the normal way to take something with
   you, and it silently did nothing. The rule exists to keep the CHROME from
   selecting — dragging a nav label or a pill during a swipe looks broken — so it
   is scoped to the chrome. <main> prose is selectable, which is the default a
   reader expects. Anything added outside main that is furniture, not text,
   belongs in this list. */
header.nav, .nav-sheet, .subnav, .nav-backdrop, footer.site, .pill, .tgl{
  -webkit-user-select:none; user-select:none;
}
input, textarea{-webkit-user-select:text; user-select:text}
::selection{background:var(--accent); color:var(--ground-0)}
a{color:inherit} img{max-width:100%}
[tabindex="-1"]:focus{outline:none}

/* ---- shared type ---- */
.eyebrow{font-family:var(--font-mono); font-size:var(--fs-eyebrow);
  letter-spacing:var(--tracking-eyebrow); text-transform:uppercase; color:var(--accent); font-weight:500}
.display{font-family:var(--font-display); font-weight:700; font-optical-sizing:none;
  font-variation-settings:'opsz' 30,'wght' 700; line-height:1.06; letter-spacing:-.008em; text-wrap:balance}
.serif-it{font-family:var(--font-display); font-style:italic; font-weight:600;
  font-optical-sizing:none; font-variation-settings:'opsz' 24,'wght' 600; text-wrap:pretty}
.mono{font-family:var(--font-mono)}
.muted{color:var(--ink-mut)}
/* -- the two accent highlights (2026-07-21 V3) --
   Inline phrases the client marked "highlight in TWS orange / lime". They use the
   -text tones, not the fills: the fills are button colours and #CCFF00 as type on
   parchment is invisible — the -text pair is the AA-safe voice of each accent. */
.hl-ember{color:var(--ember-text)}
.hl-lime{color:var(--lime-text)}
/* mint, the third of the three core highlight voices (2026-07-22 V4: "only 3 core
   highlight colours: mint, orange, lime"). Uses --accent, the site's mint. */
.hl-mint{color:var(--accent)}
/* -- the lime rule (2026-07-21 V3) --
   "A splitting lime line after the first paragraph" — a short horizontal accent
   that closes a page's opening thought. Same principle on every page: it follows
   the FIRST paragraph of the page's own copy, nothing else. An <hr> so it still
   reads as a divider with styles off. */
hr.lime-rule{width:64px; height:2px; margin:26px 0; border:0; border-radius:2px;
  background:var(--lime-text)}
/* -- "Back to the overview" (2026-07-21 V3) --
   One voice for every back-link. It was styled only inside .stub, so the pages
   that outgrew their stubs (Library, Legal) fell back to default underlined blue
   — the "inconsistent Back to overview" of the client's note. Global now. */
a.back{font-family:var(--font-mono); font-size:var(--fs-label-lg); letter-spacing:var(--tracking-label-lg);
  text-transform:uppercase; color:var(--accent); text-decoration:none}
a.back:hover{text-decoration:underline}

/* ---- layout ---- */
.wrap{width:var(--wrap); margin-inline:auto}
section{position:relative}
main{display:block}

/* ---- pills / buttons ----
   EVERY button on the site is uppercase mono (ruled on the 2026-07-17 call: the
   buttons were to look consistent with one another — the overture's SKIP INTRO
   set the standard, so STEP INSIDE, KNOCK, and the Life Read pill match it). If you
   add a button, it wears .pill — do not hand-roll a sentence-case one. */
.pill{display:inline-flex; align-items:center; gap:.55em; border-radius:var(--radius-pill);
  font-family:var(--font-mono); font-weight:600; font-size:.74rem; letter-spacing:.16em;
  text-transform:uppercase; padding:1em 1.6em; cursor:pointer;
  border:1px solid transparent; text-decoration:none; line-height:1;
  /* A button label never wraps. Uppercase + tracking widened these, and as a flex
     item a pill will happily shrink below its content and break "KNOCK ON THE
     DOOR" onto two lines. nowrap + flex:none keeps every pill one line. */
  white-space:nowrap; flex:none;
  transition:transform .25s var(--ease), background .3s, border-color .3s, color .3s}
.pill:focus-visible{outline:2px solid var(--accent); outline-offset:3px}
.pill-cta{background:var(--cta); color:var(--cta-ink)}
.pill-cta:hover{transform:translateY(-2px)}
.pill-ghost{background:transparent; color:var(--ink); border-color:var(--line)}
.pill-ghost:hover{border-color:var(--accent); color:var(--accent)}
.pill-sm{font-size:.66rem; letter-spacing:.14em; padding:.72em 1.15em}
/* A button label is the last thing that may be unreadable, and .66rem is 10.56px
   — under the 11px phone floor the label tier answers to (T3). Buttons keep their
   OWN tracking (.14em, the button voice) so only the size is floored. Safe on
   width: .foot-cta wraps, and the nav's pill-sm only exists at >=1280px where the
   floor is inert. Same media as the token floor — see tokens.css for why coarse. */
@media (max-width:600px), (pointer:coarse){ .pill-sm{font-size:max(.66rem, 11px)} }

/* the two CTA voices — lime opens The Life Read, ember knocks. Never swap them. */
.pill-lime{background:var(--lime); color:var(--lime-ink); border-color:var(--lime)}
.pill-lime:hover{background:var(--lime-hover); border-color:var(--lime-hover); transform:translateY(-2px)}
.pill-lime:focus-visible{outline-color:var(--lime)}
.pill-ember{background:var(--ember); color:var(--ember-ink); border-color:var(--ember)}
.pill-ember:hover{background:var(--ember-hover); border-color:var(--ember-hover); transform:translateY(-2px)}
.pill-ember:focus-visible{outline-color:var(--ember)}

/* ============================================================ NAV */
/* 2026-07-26 — THE STICKY HEADER NEVER STUCK. Found by the live QA sweep, and it
   had been true on all nine injected pages for as long as the injection has
   existed: `header.nav` is position:sticky, but sticky is clamped to its
   CONTAINING BLOCK, and site-chrome.js renders the whole nav inside the page's
   `<div data-site-nav>` host — a box only as tall as nav + sub-nav (measured
   114px). So the header stuck for 114px and then scrolled away for good: past
   that point The Library offered ~15 phone screens with no nav, no logo, no theme
   toggle and no burger. Only theory.html escaped it, because that page hard-codes
   its nav as a direct child of <body> — which is exactly why it was never noticed.
   display:contents removes the host box from the layout tree without touching the
   markup contract, so the header's containing block becomes the body and sticky
   means what it says. The host is a pure wrapper — nothing styles it, nothing
   measures it — so it has no box worth keeping. */
[data-site-nav]{display:contents}
header.nav{position:sticky; top:0; z-index:60;
  backdrop-filter:blur(14px) saturate(1.2); -webkit-backdrop-filter:blur(14px) saturate(1.2);
  background:color-mix(in srgb, var(--ground-1) 78%, transparent);
  border-bottom:1px solid var(--line-2)}
.nav-in{display:flex; align-items:center; gap:20px; height:64px}
.brand{display:flex; flex-direction:column; line-height:1.05; text-decoration:none}
.brand b{font-family:var(--font-mono); font-size:.74rem; letter-spacing:.22em; font-weight:600}
.brand span{font-size:.64rem; letter-spacing:.14em; color:var(--ink-mut); font-family:var(--font-mono); white-space:nowrap}
/* Wealth School wordmark (from thewealthschool.ch). Mono PNG painted via mask in the
   theme ink colour, so it's off-white on nocturne and dark-teal on meridian.
   2026-07-25 (V7): 40→48px (34→40 on phones) — client: "Enlarge the logo on all
   the pages". At 1596/1032 that widens the mark ~12px (62→74px); the desktop bar
   still fits at its 1280px breakpoint — verified in-browser at 1290px (see the
   width note below the nav-links rule). */
.brand-logo{display:block; height:48px; aspect-ratio:1596/1032; background-color:var(--ink);
  -webkit-mask:url("logo-light.png") left center/contain no-repeat;
          mask:url("logo-light.png") left center/contain no-repeat;
  transition:background-color .3s var(--ease,ease)}
@media (max-width:600px){ .brand-logo{height:40px} }
/* The seven section labels are long ("Research and Standards", "Stewardship
   Commons") — together they measure ~890px. Brand + links + toggle + the Knock
   pill needed ~1202px inside a .wrap that CAPS at 1200: the row never actually
   fit. It only looked like it did because the pill (no nowrap, shrinkable) was
   quietly collapsing onto two lines to absorb the overflow — the reported bug.
   Now the pill can't shrink, so the row is tightened and the desktop nav starts
   only where it genuinely fits (see the breakpoint below). */
.nav-links{display:none; gap:18px; margin-left:auto; align-items:center}
.nav-links a{font-size:.82rem; color:var(--ink-mut); text-decoration:none; position:relative; padding:4px 0; white-space:nowrap}
.nav-links a:hover{color:var(--ink)}
.nav-links a::after{content:''; position:absolute; left:0; bottom:-2px; height:1px; width:0; background:var(--accent); transition:width .3s}
.nav-links a:hover::after,.nav-links a.active::after{width:100%}
.nav-links a.active{color:var(--ink)}
.nav-tools{display:flex; align-items:center; gap:10px; margin-left:auto}
.tgl{width:40px; height:40px; display:grid; place-items:center; border-radius:var(--radius-pill);
  border:1px solid var(--line); background:transparent; color:var(--ink); cursor:pointer; transition:border-color .3s, color .3s}
.tgl:hover{border-color:var(--accent); color:var(--accent)}
.tgl:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
/* 2026-07-26: the open state drew a ">" chevron, not an X ("the arrow in the
   burger menu kinda breaks").
   It was display:grid. Three spans with no explicit rows become three IMPLICIT
   auto rows, and align-content's initial `normal` behaves as `stretch` — so the
   rows shared the button's full 44px and each bar was centred in its own ~15px
   band. Measured: the bar centres sat 15.3px apart, not the 5.7px the transforms
   below are built from (bar height 1.7 + the 4px margin). translateY(5.7px) then
   closed the gap only to 9.6px, so the two rotated bars met at their ends
   instead of crossing at the middle — a chevron. It also made the closed icon
   30.6px tall inside a 44px button.
   Flex column: the bars stack on their own box heights, centre-to-centre is
   exactly 5.7px, and the ±45° transforms land on a true X. If you change the bar
   height or the 4px margin, change the 5.7px translate to match (it is
   height + margin). */
.nav-burger{display:flex; flex-direction:column; align-items:center; justify-content:center;
  width:44px; height:44px; border-radius:12px;
  border:1px solid var(--line); background:transparent; color:var(--ink); cursor:pointer; padding:0}
.nav-burger span{display:block; width:18px; height:1.7px; border-radius:2px; background:currentColor; flex:none;
  transition:transform .25s var(--ease), opacity .18s}
.nav-burger span + span{margin-top:4px}
.nav-burger.is-open span:nth-child(1){transform:translateY(5.7px) rotate(45deg)}
.nav-burger.is-open span:nth-child(2){opacity:0}
.nav-burger.is-open span:nth-child(3){transform:translateY(-5.7px) rotate(-45deg)}
/* THE SHEET MUST SCROLL. It is position:fixed and, while it is open, the page
   behind it is locked (wireBurger sets html{overflow:hidden}) — so anything that
   does not fit on screen had NO way to be reached: not by scrolling the sheet
   (it had no overflow) and not by scrolling the page (locked). The sheet's
   content is a fixed ~700px — seven sections, Wealth Stewardship's three
   children, and the two pills — so EVERY viewport under ~700px tall silently ate
   the bottom of the menu. A landscape phone lost six items including The Library;
   a 375×667 SE lost The Life Read. That is the reported "stuck clicking on
   library": the link was really not there.
   max-height + overflow-y is the whole fix. dvh (not vh) because mobile Safari's
   toolbar makes vh lie — the same reason the overture uses it. overscroll-behavior
   keeps a flick at the end of the list from chaining to the locked page. */
.nav-sheet{position:fixed; left:0; right:0; top:64px; z-index:59; display:flex; flex-direction:column;
  padding:8px clamp(16px,5vw,24px) 22px; gap:2px;
  max-height:calc(100dvh - 64px); overflow-y:auto; -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  background:color-mix(in srgb, var(--ground-1) 96%, transparent);
  backdrop-filter:blur(16px) saturate(1.2); -webkit-backdrop-filter:blur(16px) saturate(1.2);
  border-bottom:1px solid var(--line);
  transform:translateY(-12px); opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .26s ease, transform .26s ease, visibility .26s}
/* the sheet is the scroller now — it must also respect the home indicator */
.nav-sheet{padding-bottom:max(22px, env(safe-area-inset-bottom))}
.nav-sheet.open{transform:none; opacity:1; visibility:visible; pointer-events:auto}
.nav-sheet a{min-height:48px; display:flex; align-items:center; gap:.5em; padding:6px 6px;
  color:var(--ink); text-decoration:none; font-size:1.06rem; border-bottom:1px solid var(--line-2)}
.nav-sheet a:hover,.nav-sheet a.active{color:var(--accent)}
.nav-sheet a.pill-cta,.nav-sheet a.pill-lime,.nav-sheet a.pill-ember{justify-content:center; border-bottom:0; margin-top:10px}
/* These -ink colours MUST be restated here. `.nav-sheet a` (0,1,1) outranks
   `.pill-lime` (0,1,0), so without this the sheet's lime pill renders in --ink
   (cream) on #CCFF00 — 1.03:1, i.e. invisible. Caught by the contrast probe. */
.nav-sheet a.pill-cta{color:var(--cta-ink)}
.nav-sheet a.pill-lime{color:var(--lime-ink)}
.nav-sheet a.pill-ember{color:var(--ember-ink)}
/* The two asks (Knock / The Life Read) sat as two full-width stacked pills — they
   dominated the open menu (2026-07-20 V2 review). Now a side-by-side row at
   pill-sm scale — and that scale must be RESTATED here, exactly like the -ink
   colours above: `.nav-sheet a` (0,1,1) outranks `.pill-sm` (0,1,0), so without
   this the labels rendered at the sheet's 1.06rem and its 6px padding. At 1.06rem
   the two nowrap labels are wider than the row; `flex:1 1 0; min-width:0` then
   shrank each pill to half the row anyway, and KNOCK ON THE DOOR ran clear across
   THE LIFE READ (2026-07-20 iPhone report — real Safari, portrait, mid-menu).
   The flex model is the second half of the fix: a pill may never shrink below its
   own label. Basis auto keeps min-width:auto in force, and the row wraps — side
   by side where the two fit, stacked where they do not. */
.nav-sheet .sheet-cta{display:flex; flex-wrap:wrap; gap:10px; margin-top:16px}
.nav-sheet .sheet-cta a.pill{flex:1 1 auto; margin-top:0; justify-content:center; text-align:center;
  font-size:.66rem; letter-spacing:.14em; padding:.72em 1.15em}
/* the same 11px handheld floor .pill-sm answers to — see tokens.css for why coarse */
@media (max-width:600px), (pointer:coarse){ .nav-sheet .sheet-cta a.pill{font-size:max(.66rem, 11px)} }
/* Wealth Stewardship's three children, shown INSIDE the burger (2026-07-17 call).
   They were previously top-bar-only, so a phone visitor could open the section
   and never learn The Theory / The Instrument existed. Rendered always-open
   rather than as a dropdown: the complaint was discovery, and a collapsed list
   hides exactly what she asked to reveal. */
.nav-sheet .sub-list{display:flex; flex-direction:column; margin:0 0 2px 14px;
  border-left:1px solid var(--line); padding-left:12px}
.nav-sheet .sub-list a{min-height:44px; font-family:var(--font-mono); font-size:var(--fs-label-lg);
  letter-spacing:var(--tracking-label-lg); text-transform:uppercase; color:var(--ink-mut); border-bottom:0}
.nav-sheet .sub-list a:hover,.nav-sheet .sub-list a.active{color:var(--accent)}
.nav-backdrop{position:fixed; inset:64px 0 0 0; z-index:58; opacity:0; visibility:hidden;
  background:color-mix(in srgb, var(--ground-0) 55%, transparent); transition:opacity .26s, visibility .26s}
.nav-backdrop.open{opacity:1; visibility:visible}
.nav-cta{display:none}
/* 1280, not 960: below this the 7-link row + Knock pill cannot fit without
   squashing something (measured — see .nav-links above). The burger now carries
   the full section list AND Wealth Stewardship's children, so narrower laptops
   and tablets get a complete menu rather than a broken row. */
@media(min-width:1280px){ .nav-burger, .nav-sheet, .nav-backdrop{display:none} .nav-links{display:flex} .nav-cta{display:inline-flex} }

/* ============================================================ SECTION SUB-NAV (Wealth Stewardship etc.) */
/* The bronze "WEALTH STEWARDSHIP" label that used to lead this row is GONE
   (2026-07-17 call): on a 375px phone it ate the width and pushed THE INSTRUMENT
   off-screen — the third item was simply unreachable. The page eyebrow
   ("Wealth Stewardship · The Definition") already says which section you are in,
   so the label was duplicating orientation at the cost of navigation.
   The active item now also takes ACCENT COLOUR, not just the hairline: the
   underline alone was too quiet to answer "where am I". */
.subnav{border-bottom:1px solid var(--line-2); background:color-mix(in srgb,var(--ground-1) 60%,transparent)}
.subnav-in{display:flex; gap:clamp(16px,5vw,26px); align-items:stretch; height:48px; overflow-x:auto; scrollbar-width:none}
.subnav-in::-webkit-scrollbar{display:none}
/* Three constraints meet in this row and one had to give: a 44px tap target (M2),
   an 11px label floor (T3), and THE INSTRUMENT reaching the end of a 375px screen
   (the 07-17 pass). The floor is what pushed it over — at 11px the row ended at
   378.6px on an SE. Legibility does not give, so the GUTTER does: 13px buys 7.9px
   of room at 375 and the row still reads as three separated items. Phone only —
   above 600px there was never a shortage. */
@media (max-width:600px){ .subnav-in{gap:13px} }
/* The row is 48px tall but the links were `padding:2px 0` — a ~20px hit target,
   less than half the 44px minimum, in exactly the place the 07-17 pass worked to
   make discoverable. The links now STRETCH to fill the row (align-items:stretch
   above), so the whole 48px band is tappable; the underline is pinned to the
   text with a pseudo-element instead of the box, so a taller target does not
   drag the active rule down with it. */
/* This row is the site's tightest width constraint: three uppercase mono items,
   the longest being THE INSTRUMENT, must all reach the end of a 375px screen —
   the 07-17 pass deleted a bronze section label to buy that room. So it takes
   the MIDDLE step, not label-lg: measured in WebKit, .72rem ends at 376.5px on a
   375px SE and clips whatever the tracking. Do not promote it a step. */
.subnav a{display:inline-flex; align-items:center; position:relative; min-height:44px;
  font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:var(--tracking-label); text-transform:uppercase;
  color:var(--ink-mut); text-decoration:none; white-space:nowrap;
  transition:color .25s}
.subnav a::after{content:''; position:absolute; left:0; right:0; bottom:12px; height:1px; background:transparent}
.subnav a:hover{color:var(--ink)}
.subnav a.active{color:var(--accent)}
.subnav a.active::after{background:var(--accent)}
.subnav a:focus-visible{outline:2px solid var(--accent); outline-offset:-4px; border-radius:6px}

/* ============================================================ ONE PORTRAIT'S CROP
   The .faces strip that briefly lived here (small overlapped portraits opening Home
   and Steward Formation) was REJECTED on the 2026-07-29 review call — the founder's
   ruling is that the first page stays without people, by design. Its rules are gone.

   What survives is a genuine crop bug the strip happened to expose, which affects the
   portrait EVERYWHERE it is used and was wrong before the strip existed:
   joy-reinelt.jpg is the one landscape environmental shot in the set (480x320, subject
   right of frame against a brick pillar); every other portrait is centred and crops
   correctly on `center top`. Cropped square on the default, her circle filled with
   brickwork and no face — at the 58px faculty card and the 64px steward card alike.
   Keyed to the FILE so it holds wherever that portrait appears. Only the X matters:
   a 3:2 source fills a square's height exactly, so nothing crops vertically. */
.person-photo[src$="joy-reinelt.jpg"],
.pc-photo[src$="joy-reinelt.jpg"]{object-position:60% center}

/* ============================================================ PAGE HERO + IN-PROGRESS STUB */
.page-hero{padding:clamp(56px,12vh,150px) 0 clamp(40px,7vh,90px)}
.page-hero .eyebrow{margin-bottom:18px}
.page-hero h1{font-size:var(--fs-display); margin:0 0 .35em}
.page-hero .lede{font-size:var(--fs-lede); color:var(--ink-mut); max-width:56ch; text-wrap:pretty}

/* -- running prose (T5) --
   Body copy that runs to more than one paragraph wears .prose on its container.
   Without it a bare <p> falls back to the browser's 1em margins and whatever
   inline margin-top the page happened to hand-write — which is how definition.html
   ended up with its own rhythm. Measure is capped here, once: prose sets its own
   line length rather than inheriting the 92vw wrap. The first paragraph opens
   with a wider gap (it follows the lede); the rest breathe evenly. */
.prose{max-width:64ch}
.prose p{margin:0 0 1.15em; text-wrap:pretty}
.prose > p:first-of-type{margin-top:26px}
.prose p:last-child{margin-bottom:0}
.prose a{color:var(--accent); text-decoration:none; border-bottom:1px solid color-mix(in srgb,var(--accent) 40%,transparent)}
.prose a:hover{border-bottom-color:var(--accent)}
.prose .note{margin-top:26px; max-width:56ch; font-size:.9rem; color:var(--ink-mut)}
.placeholder{display:inline-block; font-family:var(--font-mono); font-size:var(--fs-label-lg); letter-spacing:var(--tracking-label-lg);
  text-transform:uppercase; color:var(--ink-mut); border:1px dashed var(--glass-line);
  border-radius:10px; padding:.7em 1.1em; background:var(--glass)}
.stub{padding:clamp(40px,9vh,120px) 0; text-align:center}
.stub .status{font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:var(--tracking-label); text-transform:uppercase; color:var(--accent)}
.stub h1{font-size:clamp(2.4rem,7vw,4.4rem); margin:.2em 0 .3em}
.stub p{color:var(--ink-mut); max-width:52ch; margin:0 auto 26px; text-wrap:pretty}
.stub .back{font-family:var(--font-mono); font-size:var(--fs-label-lg); letter-spacing:var(--tracking-label-lg); color:var(--accent); text-decoration:none}
.stub .back:hover{text-decoration:underline}

/* ============================================================ HOME OVERVIEW */
.ov-intro{padding:clamp(56px,13vh,170px) 0 clamp(24px,5vh,56px)}
.ov-intro .eyebrow{margin-bottom:18px}
.ov-intro h1{font-size:var(--fs-display); margin:0 0 .3em}
.ov-intro .lede{font-size:var(--fs-lede); color:var(--ink-mut); max-width:60ch; text-wrap:pretty}
/* 2026-07-20 (V2): homepage manifesto hero — the "Read the Manifesto" link and the
   short stanza beneath the lede. First paragraph keeps .lede scale; the rest step down. */
.ov-manifesto{margin:20px 0 0}
.ov-manifesto a{font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:var(--tracking-label);
  text-transform:uppercase; color:var(--accent); text-decoration:none; border-bottom:1px solid transparent; transition:border-color .25s}
.ov-manifesto a:hover{border-bottom-color:var(--accent)}
.ov-hero-body{margin-top:24px; display:flex; flex-direction:column; gap:15px}
.ov-hero-body p{margin:0; color:var(--ink-mut); text-wrap:pretty; max-width:62ch}
/* 2026-07-22 (V4): the opening paragraph matches the section pages' lede scale —
   the client asked to align it with the rest of the site. The stanza beneath it
   keeps body size, so the first line reads as the lede and the rest steps down.
   2026-07-22 (V5): the container's 60ch cap was computed at BODY size (~601px),
   so the intro line ran far shorter than the 56ch-at-lede ledes on every section
   page (~953px) — "not the full length as other pages". The cap now lives on the
   paragraphs, in their OWN measure: the lede line gets 56ch at lede size (matching
   the section heroes exactly), the stanza a 62ch reading width. */
.ov-hero-body p:first-child{font-size:var(--fs-lede); line-height:var(--lh-body); max-width:56ch}
/* the stanza's flex gap already breathes — the rule needs only a touch more */
.ov-hero-body .lime-rule{margin:6px 0}
.ov-intro .ov-note{margin-top:28px; font-family:var(--font-mono); font-size:var(--fs-label-sm); letter-spacing:var(--tracking-label-sm); text-transform:uppercase}
.overview{padding:0 0 clamp(48px,9vh,110px)}
.ov-grid{display:grid; gap:16px; grid-template-columns:1fr}
@media(min-width:680px){.ov-grid{grid-template-columns:1fr 1fr}}
@media(min-width:1040px){.ov-grid{grid-template-columns:1fr 1fr 1fr}}
.ov-card{display:flex; flex-direction:column; gap:10px; background:var(--glass);
  border:1px solid var(--glass-line); border-radius:18px; padding:24px 22px 26px;
  text-decoration:none; color:var(--ink); transition:transform .25s var(--ease), border-color .3s}
.ov-card:hover{transform:translateY(-3px); border-color:var(--accent)}
.ov-card .ov-k{font-family:var(--font-display); font-weight:700; font-size:1.3rem}
.ov-card p{margin:0; color:var(--ink-mut); font-size:.9rem; text-wrap:pretty}
.ov-card .ov-go{margin-top:auto; font-size:.8rem; color:var(--accent); font-weight:600; font-family:var(--font-body)}

/* ============================================================ FOOTER BAND — The Life Read → Knock on the Door */
/* THE TWO STANDARD FOOTER BLOCKS — every page ends: Life Read → Knock.
   Sizing ruled on the 2026-07-17 call: "Read your own configuration" was set
   smaller than "Knock on the Door" and the block LOST — so both headings now
   share ONE size, the larger (Knock's). Do not shrink one back.
   Colour: lime = The Life Read, ember = Knock. The headings themselves carry
   the accent, which is what makes the blocks read as buttons-in-prose. */
.liferead{border-top:1px solid var(--line-2); padding:clamp(40px,7vh,80px) 0;
  background:radial-gradient(120% 90% at 50% 0%, color-mix(in srgb,var(--panel) 55%,var(--ground-1)) 0%, var(--ground-1) 72%)}
.liferead-in{display:flex; flex-wrap:wrap; gap:20px; align-items:center; justify-content:space-between}
.liferead .lr-k{font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:var(--tracking-label); text-transform:uppercase; color:var(--lime-text)}
.liferead h3{font-family:var(--font-display); font-weight:700; font-size:clamp(2.2rem,6vw,3.6rem);
  line-height:1.06; letter-spacing:-.008em; margin:.1em 0 .3em; color:var(--lime-text); text-wrap:balance}
.liferead p{color:var(--ink-mut); max-width:46ch; margin:0}


.knock{background:radial-gradient(120% 90% at 50% 0%, color-mix(in srgb,var(--panel) 70%, var(--ground-1)) 0%, var(--ground-0) 70%);
  border-top:1px solid var(--line-2); padding:clamp(48px,9vh,110px) 0}
.knock-in{display:grid; gap:clamp(30px,5vw,60px); align-items:center}
@media(min-width:880px){.knock-in{grid-template-columns:1fr 1fr}}
.knock h2{font-size:clamp(2.2rem,6vw,3.6rem); margin:.1em 0 .4em; color:var(--ember-text)}
.knock .eyebrow{color:var(--ember-text)}
.knock .k-sub{color:var(--ink-mut); max-width:42ch; margin-bottom:22px}
.knock .k-meta{font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:var(--tracking-label); text-transform:uppercase; color:var(--ember-text)}
form.reading{background:var(--glass); border:1px solid var(--glass-line); border-radius:22px;
  padding:clamp(22px,4vw,34px); backdrop-filter:blur(10px); box-shadow:var(--shadow)}
.field{margin-bottom:18px}
/* line-height 1.45: the V7 steward label runs to two–three lines (it never
   wrapped before), and the body's inherited 1.6 is a prose rhythm, not a label
   one — the wrapped uppercase mono rows read as scattered. 2026-07-25 (V7). */
.field label{display:block; font-family:var(--font-mono); font-size:var(--fs-label); letter-spacing:var(--tracking-label); text-transform:uppercase; color:var(--ink-mut); margin-bottom:8px; line-height:1.45}
.field input, .field textarea{width:100%; background:color-mix(in srgb,var(--ground-0) 40%,transparent);
  border:1px solid var(--line); border-radius:12px; padding:13px 14px; color:var(--ink);
  font-family:inherit; font-size:.95rem; transition:border-color .25s, box-shadow .25s; resize:vertical}
/* 2026-07-26: 104px → 168px. The V7 placeholder the client wrote is five wrapped
   lines on a phone ("A family stewardship readiness inquiry. A public or private
   workshop…"), and 104px showed ~3.3 of them: the fourth line was sliced through
   the glyphs by the bottom border and the closing "else uniquely yours to
   steward." was unreachable, because a placeholder does not scroll. The box has
   to fit the guidance it is given. 168px ≈ 5 lines at the 22.8px used line-height
   plus the 13px padding pair. If that placeholder is ever reworded, re-check this. */
.field textarea{min-height:168px; line-height:1.5}
.field input::placeholder, .field textarea::placeholder{color:color-mix(in srgb,var(--ink-mut) 75%,transparent)}
.field input:focus, .field textarea:focus{outline:none; border-color:var(--accent); box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent)}
/* -- form errors (U1) --
   These styles existed ONLY in theory.html's inline CSS. site-chrome.js has
   always toggled .invalid, but with nothing here to render it, an incomplete
   submit on Home and all seven sections produced no border, no message, no
   scroll — the form simply did nothing, worst of all on a phone. Ported from
   theory.html so the two forms fail the same way.
   Bronze, NOT crimson: crimson is reserved for Act 3's ruin/threshold, sitewide.
   The message is a real element (not ::after content) because it carries the
   accessible name that aria-describedby points at — see wireForm(). */
.field.invalid input, .field.invalid textarea{border-color:var(--bronze-text)}
.field.invalid input:focus, .field.invalid textarea:focus{border-color:var(--bronze-text);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--bronze-text) 22%,transparent)}
.field .err{font-family:var(--font-mono); font-size:var(--fs-label-sm); letter-spacing:var(--tracking-label-sm);
  color:var(--bronze-text); margin-top:6px; display:none}
.field.invalid .err{display:block}
form.reading .foot{display:flex; align-items:center; gap:16px; margin-top:24px; flex-wrap:wrap}
form.reading .note{font-size:.78rem; color:var(--ink-mut); max-width:24ch}
.form-ok{display:none; text-align:center; padding:20px 6px}
.form-ok.show{display:block; animation:rise .6s var(--ease)}
.form-ok h3{font-family:var(--font-display); font-size:1.6rem; margin:0 0 8px}
.form-ok p{color:var(--ink-mut); max-width:34ch; margin-inline:auto}
@keyframes rise{from{opacity:0; transform:translateY(10px)}to{opacity:1; transform:none}}

footer.site{border-top:1px solid var(--line-2); padding:44px 0 60px}
/* 2026-07-22 (V4): the footer was a two-item flex with justify-content:
   space-between — a wide void down the middle and both corners crowded ("the
   footer design is scattered — too much empty space and 2 corners too
   clattered"). It is a THREE-column grid now: contact + socials · the seven
   sections · the asks. The asks pin to the top-right so "Receive the Letters"
   reads as the footer's primary invitation. One column on a phone. */
.foot-grid{display:grid; gap:30px clamp(22px,4vw,52px); grid-template-columns:1fr; align-items:start}
@media(min-width:760px){.foot-grid{grid-template-columns:minmax(0,1.05fr) minmax(0,1fr) auto}}
.foot-brand b{font-family:var(--font-mono); letter-spacing:.2em; font-size:.8rem}
.foot-brand div{font-size:.72rem; color:var(--ink-mut); margin-top:4px; max-width:40ch}
/* 2026-07-29: footer wordmark (see renderFooter). Same masked PNG as .brand-logo,
   set a step larger than the nav's because here it is a sign-off rather than a
   navigation control, and nothing else in this column competes with it. `display:block`
   on the anchor keeps `.foot-brand div`'s margin-top off it. */
.foot-mark{display:block; width:max-content; text-decoration:none}
.foot-logo{display:block; height:56px; aspect-ratio:1596/1032; background-color:var(--ink);
  -webkit-mask:url("logo-light.png") left center/contain no-repeat;
          mask:url("logo-light.png") left center/contain no-repeat;
  transition:background-color .3s var(--ease,ease)}
.foot-mark:hover .foot-logo{background-color:var(--accent)}
.foot-brand .foot-contact{margin-top:16px}
@media(max-width:600px){ .foot-logo{height:46px} }
/* the footer MIRRORS the full 7-section nav (2026-07-17: the sections were not
   mirrored there —
   it used to carry only three). Column layout: seven links no longer fit a row. */
.foot-links{display:grid; grid-template-columns:1fr 1fr; gap:10px 24px; font-size:.82rem}
@media(min-width:880px){.foot-links{grid-template-columns:1fr 1fr; gap:10px 32px}}
.foot-links a{color:var(--ink-mut); text-decoration:none; white-space:nowrap}
.foot-links a:hover{color:var(--accent)}
/* the asks column — Receive the Letters · The Life Read · Knock on the Door.
   2026-07-22 (V5): all three are one right-aligned stack now, EQUAL width, so
   their sizes and positions line up (they were a lone pill over a wrapping
   two-pill row — mismatched widths in both layouts, the client's note). On a
   phone they stretch full-width and centre; on desktop they share a fixed
   min-width and pin to the right, The Life Read in the middle. */
.foot-asks{display:flex; flex-direction:column; gap:10px; align-items:stretch}
.foot-asks .pill{justify-content:center; text-align:center}
/* 2026-07-26: the three footer asks measured 27.7–28.8px tall on a phone — well
   under the 44px tap-target floor the rest of the site answers to (M2). .pill-sm
   sets its height purely from font-size + .72em padding, which at the floored
   11px lands at ~28px. min-height on the coarse-pointer media (the same query the
   type floor uses) fixes it without touching the desktop bar, where these pills
   are deliberately compact. The sub-nav and burger rows already had this; the
   footer never did, and no test covered it. */
@media (max-width:600px), (pointer:coarse){ .foot-asks .pill{min-height:44px} }
@media(min-width:760px){.foot-asks{align-items:flex-end}
  .foot-asks .pill{width:auto; min-width:186px}}
/* Receive the Letters — the ask, and the panel it drops open (2026-07-25).
   It was a full section band between The Life Read and Knock; the client cut it
   (too much for one field) and asked for a button that opens a small window, all inside the
   footer. See lettersAsk() in site-chrome.js for the reasoning.
   .lt-ask must behave EXACTLY like its two sibling pills in the asks column —
   stretched full-width on a phone, 186px and right-aligned on desktop — so it is
   a grid (the button fills it) rather than anything that shrink-wraps. */
.lt-ask{position:relative; display:grid}
.lt-ask > .pill{width:100%}
@media(min-width:760px){.lt-ask > .pill{width:auto}}
/* Phone: the panel takes its place in the flow and pushes the two pills below it
   down. There is no room to float 300px of form over a 375px column, and a
   fixed overlay would cover the very buttons it sits among.
   Desktop: a real dropdown, pinned under the ask and right-aligned to it, so the
   footer does not jump while someone is reaching for it. */
/* scroll-margin, not decoration: wireLetters() scrolls this into view the moment
   it opens, and the opening animation still holds a translateY at that instant —
   so the browser measures a box 6px off and lands short, leaving the Subscribe
   button clipped at the bottom of a phone. The margin absorbs that and leaves a
   line of air at the viewport edge either way. */
.lt-pop{margin-top:10px; scroll-margin:16px; background:var(--panel); border:1px solid var(--glass-line);
  border-radius:16px; padding:18px; box-shadow:var(--shadow); text-align:left;
  animation:lt-drop .28s var(--ease)}
.lt-pop[hidden]{display:none}
@media(min-width:760px){
  .lt-pop{position:absolute; z-index:6; top:calc(100% + 10px); right:0; width:300px}
  /* .up — set by wireLetters() when there is not enough page below the ask to
     drop into (it is the last block on the page, so usually there is not). */
  .lt-ask.up .lt-pop{top:auto; bottom:calc(100% + 10px); animation-name:lt-rise}
}
@keyframes lt-rise{from{opacity:0; transform:translateY(6px)}to{opacity:1; transform:none}}
@keyframes lt-drop{from{opacity:0; transform:translateY(-6px)}to{opacity:1; transform:none}}
.lt-pop .lt-k{font-family:var(--font-display); font-weight:700; font-size:1.15rem;
  line-height:1.15; color:var(--accent); margin-bottom:6px}
.lt-pop .lt-note{font-size:.78rem; color:var(--ink-mut); margin:0 0 14px; max-width:34ch}
.lt-pop .field{margin-bottom:14px}
.lt-pop .lt-go{width:100%; justify-content:center; font-size:.7rem; letter-spacing:.14em; padding:.8em 1.15em}
.lt-pop .form-ok{padding:0}
.lt-pop .form-ok h3{color:var(--accent); font-size:1.15rem}
.lt-pop .form-ok p{font-size:.78rem; margin-inline:auto; max-width:30ch}

/* the address sits alone on the contact line now — the subscribe ask moved up to
   the asks column (V4). */
.foot-contact{font-size:.72rem; color:var(--ink-mut)}
.foot-contact a{color:var(--ink-mut); text-decoration:none; border-bottom:1px solid var(--line)}
.foot-contact a:hover{color:var(--accent); border-bottom-color:var(--accent)}

/* social row — see SOCIALS in site-chrome.js. Only accounts that exist render,
   and they render as real links; there is no placeholder state any more (U4). */
/* 2026-07-22 (V5): a clear line of air between the address and the social row —
   they read as crowded together (the client's note). The gap was the real bug:
   `.foot-brand div` (0,1,1) was overriding `.foot-social`'s own margin-top (0,1,0)
   down to 4px, so the intended breathing room never applied. The selector below
   now outranks it, opening a full line between the address and the icons. */
.foot-social{display:flex; flex-wrap:wrap; gap:10px}
.foot-brand .foot-social{margin-top:30px}
.foot-social a{display:grid; place-items:center; width:44px; height:44px;
  border-radius:99px; border:1px solid var(--line); color:var(--ink-mut);
  transition:color .25s, border-color .25s, transform .25s}
.foot-social a:hover{color:var(--accent); border-color:var(--accent); transform:translateY(-2px)}
.foot-social a:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.foot-social svg{width:17px; height:17px; fill:currentColor; display:block}

/* "Study. Sense. Steward." — the school's line. 2026-07-25 (V7), client
   verbatim: "Integrate Study. Sense. Steward. into pages design. In Lime. Size
   and font as our subheadings (Knock on the Door etc). Placement – the line
   above the copyright." Type is the subheading voice at the smaller of its
   scales. DELIBERATELY un-scoped — the footer carries it sitewide AND the home
   hero reuses the class (a separate V7 pass), so only the spacing rule below
   belongs to the footer. */
/* 2026-07-26 (review): one size smaller, with a line of space added —
   one step down from the subheading scale it shipped at
   (clamp(1.8rem,4.6vw,2.8rem)), because at 28.8px on a phone it ran nearly the
   full width and out-shouted the three asks above it. */
.sss{font-family:var(--font-display); font-weight:700; font-size:clamp(1.45rem,3.6vw,2.2rem);
  line-height:1.08; letter-spacing:-.008em; color:var(--lime-text); text-wrap:balance}
/* spacing only — in the footer the line sits between the link grid and the legal
   line. The + 1em IS that requested line of space: one line of the element's own type,
   so the gap scales with the clamp instead of being a second number to maintain.
   It was crowding the KNOCK pill directly above it. */
footer.site .sss{margin-top:calc(44px + 1em)}

.foot-note{margin-top:30px; padding-top:22px; border-top:1px solid var(--line-2);
  display:flex; flex-wrap:wrap; gap:6px 18px; align-items:center;
  font-family:var(--font-mono); font-size:var(--fs-label-sm); letter-spacing:var(--tracking-label-sm); color:var(--ink-mut); text-transform:uppercase}
/* The legal line must FIT ONE LINE of a phone screen (2026-07-21 V3, client).
   45 uppercase mono chars at the 11px floor with label-sm's .22em tracking run
   ~406px — wider than a 375px handset. The floor (legibility) does not give, so
   the TRACKING does: at .05em the line measures ~330px and fits a 345px wrap.
   Scoped to the note's own spans so no other label loses its scale. */
@media (max-width:600px){
  .foot-note{gap:6px 12px}
  .foot-note span, .foot-note a{letter-spacing:.05em; white-space:nowrap}
}
.foot-note a{color:var(--ink-mut); text-decoration:none}
.foot-note a:hover{color:var(--accent)}
/* 2026-07-25 (V7): "Footer – in mobile version lots of empty space – maybe
   optimize a little?" Below 760px the grid is ONE column — contact/socials, the
   seven links, the three asks — so the desktop-scale 30px gaps and margins stack
   into one long empty run down the phone screen. Tightened a notch here only;
   759px so it can never overlap the min-width:760px column layout, whose
   desktop air is untouched by design. */
@media (max-width:759px){
  .foot-grid{gap:20px}
  .foot-brand .foot-social{margin-top:18px}
  /* same "+ one line" as the desktop rule — see .sss above */
  footer.site .sss{margin-top:calc(28px + 1em)}
  .foot-note{margin-top:22px; padding-top:16px}
}

/* ============================================================ IN PROGRESS — the stub badge.
   An animated bar, not a static word: the founder asked that these sections
   "attract attention" rather than be scrolled past as dead ends. */
.inprog{display:inline-flex; flex-direction:column; gap:9px; align-items:flex-start;
  border:1px solid var(--glass-line); background:var(--glass); border-radius:12px; padding:.85em 1.15em}
.inprog .ip-k{display:inline-flex; align-items:center; gap:.6em; font-family:var(--font-mono);
  font-size:var(--fs-label); letter-spacing:var(--tracking-label); text-transform:uppercase; color:var(--lime-text)}
.inprog .ip-k::before{content:''; width:6px; height:6px; border-radius:99px; background:var(--lime);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--lime) 70%,transparent); animation:ip-pulse 2.4s ease-out infinite}
.inprog .ip-bar{position:relative; width:min(230px,52vw); height:3px; border-radius:99px;
  background:color-mix(in srgb,var(--ink) 12%,transparent); overflow:hidden}
.inprog .ip-bar::after{content:''; position:absolute; inset:0; width:38%; border-radius:99px;
  background:linear-gradient(90deg, transparent, var(--lime), transparent); animation:ip-slide 2.1s ease-in-out infinite}
@keyframes ip-pulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--lime) 60%,transparent)}
  70%{box-shadow:0 0 0 7px transparent}100%{box-shadow:0 0 0 0 transparent}}
@keyframes ip-slide{0%{transform:translateX(-110%)}100%{transform:translateX(300%)}}
@media (prefers-reduced-motion:reduce){
  .inprog .ip-k::before{animation:none}
  .inprog .ip-bar::after{animation:none; width:42%; transform:none}
}

/* reveal */
.rv{opacity:0; transform:translateY(14px); transition:opacity .7s ease, transform .7s var(--ease)}
.rv.in{opacity:1; transform:none}
@media (prefers-reduced-motion:reduce){.rv{opacity:1; transform:none; transition:none}}
