/* ===========================================================================
   forluly.com
   ---------------------------------------------------------------------------
   Warm, hopeful, photograph-led. Terracotta and cream rather than the usual
   charity blue — it reads as personal instead of institutional, which is the
   point: people give to a person.

   Contents
     1. Tokens
     2. Reset & base
     3. Layout helpers
     4. Buttons
     5. Header & nav
     6. Hero
     7. Story
     8. Facts
     9. Timeline
    10. How to help
    11. Share kit
    12. Newsletter
    13. Footer
    14. Lightbox
    15. Toast
    16. Motion & reveal
    17. Print
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------ */
:root {
  /* Warm neutrals */
  --cream:        #fdf9f4;
  --cream-2:      #f7efe6;
  --sand:         #ede0d1;
  --clay:         #d9c3ac;

  /* Ink */
  --ink:          #2c2320;
  --ink-2:        #574a44;
  --ink-3:        #8a7a72;

  /* Accents */
  --terracotta:   #b3543f;
  --terracotta-d: #93412f;
  --terracotta-l: #d9836c;
  --amber:        #d99a4e;
  --sage:         #6f8f6a;

  /* Timeline tones */
  --tone-joy:     #d99a4e;
  --tone-hard:    #8a7a72;
  --tone-hope:    #6f8f6a;

  --white:        #ffffff;

  /* Type */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Fluid type — scales between 360px and 1200px viewports */
  /* Capped for a half-width column. The headline is three short sentences,
     so this size has to land hard without running the block past the fold
     on a phone. */
  --fs-hero:  clamp(2.15rem, 1.5rem + 2.6vw, 3.55rem);
  --fs-h2:    clamp(1.85rem, 1.4rem + 1.9vw, 2.9rem);
  --fs-h3:    clamp(1.15rem, 1.05rem + 0.45vw, 1.4rem);
  --fs-lead:  clamp(1.06rem, 1rem + 0.5vw, 1.3rem);
  --fs-body:  clamp(1rem, 0.97rem + 0.16vw, 1.09rem);
  --fs-small: 0.875rem;

  /* Space. Capped well below a full viewport-slice so adjacent sections
     don't stack into a large empty band on a wide desktop — each side of
     the padding meets the next, and 7.5rem × 2 was a lot of cream. */
  --sp-section: clamp(3.25rem, 2rem + 4vw, 4.75rem);
  --gutter:     clamp(1.15rem, 0.6rem + 2.2vw, 2.5rem);

  /* Shape */
  --r-sm: 8px;
  --r-md: 14px;
  --r-lg: 22px;
  --r-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(44, 35, 32, .06), 0 2px 8px rgba(44, 35, 32, .05);
  --shadow-md: 0 4px 12px rgba(44, 35, 32, .08), 0 12px 32px rgba(44, 35, 32, .08);
  --shadow-lg: 0 10px 30px rgba(44, 35, 32, .12), 0 30px 70px rgba(44, 35, 32, .12);

  --header-h: 68px;
}

/* ---------------------------------------------------------------------------
   2. RESET & BASE
   ------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Keeps anchored sections from hiding beneath the sticky header. */
  scroll-padding-top: calc(var(--header-h) + 12px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Set when the lightbox or mobile nav is open. */
body.is-locked { overflow: hidden; }

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

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

a { color: var(--terracotta); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--terracotta-d); }

:focus-visible {
  outline: 3px solid var(--terracotta);
  outline-offset: 3px;
  border-radius: 3px;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 50%; top: 0;
  transform: translate(-50%, -120%);
  z-index: 200;
  background: var(--ink); color: var(--cream);
  padding: .7rem 1.25rem; border-radius: 0 0 var(--r-sm) var(--r-sm);
  text-decoration: none; font-weight: 600;
  transition: transform .18s ease;
}
.skip-link:focus { transform: translate(-50%, 0); color: var(--cream); }

/* ---------------------------------------------------------------------------
   3. LAYOUT
   ------------------------------------------------------------------------ */
.wrap {
  width: 100%;
  max-width: 1140px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap-narrow { max-width: 720px; }

.section { padding-block: var(--sp-section); position: relative; }

/* --- Alternating section backgrounds ---
   These classes are applied by main.js to the sections that are actually
   VISIBLE, rather than being hardcoded per section or set with :nth-child.
   Sections can be switched off from data.js (facts, funds, who), and a
   positional rule would leave two identical bands touching whenever one of
   them was hidden — plus it drifted every time a section was added or moved.
   Deriving the rhythm from what's on screen means it can't fall out of sync. */
/* --band-bg is the same colour again as a custom property, so anything that
   has to fade into its own section — the story fold — can read it instead of
   hardcoding a swatch that goes wrong the moment the section order changes. */
.section.band-a { background: var(--cream);   --band-bg: var(--cream); }
.section.band-b { background: var(--cream-2); --band-bg: var(--cream-2); }

.section-title { font-size: var(--fs-h2); margin-bottom: .75rem; }
.section-title.center,
.section-intro.center { text-align: center; }

.section-intro {
  font-size: var(--fs-lead);
  color: var(--ink-2);
  max-width: 62ch;
  margin: 0 auto 3rem;
  text-wrap: pretty;
}
.center { text-align: center; }

/* ---------------------------------------------------------------------------
   4. BUTTONS
   ------------------------------------------------------------------------ */
.btn {
  --btn-bg: var(--terracotta);
  --btn-fg: var(--white);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .78rem 1.5rem;
  border: 1.5px solid transparent;
  border-radius: var(--r-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font: 600 0.97rem/1 var(--font-body);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: transform .16s ease, box-shadow .16s ease,
              background-color .16s ease, color .16s ease, border-color .16s ease;
}
.btn:hover  { transform: translateY(-2px); box-shadow: var(--shadow-md); color: var(--btn-fg); }
.btn:active { transform: translateY(0); }

.btn-primary { --btn-bg: var(--terracotta); --btn-fg: var(--white); }
.btn-primary:hover { --btn-bg: var(--terracotta-d); }

/* Secondary CTA on a light background: white pill, hairline border. */
.btn-soft {
  --btn-bg: var(--white);
  --btn-fg: var(--ink);
  border-color: var(--sand);
  box-shadow: var(--shadow-sm);
}
.btn-soft:hover { --btn-bg: var(--white); border-color: var(--clay); }

.btn-outline {
  --btn-bg: transparent;
  --btn-fg: var(--terracotta);
  border-color: var(--clay);
}
.btn-outline:hover { --btn-bg: var(--terracotta); --btn-fg: var(--white); border-color: var(--terracotta); }

.btn-lg { padding: 1rem 1.9rem; font-size: 1.02rem; }
.btn-sm { padding: .55rem 1.1rem; font-size: .875rem; }

.btn-icon {
  display: inline-grid;
  place-items: center;
  width: 17px; height: 17px;
  flex: none;
}
.btn-icon svg { width: 100%; height: 100%; }
/* Nudges the "read her story" arrow down on hover. */
.btn-icon-down { transition: transform .2s ease; }
.btn:hover .btn-icon-down { transform: translateY(2px); }

/* Applied by main.js when SITE.meta.gofundme is still null, so a donate
   button never links to a dead page before launch. */
.btn.is-pending { opacity: .55; cursor: not-allowed; pointer-events: none; }

/* ---------------------------------------------------------------------------
   5. HEADER & NAV
   ------------------------------------------------------------------------ */
/* The hero is light, so the header is dark-on-cream from the start. It only
   gains a border and shadow once you scroll, to separate it from content
   passing underneath. */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-h);
  z-index: 100;
  background: rgba(253, 249, 244, .82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: background-color .3s ease, box-shadow .3s ease, border-color .3s ease;
  border-bottom: 1px solid transparent;
}
.site-header.is-stuck {
  background: rgba(253, 249, 244, .95);
  border-bottom-color: var(--sand);
  box-shadow: var(--shadow-sm);
}

.header-inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--font-display);
  font-weight: 700; font-size: 1.2rem;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}
.brand-mark {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--terracotta);
  box-shadow: 0 0 0 4px rgba(179, 84, 63, .18);
  flex: none;
}

.header-tools {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.nav { display: flex; align-items: center; gap: 1.6rem; }
.nav a {
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 500; font-size: .94rem;
  transition: color .2s ease;
}
.nav a:hover { color: var(--terracotta); }
.nav-full { display: none; }

/* The two actions this page exists for. Share is the outline so Donate stays
   the louder of the pair; both read as buttons rather than another nav link. */
.nav-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.nav-actions .btn-outline {
  --btn-fg: var(--ink);
  border-color: var(--clay);
}
.nav-actions .btn-outline:hover {
  --btn-bg: var(--cream-2);
  --btn-fg: var(--ink);
  border-color: var(--terracotta);
}

/* The language toggle. Quieter than Share and Donate on purpose — it's a
   utility, not an ask — but it has to stay visible on a phone, because the
   Spanish-speaking reader it serves can't find it inside an English menu. */
.lang-toggle {
  display: inline-flex; align-items: center;
  padding: .45rem .7rem;
  font-size: .82rem; font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 999px;
  transition: color .2s ease, border-color .2s ease;
}
.lang-toggle:hover {
  color: var(--terracotta);
  border-color: var(--clay);
}

@media (max-width: 420px) {
  .lang-toggle { padding: .45rem .4rem; font-size: .78rem; }
}

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: none; border: 0; cursor: pointer; padding: 0;
}
.nav-toggle span {
  display: block; width: 22px; height: 2px; border-radius: 2px;
  background: var(--ink);
  transition: transform .28s ease, opacity .2s ease;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 820px) {
  .nav-toggle { display: flex; }
  .header-tools { gap: .45rem; }
  .nav {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 1rem var(--gutter) 1.75rem;
    background: var(--cream);
    border-bottom: 1px solid var(--sand);
    box-shadow: var(--shadow-md);
    /* Hidden by clip rather than display:none so it can animate. */
    transform: translateY(-12px);
    opacity: 0;
    visibility: hidden;
    transition: transform .25s ease, opacity .25s ease, visibility .25s;
  }
  .nav.is-open { transform: translateY(0); opacity: 1; visibility: visible; }
  .nav a {
    color: var(--ink) !important;
    padding: .9rem .25rem;
    border-bottom: 1px solid var(--sand);
    font-size: 1.05rem;
  }
  .nav-short { display: none; }
  .nav-full { display: inline; }
}

@media (max-width: 420px) {
  .nav-actions .btn-sm { padding: .5rem .8rem; font-size: .82rem; }
}

/* ---------------------------------------------------------------------------
   6. HERO
   ------------------------------------------------------------------------ */
/* Split layout: words on the left, the photograph on the right shown whole.
   Deliberately NOT a background image — the photo is the most persuasive
   thing on the page and a scrim crops and darkens exactly the part that
   does the work (her face, her daughter). */
.hero {
  position: relative;
  background: var(--cream);
  padding-top: calc(var(--header-h) + clamp(1.5rem, 0.5rem + 4vw, 4rem));
  padding-bottom: clamp(3rem, 1.5rem + 6vw, 6rem);
  overflow: hidden;
}

/* Soft warm wash behind the photo side, so the right half doesn't read as
   empty space on wide screens. */
.hero::before {
  content: "";
  position: absolute;
  top: -18%; right: -12%;
  width: 62%; aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(217,154,78,.16) 0%, rgba(217,154,78,0) 68%);
  pointer-events: none;
}

.hero-inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
  align-items: center;
  gap: clamp(2rem, 1rem + 4vw, 4.5rem);
}

.hero-copy { min-width: 0; }

/* --- Badge pill --- */
.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .45rem 1rem .45rem .8rem;
  margin-bottom: 1.5rem;
  border-radius: var(--r-pill);
  background: rgba(111, 143, 106, .13);
  color: #4f6b4b;
  font-size: .875rem;
  font-weight: 500;
}
.hero-badge-icon {
  display: inline-grid;
  place-items: center;
  width: 15px; height: 15px;
  color: var(--sage);
  flex: none;
}
.hero-badge-icon svg { width: 100%; height: 100%; }
.hero-badge[hidden] { display: none; }

.hero-title {
  font-size: var(--fs-hero);
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 1.35rem;
  letter-spacing: -0.03em;
}

/* The turn. Italic display type in terracotta, set apart from the headline
   above and the paragraph below — a different voice rather than a different
   typeface, which keeps it from reading as a charity slogan (and costs no
   extra font download). The short rule gives it the feel of a hand-written
   line added underneath. */
.hero-kicker {
  position: relative;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.35rem, 1.05rem + 1.1vw, 1.85rem);
  line-height: 1.3;
  color: var(--terracotta);
  margin-bottom: 1.5rem;
  padding-top: 1.15rem;
}
.hero-kicker[hidden] { display: none; }
.hero-kicker::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 48px; height: 2px;
  border-radius: 2px;
  background: var(--terracotta-l);
}

.hero-sub {
  font-size: var(--fs-lead);
  color: var(--ink-2);
  max-width: 46ch;
  line-height: 1.72;
  margin-bottom: 2.25rem;
  text-wrap: pretty;
}

.hero-actions { display: flex; flex-wrap: wrap; gap: .8rem; }

/* Names who is asking, directly under the buttons. Sized and coloured to read
   as a credential rather than a second pitch — it has to be findable by
   someone looking for it without competing with the headline above it. */
.hero-byline {
  margin: 1.1rem 0 0;
  font-size: .88rem;
  line-height: 1.5;
  color: var(--ink-3);
  max-width: 46ch;
}
.hero-byline[hidden] { display: none; }
.hero-byline a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--clay);
  transition: color .2s ease, border-color .2s ease;
}
.hero-byline a:hover { color: var(--terracotta); border-bottom-color: var(--terracotta); }

/* --- Photo --- */
.hero-figure {
  position: relative;
  margin: 0;
  justify-self: center;
  /* Must shrink to the image, not the grid cell. The stat card is positioned
     against this box, so a full-width figure would leave the card floating in
     dead space beside a narrower photo. */
  width: fit-content;
  max-width: 100%;
  /* No fixed aspect-ratio and no object-fit: cover — the image keeps its own
     proportions so nothing is cropped out of frame. */
  line-height: 0;
}
.hero-figure[hidden] { display: none; }

/* The stat card is positioned against this box rather than the whole figure.
   Without it the card would measure from the bottom of the thumbnail strip and
   float away from the photo it belongs to. */
.hero-figure-media {
  position: relative;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
}

/* The lead photo is a button so it opens the gallery. It ships disabled and
   .is-static, and only becomes interactive if data.js actually has a gallery
   to open — a photo that looks clickable and isn't would be worse than one
   that never invited the click. */
.hero-photo-btn {
  display: block;
  width: fit-content;
  max-width: 100%;
  padding: 0;
  border: 0;
  background: none;
  line-height: 0;
  cursor: zoom-in;
}
.hero-photo-btn.is-static { cursor: default; }
.hero-photo-btn:not(.is-static):hover img { transform: translateY(-3px); }

.hero-figure img {
  width: auto;
  max-width: 100%;
  max-height: min(74vh, 660px);
  border-radius: clamp(16px, 1.4vw, 26px);
  box-shadow: 0 18px 40px rgba(44, 35, 32, .13), 0 40px 90px rgba(44, 35, 32, .11);
  transition: transform .22s ease;
}

/* Caption for the photo — a short line, not a statistic. It used to be a
   big number hanging off the corner; the copy is a sentence now, so this
   is sized and aligned like a caption chip. */
.hero-stat {
  position: absolute;
  right: clamp(-10px, -0.8vw, 0px);
  bottom: clamp(-14px, -1vw, -8px);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .15rem;
  max-width: calc(100% - 1.5rem);
  background: var(--white);
  border-radius: 12px;
  padding: .65rem 1.05rem .7rem;
  box-shadow: var(--shadow-md);
  text-align: right;
  line-height: 1.25;
}
.hero-stat[hidden] { display: none; }
.hero-stat-value {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.05rem, 0.95rem + 0.4vw, 1.25rem);
  font-weight: 600;
  color: var(--ink);
}
.hero-stat-label {
  font-size: .8rem;
  color: var(--ink-2);
}

/* --- Photo strip ---------------------------------------------------------
   The rest of the family's photos, under the lead one. Left-aligned on
   desktop for a reason: the caption overhangs the bottom-RIGHT corner of the
   photo, so anything right-aligned here would sit directly beneath it. The
   top margin has to clear that overhang too.

   Deliberately small. These are a reward for someone who has already stopped
   scrolling — they must never compete with the headline. */
.hero-strip {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: .5rem;
  margin-top: 2rem;
}
.hero-strip[hidden] { display: none; }

.hero-thumb {
  width: 64px; height: 64px;
  padding: 0; border: 0;
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  background: var(--sand);
  opacity: .88;
  box-shadow: 0 4px 12px rgba(44, 35, 32, .10);
  transition: opacity .18s ease, transform .18s ease, box-shadow .18s ease;
}
.hero-thumb:hover,
.hero-thumb:focus-visible {
  opacity: 1;
  transform: translateY(-3px);
  box-shadow: 0 9px 20px rgba(44, 35, 32, .16);
}
.hero-thumb img { width: 100%; height: 100%; object-fit: cover; }

.hero-thumb-more {
  display: grid;
  place-items: center;
  background: var(--white);
  border: 1px dashed var(--clay);
  color: var(--ink-2);
  font: 600 .85rem/1 var(--font-body);
  opacity: 1;
}
.hero-thumb-more:hover { border-color: var(--terracotta); color: var(--terracotta); }

/* Stack below 900px. Photo leads — a face does more persuading than a
   headline, and on a phone it's the first thing in the viewport. */
@media (max-width: 900px) {
  .hero-inner {
    grid-template-columns: 1fr;
    gap: 2.5rem;
    text-align: center;
  }
  .hero-copy { order: 2; }
  .hero-figure { order: 1; }
  .hero-sub { margin-inline: auto; }
  .hero-actions { justify-content: center; }
  /* Centre the kicker's rule along with the text. */
  .hero-kicker::before { left: 50%; transform: translateX(-50%); }
  .hero-figure img { max-height: 52vh; }
  .hero-stat { bottom: -14px; }
  /* Caption stays right; the strip centres and needs clearance for the
     card's overhang. */
  .hero-strip { justify-content: center; margin-top: 2.1rem; }
  /* Sized so a full row of five still fits beside a 360px-wide photo without
     wrapping to a second line. */
  .hero-thumb { width: 52px; height: 52px; }
}

@media (max-width: 480px) {
  .hero-actions { flex-direction: column; align-items: stretch; }
  .hero-actions .btn { width: 100%; }
}

/* iPhone SE and similar. One more size down keeps five tiles on a single row
   instead of orphaning two of them onto a second line. */
@media (max-width: 380px) {
  .hero-strip { gap: .375rem; }
  .hero-thumb { width: 46px; height: 46px; }
}

/* ---------------------------------------------------------------------------
   7. STORY
   ------------------------------------------------------------------------ */

.prose { font-size: var(--fs-lead); color: var(--ink-2); text-wrap: pretty; }
.prose p { margin-bottom: 1.5em; }

/* Drop-cap on the opening paragraph — a small editorial signal that this is
   something to read rather than skim. */
.prose > p:first-of-type::first-letter {
  font-family: var(--font-display);
  font-size: 3.4em;
  font-weight: 700;
  float: left;
  line-height: .82;
  margin: .06em .1em 0 0;
  color: var(--terracotta);
}

/* The closing line of the story. By convention the last entry in
   story.paragraphs is a short closer, so it gets a little weight — keep it to
   one or two sentences or this will look odd. */
.prose > p:last-of-type {
  font-family: var(--font-display);
  font-size: 1.16em;
  line-height: 1.45;
  color: var(--ink);
  margin-top: 2rem;
}

/* --- The fold ---
   The story opens at one paragraph with the next one blurred beneath a
   button. See `story.fold` in data.js for why, and for the one thing to check
   before moving the cut.

   Note what these rules do NOT do: hide any paragraph with display:none. The
   paragraphs past the peek carry hidden="until-found", which works through
   content-visibility, and a display rule here would quietly disable
   find-in-page on the whole second half of the story. */
.prose.is-folded { position: relative; padding-bottom: 3.5rem; }

/* hidden="until-found" hides an element's contents, not its box. Left alone,
   each folded paragraph still contributes a paragraph gap, and the button
   ends up floating an inch below the text it is supposed to sit on. */
.prose.is-folded > p[hidden] { margin: 0; }

/* Clamped by line count rather than by height, so the tease is the same three
   lines deep at every size the fluid type scale can produce — and on a phone,
   where those three lines are much shorter, it stays a tease rather than
   becoming half the paragraph. */
.prose > p.is-peek {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
          line-clamp: 3;
  overflow: hidden;
  margin-bottom: 0;
  filter: blur(3.5px);
  opacity: .55;
  /* Blurred text isn't text. Without this a drag-select comes away carrying a
     paragraph the reader was never shown. */
  -webkit-user-select: none;
          user-select: none;
}

.story-fold {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  /* The gradient covers live text. It must not swallow clicks meant for it. */
  pointer-events: none;
}
.story-fold::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, transparent, var(--band-bg, var(--cream)) 66%);
}

.story-more {
  position: relative;
  pointer-events: auto;
}

/* --- The fold, without JavaScript ---
   On a prerendered page the fold arrives baked into the HTML, but expanding
   it is a script's job. If scripts never run — the `js` class on <html> is
   set by an inline script in the head, so its absence means exactly that —
   the button would be a dead control guarding blurred text. Undo the whole
   thing instead: show every paragraph, drop the blur, hide the veil. Scoped
   to html:not(.js) rather than <noscript> because it must also cover a
   script that was blocked or failed, not only one that was disabled. */
html:not(.js) .prose.is-folded { padding-bottom: 0; }
html:not(.js) .prose.is-folded > p[hidden] {
  display: block !important;
  content-visibility: visible !important;
  margin-bottom: 1.5em;
}
html:not(.js) .prose > p.is-peek {
  display: block;
  -webkit-line-clamp: unset;
          line-clamp: unset;
  overflow: visible;
  margin-bottom: 1.5em;
  filter: none;
  opacity: 1;
  -webkit-user-select: auto;
          user-select: auto;
}
html:not(.js) .story-fold { display: none; }

/* The page just got several screens longer under the reader's thumb. A short
   fade is the difference between that reading as an expansion and reading as
   a navigation. */
@media (prefers-reduced-motion: no-preference) {
  .prose > p.is-revealed { animation: story-reveal .45s ease both; }
}
@keyframes story-reveal {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.pullquote {
  margin: 3rem 0 0;
  padding: 2rem 0 0;
  border-top: 1px solid var(--sand);
  text-align: center;
}
.pullquote blockquote {
  margin: 0 0 .9rem;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 1.1rem + 1vw, 1.8rem);
  font-style: italic;
  line-height: 1.4;
  color: var(--ink);
  text-wrap: balance;
}
.pullquote blockquote::before { content: "\201C"; }
.pullquote blockquote::after  { content: "\201D"; }
.pullquote figcaption {
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ---------------------------------------------------------------------------
   8. FACTS
   ------------------------------------------------------------------------ */

/* --- What ALS takes: four icons where a sentence used to be ---
   The intro paragraph used to end "...taking away a person's ability to walk,
   talk, eat, and eventually breathe." Four icons carry that in a third of the
   height and a reader takes it in without reading. The row is always four
   across, including on a phone — stacking it would cost back everything the
   change saved, and four short words fit at 360px. */
.section-facts .section-intro { margin-bottom: 1.75rem; }

.facts-takes {
  max-width: 620px;
  margin: 0 auto 2.5rem;
  padding: 1.4rem 0 1.25rem;
  border-block: 1px solid var(--sand);
}
.facts-takes[hidden] { display: none; }

.takes-row {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: .5rem;
}
.takes-row li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .55rem;
  text-align: center;
}
/* Tinted with the terracotta rather than a cream, because this section lands
   on either cream band depending on which sections are switched on in
   data.js — a cream badge would disappear on one of them. */
.take-icon {
  width: 44px; height: 44px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(179, 84, 63, .09);
  color: var(--terracotta);
}
.take-icon svg { width: 22px; height: 22px; }
.take-label {
  font-size: .92rem;
  line-height: 1.2;
  color: var(--ink-2);
}
/* On its own line, in the display face. It is the sentence the section exists
   to deliver, and it was previously buried at the end of a definition. */
.takes-verdict {
  margin: 1.25rem 0 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--ink);
}
.takes-verdict[hidden] { display: none; }

/* --- The numbers ---
   These were white cards with padding, a shadow and an accent bar, and the
   four-across row alone ran to 246px on a desktop — mostly chrome around one
   number and one sentence. As icon-marked rows over a hairline they read the
   same and take well under half the height.

   Column counts are explicit rather than auto-fit: five items with one wide
   lead only ever sits tidily at one, two or four columns, and auto-fit kept
   finding three and orphaning a row. */
.facts-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.35rem 1.75rem;
  grid-template-columns: 1fr;
}
@media (min-width: 560px)  { .facts-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .facts-grid { grid-template-columns: repeat(4, 1fr); } }

/* Icon and figure share the first line; the sentence runs full width beneath
   it. Indenting the sentence under the figure instead would leave it about
   200px wide in a four-column row, which broke it into four ragged lines. */
.facts-grid li {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: .65rem;
  row-gap: .4rem;
  padding-top: .95rem;
  border-top: 1px solid var(--sand);
}

.fact-icon {
  grid-column: 1; grid-row: 1;
  width: 34px; height: 34px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(179, 84, 63, .09);
  color: var(--terracotta);
}
.fact-icon svg { width: 17px; height: 17px; }

.fact-value {
  grid-column: 2; grid-row: 1;
  font-family: var(--font-display);
  /* Smaller than the old card treatment: in a 253px column the previous
     2.45rem cap wrapped "Every 90 minutes" and crowded "$250,000". */
  font-size: clamp(1.5rem, 1.25rem + 1vw, 1.95rem);
  font-weight: 700;
  color: var(--terracotta);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.fact-label {
  grid-column: 1 / -1; grid-row: 2;
  font-size: .95rem;
  color: var(--ink-2);
  line-height: 1.55;
  text-wrap: pretty;
}

/* --- The lead stat (item marked `wide: true` in data.js) ---
   Spans the full row so the remaining four sit on one clean line beneath it,
   and so the headline figure reads as a statement rather than one row of
   five. Below 560px there is only one column, so it stacks like the rest. */
.facts-grid li.is-wide {
  grid-column: 1 / -1;
  border-top-color: var(--terracotta);
  border-top-width: 2px;
}
@media (min-width: 560px) {
  .facts-grid li.is-wide {
    grid-template-columns: auto auto 1fr;
    column-gap: 1rem;
  }
  .facts-grid li.is-wide .fact-value { white-space: nowrap; }
  .facts-grid li.is-wide .fact-label {
    grid-column: 3; grid-row: 1;
    font-size: 1.02rem;
  }
}
/* Bolded clause inside a stat label. Darkened as well as weighted — at this
   size, weight alone against the muted label grey barely registers. */
.fact-label strong {
  font-weight: 700;
  color: var(--ink);
}

.facts-note {
  max-width: 60ch;
  margin: 2rem auto 0;
  padding: 1.15rem 1.4rem;
  background: rgba(179, 84, 63, .07);
  border-left: 3px solid var(--terracotta);
  border-radius: 0;
  font-size: .98rem;
  color: var(--ink-2);
  text-wrap: pretty;
}

.facts-source {
  margin-top: 1.75rem;
  text-align: center;
  font-size: var(--fs-small);
  color: var(--ink-3);
}
.facts-source a {
  color: var(--ink-3);
  text-decoration: underline;
  text-decoration-color: var(--clay);
}
.facts-source a:hover { color: var(--terracotta); text-decoration-color: currentColor; }

/* ---------------------------------------------------------------------------
   9. TIMELINE
   ------------------------------------------------------------------------ */

.timeline {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: 780px;
  position: relative;
}
/* The vertical rail. Sits behind the markers. */
.timeline::before {
  content: "";
  position: absolute;
  left: 15px; top: 8px; bottom: 8px;
  width: 2px;
  background: linear-gradient(to bottom, transparent, var(--clay) 6%, var(--clay) 94%, transparent);
}

/* Tighter than it was. Most entries are now text-only, and the old 3rem gap
   made a skimmable timeline feel like a long scroll. Entries with a photo
   strip get their spacing back via the strip's own margin. */
.tl-item {
  position: relative;
  padding-left: 3.25rem;
  padding-bottom: 2.35rem;
}
.tl-item:last-child { padding-bottom: 0; }

.tl-marker {
  position: absolute;
  left: 6px; top: 5px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--white);
  border: 3px solid var(--tone, var(--terracotta));
  box-shadow: 0 0 0 5px var(--cream);
  z-index: 1;
}
.tl-item[data-tone="joy"]  { --tone: var(--tone-joy); }
.tl-item[data-tone="hard"] { --tone: var(--tone-hard); }
.tl-item[data-tone="hope"] { --tone: var(--tone-hope); }

.tl-date {
  display: inline-block;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--tone, var(--terracotta));
  margin-bottom: .3rem;
}
.tl-title { font-size: var(--fs-h3); margin-bottom: .5rem; }
.tl-body  { color: var(--ink-2); margin-bottom: 0; text-wrap: pretty; }

/* --- The closing "Today" card ---
   Everything above it is a memory; this one is the present tense, and it is
   the last thing read before the ask. The marker is filled rather than hollow
   and the body takes the full ink colour, so a reader registers that the
   timeline has caught up to them before reading a word of it. */
.tl-today .tl-marker {
  background: var(--terracotta);
  border-color: var(--terracotta);
}
.tl-today .tl-body { color: var(--ink); }

.tl-link {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  margin-top: .6rem;
  font-size: .9rem;
  font-weight: 500;
  color: var(--terracotta);
  text-decoration: none;
  border-bottom: 1px solid var(--clay);
  padding-bottom: 1px;
  transition: border-color .18s ease;
}
.tl-link::after { content: "↗"; font-size: .82em; }
.tl-link:hover { border-bottom-color: var(--terracotta); }

/* --- Thumbnail strip ---
   Horizontally scrollable on small screens with snap points; wraps to a grid
   once there's room. */
.tl-photos {
  display: flex;
  gap: .6rem;
  margin-top: 1.1rem;
  overflow-x: auto;
  padding-bottom: .5rem;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  scrollbar-color: var(--clay) transparent;
  /* Fades the right edge to hint that there's more to scroll. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent 100%);
          mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent 100%);
}
.tl-photos.is-complete {
  -webkit-mask-image: none;
          mask-image: none;
  flex-wrap: wrap;
  overflow-x: visible;
}
.tl-photos::-webkit-scrollbar { height: 6px; }
.tl-photos::-webkit-scrollbar-thumb { background: var(--clay); border-radius: 3px; }
.tl-photos::-webkit-scrollbar-track { background: transparent; }

.tl-thumb {
  flex: none;
  width: 108px; height: 108px;
  padding: 0; border: 0;
  border-radius: var(--r-sm);
  overflow: hidden;
  cursor: pointer;
  background: var(--sand);
  scroll-snap-align: start;
  position: relative;
  box-shadow: var(--shadow-sm);
  transition: transform .18s ease, box-shadow .18s ease;
}
.tl-thumb:hover { transform: translateY(-3px) scale(1.02); box-shadow: var(--shadow-md); }
.tl-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* "+12 more" tile at the end of a truncated strip. */
.tl-thumb.tl-more {
  display: grid; place-items: center;
  background: var(--cream-2);
  border: 1px dashed var(--clay);
  font: 600 .95rem/1.2 var(--font-body);
  color: var(--ink-2);
  text-align: center;
  padding: .5rem;
}

/* Play badge over video poster frames. */
.tl-thumb .play-badge,
.lb-thumb .play-badge {
  position: absolute;
  inset: 0;
  display: grid; place-items: center;
  background: rgba(28,20,18,.3);
  color: var(--white);
  font-size: 1.6rem;
  pointer-events: none;
}
.tl-thumb .play-badge::before { content: "\25B6"; text-shadow: 0 2px 8px rgba(0,0,0,.5); }

@media (min-width: 720px) {
  .tl-item { padding-left: 3.75rem; }
  .tl-thumb { width: 124px; height: 124px; }
}

/* ---------------------------------------------------------------------------
   9b. WHERE YOUR SUPPORT GOES
   ------------------------------------------------------------------------ */
.section-funds[hidden] { display: none; }

/* The van is the only card with real visual weight. The side-by-side
   amount slot is opt-in: without a figure the card is just a block, so a
   leftover flex-basis cannot stretch it on a phone. */
.fund-first {
  background: var(--white);
  border: 1px solid var(--sand);
  border-left: 4px solid var(--terracotta);
  border-radius: var(--r-lg);
  padding: clamp(1.15rem, 0.85rem + 1.2vw, 1.6rem);
  box-shadow: var(--shadow-sm);
  margin-bottom: 1.35rem;
}
.fund-first[hidden] { display: none; }
.fund-first-main { min-width: 0; }

.fund-first-title { font-size: var(--fs-h3); margin-bottom: .45rem; }
.fund-first-body  { color: var(--ink-2); font-size: .97rem; margin: 0; text-wrap: pretty; }

.fund-first-amount {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.5rem + 2.2vw, 3rem);
  font-weight: 700;
  color: var(--terracotta);
  letter-spacing: -0.02em;
  line-height: 1;
}
.fund-first-amount[hidden] { display: none; }

.fund-first:has(.fund-first-amount:not([hidden])) {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1rem, 0.5rem + 2vw, 2.5rem);
}
.fund-first:has(.fund-first-amount:not([hidden])) .fund-first-main {
  flex: 1 1 16rem;
}
.fund-first:has(.fund-first-amount:not([hidden])) .fund-first-amount {
  flex: none;
}

/* Inventory, not a card gallery. The van already has the only visual weight
   in this section; boxing the six supporting notes made people work through
   six chapters instead of scanning a list. */
.fund-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.15rem 2.75rem;
  grid-template-columns: repeat(2, 1fr);
}
.fund-item {
  padding: 0 0 0 .9rem;
  border-left: 2px solid var(--sand);
}
.fund-item h3 { font-size: .98rem; margin-bottom: .2rem; }
.fund-item p  { font-size: .9rem; color: var(--ink-2); margin: 0; text-wrap: pretty; }

@media (max-width: 640px) {
  .fund-grid { grid-template-columns: 1fr; gap: 1rem; }
}

/* Two columns so these notes span the same width as the grid above instead of
   sitting in a narrow centred column — which looked pinched and made the
   section taller than it needed to be. Splitting the width also keeps line
   lengths readable; a single full-width paragraph at 1140px would run to
   roughly 130 characters a line. */
.fund-notes {
  margin-top: 1.35rem;
  padding-top: 1.35rem;
  border-top: 1px solid var(--sand);
  display: grid;
  gap: clamp(1.1rem, 0.5rem + 2vw, 2.25rem);
  grid-template-columns: 1.05fr 1fr;
  align-items: start;
}

.fund-honesty {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.65;
  color: var(--ink-2);
  text-wrap: pretty;
}
.fund-honesty[hidden] { display: none; }

.fund-credit { font-size: var(--fs-small); color: var(--ink-3); text-wrap: pretty; }
.fund-credit[hidden] { display: none; }
.fund-credit p { margin: 0 0 .85rem; }
.fund-credit p:last-child { margin-bottom: 0; }
.fund-credit a { color: var(--ink-2); }
.fund-credit a:hover { color: var(--terracotta); }

@media (max-width: 760px) {
  .fund-notes { grid-template-columns: 1fr; gap: 1.5rem; }
}

/* Closing call to action. Deliberately plainer than the donate band in the
   section above — a second full-width coloured panel would read as nagging.
   This is just the button, where the reader now needs it. */
.fund-cta {
  margin-top: 1.75rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--sand);
  text-align: center;
}
.fund-cta[hidden] { display: none; }

.fund-cta-note {
  margin: 0 auto 1.15rem;
  max-width: 46ch;
  font-size: 1.02rem;
  color: var(--ink-2);
  text-wrap: pretty;
}
.fund-cta-note[hidden] { display: none; }

/* The pledge. Sage rather than terracotta on purpose — every other accent on
   this page is an ask, and this is the one statement that gives something
   back. A different colour stops it reading as another appeal. */
/* Full width, matching the grid above rather than sitting in a narrower
   centred column. It's short enough that long lines aren't a readability
   problem the way a full paragraph would be. */
.fund-pledge {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 1.35rem 0 0;
  padding: 1.1rem 1.35rem;
  background: rgba(111, 143, 106, .09);
  border: 1px solid rgba(111, 143, 106, .28);
  border-radius: var(--r-md);
  text-align: left;
}
.fund-pledge[hidden] { display: none; }

.fund-pledge-icon {
  display: inline-grid;
  place-items: center;
  width: 20px; height: 20px;
  flex: none;
  color: var(--sage);
}
.fund-pledge-icon svg { width: 100%; height: 100%; }

.fund-pledge p {
  margin: 0;
  font-size: .97rem;
  line-height: 1.6;
  color: #4a6446;
  text-wrap: pretty;
}
.fund-pledge a {
  color: #3d5539;
  text-decoration-color: rgba(111, 143, 106, .5);
}
.fund-pledge a:hover { color: var(--terracotta); text-decoration-color: currentColor; }

@media (max-width: 520px) {
  .fund-pledge { flex-direction: column; align-items: flex-start; gap: .7rem; }
}

@media (max-width: 620px) {
  .fund-first:has(.fund-first-amount:not([hidden])) {
    flex-direction: column;
    align-items: flex-start;
  }
  .fund-first:has(.fund-first-amount:not([hidden])) .fund-first-main {
    flex: none;
    width: 100%;
  }
}

/* ---------------------------------------------------------------------------
   10. HOW TO HELP
   ------------------------------------------------------------------------ */

.help-grid {
  display: grid;
  gap: 1.15rem;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
}

.help-card {
  background: var(--white);
  border: 1px solid var(--sand);
  border-radius: var(--r-lg);
  padding: 2rem 1.6rem;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-sm);
  transition: transform .2s ease, box-shadow .2s ease;
}
.help-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }

.help-icon {
  width: 46px; height: 46px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--cream-2);
  color: var(--terracotta);
  margin-bottom: 1.1rem;
}
.help-icon svg { width: 22px; height: 22px; }

.help-card h3 { font-size: var(--fs-h3); margin-bottom: .55rem; }
.help-card p  { color: var(--ink-2); font-size: .97rem; margin-bottom: 1.5rem; }
.help-card .btn { margin-top: auto; align-self: flex-start; }

.donate-band {
  margin-top: 2.5rem;
  background: linear-gradient(135deg, var(--terracotta) 0%, var(--terracotta-d) 100%);
  border-radius: var(--r-lg);
  padding: clamp(1.75rem, 1rem + 3vw, 3rem);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  box-shadow: var(--shadow-md);
}
.donate-band h3 { color: var(--white); font-size: clamp(1.4rem, 1.2rem + 1vw, 1.9rem); margin-bottom: .4rem; }
.donate-band p  { color: rgba(255,255,255,.9); margin: 0; max-width: 46ch; }
.donate-band .btn-primary {
  --btn-bg: var(--white);
  --btn-fg: var(--terracotta-d);
}
.donate-band .btn-primary:hover { --btn-bg: var(--cream); }

/* ---------------------------------------------------------------------------
   11. SHARE KIT
   ------------------------------------------------------------------------ */

.share-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .7rem;
  margin-bottom: 2.75rem;
}
.share-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .7rem 1.25rem;
  border: 1.5px solid var(--clay);
  border-radius: var(--r-pill);
  background: var(--white);
  color: var(--ink);
  font: 600 .9rem/1 var(--font-body);
  text-decoration: none;
  cursor: pointer;
  transition: transform .16s ease, box-shadow .16s ease,
              border-color .16s ease, background-color .16s ease;
}
.share-btn:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--terracotta);
  color: var(--ink);
}
.share-btn svg { width: 17px; height: 17px; flex: none; }

/* Phones: the long "Share on Facebook" pills wrap into a ragged stack and
   eat a surprising amount of the section. Shorten the labels (the lead
   stays in the DOM for the accessible name and for analytics.js, which
   matches on textContent), pin them to a two-column grid, and promote the
   OS share sheet — the path that actually works on a phone — to a full-
   width first row. Copy link books the bottom so the leftover cell isn't
   a half-empty last row. */
@media (max-width: 720px) {
  .share-buttons {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .5rem;
    margin-bottom: 2rem;
  }
  .share-btn {
    justify-content: center;
    width: 100%;
    padding: .7rem .65rem;
    border-radius: var(--r-md);
    font-size: .84rem;
    white-space: nowrap;
  }
  .share-btn-lead {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .share-btn-native,
  .share-btn-copy {
    grid-column: 1 / -1;
  }
  .share-btn-native { order: -1; }
}

.share-kit {
  display: grid;
  gap: 1.15rem;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.share-card {
  background: var(--white);
  border: 1px solid var(--sand);
  border-radius: var(--r-lg);
  padding: 1.6rem;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-sm);
}
.share-card header {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .75rem; margin-bottom: .9rem; flex-wrap: wrap;
}
.share-card h3 { font-size: 1.1rem; }
.share-card-tag {
  font-size: .72rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.share-copy {
  background: var(--cream-2);
  border-radius: var(--r-sm);
  padding: 1.1rem;
  font-size: .94rem;
  color: var(--ink-2);
  /* Preserves the newlines in the long-form share copy. */
  white-space: pre-wrap;
  margin-bottom: 1.15rem;
  flex: 1;
}
.share-card .btn { align-self: flex-start; }

/* The long post is several paragraphs; the other two cards are a few lines.
   Left alone, the grid row stretches every card to the tallest, so the short
   copy sits in a tall empty well. The long card opens clamped to the short
   cards' height — same row, same height — and a control on the copy itself
   expands it back to the full post. The fallback max-height is only for the
   first paint, before JS measures the neighbours; it is replaced with an
   exact pixel value so the three cards line up. */
.share-copy-well {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  margin-bottom: 1.15rem;
}
.share-copy-well .share-copy { margin-bottom: 0; }
.share-card.is-folded #shareLong {
  max-height: var(--share-copy-max, 8rem);
  overflow: hidden;
}
.share-more {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 1;
  padding: 2.1rem 1.1rem .7rem;
  border: 0;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: linear-gradient(to bottom, transparent, var(--cream-2) 58%);
  color: var(--terracotta);
  font: 600 .82rem/1 var(--font-body);
  letter-spacing: .01em;
  cursor: pointer;
  text-align: center;
}
.share-more:hover { color: var(--terracotta-d); }
.share-card:not(.is-folded) .share-more { display: none; }

.share-hashtags {
  margin-top: 1.75rem;
  text-align: center;
  font-size: .95rem;
  color: var(--ink-3);
}
.share-hashtags span { color: var(--terracotta); font-weight: 600; }

/* --- Printable flyer callout ---
   Same card shell as the outreach box below, but it must not read as a clone:
   two identical cards stacked back to back become one undifferentiated block
   and the eye skips both. The separation is structural rather than tonal —
   a short wide card led by a picture, against a tall two-column card led by a
   heading. (Tinting it was the first attempt and it failed: this section's
   background is already --cream-2, so a cream card dissolved into the page.) */
.flyer-cta {
  margin-top: 2.5rem;
  padding: clamp(1.5rem, 1rem + 2vw, 2.25rem);
  background: var(--white);
  border: 1px solid var(--sand);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(1.5rem, 0.75rem + 2.5vw, 2.75rem);
  align-items: center;
}
.flyer-cta[hidden] { display: none; }

.flyer-cta-heading { font-size: var(--fs-h3); margin-bottom: .6rem; }
.flyer-cta-body {
  color: var(--ink-2);
  font-size: .98rem;
  margin: 0 0 .55rem;
  text-wrap: pretty;
}
.flyer-cta-note {
  color: var(--ink-3);
  font-size: .85rem;
  margin: 0 0 1.15rem;
}
.flyer-cta-note[hidden] { display: none; }

/* The sheet itself. Sized by width so the A4 viewBox sets its own height —
   the paper proportion is most of what makes this read as a flyer. */
.flyer-thumb {
  display: block;
  width: clamp(124px, 8rem + 4vw, 176px);
  border-radius: 3px;
  background: var(--white);
  /* Hairline edge as well as the shadow: the card behind it is also white, and
     a shadow alone leaves the paper looking like it has no edge at all. */
  border: 1px solid var(--sand);
  box-shadow: var(--shadow-md);
  /* A degree and a half off square: enough to look like a sheet someone set
     down, not enough to look like a mistake. */
  transform: rotate(-1.5deg);
  transition: transform .18s ease, box-shadow .18s ease;
}
.flyer-thumb:hover {
  transform: rotate(-1.5deg) translateY(-3px) scale(1.02);
  box-shadow: var(--shadow-lg);
}
.flyer-thumb svg { display: block; width: 100%; height: auto; }

.ft-mark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  fill: var(--terracotta);
}
.ft-accent  { fill: var(--terracotta); }
.ft-head    { fill: var(--ink); }
.ft-text    { fill: var(--clay); }
.ft-photo   { fill: var(--sand); }
.ft-rule    { fill: var(--sand); }
.ft-qr      { fill: var(--ink); }
.ft-qr-void { fill: var(--white); }
.ft-cut {
  fill: none;
  stroke: var(--clay);
  stroke-width: 1;
  stroke-dasharray: 4 4;
}

@media (max-width: 720px) {
  /* The sheet centres, the prose does not: centring a paragraph this long
     gives every line a different starting point and costs real reading speed.
     Matches the outreach box below, which stays left-aligned too. */
  .flyer-cta {
    grid-template-columns: 1fr;
    justify-items: center;
    gap: 1.35rem;
  }
  .flyer-cta-main { width: 100%; }
  .flyer-cta-main .btn { width: 100%; }
}

/* --- Outreach --- */
.outreach {
  margin-top: 2.5rem;
  padding: clamp(1.5rem, 1rem + 2vw, 2.25rem);
  background: var(--white);
  border: 1px solid var(--sand);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  display: grid;
  /* Explicit areas so the button can sit under the text on desktop but AFTER
     the checklist on mobile — you want people to read the list and think of a
     name before they're asked to act. */
  grid-template-columns: 1.05fr 1fr;
  grid-template-areas:
    "main targets"
    "cta  targets";
  gap: clamp(1.25rem, 0.5rem + 2vw, 2rem) clamp(1.5rem, 0.75rem + 2.5vw, 3rem);
  align-items: start;
}
.outreach[hidden] { display: none; }

.outreach-main    { grid-area: main; }
.outreach-targets { grid-area: targets; }
.outreach-cta     { grid-area: cta; align-self: start; }

.outreach-heading { font-size: var(--fs-h3); margin-bottom: .6rem; }
.outreach-body {
  color: var(--ink-2);
  font-size: .98rem;
  margin: 0;
  text-wrap: pretty;
}

.outreach-targets {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .5rem;
}
.outreach-targets li {
  position: relative;
  padding-left: 1.5rem;
  font-size: .93rem;
  color: var(--ink-2);
  line-height: 1.45;
}
/* Small terracotta tick — reads as a checklist, which is the point: it invites
   the reader to run down it and match names to rows. */
.outreach-targets li::before {
  content: "";
  position: absolute;
  left: 0; top: .34em;
  width: 9px; height: 5px;
  border-left: 2px solid var(--terracotta);
  border-bottom: 2px solid var(--terracotta);
  transform: rotate(-45deg);
}

@media (max-width: 720px) {
  .outreach {
    grid-template-columns: 1fr;
    grid-template-areas: "main" "targets" "cta";
    gap: 1.35rem;
  }
  .outreach-cta .btn { width: 100%; }
}

/* ---------------------------------------------------------------------------
   12. NEWSLETTER
   ------------------------------------------------------------------------ */

/* The 62ch measure on .section-intro exists to keep long paragraphs readable.
   This one is a single short line, and the measure was breaking it after
   "only" — an awkward orphan under a full-width heading. Let it use the whole
   column, same as everything above it. */
.section-news {
  padding-block: clamp(2.5rem, 1.75rem + 3vw, 4.5rem);
}
.section-news .section-intro {
  max-width: none;
  margin-bottom: 1.5rem;
}

.news-form {
  display: flex;
  gap: .6rem;
  max-width: 470px;
  margin: 0 auto;
  flex-wrap: wrap;
}
.news-form input {
  flex: 1 1 220px;
  padding: .85rem 1.15rem;
  border: 1.5px solid var(--clay);
  border-radius: var(--r-pill);
  background: var(--white);
  font: 400 1rem/1.2 var(--font-body);
  color: var(--ink);
}
.news-form input::placeholder { color: var(--ink-3); }
.news-form input:focus { border-color: var(--terracotta); }
.news-form input[aria-invalid="true"] { border-color: #c0392b; }
.news-form .btn { flex: none; }

.news-status {
  margin-top: 1rem;
  min-height: 1.4em;
  font-size: var(--fs-small);
  color: var(--ink-2);
}
.news-status.is-error { color: #a5321f; }
.news-status.is-ok    { color: var(--sage); font-weight: 600; }

/* ---------------------------------------------------------------------------
   12b. WHO'S BEHIND THIS PAGE
   Deliberately quieter than every section above it. This is a signature at the
   bottom of a letter, not another appeal — if it competes with Luly's story
   it is doing harm.
   ------------------------------------------------------------------------ */
.section-who {
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem);
  border-top: 1px solid var(--sand);
}
.section-who[hidden] { display: none; }

.who-card {
  max-width: 720px;
  margin-inline: auto;
  display: flex;
  align-items: flex-start;
  gap: clamp(1.25rem, 0.5rem + 2.5vw, 2.25rem);
}

/* Wide, and NOT square-cropped. These are group shots with people at the far
   edges — a 1:1 centre crop lops off whoever is standing on the ends, which on
   this section is the entire point of the photo. */
.who-photo { margin: 0; flex: none; width: clamp(200px, 28vw, 300px); }
.who-photo[hidden] { display: none; }

.who-photo-btn {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: var(--r-md);
  overflow: hidden;
  line-height: 0;
  box-shadow: var(--shadow-sm);
  transition: transform .18s ease, box-shadow .18s ease;
}
.who-photo-btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.who-photo-btn img { width: 100%; height: auto; }

.who-caption {
  margin-top: .55rem;
  font-size: .82rem;
  color: var(--ink-3);
  line-height: 1.4;
}
.who-caption[hidden] { display: none; }

.who-strip {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-top: .6rem;
}
.who-strip[hidden] { display: none; }

.who-thumb {
  width: 46px; height: 46px;
  padding: 0; border: 0;
  border-radius: 6px;
  overflow: hidden;
  cursor: pointer;
  background: var(--sand);
  opacity: .8;
  transition: opacity .18s ease, transform .18s ease;
}
.who-thumb:hover { opacity: 1; transform: translateY(-2px); }
.who-thumb img { width: 100%; height: 100%; object-fit: cover; }

.who-thumb-more {
  display: grid;
  place-items: center;
  background: var(--cream-2);
  border: 1px dashed var(--clay);
  color: var(--ink-2);
  font: 600 .8rem/1 var(--font-body);
  opacity: 1;
}
.who-thumb-more:hover { border-color: var(--terracotta); color: var(--terracotta); }

.who-text { min-width: 0; }

.who-heading {
  font-size: 1.15rem;
  margin-bottom: .6rem;
}
.who-body {
  font-size: .98rem;
  color: var(--ink-2);
  margin-bottom: .75rem;
  text-wrap: pretty;
}
.who-signature {
  font-family: var(--font-display);
  font-size: 1rem;
  color: var(--ink);
  margin-bottom: .9rem;
}

@media (max-width: 560px) {
  .who-card { flex-direction: column; align-items: center; text-align: center; }
  .who-photo { width: min(100%, 340px); }
  .who-strip { justify-content: center; }
  .who-thumb { width: 52px; height: 52px; }
  }

/* ---------------------------------------------------------------------------
   13. FOOTER
   ------------------------------------------------------------------------ */
.site-footer {
  background: var(--ink);
  color: rgba(253,249,244,.72);
  padding-block: 3.5rem 2.5rem;
}
.footer-inner { text-align: center; }
.footer-note {
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: var(--cream);
  margin-bottom: 1.25rem;
}
.footer-links {
  display: flex; flex-wrap: wrap;
  justify-content: center; gap: 1.25rem;
  margin-bottom: 1.75rem;
}
.footer-links a {
  color: rgba(253,249,244,.8);
  text-decoration: none;
  font-size: .93rem;
}
.footer-links a:hover { color: var(--terracotta-l); }
/* The beneficiary statement. Boxed so it reads as a formal disclosure rather
   than blending into the footer chrome, and at a higher opacity than the rest
   of the footer text — at .55 this sat at roughly 4:1 against the dark
   background, which is under AA for body copy, and this is the one paragraph
   a cautious donor actually stops to read. */
.footer-transparency {
  max-width: 68ch;
  margin: 0 auto 1.75rem;
  padding: 1.1rem 1.4rem;
  border: 1px solid rgba(253,249,244,.16);
  border-radius: var(--r-md);
  font-size: var(--fs-small);
  line-height: 1.6;
  color: rgba(253,249,244,.78);
  text-align: left;
  text-wrap: pretty;
}
.footer-transparency[hidden] { display: none; }
.footer-copy { font-size: .82rem; color: rgba(253,249,244,.4); margin: 0; }

/* ---------------------------------------------------------------------------
   14. LIGHTBOX
   ------------------------------------------------------------------------ */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: rgba(20, 14, 12, .95);
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  opacity: 0;
  transition: opacity .22s ease;
}
.lightbox[hidden] { display: none; }
.lightbox.is-open { opacity: 1; }

.lb-stage {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.lb-media {
  display: grid;
  place-items: center;
  max-width: 100%;
  /* Leaves room for the caption row beneath. */
  max-height: calc(100vh - 11rem);
}
.lb-media img,
.lb-media video {
  max-width: 100%;
  max-height: calc(100vh - 11rem);
  width: auto; height: auto;
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-lg);
  object-fit: contain;
}

.lb-caption {
  color: rgba(255,255,255,.85);
  font-size: .92rem;
  text-align: center;
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center; gap: .75rem;
}
.lb-count {
  color: rgba(255,255,255,.5);
  font-variant-numeric: tabular-nums;
  font-size: .85rem;
}

.lb-close, .lb-nav {
  position: absolute;
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.2);
  color: var(--white);
  cursor: pointer;
  border-radius: 50%;
  display: grid; place-items: center;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background-color .16s ease, transform .16s ease;
  line-height: 1;
}
.lb-close:hover, .lb-nav:hover { background: rgba(255,255,255,.22); }

.lb-close {
  top: 1rem; right: 1rem;
  width: 46px; height: 46px;
  font-size: 1.9rem;
  padding-bottom: 4px;
}
.lb-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 52px; height: 52px;
  font-size: 2.1rem;
  padding-bottom: 5px;
}
.lb-nav:hover { transform: translateY(-50%) scale(1.06); }
.lb-prev { left: 1rem; }
.lb-next { right: 1rem; }
.lb-nav[disabled] { opacity: .25; pointer-events: none; }

@media (max-width: 620px) {
  .lb-nav   { width: 44px; height: 44px; font-size: 1.8rem; }
  .lb-prev  { left: .5rem; }
  .lb-next  { right: .5rem; }
  .lb-close { top: .5rem; right: .5rem; }
  .lb-media img, .lb-media video { max-height: calc(100vh - 13rem); }
}

/* ---------------------------------------------------------------------------
   15. TOAST
   ------------------------------------------------------------------------ */
.toast {
  position: fixed;
  left: 50%; bottom: 2rem;
  /* Offset by its own height *plus* the bottom inset, so an empty toast (which
     is only as tall as its padding) still clears the viewport edge instead of
     peeking out as a dark sliver. */
  transform: translate(-50%, calc(100% + 2rem));
  z-index: 400;
  background: var(--ink);
  color: var(--cream);
  padding: .8rem 1.4rem;
  border-radius: var(--r-pill);
  font-size: .92rem; font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transition: transform .3s cubic-bezier(.2,.8,.3,1), opacity .3s ease, visibility .3s;
  pointer-events: none;
  max-width: calc(100vw - 2rem);
  text-align: center;
}
.toast.is-visible { transform: translate(-50%, 0); opacity: 1; visibility: visible; }

/* ---------------------------------------------------------------------------
   16. MOTION & REVEAL
   ------------------------------------------------------------------------ */
/* The hidden starting state is scoped to html.js (set by an inline script in
   the head) so that a visitor without JavaScript — or a crawler rendering the
   prerendered HTML — sees every section rather than a page of opacity: 0. */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .65s ease, transform .65s cubic-bezier(.2,.8,.3,1);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* Honour the OS-level reduced-motion setting: disable transitions, animations,
   smooth scrolling, and the reveal offset entirely. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
  .btn:hover, .help-card:hover, .tl-thumb:hover, .share-btn:hover,
  .hero-thumb:hover, .hero-photo-btn:hover img { transform: none; }
  /* Keeps the resting tilt — it's decoration, not motion. */
  .flyer-thumb, .flyer-thumb:hover { transform: rotate(-1.5deg); }
}

/* ---------------------------------------------------------------------------
   17. PRINT
   Journalists print pages. Make it legible in black and white.
   ------------------------------------------------------------------------ */
@media print {
  .site-header, .nav-toggle, .lightbox, .toast,
  .share-buttons, .news-form, .hero-actions { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .hero { padding: 0 0 1.5rem; background: #fff; }
  .hero::before { display: none; }
  .hero-inner { grid-template-columns: 1fr 1fr; gap: 1.5rem; }
  .hero-figure img { max-height: 3.5in; box-shadow: none; }
  .hero-stat { display: none !important; }
  .hero-title, .hero-sub { color: #000; }
  .section { padding-block: 1.25rem; break-inside: avoid; }
  /* Print the timeline strip as it appears on screen — not the lightbox
     leftovers. The fade mask is a scroll hint; print engines often drop
     masked content entirely, so take it off for the sheet. */
  .tl-photos {
    -webkit-mask-image: none;
            mask-image: none;
  }
  .tl-item { break-inside: avoid; }
  .js .reveal { opacity: 1; transform: none; }
  /* Nobody can press a button on a sheet of paper. The story prints whole,
     however far the reader had opened it on screen. Both declarations are
     needed: hidden="until-found" hides through content-visibility, and falls
     back to display:none in browsers that don't implement it. */
  .story-fold { display: none !important; }
  .share-more { display: none !important; }
  .share-card.is-folded #shareLong {
    max-height: none !important;
    overflow: visible;
  }
  .prose.is-folded { padding-bottom: 0; }
  .prose > p.is-peek {
    display: block;
    filter: none;
    opacity: 1;
  }
  .prose > p[hidden] {
    display: block !important;
    content-visibility: visible !important;
  }
  /* A picture of a flyer, printed, is a joke at the reader's expense. The
     callout's text and its URL still print. */
  .flyer-thumb { display: none; }
  .flyer-cta { grid-template-columns: 1fr; box-shadow: none; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}
