@charset "utf-8";
/* =============================================================================
   What Would Ian Do Foundation®  —  site.css
   The single source of visual truth for all seven pages. No page defines its
   own layout or color; everything lives here, driven by the :root tokens.

   Load order in <head>:  Google Fonts  →  this file.
   Paths here are relative to assets/css/, so "../wwid-logo.png" resolves to
   assets/wwid-logo.png. Everything works from a file:// URL.

   CONTENTS
     01  Tokens + light reset          08  Photo slot system + fallback panel
     02  Base typography               09  Gallery mosaic + lightbox
     03  Skip link, .sr-only, focus    10  Forms
     04  Header + nav                  11  Donate components
     05  Buttons                       12  Footer
     06  Sections, wrap, tones         13  Reveal (scroll animation)
     07  Cards                         14  Responsive, reduced motion, print

   CLASS CONTRACT — every contracted class is implemented below. A few
   structural helpers the seven layouts need are also provided, kept inside the
   existing namespaces so nothing is improvised sideways:
     .hero .hero__media .hero__scrim .hero__inner .hero__actions  (index hero)
     .page-hero                                   (interior page title band)
     .split .split--reverse .split__media .split__body   (two-column block)
     .photo--framed                               (offset frame accent)
     .form--inline                                (email signup row)
     .footer__brand .footer__col .footer__note    (footer internals)
     .tier__amount .tier__label                   (donate tier internals)
     .section__head  .field__req                  (minor helpers)
   Mobile nav open state lives on .nav.is-open; site.js owns the scroll lock.
   ============================================================================= */


/* =============================================================================
   01  DESIGN TOKENS + LIGHT RESET
   ============================================================================= */

:root {
  /* ink & structure */
  --ink: #1c2128;
  --ink-soft: #242c37;
  --ink-line: #333d49;
  /* text greys */
  --slate: #4b5560;
  --slate-soft: #587187;
  /* glacier turquoise */
  --teal: #1f7d7a;
  --teal-bright: #3fa89e;
  --teal-deep: #155f68;
  /* alpenglow gold */
  --gold: #f0c896;
  --gold-deep: #d9a86a;
  /* paper */
  --paper: #f4f7f9;
  --paper-alt: #eaf0f4;
  --paper-edge: #cbd6de;
  /* neutrals / on-dark */
  --white: #fff;
  --muted: #8d99a5;
  --on-dark: #eef5f7;
  --on-dark-soft: #b6c1cc;

  /* rgb channels of the fixed palette — used only to build transparent tints,
     scrims and shadows. No new hues: this is the palette above, at alpha. */
  --ink-rgb: 28, 33, 40;
  --teal-rgb: 31, 125, 122;
  --teal-bright-rgb: 63, 168, 158;
  --teal-deep-rgb: 21, 95, 104;
  --gold-rgb: 240, 200, 150;
  --paper-edge-rgb: 203, 214, 222;
  --white-rgb: 255, 255, 255;

  /* derived tints & scrims */
  --tint-teal: rgba(var(--teal-rgb), .08);
  --tint-teal-strong: rgba(var(--teal-rgb), .14);
  --tint-gold: rgba(var(--gold-rgb), .18);
  --hairline: rgba(var(--ink-rgb), .10);
  --hairline-dark: rgba(var(--white-rgb), .14);
  --scrim: rgba(var(--ink-rgb), .55);
  --scrim-deep: rgba(var(--ink-rgb), .88);

  /* type */
  --font-display: 'Playfair Display', Georgia, serif;
  --font-body: 'Public Sans', system-ui, -apple-system, sans-serif;

  /* measure & layout */
  --wrap: 1180px;
  --gutter: clamp(20px, 5vw, 72px);
  --measure: 68ch;
  --measure-lede: 60ch;
  --header-h: clamp(66px, 7vw, 92px);
  --section-y: clamp(56px, 8vw, 96px);

  /* radii */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 20px;
  --r-pill: 999px;

  /* elevation */
  --shadow-sm: 0 1px 2px rgba(var(--ink-rgb), .06), 0 3px 10px rgba(var(--ink-rgb), .06);
  --shadow-md: 0 12px 30px rgba(var(--ink-rgb), .12);
  --shadow-lg: 0 20px 50px rgba(var(--ink-rgb), .20);

  /* motion */
  --ease: cubic-bezier(.22, .61, .36, 1);
  --speed: .28s;
  --speed-slow: .65s;

  /* contextual roles — re-pointed inside dark and teal sections */
  --surface: var(--paper);
  --body-fg: var(--slate);
  --heading-fg: var(--ink);
  --eyebrow-fg: var(--teal-deep);
  --link: var(--teal-deep);
  --link-hover: var(--ink);
  --rule: var(--paper-edge);
  /* Deep teal, not bright: the ring must clear 3:1 against the surface behind
     it. #155f68 is 6.6:1 on --paper, 6.3:1 on --paper-alt, 7.2:1 on white;
     #3fa89e was only 2.6:1 and failed on every light surface. */
  --focus: var(--teal-deep);
}

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--body-fg);
  font-family: var(--font-body);
  font-size: clamp(1rem, .95rem + .2vw, 1.0625rem);
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* Belt to the layout's braces: no sideways scroll at any width. Deliberately
   `clip`, never `hidden` — `overflow-x: hidden` on body turns body into a
   scroll container and silently kills the sticky header. */
@supports (overflow: clip) { body { overflow-x: clip; } }

/* Scroll lock while the mobile nav panel is open. site.js is the primary
   mechanism (it saves and restores the previous inline overflow on both
   <html> and <body>); this rule is the belt-and-braces copy for browsers
   that support :has(). There is deliberately no `.is-nav-open` class rule
   here: nothing ever set that class, so it was dead weight pretending to be
   the contract. */
@supports selector(:has(*)) { body:has(.nav.is-open) { overflow: hidden; } }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ul, ol { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; margin: 0; }
button { background: none; border: 0; }
hr { border: 0; border-top: 1px solid var(--rule); margin: clamp(28px, 4vw, 44px) 0; }
:target { scroll-margin-top: calc(var(--header-h) + 20px); }
main, section, article, div, li { min-width: 0; }   /* long words can't overflow */


/* =============================================================================
   02  BASE TYPOGRAPHY
   ============================================================================= */

a {
  color: var(--link);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  transition: color var(--speed) var(--ease), text-decoration-color var(--speed) var(--ease);
}
a:hover { color: var(--link-hover); }

/* Body-copy links stay underlined — colour alone never carries the meaning. */
.prose a, .lede a, .card__text a, .footer__note a, .donate-note a, .photo__caption a { text-decoration: underline; }
.prose a:hover, .lede a:hover { text-decoration-thickness: 2px; }

.h-display {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.5rem, 1.55rem + 4.4vw, 4.625rem);    /* 40 → 74px */
  line-height: 1.04;
  letter-spacing: -.015em;
  color: var(--heading-fg);
  text-wrap: balance;
}
.h-section {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.875rem, 1.3rem + 2.3vw, 2.625rem);   /* 30 → 42px */
  line-height: 1.12;
  letter-spacing: -.01em;
  color: var(--heading-fg);
  text-wrap: balance;
}
.h-sub {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.12rem + .5vw, 1.5rem);      /* 20 → 24px */
  line-height: 1.22;
  color: var(--heading-fg);
  text-wrap: balance;
}
.eyebrow {
  display: block;
  font-weight: 600;
  font-size: .75rem;
  line-height: 1.2;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--eyebrow-fg);
  text-wrap: balance;
}

/* rhythm between the stock heading pairings */
.eyebrow + .h-display, .eyebrow + .h-section, .eyebrow + .h-sub { margin-top: clamp(10px, 1.4vw, 16px); }
.h-display + .lede, .h-section + .lede, .h-sub + .lede { margin-top: clamp(16px, 2vw, 24px); }
.h-section + .prose, .h-sub + .prose { margin-top: clamp(14px, 1.8vw, 22px); }

.lede {
  max-width: var(--measure-lede);
  font-size: clamp(1.0625rem, 1rem + .35vw, 1.1875rem);   /* 17 → 19px */
  line-height: 1.7;
  color: var(--body-fg);
  text-wrap: pretty;
}
.prose {
  max-width: var(--measure);
  font-size: clamp(1rem, .96rem + .25vw, 1.0625rem);      /* 16 → 17px */
  line-height: 1.8;
  color: var(--body-fg);
}
.prose > * + * { margin-top: 1.15em; }
.prose p, .prose li { text-wrap: pretty; }
.prose h2, .prose h3, .prose h4 { margin-top: 1.6em; }
.prose ul, .prose ol { padding-left: 1.35em; }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li { margin-top: .5em; }
.prose li::marker { color: var(--teal); }
.prose strong { font-weight: 600; color: var(--heading-fg); }

.center { text-align: center; }
.center .lede, .center .prose, .center > .h-display, .center > .h-section { margin-inline: auto; }

/* Prose that answers to the figure above it rather than to the 68ch measure:
   it spans the photo's full width and is inset from the photo's edges (1in
   once there is room - see section 14). Text stays left-aligned; .center would
   centre the lines too, and centred lines this long are a hard read. */
.prose--center { max-width: none; margin-inline: auto; }
.photo + .prose { margin-top: clamp(28px, 4vw, 44px); }

.pull-quote {
  max-width: 30ch;
  margin: clamp(28px, 4vw, 44px) 0;
  padding-left: clamp(18px, 2.4vw, 28px);
  border-left: 3px solid var(--teal-bright);
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.25rem, 1.05rem + .9vw, 1.75rem);
  line-height: 1.4;
  color: var(--teal-deep);
  text-wrap: pretty;
}
.pull-quote p + p { margin-top: .6em; }
.center .pull-quote {
  max-width: 34ch;
  margin-inline: auto;
  padding: clamp(18px, 2.4vw, 26px) 0 0;
  border-left: 0;
  border-top: 3px solid var(--teal-bright);
}
/* Gold reads at 10.3:1 on ink but only 3.1:1 on teal, and at mobile sizes this
   quote is normal-weight 20px text, so the teal band takes white (4.9:1). */
.section--ink .pull-quote { color: var(--gold); border-color: var(--gold); }
.section--teal .pull-quote { color: var(--white); border-color: var(--white); }

.stack > * + * { margin-top: var(--stack-gap, 1.15rem); }


/* =============================================================================
   03  SKIP LINK, SCREEN-READER TEXT, FOCUS RINGS
   ============================================================================= */

.skip-link {
  position: fixed;              /* reachable however far the page has scrolled */
  top: 0;
  left: 12px;
  z-index: 999;
  transform: translateY(-120%);
  padding: 12px 20px;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: var(--gold);
  color: var(--ink);
  font-weight: 700;
  font-size: .9375rem;
  text-decoration: none;
  box-shadow: var(--shadow-md);
  transition: transform var(--speed) var(--ease);
}
.skip-link:focus, .skip-link:focus-visible { transform: translateY(0); color: var(--ink); }

.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Focus is never removed. --focus is re-pointed per surface so the ring always
   clears 3:1 against whatever sits behind it. The outline follows each
   element's own radius, so nothing here touches border-radius. */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
:focus:not(:focus-visible) { outline: none; }


/* =============================================================================
   04  HEADER + NAV
   ============================================================================= */

.site-header {
  --nav-fg: var(--ink);
  --nav-fg-dim: var(--slate);
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--white);
  border-bottom: 1px solid var(--hairline);
  transition: background var(--speed) var(--ease), box-shadow var(--speed) var(--ease), border-color var(--speed) var(--ease);
}
.site-header__inner,
.site-header > .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 40px);
  min-height: var(--header-h);
  padding-block: 10px;
}

/* transparent variant — index.html only, over the hero art */
.site-header--overlay {
  --nav-fg: var(--on-dark);
  --nav-fg-dim: var(--on-dark-soft);
  --focus: var(--gold);
  position: absolute;
  top: 0; left: 0; right: 0;
  background: transparent;
  border-bottom-color: transparent;
}

/* site.js adds .is-stuck once the page scrolls past the hero (or ~24px on
   interior pages). The overlay header becomes a real fixed solid bar. */
.site-header.is-stuck { background: var(--white); border-bottom-color: var(--hairline); box-shadow: var(--shadow-sm); }
.site-header--overlay.is-stuck {
  --nav-fg: var(--ink);
  --nav-fg-dim: var(--slate);
  --focus: var(--teal-deep);      /* the bar is white once stuck: 7.2:1 */
  position: fixed;
  animation: header-drop var(--speed) var(--ease) both;
}
@keyframes header-drop { from { transform: translateY(-100%); } to { transform: translateY(0); } }

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
  text-decoration: none;
  color: var(--nav-fg);
  border-radius: var(--r-sm);
}
.brand:hover { color: var(--nav-fg); }
.brand__mark { width: clamp(40px, 5vw, 52px); height: clamp(40px, 5vw, 52px); object-fit: contain; flex: 0 0 auto; }
.brand__word {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1rem, .95rem + .2vw, 1.0625rem);
  line-height: 1;
  letter-spacing: .02em;
  color: var(--nav-fg);
  white-space: nowrap;
}
.site-header--overlay:not(.is-stuck) .brand__mark { filter: drop-shadow(0 2px 6px rgba(var(--ink-rgb), .45)); }
.site-header--overlay:not(.is-stuck) .brand__word { text-shadow: 0 1px 8px rgba(var(--ink-rgb), .55); }

.nav { display: flex; align-items: center; gap: 8px; min-width: 0; }
.nav__links { display: flex; align-items: center; gap: clamp(14px, 1.9vw, 30px); margin: 0; padding: 0; list-style: none; }
.nav__links li { display: flex; }

.nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;             /* a real target, not just a 14px word */
  padding: 8px 2px;
  font-size: .875rem;
  font-weight: 500;
  line-height: 1;
  color: var(--nav-fg);
  text-decoration: none;
  white-space: nowrap;
}
.site-header--overlay:not(.is-stuck) .nav__link:not(.btn) { text-shadow: 0 1px 6px rgba(var(--ink-rgb), .5); }

.nav__link:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: 8px;                  /* keeps the rule under the word now that the
                                   link box is 44px tall for touch */
  height: 2px;
  border-radius: 2px;
  background: var(--gold);
  transform: scaleX(0);
  transition: transform var(--speed) var(--ease);
}
.nav__link:not(.btn):hover::after { transform: scaleX(.7); }
.nav__link.is-active, .nav__link[aria-current="page"] { font-weight: 700; color: var(--nav-fg); }
.nav__link.is-active:not(.btn)::after,
.nav__link[aria-current="page"]:not(.btn)::after { transform: scaleX(1); }

/* the Donate pill carries .btn.btn--gold as well — drop the nav treatment */
.nav__link.btn { padding-block: 11px; font-size: .875rem; color: var(--ink); }
.nav__link.btn::after { content: none; }

/* Language selector — a plain EN/ES pair, not a dropdown widget, so it works
   with no JavaScript and each half points at the exact counterpart page in
   the other language. The active language is a non-interactive <span> (no
   reason to offer a link that reloads the page you are already on); the
   other language is a real <a>. Both share this class, so the two states
   share one set of rules. */
.nav__lang {
  align-items: center;
  gap: 2px;
  padding-inline-start: 14px;
  border-inline-start: 1px solid rgba(var(--ink-rgb), .14);
}
.site-header--overlay:not(.is-stuck) .nav__lang { border-inline-start-color: rgba(var(--white-rgb), .4); }
.nav__lang-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 8px 6px;
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--nav-fg);
  text-decoration: none;
  opacity: .6;
}
.site-header--overlay:not(.is-stuck) .nav__lang-link { text-shadow: 0 1px 6px rgba(var(--ink-rgb), .5); }
.nav__lang-link:hover { opacity: .9; }
.nav__lang-link.is-active { opacity: 1; font-weight: 700; }
.nav__lang-sep { opacity: .35; font-size: .75rem; }

/* Mobile disclosure toggle. It needs no inner bars: the three strokes come
   from ::before, ::after and a centred background gradient. Markup is just
   <button class="nav__toggle" aria-expanded="false" aria-controls="nav-links">
     <span class="sr-only">Menu</span></button> */
.nav__toggle {
  position: relative;
  display: none;                /* revealed at the nav breakpoint, §14 */
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  flex: 0 0 auto;
  border-radius: var(--r-sm);
  color: var(--nav-fg);
  cursor: pointer;
  background: transparent linear-gradient(currentColor, currentColor) no-repeat center / 22px 2px;
  transition: background-color var(--speed) var(--ease), background-size var(--speed) var(--ease);
}
.nav__toggle::before, .nav__toggle::after {
  content: "";
  position: absolute;
  left: 11px; right: 11px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform var(--speed) var(--ease), top var(--speed) var(--ease);
}
.nav__toggle::before { top: 14px; }
.nav__toggle::after { top: 28px; }
.nav__toggle:hover { background-color: var(--tint-teal); }
.nav.is-open .nav__toggle { background-size: 0 2px; }
.nav.is-open .nav__toggle::before { top: 21px; transform: rotate(45deg); }
.nav.is-open .nav__toggle::after { top: 21px; transform: rotate(-45deg); }


/* =============================================================================
   05  BUTTONS
   ============================================================================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55em;
  min-height: 44px;
  padding: 14px 30px;
  border: 1.5px solid transparent;
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--speed) var(--ease), border-color var(--speed) var(--ease),
              color var(--speed) var(--ease), box-shadow var(--speed) var(--ease),
              transform var(--speed) var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; transform: none; box-shadow: none; }

.btn--gold { background: var(--gold); color: var(--ink); box-shadow: 0 8px 24px rgba(var(--ink-rgb), .22); }
.btn--gold:hover, .btn--gold:focus-visible { background: var(--gold-deep); color: var(--ink); box-shadow: 0 12px 30px rgba(var(--ink-rgb), .26); }
.btn--gold:active { box-shadow: 0 4px 14px rgba(var(--ink-rgb), .22); }

.btn--teal { background: var(--teal); color: var(--white); box-shadow: 0 8px 22px rgba(var(--teal-deep-rgb), .28); }
.btn--teal:hover, .btn--teal:focus-visible { background: var(--teal-deep); color: var(--white); }

/* ghost: teal outline on light surfaces, frosted white over art and on the
   dark / teal bands (the mockup's secondary hero button) */
.btn--ghost { background: transparent; border-color: var(--teal); color: var(--teal-deep); }
.btn--ghost:hover, .btn--ghost:focus-visible { background: var(--tint-teal); border-color: var(--teal-deep); color: var(--teal-deep); }

.section--ink .btn--ghost, .section--teal .btn--ghost,
.donate-hero .btn--ghost, .footer .btn--ghost {
  background: rgba(var(--white-rgb), .14);
  border-color: rgba(var(--white-rgb), .6);
  color: var(--white);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.section--ink .btn--ghost:hover, .section--teal .btn--ghost:hover,
.donate-hero .btn--ghost:hover, .footer .btn--ghost:hover,
.section--ink .btn--ghost:focus-visible,
.section--teal .btn--ghost:focus-visible, .donate-hero .btn--ghost:focus-visible,
.footer .btn--ghost:focus-visible {
  background: rgba(var(--white-rgb), .24);
  border-color: var(--white);
  color: var(--white);
}

/* In the hero the button sits on an unconstrained photograph — the snow-lit
   band of the Ausangate frame is bright enough that a white wash would leave
   white type at ~1.9:1. An ink wash carries its own contrast (≥6.5:1 over any
   pixel in that image) and still reads as frosted glass over the mountain. */
.hero .btn--ghost {
  background: rgba(var(--ink-rgb), .60);
  border-color: rgba(var(--white-rgb), .75);
  color: var(--white);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.hero .btn--ghost:hover, .hero .btn--ghost:focus-visible {
  background: rgba(var(--ink-rgb), .74);
  border-color: var(--white);
  color: var(--white);
}

.btn--lg { min-height: 54px; padding: 17px 42px; font-size: 1.0625rem; }
.btn--block { display: flex; width: 100%; }


/* =============================================================================
   06  SECTIONS, WRAP, TONE VARIANTS
   ============================================================================= */

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }

.section { position: relative; padding-block: var(--section-y); background: var(--surface); color: var(--body-fg); }
.section > .wrap > * + .card-grid,
.section > .wrap > * + .gallery { margin-top: clamp(32px, 4.5vw, 54px); }
.section__head { max-width: 900px; margin-bottom: clamp(32px, 4.5vw, 52px); }
.section__head.center { margin-inline: auto; }

.section--paper { --surface: var(--paper); background: var(--paper); }
.section--paper-alt { --surface: var(--paper-alt); background: var(--paper-alt); }

.section--ink, .footer {
  --surface: var(--ink);
  --body-fg: var(--on-dark-soft);
  --heading-fg: var(--white);
  --eyebrow-fg: var(--gold);
  --link: var(--gold);
  --link-hover: var(--white);
  --rule: var(--ink-line);
  --focus: var(--gold);
}
.section--ink { background: var(--ink); color: var(--on-dark-soft); }

.section--teal {
  --surface: var(--teal);
  --body-fg: var(--white);
  --heading-fg: var(--white);
  /* On teal, --on-dark is 4.4:1 and gold 3.1:1 — both short of 4.5:1 for the
     12px eyebrow and for link text. White (4.9:1) is the only palette value
     that clears it, so hover is carried by the underline instead of colour. */
  --eyebrow-fg: var(--white);
  --link: var(--white);
  --link-hover: var(--white);
  --rule: rgba(var(--white-rgb), .28);
  --focus: var(--white);
  overflow: hidden;
  color: var(--white);
  /* The field behind text never runs lighter than --teal, so white copy holds
     4.9:1 across the whole band. Bright turquoise is a highlight and a ring,
     never a surface under type. */
  background:
    radial-gradient(90% 70% at 88% 6%, rgba(var(--teal-bright-rgb), .08), transparent 62%),
    linear-gradient(135deg, var(--teal-deep) 0%, var(--teal) 55%, var(--teal-deep) 100%);
}

/* the traveling duck (left) and the walking photo (right) — this one teal
   band on index.html only, not every .section--teal (about.html has one too,
   for "The question"). Mirrored corners, same size, same treatment. */
.donate-cta__duck, .donate-cta__walker {
  position: absolute;
  top: clamp(14px, 3vw, 28px);
  z-index: 1;
  width: clamp(100px, 15vw, 190px);
  height: auto;
  border-radius: var(--r-md);
  box-shadow: 0 6px 20px rgba(var(--ink-rgb), .35);
}
/* the duck is a <picture> (it swaps format, and swaps to a still frame under
   prefers-reduced-motion), so the box above is the wrapper and the image
   inside has to fill it and take the same corners */
.donate-cta__duck { display: block; overflow: hidden; line-height: 0; }
.donate-cta__duck img { display: block; width: 100%; height: auto; border-radius: inherit; }
.donate-cta__duck { left: clamp(14px, 3vw, 28px); }
.donate-cta__walker { right: clamp(14px, 3vw, 28px); object-fit: cover; aspect-ratio: 1; }

/* Second image in each corner column: the bird drawing under the duck, the
   quote print under the walking photo. Same width and treatment as the image
   above it. Remember .section--teal clips overflow, so if either ever grows it
   has to stay inside the band.

   They are anchored differently on purpose. The quote is tall and hangs from
   the walking photo: its top is the corner inset + the height of the image
   above (duck and walker are both square, so height = width) + a gap, which
   lands it close to the foot of the band on its own. The bird is a third of
   that height, so hanging it the same way left the whole lower half of the
   left column empty. It sits on the bottom corner inset instead - the mirror
   of the duck's inset at the top - which balances the two columns. */
.donate-cta__bird, .donate-cta__quote {
  position: absolute;
  z-index: 1;
  width: clamp(100px, 15vw, 190px);
  height: auto;
  border-radius: var(--r-md);
  box-shadow: 0 6px 20px rgba(var(--ink-rgb), .35);
}
.donate-cta__quote {
  right: clamp(14px, 3vw, 28px);
  top: calc(clamp(14px, 3vw, 28px) + clamp(100px, 15vw, 190px) + clamp(10px, 2vw, 16px));
}
.donate-cta__bird {
  left: clamp(14px, 3vw, 28px);
  bottom: clamp(14px, 3vw, 28px);
  background: var(--white);
}
/* These two sit lower than the duck and the walker, where the band's centred
   copy is at its widest — below about 1080px they collide with it, so they
   only appear once there is measured room. (Checked in a browser, not by eye:
   at 1080 the gap to the lede is 1px, so 1100 is the honest threshold.) */
@media (max-width: 1100px) {
  .donate-cta__bird, .donate-cta__quote { display: none; }
}
@media (max-width: 560px) {
  /* At this size the centered heading starts too close to either edge for
     full-size corner images to sit beside it without covering the text. */
  .donate-cta__duck, .donate-cta__walker { width: 60px; top: 10px; }
  .donate-cta__duck { left: 10px; }
  .donate-cta__walker { right: 10px; }
}

/* the mockup's outlined circle, echoed on teal bands */
.section--teal::after, .donate-hero::after {
  content: "";
  position: absolute;
  top: -40px; right: -40px;
  width: clamp(150px, 22vw, 260px);
  aspect-ratio: 1;
  border: 2px solid rgba(var(--white-rgb), .15);
  border-radius: 50%;
  pointer-events: none;
}
.section--ink .prose strong, .section--teal .prose strong { color: var(--white); }

/* Link hover on the teal surfaces carries no colour delta by design (see the
   note above), so it has to be visible some other way. */
.section--teal a:not(.btn):not(.tier):hover,
.donate-hero a:not(.btn):not(.tier):hover {
  text-decoration: underline;
  text-decoration-thickness: 2px;
}

/* --- hero, page hero, split (structural helpers) --------------------------- */

.hero {
  --body-fg: var(--on-dark);
  --heading-fg: var(--white);
  --eyebrow-fg: var(--gold);
  --focus: var(--gold);
  position: relative;
  display: grid;
  align-items: center;
  min-height: clamp(520px, 82vh, 760px);
  padding-block: calc(var(--header-h) + clamp(40px, 7vw, 90px)) clamp(56px, 9vw, 110px);
  overflow: hidden;
  background: var(--ink);
  color: var(--on-dark);
  isolation: isolate;
}
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  /* No background-image on purpose. The <picture> inside this element already
     paints the photograph, and it picks the right format and width for the
     device; a background url() here would be a second, unconditional download
     of a file the browser has no way to skip. --hero-image is still honoured
     if someone wants to override the art without touching the markup. */
  background: var(--hero-image, none) center 30% / cover no-repeat, var(--ink);
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; }
.hero__media picture { display: contents; }
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(var(--ink-rgb), .60) 0%, rgba(var(--ink-rgb), .12) 30%,
    rgba(var(--ink-rgb), .20) 58%, rgba(var(--ink-rgb), .74) 100%);
}
.hero__inner { position: relative; max-width: 900px; margin-inline: auto; text-align: center; }
.hero__inner .eyebrow { letter-spacing: .4em; text-shadow: 0 1px 3px rgba(var(--ink-rgb), .85), 0 2px 14px rgba(var(--ink-rgb), .6); }
.hero__inner .h-display { margin-top: 18px; color: var(--white); text-shadow: 0 4px 26px rgba(var(--ink-rgb), .5); }
.hero__inner .lede {
  margin: clamp(18px, 2.6vw, 26px) auto 0;
  max-width: 34rem;
  color: var(--on-dark);
  text-shadow: 0 2px 12px rgba(var(--ink-rgb), .6);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; margin-top: clamp(26px, 3.6vw, 34px); }

/* --- hero seals — index.html only, both bottom corners of the hero photo --
   .hero only exists on index.html, so nothing here needs a page guard. Sized
   and placed in physical units (a US silver dollar is 1.5in across) rather
   than viewport-relative ones, since that was the actual brief; the source
   PNG is pre-cropped to the coin's own edge, so 1.5in here is the coin, not
   its bounding box plus transparent padding. */
.hero__seal {
  position: absolute;
  bottom: .5in;
  z-index: 5;
  width: 1.5in;
  height: 1.5in;
  filter: drop-shadow(0 4px 16px rgba(var(--ink-rgb), .5));
}
/* each seal is a <picture> (WebP with a PNG behind it), so the box above is
   the wrapper and the image inside has to fill it */
.hero__seal { display: block; line-height: 0; }
.hero__seal img { display: block; width: 100%; height: 100%; object-fit: contain; }
.hero__seal--right { right: .5in; }
.hero__seal--left { left: .5in; }

/* Below this height, the shortest common phone viewports leave under 60px
   between the stacked buttons and the hero's bottom edge -- not enough room
   for a 1.5in coin without covering button text. Both seals shrink to fit
   inside whatever's actually left, rather than covering the buttons. */
@media (max-height: 700px), (max-width: 420px) {
  .hero__seal { width: 46px; height: 46px; bottom: 8px; }
  .hero__seal--right { right: 8px; }
  .hero__seal--left { left: 8px; }
}

.page-hero {
  --body-fg: var(--on-dark-soft);
  --heading-fg: var(--white);
  --eyebrow-fg: var(--gold);
  --link: var(--gold);
  --focus: var(--gold);
  position: relative;
  padding-block: clamp(48px, 7vw, 84px);
  background: radial-gradient(80% 120% at 80% -20%, rgba(var(--teal-rgb), .35), transparent 60%), var(--ink);
  color: var(--on-dark-soft);
}
.page-hero .h-display { font-size: clamp(2.25rem, 1.5rem + 3.2vw, 3.5rem); }
.page-hero .lede { color: var(--on-dark); }

.split { display: grid; grid-template-columns: 1fr; gap: clamp(32px, 4.5vw, 56px); align-items: center; }
.split__media { position: relative; padding: clamp(2px, 1.6vw, 20px); }  /* room for the offset frame */
.split__body { min-width: 0; }

/* site.js adds this to the giving block when there is no amount chooser to
   show, so the layout does not keep a two-column shape with one column empty.
   The rule has to beat the two-column rule in the responsive section further
   down, hence the doubled class. */
.split.split--single.split--single { grid-template-columns: 1fr; max-width: 30rem; margin-inline: auto; gap: clamp(20px, 3vw, 30px); }
.split--single .split__body { text-align: center; }


/* =============================================================================
   07  CARDS
   ============================================================================= */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(26px, 3vw, 36px) clamp(22px, 2.6vw, 30px);
  border: 1px solid var(--paper-edge);
  border-radius: var(--r-md);
  background: var(--white);
  box-shadow: var(--shadow-sm);
  transition: transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease), border-color var(--speed) var(--ease);
}
.card__num { font-family: var(--font-display); font-weight: 700; font-size: 2.5rem; line-height: 1; color: var(--teal); }
.card__title {
  margin-top: 16px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.375rem;
  line-height: 1.2;
  color: var(--heading-fg);
  text-wrap: balance;
}
.card__text { margin-top: 10px; font-size: .9375rem; line-height: 1.7; color: var(--body-fg); text-wrap: pretty; }
.card__text + .btn, .card__text + .card__text { margin-top: 16px; }
.card > .btn { margin-top: auto; align-self: flex-start; }
.card > .btn.btn--block { align-self: stretch; }

a.card { text-decoration: none; color: inherit; }
a.card:hover { transform: translateY(-3px); border-color: var(--teal-bright); box-shadow: var(--shadow-md); }

/* the mockup's value cards, on the ink band */
.section--ink .card, .footer .card { border-color: var(--ink-line); background: var(--ink-soft); box-shadow: none; }
.section--ink .card__num { color: var(--teal-bright); }
.section--ink .card__title { color: var(--white); }
.section--ink .card__text { color: var(--on-dark-soft); }

.section--teal .card { border-color: rgba(var(--white-rgb), .28); background: rgba(var(--white-rgb), .10); box-shadow: none; color: var(--white); }
.section--teal .card__num, .section--teal .card__title, .section--teal .card__text { color: var(--white); }

.card-grid { display: grid; grid-template-columns: 1fr; gap: clamp(18px, 2.4vw, 28px); align-items: stretch; }
.card-grid > * { min-width: 0; }
/* .card-grid--3 : 1-up mobile → 2-up tablet → 3-up desktop, see §14 */


/* =============================================================================
   08  PHOTO SLOT SYSTEM
   -----------------------------------------------------------------------------
   <figure class="photo photo--4x3" data-photo="SLOT_ID">
     <img class="photo__img" src="assets/photos/SLOT_ID.jpg" alt="…"
          loading="lazy" decoding="async">
     <figcaption class="photo__caption">optional caption</figcaption>
   </figure>

   site.js adds .is-empty to the figure when the image fails to load and shows
   .photo__fallback. The tonal panel and the emblem watermark are drawn by
   .photo.is-empty itself, so a slot degrades beautifully even if the
   .photo__fallback element is absent — that element only adds the quiet label.
   No dashed borders, no grey dev boxes: this is a designed empty state.
   ============================================================================= */

.photo {
  --ar: 4 / 3;
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  margin: 0;
  min-width: 0;
  container-type: inline-size;
}
.photo--4x3 { --ar: 4 / 3; }
.photo--4x5 { --ar: 4 / 5; }
.photo--16x9 { --ar: 16 / 9; }
.photo--3x2 { --ar: 3 / 2; }
.photo--3x4 { --ar: 3 / 4; }
.photo--2x3 { --ar: 2 / 3; }
.photo--square { --ar: 1 / 1; }

.photo__img {
  width: 100%;
  height: auto;
  aspect-ratio: var(--ar);      /* nothing shifts when real photos land */
  object-fit: cover;
  border-radius: var(--r-md);
  background: var(--paper-alt);
  box-shadow: var(--shadow-md);
}
.photo__caption { margin-top: 12px; font-size: .875rem; line-height: 1.6; color: var(--body-fg); text-wrap: pretty; }
.section--ink .photo__caption, .section--teal .photo__caption { color: var(--on-dark-soft); }

/* A caption that introduces the photo below it rather than describing the one
   above: centred, in the display face and lightly italicised so it reads as
   a soft lead-in rather than body copy. */
.photo__caption--intro {
  margin-top: 0;
  margin-bottom: 14px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.0625rem;
  line-height: 1.5;
  text-align: center;
  color: var(--teal-deep);
}
.section--ink .photo__caption--intro, .section--teal .photo__caption--intro { color: var(--gold); }

/* Short accent rule standing in for a section break, echoing the pull-quote's
   teal-bright top border rather than the plain full-width --rule hr. */
.section-divider {
  width: 64px;
  height: 3px;
  margin: clamp(28px, 4vw, 44px) auto;
  border: 0;
  border-radius: 2px;
  background: var(--teal-bright);
}
.section--ink .section-divider, .section--teal .section-divider { background: var(--gold); }

/* the mockup's offset outline behind the portrait */
.photo--framed { outline: 2px solid var(--paper-edge); outline-offset: clamp(9px, 1.5vw, 18px); border-radius: var(--r-md); }
.section--ink .photo--framed, .section--teal .photo--framed { outline-color: rgba(var(--white-rgb), .28); }

/* --- empty state ----------------------------------------------------------- */

.photo.is-empty .photo__img { display: none; }

/* the tonal panel: soft alpine light over a paper wash, with a whisper of grain */
.photo.is-empty::before {
  content: "";
  display: block;
  width: 100%;
  aspect-ratio: var(--ar);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm), inset 0 0 0 1px rgba(var(--paper-edge-rgb), .9);
  background-color: var(--paper-alt);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.22'/%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 50% 0%, rgba(var(--teal-bright-rgb), .16), transparent 62%),
    linear-gradient(158deg, var(--paper) 0%, var(--paper-alt) 48%, rgba(var(--paper-edge-rgb), .75) 100%);
  background-size: 140px 140px, auto, auto;
  background-repeat: repeat, no-repeat, no-repeat;
}
/* the faint centred emblem watermark */
.photo.is-empty::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: var(--r-md);
  background: url("../wwid-logo.png") no-repeat center / min(38%, 132px) auto;
  opacity: .13;
}
/* the low-key corner copyright mark, on every populated photo site-wide.
   Scoped to :not(.is-empty) so it never doubles up with the centred emblem
   above; sized in cqw off .photo's own container-type: inline-size, so a
   gallery thumbnail and a full-width hero photo both get a proportionate
   mark without a manual breakpoint per size. Purely decorative and drawn by
   the browser — pointer-events: none keeps it out of the lightbox/zoom click
   target, and it is never baked into the photo file itself. */
.photo:not(.is-empty)::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  width: clamp(18px, 9cqw, 34px);
  aspect-ratio: 1;
  margin: 0 clamp(6px, 4cqw, 14px) clamp(6px, 4cqw, 14px) 0;
  background: url("../wwid-logo-transparent.png") no-repeat center / contain;
  opacity: .55;
  filter: drop-shadow(0 1px 3px rgba(var(--ink-rgb), .55));
  pointer-events: none;
}

/* the quiet label, revealed by site.js */
.photo__fallback {
  display: none;
  position: absolute;
  inset: 0;
  align-items: flex-end;
  justify-content: center;
  padding: clamp(12px, 4%, 22px);
  text-align: center;
  pointer-events: none;
  border-radius: var(--r-md);
}
.photo.is-empty .photo__fallback { display: flex; }
.photo__fallback, .photo__fallback * {
  font-family: var(--font-body);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--slate);
}
/* on a small slot the label would crowd the emblem */
@container (max-width: 210px) {
  .photo__fallback { display: none !important; }
  .photo.is-empty::after { background-size: 46% auto; }
}

/* the same panel, tuned for dark surfaces */
.section--ink .photo.is-empty::before,
.section--teal .photo.is-empty::before,
.footer .photo.is-empty::before {
  background-color: var(--ink-soft);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.16'/%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 50% 0%, rgba(var(--teal-bright-rgb), .22), transparent 62%),
    linear-gradient(158deg, var(--ink-soft) 0%, var(--ink) 100%);
  box-shadow: inset 0 0 0 1px rgba(var(--white-rgb), .10);
}
.section--ink .photo.is-empty::after,
.section--teal .photo.is-empty::after,
.footer .photo.is-empty::after { opacity: .18; }
.section--ink .photo__fallback, .section--ink .photo__fallback *,
.section--teal .photo__fallback, .section--teal .photo__fallback * { color: var(--on-dark-soft); }


/* =============================================================================
   09  GALLERY MOSAIC + LIGHTBOX
   ============================================================================= */

/* dense: a wide or tall tile that cannot fit the columns left in a row would
   otherwise leave that space empty for good. Dense lets the smaller tiles that
   follow back-fill those holes, so the mosaic stays solid as photos are added. */
.gallery {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: clamp(130px, 26vw, 200px);
  grid-auto-flow: row dense;
  gap: clamp(10px, 1.4vw, 16px);
}
.gallery__item {
  position: relative;
  height: 100%;
  margin: 0;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--r-md);
}
.gallery__item--wide { grid-column: span 2; }
.gallery__item--tall { grid-row: span 2; }

/* media inside a mosaic cell fills the cell rather than using its own ratio */
.gallery__item.photo, .gallery__item .photo { height: 100%; }
.gallery__item .photo__img,
.gallery__item.photo.is-empty::before,
.gallery__item .photo.is-empty::before {
  flex: 1 1 auto;
  height: 100%;
  min-height: 0;
  aspect-ratio: auto;
  object-fit: cover;
}
.gallery__item .photo__img { cursor: zoom-in; transition: transform var(--speed-slow) var(--ease); }
.gallery__item:hover .photo__img { transform: scale(1.03); }

/* captions overlay the tile instead of pushing the grid */
.gallery__item .photo__caption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  margin: 0;
  padding: 28px 16px 12px;
  background: linear-gradient(180deg, transparent, rgba(var(--ink-rgb), .78));
  color: var(--white);
  font-size: .8125rem;
  opacity: 0;
  transition: opacity var(--speed) var(--ease);
}
.gallery__item:hover .photo__caption, .gallery__item:focus-within .photo__caption { opacity: 1; }

/* A tile whose photograph failed to load draws the "Photograph coming soon"
   panel across itself; a caption would come up on hover on top of that label. */
.gallery__item.photo.is-empty .photo__caption,
.gallery__item .photo.is-empty .photo__caption { display: none; }

.gallery__item button, .gallery__item a {
  display: block;
  width: 100%; height: 100%;
  padding: 0;
  border: 0;
  border-radius: var(--r-md);
  background: none;
  cursor: zoom-in;
}

/* --- video ------------------------------------------------------------------ */

/* Deliberately OUTSIDE the .photo system, and it must stay that way.
   initPhotos() walks $$('.photo__img') and treats anything it finds with no
   usable src as a missing photograph, and the lightbox paints every tile into
   one shared <img>. A <video> wearing .photo__img or .gallery__item therefore
   ends up either hidden behind "Photograph coming soon" or opened as a broken
   still. This figure owns its own classes and its own styles so neither system
   can see it. */
.video-figure { margin: 0; }

.video-figure__player {
  display: block;
  width: 100%;
  /* height:auto is load-bearing, not boilerplate. The width/height attributes
     on the <video> tag are presentational hints, so height="1280" applies as
     CSS unless something overrides it: the box then stands 1280px tall, the
     9:16 film is letterboxed inside it, and you get a deep black band above
     and below. Same reason every reset carries `img { height: auto }`. */
  height: auto;
  /* The source is a 9:16 phone recording. Left full-width it would stand two
     screens tall, so it is capped and centred instead. */
  max-width: 22.5rem;
  aspect-ratio: 9 / 16;
  margin-inline: auto;
  border-radius: var(--r-md);
  background: #000;
  box-shadow: var(--shadow-lg);
}

.video-figure__caption {
  max-width: var(--measure-lede);
  margin: clamp(14px, 2vw, 20px) auto 0;
  font-size: .9375rem;
  line-height: 1.6;
  color: var(--body-fg);
  text-wrap: pretty;
}

/* --- lightbox --------------------------------------------------------------- */

.lightbox {
  --focus: var(--gold);
  display: none;                /* closed = out of the tab order entirely */
  position: fixed;
  inset: 0;
  z-index: 300;
  padding: clamp(16px, 4vw, 48px);
  background: var(--scrim-deep);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.lightbox.is-open { display: grid; place-items: center; animation: fade-in var(--speed) var(--ease) both; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.lightbox__stage {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  max-width: min(1100px, 100%);
  max-height: 100%;
}
.lightbox__img {
  max-width: 100%;
  max-height: 76vh;
  width: auto; height: auto;
  object-fit: contain;
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-lg);
  background: var(--ink-soft);
}
.lightbox__caption { max-width: 60ch; color: var(--on-dark); font-size: .9375rem; line-height: 1.6; text-align: center; text-wrap: pretty; }

/* controls are fixed to the viewport so they are reachable at every size */
.lightbox__close, .lightbox__prev, .lightbox__next {
  position: fixed;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px; height: 48px;
  border: 1px solid rgba(var(--white-rgb), .35);
  border-radius: var(--r-pill);
  background: rgba(var(--white-rgb), .12);
  color: var(--white);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  transition: background-color var(--speed) var(--ease), border-color var(--speed) var(--ease), transform var(--speed) var(--ease);
}
.lightbox__close:hover, .lightbox__prev:hover, .lightbox__next:hover { background: rgba(var(--white-rgb), .26); border-color: var(--white); }
.lightbox__close { top: clamp(12px, 3vw, 28px); right: clamp(12px, 3vw, 28px); }
.lightbox__prev { left: clamp(10px, 2.5vw, 32px); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: clamp(10px, 2.5vw, 32px); top: 50%; transform: translateY(-50%); }
.lightbox__prev:hover, .lightbox__next:hover { transform: translateY(-50%) scale(1.06); }


/* =============================================================================
   10  FORMS
   ============================================================================= */

.form { width: 100%; max-width: 40rem; }
.form > * + * { margin-top: clamp(16px, 2vw, 22px); }
.form--inline { display: flex; flex-wrap: wrap; gap: 12px; max-width: 34rem; }
.form--inline > * + * { margin-top: 0; }
.form--inline .field { flex: 1 1 15rem; margin: 0; }
.form--inline .btn { flex: 0 0 auto; }

.field { display: block; }
.field__label { display: block; margin-bottom: 8px; font-size: .875rem; font-weight: 600; line-height: 1.4; color: var(--heading-fg); }
.field__req { color: var(--teal); }

.field__input {
  display: block;
  width: 100%;
  min-height: 48px;
  padding: 13px 16px;
  border: 1px solid var(--paper-edge);
  border-radius: var(--r-md);
  background: var(--white);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.5;
  transition: border-color var(--speed) var(--ease), box-shadow var(--speed) var(--ease), background-color var(--speed) var(--ease);
}
textarea.field__input { min-height: 9rem; resize: vertical; line-height: 1.7; }
select.field__input { padding-right: 40px; cursor: pointer; }
/* --muted on white is 2.9:1; placeholder text is text and needs 4.5:1. */
.field__input::placeholder { color: var(--slate); opacity: 1; }
.field__input:hover { border-color: var(--slate-soft); }
.field__input:focus { outline: none; border-color: var(--teal); box-shadow: 0 0 0 3px var(--tint-teal-strong); }
.field__input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* an invalid field is never signalled by colour alone: weight + message too */
.field__input[aria-invalid="true"], .field.has-error .field__input {
  border-color: var(--gold-deep);
  border-width: 2px;
  background: rgba(var(--gold-rgb), .10);
}
.field__error {
  display: block;
  margin-top: 8px;
  padding-left: 12px;
  border-left: 3px solid var(--gold-deep);
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--heading-fg);
}
.field__error:empty { display: none; }

/* -- photograph uploads (contact page) ------------------------------------
   The field removes itself unless the form has a relay to post to, because a
   mailto: link cannot carry an attachment. site.js owns that; see
   assets/js/site.js, "Photograph uploads".
   ------------------------------------------------------------------------ */

.field__optional { font-weight: 400; color: var(--slate); }
.field__help { margin-top: 8px; font-size: .8125rem; line-height: 1.6; color: var(--slate); }

/* A file input cannot be restyled as one piece, but its button half can be,
   and the rest is brought into line with the other fields so the row does not
   sit in the form looking like it came from somewhere else. */
.field__input--file { padding: 10px 12px; cursor: pointer; }
.field__input--file::file-selector-button {
  margin-right: 14px;
  padding: 8px 16px;
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  background: var(--paper-alt);
  font: inherit;
  font-size: .875rem;
  font-weight: 600;
  color: var(--heading-fg);
  cursor: pointer;
  transition: background var(--speed) var(--ease), border-color var(--speed) var(--ease);
}
.field__input--file::file-selector-button:hover {
  border-color: var(--teal);
  background: var(--tint-teal);
  color: var(--teal-deep);
}

.file-list { margin-top: 12px; padding: 0; list-style: none; }
.file-list__item, .file-list__total {
  display: flex;
  gap: 12px;
  align-items: baseline;
  justify-content: space-between;
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: .875rem;
  line-height: 1.5;
}
.file-list__item { background: var(--paper-alt); color: var(--body-fg); }
.file-list__item + .file-list__item { margin-top: 6px; }
/* A phone camera filename has no spaces to break at, so it is allowed to
   break anywhere rather than push the form sideways. */
.file-list__name { min-width: 0; overflow-wrap: anywhere; }
.file-list__size { flex: none; color: var(--slate); font-variant-numeric: tabular-nums; }

/* Marked on the row itself, so it is clear *which* photograph has to be
   swapped rather than only that one of them does. */
.file-list__item--over { background: var(--tint-gold); color: var(--ink); font-weight: 600; }
.file-list__item--over .file-list__size { color: var(--ink); }

.file-list__total {
  margin-top: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  color: var(--slate);
  font-weight: 600;
}

.form-status {
  padding: 14px 18px;
  border-radius: var(--r-md);
  border-left: 4px solid var(--rule);
  background: var(--white);
  font-size: .9375rem;
  line-height: 1.6;
  color: var(--heading-fg);
}
.form-status:empty { display: none; }
.form-status--ok { border-left-color: var(--teal); background: var(--tint-teal); color: var(--teal-deep); }
.form-status--err { border-left-color: var(--gold-deep); background: var(--tint-gold); color: var(--ink); }

/* Honeypot: off-screen, NOT display:none, so bots still fill it. The markup
   must also carry aria-hidden="true" and tabindex="-1" on the input. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  top: auto;
  width: 1px; height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

/* forms on dark surfaces */
.section--ink .field__input, .footer .field__input { border-color: var(--ink-line); background: var(--ink-soft); color: var(--white); }
.section--ink .field__input::placeholder, .footer .field__input::placeholder { color: var(--muted); }
.section--ink .field__input:hover, .footer .field__input:hover { border-color: var(--slate-soft); }
.section--ink .field__input:focus, .footer .field__input:focus { border-color: var(--teal-bright); box-shadow: 0 0 0 3px rgba(var(--teal-bright-rgb), .28); }
.section--ink .field__error, .footer .field__error { border-left-color: var(--gold); color: var(--white); }
.section--ink .form-status, .footer .form-status { background: var(--ink-soft); color: var(--on-dark); }
.section--ink .form-status--ok, .footer .form-status--ok { border-left-color: var(--teal-bright); color: var(--on-dark); }
.section--ink .form-status--err, .footer .form-status--err { border-left-color: var(--gold); color: var(--on-dark); }

/* pill inputs sit better beside the pill button in the inline signup */
.form--inline .field__input { border-radius: var(--r-pill); padding-inline: 20px; }


/* =============================================================================
   11  DONATE COMPONENTS
   ============================================================================= */

.donate-hero {
  --body-fg: var(--white);
  --heading-fg: var(--white);
  /* Same teal band, same reasoning as .section--teal above. */
  --eyebrow-fg: var(--white);
  --link: var(--white);
  --link-hover: var(--white);
  --focus: var(--white);
  position: relative;
  overflow: hidden;
  padding-block: clamp(56px, 8vw, 100px);
  color: var(--white);
  background:
    radial-gradient(90% 70% at 88% 6%, rgba(var(--teal-bright-rgb), .08), transparent 62%),
    linear-gradient(135deg, var(--teal-deep) 0%, var(--teal) 55%, var(--teal-deep) 100%);
}
.donate-hero > .wrap { position: relative; z-index: 1; }
.donate-hero .h-display, .donate-hero .h-section { color: var(--white); }
.donate-hero .lede { margin-inline: auto; color: var(--white); }

.qr-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: 100%;
  max-width: 24rem;
  margin-inline: auto;
  padding: clamp(22px, 3vw, 32px);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-lg);
  text-align: center;
  color: var(--slate);
}
.qr-card__canvas {
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 15rem;
  aspect-ratio: 1;
  padding: 12px;
  border-radius: var(--r-md);
  background: var(--white);
  box-shadow: inset 0 0 0 1px var(--paper-edge);
}
/* max-* rather than width/height:100%. The canvas is a centred grid cell, so
   its height is indefinite and a percentage height silently resolves to auto:
   a portrait image then took its intrinsic ratio, grew past the box and sat
   on top of the buttons below it. Capping both axes contains anything, square
   or not. */
.qr-card__canvas canvas, .qr-card__canvas svg, .qr-card__canvas img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
}
/* Crisp modules for a code the site draws itself. A supplied card image is a
   photograph of printed artwork, and pixelated would only make it look rough. */
.qr-card__canvas canvas, .qr-card__canvas svg { image-rendering: pixelated; }
/* quiet state before a handle is pasted into config.js */
.qr-card__canvas:empty {
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(var(--teal-bright-rgb), .16), transparent 62%),
    linear-gradient(158deg, var(--paper) 0%, var(--paper-alt) 100%);
}
.qr-card__handle { font-size: 1.0625rem; font-weight: 700; letter-spacing: .02em; line-height: 1.4; color: var(--ink); overflow-wrap: anywhere; }
.qr-card .btn { width: 100%; }

.amount-tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
  gap: 12px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tier {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 64px;
  padding: 12px 14px;
  border: 1.5px solid var(--paper-edge);
  border-radius: var(--r-md);
  background: var(--white);
  color: var(--ink);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--speed) var(--ease), background-color var(--speed) var(--ease),
              box-shadow var(--speed) var(--ease), transform var(--speed) var(--ease);
}
.tier:hover { border-color: var(--teal); background: var(--tint-teal); transform: translateY(-2px); }
/* selection is carried by weight + ring + tint, not by colour alone */
.tier.is-selected, .tier[aria-pressed="true"] {
  border-color: var(--teal);
  background: var(--tint-teal-strong);
  color: var(--teal-deep);
  font-weight: 700;
  box-shadow: inset 0 0 0 2px var(--teal);
}
.tier__amount { font-family: var(--font-display); font-size: 1.375rem; font-weight: 700; line-height: 1.1; }
.tier__label { font-size: .75rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--slate); }
.tier.is-selected .tier__label { color: var(--teal-deep); }

.donate-hero .tier, .section--teal .tier { border-color: rgba(var(--white-rgb), .45); background: rgba(var(--white-rgb), .12); color: var(--white); }
.donate-hero .tier .tier__label, .section--teal .tier .tier__label { color: var(--white); }
.donate-hero .tier:hover, .section--teal .tier:hover { background: rgba(var(--white-rgb), .22); }
.donate-hero .tier.is-selected, .section--teal .tier.is-selected,
.donate-hero .tier[aria-pressed="true"], .section--teal .tier[aria-pressed="true"] {
  background: var(--white);
  color: var(--teal-deep);
  box-shadow: inset 0 0 0 2px var(--white);
}
.donate-hero .tier.is-selected .tier__label, .section--teal .tier.is-selected .tier__label { color: var(--teal-deep); }

.donate-alt {
  padding: clamp(22px, 3vw, 32px);
  border: 1px solid var(--paper-edge);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-sm);
}
.donate-alt > * + * { margin-top: 14px; }
.section--ink .donate-alt, .donate-hero .donate-alt {
  border-color: var(--hairline-dark);
  background: rgba(var(--white-rgb), .10);
  box-shadow: none;
  color: var(--white);
}
.donate-note { max-width: 52ch; font-size: .875rem; line-height: 1.7; color: var(--slate-soft); text-wrap: pretty; }
.center .donate-note { margin-inline: auto; }
/* --on-dark is 14.7:1 on ink but only 4.4:1 on teal, and this is 14px copy. */
.section--ink .donate-note, .footer .donate-note { color: var(--on-dark); }
.section--teal .donate-note, .donate-hero .donate-note { color: var(--white); }


/* =============================================================================
   12  FOOTER
   ============================================================================= */

.footer { background: var(--ink); color: var(--on-dark-soft); padding-block: clamp(48px, 6vw, 72px) clamp(24px, 3vw, 40px); }
.footer__inner { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.footer__cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 56px);
  padding-bottom: clamp(28px, 4vw, 48px);
  border-bottom: 1px solid var(--ink-line);
}
.footer__col > * + * { margin-top: 12px; }
.footer__col .h-sub, .footer__col h2, .footer__col h3 { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; color: var(--white); }
.footer__col ul { display: grid; gap: 0; }
.footer__col a { color: var(--on-dark-soft); font-size: .9375rem; text-decoration: none; }
/* A 15px word is a ~26px target. The list gap becomes padding inside the link
   instead, so each one is a full 44px tall without stretching the column. */
.footer__col li > a { display: inline-flex; align-items: center; min-height: 44px; padding-block: 4px; }
.footer__col a:hover { color: var(--white); text-decoration: underline; }
.footer__brand { display: inline-flex; align-items: center; gap: 12px; text-decoration: none; color: inherit; }
.footer__brand img { width: 40px; height: 40px; object-fit: contain; flex: 0 0 auto; }
.footer__note { max-width: 40ch; font-size: .9375rem; line-height: 1.7; color: var(--on-dark-soft); text-wrap: pretty; }
.footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px clamp(16px, 3vw, 40px);
  padding-top: clamp(20px, 2.6vw, 28px);
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--muted);
}
.footer__legal p { text-wrap: pretty; }
.footer__legal a { color: var(--muted); }
.footer__legal a:hover { color: var(--on-dark); }


/* --- phone held sideways --------------------------------------------------
   A landscape phone is ~390px tall. The hero's min-height (520px+) and its
   generous vertical padding are sized for a portrait screen, so sideways the
   "Donate in Ian's honor" button lands below the fold and the decorative
   corner pieces take a large bite out of what little height there is. Short
   AND landscape only: this must not touch a small portrait phone, where the
   full-height hero is exactly right. */
@media (max-height: 500px) and (orientation: landscape) {
  .hero {
    min-height: 0;
    padding-block: calc(var(--header-h) + 14px) 22px;
  }
  .hero__inner .h-display { margin-top: 8px; font-size: clamp(1.9rem, 7vw, 2.6rem); }
  .hero__inner .lede { margin-top: 8px; font-size: .9375rem; }
  .hero__actions { margin-top: 14px; gap: 10px; }
  .hero__actions .btn { min-height: 44px; padding: 11px 24px; font-size: .9375rem; }
  /* decoration yields to the call to action when there is no room for both */
  .hero__seal { display: none; }
  .page-hero { padding-block: calc(var(--header-h) + 18px) 24px; }
}


/* =============================================================================
   13  REVEAL — scroll animation
   -----------------------------------------------------------------------------
   site.js observes .reveal and adds .is-visible. Stagger siblings by setting
   --i on each (style="--i:1", "--i:2", …).

   The hidden state is gated on `html.js`, which site.js sets as its very first
   act. Nothing is ever hidden by a script that did not run: with scripting off
   .reveal is simply inert and every word is on the page. That also lets the
   old 3s failsafe animation go — it used to snap every un-scrolled element
   visible three seconds after load, quietly killing the effect on long pages.

   The transition lives on .is-visible rather than on .reveal so the class
   arriving mid-parse can only ever hide instantly, never fade content out.
   ============================================================================= */

.js .reveal {
  opacity: 0;
  transform: translateY(16px);
  will-change: opacity, transform;
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity var(--speed-slow) var(--ease), transform var(--speed-slow) var(--ease);
  transition-delay: calc(var(--i, 0) * 90ms);
  will-change: auto;
}


/* =============================================================================
   14  RESPONSIVE REFINEMENTS
   Breakpoints: 520 · 640 · 820 · 940 (nav) · 1200.  Written mobile-first.
   ============================================================================= */

@media (min-width: 520px) {
  .gallery { grid-auto-rows: clamp(150px, 24vw, 200px); }
}

@media (min-width: 640px) {
  .card-grid, .card-grid--3 { grid-template-columns: repeat(2, 1fr); }
  .amount-tiers { grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); }
  .form--inline .field__input { min-height: 52px; }
}

@media (min-width: 820px) {
  /* One inch in from each edge of the photo above. Held back until 820px
     because below that the inset would eat most of the line. */
  .prose--center { padding-inline: 1in; }
  .split { grid-template-columns: 1fr 1.15fr; }
  .split--reverse { grid-template-columns: 1.15fr 1fr; }
  .split--reverse .split__media { order: 2; }
  .gallery { grid-template-columns: repeat(4, 1fr); }
  .footer__cols { grid-template-columns: 1.4fr 1fr 1fr; }
}

@media (min-width: 940px) {
  .card-grid { grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
  .card-grid--3 { grid-template-columns: repeat(3, 1fr); }
}

/* Below 940px the nav collapses into an accessible disclosure panel.
   site.js owns aria-expanded, Escape-to-close and the focus trap.

   Every rule that hides the panel is gated on `html.js`, the class site.js adds
   the moment it runs. Only a script that is actually running is allowed to put
   the navigation off-screen; without one, the links below stay in the header as
   a plain wrapping row and all seven pages remain reachable. */
@media (max-width: 939.98px) {

  /* --- the unscripted shape: a wrapping row of links, always on screen ----- */
  html:not(.js) .site-header__inner,
  html:not(.js) .site-header > .wrap { flex-wrap: wrap; justify-content: center; row-gap: 4px; }
  html:not(.js) .nav__links { flex-wrap: wrap; justify-content: center; gap: 2px clamp(12px, 3.5vw, 22px); }
  html:not(.js) .nav__link.btn { padding-block: 9px; }
  /* that header is taller than the scripted one, so the hero art starts lower */
  html:not(.js) .hero { padding-block-start: calc(var(--header-h) + clamp(96px, 16vw, 150px)); }

  /* --- the scripted shape: the disclosure panel ---------------------------- */
  .js .nav__toggle { display: inline-flex; }

  .js .nav.is-open::before {             /* dim the page behind the panel */
    content: "";
    position: fixed;
    inset: 0;
    z-index: 1;
    background: var(--scrim);
    animation: fade-in var(--speed) var(--ease) both;
  }
  .js .nav__links {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: auto;
    z-index: 2;
    width: min(22rem, 86vw);
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    justify-content: flex-start;
    gap: 4px;
    padding: calc(var(--header-h) + 20px) clamp(20px, 6vw, 32px) 40px;
    background: var(--white);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform var(--speed) var(--ease), visibility 0s linear var(--speed);
  }
  .js .nav.is-open .nav__links {
    transform: translateX(0);
    visibility: visible;
    transition: transform var(--speed) var(--ease), visibility 0s linear 0s;
  }
  .js .nav__links li { display: block; }
  .js .nav__link {
    display: flex;
    width: 100%;
    padding: 14px 4px;
    border-bottom: 1px solid var(--hairline);
    font-size: 1.0625rem;
    color: var(--ink);
    text-shadow: none;
  }
  /* the panel is solid even under the overlay header */
  .js .site-header--overlay .nav__links { --nav-fg: var(--ink); }
  .js .site-header--overlay .nav__link:not(.btn) { color: var(--ink); text-shadow: none; }
  .js .site-header--overlay .nav__links :focus-visible { outline-color: var(--teal-deep); }

  /* Indicator moves to the left edge. Written as one `transform` rather than
     the individual `translate` property: that shorthand only landed in
     Chrome 104 / Safari 14.1, and where it is unsupported the declaration is
     dropped and the indicator loses both its offset and its centring. */
  .js .nav__link:not(.btn)::after {
    left: 0; right: auto; top: 50%; bottom: auto;
    width: 3px; height: 0;
    transform: translate(-12px, -50%);
    transition: height var(--speed) var(--ease);
  }
  .js .nav__link:not(.btn):hover::after { height: 22px; transform: translate(-12px, -50%); }
  .js .nav__link.is-active:not(.btn)::after,
  .js .nav__link[aria-current="page"]:not(.btn)::after { height: 26px; transform: translate(-12px, -50%); }
  .js .nav__link.btn { margin-top: 20px; padding-block: 15px; border-bottom: 0; font-size: 1rem; }

  /* The lang li matches the same `.nav__links li { display: block }` rule as
     every other item, which would stack EN and ES on separate lines. Put it
     back to a centred row, set off from the links above it. */
  .js .nav__lang {
    display: flex;
    justify-content: center;
    width: 100%;
    padding: 14px 4px 6px;
    margin-top: 8px;
    border-inline-start: 0;
    border-top: 1px solid var(--hairline);
  }
}

@media (min-width: 1200px) {
  .hero { min-height: clamp(600px, 80vh, 760px); }
}

/* coarse pointers: no hover lift, captions always legible */
@media (hover: none) {
  .btn:hover, a.card:hover, .tier:hover { transform: none; }
  .gallery__item:hover .photo__img { transform: none; }
  .gallery__item .photo__caption { opacity: 1; }

  /* There is no hover on a phone, so this band is permanent rather than
     summoned - and every tile carries one. Left at the desktop size it ate
     between a third and four fifths of the smaller tiles, burying the very
     photographs it describes. Two lines is the cap; the full text is still
     one tap away in the lightbox, which shows the whole caption. */
  .gallery__item .photo__caption {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    padding: 18px 10px 8px;
    font-size: .75rem;
    line-height: 1.35;
  }
}

@media (max-width: 400px) {
  .hero__actions .btn { width: 100%; }
  .btn { padding-inline: 22px; }
  .brand__word { font-size: .9375rem; }
}


/* =============================================================================
   REDUCED MOTION — every transition, animation and scroll effect off
   ============================================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  /* nothing moves, and nothing waits on a scroll event to become readable */
  .reveal { opacity: 1 !important; transform: none !important; animation: none !important; }
  .btn:hover, a.card:hover, .tier:hover,
  .gallery__item:hover .photo__img { transform: none; }
  .lightbox__prev, .lightbox__next,
  .lightbox__prev:hover, .lightbox__next:hover { transform: translateY(-50%); }
  .site-header--overlay.is-stuck { animation: none; }
}


/* =============================================================================
   PRINT — families print the story page. Give them a clean sheet.
   ============================================================================= */

@media print {
  @page { margin: 18mm 16mm; }

  html, body { background: var(--white) !important; color: var(--ink) !important; font-size: 11.5pt; line-height: 1.6; }

  .site-header, .nav, .nav__toggle, .skip-link, .lightbox, .footer__cols,
  .btn, .amount-tiers, .qr-card, .donate-alt, .form, .form-status,
  .hero__actions { display: none !important; }

  .hero, .page-hero, .section, .section--ink, .section--teal, .section--paper,
  .section--paper-alt, .donate-hero, .footer {
    background: var(--white) !important;
    color: var(--ink) !important;
    min-height: 0 !important;
    padding-block: 0 !important;
  }
  .hero { padding-block: 0 12mm !important; }
  .hero__media, .hero__scrim, .section--teal::after, .donate-hero::after { display: none !important; }
  .section { padding-block: 8mm !important; }

  .h-display, .h-section, .h-sub, .card__title, .footer__col h2 {
    color: var(--ink) !important;
    text-shadow: none !important;
    break-after: avoid;
    page-break-after: avoid;
  }
  .h-display { font-size: 26pt; }
  .h-section { font-size: 18pt; }
  .h-sub { font-size: 13pt; }
  .eyebrow { color: var(--slate) !important; font-size: 8.5pt; letter-spacing: .22em; }

  .lede, .prose, .card__text, .photo__caption {
    color: var(--ink) !important;
    max-width: none;
    text-shadow: none !important;
  }
  .prose { font-size: 11.5pt; }
  .pull-quote {
    color: var(--ink) !important;
    border-color: var(--slate) !important;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .photo, .card, .gallery__item, figure, blockquote, li { break-inside: avoid; page-break-inside: avoid; }
  .photo__img { box-shadow: none !important; max-height: 100mm; object-fit: contain; }
  .photo.is-empty, .photo.is-empty::before, .photo.is-empty::after, .photo__fallback { display: none !important; }
  .photo::after { display: none !important; }
  .photo--framed { outline: none !important; }

  .card { border: 1px solid var(--slate) !important; background: var(--white) !important; box-shadow: none !important; }
  .card__num { color: var(--slate) !important; }

  .split { display: block; }
  .split__media { padding: 0; margin-bottom: 6mm; }
  .gallery { display: block; }
  .gallery__item { height: auto; margin-bottom: 5mm; }
  .gallery__item .photo__caption {
    position: static;
    background: none !important;
    color: var(--ink) !important;
    opacity: 1;
    padding: 4px 0 0;
  }

  .reveal { opacity: 1 !important; transform: none !important; animation: none !important; }
  .footer { border-top: 1px solid var(--paper-edge); padding-top: 6mm !important; }
  .footer__legal, .footer__legal a { color: var(--slate) !important; font-size: 9pt; }
  a { color: var(--ink) !important; text-decoration: none; }
}
