/* ============================================================
   Creation Education Museum — Main stylesheet
   ============================================================ */

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

/* ============================================================
   THE LIGHT GROUND — sand texture, site-wide
   ============================================================
   Every sand section on every page. The user's artwork: impressed dinosaur
   and human tracks, trilobites, an ammonite, a fern, scattered bone.

   THIS IS ONE BACKGROUND ON THE CANVAS, NOT ONE PER SECTION, and that is the
   whole design. The three photographic zones on this site (.leaf-zone,
   .road-zone, .fossil-zone) each need a wrapper element because
   `background-size: cover` crops a different region at a different scale on a
   74px seam than on an 800px band, so the picture has to be owned once by a
   parent. None of that applies here: this is a REPEATING TILE AT A FIXED
   PIXEL SIZE, and a fixed-size tile on the canvas is continuous under
   everything by construction. So there are no wrappers, no per-page markup,
   and the ground runs unbroken through the seams. Do not "improve" this into
   zones; it would be more code and a worse result.

   The tile is on the ROOT rather than on body. Body's background would
   propagate to the canvas anyway, but positioned by rules that are easy to
   get wrong; declaring it here means the positioning area is plainly the root
   box, so the tile runs the full height of the document. Body is transparent
   so it cannot cover this.

   WHY A VEIL RATHER THAN opacity: opacity on the root would fade the content
   too. A --bg veil at alpha 0.90 laid OVER the tile composites to exactly
   0.90 x --bg + 0.10 x tile, which is the same arithmetic as the tile at 0.10
   opacity over --bg, and it leaves the text alone. --bg is still the
   background-COLOUR underneath, so a failed image request degrades to the
   flat sand this site had before.

   THE SETTINGS ARE THE USER'S, 2026-08-28: strength 0.10, tile 2200px.
   Measured at those settings over each element's own box at 1330px wide:
     body copy --text-muted   5.53:1   (6.29 on the flat ground)
     aims link --clay-deep    5.91:1   (6.22 flat)
     headings --ink          10.69:1   (12.05 flat)
     eyebrow --clay           3.67:1   (4.17 flat)
   Ground mean luminance 0.678 against the flat ground's 0.682, so the tone
   the user settled on after two rounds of darkening is untouched: the texture
   adds relief, not colour. Nothing on the site needed re-toning to sit on it.
   THE ONE COST IS THE EYEBROW, 4.17 -> 3.67. It was already under the 4.5 bar
   site-wide before this and is on the standing flagged list; the texture
   deepens that shortfall rather than creating a new one.

   THE TILE IS SEAMLESS IN BOTH AXES AND THAT TOOK WORK, so do not swap the
   source artwork in. `Sandbackground.jpg` at the project root (912x1177)
   already wraps horizontally: its wrap column differs from its neighbour by
   18.4 dRGB against 16.7 for an ordinary interior pair, i.e. just the grain.
   Vertically it does NOT, 24.6 against 5.0 on a blurred comparison. The tone
   matches top to bottom so there is no visible band, but the impressions
   crossing the bottom edge do not continue at the top. sand-tile.jpg is a
   912x976 cross-fade wrap of it: write out height H' = H - 201 and ramp row
   y + H' into row y for the first 201 rows, then re-encode at -q:v 3. Both
   dimensions are multiples of 16 so JPEG's block padding cannot reopen the
   seam. Verified at 5.7 against an interior 4.1.
   ============================================================ */
html {
  background-color: var(--bg);
  background-image:
    linear-gradient(var(--bg-veil), var(--bg-veil)),
    url("../assets/img/sand-tile.jpg");
  background-repeat: no-repeat, repeat;
  background-position: 0 0, 50% 0;
  background-size: auto, 2200px auto;
}

/* The tile shrinks on a phone, and the reason is the opposite of the obvious
   one. 2200px is nearly six times a 375px viewport, so a phone would get a
   single near-blank patch of tile and the texture would disappear entirely.
   600px keeps it perceptible at the same visual scale relative to the screen.
   This is also the only place the seamless tiling earns its keep: at 2200px
   almost nothing repeats on a desktop, but at 600px on a phone, where the
   same content stacks several thousand pixels tall, the tile wraps many times
   over. Breakpoint matches .aims, where the two columns collapse to one. */
@media (max-width: 759px) {
  html { background-size: auto, 600px auto; }
}

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--text);
  /* Transparent, NOT --bg: the ground is on the root above. Painting --bg
     here would cover the texture on every page. */
  background: transparent;
  -webkit-font-smoothing: antialiased;
}
img, picture, svg { display: block; max-width: 100%; }
a { color: inherit; }
button, input, select, textarea { font: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

p { text-wrap: pretty; }

/* --- Utilities --- */
.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
.wrap-narrow { width: min(100% - 2.5rem, var(--wrap-narrow)); margin-inline: auto; }
.section { padding-block: var(--space-xl); }
.skip-link {
  position: absolute; left: -9999px;
  background: var(--ink); color: var(--cream);
  padding: 0.75rem 1.25rem; z-index: 999;
}
.skip-link:focus { left: 1rem; top: 1rem; }

:focus-visible { outline: 3px solid var(--ochre); outline-offset: 3px; }

/* Available to screen readers, invisible on screen. Absolutely positioned so
   it stays out of flow — buttons derive their height from their width via
   aspect-ratio, and an in-flow label would widen them. */
.u-sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Underline that is NOT a link. Sits clear of descenders and stays thin so it
   reads as emphasis rather than an unstyled anchor. */
.u-ul { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* Caps applied by CSS rather than typed, so the word stays lowercase in the
   markup: screen readers spell out shouted words letter by letter, and copy
   pasted out of the page keeps its normal case. Caps need tracking to breathe. */
.u-caps { text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }

.eyebrow {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: var(--space-sm);
}
.eyebrow--invert { color: var(--sandstone); }

.lead { font-size: var(--step-1); color: var(--text-muted); max-width: var(--measure); }

/* --- Buttons --- */
/* Matches the CEM logo's oval: the same true-ellipse curve AND the same
   2.368:1 proportion. Width comes from the label, height follows from the
   aspect ratio — so every button is the logo's shape at a different size.
   The taller ellipse means far less horizontal padding is needed to keep
   the label clear of the curving sides than a flat lens shape would.

   ONE BUTTON, EVERY GROUND. Settled 2026-08-28 at the user's instruction:
   "one uniform design for all of them, no matter where they are." There are no
   variants any more. `btn--primary`, `btn--ghost` and `btn--outline` are gone
   from the stylesheet AND from all 19 buttons in the markup, so a stray
   modifier now does nothing instead of quietly making a button vanish.

   WHY IT IS TWO TONES, AND WHY IT HAS TO BE. Buttons on this site sit on four
   grounds: the sand, the clay band, the leaf/moss band, and the hero. A single
   flat fill CANNOT serve all four, and this is arithmetic rather than taste.
   To clear 3:1 against the sand (luminance 0.682) a colour must sit at or
   below 0.194; to clear 3:1 against the clay band (0.068) it must sit at or
   above 0.304. There is no such colour. So the button carries a dark fill and
   a light ring, and whichever one the ground does not swallow does the work.
   Measured, best of fill/ring on each ground:
     sand, flat          fill 4.17   ring 1.32   -> 4.17
     sand, darkest pixel fill 3.56   ring 1.55   -> 3.56
     clay band           fill 1.49   ring 8.21   -> 8.21
     leaf/moss band      fill 1.35   ring 7.41   -> 7.41
     hero / slate        fill 2.49   ring 13.68  -> 13.68
   Label on fill is 5.50:1 everywhere, because both travel with the button.
   The consequence to expect rather than treat as a bug: ON THE DARK BANDS THE
   FILL NEARLY MATCHES THE GROUND, so the button reads as a cream outline,
   which is what those buttons already looked like. On the sand the ring is the
   invisible half and it reads as a clay pill. Same design, different half
   doing the work.
   Rejected on the numbers, not by eye: clay with no ring at all (1.49, 1.35
   and 2.49 on the three dark grounds, i.e. gone), and an ink fill (1.16 on the
   hero, and ink pills are not this palette's accent).

   THIS COSTS THE PRIMARY/SECONDARY DISTINCTION in the two places that had one,
   the homepage hero pair and the Creation Speaks pair. Flagged to the user. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  aspect-ratio: var(--oval-ratio);
  padding: 0 1.7rem;
  white-space: nowrap;
  font-weight: 600;
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  background: var(--clay);
  color: var(--cream);
  border: 2px solid var(--cream);
  border-radius: var(--radius-oval);
  transition: background 220ms var(--ease), color 220ms var(--ease),
              border-color 220ms var(--ease), transform 220ms var(--ease);
}
/* Hover deepens the fill and keeps the ring, so it behaves the same way on
   every ground. The old ghost hover flooded the button with cream, which on
   the sand would now be a bright blob: nothing else on this site is near
   white, and that rule holds for a hover state too. */
.btn:hover { background: var(--clay-deep); transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

/* --- Link with rule underneath (reference-site style) --- */
.link-rule {
  display: inline-block;
  text-decoration: none;
  font-weight: 600;
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  padding-bottom: 0.35rem;
  border-bottom: 1px solid currentColor;
  transition: opacity 200ms var(--ease);
}
.link-rule:hover { opacity: 0.62; }

/* ============================================================
   Parent-org bar + Header
   ============================================================ */
/* Height the fixed header occupies. Interior pages pad their page-head by
   this much so content doesn't slide underneath. Set to 0 on small screens,
   where the header is `sticky` and therefore already takes up flow space. */
:root { --header-h: 92px; }

/* Every in-page anchor used to land with its target tucked under the fixed
   header — #visit, #nifty-fifty, #past, #signup and the rest, site-wide, since
   the header stopped taking flow space. `scroll-padding-top` on the scroll
   container fixes all of them at once, and unlike per-element
   `scroll-margin-top` it also governs scripted `scrollIntoView`, so the two
   can never disagree. Affects scrolling only, never layout. */
html { scroll-padding-top: calc(var(--header-h) + var(--space-sm)); }

/* The header floats ON the hero image as a translucent stone-dark bar,
   with the logo centred and the menu split either side of it. */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  /* Deliberately thin so the artwork reads through the bar. The blur was
     doing as much to obscure it as the tint was, so both came down hard.
     Legibility is carried by the label shadows instead of by the panel. */
  /* Hand-written near-ink, so it does NOT follow the --ink token on its own.
     Re-toned with the ramp 2026-09-01; was rgba(25, 27, 29, ...). */
  background: linear-gradient(to bottom, rgba(21, 28, 35, 0.52), rgba(21, 28, 35, 0.20));
  backdrop-filter: blur(3px);
  transition: background 260ms var(--ease), backdrop-filter 260ms var(--ease);
  border-bottom: 1px solid rgba(250, 245, 234, 0.16);
  color: var(--cream);
}

/* Once the dark artwork has scrolled past, the bar has to carry itself: at
   0.06 alpha the menu would be invisible over the light sand sections. */
.site-header.is-solid {
  /* Also hand-written; re-toned with the ramp. Was rgba(22, 24, 26, ...). */
  background: linear-gradient(to bottom, rgba(17, 23, 29, 0.95), rgba(17, 23, 29, 0.88));
  backdrop-filter: blur(10px);
}

.orgbar {
  border-bottom: 1px solid rgba(250, 245, 234, 0.10);
  color: var(--text-invert-muted);
  font-size: var(--step--1);
}
.orgbar__inner {
  display: flex; flex-wrap: wrap; gap: var(--space-sm);
  align-items: center; justify-content: space-between;
  padding-block: 0.4rem;
}
.orgbar a { color: var(--cream); text-decoration: none; border-bottom: 1px solid var(--rule-invert); }
.orgbar a:hover { border-color: var(--cream); }

/* Three columns: menu | logo | menu */
.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-sm);
  padding-block: 0.35rem;
}
/* `display: contents` lets the two menu lists sit directly in the header
   grid on desktop, then become a single dropdown panel on mobile. */
.nav__panel { display: contents; }
.nav-group { display: flex; list-style: none; margin: 0; padding: 0; gap: 0.3rem; align-items: center; }
/* All three must share row 1 — without an explicit row the logo auto-places
   onto a second row and the bar doubles in height. */
.nav-group--left  { grid-column: 1; grid-row: 1; justify-content: flex-end; }
.nav-group--right { grid-column: 3; grid-row: 1; justify-content: flex-start; }
.site-header__logo { grid-column: 2; grid-row: 1; justify-self: center; }
/* The logo is the identity — centred and given real presence */
.site-header__logo img {
  /* Sized so the bar stays under ~15% of the hero image height and never
     rides down over the top of the Ohio outline (which starts at ~20%). */
  height: clamp(50px, 5.6vw, 80px);
  width: auto;
  filter: drop-shadow(0 3px 12px rgba(0, 0, 0, 0.55));
  transition: transform 300ms var(--ease);
}
.site-header__logo:hover img { transform: scale(1.04); }

/* --- Map / directions button, upper-right corner of the bar --------------
   Added 2026-09-07. This is the third answer to one reviewer note asking for
   the address more prominently: the footer address was promoted, a FIND US
   line was tried in the visit bar's Contact cell and REJECTED, and the user
   asked for the map icon here instead.

   ABSOLUTE, NOT A FOURTH GRID TRACK, and that is the whole design decision.
   `.site-header__inner` is `1fr auto 1fr` and the logo is dead-centre only
   because columns 1 and 3 are equal. A fourth `auto` track would drag the
   logo left by half this button's width — off the centre line it shares with
   the Ohio outline in the hero directly below it. Absolute takes the button
   out of flow and the logo does not move a pixel.

   Anchored on `.site-header__inner`, not `.site-header`, so `right: 0` lands
   on the wrap's content edge. The icon then sits in the same gutter every
   other element on the page respects instead of flush against the glass.

   In the markup it is a direct child of `.site-header__inner`, deliberately
   OUTSIDE `.nav__panel`: the panel collapses into the hamburger dropdown at
   980px, so anything inside it would be hidden behind a tap on every phone —
   which is exactly where a directions link is most wanted. */
.site-header__inner { position: relative; }
.mapbtn {
  position: absolute;
  right: 0; top: 50%;
  transform: translateY(-50%);
  /* line-height: 0 stops the inline-image baseline gap from making the box
     taller than the picture and throwing the vertical centring off. */
  display: block; line-height: 0;
  /* TAP TARGET. The picture is only 30x24 at the small end, which clears the
     24px WCAG 2.5.8 floor but is a mean target for a thumb next to a 46px
     hamburger. The padding grows the hit area to ~46x40 without touching the
     artwork, and the matching negative offset puts the IMAGE's right edge
     back on the content edge — otherwise the padding would hold the icon
     8px in from the corner the user asked for. */
  padding: 8px;
  right: -8px;
}
.mapbtn img {
  /* Tops out below the logo's 80px so the identity stays the largest thing
     in the bar. THE vw TERM IS LOAD-BEARING, not decoration. Because this
     button is absolute it cannot push the nav, so nothing stops the two from
     colliding — and the space between "Believe" and the content edge is set
     by the nav's own fixed content width against a `1fr` track, so it closes
     as the viewport narrows: 162px at 1449, 47px at 1000, 41px at 985, which
     is the narrowest desktop there is (the hamburger takes over at 980).
     Measured with a flat 38px the gap was 3px at 985 and the icon sat on top
     of BELIEVE. At 3vw it is ~30px there for an 11px gap — wider than the
     nav's own 0.3rem inter-item gap — and grows back to the 46px cap by
     ~1530px. Re-measure this if the nav ever gains or loses an item. */
  width: clamp(30px, 3vw, 46px);
  height: auto;
  display: block;
  /* The same shadow the logo carries. The bar is translucent over the hero's
     rock face and a flat cartoon with no shadow floats loose on it. */
  filter: drop-shadow(0 3px 12px rgba(0, 0, 0, 0.55));
  transition: transform 300ms var(--ease);
}
.mapbtn:hover img,
.mapbtn:focus-visible img { transform: scale(1.08); }

.nav__item { position: relative; }

.nav__link,
.nav__trigger {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: none; border: 2px solid transparent; cursor: pointer;
  text-decoration: none;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cream);
  /* Carries legibility now that the bar itself is nearly transparent: a tight
     dark halo plus a wider soft one, so labels hold against bright rock. */
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.95),
    0 0 6px rgba(0, 0, 0, 0.85),
    0 0 16px rgba(0, 0, 0, 0.6);
  padding: 0.55rem 1.05rem;
  /* A hover highlight, not a button — at 50% these wide, short items would
     render as stretched lenses. A soft pill stays quiet behind the label. */
  border-radius: 999px;
  transition: background 200ms var(--ease), color 200ms var(--ease);
}
.nav__link:hover, .nav__trigger:hover,
.nav__item[data-open="true"] .nav__trigger { background: rgba(250, 245, 234, 0.18); color: #fff; }

.nav__caret { width: 9px; height: 9px; transition: transform 220ms var(--ease); }
.nav__item[data-open="true"] .nav__caret { transform: rotate(180deg); }

/* Dropdown — mirrors the footer groupings exactly */
.nav__submenu {
  position: absolute; top: calc(100% + 0.5rem); left: 0;
  min-width: 235px;
  list-style: none; padding: 0.55rem; margin: 0;
  background: var(--cream);
  border: 1px solid var(--rule);
  border-radius: 18px;
  box-shadow: var(--shadow-card);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity 180ms var(--ease), transform 180ms var(--ease), visibility 180ms;
  z-index: 120;
}
.nav__item[data-open="true"] .nav__submenu { opacity: 1; visibility: visible; transform: translateY(0); }

/* On pointer devices, hovering or tabbing into a group opens it */
@media (min-width: 981px) {
  .nav__item:hover .nav__submenu,
  .nav__item:focus-within .nav__submenu { opacity: 1; visibility: visible; transform: translateY(0); }
  .nav__item:hover .nav__trigger,
  .nav__item:focus-within .nav__trigger { background: rgba(250, 245, 234, 0.18); color: #fff; }
  .nav__item:hover .nav__caret,
  .nav__item:focus-within .nav__caret { transform: rotate(180deg); }
}
.nav__submenu a {
  display: block; text-decoration: none;
  padding: 0.6rem 0.95rem;
  font-size: var(--step--1);
  color: var(--ink);
  /* Rows, not buttons — an ellipse would read as a distortion here */
  border-radius: 12px;
  transition: background 160ms var(--ease);
}
.nav__submenu a:hover { background: var(--sand); }

/* Standard three-bar menu button. Circular rather than the wide oval the
   text version used: at 108px the toggle overflowed its grid column and
   nudged the centred logo off true. A circle is still the logo's shape,
   just with equal axes, and it comfortably clears a 44px tap target. */
.nav-toggle {
  display: none;
  position: relative;
  background: none;
  border: 2px solid var(--rule);
  width: 46px;
  height: 46px;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  /* Collapses the "Menu" label visually while leaving it in the
     accessibility tree as the button's name. */
  font-size: 0;
  color: var(--cream);
}
/* Three bars drawn from one pseudo-element plus two box-shadows */
.nav-toggle::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 20px; height: 2px;
  background: currentColor;
  transform: translate(-50%, -50%);
  box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
}

/* ============================================================
   HERO — full-bleed, headline centered below the Ohio cutout
   ============================================================ */
/* The Ohio cutout occupies roughly 16%–83% of the source image's height and
   sits dead centre. Because the image is 16:9 — wider than most hero
   viewports — `object-fit: cover` crops horizontally, which leaves no
   vertical slack to push the map upward. Overlaying the headline anywhere
   in the lower half would therefore land it ON the map.

   So: give the image its own row at natural proportions, and give the
   headline a dedicated strata band beneath it, blended at the seam so the
   two read as one continuous rock face. */
.hero {
  position: relative;
  background: var(--slate-deep);
  display: grid;
  grid-template-rows: auto 1fr;
  overflow: hidden;
  isolation: isolate;
}
/* Because the sharp image is never cropped, wide screens leave bands at its
   sides. Rather than flat dead colour, fill them with a blurred, darkened
   copy of the same rock face — the hero reads as full-bleed stone while the
   Ohio outline stays whole and centred. */
.hero__backdrop {
  position: absolute; inset: 0; z-index: -1;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.18);
  filter: blur(34px) saturate(0.75) brightness(0.42);
}
.hero__vignette {
  position: absolute; inset: 0; z-index: -1;
  /* Hand-written; re-toned with the ramp 2026-09-01. Was rgba(25,27,29,0.55). */
  background: radial-gradient(ellipse at 50% 42%, transparent 42%, rgba(21, 28, 35, 0.55) 100%);
}
/* The backdrop and vignette darken the hero's base below flat --slate-deep,
   so the seam that follows didn't match and showed as a lighter strip above
   the gold. This settles the last stretch to exactly --slate-deep. */
.hero::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 160px;
  z-index: -1;
  /* The transparent stop carries --slate-deep's own value as rgba(...,0). The
     colour is invisible at zero alpha but a stale value there is still a trap
     the next person has to reason about, so it moved with the ramp too.
     Was rgba(35, 40, 44, 0). */
  background: linear-gradient(to bottom, rgba(28, 39, 48, 0) 0%, var(--slate-deep) 92%);
  pointer-events: none;
}
/* The Ohio outline must never be clipped. The figure therefore holds the
   image at its exact native aspect ratio — no cropping in either axis.
   On wide screens the height is what's constrained, so the figure narrows
   and centres on the dark strata ground rather than slicing the map. */
.hero__figure {
  position: relative;
  aspect-ratio: 3200 / 1792;
  /* Full-bleed width at native proportions — the whole Ohio outline, with
     the header floating over the rock band above it. Capped on very wide
     monitors so the hero can't become absurdly tall. */
  width: min(100%, 2000px);
  margin-inline: auto;
  overflow: hidden;
  z-index: 1;
  /* Lets the motto scale with the figure rather than the viewport */
  container-type: inline-size;
  /* Rugged torn edge along the base, melting into the headline band */
  -webkit-mask-image: var(--tear-bottom);
  mask-image: var(--tear-bottom);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
}
.hero__img {
  width: 100%; height: 100%;
  object-fit: contain;   /* belt and braces: never crop the outline */
  object-position: 50% 50%;
}
/* Ohio's state motto, centred inside the Ohio cutout. Bounds measured off
   the source image by flood-filling the cutout region: it spans 33–66%
   horizontally and 16.5–82.1% vertically, with its area centroid at
   48.5%, 48.8%. Positioned in percentages so it tracks the cutout as the
   figure scales, and sized in container units so the type scales with the
   figure rather than the viewport. (The Great Seal artwork is intentionally
   NOT used: ORC 5.10 restricts reproducing it. The motto alone does not.) */
.hero__motto {
  position: absolute;
  left: 49.5%;
  top: 49.3%;
  width: 30%;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;
}
.hero__motto-text {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 4.2cqw;
  line-height: 1.06;
  letter-spacing: -0.01em;
  color: var(--cream);
  /* Carved-into-stone feel, and enough weight to stay legible over both the
     bright farmland above and the dark strata below. */
  text-shadow:
    0 2px 4px rgba(25, 27, 29, 0.92),
    0 0 24px rgba(25, 27, 29, 0.70),
    0 1px 0 rgba(250, 245, 234, 0.20);
}
.hero__motto-src {
  margin-top: 1.4cqw;
  font-family: var(--font-body);
  font-size: max(9px, 1.15cqw);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(250, 245, 234, 0.82);
  text-shadow: 0 1px 7px rgba(25, 27, 29, 0.95);
}
@media (max-width: 700px) {
  /* Must stay inside the cutout, which is only ~35% of the figure width */
  .hero__motto { width: 32%; }
  .hero__motto-text { font-size: 4.6cqw; }
  /* No room for the attribution line once the figure is ~210px tall */
  .hero__motto-src { display: none; }
}

/* Melts the base of the photograph into the headline band. */
.hero__scrim {
  position: absolute; inset: 0;
  /* Hand-written; re-toned with the ramp 2026-09-01. Was rgba(25, 27, 29, ...). */
  background: linear-gradient(to bottom,
    rgba(21, 28, 35, 0.30) 0%,
    rgba(21, 28, 35, 0.00) 22%,
    rgba(21, 28, 35, 0.00) 68%,
    rgba(21, 28, 35, 0.55) 88%,
    var(--slate-deep) 100%);
}
.hero__content {
  position: relative;
  text-align: center;
  color: var(--text-invert);
  padding-block: var(--space-sm) var(--space-md);
  align-self: center;
}
.hero__title {
  /* No two-line split of this phrase balances well — the options measured
     131px and 152px apart, and the tighter one dangles "AND" at a line end.
     A single line is perfectly even, so the type is sized to hold one line
     and the headline is allowed to run wider than the page wrap to do it.
     Below ~520px it wraps, which is fine. */
  font-size: clamp(2.2rem, 4vw, 3.6rem);
  /* Breaks out of the 1240px .wrap so the line has room to stay unbroken,
     while staying centred on the viewport. */
  width: min(96vw, 1400px);
  max-width: none;
  margin-left: 50%;
  transform: translateX(-50%);
  color: var(--cream);
  text-shadow: 0 2px 30px rgba(25, 27, 29, 0.5);
  /* Uppercased in CSS, not in the markup, so the DOM keeps natural casing —
     some screen readers spell out all-caps text letter by letter. */
  text-transform: uppercase;
  /* Caps need looser tracking than the -0.015em the h1 rule applies */
  letter-spacing: 0.015em;
  line-height: 1.12;
  /* NB: no `margin-inline: auto` here — it would override the margin-left
     above and knock the headline off centre. */
}
/* Must come AFTER .hero__title: same specificity, so source order decides. */
@media (max-width: 700px) {
  /* At the clamp floor the headline ran to four lines. Slightly smaller
     type lets it settle into three. */
  .hero__title { font-size: 1.9rem; }
}
.hero__sub {
  margin-top: var(--space-sm);
  font-size: var(--step-1);
  color: var(--text-invert-muted);
  /* Wide enough for the longest sentence (863px) to hold a single line.
     At the old 56ch (759px) the first sentence spilled its last word onto
     line two, where the second sentence then began beside it. */
  max-width: min(920px, 100%);
  margin-inline: auto;
  text-shadow: 0 1px 16px rgba(25, 27, 29, 0.6);
}
/* Each sentence is its own block, so two sentences can never share a line
   no matter how the text reflows. */
.hero__sub span { display: block; }
.hero__actions {
  margin-top: var(--space-md);
  display: flex; flex-wrap: wrap; gap: var(--space-sm); justify-content: center;
  /* Without this, flex stretch equalises the buttons' heights and overrides
     the oval aspect ratio on whichever label is shorter. */
  align-items: center;
}
.hero__meta {
  margin-top: var(--space-md);
  font-size: var(--step-0);
  color: rgba(250, 245, 234, 0.86);
}
.hero__meta a { color: var(--cream); text-decoration: none; border-bottom: 1px solid var(--rule-invert); }
.hero__meta a:hover { border-color: var(--cream); }

/* ============================================================
   Strata seam — swooping layered rock bands between sections.
   Real sedimentary boundaries undulate rather than running flat, so the
   curved layers are truer to the theme than straight bands. The frontmost
   layer takes the colour of whatever section follows, so the seam resolves
   into it instead of stopping at a hard edge.
   ============================================================ */
.wave {
  line-height: 0;
  background: var(--wave-from, var(--slate-deep));
  position: relative;
}

/* Kills the hairline along the TOP of a seam. Different cause from the bottom
   one below, and it survives even though the seam block and the section above
   are the SAME colour. Their boxes share one fractional y (0.844 at 1440), so
   each paints its dark at partial coverage over the sand body background, and
   the two partial composites do not add back up to opaque: the boundary row
   lands near rgb(61,63,63) against a true rgb(35,40,44). Matching the colours
   was never going to be enough. This strip paints --wave-from across the join
   at full coverage. Only visible where the section above differs from the body
   background, but harmless where it does not. */
.wave::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: -1px;
  height: 2px;
  background: var(--wave-from, var(--slate-deep));
  pointer-events: none;
}
/* Exception: inside the leaf zone the ground above the lower seam is moss PLUS
   a photograph and a vignette, so a flat --moss-deep strip would read as a band
   across the picture. The zone shows through instead, same reasoning as
   `.leaf-zone .wave { background: transparent }`. */
.leaf-zone .wave--from-moss::before { content: none; }

/* Kills the hairline that used to show along the BOTTOM of every seam.
   The seam's height is `clamp(44px, 5.5vw, 86px)`, which lands on a fraction
   (79.188px at 1440 wide), so the frontmost path's edge falls mid-device-pixel.
   That last row composites to roughly 77% --wave-to plus 23% of the colour
   ABOVE, reading as a thin line of the wrong colour against the section below.
   This strip paints --wave-to across the boundary at full coverage, overshooting
   1px past the fractional edge so no blended row survives. It is invisible by
   definition: it is exactly the colour of the section it sits on.
   No layout shift, and where --wave-to is `transparent` (the leaf zone) it
   self-disables rather than punching a hole. */
.wave::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--wave-to, var(--slate-deep));
  pointer-events: none;
}
.wave svg {
  display: block;
  width: 100%;
  /* Tried and rejected: `round(..., 1px)` to force a whole-pixel seam. It makes
     the HEIGHT an integer but the seam's top and bottom still land on fractions
     (measured 0.234, 0.563, 0.656, 0.844 at 810px wide), because the fluid
     clamp() type above each seam contributes fractional block heights. Boundary
     positions cannot be made integral from here, so the edge strips below are
     the actual fix, not a workaround for this. */
  height: clamp(44px, 5.5vw, 86px);
}
.wave .w1 { fill: var(--sandstone); }
.wave .w2 { fill: var(--ochre); }
.wave .w3 { fill: var(--clay); }
.wave .w4 { fill: var(--wave-to, var(--slate-deep)); }

/* --- The UPWARD strata, used by every `wave--to-light` seam ---------------
   Same four curves, same four bands, drawn the other way up so the region
   BELOW the last curve is left unpainted and the canvas sand texture runs
   through the seam.

   THE REASON THIS EXISTS IS A BUG THAT COST A ROUND, and it is worth stating
   plainly because the obvious fix is the wrong one. In the downward
   construction every path fills from its own curve to y=100, so each covers
   the one before it: `w4` is not merely "the colour of the section below", it
   is the LID over w3's clay. Setting `--wave-to: transparent` therefore does
   not reveal the ground, it reveals the CLAY, and the seam stops resolving
   into the section and ends on a hard brown edge. Caught by rendering both
   states and comparing, not by reading the CSS, which looks correct either
   way.
   Filling upward inverts the covering order and gives an identical picture
   with an open bottom. Paint order in the markup is u4, u3, u2, u1, deepest
   curve first, so each shallower band lands on top; every boundary is still
   an overlap, so no band can crack open along a fractional edge.
   NB u1 carries --wave-from, the colour ABOVE the seam, because in this
   construction the topmost band is the one the block background used to
   paint. That is also why `.wave--to-light` clears its background.

   THE SAME LATENT FAULT IS STILL IN `wave--to-photo` / `wave--to-leaf`, which
   the three photographic zones use. Those seams end in clay rather than
   resolving into their picture. Left alone deliberately: those bands were
   settled with the user over several rounds and are outside the sand ground
   this change is about. Fixing them is this same swap. */
.wave .u1 { fill: var(--wave-from, var(--slate-deep)); }
.wave .u2 { fill: var(--sandstone); }
.wave .u3 { fill: var(--ochre); }
.wave .u4 { fill: var(--clay); }

.wave--to-dark    { --wave-to: var(--slate-deep); }

/* THE TWO LIGHT-SIDE SEAMS ARE TRANSPARENT, so the canvas texture runs
   straight through them. They used to paint flat --bg, which was right when
   the ground was flat and would now leave a smooth patch across every seam
   where the impressions stop dead.

   `to-light`: the frontmost path goes transparent AND the block background
   with it, because the block background is --wave-from, i.e. the DARK colour
   above, and it would show through the hole the transparent path leaves. The
   dark above the first curve is supplied instead by a `w0` path in the
   markup, same `d` as w1 but closed to y=0 so it fills upward. Every
   `to-light` seam on the site carries one. This is the same construction as
   `wave--to-photo`, which the three photographic zones use, and the shared
   `.wave .w0` rule below serves both.

   `from-light`: only the block background has to go, because --wave-from is
   what paints it and the light ground is above. No w0: the canvas is already
   showing there.

   THE EDGE STRIPS ARE UNAFFECTED AND STILL NEEDED. `::after` self-disables
   where --wave-to is transparent, and there is nothing left for it to fix:
   the fractional-pixel hairline came from two BOXES each painting their own
   colour at partial coverage, and neither box paints now. `::before` still
   paints --wave-from on a `to-light` seam, where the section above is a real
   dark band and the join is real. Do not delete either. */
.wave--to-light   { --wave-to: transparent; background: transparent; }
.wave--to-ink     { --wave-to: var(--ink); }
.wave--to-moss    { --wave-to: var(--moss-deep); }
.wave--to-clay    { --wave-to: var(--clay-deep); }
.wave--from-dark  { --wave-from: var(--slate-deep); }
.wave--from-light { --wave-from: transparent; }
.wave--from-moss  { --wave-from: var(--moss-deep); }
.wave--from-clay  { --wave-from: var(--clay-deep); }

/* NB: do NOT mirror the svg with scaleY(-1) to vary the curve. Each path
   fills from its own curve DOWN to the bottom edge, so mirroring also swaps
   which side every layer covers: --wave-from would end up at the bottom and
   --wave-to at the top, inverting the transition. Vary the seam by writing
   different path data, never by flipping. */

/* ============================================================
   Visit bar — hours / admission / directions
   ============================================================ */
.visitbar { background: var(--slate-deep); color: var(--text-invert); }
.visitbar__grid {
  display: grid;
  /* Explicit three, not auto-fit: auto-fit would drop to two columns at some
     widths and leave the third stranded alone on its own row. */
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--rule-invert);
}
.visitbar__cell {
  background: var(--slate-deep);
  padding: var(--space-md) 1.75rem var(--space-lg);
  text-align: center;
}

/* Centred heading whose rule matches the width of the text itself */
.visitbar__title {
  font-family: var(--font-display);
  font-size: var(--step-2);
  color: var(--cream);
  width: fit-content;
  margin-inline: auto;
  margin-bottom: var(--space-md);
  padding-bottom: 0.55rem;
  border-bottom: 3px solid var(--sandstone);
}

/* Body copy in this band reads at --step-0, not --step--1. At the smaller
   step it measured the same 14.4px as the button labels but read much
   smaller, because the buttons are uppercase, semibold and full-strength
   cream while this is lowercase, regular weight and dimmed. */
.visitbar__lead {
  font-size: var(--step-0);
  color: rgba(250, 245, 234, 0.86);
  max-width: 34ch;
  margin-inline: auto;
}
.visitbar__note {
  font-size: var(--step-0);
  color: rgba(250, 245, 234, 0.74);
  margin-top: var(--space-sm);
  max-width: 36ch;
  margin-inline: auto;
}
.visitbar__sublabel {
  margin-top: var(--space-md);
  /* Eyebrow labels stay below body size on purpose: the caps, tracking and
     sandstone colour already give them plenty of presence. */
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--sandstone);
}
.upcharge { color: var(--cream); }

.price {
  font-family: var(--font-display);
  font-size: var(--step-4);
  line-height: 1;
  color: var(--cream);
  margin-bottom: var(--space-sm);
}

/* Lists read left-aligned but sit as a centred block in the column */
/* --- Contact cell --- */
.tel {
  display: inline-flex; align-items: baseline; justify-content: center;
  margin-top: var(--space-md);
  font-family: var(--font-display); line-height: 1;
  font-size: clamp(1.3rem, 1.0rem + 1.15vw, 1.8rem);
  color: var(--cream); text-decoration: none;
  transition: color 160ms var(--ease);
}
.tel:hover, .tel:focus-visible { color: var(--ochre); }
/* Eight children, four columns: letters fill row one, digits row two.
   Columns are `auto`, not `1fr` — equal columns pad the narrow letters out to
   the width of the widest one, and DINO starts reading as D I N O. */
.tel__word { display: inline-grid; grid-template-columns: repeat(4, auto); justify-items: center; }
.tel__word .d {
  font-family: var(--font-body); font-size: 0.42em; letter-spacing: 0;
  /* Sandstone, not ochre: ochre measures 4.0:1 on this ground, and at ~12px
     these are normal-size text needing 4.5:1. */
  color: var(--sandstone); margin-top: 0.45em;
}

.mail {
  display: grid; place-items: center;
  width: 46px; height: 46px; margin: var(--space-md) auto 0;
  border: 1px solid var(--rule-invert); border-radius: var(--radius-oval);
  color: rgba(250, 245, 234, 0.86);
  transition: color 160ms var(--ease), border-color 160ms var(--ease);
}
.mail:hover, .mail:focus-visible { color: var(--cream); border-color: var(--cream); }
/* The label already carries the section gap; without this the two stack their
   own top margins and the icon drifts away from the words it belongs to. */
.visitbar__sublabel + .mail { margin-top: var(--space-sm); }
.mail svg {
  width: 22px; height: 22px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
/* The icon shakes, not the ring — the ring staying put is what makes it read
   as a nudge rather than the whole button wobbling loose.
   The animation runs on this wrapper span, NOT on the <svg>. Applying it
   straight to the svg leaves computed animation-name set but registers no
   animation at all (getAnimations() stays empty and no transform renders),
   while an identical span in the same slot animates. Do not "simplify" this
   span away. */
.mail__icon { display: block; }
@keyframes mail-shake {
  0%, 100% { transform: rotate(0); }
  15% { transform: rotate(-9deg); }
  32% { transform: rotate(7deg); }
  49% { transform: rotate(-5deg); }
  66% { transform: rotate(3.5deg); }
  83% { transform: rotate(-1.5deg); }
}
.mail:hover .mail__icon,
.mail:focus-visible .mail__icon { animation: mail-shake 620ms var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .mail:hover .mail__icon,
  .mail:focus-visible .mail__icon { animation: none; }
}

/* 2026-09-07: a `.visitbar__addr` lived here for about ten minutes — FIND US
   plus the street address, between the mail icon and the note. The user did
   not like what it did to the Contact cell and reverted it. The address went
   into the header as `.mapbtn` instead. Do not re-add it here. */

/* --- Membership price --- */
.pricetag {
  display: flex; align-items: baseline; gap: 0.55rem;
  margin-top: var(--space-md);
}
.pricetag__amount {
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-3); line-height: 1; color: var(--cream);
}
.pricetag__unit {
  font-size: 0.95rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
  /* Cream, not sandstone. Sandstone carries small caps fine on the ink visit
     bar (6.16:1) but collapses to 3.03:1 on this moss ground. Every other
     label in this band is cream for the same reason. */
  color: rgba(250, 245, 234, 0.82);
}

.itemlist {
  list-style: none;
  padding: 0;
  margin: 0.75rem 0 0;
  display: inline-block;
  text-align: left;
}
.itemlist li {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
  font-size: var(--step-0);
  color: rgba(250, 245, 234, 0.88);
  padding-block: 0.32rem;
}
.itemlist li::before {
  content: "";
  flex: none;
  width: 8px; height: 8px;
  background: var(--ochre);
  translate: 0 -1px;
}

/* Hours: fewer words than the other columns, so set them larger */
.hours-opt { display: block; }
/* Kept as a guard, not as live behaviour. Nothing sets hidden any more (the
   seasonal switch came out of nav.js on 2026-09-02), but `display: block`
   above would beat the UA's own [hidden] rule if anything ever did. */
.hours-opt[hidden] { display: none; }
/* Both seasons stack now, so the second one needs to be told it is a second
   one. Only the gap between them — no top margin on the first. */
.hours-opt + .hours-opt { margin-top: var(--space-sm); }
.hours-tag {
  display: block;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--sandstone);
  margin-bottom: 0.35rem;
}
.hours-days {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1.05;
  color: var(--cream);
}
.hours-time {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--font-display);
  font-size: var(--step-1);
  color: var(--text-invert-muted);
}

/* Placed after the rules above so source order lets them win */
@media (max-width: 900px) {
  /* Give the text back the room the padding was taking */
  .visitbar__cell { padding-inline: 1rem; }
  .visitbar__title { font-size: var(--step-1); }
  .hours-days { font-size: var(--step-2); }
  .price { font-size: var(--step-3); }
}
@media (max-width: 620px) {
  .visitbar__grid { grid-template-columns: 1fr; }
  .visitbar__cell { padding-inline: 1.5rem; }
}

/* ============================================================
   Intro
   ============================================================ */
.intro__grid {
  display: grid; gap: var(--space-lg);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .intro__grid { grid-template-columns: 1.1fr 1fr; align-items: start; }
}
.intro__title { font-size: var(--step-4); }
/* The heading is already Fraunces 600, so weight alone barely reads as
   emphasis. Colour does the work; the weight bump supports it. <strong> is
   the right element here: strong importance, not stylistic bolding. */
.intro__title strong {
  color: var(--clay);
  font-weight: 700;
  /* Keep the phrase intact: split across a line break it stops reading as a
     single emphasised idea. Short enough that this can't cause overflow. */
  white-space: nowrap;
}
.intro__body { display: grid; gap: var(--space-sm); color: var(--text-muted); font-size: var(--step-0); }

/* --- The four purposes -------------------------------------------------
   These sit BELOW the two-column grid rather than inside the body column
   because a reader skims this section: four distinct reasons run together
   as prose read as one long paragraph and none of them survives. No card,
   no panel and no border box. The hairline above and the display-face
   titles carry it, which keeps this out of the generic rounded-panel
   territory the site has rejected before. */
.aims {
  margin-top: var(--space-lg);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--rule);
  display: grid;
  gap: var(--space-md) var(--space-lg);
  list-style: none;
  /* `* { margin: 0 }` clears the list's margin but not its padding. */
  padding-left: 0;
}
@media (min-width: 760px) {
  .aims { grid-template-columns: repeat(2, 1fr); }
}
.aim h3 { font-size: var(--step-1); margin-bottom: 0.4rem; }
.aim p { color: var(--text-muted); max-width: var(--measure); }
/* Clay rather than the inherited muted body colour, so the one link in this
   block reads as a link without an underline fighting the paragraph. */
.aim a { color: var(--clay-deep); text-decoration: underline; text-underline-offset: 3px; }

.intro__more { margin-top: var(--space-md); }

/* ============================================================
   Statement of Faith
   ============================================================ */
/* A document, so it is set as one: a single measured column rather than the
   site's usual multi-column sections.
   700, arrived at from the widest thing in it. The articles give 2.8rem plus a
   gap to the hanging numeral, leaving their prose 639px, about 71 characters.
   An earlier 940 left it at 852, roughly 95 characters, half again a
   comfortable line. Re-derive this if the numeral column changes. */
.creed {
  max-width: 700px;
  display: grid;
  gap: var(--space-xl);
}
.creed__part { display: grid; }

/* Each part is titled the way the visit bar titles its columns: a sandstone
   rule that stops at the width of the words rather than running the column.
   That is what replaced the (A) to (D) markers, and it does more work than
   they did, because it marks the start of a part instead of labelling it. */
.creed__head {
  font-size: var(--step-2);
  width: fit-content;
  max-width: 100%;
  padding-bottom: 0.55rem;
  margin-bottom: var(--space-md);
  border-bottom: 2px solid var(--sandstone);
}
/* The motto part only. Its block below already carries a sandstone rule top
   AND bottom, so the heading's own rule made three horizontal lines inside a
   few inches: short rule, gap, long rule, motto, long rule. The heading keeps
   its size and its place in the outline and gives up the rule, which is the
   one that was doing the least. */
.creed__head--plain { border-bottom: none; padding-bottom: 0; }

/* The motto takes the scripture block's treatment: ruled top and bottom so it
   reads as another stratum, rather than the conventional left bar. It is the
   shortest line in the document and the one everything else serves, so it is
   also the largest. */
.creed__motto {
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1.22;
  color: var(--clay-deep);
  padding-block: var(--space-md);
  border-top: 2px solid var(--sandstone);
  border-bottom: 2px solid var(--sandstone);
}

.creed__intro { color: var(--text-muted); max-width: var(--measure); margin-bottom: var(--space-md); }

/* The two priorities. Only two of them, and both are declarations rather than
   items in an inventory, so they are set a size up from body copy and at full
   ink. The square mark is the same device as the Nifty Fifty perks list, in
   clay rather than sandstone because this ground is sand.
   `role="list"` is in the markup: `list-style: none` strips list semantics in
   Safari, and these are genuinely a list in the source document. */
.creed__points { list-style: none; padding: 0; display: grid; gap: var(--space-md); }
.creed__points li {
  display: flex; gap: 1rem; align-items: baseline;
  font-size: var(--step-1); line-height: 1.45;
}
.creed__points li::before {
  content: ""; flex: none;
  width: 10px; height: 10px;
  background: var(--clay);
  translate: 0 -3px;
}

/* The numbered articles. The numeral hangs in its own column in the display
   face, which is the whole formatting idea here: ten articles set as a default
   <ol> are a wall of grey, and the hanging numerals give the eye a rung to
   climb down. Hairlines between them do the rest.
   Counters rather than ::marker because ::marker gives no control over the gap
   between the number and the text, and this numeral is nearly twice body size.
   Both lists restart at 1, exactly as the source document does. */
.creed__articles { counter-reset: article; list-style: none; padding: 0; }
.creed__articles li {
  counter-increment: article;
  display: grid;
  grid-template-columns: 2.8rem 1fr;
  column-gap: var(--space-sm);
  align-items: baseline;
  padding-block: var(--space-md);
  border-top: 1px solid var(--rule);
  color: var(--text-muted);
}
.creed__articles li:last-child { border-bottom: 1px solid var(--rule); }
.creed__articles li::before {
  content: counter(article);
  font-family: var(--font-display);
  font-weight: 600;
  /* --step-1, NOT --step-2. At --step-2 the numeral was set at exactly the same
     size as the .creed__head above it, so an article's number carried as much
     weight as the title of the part containing it: a hierarchy inversion. One
     step down still reads as a marker against 18px body copy, in the display
     face and in clay, without competing with the heading. */
  font-size: var(--step-1);
  line-height: 1.25;
  /* Tabular figures so the numerals form a straight edge down the margin. */
  font-variant-numeric: tabular-nums;
  color: var(--clay);
}

/* ============================================================
   Who We Are — two branches, one tree
   ============================================================ */
/* The opening statement is centred and narrow, against the site's usual
   left-aligned section head. This one block IS the page's thesis and it sits
   directly above a full-width photograph of a single tree, so a left-ragged
   column beside empty space would fight the symmetry underneath it. */
.tree-head { text-align: center; max-width: 780px; margin-inline: auto; }
.tree-title { font-size: var(--step-4); }
.tree-lede {
  margin-top: var(--space-md);
  font-size: var(--step-1);
  color: var(--text-muted);
}

.tree-figure { margin-top: var(--space-lg); }
/* See the markup: a degree of rotation reads as a pinned snapshot at gallery
   size and as a mistake at 1240px. */
.tree-figure .frame { --tilt: 0deg; }
/* `.frame img` sets `height: 100%`, which is meant for the fixed-ratio gallery
   cards. This photo sets its own ratio instead, so the height has to go back to
   auto. Same specificity, so this rule has to stay BELOW `.frame img`.
   The width/height attributes on the img are there for CLS; `height: auto` is
   also what stops those attributes overriding `aspect-ratio`. */
.tree-figure img { aspect-ratio: 1408 / 768; height: auto; }

/* The building drawing. It opens `our-story.html`, above the founder's story,
   at the user's direction 2026-08-28. (It spent an hour on `who-we-are.html`
   before that; the class is named for the picture rather than the page so the
   next move costs nothing.)
   THE WHITE BACKGROUND IS REMOVED BY BLENDING, NOT BY A CUTOUT, and that was
   the user's call after cutting it out went wrong: keying the white left the
   gaps between the leaves full of white flecks, because every hole in the
   canopy had page showing through it. They supplied a fixed drawing on a
   clean white ground instead.
   `mix-blend-mode: multiply` is exactly right for that. White multiplied by
   any colour IS that colour, so the 39% of this image that is pure white
   becomes the sand ground precisely, with no edge and nothing to key. The
   drawing itself darkens by the ground, which warms the greens a shade and
   settles the whole thing into the strata palette rather than sitting on top
   of it. It also means the ground's own texture reads faintly through, so the
   picture belongs to the page instead of being pasted onto it.
   NB this depends on nothing above it creating a stacking context with
   `isolation: isolate`. The three photographic zones do exactly that, so if
   this drawing is ever moved inside one, the blend will stop at the zone and
   the white will come back.
   `height: auto` alongside the width/height attributes, for the fifth-ish
   time on this site: without it the attributes act as a presentational hint
   and the image squashes. */
/* No top margin: it is the first thing in its section, so the section's own
   padding already sets it off. The bottom margin is what separates it from the
   story that follows. */
.building-drawing { margin-bottom: var(--space-xl); }
.building-drawing img {
  width: 100%;
  height: auto;
  mix-blend-mode: multiply;
}

/* The two branches. Divider on the rule rather than under either heading, so
   neither branch reads as the subordinate one: the whole point of the section
   is that they are peers. */
.branches { margin-top: var(--space-xl); display: grid; gap: var(--space-lg); }
/* The gutter is built from PADDING on the two columns, not from column-gap,
   so the rule can sit at the exact midpoint while both columns keep the same
   text width. Doing it the other way (gap plus a negative margin to pull the
   border back into the gutter) centres the rule but widens column two's box,
   which cost column two 48px of measure: 572 against 524. Measure both
   columns after any change here, not just the rule's position. */
@media (min-width: 900px) {
  .branches { grid-template-columns: 1fr 1fr; column-gap: 0; }
  .branches .branch { padding-inline: calc(var(--space-xl) / 2); }
  .branches .branch:first-child { padding-left: 0; }
  .branches .branch:last-child {
    padding-right: 0;
    border-left: 1px solid var(--rule);
  }
}
/* Four rows for four children, with the paragraph row absorbing the slack, so
   the two links sit on the same baseline whichever paragraph is longer. Both
   columns must hold the same four children for this to hold. */
.branch { display: grid; grid-template-rows: auto auto 1fr auto; }
.branch h3 { font-size: var(--step-2); }
.branch p { margin-top: var(--space-sm); color: var(--text-muted); }
.branch .link-rule { justify-self: start; margin-top: var(--space-md); }

/* --- The museum branch's own band -----------------------------------
   Three offerings across. `.band p` is (0,1,1) and would outrank a bare
   `.museum-list h3` colour, which is why the cream here is set explicitly:
   `.band h2` does not reach an h3. Same trap as the Creation on the Road
   talk title. */
.museum-list {
  display: grid; gap: var(--space-lg) var(--space-md);
  list-style: none; padding-left: 0;
}
/* 1040, not the 860 first tried: at 860 three columns leave each blurb 252px
   and at 920 they leave 267px, about 33 characters. 1040 is the width at which
   the columns reach 312px, which is in line with the homepage aims (328) and
   the exhibit cards (280 floor). Below it the items stack full width, where
   `.band p` caps them at --measure anyway. Same fault the partners page hit,
   less severely: three across too early eats the text, and the fix is the
   breakpoint, not the gap. */
@media (min-width: 1040px) {
  .museum-list { grid-template-columns: repeat(3, 1fr); }
}
.museum-list li { display: grid; grid-template-rows: auto 1fr auto; }
.museum-list h3 { font-size: var(--step-1); color: var(--cream); }
.museum-list .link-rule { justify-self: start; margin-top: var(--space-md); }

.museum-note {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--rule-invert);
}
/* `.band p` caps every paragraph at --measure, which is right for a column of
   body copy and wrong for a single closing line that should run the width of
   the band. (0,1,1) beats a bare class, so this needs the extra qualifier. */
.band .museum-note { max-width: none; }

/* ============================================================
   Exhibit gallery
   ============================================================ */
/* ---- Rugged photo frame -------------------------------------------
   A quarried, torn-edge mat around every photograph, tilted slightly
   like snapshots pinned to a board. Straightens on hover. --------- */
.frame {
  position: relative;
  padding: 12px;
  background:
    linear-gradient(148deg, var(--sand) 0%, var(--sandstone) 42%, var(--ochre) 100%);
  clip-path: var(--tear-all);
  filter: drop-shadow(0 10px 18px rgba(25, 27, 29, 0.22));
  transform: rotate(var(--tilt, -1.1deg));
  transition: transform 420ms var(--ease);
}
.frame::after {                       /* grain over the mat */
  content: ""; position: absolute; inset: 0;
  background-image: var(--grain);
  opacity: 0.30; mix-blend-mode: multiply;
  pointer-events: none;
}
.frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  clip-path: var(--tear-all);
  transition: transform 700ms var(--ease);
}
.frame:hover { transform: rotate(0deg) scale(1.015); }
.frame:hover img { transform: scale(1.04); }

/* Alternate the tilt so a grid doesn't look mechanically repeated */
.gallery > *:nth-child(3n+1) .frame { --tilt: -1.4deg; }
.gallery > *:nth-child(3n+2) .frame { --tilt:  0.9deg; }
.gallery > *:nth-child(3n+3) .frame { --tilt: -0.5deg; }

.gallery { display: grid; gap: var(--space-lg) var(--space-md); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
/* Explicit columns for a FIVE-card gallery. The auto-fit track above fits four
   across at the 1240 wrap (4x280 + 3x32 = 1216), which strands the fifth card
   alone on a row of its own. Three across gives 3 + 2, which reads as a list
   that ran on rather than as one card left behind. Same reasoning as the visit
   bar's explicit three. */
@media (min-width: 700px)  { .gallery--3up { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .gallery--3up { grid-template-columns: repeat(3, 1fr); } }
.card { display: flex; flex-direction: column; }
.card__media { aspect-ratio: 4 / 3; }
.card__body { padding: 1.4rem 0.4rem 0; display: grid; gap: 0.5rem; }
.card__kicker { font-size: var(--step--1); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--moss-deep); font-weight: 600; }
.card__title { font-size: var(--step-1); }
.card__text { font-size: var(--step--1); color: var(--text-muted); }

.section-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: var(--space-sm); margin-bottom: var(--space-md); }
.section-head h2 { font-size: var(--step-3); }

/* ============================================================
   Interior page header
   ============================================================ */
.pagehead {
  background: var(--slate-deep);
  color: var(--cream);
  text-align: center;
  padding-top: calc(var(--header-h) + var(--space-lg));
  padding-bottom: var(--space-lg);
}
.pagehead__title {
  font-family: var(--font-display);
  font-size: var(--step-4);
  line-height: 1.1;
  color: var(--cream);
  text-transform: uppercase;
  letter-spacing: 0.015em;
  width: fit-content;
  margin-inline: auto;
  padding-bottom: 0.6rem;
  border-bottom: 3px solid var(--sandstone);
}
.pagehead__lede {
  margin-top: var(--space-md);
  font-size: var(--step-1);
  color: rgba(250, 245, 234, 0.86);
  max-width: 56ch;
  margin-inline: auto;
  /* Centred display copy, so a short ragged last line reads as a mistake
     rather than as texture. Added 2026-08-25, when the signup lede grew by one
     word and broke to "...throughout / the year." Applied to EVERY lede on
     purpose: one page balancing while its neighbours do not is worse than
     either state, the same argument that keeps .eyebrow's 4.17:1 consistent
     rather than fixed on one page. Costs nothing where a lede already fits on
     one line, and it composes with .lede-line below, which makes each forced
     sentence its own block and so balances each independently. */
  text-wrap: balance;
}
/* Short display copy gives each sentence its own line. Opt-in per lede, since
   a one-sentence lede has nothing to split and long ones should just wrap. */
.pagehead__lede .lede-line { display: block; }

/* --- A LONG lede, where the one-sentence-per-line device works AGAINST it ---
   `.lede-line` suits a short lede: two brief sentences, one per line, each
   balanced. `why-creation.html` has THREE sentences and 277 characters, which
   is nearly double the next longest lede on the site (volunteer, 164) and more
   than twice the typical 110. Measured there before this rule: the lede stood
   225px tall against 75px on most pages and 112px on the tallest, and because
   `text-wrap: balance` runs on each sentence SEPARATELY, each one shrank to fit
   its own two lines — the text painted only 539px of its own 741px box, i.e.
   46% of the 1181px wrap. That is the narrow band, and the max-width was never
   the cause.
   Above 900 the sentences run together as ordinary prose and balance as ONE
   block, so the lede fills the column it was given. Below 900 nothing changes:
   on a phone the band is narrow anyway and one sentence per line is right
   there, which is exactly how the user put it.
   The 64ch cap keeps the ruled stack nesting correctly — the title is
   fit-content and .pagehead__verse is 52ch, so the verse stays inside the
   lede's column as its comment requires. */
@media (min-width: 900px) {
  .pagehead__lede--flow { max-width: 64ch; }
  .pagehead__lede--flow .lede-line { display: inline; }
}

/* Current page marker in the dropdown menus */
.nav__submenu a[aria-current="page"] {
  background: var(--sand);
  color: var(--clay-deep);
  font-weight: 600;
}

/* ============================================================
   Reviews
   ============================================================ */
/* Reviews and the intro share the page ground on purpose. Two near-identical
   sands meeting at a butt joint read as a stray line; one continuous ground
   removes the seam instead of decorating it. */
.stars { color: var(--ochre); letter-spacing: 0.12em; font-size: var(--step-0); }

.reviews__grid { display: grid; gap: var(--space-md); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.review {
  margin: 0;
  padding: 1.6rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  /* Softly rounded, echoing the logo's oval without imitating a button */
  border-radius: 22px;
  box-shadow: var(--shadow-card);
  display: grid;
  gap: 0.85rem;
  align-content: start;
}
.review blockquote {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.35;
  color: var(--text);
}
.review figcaption { font-size: var(--step--1); color: var(--text-muted); }
.review__src { display: block; margin-top: 0.15rem; font-size: 0.82em; opacity: 0.8; }

/* ============================================================
   Full-bleed colour bands (field trips / support)
   ============================================================ */
.band { color: var(--text-invert); position: relative; }
.band--clay { background: var(--clay-deep); }
.band--moss { background: var(--moss-deep); }
.band__grid { display: grid; gap: var(--space-lg); align-items: center; }
@media (min-width: 900px) { .band__grid { grid-template-columns: 1fr 1fr; } }
.band h2 { font-size: var(--step-3); color: var(--cream); }
.band p { color: var(--text-invert-muted); max-width: var(--measure); margin-top: var(--space-sm); }
/* Two separate faults, both invisible until you measure. Barlow is loaded at
   400/500/600 only, so the UA default `bold` asks for a 700 that does not
   exist and gets a synthesised one. And .band p is muted, so a bold run at the
   SAME colour reads as a rendering glitch rather than as emphasis — the point
   of <strong> here is the phrase people must not miss. Full cream fixes both
   the look and the contrast, 5.14:1 to 8.21:1 on clay. */
.band p strong { font-weight: 600; color: var(--cream); }
.band__media .frame { --tilt: 1.2deg; }
.band__media img { width: 100%; aspect-ratio: 3/2; object-fit: cover; }
/* --- Leaf zone ---------------------------------------------------------
   The photograph belongs to ONE element spanning the top seam, the band and
   the bottom seam. Painting it separately on each of the three cannot line up:
   `cover` on a 1330x74 seam crops a thin slice at one scale, `cover` on the
   ~700px band crops a different region at another, so the seams read as a
   break in the pattern no matter how the colours are matched.

   Everything inside is transparent and lets this show through. z-index -1
   paints these above the zone's own moss but below every descendant;
   `isolation: isolate` keeps that negative index from escaping upward.
   No mix-blend-mode on purpose: blending already failed once on this site
   when a z-index elsewhere isolated the group. */
.leaf-zone { position: relative; isolation: isolate; background-color: var(--moss-deep); }
.leaf-zone::before,
.leaf-zone::after { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.leaf-zone::before {
  background-image: url("../assets/img/leaves-bg.jpg");
  background-size: cover; background-position: center;
  /* 0.18, not 0.30. The brightest leaves are rgb(197,239,130); at 0.30 with a
     transparent vignette centre, body copy measured 2.67:1 against them. */
  opacity: 0.18;
}
.leaf-zone::after {
  /* The centre is scrimmed too, not just the edges — a vignette that clears to
     nothing in the middle leaves the brightest leaves sitting under the text.
     0.48 centre with the 0.18 photo puts the worst case over 4.5:1. */
  background:
    radial-gradient(115% 85% at 50% 50%,
      rgba(40, 49, 26, 0.48) 30%,
      rgba(36, 45, 24, 0.70) 72%,
      rgba(26, 33, 17, 0.92) 100%);
}
/* The band's own moss would hide the zone, so it steps aside. */
.leaf-zone .band--moss { background-color: transparent; }

/* Seams inside the zone paint only their coloured strata; the moss end of each
   transition becomes the zone showing through.
   Top seam: `--wave-to: transparent` clears the moss fill below the last
   curve, and a .w0 path supplies the dark colour ABOVE the first curve, which
   the block background used to provide. Paths fill downward, so covering the
   top of the seam needs its own path closing up to y=0 rather than a
   background. */
.leaf-zone .wave { background: transparent; }
/* Both names do the same thing: clear the flat fill so a photographic zone
   shows through. --to-leaf is the original, kept because support.html uses it;
   --to-photo is the generic name any later zone should use. */
.wave--to-leaf,
.wave--to-photo { --wave-to: transparent; }
/* The mirror of the above for the seam at the BOTTOM of a photographic zone:
   the ground it comes FROM is a picture, so the hairline strip has no flat
   colour to paint and would band the photo with a stripe. Same exception as
   `.leaf-zone .wave--from-moss::before`, but expressed as a modifier so it
   travels with the seam instead of needing a zone-specific rule. */
.wave--from-photo::before { content: none; }
.wave .w0 { fill: var(--wave-from, var(--slate-deep)); }

/* --- Nifty Fifty band -------------------------------------------------
   Two columns of near-equal height: all the words on the left, the coin/price/
   button block on the right. The composition is capped well inside the 1240px
   wrap — at full width this content could not fill the band, and the leftover
   opened three separate holes. The photograph still runs edge to edge behind,
   so the narrower plate reads as deliberate rather than as content that ran
   out. Scoped to this band; .band__grid elsewhere is untouched. */
.nifty {
  max-width: 940px; margin-inline: auto;
  display: grid; gap: var(--space-xl); align-items: center;
}
.nifty__copy > :first-child { margin-top: 0; }
/* .band p caps every paragraph at --measure and is (0,1,1). A bare .nifty__pitch
   is (0,1,0) and loses no matter where it sits in the file, so this has to be
   scoped to .band to out-specify it. */
.band .nifty__pitch { max-width: none; font-size: var(--step-1); line-height: 1.45; }
.nifty .perks { margin-top: var(--space-lg); }

/* Coin, price and button centred on each other as one column. */
.nifty__offer {
  display: grid; justify-items: center; gap: var(--space-md);
  width: 100%; max-width: 360px; margin-inline: auto;
}
.nifty__coin {
  width: 100%; aspect-ratio: 1; object-fit: contain; background: none;
  /* drop-shadow follows the PNG's alpha, so the shadow is cast by the coin's
     circle rather than by its bounding box. It reads as an object resting on
     the leaves instead of a cut-out floating over them. */
  filter: drop-shadow(0 16px 26px rgba(16, 22, 10, 0.55));
}
/* Cancel the standalone margin: the grid gap already spaces these. */
.nifty__offer .pricetag { margin-top: 0; }

/* justify-items: center, not the default stretch — .btn derives its height from
   its width via aspect-ratio, and a stretched button flattens the oval. */
.nifty__cta { display: grid; justify-items: center; gap: 0.8rem; }
/* Out-specifies .band p (0,1,1), which would otherwise cap the width and add a
   top margin on top of the grid gap. */
.nifty__cta .offer-note {
  margin: 0; max-width: 34ch; text-align: center;
  /* --step-0 at 500, not --step--1 at 400. This sits on the leaf photograph,
     and a busy ground breaks up letterforms in a way no contrast figure
     reports: the note measured a passing 4.77:1 against the composited moss
     and was still the hardest thing on the page to read. Same call the user
     made for the visit bar, and the same fix as the road zone.
     Alpha lifted from 0.72 as part of the same change; at 0.72 the size
     increase alone still left it looking like a disclaimer. */
  font-size: var(--step-0); font-weight: 500;
  color: rgba(250, 245, 234, 0.9);
  /* The note now runs to two lines, and at 34ch the natural break stranded
     "of any size." on its own. `balance` evens the two lines instead. */
  text-wrap: balance;
}

/* --- Closing thanks ----------------------------------------------------
   A coda to the band, so it takes a rule rather than a box: horizontal bands
   are this site's boundary idiom (the seams, the page-head rule, the verse
   block), and a panel here would be the sort of generic card that has been
   rejected before. Centred, because it is addressed to the reader rather
   than being another column of information. */
.nifty-thanks {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--rule-invert);
  text-align: center;
}
/* Ties with `.band p` on specificity (both 0,1,1) and wins on source order
   only, because the Nifty block sits later in this file than the band rules.
   Do not move this above them. Cream at 0.9 rather than --text-invert-muted
   at 0.72, and 500 rather than 400, for the leaf photograph underneath: the
   same lift .offer-note needed, for the same reason. */
.nifty-thanks p {
  max-width: 66ch; margin-inline: auto;
  color: rgba(250, 245, 234, 0.9);
  font-weight: 500;
}
/* .band p already spaces these; its margin would stack on the padding above. */
.nifty-thanks p:first-child { margin-top: 0; }
/* Two class selectors, NOT the bare `.nifty-thanks__sign`: on its own that is
   0,1,0 and `.band p` at 0,1,1 would quietly win the colour, leaving the
   closing line dimmer than the paragraph it is meant to lift off. */
.nifty-thanks .nifty-thanks__sign {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.25;
  color: var(--cream);
  max-width: 24ch;
  text-wrap: balance;
}

/* Media queries go BELOW the rules they override — they add no specificity, so
   above them they would lose on source order and do nothing. */
@media (min-width: 900px) {
  /* 4rem, not the --space-xl/2xl used between sections: those are 6 and 9rem,
     and at this width a 144px channel reopened the hole in the middle. */
  .nifty { grid-template-columns: minmax(0, 1fr) 360px; gap: var(--space-lg); }
}
/* The coin is a round object on transparency, not a photograph, so it opts out
   of the 3:2 crop and cover fill the framed photos use. */
.nifty__coin img { width: 100%; aspect-ratio: 1; object-fit: contain; background: none; }

.perks { list-style: none; padding: 0; margin-top: var(--space-md); display: grid; gap: 0.75rem; }
/* Raised from --step--1, where they read as fine print. Held at --step-0 rather
   than --step-1 so the pitch above still leads: two body sizes in one column
   with neither subordinate flattens the hierarchy. */
.perks li { display: flex; gap: 0.85rem; align-items: baseline; color: var(--text-invert-muted); font-size: var(--step-0); }
.perks li::before { content: ""; flex: none; width: 10px; height: 10px; background: var(--sandstone); translate: 0 -2px; }

/* ============================================================
   Exhibit index
   ============================================================ */
.gallery-head { margin-bottom: var(--space-md); }
/* The one-off explainer above the activities gallery, and the closing note
   below it. Capped and centred rather than left at full wrap width: a lone
   paragraph stops at --measure regardless, so across 1240 it would leave the
   same empty right-hand third that .cs-intro and the Nifty Fifty band were
   capped to avoid. A size up from body copy because it is the rule the whole
   gallery is read against. */
/* Left, not centred: .gallery-head above it is left-aligned, and a centred
   paragraph under a left-aligned heading reads as a stray block rather than as
   that heading's introduction. Capped at 68ch so it stays a readable measure
   without needing to fill the 1240 wrap — the gallery beneath it is what uses
   the full width. */
.activities-lead {
  font-size: var(--step-1);
  max-width: 68ch; margin-bottom: var(--space-lg);
}
.activities-lead strong { font-weight: 600; }
.index-head .activities-lead { margin-bottom: 0; }
.index-head {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--rule);
}
.index-cta {
  margin-top: var(--space-lg);
  /* align-items matters: .btn takes its height from its width via aspect-ratio,
     and the default stretch would equalise it and flatten the oval. */
  display: flex; justify-content: center; align-items: center;
}
.index-head__note { max-width: 56ch; margin-top: var(--space-sm); color: var(--text-muted); }

.exhibit-index {
  counter-reset: exhibit;
  list-style: none; padding: 0;
  margin-top: var(--space-md);
  columns: 3; column-gap: var(--space-lg);
}
.exhibit-index li {
  /* Without this a title can be split across the column break. */
  break-inside: avoid;
  display: flex; gap: 0.85rem; align-items: baseline;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--step-0); line-height: 1.3;
}
.exhibit-index li::before {
  content: counter(exhibit, decimal-leading-zero);
  counter-increment: exhibit;
  flex: none; min-width: 2.2ch;
  /* Tabular figures so the numbers form a straight edge down each column. */
  font-variant-numeric: tabular-nums;
  font-size: var(--step--1); font-weight: 600;
  color: var(--clay-deep);
}
/* The list lands on the museum's own closing line, so let it read as the
   conclusion rather than as a twenty-fifth topic. */
.exhibit-index__last { font-family: var(--font-display); font-weight: 600; }
.exhibit-index__last::before { color: var(--clay); }

/* Below the base rule, per the source-order rule. */
@media (max-width: 900px) { .exhibit-index { columns: 2; } }
@media (max-width: 600px) { .exhibit-index { columns: 1; } }

/* ============================================================
   Programs
   ============================================================ */
.programs { display: grid; gap: var(--space-md); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
/* The clay rule sits UNDER the heading, not above the card. Moved 2026-08-28 at
   the user's request on tours.html, and applied to the component rather than to
   that page, because visit.html's "Good to Know" cards reuse it and the rule
   landing on opposite sides of two identical grids would read as a bug.
   This also puts the cards in step with the rest of the site, where a heading
   underlined in sandstone or clay is the standing device: .pagehead__title,
   .visitbar__title, .creed h2. Those are `fit-content`; this one runs the full
   column, because the card IS the column and a short rule under a two-word
   heading would leave the grid looking ragged. */
.program { display: grid; gap: 0.7rem; align-content: start; }
.program h3 {
  font-size: var(--step-1);
  padding-bottom: 0.6rem;
  border-bottom: 3px solid var(--clay);
}
.program p { font-size: var(--step--1); color: var(--text-muted); }

/* --- The same cards on a CLAY band (index.html's four purposes) -------------
   Added 2026-09-03. The component was written for the sand, and two of its own
   defaults are wrong on `--clay-deep`. BOTH OF THESE WIN ON SPECIFICITY, (0,2,1)
   against (0,1,1), NOT on source order — so this block can be moved without
   silently reverting, unlike the interaction block at the end of this file.
   1. The heading rule is `--clay` on a `--clay-deep` ground, which is very
      nearly invisible. Sandstone is the site's own answer on this band: the
      same pairing as the address link on `.cs-event`.
   2. `.program p` is `--text-muted`, a DARK muted, and it is declared LATER
      than `.band p`, so it would win at equal specificity and paint dark grey
      body copy on a dark brown band. This is the identical trap the audio tour
      hit with `.tour-item.is-playing`. Do not delete either rule as a duplicate. */
.band .program h3 { border-bottom-color: var(--sandstone); }
.band .program p  { color: var(--text-invert-muted); }

/* THE FOUR PURPOSES ARE PROSE, NOT THE SHORT FACTUAL CARDS THIS COMPONENT WAS
   BUILT FOR. Inheriting `.program p`'s `--step--1` dropped them from 17.80px to
   14.35px — a full step SMALLER than `.intro__body p` directly above, which they
   are a continuation of. The user caught it by eye: "the section just above this
   is larger and more readable". Restored at (0,2,1).
   `tours.html` and `visit.html` keep `--step--1`, which is right for what those
   cards hold: one or two sentences of fact each. */
.programs--four .program p { font-size: var(--step-0); }

/* An inline link inherits the muted body colour on this band, which left it
   the SAME colour as the prose around it and carried by its underline alone.
   Full cream with a sandstone underline is the site's settled answer for a link
   on a dark band — copied from `.band .why-q__body a`, NOT invented here.
   Measured: 8.21:1 against 5.14:1 for the copy it sits in. */
.band .program p a { color: var(--cream); text-decoration-color: var(--sandstone); }

/* `.intro__more` is a <p>, and `.band p` therefore catches it TWICE over — the
   trap here is that `.band p` at (0,1,1) beats a single class at (0,1,0), so it
   wins on specificity, not source order, and it sets more than colour:
   1. COLOUR. It painted the section's own onward link MUTED while the link
      inside a card beside it was full cream — the hierarchy upside down, the
      section closer reading as the quieter of the two.
   2. MARGIN. `.band p { margin-top: var(--space-sm) }` silently halved
      `.intro__more`'s intended 2rem gap to 1rem, so the link hugged the grid.
   Both restated at (0,2,0). Index-only class, so this reaches nothing else. */
.band .intro__more { margin-top: var(--space-md); }
.band .intro__more .link-rule { color: var(--cream); }

/* FOUR items, not six. `auto-fit` would drop all four onto one row on a wide
   screen, and these paragraphs run three to four times longer than the tours
   ones, so the columns would be narrow and very tall. Two keeps the measure the
   `.aims` grid this replaced already had. */
@media (min-width: 760px) {
  .programs--four { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================
   Creation Speaks
   ============================================================ */

/* The series has its own roundel mark, so the intro is built around that
   rather than around a stock photograph. It is a real CEM asset, and a
   circle sits naturally beside the logo-derived oval of the buttons. */
/* `start`, not `center`: the copy column is long enough that a vertically
   centred mark would float on its own with dead space above and below it.
   Top-aligned, it sits against the eyebrow and heading. */
.cs-intro { display: grid; gap: var(--space-lg); align-items: start; }
@media (min-width: 900px) {
  .cs-intro { grid-template-columns: minmax(200px, 290px) 1fr; }
}
/* Capped well inside the 1240px wrap and centred, the same fix the Nifty Fifty
   band needed: the paragraphs stop at --measure regardless, so at full width
   the column simply left a 320px hole down the right. 290 mark + 64 gap + the
   ~560px measure is about 914, so 940 holds it with a little slack. */
.cs-intro { max-width: 940px; }
.cs-mark {
  width: min(100%, 290px);
  aspect-ratio: 1;
  /* Required, and it is not redundant. An <img> carrying width/height
     attributes for CLS turns `height` into a presentational hint, and a
     concrete height beats `aspect-ratio` on a box that already has a width.
     Without this reset the Creation on the Road mark rendered 290 wide by its
     full 519 attribute height: squashed to 56% of its true width. */
  height: auto;
  justify-self: center;
  filter: drop-shadow(0 10px 24px rgba(25, 27, 29, 0.22));
}
.cs-intro__body { display: grid; gap: var(--space-sm); }
/* Both qualifiers matter, and each was learned the hard way here.
   `:not(.eyebrow)` because `.cs-intro__body p` outranks `.eyebrow`, so without
   it the eyebrow silently greys out while the identical eyebrow further down
   the page stays clay. `>` because this rule would otherwise reach INTO the
   verse blockquote and mute it too, again outranking `.cs-verse p` on
   specificity. Scope block-level `p` rules to direct children. */
.cs-intro__body > p:not(.eyebrow) { color: var(--text-muted); max-width: var(--measure); }

/* --- Scripture block ---------------------------------------------------
   Ruled top and bottom rather than given the usual left bar: horizontal
   bands are this site's idiom (the seams, the page-head rule, the year
   markers), so the verse reads as another stratum. */
.cs-verse {
  margin-block: var(--space-xs);
  padding-block: var(--space-sm);
  border-top: 2px solid var(--sandstone);
  border-bottom: 2px solid var(--sandstone);
  max-width: var(--measure);
}
/* SCRIPTURE TAKES ITS OWN FACE, --font-scripture, and is the ONLY thing on the
   site that does. See the token for the audit that produced it. Line-height is
   looser than the Fraunces setting it replaces: Garamond's small x-height and
   long extenders want more room, and 1.32 crowded the ascenders. */
.cs-verse p {
  font-family: var(--font-scripture);
  font-size: calc(var(--step-1) * var(--scripture-scale));
  line-height: 1.42;
  color: var(--text);
  /* 500 EVERYWHERE, not 400-on-sand / 500-on-dark. Changed 2026-09-01 at the
     user's instruction: "I like the weight of the ones in clay, so apply that
     same weight to the ones on sand."
     The old split existed to make the two grounds look the SAME weight, on the
     reasoning that light-on-dark eats Garamond's hairlines. They compared the
     two directly on why-creation.html and preferred the heavier one on both, so
     the compensation is now moot: the face is simply set at 500.
     `.band .cs-verse p` and `.pagehead__verse p` still declare 500 of their own.
     That is now redundant for weight and is LEFT ALONE, because both rules exist
     to carry the dark-ground COLOUR and deleting the weight from them would
     only make the two look different again if this line is ever reverted. */
  font-weight: 500;
}
.cs-verse cite {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--font-body);
  /* cite defaults to italic, and the loaded Fraunces has no italic axis. Even
     in Barlow the reference is set upright to match the footer verse. */
  font-style: normal;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  /* --clay-deep (5.9:1), not --sandstone. Sandstone carries the footer verse
     because that sits on ink; on this sand ground it all but disappears. */
  color: var(--clay-deep);
}
/* Scripture in a page head. Lives HERE, not up with the other .pagehead rules,
   because `.pagehead__verse p` and `.cs-verse p` have identical specificity
   (one class, one type) and source order is what decides — declared earlier it
   would silently lose to the block above and render in sand colours on ink.
   Only the tone and alignment change: the top-and-bottom sandstone rules are
   the site's scripture idiom and already read on this ground, the page-head
   title being underlined in the same colour. The palette is the footer verse's,
   which is the established dark-ground treatment; --text and --clay-deep both
   disappear against --slate-deep. */
.pagehead__verse {
  margin-top: var(--space-md);
  margin-inline: auto;
  /* Narrower than --measure so the ruled edges stay inside the lede's column
     and the band reads as one centred stack rather than three widths. */
  max-width: 52ch;
  text-align: center;
}
/* --- A LONG page-head verse, 2026-08-31 -------------------------------------
   The user, on why-creation.html: the verse "looks like it could be spread out
   more since the text above it is, and that would help make sure no one word is
   just hanging there by itself."
   ONLY TWO PAGES ON THE SITE CARRY A PAGE-HEAD VERSE: this one (Revelation
   4:11, 145 characters) and who-we-are (Hebrews 1:10, 118). At the shared 52ch
   the long one broke 472 / 511 / 487 / 148 — a fourth line holding just "were
   created." Swept 52 to 70ch: 58 and 60 both settle it into THREE nearly equal
   lines, 521 / 579 / 524, and everything past 62 strands a short tail again.
   60ch rather than 58 because the widest line paints 579, which is 4px inside a
   58ch box and 24px inside a 60ch one; identical output, and the slack survives
   a font-metric shift.
   IT IS A MODIFIER, NOT A CHANGE TO THE RULE ABOVE, and the reason is measured:
   who-we-are's shorter verse reads 501 / 503 / 330 at 52ch and 544 / 543 / 247
   at 60ch, so widening it globally would make the other page's rag WORSE.
   No media query: below 900 the container is narrower than either cap, so the
   max-width is not the binding constraint and nothing changes on a phone.
   Still nests inside the lede, which is 844px here under
   `.pagehead__lede--flow`. */
.pagehead__verse--wide { max-width: 60ch; }
/* Weight 500, the dark-ground scripture rule. See .site-footer__verse p. */
.pagehead__verse p { color: var(--text-invert-muted); font-weight: 500; }
.pagehead__verse cite { color: var(--sandstone); }

.cs-intro__body h2 { font-size: var(--step-3); }

/* --- Next talk band ---------------------------------------------------
   With nothing on the calendar, the honest notice on its own would be a
   dead end. Two columns instead, so the band still does work: collect the
   people who want telling, and the churches who would host. The rule sits
   on the divider rather than under either heading, so neither half reads
   as subordinate to the other. */
.cs-next { display: grid; gap: var(--space-lg); }
@media (min-width: 900px) {
  .cs-next { grid-template-columns: 1fr 1fr; }
  .cs-next__aside { padding-left: var(--space-lg); border-left: 1px solid var(--rule-invert); }
}
/* `justify-items: start`, not the default stretch: a stretched grid item would
   equalise the button's height and flatten the oval it takes from the logo.
   The `1fr` row is the paragraph, so it absorbs the slack in whichever column
   is shorter and both buttons land on the same baseline. Both columns hold the
   same four children (eyebrow, heading, copy, button), which is what makes one
   shared row template possible. No `align-content` needed: the 1fr row leaves
   no free space for it to distribute. */
.cs-next__col {
  display: grid; gap: var(--space-sm); justify-items: start;
  grid-template-rows: auto auto 1fr auto;
}
/* Both columns are peers, so both headings are h2 and both take the same size.
   --step-2, not the --step-3 the rest of the page's section headings use: these
   are two headings sitting side by side inside one band, and the clay ground is
   already carrying the emphasis.
   NB this ties with `.band h2` on specificity (both 0,1,1) and only wins on
   source order, because the Creation Speaks block sits later in this file. Do
   not move it above the band rules. */
.cs-next h2 { font-size: var(--step-2); }
/* The grid gap already spaces these; .band p would add a second margin. */
.band .cs-next p { margin-top: 0; }
/* The two buttons are a matched pair, so they are sized off the longer label
   rather than each off its own. `min-width`, not `width`: height derives from
   the aspect ratio, so this is also how a button gets a floor, and a label
   longer than 13rem still grows instead of spilling out of the oval. */
.cs-next .btn { margin-top: var(--space-xs); min-width: 13rem; }

/* --- A booked evening -------------------------------------------------
   Written into the band by js/next-talk-render.js when data/next-talk.js holds a
   talk whose date has not passed. Absent the rest of the time, which is
   most of the time, so nothing here has any effect on the empty band.

   The pair below it keeps its place and is DEMOTED rather than removed:
   somebody who cannot make this evening still wants the mailing list, and a
   church reading about one talk is exactly who might host the next. They are
   separated by a hairline, the same stratum device as the seams and the year
   markers, rather than by a box or a shaded panel.

   Nothing here is a new shape. The poster takes the site's torn frame, the
   speaker takes the archive's ringed roundel, the facts are hairline rows
   like the exhibit index, and the buttons are the one button. */
/* CONTAINER QUERIES, NOT MEDIA QUERIES, AND THE REASON IS THE EDITOR. The
   card is previewed inside a column on event-editor.html, and a viewport
   query fires on the window rather than on that column, so the preview would
   show a two-up layout squeezed into 620px: a picture of something no visitor
   will ever see. Asking the card how wide IT is answers correctly in both
   places, and on the live page it lands on exactly the same breakpoints.
   Where container queries are unsupported neither rule matches and the card
   stacks in one column, which is the mobile layout and is perfectly usable. */
[data-next-talk] { container-type: inline-size; }
.cs-event { display: grid; gap: var(--space-lg); align-items: start; }
@container (min-width: 900px) {
  /* Only when there is a poster. Without one the details would be stranded
     in a 55% column with a hole beside them, the same fault `.cs-intro` and
     the Nifty Fifty band were capped to avoid. */
  .cs-event--poster { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); }
}
/* A flyer is a document, not a snapshot pinned to a board: at this size the
   gallery's tilt reads as a mistake. Same call as the tree figure. */
.cs-event__poster .frame { --tilt: 0deg; }
/* REQUIRED, NOT REDUNDANT, and it must stay BELOW `.frame img` (same
   specificity, later wins). That rule sets `height: 100%` for the gallery's
   fixed-ratio cards; a poster comes in whatever proportion it was drawn. */
.cs-event__poster img { height: auto; }

.cs-event__body { display: grid; gap: var(--space-sm); justify-items: start; }
/* The eyebrow's own bottom margin would stack on the grid gap. */
.cs-event__body .eyebrow { margin-bottom: 0; }
/* Left at `.band h2`'s --step-3, one step ABOVE the pair below, which sits at
   --step-2. The booked evening is the reason the band exists while it is
   there; the two standing offers are not its peers for those few weeks. */
.cs-event__title { max-width: 20ch; }

.cs-event__who { display: flex; align-items: center; gap: 0.9rem; }
/* The archive's portrait treatment at a larger size: the speaker is the
   headline act here rather than one row in a list. `object-fit: cover`
   because a newly supplied headshot may be any shape, while the eleven in
   the archive arrive already cut as circles. */
.cs-event__face {
  flex: none; width: 84px; height: 84px;
  border-radius: 50%;
  border: 2px solid var(--sandstone);
  background: var(--surface);
  object-fit: cover;
  box-shadow: 0 2px 8px rgba(25, 27, 29, 0.22);
}
.cs-event__speaker { font-family: var(--font-display); font-size: var(--step-1); color: var(--cream); }
/* Out-specifies `.band p` (0,1,1), which would otherwise cap the width and
   add a margin above a line that belongs tight under the name. */
.band .cs-event__role { font-size: var(--step--1); margin-top: 0.1rem; }

.cs-event__facts { width: 100%; max-width: 36rem; }
.cs-event__fact {
  display: grid; gap: 0.15rem;
  padding: 0.7rem 0;
  border-top: 1px solid var(--rule-invert);
}
.cs-event__fact:last-child { border-bottom: 1px solid var(--rule-invert); }
@container (min-width: 620px) {
  /* Below this the label column would leave a full street address about
     200px wide, which wraps to four lines. */
  .cs-event__fact { grid-template-columns: 8rem 1fr; gap: 0.5rem var(--space-sm); }
}
/* MUTED CREAM, NOT SANDSTONE, AND IT IS MEASURED. Sandstone on the clay band
   is 3.68:1, which is fine for the band's eyebrow (a label the eye skips) and
   is the site's known eyebrow shortfall, but these four labels are the ones a
   visitor is actually reading to find out when and where. Muted cream is
   5.16:1 and still reads as a label rather than as copy, because the caps,
   the tracking and the weight are doing that work, not the colour. */
.cs-event__fact dt {
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--text-invert-muted);
}
.cs-event__fact dd { margin: 0; color: var(--cream); }
.cs-event__fact time { font-variant-numeric: tabular-nums; }
.cs-event__venue,
.cs-event__city,
.cs-event__addr { display: block; }
.cs-event__city { color: var(--text-invert-muted); }
/* Cream text at 8.22:1 with a SANDSTONE RULE under it. The colour that would
   normally mark this as a link cannot carry the text here, so it carries the
   underline instead, where 3.68:1 clears the 3:1 bar a non-text mark has to
   meet. The hover brings the rule up to cream, so the state change is a real
   one and never costs contrast. */
.cs-event__addr {
  margin-top: 0.35rem;
  font-size: var(--step--1);
  color: var(--cream);
  text-decoration: underline;
  text-decoration-color: var(--sandstone);
  text-underline-offset: 3px;
  transition: text-decoration-color 180ms var(--ease);
}
.cs-event__addr:hover,
.cs-event__addr:focus-visible { text-decoration-color: var(--cream); }
/* Buttons take their height from their width via aspect-ratio, so the
   default stretch would flatten the oval. Same note as .index-cta. */
.cs-event__actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-sm); margin-top: var(--space-xs);
}
.cs-event__actions .btn { min-width: 13rem; }

/* Two evenings booked at once. A line each, deliberately not a second card:
   the band is called Next Talk, and two cards would leave a visitor working
   out which one is next. */
.cs-event-more { margin-top: var(--space-lg); }
.cs-event-more .eyebrow { margin-bottom: var(--space-xs); }
.cs-event-more__list { list-style: none; padding: 0; }
.cs-event-more__list li {
  display: grid; gap: 0.1rem;
  padding: 0.7rem 0;
  border-top: 1px solid var(--rule-invert);
}
@container (min-width: 760px) {
  .cs-event-more__list li { grid-template-columns: 16rem minmax(0, 1fr); gap: 0.1rem var(--space-md); }
  .cs-event-more__who { grid-column: 2; }
}
/* Muted cream for the same measured reason as the fact labels above: a date
   is read, and sandstone on this band is 3.68:1. */
.cs-event-more__date { font-variant-numeric: tabular-nums; color: var(--text-invert-muted); }
.cs-event-more__title { font-family: var(--font-display); font-size: var(--step-1); color: var(--cream); line-height: 1.2; }
.cs-event-more__who { font-size: var(--step--1); color: var(--text-invert-muted); }

/* The class is set by the script, so this only ever applies with a card
   above the pair. */
.has-next-talk .cs-next {
  margin-top: var(--space-lg);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--rule-invert);
}

/* --- Past talks -------------------------------------------------------
   Reads down like a column of rock: newest year at the top, older beneath,
   each year marked off by its own rule. Rows reuse the hairline and tabular
   figures already established by the exhibit index rather than introducing
   another card shape. */
/* .gallery-head leaves its h2 at the browser default, which lands BELOW the
   step-2 year markers inside the list and inverts the hierarchy. Scoped here
   rather than fixed on .gallery-head, which would also move the exhibits page.
   Ladder is now section 42.6px > year 32px > talk title 24px. */
.talks-head h2 { font-size: var(--step-3); }
.talks { margin-top: var(--space-md); }
.talks__year {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-variant-numeric: tabular-nums;
  width: fit-content;
  padding-bottom: 0.35rem;
  border-bottom: 3px solid var(--sandstone);
  margin-top: var(--space-lg);
}
.talks__year:first-child { margin-top: 0; }
.talks__list { list-style: none; padding: 0; margin-top: var(--space-sm); }
.talk {
  display: grid;
  gap: 0.4rem var(--space-md);
  padding: 1rem 0;
  border-bottom: 1px solid var(--rule);
  /* `center`, not `baseline`: the row now carries a 64px portrait, which has
     no useful baseline and would drag the text columns down against it. */
  align-items: center;
}
@media (min-width: 760px) {
  /* Every column here MUST be an `fr`. Each .talk is its own separate grid, and
     grid tracks do not align between sibling grids, so any content-sized track
     (`auto`, `max-content`) resolves per row against that row's own name. Both
     were tried: the date column's left edge then wandered over a 49px spread.
     `fr` is purely proportional, so independent rows still land on the same
     boundaries.
     The fractions are sized to the widest content each column has to hold at
     the 1240px wrap: title 498px PLUS ~22px for the play glyph on talks that
     have a recording, portrait plus name 257px, venue 358px. This split gives
     them 527 / 263 / 386, so nothing wraps and the middle column no longer
     sits on ~130px of empty space. Re-measure these if a longer title or a
     longer venue is ever added. */
  .talk { grid-template-columns: minmax(0, 1.50fr) minmax(0, 0.75fr) minmax(0, 1.10fr); }
}
.talk__title { font-family: var(--font-display); font-weight: 600; font-size: var(--step-1); line-height: 1.15; }
/* A parenthetical under a title, for the occasion a talk marked. Set in the
   body face so it reads as a note on the title rather than part of it.
   --clay-deep (5.9:1), not --clay (4.17:1), because this is small text. */
.talk__sub {
  display: block; margin-top: 0.28rem;
  font-family: var(--font-body); font-weight: 500; font-size: var(--step--1);
  letter-spacing: 0.03em; color: var(--clay-deep);
}
/* A talk with a recording makes its own title the link. That gives the five
   watchable evenings the weight they deserve on a page with nothing currently
   booked, and it needs no extra column. The play mark is the only signal at
   rest, so the list still reads as one clean column of titles. */
.talk__play {
  color: inherit; text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}
.talk__play:hover,
.talk__play:focus-visible { color: var(--clay-deep); border-bottom-color: var(--sandstone); }
/* svg is display:block globally, so this has to be put back inline. A literal
   &nbsp; sits before it in the markup so the glyph can never wrap onto a line
   of its own, orphaned from the title it belongs to. */
.talk__playicon {
  display: inline-block; vertical-align: -0.1em;
  width: 0.92em; height: 0.92em;
  color: var(--clay);
  transition: color 180ms var(--ease);
}
.talk__play:hover .talk__playicon,
.talk__play:focus-visible .talk__playicon { color: var(--clay-deep); }

/* --- The audio talk ---------------------------------------------------
   One talk in the archive was recorded as audio, not video, so it must not
   borrow the play triangle: at a glance that promises something to watch.
   It carries a waveform in the same 9.2r circle instead, which keeps the
   family resemblance while reading as sound, and the row states "Audio only"
   in words as well, because an icon alone is not a claim anyone can rely on.
   <details> so it works with JavaScript off. */
/* The waveform reads as three bars rather than a solid wedge, so it needs a
   touch more room than the triangle to stay legible at this size. */
.talk__playicon--audio { width: 1.02em; height: 1.02em; }
.talk__fmt {
  display: block; margin-top: 0.28rem;
  font-family: var(--font-body); font-weight: 600;
  font-size: var(--step--1); letter-spacing: 0.04em;
  text-transform: uppercase;
  /* --clay-deep at 5.9:1. --clay fails the normal-text bar at this size. */
  color: var(--clay-deep);
}
/* --- The player dialog ------------------------------------------------
   The native <audio controls> bar was tried inline first and cut: it is a
   white slab, and nothing else on this site is white. This is built from the
   palette instead, and it is a modal so the transport controls are never
   competing with a page full of other links.
   Shapes are taken from things already here: the round transport buttons
   echo the speaker portraits and the mail ring, and the seek bar is a
   stratum line like the seams and the year rules. Corners stay near-square
   at --radius; a soft rounded card would be exactly the generic panel this
   site keeps rejecting. */
.aplayer {
  width: min(100% - 2rem, 520px);
  /* Required, and it is not redundant. A modal <dialog> is centred by the UA
     stylesheet's `margin: auto`, which this sheet's `* { margin: 0 }` reset
     wipes out — so without this the dialog pins itself to the top left corner
     and nothing in the rule below looks wrong. */
  margin: auto;
  padding: var(--space-md);
  border: none;
  border-top: 3px solid var(--clay);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 18px 60px rgba(25, 27, 29, 0.34);
}
.aplayer::backdrop { background: rgba(25, 27, 29, 0.62); }
.aplayer__head { display: flex; align-items: start; justify-content: space-between; gap: var(--space-sm); }
.aplayer__eyebrow {
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  /* --clay-deep, not --clay: at this size it is normal text and needs 4.5:1. */
  color: var(--clay-deep);
}
.aplayer__title {
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-2); line-height: 1.12; margin-top: 0.3rem;
}
.aplayer__meta { font-size: var(--step--1); color: var(--text-muted); margin-top: 0.35rem; }
.aplayer__close {
  flex: none;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--rule); border-radius: 50%;
  background: none; color: var(--text-muted); cursor: pointer;
  transition: background 160ms var(--ease), color 160ms var(--ease);
}
.aplayer__close svg { width: 18px; height: 18px; }
.aplayer__close:hover,
.aplayer__close:focus-visible { background: var(--clay); color: var(--cream); border-color: var(--clay); }

.aplayer__transport {
  display: flex; align-items: center; justify-content: center;
  gap: var(--space-md);
  margin-top: var(--space-md);
}
/* `position: relative` so the numeral can sit inside the arrow's curl. */
.aplayer__skip {
  position: relative;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: none; background: none; cursor: pointer;
  color: var(--text-muted);
  transition: color 160ms var(--ease);
}
.aplayer__skip:hover, .aplayer__skip:focus-visible { color: var(--clay-deep); }
.aplayer__skip svg { width: 30px; height: 30px; }
.aplayer__skip span {
  position: absolute; top: 55%; left: 50%; translate: -50% -50%;
  font-size: 0.66rem; font-weight: 600; font-variant-numeric: tabular-nums;
}
/* Circular, not the logo oval. The oval belongs to labelled buttons; a
   transport control is a roundel, which this site already speaks in. */
.aplayer__toggle {
  width: 68px; height: 68px;
  display: grid; place-items: center;
  border: none; border-radius: 50%;
  background: var(--clay); color: var(--cream);
  cursor: pointer;
  box-shadow: var(--shadow-card);
  transition: background 160ms var(--ease), transform 160ms var(--ease);
}
.aplayer__toggle:hover { background: var(--clay-deep); transform: translateY(-2px); }
.aplayer__toggle:active { transform: translateY(0); }
.aplayer__toggle svg { width: 28px; height: 28px; }
.aplayer__toggle svg[hidden] { display: none; }

/* One track, painted by a gradient stop that JS moves. A second overlaid
   element would have to be kept in sync with the thumb's own inset. */
.aplayer__seek {
  -webkit-appearance: none; appearance: none;
  width: 100%; margin-top: var(--space-md);
  height: 6px; border-radius: 0;
  background: linear-gradient(to right,
    var(--clay) 0 var(--progress, 0%),
    var(--sand) var(--progress, 0%) 100%);
  cursor: pointer;
}
.aplayer__seek:disabled { cursor: default; opacity: 0.5; }
.aplayer__seek::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--clay-deep); border: 2px solid var(--surface);
  box-shadow: 0 1px 4px rgba(25,27,29,0.3);
}
.aplayer__seek::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--clay-deep); border: 2px solid var(--surface);
}
.aplayer__seek:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }

.aplayer__times {
  display: flex; justify-content: space-between;
  margin-top: 0.5rem;
  font-size: var(--step--1); color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.aplayer__note { margin-top: var(--space-sm); font-size: var(--step--1); }
.aplayer__dl { color: var(--clay-deep); text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 420px) {
  .aplayer { padding: var(--space-sm); }
  .aplayer__transport { gap: var(--space-sm); }
}

/* The portrait belongs to the speaker, so it sits with the name rather than
   leading the row and outranking the talk title. */
.talk__who { display: flex; align-items: center; gap: 0.85rem; min-width: 0; }
/* The headshots arrive already cut as circles, and the series' own emblem is a
   roundel, so the circle is taken from the source material rather than being a
   stock avatar shape. The ring echoes the roundel's gold band. */
.talk__face {
  flex: none; width: 64px; height: 64px;
  border-radius: 50%;
  border: 2px solid var(--sandstone);
  background: var(--surface);
  box-shadow: 0 2px 8px rgba(25, 27, 29, 0.14);
}
.talk__speaker { font-size: var(--step-0); font-weight: 500; }
.talk__where { font-size: var(--step--1); color: var(--text-muted); }
.talk__date { display: block; font-variant-numeric: tabular-nums; }
.talk__venue { display: block; }

/* ============================================================
   Creation on the Road
   ============================================================ */

/* NB the .cs-intro / .cs-mark block above is shared with this page. It is the
   "series page" opener (roundel mark, copy), not anything specific to Creation
   Speaks, and both Learn pages use it. The cs- prefix is now a misnomer;
   renaming would touch both pages, so it has been left alone deliberately.
   This page also carries .cotr-intro, below, which resizes the mark. Creation
   Speaks does not, and is unaffected. */

/* --- Road zone ---------------------------------------------------------
   Same construction as .leaf-zone: one wrapper owning the photograph and the
   vignette across the top seam, the section and the bottom seam, with
   everything inside transparent. z-index -1 paints these above the zone's own
   base colour but below every descendant; `isolation: isolate` keeps that
   negative index from escaping upward.
   The photograph is a desert highway, which is the program in one image, and
   its rust and ochre ground is already the site's palette.

   IT SITS ON THE SAND GROUND, NOT A DARK ONE, and that was measured rather
   than chosen. A dark treatment with cream text was built first and the user
   found it too heavy. It cannot be rescued: sweeping base colour, photo
   opacity and vignette, the lightest dark version that still clears 4.5:1 for
   cream body copy reaches a mean luminance of 0.045 against the 0.030 it
   already had, which nobody would notice, and it spends the whole safety
   margin to get there. Pushing the picture to a genuinely open brightness puts
   the text at 1.9 to 2.6:1. A `contrast()`/`brightness()` filter to lift the
   shadows was tried too and is worse: brightness raises the highlights, which
   is the half that matters.
   The picture's presence and the text's legibility come out of one budget, so
   the ground has to be chosen first: a strong picture with light text, or a
   strong picture with dark text. This is the second.

   The first pass at the light version put the photo at 0.24 and the user found
   THAT too light, a watermark rather than a photograph. What buys the middle
   is darkening the TEXT rather than touching the picture. WCAG constrains the
   worst pixel against the text colour, so dropping the body copy from
   --text-muted to full --text moves the floor a long way: the same 4.5:1 that
   capped the photo at 0.24 allows 0.58 once the copy is ink. The eyebrow needs
   the same treatment and goes further still, see below.
   Measured mean luminance of the three versions, for anyone tempted to move
   it again: dark 0.030, watermark 0.574, this 0.478. */
.road-zone { position: relative; isolation: isolate; background-color: var(--bg); }
.road-zone::before,
.road-zone::after { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.road-zone::before {
  background-image: url("../assets/img/road-bg.jpg");
  background-size: cover;
  /* 58% rather than centre: the horizon and the road matter, the empty top of
     the sky does not, and at these wide aspect ratios `cover` has to crop
     something. */
  background-position: center 58%;
  /* Solved for, not eyeballed, by the method the leaf zone used: rebuild the
     composite on a canvas (ground + photo at this opacity + the veil below),
     then take the WORST pixel inside each text element's box and compute its
     contrast. On a light ground the enemy is the DARK pixels, the asphalt and
     the deep blue sky, which is the opposite of the dark version's problem.
     With ink copy and the eyebrow colour below, 0.58 holds the tightest
     element at 5.4:1. Past that it stops paying: 0.68 drops the eyebrow to
     4.65, and lifting the veil to recover it takes back the picture the extra
     opacity just bought. */
  opacity: 0.58;
}
.road-zone::after {
  /* A lifting veil rather than a darkening vignette, and strongest in the
     MIDDLE where the text sits, easing toward the edges so the picture stays
     readable at the margins. The usual edges-dark vignette is exactly wrong
     here: it would deepen the corners on a light ground and leave the shadowed
     asphalt sitting under the copy untouched. */
  background:
    radial-gradient(120% 90% at 50% 50%,
      rgba(229, 214, 185, 0.60) 28%,
      rgba(226, 206, 166, 0.50) 70%,
      rgba(219, 201, 164, 0.42) 100%);
}
.road-zone .wave { background: transparent; }

/* Both of these are DARKER than the same elements elsewhere on the site, and
   that is what pays for the photograph. Every step darker in the text is a
   step the picture can take toward full strength at the same 4.5:1.
   Body copy at full --text rather than --text-muted, measured 6.8:1 here.

   It is also BIGGER and HEAVIER than body copy elsewhere, and that is a
   separate problem from contrast. The ratios here run 5.4:1 to 7:1, comfortably
   past the bar, and the copy was still harder to read than the same words on
   flat sand: a busy ground interrupts letter shapes at the stroke, which a
   contrast figure computed per pixel cannot see. Weight and size are the fix
   for that, not more scrim. --step-1 at 500 rather than --step-0 at 400, which
   also suits this block being the page's opening statement.
   Barlow is loaded at 400/500/600 only, so 500 is a real face and not a
   synthesised one. Keep it in that set if it is ever changed. */
.road-zone .cs-intro__body > p:not(.eyebrow) {
  color: var(--text);
  font-size: var(--step-1);
  font-weight: 500;
}
/* The name of the talk, which was `bold` and would therefore have asked for a
   700 Barlow that is not loaded. 600 against the surrounding 500. */
.road-zone .cs-intro__body strong { font-weight: 600; }
/* Fraunces has a real 700. On flat sand the 600 heading is emphatic enough;
   over a photograph it wants the extra stroke. */
.road-zone .cs-intro__body h2 { font-weight: 700; }
/* The eyebrow is the tightest element on the band, being 14.4px, and neither
   clay token survives: --clay measures 2.39:1 on this ground and --clay-deep
   3.57:1, both well under 4.5. This is one step deeper again, and measures
   5.4:1. Kept as a literal rather than promoted to a token because it exists
   to solve this one photograph, not to join the palette. If the photo opacity
   is ever changed, re-measure THIS first: it fails before anything else does.
   Also a notch up in size and weight for the same reason as the body copy:
   letterspaced small caps are the most fragile thing on a busy ground, since
   the tracking hands the background a gap between every pair of letters. It
   still sits BELOW the body size, which is the site-wide rule for eyebrows. */
.road-zone .eyebrow {
  color: #4A2C14;
  font-size: var(--step-0);
  font-weight: 700;
}

/* --- The mark, sized to stand as tall as the copy beside it ------------
   The shared 290px does not: with no scripture block this page's copy is much
   taller and the logo floated against the heading.
   THE THREE NUMBERS ARE ONE SUM AND MOVE TOGETHER:
     439 mark + 64 gap + 580 copy = 1083.
   Re-derive them whenever this section's copy is edited. Adding one sentence
   to the first paragraph cost a line and put the sum out by 39px, and deleting
   the "we are currently offering" paragraph outright (moved to the band below
   as Current Offerings) took the copy from 446px tall to 353 and put it out by
   93. The copy is now one paragraph, so the plateaux are wide: 438px tall
   holds from 540 to 620, and 580 is the middle of it.
   Re-derived when the copy went to --step-1/500 for legibility over the
   photograph, which is exactly the trap to watch for: bigger type made the
   copy 492px tall while the mark was still capped at 352 wide, so the artwork
   stopped meeting the text even though a box-level check still reported both
   edges aligned. `object-fit: contain` letterboxes rather than distorts, so
   the BOX kept matching while the picture inside it shrank away from the
   edges. Measure the rendered artwork, not the element.
   Widening the copy is the fix, not shrinking the type back. Pick the copy
   width off the PLATEAU rather than at a step, so a small edit cannot move it.
   Narrowing the copy is what keeps the mark large here: 640 to 660 buys a
   399px block and 680 to 740 a 353px one, but each of those shrinks the mark
   to match, and the mark was enlarged in the first place because the user
   asked for it to meet the text properly. 580px of 24px Barlow is about 52
   characters, inside a sound measure. */
.cotr-intro { max-width: 1083px; }
@media (min-width: 900px) {
  .cotr-intro { grid-template-columns: minmax(200px, 439px) 1fr; }
  /* Stretched to the row rather than given a fixed square, so the mark still
     matches if the copy is ever edited, and `contain` keeps the artwork true
     below 1172 where the copy wraps taller than the track is wide.
     Overrides the block's `align-items: start`. */
  .cotr-intro .cs-mark {
    align-self: stretch;
    width: 100%; height: 100%;
    object-fit: contain;
  }
}

/* The talk and the speaker are peers, so they sit side by side with the rule
   on the divider rather than under either heading.
   0.95 / 1.05, slightly favouring the speaker: that column carries the 150px
   portrait as well as its text, and the padding-left of the divider. Measured
   across 900 to 1240, this split keeps the two columns' natural heights within
   about 20px of each other, which is what keeps the slack below invisible. */
.cotr-talk { display: grid; gap: var(--space-lg); }
@media (min-width: 900px) {
  .cotr-talk { grid-template-columns: 0.95fr 1.05fr; }
  .cotr-talk__aside { padding-left: var(--space-lg); border-left: 1px solid var(--rule-invert); }
}
/* Eyebrow pinned to the top, body pinned to the bottom, with the 1fr row
   swallowing whatever is left over. Both halves therefore START and END on the
   same line no matter which one runs longer, and no matter how the copy is
   later edited. Tuning column widths until the text happened to match was the
   first attempt and it only held at one viewport width: the two columns reflow
   at different rates, so the bottoms drifted up to 80px apart in between. */
.cotr-talk__col { display: grid; grid-template-rows: auto 1fr; }
.cotr-talk__body { align-self: end; margin-top: var(--space-sm); }
/* --step-2, matching the pair of headings in the Creation Speaks band: the
   clay ground already carries the emphasis, and this heading now sits under
   the band's own "Current Offerings" h2, so it must read as smaller than it.
   An h3, so `.band h2` never applies and the cream has to be set here. */
.cotr-talk h3 { font-size: var(--step-2); color: var(--cream); }

/* The featured speaker has no heading of his own: the bio opens with his name
   in bold, so a title above it repeated the same three words.
   Portrait ABOVE the bio, not beside it. Beside was tried: the portrait is a
   fixed 150px inside a column that also gives up 64px to the divider padding,
   so as the band narrows the bio gets crushed into a ~180px measure and the
   column shot up to 865px tall at 900. Above, the paragraph always has the
   full column width and the block scales smoothly. */
/* Deliberately NO `background` behind the image, unlike .talk__face: on the
   sand ground a cream fill hides any gap at the circle's edge, but on clay it
   would read as a bright ring around the photograph. The portrait arrived
   already cut as a circle that fills its canvas, verified, so there is nothing
   to hide. */
.cotr-speaker__face {
  display: block;
  width: 150px; height: 150px;
  border-radius: 50%;
  border: 2px solid var(--sandstone);
  box-shadow: 0 3px 12px rgba(25, 27, 29, 0.3);
}
.cotr-speaker__bio { margin-top: var(--space-sm); }

/* --- The portrait fills whatever slack the column has -------------------
   The bio is shorter than the message beside it, and `.cotr-talk__body`
   bottom-aligns, so the difference used to show as dead space under THE
   SPEAKER: 91px of it at 1240 once Current Offerings and the duration line
   went in. The portrait absorbs it instead, so the eyebrow-to-content gap is
   32px in BOTH columns, the same as the left one's eyebrow to its h3.

   HOW, because it is not obvious and two simpler versions were wrong. The
   slack has to reach the image without the image adding to the column's
   height, or the right column simply becomes the taller one and the band
   grows: `height: 100%; max-height: 240px` did exactly that, +51px at 1240,
   because an image sized off an indefinite track falls back to its INTRINSIC
   height and contributes that. `height: 0` contributes nothing, and
   `min-height` fills the track once track sizing has made it definite.
   The floor is on the TRACK, not the image, for the same reason.

   The cap is inside `min-height`, not a `max-height`: a minimum always beats
   a maximum in CSS, so a `max-height` next to `min-height: 100%` is ignored.
   Same trap as the SimpleBooklet iframe.

   Measured 900 to 1240: gap a constant 32, portrait 180 to 240, column
   bottoms level throughout, band height unchanged from the 150px version.
   240 is the cap because the asset is 480px and that keeps it 2x. */
@media (min-width: 900px) {
  .cotr-speaker {
    /* Overrides `.cotr-talk__body { align-self: end }`: the block now spans
       the free space instead of sitting at the bottom of it. */
    align-self: stretch;
    display: grid;
    grid-template-rows: minmax(150px, 1fr) auto;
  }
  .cotr-speaker__face {
    width: auto; height: 0;
    min-height: min(100%, 240px);
    align-self: start; justify-self: start;
  }
}
/* The bolded name replaces the heading that used to sit above this paragraph,
   so it needs the display face to read as more than emphasis mid-sentence. */
.cotr-speaker__bio strong {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--cream);
}

/* The SimpleBooklet embed's rules stood here: `.tract`, `.tract__frame` and
   `.tract__fallback`. Deleted 2026-08-24, when the user chose the in-house
   reader over the embed and the iframe left the site. The reader's own styles
   are further down under "The Language of You reader". */

/* ============================================================
   Partners
   ============================================================ */
.partners { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-lg); }

/* Same card treatment as the homepage reviews — surface, hairline, 22px
   radius, card shadow — so a partner reads as one object in a list rather
   than as a slab of page. */
.partner {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 22px;
  box-shadow: var(--shadow-card);
  padding: var(--space-md);
  display: grid;
  gap: var(--space-md);
}
/* TWO breakpoints, and the middle one is the point of the exercise. The three
   regions are 300 + 200 + copy, and three columns only fit once the card is
   wide enough to leave the copy a real measure. Going straight to three at 900
   was the first version and it crushed the copy to 142px at that width, about
   sixteen characters. Exactly the fault the Creation on the Road speaker column
   already hit: a fixed-width portrait beside text does not narrow gracefully,
   it just eats the text's column.
   So below 1240 the logo and the portrait stack in ONE left column and the copy
   takes all the rest, and only from 1240 do the three sit in a row. 1240 rather
   than the 1180 first tried, because at 1180 three-across still left the copy
   380px, about 42 characters, when two columns at the same width would have
   given it 638. The three-across arrangement is the artwork's, and it is worth
   having, but not at the price of a cramped measure: it earns its place only
   once the copy clears ~440. That is also where `.wrap` stops growing, so the
   copy settles at 442 to 467 and goes no narrower. */
@media (min-width: 900px) {
  .partner {
    grid-template-columns: minmax(240px, 300px) 1fr;
    grid-template-areas:
      "brand body"
      "face  body";
    gap: var(--space-md) var(--space-lg);
    /* The regions are different lengths and none of them should stretch to
       match: the logo would blow up and the portrait would go oval. */
    align-items: start;
  }
  .partner__brand { grid-area: brand; }
  .partner__face  { grid-area: face; }
  .partner__body  { grid-area: body; }
}
@media (min-width: 1240px) {
  .partner {
    grid-template-columns: 300px 200px minmax(380px, 1fr);
    grid-template-areas: "brand face body";
    gap: var(--space-lg);
    padding: var(--space-lg);
  }
  /* Centred against the whole card, which is what the printed piece does.
     Only in the three-across layout: stacked under the logo it belongs at the
     top of its own row, not floating in the middle of one. */
  .partner__face { align-self: center; }
}

.partner__name { margin: 0; }
/* Capped by its 300px track, so the 600px asset lands at 2x. `height: auto`
   is not optional beside the width/height attributes: those become a
   presentational height that would otherwise beat the intrinsic ratio and
   squash the artwork. Same trap as the Creation on the Road mark. */
.partner__logo { display: block; width: 100%; height: auto; }
/* Round badges only. A seal is roughly as tall as it is wide, so filling the
   300px track stands it 220 high next to a horizontal lockup's 66 and it reads
   as the loudest thing on the page rather than as one item in a list. Capping
   the WIDTH rather than the height keeps `height: auto` doing the work, so the
   width/height attributes still describe the ratio and nothing is squashed. */
.partner__logo--seal { max-width: 246px; }

.partner__verse {
  margin: var(--space-md) 0 0;
  padding-top: var(--space-sm);
  /* Ruled on ONE edge here, unlike .cs-verse, which is ruled top and bottom.
     That block is a full-width statement; this one is a footnote under a logo
     inside a card that already has a border of its own, and two more rules
     inside it read as clutter. */
  border-top: 1px solid var(--rule);
  /* Scripture face. This was the other half of the audit's finding: set in
     Barlow at --step--1, it matched the partner card's own body copy exactly.
     It stays SMALLER than the other scripture on the site — it is a footnote
     under a logo inside a card, not a statement — but it is no longer the same
     type as the prose beside it. */
  font-family: var(--font-scripture);
  font-size: calc(var(--step--1) * var(--scripture-scale));
  line-height: 1.5;
  color: var(--text-muted);
}
.partner__verse cite {
  display: block;
  margin-top: 0.5rem;
  /* cite defaults to italic and Fraunces has no italic axis; set upright to
     match every other scripture reference on the site. */
  font-style: normal;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--clay-deep);
}

/* The ring matches the speaker portraits. NO `background` behind it, unlike
   `.talk__face`: that fill exists to hide a gap at the circle's edge, and this
   photograph was checked as a circle filling its canvas 100%, so there is no
   gap and the fill would only show as a bright rim. */
.partner__face {
  display: block;
  width: 100%; max-width: 200px; height: auto;
  justify-self: center;
  border-radius: 50%;
  border: 2px solid var(--sandstone);
  box-shadow: 0 3px 12px rgba(25, 27, 29, 0.18);
}

.partner__body { display: grid; gap: var(--space-sm); align-content: start; }
.partner__body p { max-width: var(--measure); }
/* Both exclusions are load-bearing. `.eyebrow` because this rule outranks it
   and would silently grey the label out; `.partner__thanks` because it
   outranks that too, and an `!important` to win it back would be the wrong
   fix for a specificity problem of our own making. */
.partner__body > p:not(.eyebrow):not(.partner__thanks) { color: var(--text-muted); }
/* The museum's own line, so it leads the column at full ink rather than
   sitting level with the partner's description of themselves underneath. */
.partner__thanks { color: var(--text); }
.partner__thanks strong { font-family: var(--font-display); font-weight: 600; color: var(--text); }
/* The label that marks the change of voice. Its default bottom margin would
   double up with the grid gap. */
.partner__body .eyebrow { margin-bottom: 0; }

.partner__more {
  justify-self: start;
  font-weight: 600;
  color: var(--clay-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ============================================================
   Our Story
   ============================================================ */
/* The founder's portrait beside the founding copy. Same shape as .cs-intro,
   but the picture is a portrait rather than a square mark. The source file is
   only 300px wide, so the column is capped there and the photograph is never
   asked to upscale. Stacked below 900 rather than narrowed: a fixed-width
   image beside text in a narrowing column eats the text's measure, which is
   what crushed the Creation on the Road speaker column to sixteen characters. */
.founder { display: grid; gap: var(--space-lg); align-items: start; max-width: 980px; }
@media (min-width: 900px) {
  .founder { grid-template-columns: minmax(220px, 300px) 1fr; }
}
.founder__portrait { width: min(100%, 300px); justify-self: center; }
.founder__portrait .frame { --tilt: 1.4deg; }
/* Required, not redundant. `.frame img { height: 100% }` is written for the
   fixed-ratio gallery cards; same specificity, so this must stay BELOW it.
   `height: auto` also stops the width/height attributes on the <img> from
   supplying a concrete height and cancelling the aspect ratio. */
.founder__portrait img { aspect-ratio: 300 / 448; height: auto; }
.founder__caption {
  margin-top: var(--space-sm);
  text-align: center;
  font-size: var(--step--1);
  color: var(--text-muted);
}
.founder__body { display: grid; gap: var(--space-sm); }
.founder__body h2 { font-size: var(--step-3); }
/* Both qualifiers matter, for the reasons written out against .cs-intro__body:
   `:not(.eyebrow)` because this rule outranks `.eyebrow` and would grey it
   out, and `>` so it cannot reach into the pull quote below. */
.founder__body > p:not(.eyebrow) { color: var(--text-muted); max-width: var(--measure); }

/* --- Pull quote ------------------------------------------------------
   ONE rule, on top only. The scripture block on Creation Speaks is ruled top
   AND bottom, and that pairing belongs to scripture; a single stratum line
   keeps a spoken quote visibly distinct from a verse, and keeps this page
   from stacking two rule devices within a few inches of each other. */
.story-quote {
  margin-top: var(--space-lg);
  padding-top: var(--space-sm);
  border-top: 2px solid var(--sandstone);
  max-width: 700px;
}
.story-quote p {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.28;
  color: var(--text);
}
.story-quote cite {
  display: block;
  margin-top: 0.8rem;
  font-family: var(--font-body);
  /* cite defaults to italic and the loaded Fraunces has no italic axis, so
     the attribution is set upright to match the verse blocks. */
  font-style: normal;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  /* --clay-deep (5.9:1) rather than --sandstone, which all but vanishes on
     this sand ground. */
  color: var(--clay-deep);
}

/* Heading left, prose right, the same arrangement as the homepage intro.
   Three paragraphs alone in one --measure column left about half the 1240
   wrap empty down the right side: the identical hole the Nifty Fifty band
   and .cs-intro both had to be capped to avoid. Here there is a heading big
   enough to fill the other half, so it moves beside the prose instead. */
.story-split { display: grid; gap: var(--space-lg); grid-template-columns: 1fr; }
/* Two columns, and the left one carries the heading at the TOP and the pull
   quote at the BOTTOM. Before this the left column held nothing but a two-line
   heading against four paragraphs of prose, which left roughly half a screen
   of dead space under it — the user flagged it 2026-08-25.
   The quote is placed here rather than reordered here: it stays third in the
   document so that below 900, where this collapses to one column, it still
   reads as the coda to the prose rather than as an epigraph before it. Same
   principle as the volunteer page's splits — placement is the grid's job,
   order is the document's.
   `1fr` on row 2 is what does the work: the prose spans both rows and sets the
   height, row 2 absorbs whatever is left over, and `align-self: end` drops the
   quote onto the prose's own baseline. The leftover then hides as breathing
   room under the heading instead of piling up at the bottom. Same device as
   the Creation on the Road talk band, and it holds at any width and after any
   copy edit, which is exactly what tuning the column widths could not do. */
@media (min-width: 900px) {
  .story-split {
    grid-template-columns: 1fr 1.25fr;
    grid-template-rows: auto 1fr;
    align-items: start;
  }
  .story-split > :first-child { grid-column: 1; grid-row: 1; }
  .story-split .story-body    { grid-column: 2; grid-row: 1 / span 2; }
  /* align-self beats the container's align-items: start. */
  .story-split .story-aside   { grid-column: 1; grid-row: 2; align-self: end; }
}
.story-split h2 { font-size: var(--step-3); }
.story-body { display: grid; gap: var(--space-sm); }
.story-body > p { color: var(--text-muted); max-width: var(--measure); }
/* Sits directly under the closing pull quote, which is taken from this very
   recording, so the offer to hear the rest lands where the reader has just
   been given a taste of it. Not a second oval button: listening is a
   different kind of act from "See the Exhibits" and should not compete with
   it for the same shape. */
.story-listen { margin-top: var(--space-md); }
.story-listen__link {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-1); color: var(--clay-deep);
  text-decoration: none;
  border-bottom: 2px solid var(--sandstone);
  padding-bottom: 0.15rem;
  transition: border-color 180ms var(--ease), opacity 180ms var(--ease);
}
.story-listen__link:hover,
.story-listen__link:focus-visible { border-bottom-color: var(--clay-deep); }
/* svg is display:block site-wide, which is what we want inside the flex row;
   `flex: none` stops it being squeezed when the label wraps on a phone. */
.story-listen__icon { flex: none; width: 1.35em; height: 1.35em; }
.story-listen__note {
  display: block; margin-top: 0.45rem;
  font-size: var(--step--1); color: var(--text-muted);
}

.story-cta { margin-top: var(--space-lg); }

/* The clay band's opening paragraph needs real air beneath it. `.band p`
   supplies a top margin only, so without this the three column headings
   start one line below the prose and read as a continuation of it. */
.band__lead { margin-bottom: var(--space-lg); }

/* ============================================================
   Footer
   ============================================================ */
.site-footer { background: var(--ink); color: var(--text-invert-muted); padding-block: var(--space-lg) var(--space-md); }
.site-footer__brand {
  display: flex; align-items: center; gap: var(--space-md); flex-wrap: wrap;
  padding-bottom: var(--space-md);
  margin-bottom: var(--space-lg);
  border-bottom: 1px solid var(--rule-invert);
}
.site-footer__brandmark { display: flex; flex-direction: column; align-items: center; gap: var(--space-sm); }
.site-footer__brand img { height: 96px; width: auto; }
.site-footer__brand p { font-size: var(--step--1); max-width: 34ch; }

/* Must sit below .site-footer__brand p — equal specificity, so source order
   decides which max-width and font-size win. */
.site-footer__verse { margin: 0; flex: 1 1 20ch; min-width: 0; }
/* Scripture face, and WEIGHT 500 rather than 400. On the ink footer a 400
   Garamond went thin and silvery where Fraunces had held: the small x-height
   and fine hairlines that read well on sand thin out against a dark ground.
   500 restores the colour of the text without making it look bold. The three
   dark-ground verses (here, .pagehead__verse and .band .cs-verse) all take it.
   SUPERSEDED IN PART, 2026-09-01: `.cs-verse` scripture is now 500 on EVERY
   ground, at the user's instruction, so the sand/dark split no longer applies
   to it. The two still at 400 are `.tract-text__body blockquote p` and
   `.partner__verse`, which were flagged and not swept. */
.site-footer__verse p {
  font-family: var(--font-scripture); font-weight: 500;
  font-size: calc(var(--step-0) * var(--scripture-scale)); line-height: 1.5;
  max-width: 44ch;
  color: var(--text-invert-muted);
  /* No italic: the loaded Fraunces has no italic axis, so it would be faux
     obliqued — bad on a display serif. */
}
.site-footer__verse cite {
  display: block; margin-top: 0.6rem;
  font-style: normal; font-family: var(--font-body);
  font-size: var(--step--1); text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow); color: var(--sandstone);
}

/* Fills the empty right half of the brand row. margin-left:auto pushes it to
   the far edge while the logo and tagline stay left. */
.site-footer__place {
  margin-left: auto;
  flex: 1 1 360px;
  max-width: 620px;
  /* 0.45rem when the address was --step--1 with no underline. The promoted
     address is taller AND carries a rule 4px under its baseline, which ate
     most of that gap and left the underline nearly touching the map border. */
  display: flex; flex-direction: column; gap: 0.7rem;
}
/* THE ADDRESS IS THE LOUDEST THING IN THE FOOTER, DELIBERATELY. It used to
   inherit `.site-footer a` wholesale — --step--1 at 72% cream with no
   underline — which made the museum's street address the quietest line on the
   panel; outside reviewers of the preview site read the footer and did not
   register that the address was there at all. So it is promoted: --step-0,
   full cream, and an underline AT REST so it reads as a link before anyone
   hovers it. Everything around it stays --step--1 at 72%, and that gap is
   what does the work.
   SPECIFICITY, AND WHY THE SELECTOR IS DOUBLED: `.site-footer a` (0,1,1) at
   the bottom of this section sets the footer link size and kills underlines.
   A bare `.site-footer__addr` (0,1,0) loses to it and `a.site-footer__addr`
   (0,1,1) only ties and then loses on source order, so the size and the
   underline would both silently revert. `.site-footer .site-footer__addr`
   (0,2,0) is the smallest selector that actually wins. */
.site-footer .site-footer__addr {
  align-self: flex-start;
  font-size: var(--step-0);
  color: var(--cream);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  text-decoration-color: var(--rule-invert);
  /* At --step--1 the address fitted one line down to 320px. At --step-0 it
     does not, and the natural break leaves "OH 44321" alone on a 63px second
     line. Balance splits it near the middle instead ("...Massillon /
     Rd, Copley, OH 44321"). A no-op wherever it still fits on one line. */
  text-wrap: balance;
  transition: color 160ms var(--ease), text-decoration-color 160ms var(--ease);
}
.site-footer .site-footer__addr:hover,
.site-footer .site-footer__addr:focus-visible { text-decoration-color: currentColor; }

.site-footer__map {
  height: 168px;              /* matches the 96px logo plus its breathing room */
  border: 1px solid var(--rule-invert);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--ink);
}
.site-footer__map iframe {
  display: block; width: 100%; height: 100%; border: 0;
  /* Neither the keyless embed nor the Embed API accepts a style parameter, so
     dark mode is done optically: invert flips the light map dark and the hue
     rotation puts water and land back near their real hues. The desaturation
     matters more than it looks — Copley reads as solid tree canopy at this
     zoom, and inverted green leaves a heavy cast over the whole panel. */
  filter: invert(100%) hue-rotate(180deg) saturate(0.32) brightness(0.9);
}
@media (max-width: 700px) {
  .site-footer__place { margin-left: 0; flex-basis: 100%; }
  .site-footer__map { height: 180px; }
}

.site-footer__grid { display: grid; gap: var(--space-md); grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); }
/* --- Even gaps once the groups all fit on one row ----------------------
   The auto-fit tracks above are equal width, but the LINKS inside them are
   not, so the gap the eye actually sees is (track - widest link) + 32 and it
   varies with whatever each column happens to contain. Measured at 1221:
   About-Visit 125, Visit-Support 112, Support-Discover 108, Discover-Learn
   141, Learn-Believe 71. The user flagged the two widest, which is exactly
   what this produces — Discover holds "Exhibits" at 59px, Believe holds
   "The Language of You" at 129.
   Sizing the tracks to their content and letting justify-content share out
   the slack makes every visible gap identical, and it stays correct if a
   group's links are ever renamed. `grid-auto-flow: column` rather than a
   hardcoded repeat(6), so adding or removing a nav group needs no change
   here; `grid-template-columns: none` is required to clear the auto-fit
   tracks above, or the items flow into those instead.
   1205px is where the six columns first fit: 6 x 165 + 5 x 32 = 1150 of grid
   width, which this layout reaches at about that viewport. Below it the
   auto-fit wrapping is left exactly as it was — space-between on a part-full
   final row would push two groups to opposite edges, which is what happens at
   the four-column widths (roughly 811 to 1008). */
@media (min-width: 1205px) {
  .site-footer__grid {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: max-content;
    justify-content: space-between;
  }
}
.site-footer h4 { font-family: var(--font-body); font-size: var(--step--1); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); color: var(--sandstone); margin-bottom: var(--space-sm); }
.site-footer ul { list-style: none; padding: 0; display: grid; gap: 0.5rem; }
.site-footer a { text-decoration: none; font-size: var(--step--1); }
.site-footer a:hover { color: var(--cream); }

/* Selector must out-specify `.site-footer ul`, which sets display:grid above
   and would otherwise win on specificity no matter where this sits. */
.site-footer .social {
  display: flex; gap: 0.6rem;
  list-style: none; padding: 0; margin: 0;
}
.site-footer .social a {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border: 1px solid var(--rule-invert);
  border-radius: var(--radius-oval);
  --brand: var(--cream);
  --brand-tint: rgba(250, 245, 234, 0.16);
  color: var(--brand);
  transition: color 160ms var(--ease), border-color 160ms var(--ease), background-color 160ms var(--ease);
}

/* Each platform's own colour. X's mark on a dark ground is white, and --cream
   is this site's white, so it stays in the palette instead of glaring.
   Instagram is a gradient the glyph carries itself (fill="url(#ig-grad)" in the
   markup, which beats the inherited currentColor below); --brand here is only
   the pink midpoint of that gradient, used for the ring and hover tint. */
.site-footer .social .is-ig { --brand: #E1306C; --brand-tint: rgba(225,  48, 108, 0.16); }
.site-footer .social .is-fb { --brand: #1877F2; --brand-tint: rgba( 24, 119, 242, 0.18); }
.site-footer .social .is-yt { --brand: #FF0000; --brand-tint: rgba(255,   0,   0, 0.16); }

.site-footer .social svg { width: 17px; height: 17px; display: block; fill: currentColor; }

/* Hover brings the ring up to the brand colour rather than washing the glyph
   out to cream, which on a coloured resting state read as the icon going dim. */
.site-footer .social a:hover,
.site-footer .social a:focus-visible {
  border-color: var(--brand);
  background-color: var(--brand-tint);
}
.site-footer__base { margin-top: var(--space-lg); padding-top: var(--space-md); border-top: 1px solid var(--rule-invert); font-size: var(--step--1); display: flex; flex-wrap: wrap; gap: var(--space-sm); justify-content: space-between; }
.site-footer__logo img { height: 96px; width: auto; margin-bottom: var(--space-sm); }

/* --- TODO marker for facts awaiting confirmation --- */
.todo {
  background: #FFF3C4; color: #6B4E00;
  padding: 0.05em 0.4em; border-radius: 2px;
  font-size: 0.9em; font-weight: 600;
}
.band .todo, .visitbar .todo { background: rgba(255, 243, 196, 0.92); }

/* ============================================================
   Mobile nav
   ============================================================ */
@media (max-width: 980px) {
  /* On a phone the hero image is only ~210px tall, so an overlaid bar would
     sit across the top of the Ohio outline. Put the header back in normal
     flow here — the image starts cleanly beneath it.
     SUPERSEDED 2026-08-22: the bar stays `fixed` on small screens too, so the
     artwork runs underneath it and shows through. It was sticky back when the
     mobile image was only ~210px tall and an overlaid bar would have sat
     across the Ohio outline; the mobile crop is taller now and it clears. */
  :root { --header-h: 64px; }

  .hero__content { padding-block: var(--space-sm) var(--space-md); }
  .site-header__logo img { height: clamp(50px, 12vw, 64px); }

  /* Toggle sits in the left column, logo stays centred */
  .nav-toggle { display: block; grid-column: 1; grid-row: 1; justify-self: start; border-color: rgba(250,245,234,0.4); color: var(--cream); }

  /* The two menu groups stop being header columns and stack into one panel */
  .nav__panel {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    background: rgba(25, 27, 29, 0.96);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--rule-invert);
    box-shadow: var(--shadow-card);
    padding: var(--space-sm) 1.25rem var(--space-md);
    max-height: 72svh; overflow-y: auto;
  }
  .nav__panel[data-open="true"] { display: block; }
  .nav-group { display: block; }
  .nav__item { border-bottom: 1px solid var(--rule-invert); }
  .nav__link, .nav__trigger { width: 100%; justify-content: space-between; padding-block: 0.95rem; }
  .nav__submenu a { color: var(--cream); }

  /* Submenus expand inline rather than floating */
  .nav__submenu {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: none; background: transparent;
    min-width: 0; padding: 0 0 0.6rem 0.5rem;
    display: none;
  }
  .nav__item[data-open="true"] .nav__submenu { display: block; }

  /* `.site-header__inner { position: relative }` used to be declared here,
     to anchor the absolute panel above. It is unconditional now — `.mapbtn`
     needs the same containing block at every width — so it is gone from this
     query rather than restated. */
  .site-header__logo { grid-column: 2; }
}

/* ============================================================
   Tract reader (The Language of You)
   ============================================================ */

/* The panels are images of the real printed artwork, sliced from the print
   PDF on the fold lines, so nothing here re-typesets the tract. That means
   the layout only has to hold a fixed-proportion picture, which is why the
   panel can take a hard aspect-ratio: there is no text inside to clip. */
.tract-reader { margin-top: var(--space-lg); --tpanel-w: clamp(272px, 80vw, 352px); }

/* A scroll-snap strip, not a slideshow. Swiping, momentum and keyboard
   scrolling all come from the browser, and with js/tract-reader.js absent the
   strip still scrolls and every panel is still reachable. */
.tract-reader__strip {
  list-style: none; margin: 0; padding: 0;
  display: flex;
  gap: var(--space-md);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Room for the panel shadows, which a plain overflow would shear off. */
  padding-block: 4px var(--space-sm);
  scrollbar-width: none;
}
.tract-reader__strip::-webkit-scrollbar { display: none; }
.tract-reader__strip:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) { .tract-reader__strip { scroll-behavior: auto; } }

.tpanel {
  /* `start`, not `center`. With centre snapping the first panel can never be
     centred, because that would need a negative scroll position, so the reader
     opened reporting "Panel 2 of 6" and the cover was never current. */
  scroll-snap-align: start;
  flex: 0 0 auto;
  width: var(--tpanel-w);
  border-radius: 3px;
  overflow: hidden;
  background: #F3E4CC;
  box-shadow: 0 2px 4px rgba(25,27,29,0.14), 0 14px 32px rgba(25,27,29,0.20);
}
.tpanel img {
  display: block;
  width: 100%;
  /* The rendered panel is 845x1958, which is the printed 3.667in by 8.5in.
     `height: auto` is not optional next to the width/height attributes: those
     attributes become a presentational height that would otherwise beat any
     ratio. Same trap as the Creation on the Road mark. */
  height: auto;
}

/* --- Controls --------------------------------------------------------- */
.tract-reader__bar {
  margin-top: var(--space-sm);
  display: flex; align-items: center; justify-content: center; gap: var(--space-sm);
}
.tract-reader__nav {
  flex: none;
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border: 2px solid var(--sandstone); border-radius: 50%;
  background: transparent; color: var(--clay-deep);
  cursor: pointer;
  transition: background 180ms var(--ease), color 180ms var(--ease);
}
.tract-reader__nav svg { width: 20px; height: 20px; }
.tract-reader__nav:hover:not(:disabled) { background: var(--sandstone); color: var(--cream); }
.tract-reader__nav:disabled { opacity: 0.32; cursor: default; }

.tract-reader__dots { list-style: none; margin: 0; padding: 0; display: flex; gap: 0.5rem; }
/* An 11px dot is far under the 24px minimum tap target, so the hit area is
   grown by the list item around it rather than by fattening the dot. */
.tract-reader__dots li { position: relative; display: grid; place-items: center; width: 26px; height: 26px; }
/* Required, and it is not belt and braces. `hidden` works by setting
   `display: none` in the UA sheet, which any author `display` beats, so the
   rule above would keep the dead dots on screen while the DOM said they were
   hidden. syncDots in js/tract-reader.js is what sets the attribute. */
.tract-reader__dots li[hidden] { display: none; }
.tract-reader__dots button {
  width: 11px; height: 11px; padding: 0;
  border: 0; border-radius: 50%;
  background: rgba(107,63,29,0.28);
  cursor: pointer;
  transition: background 180ms var(--ease), transform 180ms var(--ease);
}
.tract-reader__dots button::after { content: ""; position: absolute; inset: 0; }
.tract-reader__dots button[aria-current="true"] { background: var(--clay-deep); transform: scale(1.25); }

/* Off screen, not deleted. As printed text under the dots it told a sighted
   reader nothing the panels in front of them did not already say, and it read
   as wrong besides: "Panel 4 of 6" while panels 4, 5 and 6 were all on screen.
   It stays in the DOM as the live region that announces the move after a dot
   or arrow is pressed, which is the one audience it was ever any use to. */
.tract-reader__status {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* --- The transcript ---------------------------------------------------
   The panels are pictures of words, so the tract's text lives here as real
   markup for search engines and screen readers. Deliberately a visible
   <details> rather than hidden text: text hidden behind an image that
   duplicates it is what cloaking looks like, and a transcript a reader can
   open is more use than one only a crawler sees. */
.tract-text {
  margin-top: var(--space-lg);
  max-width: var(--measure);
  margin-inline: auto;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.tract-text > summary {
  padding: var(--space-sm) 0;
  cursor: pointer;
  font-family: var(--font-body);
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--clay-deep);
}
.tract-text > summary:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }
.tract-text__body { padding-bottom: var(--space-md); }
.tract-text__body h3 {
  margin-top: var(--space-md);
  font-family: var(--font-body);
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--clay-deep);
}
.tract-text__body h3:first-child { margin-top: 0; }
.tract-text__body p { margin-top: var(--space-sm); color: var(--text-muted); }
.tract-text__body blockquote {
  margin: var(--space-sm) 0 0;
  padding-left: var(--space-sm);
  border-left: 3px solid var(--sandstone);
}
/* THE NINE TRACT VERSES WERE THE WORST CASE THE AUDIT FOUND: Barlow 400 at
   17.8px against body copy that was also Barlow 400 at 17.8px, so the only
   thing marking scripture in the site's largest body of it was the left rule.
   The face is now doing that work and the rule is the secondary signal. */
.tract-text__body blockquote p {
  font-family: var(--font-scripture);
  font-size: calc(var(--step-0) * var(--scripture-scale));
  line-height: 1.5;
  color: var(--text);
}
.tract-text__body cite {
  display: block; margin-top: 0.35rem;
  font-style: normal;
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--clay-deep);
}

/* --- The page's opening copy ------------------------------------------
   This was a second copy of the block that used to sit up in the embed's
   section; the embed's copy has gone with it, so this is now the only one.
   `.tract__fallback` sat here too and went the same way: the "ask us for a
   printed copy" line it styled was cut from the page. */
.tract__intro { max-width: var(--measure); }
.tract__intro h2 { font-size: var(--step-3); }
.tract__intro p:not(.eyebrow) { color: var(--text-muted); margin-top: var(--space-sm); }

/* ============================================================
   Volunteer
   ============================================================ */
/* Two photo/copy splits with the picture on opposite sides, then a centred
   closing block. The picture leads in the DOM on the first split and follows
   on the second, so the stacked phone order and the two-column desktop order
   are the same reading order in both. No `order` property anywhere on purpose:
   the moment those two disagree, the page reads differently to a screen reader
   than it looks. */
.vol-split { display: grid; gap: var(--space-lg); align-items: center; }
@media (min-width: 900px) { .vol-split { grid-template-columns: 1fr 1fr; } }

.vol-split__figure .frame { --tilt: -1.2deg; }
.vol-split__figure--b .frame { --tilt: 1.1deg; }
/* `height: auto` is required, not redundant, and must stay BELOW `.frame img`
   (same specificity, later wins). It undoes `.frame img { height: 100% }`,
   which is written for the fixed-ratio gallery cards, AND it stops the img's
   own width/height attributes from acting as a presentational height, which
   would silently beat the aspect-ratio and squash the picture. */
.vol-split__figure img {
  width: 100%; height: auto;
  aspect-ratio: 3 / 2; object-fit: cover;
}

.vol-split__body h2 { font-size: var(--step-3); }
/* p:not(.eyebrow): a block-scoped `p` rule is (0,1,1) and would outrank
   `.eyebrow` at (0,1,0), greying out the eyebrow in this block while the
   identical one elsewhere on the page stayed clay. */
.vol-split__body p:not(.eyebrow) { margin-top: var(--space-sm); color: var(--text-muted); max-width: var(--measure); }

/* The perks list is written for an inverted ground (sandstone squares, muted
   cream). On this page it sits on sand, so the two colours are restated.
   (0,2,1) against `.perks li`'s (0,1,1), so it wins outright rather than by
   source order. */
.vol-perks .perks li { color: var(--text-muted); }
.vol-perks .perks li::before { background: var(--clay); }
.vol-perks .perks { max-width: var(--measure); }

/* --- Ways to help ---------------------------------------------------------
   Two columns, not the three-across `.museum-list`: an odd number of items in
   three columns strands the last one alone on a row of its own, the same fault
   the five-card gallery had. A trailing gap in a two-column list just reads as
   the list ending.
   820, not 900: these items are a short heading over two lines of copy, so
   they hold up in a narrower column than a full paragraph does. At 820 each
   column is ~380px; at the 1240 wrap they are 588. */
.help-list {
  margin-top: var(--space-lg);
  display: grid; gap: var(--space-lg) var(--space-md);
  list-style: none; padding-left: 0;
}
@media (min-width: 820px) { .help-list { grid-template-columns: repeat(2, 1fr); } }
/* Explicit cream: `.band h2` does not reach an h3, and `.band p` at (0,1,1)
   would otherwise be the only colour in this list. Same trap as
   `.museum-list h3` and the Creation on the Road talk title. */
.help-list h3 { font-size: var(--step-1); color: var(--cream); }
.help-list p { margin-top: 0.4rem; }

/* --- Come and serve -------------------------------------------------------
   Centred rather than split, so the page does not end on a third variation of
   the same two-column arrangement. `justify-items: center` matters for the
   button: .btn takes its height from its width via aspect-ratio, and a grid's
   default stretch would equalise it and flatten the oval into a lens. */
.vol-close-section { padding-block: 0 var(--space-xl); }
.vol-close {
  display: grid; justify-items: center; text-align: center;
  gap: var(--space-md);
  padding-top: var(--space-xl);
  border-top: 1px solid var(--rule);
}
.vol-close__figure { width: min(100%, 420px); }
.vol-close__figure .frame { --tilt: 0.8deg; }
.vol-close__figure img { width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; }
.vol-close h2 { font-size: var(--step-3); }
/* Same :not() guard as above, for the same reason: without it the descendant
   `p` rule below greys out the display line and it stops reading as the
   emphasis it is. */
.vol-close p:not(.vol-close__line) { color: var(--text-muted); max-width: 62ch; }
.vol-close__line {
  font-family: var(--font-display);
  font-size: var(--step-2); line-height: 1.28;
  color: var(--text); max-width: 30ch;
  /* Short centred copy: the natural break strands a single word on the last
     line, which the user dislikes. */
  text-wrap: balance;
}
.vol-close .index-cta { margin-top: 0; }
.vol-close__note { font-size: var(--step--1); max-width: 54ch; }

/* ============================================================
   Sign-Up
   ============================================================ */
/* Third use of the photographic-zone pattern, after the leaf band and the road
   zone. One positioned, isolated element owns the picture on ::before and the
   veil on ::after, both at z-index -1, with the seams inside made transparent.

   MEASURED, not estimated. This photograph is DARK: mean luminance 0.102
   against the road photo's 0.478, and its darkest pixels are the skull's eye
   sockets at rgb(2,2,4). So on the sand ground the enemy flips — it is the
   photo's DARKEST pixels against dark text, not its brightest.

   THE FIRST PASS GOT THIS WRONG IN THE DOCUMENTED WAY, so the numbers are here
   to stop it happening again. It ran the photo at 0.26 under a 0.74 centre
   veil, which composites to an effective 6.8% and a mean luminance of 0.621:
   a washed-out smear, buying contrast that was never in doubt. The photo at
   0.26 with NO veil already measured 5.69:1 for --text.
   The rule is: darken the TEXT, do not scrim the picture. Moving the body copy
   and the note off --text-muted onto full --text, and the eyebrow onto the
   road zone's #4A2C14, is what paid for the settings below.
     photo 0.30 / veil 0.22 -> effective 23.4%, mean luminance 0.484
     --text        6.08:1     #4A2C14 eyebrow  5.16:1
     --text-muted  3.68:1     --clay-deep      3.64:1   <- BOTH FAIL HERE
   0.484 is within 0.006 of the road zone's 0.478, which the user settled on
   after three rounds, so this band sits at the same weight as that one.
   Do not reintroduce --text-muted or --clay-deep inside this zone. */
.fossil-zone { position: relative; isolation: isolate; background-color: var(--bg); }
.fossil-zone::before,
.fossil-zone::after { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
/* THE BLUR IS BAKED INTO THE FILE, not applied here, and that is deliberate.
   The user still found the copy slightly hard to read at 0.30 with the sharp
   photo, and the cause was never contrast — it was ROUGHNESS. Measured as the
   mean luminance step between neighbouring pixels, the sharp file reads 0.0249
   and a gaussian at sigma 5 reads 0.0121, less than half. That is the number
   that tracks "busy", and no contrast ratio can see it.
   Blur also NUDGES CONTRAST THE RIGHT WAY, because averaging pulls the extremes
   toward the mean: the darkest pixel lifts from rgb(2,2,4) to rgb(13,12,9) and
   --text goes 6.08 -> 6.24:1. So this cost nothing and was not a trade.
   Baked rather than `filter: blur()` because a CSS filter on a full-bleed
   ::before feathers its own edges, which then needs inset padding plus
   overflow: hidden on the zone to hide, and it re-rasterises the layer at paint
   time for a picture that never changes. Baking also let the file drop to
   1440x810 and 46KB, from 1920x1080 and 493KB, since blurred detail below about
   15px is gone anyway. Regenerate with:
     ffmpeg -i <source> -vf "scale=1440:810:flags=lanczos,gblur=sigma=5" -q:v 4 */
.fossil-zone::before {
  background-image: url("../assets/img/fossil-bg.jpg");
  background-size: cover; background-position: center;
  opacity: 0.30;
}
/* INVERTED vignette, and this is the rule for any LIGHT photographic ground:
   the conventional edges-dark vignette is backwards here. It would deepen the
   corners, where no text is, and leave the fossil's own black sockets sitting
   directly under the copy. This veil is strongest in the MIDDLE and eases
   outward, so the skull reads as a picture toward the edges of the band while
   the centre stays calm enough to read on. Light touch by design: at 0.22 it
   lifts the busiest area without flattening the photograph. */
.fossil-zone::after {
  background:
    radial-gradient(120% 92% at 50% 50%,
      rgba(229, 214, 185, 0.22) 0%,
      rgba(229, 214, 185, 0.12) 46%,
      rgba(229, 214, 185, 0.02) 100%);
}
.fossil-zone .wave { background: transparent; }

/* One centred column in plain document flow. The arrangement is load-bearing,
   not decorative: the user's copy says "the button below", and that is only
   true if the button really is below the words at every width. A two-column
   grid here would make their own sentence wrong at one breakpoint or another,
   which is exactly what the direction-word rule is about. */
.signup {
  max-width: 720px;
  display: grid; justify-items: center; text-align: center;
  gap: var(--space-md);
}
.signup h2 { font-size: var(--step-3); font-weight: 700; }
/* Bigger and heavier than the site's --step-0/400 body, per the rule that a
   busy ground is fixed with weight and size rather than more scrim. A cracked
   texture interrupts letter shapes at the stroke, which a per-pixel contrast
   figure cannot see, and more scrim only buys a number that already passed
   while costing the picture.
   BACK AT 500, and it should stay there. It was raised to 600 when the user
   said the copy was still hard to read, and they rejected that: "the heavier
   weight is too uncomfortable." The blur landed in the same round and is what
   actually fixed the legibility, so 500 now sits on a ground half as rough as
   the one it was failing on. Weight was the wrong lever here; roughness was
   the right one. Do not reach for 600 again. */
.signup__lead {
  font-size: var(--step-1); font-weight: 500;
  color: var(--text); max-width: 60ch;
}
/* Letterspaced small caps are the most fragile thing on a photograph, because
   the tracking hands the background a gap between every pair of letters, so
   this takes the biggest jump of anything here.
   #4A2C14 is the road zone's eyebrow colour, a step past --clay-deep, and it
   is here for the same reason: on this ground --clay-deep measures 3.64:1 and
   --clay would be worse. This measures 5.28:1. Not a token, because it exists
   only for photographic zones; see .fossil-zone.
   600, NOT the road zone's 700. Barlow is loaded at 400/500/600 on this site,
   so 700 is a browser-synthesised face — a smeared approximation, and smearing
   is the last thing letterspaced small caps on a photograph need. `.road-zone
   .eyebrow` still asks for 700 and is live with that fault on
   creation-on-the-road.html; flagged to the user, not changed unasked. */
.signup__eyebrow { font-size: var(--step-0); font-weight: 600; color: #4A2C14; }
.signup__btn { margin-top: var(--space-sm); }
/* Full --text, NOT --text-muted, which measures 3.68:1 over this photograph.
   Small print is the first thing a busy ground eats, so it takes 500 rather
   than the site's 400 — but not the 600 it briefly carried, for the same
   reason as .signup__lead above. */
.signup__note {
  font-size: var(--step--1); font-weight: 500;
  color: var(--text); max-width: 56ch;
  text-wrap: balance;
}

/* ============================================================
   Tours
   ============================================================ */

/* ---- The self-guided walk -------------------------------------------
   The copy sits beside a photograph of a phone scanning a QR code, added
   at the user's request 2026-08-27. It replaced a deliberate no-photo
   decision, and the reason that decision was wrong is worth keeping: the
   argument was that two framed pictures in a row read as a gallery, but
   these two are separated by a seam AND a change of ground, they are
   different subjects, and the abstract half of this page (a code you
   scan) is the half that most needed showing.
   The section keeps its second device as well: NUMBERED STATIONS, full
   width beneath the split rather than crushed beside it. The exhibit
   index already numbers the walking route and the creed already hangs a
   numeral beside each article, so a numbered sequence is this site's own
   idiom rather than an imported "01 / 02 / 03" tic.
   The order is real: you cannot scan a code before you are through the
   door, and you cannot listen before you have scanned. That is the test
   from the design rules, and this passes it. */
.tours-split { display: grid; gap: var(--space-lg); align-items: center; }
/* Below the base rule, per the source-order rule. Slightly favours the copy:
   an even split gave the paragraphs 556px and the photo more room than a
   662px source can honestly fill. */
@media (min-width: 900px) { .tours-split { grid-template-columns: 1.1fr 0.9fr; } }
/* 520 from a 662px source is 1.27x. There is NO larger original, so this is
   the cap rather than a layout preference: at the column's full width it
   would render below 1x on any modern screen. Same constraint as
   .founder__portrait, which is pinned to its 300px source. */
.tours-split__figure { width: min(100%, 520px); justify-self: center; }
.tours-split__figure .frame { --tilt: 1.2deg; }
/* `height: auto` undoes .frame img { height: 100% }. Fourth time on this site
   after .tree-figure, .founder__portrait and .guided__figure. */
.tours-split__figure img { width: 100%; aspect-ratio: 662 / 463; height: auto; }

.tours-lead { max-width: var(--measure); }
.tours-lead h2 { font-size: var(--step-3); }
.tours-lead p:not(.eyebrow) { margin-top: var(--space-sm); color: var(--text-muted); }
/* The narration is the reason this tour is worth taking at all, so it
   sits at full ink and a size up while the paragraphs around it stay
   muted. Cheaper than a pull quote and it keeps the reading order. */
.tours-lead .tours-lead__key {
  color: var(--text); font-size: var(--step-1); font-weight: 500;
}

.tour-steps {
  list-style: none; padding: 0;
  counter-reset: step;
  margin-top: var(--space-lg);
  display: grid; gap: var(--space-md);
}
/* 1160, not the 860 first tried and not the 1040 tried second. Below the base
   rule, per the source-order rule. MEASURE THE TEXT, NOT THE TRACK: the hanging
   numeral and its gap take about 40px off the front of each column, so at 860
   the blurbs were 252px (about 28 characters, the crushed-column fault the
   partner cards and .museum-list both hit) and at 1040 they were 267px, which
   is the exact figure .museum-list was moved off for being too tight. 1160
   puts them at 312, .museum-list's own target, and 1240 at 352.
   There is no two-column step: three items across two columns strands one. */
@media (min-width: 1160px) { .tour-steps { grid-template-columns: repeat(3, 1fr); } }
.tour-steps li {
  display: grid; grid-template-columns: auto 1fr;
  column-gap: var(--space-sm);
  border-top: 1px solid var(--rule);
  padding-top: var(--space-sm);
}
/* Counters rather than ::marker: ::marker gives no control over the gap
   between the numeral and the text, and this one is nearly twice body
   size. Same reasoning as .creed__articles.
   --clay measures 4.17:1 on the sand ground, which fails the 4.5:1 bar
   for normal text and clears the 3:1 large-text bar comfortably. At
   --step-2 (25 to 32px) this IS large text, and it is a marker rather
   than something anyone has to read, so clay is safe here in a way it is
   not at body size. */
.tour-steps li::before {
  counter-increment: step;
  content: counter(step);
  grid-row: 1 / span 2;
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-2); line-height: 1;
  color: var(--clay);
  min-width: 1.2ch;
}
.tour-steps h3 { font-size: var(--step-1); }
/* Capped, because below 1040 these are full-width rows rather than columns and
   a two-line blurb would otherwise run the whole 1000px of the wrap. */
.tour-steps p { margin-top: 0.4rem; color: var(--text-muted); font-size: var(--step-0); max-width: var(--measure); }

/* ---- The guided tour band -------------------------------------------
   The photograph is PORTRAIT (720x960), so it opts out of the band's
   3:2 landscape crop. Cropping this one to 3:2 takes the top off the
   Creation Education Museum sign and the bottom off the children, which
   is most of what the picture is for. */
.guided { display: grid; gap: var(--space-lg); align-items: center; }
@media (min-width: 900px) { .guided { grid-template-columns: minmax(240px, 340px) 1fr; } }
.guided__figure { width: min(100%, 340px); justify-self: center; }
.guided__figure .frame { --tilt: -1.3deg; }
/* `height: auto` undoes .frame img { height: 100% }, which is written for
   the fixed-ratio gallery cards. Same specificity, so this rule has to
   stay BELOW it in the file. Same trap as .tree-figure and .founder. */
.guided__figure img { width: 100%; aspect-ratio: 720 / 960; height: auto; }
.guided__body { display: grid; gap: var(--space-sm); }
/* .band p supplies a top margin only, so without this the first paragraph
   would sit one line clear of the heading and the gap would double. */
.band .guided__body p { margin-top: 0; }
.guided__cta { margin-top: var(--space-sm); justify-self: start; }

/* ---- "We do not argue" ----------------------------------------------
   A coda to the band rather than a section of its own, and ruled rather
   than boxed: horizontal bands are this site's boundary idiom and a
   panel here would be the sort of generic card that has been rejected
   before. Same construction as .nifty-thanks, which is the proven one.
   This line is the concrete proof behind the homepage's "we don't tell
   you what to think", and it belongs to the whole museum rather than to
   the guided tour alone, which is why it closes the band instead of
   sitting inside the copy column. */
.tour-creed {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--rule-invert);
  text-align: center;
}
/* Two class selectors, NOT the bare .tour-creed__line: on its own that is
   0,1,0 and `.band p` at 0,1,1 quietly wins the colour, which would leave
   the line dimmer than the paragraph it is meant to lift off. `.band p`
   has now outranked something on this site four times; assume it will. */
/* 36ch, raised from 22ch on 2026-08-27: the user wants this on ONE line and
   22ch capped it at 467px when the sentence needs 489px at --step-2, so it
   always broke after "argue". Measured with a nowrap probe carrying the
   element's own computed `font`, not estimated. 36ch is about 570px, which
   clears 489 with room for the type to grow, and the band it sits in is 1225
   wide, so there is nothing to collide with.
   It still wraps below roughly 540px of viewport, which no cap can prevent:
   one line of 489px cannot fit a 375px phone. `text-wrap: balance` stays for
   exactly that case, and is a no-op on the single line everywhere else. */
.tour-creed .tour-creed__line {
  margin-top: 0;
  font-family: var(--font-display);
  font-size: var(--step-2); font-weight: 600; line-height: 1.25;
  color: var(--cream);
  max-width: 36ch; margin-inline: auto;
  text-wrap: balance;
}
/* 74ch, raised from 58ch on 2026-08-27: the user wants this on ONE line to
   match the display line above it, and 58ch capped it at 587px when the
   sentence needs 663px. Measured with a nowrap probe carrying the element's
   own computed `font`, which put the true requirement at 66ch; 74 clears it
   with room for the type to grow. The band is 1225 wide, so nothing collides.
   This deliberately runs PAST --measure (62ch). That cap is for reading
   columns; this is a single centred sentence closing a band, and one line is
   the whole point of it.
   `text-wrap: balance` stays for the narrow widths where one line is
   impossible, and is a no-op on the single line everywhere else. */
.tour-creed .tour-creed__body {
  max-width: 74ch; margin-inline: auto;
  color: rgba(250, 245, 234, 0.86);
  text-wrap: balance;
}

/* ---- The practical detail -------------------------------------------
   Reusing .programs / .program, which has been dead CSS since the old
   "Beyond the museum" section was deleted. The clay top rule reads as a
   spec sheet, which is exactly what these six are.
   The one change is size: .program p sits at --step--1, and body copy on
   this site was deliberately raised off --step--1 on 2026-08-21 because
   the user called it too small. Scoped, so reviving the class elsewhere
   is not blocked. .tour-facts .program p is 0,3,0 against .program p at
   0,2,0, so it wins on specificity and its position in the file does not
   matter. */
.tour-facts { margin-top: var(--space-lg); }
.tour-facts .program p { font-size: var(--step-0); }
/* Explicit tracks rather than .programs' own auto-fit minmax(260px, 1fr).
   Auto-fit put FOUR across at 1240 and left the last two stranded on a row
   of their own, the same fault that sent .help-list to two columns. Six
   items want three or two, never four. Breakpoints match .museum-list, so
   the two "spec grid" idioms on this site reflow at the same widths.
   .tour-facts .programs is 0,2,0 against .programs at 0,1,0, so these win
   on specificity and their position in the file does not matter. */
.tour-facts .programs { grid-template-columns: 1fr; }
@media (min-width: 700px)  { .tour-facts .programs { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .tour-facts .programs { grid-template-columns: repeat(3, 1fr); } }

/* ---- The Founder's Tour ---------------------------------------------
   IT HAS ITS OWN CLAY BAND SINCE 2026-09-05, at the user's request.
   This note used to read "Ruled off and set at a measure rather than
   given a band of its own: it is a footnote to the guided tour, not a
   third offer of equal weight." That call was overturned deliberately.

   The margin/padding/hairline that used to hang it off the sand section
   above are GONE: `.section` supplies the 96px and the two seams do the
   dividing. Restoring any of them stacks onto the band's own padding —
   the same 160px-of-empty-ground fault the audio tour list hit twice.
   There is deliberately NO base `.founder-tour` rule any more; the block
   is now just a grid at >=900 (below) plus the re-tones at the end of
   this section. */
/* The cap moved off .founder-tour and onto the text, so the rule above can run
   the full width of the wrap while the prose still stops at a measure. */
.founder-tour__body { max-width: var(--measure); }
/* Below the base rule, per the source-order rule. The portrait fills the empty
   right-hand half the block used to leave, and is CENTRED in that half rather
   than pinned to the far edge of the wrap, where a lone circle reads as having
   drifted away from the text it belongs to. */
@media (min-width: 900px) {
  .founder-tour {
    display: grid;
    /* minmax(300px, 1fr), NOT a bare 1fr. With 1fr the portrait's track
       collapsed to 180px at a 900 viewport, because column one took the whole
       --measure (601px) first and left only the remainder. `img { max-width:
       100% }` then squeezed the picture to 180 wide while `height: 300px` held,
       and it rendered as an ELLIPSE. Column one's min is 0, so it gives way
       and the text simply sets narrower; the circle never does. */
    grid-template-columns: minmax(0, var(--measure)) minmax(300px, 1fr);
    gap: var(--space-lg);
    align-items: center;
  }
  .founder-tour__face { justify-self: center; }
}
/* --step-3, raised from --step-2 on 2026-09-05 when this became a band of its
   own. The smaller size was correct while the block was a footnote hanging off
   the foot of the sand section above; as a peer of "Guided Tours" one band up
   it has to match it, or the page carries two clay bands whose headings differ
   for no reason a reader can see. Set explicitly rather than deleted and left
   to `.band h2`: the two tie at (0,1,1) and this one wins on source order, so
   deleting it would work here but would drop the heading to the UA's 27px if
   the component were ever used outside a band. That is open question 70. */
.founder-tour h2 { font-size: var(--step-3); }
/* `:not(.eyebrow)` ADDED 2026-09-05 WITH THE EYEBROW, and it is load-bearing in
   two ways. The eyebrow is a <p>, so without it this rule paints it --text-muted
   and hands it a top margin it does not want as the first child of the column.
   More importantly it protects the CLAY re-tone below: see the note there. This
   is the same fix `.cs-intro__body > p:not(.eyebrow)` already carries, for the
   identical reason. */
.founder-tour p:not(.eyebrow) { margin-top: var(--space-sm); color: var(--text-muted); }
/* Two class selectors so it beats .founder-tour p (0,2,0) rather than tying
   with it and losing on source order. Full ink, because this is an offer
   rather than another line of detail, and the members it is aimed at have to
   spot it to claim it. */
.founder-tour .founder-tour__perk { color: var(--text); }
.founder-tour .founder-tour__perk a { color: var(--clay-deep); text-decoration: underline; text-underline-offset: 3px; }
.founder-tour .link-rule { margin-top: var(--space-md); }
/* The site's circular-portrait treatment, taken from .talk__face and
   .cotr-speaker__face: sandstone ring echoing the Creation Speaks roundel's
   gold band, and the circle made by border-radius rather than baked into the
   file, so the source stays an ordinary opaque JPEG and the inset-circle trap
   that cost two passes on the speaker headshots cannot apply here.
   300 from a 300px crop is EXACTLY 1x, and that is the ceiling rather than a
   preference. The Our Story portrait is 300x448 and it is the largest file of
   this face that exists anywhere in the project (`Bill Head Shot.jpg` is the
   same 300x448, `BillHeadshot.png` is 254, the speaker headshot 160), so a
   circle cannot be cut wider than the source's 300px width. Raised from 220 on
   2026-08-27 at the user's request, to balance the text column beside it, which
   measures 402px tall. Going past 300 means upscaling; ask for a bigger
   original first. */
.founder-tour__face { margin: 0; }
/* `aspect-ratio: 1` with `height: auto` rather than a fixed height, so that if
   anything ever caps the width (the site's `img { max-width: 100% }` inside a
   narrow parent) the picture shrinks as a CIRCLE instead of squashing into an
   ellipse. `height: auto` is required for the ratio to apply at all, because
   the img carries width/height attributes and a box with both a width and a
   height ignores its aspect ratio. Same trap as .cs-mark. */
.founder-tour__face img {
  display: block;
  width: 300px; aspect-ratio: 1; height: auto;
  border-radius: 50%;
  border: 2px solid var(--sandstone);
  box-shadow: 0 3px 12px rgba(25, 27, 29, 0.3);
}
/* Centred below 900, where the grid collapses and the circle signs off the
   block instead of sitting beside it. */
@media (max-width: 899px) {
  .founder-tour__face { margin-top: var(--space-lg); display: flex; justify-content: center; }
}

/* ---- The same block on its CLAY band, 2026-09-05 --------------------
   THIS COMPONENT WAS WRITTEN FOR THE SAND AND FOUR OF ITS OWN DEFAULTS ARE
   WRONG ON --clay-deep. Every rule below wins on SPECIFICITY, (0,2,x) or
   better against the sand rules' (0,1,1) and (0,2,0), so this block can be
   moved or deleted without silently reverting. Same checklist the homepage's
   four purposes went through on 2026-09-03.

   1. `.founder-tour p` sets `color: var(--text-muted)`, a DARK muted, and it
      is declared LATER in this file than `.band p`, so at equal (0,1,1) it
      would win on source order and paint dark grey prose on dark brown.
      The identical trap `.program p` and `.tour-item.is-playing` both hit.
   2. `.founder-tour__perk` is full `--text`, i.e. near-black ink, at (0,2,0).
      It is the members' offer and the one line that must not be missed, so it
      goes to full cream rather than the muted body colour.
   3. ITS LINK WAS `--clay-deep` ON --clay-deep, which is 1:1 and invisible.
      Full cream with a sandstone underline is this site's settled answer for
      an inline link on a dark band, copied from `.band .why-q__body a`.
   4. `.link-rule` is a light-side colour too and needs the same lift; the
      `.band .intro__more .link-rule` precedent.
   The h2 needs nothing: `.founder-tour h2` sets only a size and is later than
   `.band h2`, so it keeps --step-2 and takes the cream. The portrait's
   sandstone ring is a graphical object, not text, and measures 3.69:1 here
   against the 3:1 it needs — it keeps the ring that .talk__face and
   .cotr-speaker__face wear, so the three portraits still read as one idiom. */
/* `:not(.eyebrow)` IS REQUIRED HERE, NOT TIDINESS. Without it this rule is
   (0,2,1) and OUT-SPECIFIES `.band--clay .eyebrow--invert` at (0,2,0), so the
   eyebrow added 2026-09-05 would silently render muted cream instead of the
   band's gold — and it would look plausible, because muted cream is what every
   eyebrow on a band looked like before that token existed. With the `:not` both
   selectors climb one step and the gap between them holds. */
.band .founder-tour p:not(.eyebrow) { color: var(--text-invert-muted); }
/* `.band p` SETS A TOP MARGIN AS WELL AS A COLOUR, and the `:not` above hands
   the eyebrow straight back to it: (0,1,1) beats `.eyebrow` at (0,1,0), which
   declares only a margin-BOTTOM. Measured before this rule: 16px above the
   eyebrow here against 0px on "Booked in advance" one band up, so the two clay
   bands started their content 96px and 112px below their seams. (0,2,0) beats
   (0,1,1) on specificity, so this does not depend on source order. Third time
   `.band p`'s margin has caught something on this site. */
.founder-tour .eyebrow { margin-top: 0; }
.band .founder-tour .founder-tour__perk { color: var(--cream); }
.band .founder-tour .founder-tour__perk a { color: var(--cream); text-decoration-color: var(--sandstone); }
.band .founder-tour .link-rule { color: var(--cream); }

/* ---- Closing ---------------------------------------------------------
   No seam above this: it shares the sand ground with the section before
   it, and decorating that join would draw a line where there is no
   change of ground. Same reasoning as .vol-close-section. */
.tours-close-section { padding-block: 0 var(--space-xl); }
/* REACH FOR THIS WHENEVER A CLOSE FOLLOWS A SEAM. Two pages now:
   why-creation.html (2026-08-31) and creation-education-museum-audio-tour.html
   (2026-09-02). The user reported the same symptom on both, the second time as
   "the same problem we had in the Why Creation section at the bottom".

   THE CONDITION IS THE SEAM, NOT THE HEADING, and this note used to say
   otherwise. It read "that page's close is the one with no h2, so the block is
   short", which fitted the one data point available at the time and was WRONG.
   The audio tour's close carries an h2 and three lines and had the identical
   fault. The real cause: `.tours-close-section` is `padding-block: 0 96px`, so
   it supplies NO space above itself and relies on whatever precedes it. On
   tours, faq, review and visit the close follows a `</section>` of the same
   ground whose own 96px bottom padding does that job. A SEAM HAS NO BOTTOM
   PADDING, so on those two pages the content sat flush against the strata with
   96px of empty ground below it, uncentred.

   The user's words the first time: "this last section just needs to shrink a
   bit, so that the info in it is centered properly." 32/32 both centres it and
   takes 32px off the section, which is why the top padding goes UP and the
   block still gets smaller. Written as a modifier rather than a change to the
   rule above, because the four seam-less closes are approved as they are. */
.tours-close-section--balanced { padding-block: var(--space-md); }
.tours-close { text-align: center; display: grid; justify-items: center; gap: var(--space-sm); }
.tours-close h2 { font-size: var(--step-3); }
.tours-close__line {
  font-family: var(--font-display);
  font-size: var(--step-1); color: var(--text);
  max-width: 40ch; text-wrap: balance;
}
.tours-close .index-cta { margin-top: var(--space-xs); }
.tours-close__note { font-size: var(--step--1); color: var(--text-muted); max-width: 54ch; }
/* `.tours-close__line a` joined this selector 2026-08-31, when why-creation.html
   became the first page to carry a link in the display-face closing line. It is
   the site's one prose-link idiom on the sand ground, shared with `.faq__a a`
   and `.why-q__body a`; a fourth copy of the same three declarations was not
   worth writing. --clay-deep measures 5.9:1 on sand, and at --step-1 the line
   is large text anyway. */
.tours-close__note a,
.tours-close__line a { color: var(--clay-deep); text-decoration: underline; text-underline-offset: 3px; }

/* ============================================================
   Plan Your Visit
   ============================================================ */
/* The page head runs straight into .visitbar with no seam. Both are
   --slate-deep, and a seam between two identical grounds draws a line where
   there is no change of ground. See the reviews/intro join on the homepage. */

/* ---- Finding the front door -----------------------------------------
   Copy column first in the DOM so the stacked order below 900 opens on the
   heading, with the grid doing the placement. The photograph is PORTRAIT
   (720x960), the same shape and the same treatment as the guided-tour
   picture on tours.html. */
.visit-find { display: grid; gap: var(--space-lg); align-items: center; }
@media (min-width: 900px) { .visit-find { grid-template-columns: 1fr minmax(240px, 340px); } }
.visit-find__body { display: grid; gap: var(--space-sm); }
.visit-find__body > p:not(.eyebrow) { color: var(--text-muted); max-width: var(--measure); }
.visit-find__figure { width: min(100%, 340px); justify-self: center; }
.visit-find__figure .frame { --tilt: -1.2deg; }
/* `height: auto` undoes .frame img { height: 100% }, which is written for the
   fixed-ratio gallery cards. Same specificity, so this rule has to stay BELOW
   it in the file. Fifth time this trap has been paid for on this site, after
   .tree-figure, .founder__portrait, .guided__figure and .cs-mark. */
.visit-find__figure img { width: 100%; aspect-ratio: 720 / 960; height: auto; }

/* The one sentence most likely to save somebody a phone call, so it sits at
   full ink and a size up while the paragraphs either side stay muted. The
   scoped rule above colours `p`, so this needs to outrank it rather than sit
   beside it. Same device as .tours-lead__key. */
.visit-find__body .visit-find__key {
  font-family: var(--font-display);
  font-size: var(--step-1); line-height: 1.4;
  color: var(--text);
}
.visit-find__key strong { font-weight: 600; color: var(--clay-deep); white-space: nowrap; }

/* ---- The two approach photographs ------------------------------------
   Two, not a gallery: each answers a different question and the caption does
   as much work as the picture. Explicit two-column tracks rather than
   auto-fit, which would put both on one row at widths where the captions are
   too narrow to read. */
.visit-approach { margin-top: var(--space-lg); display: grid; gap: var(--space-lg); }
@media (min-width: 820px) { .visit-approach { grid-template-columns: 1fr 1fr; } }
.visit-approach figure { display: grid; gap: 0.9rem; align-content: start; }
.visit-approach figure:first-child .frame { --tilt: 1deg; }
.visit-approach figure:last-child .frame { --tilt: -0.9deg; }
.visit-approach img { width: 100%; aspect-ratio: 3 / 2; height: auto; }
.visit-approach figcaption {
  font-size: var(--step-0); line-height: 1.5;
  color: var(--text-muted); max-width: 46ch;
}
/* The caption's opening phrase is the label, so it carries the ink. Not an
   .eyebrow: these are sentences, not letterspaced small caps. */
.visit-approach figcaption strong { color: var(--text); font-weight: 600; }

/* ---- Arrival band ----------------------------------------------------
   .band p supplies a top margin only, so without this the first paragraph
   sits a line clear of the heading and the gap doubles. Same fix as
   .band .guided__body p. */
.visit-desk__body { display: grid; gap: var(--space-sm); }
.band .visit-desk__body p { margin-top: 0; }

/* ---- Good to know ----------------------------------------------------
   Reuses .tour-facts, which already declares explicit tracks at the
   .museum-list breakpoints, because six items under auto-fit strand the last
   two on a row of their own at 1240. */
.visit-lead { display: grid; gap: var(--space-sm); }
.visit-lead h2 { font-size: var(--step-3); }
.visit-lead > p:not(.eyebrow) { color: var(--text-muted); max-width: var(--measure); }

/* ============================================================
   Museum FAQ
   ============================================================ */
/* Collapsible, at the user's request 2026-08-28, matching the transcript block
   on language-of-you.html. Native <details>/<summary>: no JavaScript, keyboard
   operable and announced as expanded or collapsed for free, and it still works
   with scripting off. Hairlines between entries are .creed's idiom minus the
   hanging numerals, since nothing here is cited by number. */
/* Typography, colour and rules all taken from .tract-text on
   language-of-you.html, at the user's request 2026-08-28: Barlow rather than
   the display face, --step--1 at 600, uppercase and letterspaced, --clay-deep,
   with a hairline above every question and one closing the list. Keeping the
   two blocks identical means the site has ONE collapsible idiom rather than
   two that nearly match. */
.faq { max-width: 720px; margin-inline: auto; }

/* ONE continuous list. The user cut the group titles first and then the gaps
   between the groups, so nothing marks a set any more and the grouping lives
   entirely in the ORDER. The wrapper elements went with the gaps rather than
   being left in place doing nothing: kept, they would only have doubled the
   rule where two groups met. */

/* A rule above every question and one closing the list. */
.faq__item { border-top: 1px solid var(--rule); }
.faq__item:last-child { border-bottom: 1px solid var(--rule); }

/* `list-style: none` kills the disclosure triangle in Firefox and Chrome, the
   ::-webkit rule is still needed for Safari, and BOTH are needed: setting
   `display` on a summary does not reliably remove the marker on its own. */
.faq__sum {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) 0;
  cursor: pointer;
  list-style: none;
}
.faq__sum::-webkit-details-marker { display: none; }
.faq__sum:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }
/* .faq__q is an h2, so the display face has to be overridden explicitly. It
   stays an h2: the questions are this page's document outline even though they
   are now set as labels. */
.faq__q {
  font-family: var(--font-body);
  font-size: var(--step--1); font-weight: 600;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  line-height: 1.45;
  color: var(--clay-deep);
}
/* The nav's own chevron, same path and same 180deg rotation, so the open and
   closed states are an affordance the visitor has already met in the header.
   11px, sized against the small caps beside it rather than against body copy.
   A transition on an inline svg is fine here; it is `animation` that silently
   fails on this site (see the .mail__icon wrapper), and .nav__caret already
   proves the transform path works. */
.faq__caret {
  flex: none; width: 11px; height: 11px;
  color: var(--clay-deep);
  transition: transform 220ms var(--ease);
}
.faq__item[open] .faq__caret { transform: rotate(180deg); }

.faq__a { display: grid; gap: var(--space-sm); padding-bottom: var(--space-md); }
/* Scoped to direct children so it cannot reach into a nested list, and
   :not(.eyebrow) by the standing rule, since a block-scoped `p` rule at 0,2,0
   otherwise outranks .eyebrow at 0,1,0. */
.faq__a > p:not(.eyebrow) { color: var(--text-muted); max-width: var(--measure); }
.faq__a a { color: var(--clay-deep); text-decoration: underline; text-underline-offset: 3px; }

/* Square marker in clay, the sand-ground counterpart of .itemlist's ochre one
   on the ink visit bar.

   NOT flex, and .itemlist's flex version cannot be copied here. Every item in
   this list opens with a <strong> label, and in a flex container the <strong>
   and the text after it become TWO separate flex items, each sized on its own
   content: the label ends up in a narrow ragged column with the rest of the
   sentence starting to the right of it. .itemlist survives that only because
   each of its items holds a single text node. Absolute positioning keeps the
   whole answer in normal inline flow, so the label runs on into the sentence
   and wrapped lines still indent past the marker. */
.faq__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.75rem; max-width: var(--measure); }
.faq__list li {
  position: relative;
  padding-left: 1.65rem;
  color: var(--text-muted); line-height: 1.55;
}
.faq__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 8px; height: 8px;
  background: var(--clay);
}
/* The opening phrase is the label for the item, so it carries the ink. Not an
   .eyebrow: these are sentences, not letterspaced small caps. */
.faq__list strong { color: var(--text); font-weight: 600; }

/* ============================================================
   Review Us
   ============================================================ */
.review-lead { display: grid; gap: var(--space-sm); }
.review-lead h2 { font-size: var(--step-3); }
.review-lead > p:not(.eyebrow) { color: var(--text-muted); max-width: var(--measure); }

/* Two cards, explicit tracks rather than auto-fit: there are exactly two and
   they should either sit side by side or stack, never anything else. */
.review-list {
  list-style: none; padding: 0;
  margin: var(--space-lg) 0 0;
  display: grid; gap: var(--space-lg);
}
@media (min-width: 820px) { .review-list { grid-template-columns: 1fr 1fr; } }

/* The whole card is the link, so the tap target is the card and not a line of
   text. Treatment is .review's, the homepage testimonial card: surface,
   hairline, 22px radius, --shadow-card. Same reasoning as .partner, which
   borrowed it for the same reason, that these are objects in a list. */
.review-card {
  display: grid;
  gap: var(--space-sm);
  align-content: start;
  height: 100%;
  padding: 1.6rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 22px;
  box-shadow: var(--shadow-card);
  text-decoration: none;
  color: inherit;
  transition: transform 180ms var(--ease), box-shadow 180ms var(--ease);
}
.review-card:hover, .review-card:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 2px 4px rgba(25,27,29,0.08), 0 14px 34px rgba(25,27,29,0.12);
}
.review-card:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }

/* The badges are supplied as OPAQUE white PNGs with no alpha, so the white has
   to live somewhere. It lives here, in a chip sized to the mark, rather than
   bleeding across the card: nothing else on this site is white and a full-width
   white panel would read as a foreign object. Near-square corners, so the chip
   reads as a badge rather than as a second rounded card inside the first. */
.review-card__badge {
  background: #FFFFFF;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--space-md) var(--space-sm);
  display: grid; place-items: center;
}
/* `height: auto` because the img carries width/height attributes, and a box
   with both dimensions set ignores everything else. Sixth time on this site. */
.review-card__badge img { width: min(100%, 260px); height: auto; }

.review-card__title {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.25;
  color: var(--text);
}
.review-card__note { font-size: var(--step--1); color: var(--text-muted); }
/* The card is an <a>, so the title would otherwise inherit link colouring on
   hover and the whole card would flicker. Only the lift responds. */
.review-card:hover .review-card__title { color: var(--clay-deep); }


/* ============================================================
   Why Creation?
   ============================================================ */

/* --- The opening ------------------------------------------------------
   Made distinct from the run of six below at the user's request 2026-08-29.
   Before this it was the homepage's .intro__grid, which is the SAME left
   column / right column shape the six questions use, so it read as the first
   of them rather than as the preamble to them. Measured at the time: a 120px
   heading in a column 499px tall, i.e. 379px of dead air underneath it.
   Three signals, and not one of them is a panel, a box or a tint — this site
   has turned all three down before:
     1. the prose runs a size up at --step-1, so it reads as a lede against the
        six questions' --step-0 body copy. This is the loudest of the three and
        needs no decoration at all;
     2. the left column gains a display-face coda pinned to the bottom, which
        is what fills the dead space;
     3. a hairline closes the block, marking where the run of six starts.
   The coda mechanism is .story-split's, unchanged: the prose spans both rows
   and sets the height, row 2 absorbs the slack, and `align-self: end` drops
   the coda onto the prose's own baseline. The leftover then reads as breathing
   room under the heading instead of piling up at the bottom, and it holds at
   any width and after any copy edit. */
/* Row gap tighter than the column gap. With the six questions in the left
   column, that column is now tall enough to overrun the prose at wide
   viewports — measured 585 against 517 at 1280, which left the coda hanging
   68px below the prose's last line. Halving the row gap brings the left column
   back under the prose across the range, so the coda goes on sitting where
   .story-split's mechanism puts it. */
.why-open { display: grid; row-gap: var(--space-md); column-gap: var(--space-lg); grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .why-open {
    grid-template-columns: 1fr 1.1fr;
    /* THREE rows: heading, the six category titles, the coda. The prose spans
       all three and sets the height.
       THE SLACK ROW IS THE MIDDLE ONE, so the list floats centred in whatever
       space is left between the heading above it and the coda below it, which
       is what the user asked for 2026-08-29. Rows 1 and 3 are `auto`, so the
       heading stays pinned to the top and the coda to the prose's own last
       line; everything left over goes to row 2 and is split evenly above and
       below the list by `align-self: center`.
       (Before this the slack was in row 3, which pushed the list up under the
       heading and left the whole gap beneath it.) */
    grid-template-rows: auto 1fr auto;
    align-items: start;
  }
  .why-open__title { grid-column: 1; grid-row: 1; }
  /* align-self beats the container's align-items: start. */
  .why-open__list  { grid-column: 1; grid-row: 2; align-self: center; }
  .why-open__body  { grid-column: 2; grid-row: 1 / span 3; }
  .why-open__coda  { grid-column: 1; grid-row: 3; }
}

/* The six CATEGORY TITLES, verbatim, in the order they are answered below.
   The user was explicit about this 2026-08-29: the list mirrors the label that
   sits above each section, NOT the section headings and NOT the plain-words
   questions in the paragraph opposite. All three coexist on purpose and each
   says the same six things a different way: the paragraph asks them in plain
   words, this names them, the sections head them.
   Body face rather than the display face the heading and coda either side of
   it use, so the left column does not become three sizes of Fraunces stacked
   up, and so this reads as a list rather than as a third heading.
   Marker is the site's own: an 8px clay square, near-square corners, exactly
   as .faq__list sets it. `role="list"` because Safari drops list semantics
   from a list with `list-style: none`. */
/* No top margin: the grid's own row gap already separates this from the
   heading, and the extra 32px pushed the left column past the prose and knocked
   the coda 28px below the baseline it is supposed to sit on. */
.why-open__list {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: var(--space-sm);
}
/* EACH ONE LINKS TO ITS SECTION, at the user's instruction 2026-08-29, so this
   is a contents list for the page rather than a static preview. The targets
   are ids on the six .why-q blocks; `html { scroll-padding-top }` is already
   set site-wide, so the landing clears the fixed header with nothing added
   here.
   TYPOGRAPHY IS THE FAQ QUESTION'S, also at the user's instruction: Barlow
   rather than the display face, 600, uppercase, letterspaced, --clay-deep at
   6.22:1. One size UP from the FAQ's own --step--1 to --step-0, because the
   note was that these read too small.
   The anchor is a BLOCK carrying the padding, not an inline span, so the whole
   row is the target rather than just the words — and the padding is what opens
   the list out, the other half of the same note. */
.why-open__list a {
  display: block;
  position: relative;
  /* 0.65rem, not the 0.45 first tried: at 0.45 the rows measured 38px on a
     phone, under the 44px touch target. They are 44 now, and the full row is
     the target since the anchor is a block. */
  padding: 0.65rem 0 0.65rem 1.65rem;
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  line-height: 1.45;
  color: var(--clay-deep);
  text-decoration: none;
}
/* The site's square marker in clay, as .faq__list and .itemlist set it. */
.why-open__list a::before {
  content: "";
  position: absolute;
  left: 0; top: 1.05em;
  width: 8px; height: 8px;
  background: var(--clay);
}
/* Underlined on hover rather than recoloured: --clay-deep is the contrast the
   6.22:1 rests on, and lightening it to --clay on hover would drop it to 4.17.
   Underline is this site's link idiom anyway. */
.why-open__list a:hover,
.why-open__list a:focus-visible { text-decoration: underline; text-underline-offset: 4px; }
.why-open__list a:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }
.why-open__title { font-size: var(--step-4); }
/* Colour does the work; the weight bump supports it. <strong> is right here:
   strong importance, not stylistic bolding. `nowrap` keeps the emphasised word
   whole, since split across a line break it stops reading as one idea. */
.why-open__title strong { color: var(--clay); font-weight: 700; white-space: nowrap; }
.why-open__body { display: grid; gap: var(--space-md); }
.why-open__body > p { font-size: var(--step-1); color: var(--text-muted); max-width: var(--measure); }
/* The page's thesis, moved here from the head of the third paragraph so it
   lands as a declaration rather than as a clause. Display face at full ink,
   and narrow on purpose: it should break over two or three lines and read as a
   statement, not as another paragraph. */
.why-open__coda p {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.3;
  color: var(--text);
  max-width: 22ch;
}

/* THE SIX QUESTIONS ALTERNATE GROUND, sand and clay, at the user's request
   2026-08-29. So each one is its own <section> with a seam either side, and
   the hairlines that used to separate them are gone: the seam is the divider
   now, and two dividers doing one job is one too many.
   1, 3 and 5 sit on sand; 2, 4 and 6 on clay. Question 1 shares its section
   with the page's opening rather than taking a seam of its own, because a seam
   between two stretches of identical sand draws a line where there is no
   change of ground. That is also what keeps question 6 on clay, which is where
   the page wants to end.

   LAYOUT, settled by the user 2026-08-29 after three passes:
     row 1   the category label, spanning the full width, centred
     row 2   the picture on the left, the prose on the right
     row 3   the verse, spanning the full width, centred
   Below 900 the two columns stack, giving label / picture / prose / verse in
   that order - which is the document order too, so nothing needs reordering
   and no CSS `order` property is involved.
   1080px, not the 1240 wrap: 26rem of picture plus the gap leaves 600 for the
   prose, which is --measure. A wider container would only add air at the ends
   of the label and the verse. */
.why-q {
  display: grid;
  gap: var(--space-md);
  max-width: 1080px;
  margin-inline: auto;
}
@media (min-width: 900px) {
  .why-q {
    grid-template-columns: 26rem 1fr;
    column-gap: var(--space-lg);
  }
  .why-q__label  { grid-column: 1 / -1; }
  .why-q__figure { grid-column: 1; min-height: 0; }
  .why-q__body   { grid-column: 2; }
  .why-q__verse  { grid-column: 1 / -1; }
}

/* Centred across the whole block, above both columns. It stays an .eyebrow
   rather than becoming a heading: the QUESTION is the heading, and titling
   each item twice would put both in the page outline. */
.why-q__label { text-align: center; margin-bottom: 0; }
/* The label is a <p>, so on the three clay questions it picks up BOTH of
   `.band p`'s declarations: a top margin that pushed it down against the sand
   ones, and `max-width: --measure`, which capped it at 501px of the 1080 it
   spans and left it centred inside that stub instead of over the block.
   Measured before the fix: 1080 on sand, 501 on clay. Two classes beat one
   class plus one type. */
.band .why-q__label { margin-top: 0; max-width: none; }

/* Stacked, the picture keeps the square it was supplied as. */
.why-q__figure img { aspect-ratio: 1 / 1; height: auto; }
@media (min-width: 900px) {
  /* Beside the prose it MATCHES THE PROSE COLUMN'S HEIGHT instead, which is
     what the user asked for. The grid row is sized by the prose, the frame
     stretches into it, and `.frame img`'s own `object-fit: cover` crops the
     square rather than distorting it - so this wants the square override
     LIFTED, not replaced.
     THE MAX-HEIGHT IS WHAT KEEPS THIS HONEST. Five of the six questions run
     416 to 474px of prose against a 416px-wide column, so they match exactly
     and stay near square. The science question is nearly twice that at 711px,
     because it carries a fourth paragraph and the Britannica definition, and
     unbounded stretch cropped its picture to a 1:0.58 slot. 32.5rem is 1.25x
     the column width, so the crop can never go past a 1:0.8 portrait; below
     that ceiling the stretch still matches the prose to the pixel, and above
     it the picture simply sits at the top of its row.
     `min-height: 0` on the figure keeps the image's intrinsic height out of
     the row sizing, which would otherwise make this circular. */
  .why-q__figure { display: grid; max-height: 32.5rem; }
  .why-q__figure .frame { height: 100%; }
  .why-q__figure img { aspect-ratio: auto; height: 100%; }
}
/* Tilt tied to the ground, so no two consecutive frames lean the same way and
   the sand/clay stagger reads in the artwork as well as in the colour. */
.why-q__figure .frame { --tilt: -1.2deg; }
.band .why-q__figure .frame { --tilt: 1deg; }

/* Left-aligned, unlike the label and the verse either side of it: this column
   heads and carries the argument, and a centred heading over left-aligned
   prose in a side column reads as a mistake.
   `align-content: start` so the prose sits at the top of its row rather than
   being spread down it when the picture is the taller of the two. */
.why-q__body { display: grid; gap: var(--space-sm); max-width: var(--measure); align-content: start; }
.why-q__body h2 { font-size: var(--step-2); }
/* Direct children only, or this reaches into the quoted definition below and
   restyles it. */
.why-q__body > p { color: var(--text-muted); }
/* The one sentence each question turns on, at full ink and a size up while the
   paragraphs around it stay muted. Same device as .tours-lead__key, and it is
   what keeps the page from reading as six paragraphs of equal weight. */
.why-q__body > p.why-q__stand { color: var(--text); font-size: var(--step-1); font-weight: 500; }
.why-q__body a { color: var(--clay-deep); text-decoration: underline; text-underline-offset: 3px; }

/* --- Crediting the founder on a stand line -----------------------------
   Two of the stand lines on this page are Bill Sanderson's own words, and the
   user asked for them to be credited (2026-08-30). The attribution copies
   `.story-quote cite` exactly — body face, uppercase, tracked, --clay-deep —
   because that is already this site's idiom for crediting him, and a founder
   quote should not be announced two different ways on two pages.
   What is NOT copied is .story-quote's own frame: the display face, the size
   and the sandstone rule. The stand treatment on this page is approved and the
   quotes keep it; only the credit is added underneath.
   IT RUNS IN ON THE LAST LINE OF THE QUOTE, not on a line of its own — the
   user asked for that 2026-08-30. So the cite lives INSIDE the .why-q__stand
   paragraph and is inline; there is a real space before it in the markup as
   well as this margin, because without one there is no break opportunity and a
   narrow viewport has nowhere to wrap. Baselines align on their own, which is
   what puts it "in line" despite the two sizes.
   (It was a block underneath at first. That needed a negative top margin to
   beat `.why-q__body`'s grid gap, or it floated equidistant between its own
   quote and the next paragraph. Inline, the problem does not arise.) */
.why-q__cite {
  margin-left: 0.4rem;
  /* Kept whole. At 375 the science credit broke after "BILL" and left the
     surname and title on the next line, which reads as a mistake. Unbreakable,
     it either finishes the quote's last line or moves to the next line intact.
     It cannot overflow: the credit measures about 240px against a 335px column
     at 375, and narrower still at 320. */
  white-space: nowrap;
  font-family: var(--font-body);
  /* cite is italic by default and the display face has no italic axis; upright
     matches the verse cites and .story-quote. */
  font-style: normal;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--clay-deep);
}

/* The verse closes every section, centred under both columns. Centred text and
   centred in the block, unlike the .cs-verse used elsewhere on the site, which
   is set left inside a column.
   `width`, not `max-width`. On a grid item `margin-inline: auto` overrides the
   default stretch and makes the box shrink to fit its own text, so the science
   verse — one short line — drew its rules 474px wide against the other five at
   617. The rules are the visible part of this block, so they have to be the
   same length in all six. */
.why-q__verse { width: min(100%, var(--measure)); margin-inline: auto; text-align: center; }

/* --- The same question, on clay ---------------------------------------
   Every colour above is written for sand and not one of them survives the
   move, so each is restated. Two classes throughout, because `.band p` is one
   class and one type and would otherwise take the muted ink straight back.
   The h2 needs nothing: `.why-q__body h2` sets only a size, so `.band h2`
   still supplies the cream. */
.band .why-q__body > p { color: var(--text-invert-muted); }
.band .why-q__body > p.why-q__stand { color: var(--cream); }
.band .why-q__body a { color: var(--cream); text-decoration-color: var(--sandstone); }
/* --clay-deep is invisible on clay, and --sandstone is the reflex that keeps
   being wrong here: it measures 3.69:1 on this ground, the same trap already
   paid for on `.cs-verse cite` and `.why-q__def cite`. Muted cream is 5.14.
   MUST stay below `.why-q__cite`; same specificity would not, but this is one
   class higher and the source order is kept deliberate anyway. */
.band .why-q__cite { color: var(--text-invert-muted); }

/* --- A quoted definition, which is NOT scripture ----------------------
   The Britannica definition on the science question wore .cs-verse on the
   first build, which was wrong: the top-and-bottom sandstone rules are this
   site's scripture idiom, and that section now closes on a real verse, so the
   two would have worn the same clothes in one section. Ruled on ONE edge and
   set in the body face instead, the same distinction .story-quote already
   draws between a spoken quote and a verse. It sits INSIDE .why-q__body,
   because it belongs to that column's argument rather than being a third row
   of the block. */
.why-q__def {
  padding-top: var(--space-sm);
  border-top: 1px solid var(--rule);
}
.why-q__def p { font-size: var(--step-0); color: var(--text-muted); }
.why-q__def cite {
  display: block;
  margin-top: 0.6rem;
  font-style: normal;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--clay-deep);
}
.band .why-q__def { border-top-color: var(--rule-invert); }
.band .why-q__def p { color: var(--text-invert-muted); }
/* --sandstone AGAIN measured 3.69:1 here, the same trap as the .cs-verse cite
   a few rules down. Sandstone is the site's cite colour on ink and slate and
   it does NOT survive a move onto clay. Muted cream gives 5.14. */
.band .why-q__def cite { color: var(--text-invert-muted); }

/* --- Scripture on a coloured band -------------------------------------
   Written against `.band` rather than against this page: nothing on the site
   had ever put a .cs-verse on anything but sand or a page head, and this is
   the general answer to it. Verified 2026-08-29 that no other page carries one
   inside a band, so this cannot reach anything already shipped.
   MUST STAY BELOW .cs-verse IN THIS FILE.
   NOT --sandstone on the cite: it reads 6.16:1 on --slate-deep and 6.6 on
   --ink, but only 3.69 on this clay, and the cite is small caps at --step--1,
   so it needs 4.5. The band's own muted cream gives 5.14 and still sits back
   from the verse above it. Measured 2026-08-29. */
/* Weight 500 for the same reason the footer verse takes it: Garamond at 400
   thins out on a dark ground. Clay is the third dark scripture ground. */
.band .cs-verse p { color: var(--cream); font-weight: 500; }
.band .cs-verse cite { color: var(--text-invert-muted); }

/* `.band .why-decide` WAS HERE and is deleted, 2026-08-31, with the "You
   decide." line it styled on why-creation.html. That page's closing block now
   says the same thing in the museum's own words. Unlike `.why-q__def` further
   up, this one was not worth keeping unused: it was a centred display-face
   coda with a hairline over it, and `.why-open__coda` and `.nifty-thanks__sign`
   already cover that idiom. Its one specificity note is worth keeping, since it
   will bite again: it had to be written `.band .why-decide`, because `.band p`
   is one class plus one type and outranks a bare single class. */

/* Question 1 shares the opening's section, since they sit on the same ground
   and a seam between them would mark a change that is not happening. This is
   the gap that the section padding would otherwise have supplied.
   The hairline is the third of the opening's three distinguishing signals: the
   seams divide the six questions from each other, so the join between the
   preamble and the first of them is the one boundary on this page that a seam
   cannot mark. Full wrap width, matching the opening above it rather than the
   1000px question block below. */
.why-q-follows {
  margin-top: var(--space-xl);
  padding-top: var(--space-xl);
  border-top: 1px solid var(--rule);
}

/* ============================================================
   THE COLD VEIN IN THE STRATA SEAMS
   Approved and made permanent 2026-09-01. Was a gated preview in
   css/blue-variant.css, which is gone.

   THE RULE, in the user's own vocabulary — SLATE is the dark blue ground,
   SAND is the light textured one, CLAY is the flat mid-brown one:

     THE VEIN ALWAYS TOUCHES THE SLATE, ON WHICHEVER SIDE THE SLATE IS.
     Slate BELOW a seam -> the band sits immediately above it  (.wv)
     Slate ABOVE a seam -> the band sits immediately below it  (.wu-top,
                                                                .wv-top)
     No slate at either end -> no vein.

   What sits on the vein's OTHER side is not part of the rule. It is clay on
   one kind of seam and sandstone on another, and both are correct: the vein
   is the edge the slate is cut on, not a member of the warm stack. An earlier
   pass tried to constrain the far side too and deleted most of the veins. Do
   not re-derive that.

   READING A SEAM. --wave-from and --wave-to BOTH DEFAULT to --slate-deep
   above, which is why the fifteen bare `wave--to-light` pagehead seams count
   as slate-above despite carrying no from- modifier at all:
     slate above = no `wave--from-` class, or `wave--from-dark`
     slate below = `wave--to-dark` or `wave--to-ink`
   The selectors say exactly that, so a seam that gains or loses a modifier
   later starts or stops qualifying on its own.

   THE PATHS ARE IN THE MARKUP and are inserted by .claude/seam-veins.js,
   which can also strip them again (--undo). 40 bands over 19 pages: 20 .wv,
   16 .wu-top, 4 .wv-top pairs. index.html's hero seam is the only one with
   slate on BOTH sides and correctly carries two.

   GEOMETRY. Every seam paints each path as the LID over the one before it, so
   a band goes in BEFORE the path it should sit under, as that path's own curve
   offset five viewBox units. THE CURVES ARE NOT CONSTANT ACROSS THE SITE — two
   seams carry their own — so offsets are computed per seam, never hardcoded.
   Each band renders about 3.7px of a 74px seam at desktop and 2.2px at 375.

   THE GOLDEN HAIRLINE, and why .wv-top-lid is SLATE rather than sandstone.
   The first version of the slate-above-a-downward-seam case painted the vein
   downward over w1 and used a SANDSTONE lid to put the warm stack back. Every
   band measured correct and it still drew a thin gold line between the slate
   and the vein. ANTIALIASING, NOT GEOMETRY: w1 and the vein share a curve but
   rasterise separately, so the boundary pixel composites to
   (1-f)^2*slate + f(1-f)*sandstone + f*blue, leaving ~25% sandstone at f=0.5.
   THREE COLOURS MEETING AT ONE EDGE IS THE BUG. Both paths now fill UPWARD and
   the lid carries --wave-from, so the original ground lands last and only two
   colours meet. The general rule, anywhere a band is slipped under an existing
   layer on this site: PUT THE ORIGINAL COLOUR BACK ON TOP, NEVER A SUBSTITUTE.

   Do not mirror a seam with scaleY(-1) to simplify any of this; it swaps which
   side every layer covers and silently inverts the transition.
   ============================================================ */
.wave .wv, .wave .wu-top, .wave .wv-top, .wave .wv-top-lid { display: none; }
.wave .wv, .wave .wu-top, .wave .wv-top { fill: var(--oval-lit); }
.wave .wv-top-lid { fill: var(--wave-from, var(--slate-deep)); }

/* Slate BELOW — the band sits on top of it. */
.wave--to-dark .wv,
.wave--to-ink .wv { display: inline; }

/* Slate ABOVE — the band sits under it. `:not([class*="--from-"])` is how a
   seam with no from- modifier is caught, and it is load-bearing: that is the
   fifteen pagehead seams, the largest group on the site. */
.wave:not([class*="--from-"]) .wu-top,
.wave--from-dark .wu-top,
.wave:not([class*="--from-"]) .wv-top,
.wave--from-dark .wv-top,
.wave:not([class*="--from-"]) .wv-top-lid,
.wave--from-dark .wv-top-lid { display: inline; }

/* ============================================================
   THE CLAY BANDS GET A SECOND COLOUR
   Added 2026-09-05 at the user's request, approved from three rendered
   candidates. See --sandstone-lit in tokens.css for why the colour is what
   it is.

   THE DIAGNOSIS WAS THE USER'S: "each page that has a clay section only has
   one color on it; white (or off white), whereas the sand sections have
   multiple colors." Measured and true — before this block every clay band was
   cream at 8.21:1 and cream at 72% (5.14:1) and nothing else.

   THEY ASKED FOR SLATE AND SLATE CANNOT DO IT. The whole dark ramp dies on
   --clay-deep: --slate 1.36:1, --slate-2 1.19, --slate-deep 1.70, --oval-lit
   1.50. Clay-deep and the slate ramp sit at nearly the same luminance, so a
   slate rule reads as a dent rather than a line. --ice clears it at 6.62 but
   spending it here would break COLD MEANS INTERACTIVE below. The user saw all
   three rendered, rejected the blues as "too much like the white already
   there", and asked for a gold instead.

   SCOPED TO .band--clay, NOT .band. --moss-deep is a different ground and has
   not been measured for this colour. Do not widen the selector without
   re-measuring.
   ============================================================ */

/* (0,2,0), and the extra class is doing real work: `.eyebrow--invert` is
   declared `var(--sandstone)` at the top of this file but every clay-band
   eyebrow is a <p>, so `.band p` at (0,1,1) out-specifies it and paints it
   muted cream. That is the fallback the audio tour's CSS comments refer to.
   This restores the eyebrow to the sandstone family it was always meant to
   be, at a lightness that survives the ground. 11 eyebrows across 9 pages. */
.band--clay .eyebrow--invert { color: var(--sandstone-lit); }

/* The founder credit under both Bill Sanderson quotes. (0,3,0) against
   `.band .why-q__cite` at (0,2,0), so this wins on SPECIFICITY and does not
   depend on sitting later in the file. That rule's own comment says sandstone
   "is the reflex that keeps being wrong here" at 3.69 — it was right about the
   colour and wrong only about the lightness. Do not delete either rule.
   The verse citations (.cs-verse cite) and the definition cite were offered in
   the same pass and the user left them muted cream. They stay. */
.band--clay .why-q__stand .why-q__cite { color: var(--sandstone-lit); }

/* Heading rules for the headline-plus-paragraph grids: .museum-list on
   our-story (3) and who-we-are (3), .help-list on volunteer (7).
   THE 3px RULE AND THE 0.6rem GAP ARE COPIED FROM `.program h3`, NOT
   INVENTED — that component already carries this exact device, and on a clay
   band `.band .program h3` already overrides its colour to --sandstone. The
   user chose to LEAVE those four alone rather than restate them here, so
   index.html keeps true sandstone and everything else takes the lit tone.
   Both are the same hue, so they read as one family rather than two accents.
   (0,2,1) against the bare `.museum-list h3` / `.help-list h3` at (0,1,1),
   so specificity carries it. Those rules still supply the cream and the size;
   this adds only the rule beneath.
   NOT APPLIED to creation-on-the-road's talk title, which is the only other
   h3 on a clay band: its column is one of a pair and the facing column has no
   heading at all, so ruling one and not the other reads as an accident. */
.band--clay .museum-list h3,
.band--clay .help-list h3 {
  padding-bottom: 0.6rem;
  border-bottom: 3px solid var(--sandstone-lit);
}

/* ============================================================
   COLD MEANS INTERACTIVE
   Approved and made permanent 2026-09-01, from the same preview.

   There is no light blue anywhere else in this stylesheet and that scarcity is
   the whole mechanism: on a site where every accent is warm, one cold colour
   reads as a signal the moment it appears.

   DARK GROUNDS ONLY, and the reason is measured, not stylistic. Against the
   sand the ice tones run 1.06:1 to 1.36:1 and the oval's lit face only reaches
   3.4:1, so none of them can be text, a rule or a fill on the light side. On
   the ink they run 8.9:1 to 12.8:1. THE SITE-WIDE FOCUS RING STAYS OCHRE
   everywhere outside the four dark regions named below.

   THESE RULES MUST STAY AT THE END OF THIS FILE. They deliberately restate
   selectors declared earlier (`.site-footer a:hover`, `.tel:hover`) at the SAME
   specificity, so they win on source order alone. Moving them up the file
   silently reverts the interaction colour to warm.
   ============================================================ */
.site-header :focus-visible,
.visitbar :focus-visible,
.site-footer :focus-visible,
.hero :focus-visible {
  outline-color: var(--ice);
}

/* The nav hover pill. It was a neutral cream wash; this makes the highlight
   itself cold, so the thing under the pointer is the one cold spot on the bar.
   Alpha kept at the shipped 0.18-equivalent weight so the bar does not gain
   visual mass. */
@media (min-width: 981px) {
  .nav__item:hover .nav__trigger,
  .nav__item:focus-within .nav__trigger {
    background: rgba(160, 190, 208, 0.22);
  }
}

/* The visit bar's phone number and envelope, both on --slate-deep. The tel
   hover was ochre, which is the same warm family as its resting state and so
   read as a brightness change rather than a state change. */
.tel:hover,
.tel:focus-visible { color: var(--ice); }
.mail:hover,
.mail:focus-visible { color: var(--ice); border-color: var(--ice); }

/* Footer links, on --ink. */
.site-footer a:hover { color: var(--ice); }
.site-footer__addr:hover,
.site-footer__addr:focus-visible { color: var(--ice); }

/* THE SOCIAL ICONS ARE EXEMPT AND THIS RULE IS WHAT MAKES IT TRUE. They carry
   the four platforms' own brand colours, and `.site-footer a:hover` above
   out-specifies the resting `.site-footer .social a { color: var(--brand) }`
   (0,2,1 against 0,2,1, later wins), so without this the icons would all flip
   to one blue on hover and undo the point of colouring them. Restated here at
   (0,3,1) so the brand colour holds. Do not delete this as redundant. */
.site-footer .social a:hover,
.site-footer .social a:focus-visible { color: var(--brand); }
