/* ============================================================================
   Sobbr Life — public site ("The Everlight")
   Each page opens in its time of day (the dawn clock); you read in warm morning
   light on paper. Consumes tokens.css. Mobile-first; enhances up. Every motion
   has a reduced-motion / no-JS fallback (content is fully present without JS).
   ============================================================================ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--dawn-cream);
  color: var(--pub-ink-on-dawn);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--dawn-magenta); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--rose-pressed); }

/* focus — always visible, high-contrast, never removed */
:focus-visible { outline: 3px solid var(--dawn-rose); outline-offset: 3px; border-radius: 4px; }

.wrap { width: 100%; max-width: 1120px; margin: 0 auto; padding: 0 20px; }
.narrow { max-width: 720px; }

/* skip link */
.skip { position: absolute; left: -9999px; top: 0; background: var(--rose); color: #fff; padding: 12px 16px; z-index: 100; border-radius: 0 0 10px 0; }
.skip:focus { left: 0; }

/* -- type ------------------------------------------------------------------- */
/* Fraunces was set at wght 320–340 with opsz 110–144 and SOFT 0. That is a
   display setting: gorgeous on a big screen, genuinely hard to read on a phone,
   because a high optical size thins the hairlines exactly when you can least
   afford it.
   Three axes moved together, and the combination is the point:
     · wght  340 → 450   more ink
     · opsz  144 → 90    LOWER optical size draws sturdier strokes; the high
                         setting is what made it delicate in the first place
     · SOFT    0 → 40    rounds the terminals, so the extra weight reads warm
                         rather than sharp
   Weight alone would have made it heavier AND harder — SOFT is what keeps it
   from getting harsh. */
h1, h2, h3, .display { font-family: var(--font-display); font-weight: 450; line-height: var(--lh-tight); letter-spacing: -0.015em; margin: 0 0 0.4em; text-wrap: balance; font-variation-settings: "opsz" 90, "SOFT" 40; }
.display { font-weight: 450; letter-spacing: -0.018em; font-variation-settings: "opsz" 90, "SOFT" 40; }
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: 1.35rem; }
.italic { font-style: italic; font-weight: 400; font-variation-settings: "opsz" 72, "SOFT" 45; }
.eyebrow, .kicker { font-family: var(--font-mono); text-transform: uppercase; letter-spacing: var(--tracking-label); font-size: var(--fs-label); color: var(--pub-ink-on-dawn-soft); }
.lede { font-size: var(--fs-lead); color: var(--pub-ink-on-dawn-soft); max-width: 60ch; }
p { max-width: 64ch; }

/* -- header / nav ----------------------------------------------------------- */
.site-header { position: absolute; top: 0; left: 0; right: 0; z-index: 30; }
.site-header .wrap { display: flex; align-items: center; gap: 18px; padding-top: 18px; padding-bottom: 18px; }
.brand { display: inline-flex; align-items: center; gap: 11px; text-decoration: none; color: inherit; min-height: 44px; }
.brand svg { width: 34px; height: 34px; }

/* -- the nav mark (the heart of Lyla's badge) -------------------------------
   Her artwork sits on its own pale ground, which is how the badge is drawn, so
   it needs a dark ground behind it to read. It gets one on every page — see the
   two-state header rule below. One ring, and on a dark ground it is a courtesy
   rather than the only thing holding the disc together. */
.brand-mark { display: block; flex: none; line-height: 0; }
.brand-mark img { display: block; width: 38px; height: 38px; border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(255,255,255,.34), 0 2px 8px rgba(0,12,20,.34); }
/* 38px is the size Lyla approved, and a 390px-wide phone has room for it —
   the brand block is only 148px of a 390px bar. Only the genuinely narrow
   handsets (SE-class, 375 and under) step down. */
@media (max-width: 360px) { .brand-mark img { width: 34px; height: 34px; } }
.brand .wm { font-family: var(--font-display); font-size: 1.35rem; font-weight: 460; letter-spacing: -0.01em; }
.nav { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.nav a { font-family: var(--font-body); font-size: 0.98rem; text-decoration: none; padding: 9px 12px; border-radius: 9px; font-weight: 600; }
/* Donate is a filled pill with no border, sitting on a deep-teal ground. Its
   white label is fine (7.44:1), but the FILL is what marks it out as the primary
   action among five plain text links — and the fill's own boundary measured
   1.17–1.85:1 against the bar depending on where the gradient sits under it,
   against the 3:1 WCAG 1.4.11 asks of a control's boundary. That predates the
   solid-bar change; the bar just made it visible by putting the pill and the
   ground side by side.
   A hairline in the header's own light ink fixes it without touching the colour
   Lyla picked — the boundary is now carried by the ring, not the fill. */
.nav a.give { background: var(--rose); color: #fff; box-shadow: 0 0 0 1px rgba(255,255,255,.62); }
.nav a.give:hover { background: var(--rose-pressed); box-shadow: 0 0 0 1px rgba(255,255,255,.85); }
/* -- the header has two states, and they are not arbitrary --------------------
   DARK HERO  → the header stays transparent and the sunrise runs behind it.
                Making it solid there puts a hard seam across the sky and cuts
                the gradient in half; it was tried and it looks worse.
   LIGHT HERO → a solid deep-teal bar. Lyla saw this pairing in a mockup and
                said she liked "the cream with the dark", and she was right:
                the pale pages had a washed-out header where the brand had to
                fight the background instead of sitting on it.
   It also fixes a measured problem. Her nav mark sits on its own pale ground,
   so on cream it had nothing to separate against — 1.73:1 disc-edge contrast,
   against 8.69:1 on a dark ground. On a solid dark bar every page gets the
   8.69 figure, and the ring goes back to being a courtesy rather than the only
   thing holding the mark together. */
body:not(.hero-dark) .site-header {
  /* `relative`, NOT `static`. z-index has no effect on a statically positioned
     element, so `static` here silently discarded the `z-index: 30` above it and
     the hero section painted over the open mobile nav panel. On the five
     cream-hero pages - apply, contact, donate, volunteer, partners - the menu
     rendered UNDER the hero and elementFromPoint at a menu item returned
     SECTION.hero, so the taps went to the hero. Main navigation, unusable, on the
     page a woman uses to ask for a bed. `relative` with no offsets occupies the
     identical box, so the in-flow layout this rule exists for is unchanged; it
     just makes the element positioned so z-index applies. */
  position: relative;
  background: linear-gradient(160deg, var(--brand-navy), var(--brand-teal-deep) 72%, var(--brand-teal));
}
body:not(.hero-dark) .site-header .brand,
body:not(.hero-dark) .site-header .nav a:not(.give) { color: var(--pub-ink-on-night); }
body:not(.hero-dark) .site-header .nav a:not(.give):hover { color: #fff; }
body:not(.hero-dark) .site-header .nav-toggle { color: var(--pub-ink-on-night); }
/* the header is in the flow now, so the hero no longer reserves room for it */
body:not(.hero-dark) .hero { padding-top: clamp(34px, 6vh, 56px); }
/* The Donate pill is the deep teal action colour, which was right against a pale
   header and disappears against a deep teal one. On the solid bar it takes the
   brand's button-safe orange — the mark's own pairing, and 4.6:1 with white. */
body:not(.hero-dark) .site-header .nav a.give { background: var(--brand-orange-fill); }
body:not(.hero-dark) .site-header .nav a.give:hover { background: var(--brand-orange-ink); }

/* on dark hero, header text is light; JS/no-JS both fine (hero is dark by default) */
.hero-dark .site-header .brand, .hero-dark .site-header .nav a:not(.give) { color: var(--pub-ink-on-night); }
.hero-dark .site-header .nav a:not(.give):hover { color: #fff; }
.hero-dark .site-header .nav-toggle { color: var(--pub-ink-on-night); } /* was invisible: dark bars on a dark hero */
.nav-toggle { display: none; }

@media (max-width: 760px) {
  /* Explicit z-index on the panel itself, above the hero's z-index: 2 and its
     scrim, so this cannot break again if the header's positioning is retuned. */
  .nav { position: fixed; z-index: 50; inset: 0 0 0 auto; width: min(78vw, 320px); background: var(--dawn-plum);
         flex-direction: column; align-items: stretch; gap: 2px; padding: 84px 16px 24px; transform: translateX(100%);
         transition: transform var(--dur-move) var(--ease-out-soft); box-shadow: -20px 0 60px rgba(0,0,0,.4); }
  .nav a { color: var(--pub-ink-on-night) !important; font-size: 1.1rem; padding: 14px 14px; }
  .nav a.give { background: var(--rose); text-align: center; margin-top: 8px; }
  body.nav-open .nav { transform: translateX(0); }
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; margin-left: auto;
                width: var(--tap-min); height: var(--tap-min); border: 0; background: transparent; cursor: pointer; z-index: 40; }
  .nav-toggle span, .nav-toggle span::before, .nav-toggle span::after { content:""; display:block; width: 24px; height: 2px; background: currentColor; position: relative; transition: transform var(--dur-state); }
  .nav-toggle span::before { position: absolute; top: -7px; } .nav-toggle span::after { position: absolute; top: 7px; }
  body.nav-open .nav-toggle span { background: transparent; }
  body.nav-open .nav-toggle span::before { transform: translateY(7px) rotate(45deg); }
  body.nav-open .nav-toggle span::after { transform: translateY(-7px) rotate(-45deg); }
}

/* -- the dawn sky (hero background) ----------------------------------------- */
.hero { position: relative; overflow: hidden; padding: clamp(120px, 22vh, 200px) 0 clamp(56px, 9vh, 92px); isolation: isolate; }
.hero > .wrap { position: relative; z-index: 2; }
.hero canvas.sky-canvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.hero .scrim { position: absolute; inset: 0; z-index: 1; background: var(--pub-scrim); }
/* dawn-clock skies, per page's place in the sunrise */
.sky-night    { background: linear-gradient(180deg, var(--dawn-night) 0%, var(--dawn-indigo) 40%, var(--dawn-plum) 78%, var(--dawn-violet) 100%); }
.sky-predawn  { background: linear-gradient(180deg, var(--dawn-indigo) 0%, var(--dawn-plum) 34%, var(--dawn-violet) 66%, var(--dawn-magenta) 100%); }
.sky-breaking { background: linear-gradient(180deg, var(--dawn-plum) 0%, var(--dawn-magenta) 42%, var(--dawn-rose) 76%, var(--dawn-ember) 100%); }
/* a genuinely LIGHT morning sky (no dark top) so dark ink reads across the whole
   hero, header included — paired with hero-light on the "full morning" pages. */
.sky-morning  { background: linear-gradient(180deg, var(--dawn-coral) 0%, var(--dawn-gold) 38%, var(--dawn-amber) 72%, var(--dawn-peach) 100%); }
/* scoped to the hero SECTION so the body.hero-dark class (used only to light the
   header over a dark hero) never washes out the dark-on-cream sections below */
.hero.hero-dark { color: var(--pub-ink-on-night); }
.hero.hero-dark .eyebrow { color: var(--dawn-peach); opacity: .9; }
.hero.hero-dark h1, .hero.hero-dark .display { color: var(--dawn-cream); text-shadow: 0 1px 24px rgba(0,12,20,.5); }
.hero.hero-dark .lede { color: var(--pub-ink-on-night-soft); }
.hero.hero-light { color: var(--pub-ink-on-dawn); }
.hero.hero-light .eyebrow { color: var(--pub-ink-on-dawn); } /* dark ink for AA on the light sky */
.hero.hero-light .scrim { display: none; } /* the dark scrim would only hurt dark ink */
/* The soft ink is 3.9:1 against the sand band of the morning sky — under AA, and
   the lede is the sentence that tells someone what this page is for. On a light
   hero it uses the full-strength ink; the size already gives it the hierarchy
   that the lighter colour was there to provide. */
.hero.hero-light .lede { color: var(--pub-ink-on-dawn); }

/* -- buttons ---------------------------------------------------------------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: var(--tap-min);
       padding: 13px 22px; border-radius: var(--radius-btn); font-family: var(--font-body); font-weight: 700; font-size: 1rem;
       text-decoration: none; border: 1.5px solid transparent; cursor: pointer; transition: transform var(--dur-press) var(--ease-standard), background var(--dur-state), box-shadow var(--dur-state); }
.btn:active { transform: scale(.975); }
.btn-primary { background: var(--rose); color: #fff; }
.btn-primary:hover { background: var(--rose-pressed); color: #fff; box-shadow: var(--shadow-accent); }
.btn-light { background: var(--dawn-cream); color: var(--pub-ink-on-dawn); }
.btn-light:hover { background: #fff; color: var(--pub-ink-on-dawn); }
.btn-ghost { background: transparent; border-color: currentColor; color: inherit; }
.btn-lg { font-size: 1.08rem; padding: 16px 26px; }

/* -- split hero (Home) ------------------------------------------------------ */
/* The two doors are a matched pair and have to read as one. They used to hold
   four elements each (eyebrow, heading, button, note) and `justify-content:
   flex-end` was fine — bottom-aligned, everything lined up. Lyla cut them to one
   line and one button, which left the left door with three children and the
   right with two, and bottom-alignment then pushed the right-hand heading about
   130px lower than the left. Nothing aligned with anything.
   Fixed with a subgrid: .split owns three rows — heading, action, note — and
   each door spans all three, so the headings sit on one line and the buttons on
   another no matter how much text is in either. The right door simply leaves
   the note row empty.
   The @supports fallback below top-aligns instead, which gets the same result
   whenever the two headings run to the same number of lines. */
.split { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto auto;
  column-gap: 3px; row-gap: 0; border-radius: var(--radius-card); overflow: hidden; box-shadow: var(--shadow-card); margin-top: 28px; }
.door { padding: clamp(24px, 4vw, 40px); min-height: 260px; display: flex; flex-direction: column; justify-content: flex-start; gap: 14px; text-decoration: none; transition: filter var(--dur-state); }
@supports (grid-template-rows: subgrid) {
  .door { display: grid; grid-template-rows: subgrid; grid-row: span 3; align-content: start; row-gap: 14px; }
}
.door:hover { filter: brightness(1.04); }
.door-need { background: linear-gradient(155deg, var(--dawn-plum), var(--dawn-violet) 68%, var(--dawn-magenta)); color: var(--pub-ink-on-night); }
.door-help { background: linear-gradient(155deg, var(--dawn-ember), var(--dawn-gold) 55%, var(--dawn-amber)); color: var(--pub-ink-on-dawn); }
.door .kicker { color: inherit; opacity: .82; }
.door h2 { font-size: clamp(1.5rem, 3.6vw, 2.1rem); color: inherit; margin-bottom: 4px; }
.door .crisis-line { font-size: 0.92rem; opacity: .92; }
.door .crisis-line a { color: inherit; font-weight: 700; }
/* the .door-help override lives beside the dark-hero rule it has to beat —
   see the "light panel inside a dark hero" note further down */
/* Stacked on a phone, so there is no pairing to preserve — each door goes back
   to being its own flex column and sizes to its own content. */
@media (max-width: 620px) {
  .split { grid-template-columns: 1fr; grid-template-rows: none; }
  .door { min-height: 200px; display: flex; grid-row: auto; }
}

/* -- sections & cards (warm reading light on paper) ------------------------- */
.section { padding: clamp(48px, 8vh, 90px) 0; }
.section-tint { background: linear-gradient(180deg, #fff8ee, var(--dawn-cream)); }
.card { background: var(--db-surface); border: 1px solid var(--db-hairline); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: clamp(20px, 3vw, 30px); }
.grid { display: grid; gap: 18px; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 820px) { .grid-3 { grid-template-columns: 1fr; } .grid-2 { grid-template-columns: 1fr; } }

/* house cards */
/* Each house wears its own badge. The cards went LIGHT to make that work: the
   old dark gradient swallowed the pale skies and fine linework inside each mark.
   The house's own colour survives as the top rule and the name, which is what
   still tells the three apart at a glance — and it keeps the rose tier alive
   against the teal chrome without the two fighting. */
.house { position: relative; border-radius: var(--radius-card); background: #fff;
  color: var(--pub-ink-on-dawn); border: 1px solid rgba(0,48,74,.10);
  border-top: 4px solid var(--house-c);
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: 22px 22px 26px; box-shadow: var(--shadow-card); }
.house.starfish  { --house-c: var(--house-starfish); }
.house.everlight { --house-c: var(--house-everlight); }
.house.phoenix   { --house-c: var(--house-phoenix); }
.house-mark { display: block; width: min(240px, 66%); margin: 4px auto 12px; }
.house-mark img { width: 100%; height: auto; display: block; }
.house .kicker { color: var(--pub-ink-on-dawn-soft); }
.house h3 { color: var(--house-c); font-size: 1.5rem; margin-top: 2px; }
.house p { color: var(--pub-ink-on-dawn-soft); font-size: 0.98rem; margin-top: 6px; }
.badge-new { position: absolute; top: 14px; right: 14px; background: var(--dawn-gold); color: #5a2d12; font-family: var(--font-mono); font-size: 0.64rem; letter-spacing: .12em; text-transform: uppercase; padding: 5px 10px; border-radius: 999px; font-weight: 700; }

/* stat row */
.stats { display: flex; flex-wrap: wrap; gap: 14px; }
.stat { flex: 1 1 150px; }
.stat .n { font-family: var(--font-display); font-weight: 460; font-size: clamp(2rem, 5vw, 2.8rem); font-variation-settings: "opsz" 120; }
.stat .l { color: var(--pub-ink-on-dawn-soft); font-size: 0.95rem; }

/* partner grid */
.partners { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; }
.partner { background: #fff; border: 1px solid var(--db-hairline); border-radius: 14px; padding: 20px; text-align: center; color: var(--pub-ink-on-dawn-soft); font-weight: 600; font-size: 0.95rem; min-height: 84px; display: flex; align-items: center; justify-content: center; }

/* -- butterfly divider ------------------------------------------------------ */
.bfly-divider { display: flex; align-items: center; gap: 18px; color: #e4d6c6; margin: 8px 0; }
.bfly-divider::before, .bfly-divider::after { content: ""; height: 1px; flex: 1; background: currentColor; }
.bfly-divider svg { width: 26px; height: 26px; color: var(--rose); opacity: .8; }

/* -- forms (apply / contact / volunteer) ------------------------------------ */
.field { margin-bottom: 18px; }
.field label { display: block; font-weight: 700; margin-bottom: 6px; font-size: 1rem; }
.field .hint { color: var(--pub-ink-on-dawn-soft); font-size: 0.9rem; margin: 2px 0 8px; }
.field input, .field select, .field textarea { width: 100%; min-height: var(--tap-min); padding: 12px 14px; font: inherit;
  border: 1.5px solid #d9cdbe; border-radius: var(--radius-input); background: #fff; color: var(--pub-ink-on-dawn); }
.field textarea { min-height: 120px; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--rose); outline: none; box-shadow: var(--focus-ring); }
fieldset { border: 0; padding: 0; margin: 0 0 8px; }
.form-status { margin-top: 14px; padding: 12px 14px; border-radius: 12px; background: var(--rose-wash); color: var(--pub-ink-on-dawn); font-weight: 600; }
/* A missing field is not an error the person made — it's information. Amber,
   not red, and never colour alone: the wording carries the meaning. */
.form-status-error { background: var(--attn-wash); color: var(--attn-ink); }

/* THE FORM THAT CANNOT SEND SAYS SO, AND KEYS OFF THE FORM RATHER THAN THE PAGE.
   site.js sets data-live on each form at the moment it attaches the submit
   handler, so this hides only where sending really works. Written the other way
   round on purpose: the block is VISIBLE in the shipped HTML and CSS takes it
   away, because the failure being guarded is site.js never arriving — and a rule
   that has to run to reveal something is no use when nothing is running. The
   button ships disabled for the same reason. */
.form-offline { margin-top: 14px; padding: 12px 14px; border-radius: 12px;
  background: var(--attn-wash); color: var(--attn-ink); line-height: 1.6; }
.form-offline a { color: inherit; }
form[data-live] .form-offline { display: none; }

/* -- the long intake form (apply) ------------------------------------------
   Lyla's initial application asks 48 drug options, 8 mental-health, 5 physical
   and a repeatable medication list. None of that can go inside `.field`: that
   rule stretches every descendant `input` to 100% width and 48px tall, which
   turns a checkbox into a full-width slab. So the multi-answer questions get
   their own block, and `.field` is used only where it was designed to be —
   around a single text control. */
.qblock { margin: 0 0 26px; }
.qblock > legend, .qblock > .qlabel { display: block; font-weight: 700; font-size: 1rem; margin-bottom: 6px; padding: 0; }
.qblock .hint { color: var(--pub-ink-on-dawn-soft); font-size: 0.9rem; margin: 2px 0 10px; }

.opt-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 2px 14px;
  border: 1.5px solid #d9cdbe; border-radius: var(--radius-input); background: #fff; padding: 6px; }
/* Only the 48-option list gets a scroll cap. The 5- and 8-option lists are
   shorter than the cap would be, and a scroll container around content that
   never scrolls is a scrollbar that lies. */
.opt-list-tall { max-height: 44vh; min-height: 240px; overflow-y: auto; overscroll-behavior: contain; }
.opt { display: flex; align-items: center; gap: 12px; min-height: var(--tap-min); padding: 4px 10px;
  border-radius: 10px; font-weight: 400; line-height: 1.35; cursor: pointer; }
/* `hidden` loses to `display:flex` on specificity alone, so the filter would
   set the attribute and nothing would move. This is what makes it work. */
.opt[hidden] { display: none; }
.opt:hover { background: var(--rose-wash); }
.opt input[type="checkbox"] { width: 22px; height: 22px; flex: 0 0 auto; margin: 0; accent-color: var(--rose); }
.opt:focus-within { background: var(--rose-wash); box-shadow: var(--focus-ring); }

.opt-filter-label { display: block; font-weight: 600; font-size: 0.92rem; margin-bottom: 6px; color: var(--pub-ink-on-dawn-soft); }
input.opt-filter { width: 100%; min-height: var(--tap-min); padding: 12px 14px; font: inherit;
  border: 1.5px solid #d9cdbe; border-radius: var(--radius-input); background: #fff; color: var(--pub-ink-on-dawn); }
input.opt-filter:focus { border-color: var(--rose); outline: none; box-shadow: var(--focus-ring); }
.opt-count { color: var(--pub-ink-on-dawn-soft); font-size: 0.88rem; margin: 8px 0; }

.med-row { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 0 14px; }
.med-row .field { margin-bottom: 12px; }
.med-row + .med-row { border-top: 1px dashed var(--db-hairline); padding-top: 14px; }
@media (max-width: 640px) { .med-row { grid-template-columns: 1fr; } }

/* A panel inside body copy: the privacy notice, and the Sobriety Hub route
   that still works while /api/apply does not. */
.notice { background: var(--rose-wash); border-radius: var(--radius-card); padding: 18px 20px; margin: 26px 0; }
.notice h3 { font-size: 1.12rem; margin: 0 0 8px; }
.notice p { margin: 0 0 10px; max-width: 62ch; }
.notice p:last-child { margin-bottom: 0; }
/* The crisis numbers, repeated down a long form. Cream rather than white so it
   still reads as a panel on the white card the form sits on. */
.crisis-note { background: var(--dawn-cream); border: 1px solid #ecdcc7; border-radius: 14px;
  padding: 14px 16px; max-width: 60ch; margin: 0 0 22px; }

/* -- reveals (native, 0-KB; JS-gated so no-JS shows everything) -------------- */
.js .rv { opacity: 0; transform: translateY(16px); transition: opacity 640ms var(--ease-quart), transform 640ms var(--ease-expo); }
.js .rv.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .js .rv { opacity: 1 !important; transform: none !important; transition: none; } }

/* -- footer + crisis ------------------------------------------------------- */
.crisis-bar { background: var(--dawn-plum); color: var(--pub-ink-on-night); font-size: 0.92rem; }
.crisis-bar .wrap { display: flex; flex-wrap: wrap; gap: 8px 22px; padding: 8px 20px; align-items: center; justify-content: center; text-align: center; }
.crisis-bar strong { color: #fff; }
/* The crisis numbers were 27x19 and 24x17. My first fix made them inline-flex
   with min-height 44px — which works, and is wrong. WCAG 2.5.8 has an explicit
   INLINE exception: a target inside a sentence, sized by the line-height of the
   text around it, is exempt. Forcing a flex box into a sentence pushed the
   lines apart and put a visible gap before the comma in "988, day or night".
   So: back to normal inline flow, and the hit area is enlarged with a
   positioned pseudo-element instead — bigger to the finger, invisible to the
   layout. Note for anyone auditing this: getBoundingClientRect() on the anchor
   will report the small text box, not the real touch area. */
.crisis-bar a, .legal a, .crisis-line a { color: var(--dawn-peach); font-weight: 700; position: relative; }
.crisis-bar a::after, .legal a::after, .crisis-line a::after {
  /* Height, not insets. Symmetric insets sound right and aren't: the box they
     grow depends on the font size of the link, so one inset value cannot serve
     .crisis-line (19px text → 45px) and .legal (17px text → 43px) at once. An
     earlier -12px version claimed "≥44px" in a comment and actually delivered
     43.33. Pinning the height makes the guarantee true at any type size. */
  content: ""; position: absolute; left: -8px; right: -8px;
  top: 50%; transform: translateY(-50%); height: 44px;
}
/* The bottom padding carries the space reserved for the fixed quick-exit button
   (see the quick-exit block below). It lives HERE and not on <body>, because on
   <body> the reserved strip sits outside the footer and renders as a band of
   cream under the dark footer — a stray light bar across the foot of every
   page. Inside the footer, the same reservation is simply more footer. */
.site-footer { background: linear-gradient(180deg, var(--dawn-plum), var(--dawn-night)); color: var(--pub-ink-on-night);
  padding: 56px 0 calc(40px + 76px + env(safe-area-inset-bottom, 0px)); }
@media (min-width: 900px) { .site-footer { padding-bottom: calc(40px + 40px + env(safe-area-inset-bottom, 0px)); } }
.site-footer a { color: var(--dawn-peach); }
.site-footer .cols { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 30px; }
@media (max-width: 720px) { .site-footer .cols { grid-template-columns: 1fr; gap: 22px; } }
/* These are <h2> in the markup now — they were <h4>, which put an h1→h4 jump in
   the outline of every single page. They still LOOK like small mono eyebrows. */
.site-footer h2 { font-family: var(--font-mono); text-transform: uppercase; letter-spacing: .2em; font-size: .76rem; font-weight: 700; color: var(--dawn-gold); margin: 0 0 8px; }
.site-footer nav a { display: flex; align-items: center; min-height: 44px; padding: 2px 0; text-decoration: none; }
/* Lyla's email and phone, added 2026-07-29 — until now the only route to Sobbr
   Life was a form POSTing to an undeployed Worker, so a woman who couldn't use
   the form had nowhere to go. They are stacked one per line rather than run
   together in a sentence, so each gets the same honest 44px target as the nav
   links above instead of being a 17px word inside a comma list. */
.footer-contact { margin: 8px 0 0; display: flex; flex-direction: column; }
.footer-contact a { display: flex; align-items: center; min-height: 44px; padding: 2px 0;
  text-decoration: underline; text-underline-offset: 3px; word-break: break-word; }

/* Same idea on /contact, inside the needs card. Colour and underline already come
   from `.section a:not(.btn)`; this rule only buys the height. */
.reach-direct { margin: 0 0 14px; line-height: 1.5; }
.reach-direct a { display: inline-flex; align-items: center; min-height: 44px; word-break: break-word; }
/* was two inline #e6d8ea / #cbb9cf lavenders, hardcoded on all 13 pages */
.footer-blurb { color: var(--pub-ink-on-night-soft); }
.footer-counter { font-family: var(--font-display); }
.footer-counter .n { font-size: 1.6rem; font-weight: 500; color: var(--dawn-gold); font-variant-numeric: tabular-nums; }
.footer-mark { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.footer-mark svg { width: 30px; height: 30px; color: var(--dawn-rose); }
.footer-mark .wm { font-family: var(--font-display); font-size: 1.3rem; }
/* was #b9a9bd — a lavender left over from the plum palette, on every page */
.legal { color: var(--pub-ink-on-night-soft); font-size: 0.85rem; margin-top: 26px; }
/* Build credit. Deliberately the quietest thing in the footer — this is the
   nonprofit's page, not the builder's — but a real, tappable link, not 8px grey
   mouse type. 44px of height on the anchor so it clears the tap floor the rest
   of the site holds to. */
.footer-credit { margin-top: 18px; font-size: 0.8rem; color: var(--pub-ink-on-night-soft); opacity: .85; }
.footer-credit a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px;
  color: var(--dawn-peach); text-decoration: underline; text-underline-offset: 3px; }
.footer-credit a:hover, .footer-credit a:focus-visible { color: #fff; }

/* -- the reduce-motion toggle (satisfies WCAG 2.2.2; serves users who can't set an OS pref) */
/* Reduce motion is a comfort control, not an emergency one — it does not need to
   follow anyone down the page, and while it was fixed it sat on top of "Apply for
   a bed" on every screen. It lives in the footer now. */
.footer-util { margin-top: 18px; }
.motion-toggle { background: rgba(255,255,255,.10); color: var(--pub-ink-on-night);
  border: 1px solid rgba(255,255,255,.28); border-radius: 999px; padding: 10px 16px; min-height: 44px;
  font: 600 0.82rem var(--font-body); cursor: pointer; }
.motion-toggle:hover { background: var(--dawn-plum); }

/* -- quick-exit (safety) ---------------------------------------------------- */
/* Quick-exit STAYS fixed — it is a safety control and has to be one tap from
   anywhere. What it must not do is cover the page: hence the safe-area inset so
   it clears a phone's gesture bar, and the reserved space at the foot of the
   document below so no content can ever sit underneath it. */
.quick-exit { position: fixed; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 60;
  background: #b23a2e; color: #fff; border: 0; border-radius: 999px; padding: 11px 16px;
  font: 700 0.82rem var(--font-body); cursor: pointer; box-shadow: 0 4px 14px rgba(0,0,0,.3); min-height: 44px; }
/* The reserved strip moved into .site-footer's own bottom padding — on <body> it
   painted the cream page background below the dark footer. Pages that have no
   site footer (none today, but 404/offline are built from the same layout so
   this stays honest) fall back to reserving it here. */
body:not(:has(.site-footer)) { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
.quick-exit:hover { background: #9a3125; }

.spacer { height: 1px; }
.center { text-align: center; }
.mt-1{margin-top:8px}.mt-2{margin-top:16px}.mt-3{margin-top:24px}.mt-4{margin-top:36px}
.cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px; }

/* -- the seal ---------------------------------------------------------------
   Lyla's full badge, used large and rarely. The butterfly monogram stays the
   working mark (nav, dividers, canvas); this is the org identifying itself. */
.seal-block { display: flex; justify-content: center; margin: 0 0 clamp(20px, 4vh, 34px); }
.seal-block img { width: min(160px, 42vw); height: auto; display: block; }
.footer-seal { margin-bottom: 14px; }
.footer-seal img { width: 120px; height: auto; display: block; }

/* plain, readable lists for the advocacy pages — a person in distress reads
   short lines with a bolded first clause, not paragraphs */
.plain-list { list-style: none; padding: 0; margin: 18px 0 0; }
.plain-list li { padding: 12px 0; border-top: 1px solid rgba(0,48,74,.12); line-height: 1.6; }
.plain-list li:first-child { border-top: none; }

/* Links inside a dark hero must not fall back to the teal accent — on the navy
   sky that lands around 1.5:1 and the 988 number effectively disappears. This
   was live on the MADD hero, which is the worst possible place for it.

   SCOPE MATTERS. `.hero-dark` is set on <body> (layout.mjs), so an unscoped
   `.hero-dark a` rule paints EVERY link on the page near-white — including the
   ones sitting in the cream body sections below the fold. That shipped, and it
   made the Missouri Crime Victims' Compensation phone number, cvc@dps.mo.gov
   and the guidelines link on /advocacy/madd/ invisible at 1.02:1. On a page
   read by families in the week after a crash, with a two-year filing deadline
   attached to that phone number. Only ever scope this to the hero SECTION and
   to the dark ground elements that genuinely sit on night. */
.hero.hero-dark a:not(.btn),
.crisis-line a,
.site-footer a,
.crisis-bar a { text-decoration-color: rgba(255,255,255,.55); }
.hero.hero-dark a:not(.btn) { color: var(--pub-ink-on-night); }
.hero.hero-dark a:not(.btn):hover,
.hero.hero-dark a:not(.btn):focus-visible { color: #fff; }

/* A LIGHT PANEL INSIDE A DARK HERO.
   The rule above is right about the hero and wrong about one thing inside it:
   .door-help is a bright orange panel nested in the dark hero, so "everything
   in here sits on night" stops being true at its edge. Its /volunteer link came
   out near-white on orange — 1.64:1, invisible. Same shape as the bug that hid
   the MADD compensation contacts: a ground-based rule applied by ancestry
   instead of by actual ground.
   This override is deliberately parked HERE rather than up with the other .door
   rules. `:not(.btn)` contributes its argument's specificity, so the rule above
   is 0,3,1 — the same as a natural `.hero .door-help .crisis-line a`, which
   then loses on source order. Keeping the pair adjacent means the next person
   to touch either one can see both, instead of discovering the interaction by
   measuring a contrast failure. */
.hero.hero-dark .door-help a:not(.btn) {
  color: var(--brand-navy);
  text-decoration: underline; text-decoration-color: currentColor;
  text-decoration-thickness: 1.5px; text-underline-offset: 3px;
  /* 600, not the 700 that .door .crisis-line a sets. That 700 was written for
     "988" — a three-character token, where bold is exactly right and stays
     compact. Applied to a five-word phrase in the middle of a sentence it makes
     the link a heavy block: the eye lands on "Time, a skill or a ride" before
     "Can't give money right now?", which inverts the order the sentence is
     written in. The colour and the underline already say "link" unambiguously,
     so the weight can afford to come down. The left door keeps its 700. */
  font-weight: 600;
}
.hero.hero-dark .door-help a:not(.btn):hover,
.hero.hero-dark .door-help a:not(.btn):focus-visible { color: #000; }

/* Body-copy links on the cream ground. Teal, underlined, and thick enough to be
   obviously a link — several of these are a phone number or an email address
   that somebody needs to be able to find while upset.

   Scoped to .section ONLY. A first pass at this also matched `.wrap > p a`,
   which reached into the footer and painted the 988 link in .legal deep teal on
   a near-black ground: 1.8:1. Exactly the same class of mistake as the bug this
   whole rule exists to fix, two rules further down the file. Light grounds get
   dark links; dark grounds are handled above. Nothing gets a rule that spans
   both. */
.section a:not(.btn) {
  color: var(--brand-teal-deep);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.section a:not(.btn):hover, .section a:not(.btn):focus-visible { color: var(--brand-orange-ink); }
