/* ==========================================================================
   GraceInspired Ministries - shared stylesheet
   Design read: redesign (preserve) of a nonprofit advocacy site.
   Dials: DESIGN_VARIANCE 5 / MOTION_INTENSITY 4 / VISUAL_DENSITY 4

   LOCKS (audited before ship):
   - Accent lock ....... one accent, the logo's leaf green, flat fills only.
                         No glows, no gradients — the gradient belongs to the
                         leaf artwork and nowhere else.
   - Shape lock ........ documented rule: sections + cards = 0 radius,
                         interactive (buttons, inputs, tiles) = 4px.
   - Theme lock ........ light only. The palette below is the whole theme;
                         there is no prefers-color-scheme branch to keep in
                         sync. The footer's dark band is an inversion of the
                         light palette, not a second theme.
   - Type ............... Ubuntu, carried over from the brand audit.

   ACCENT (resolved): the interface used to run on neon lime #C6FF3D, locked
   before the logo existed. It now runs on the logo's leaf green. Because the
   accent went from light to dark, --accent-ink flipped from near-black to
   white, and two rules that assumed a light accent had to change with it:
   .call .btn (was background: var(--accent-ink), which would now be white on
   white) and .wcard h3 a:hover (dark label on a dark fill). If you ever move
   the accent back into the light half of the range, revisit both.
   ========================================================================== */

:root {
  color-scheme: light;

  /* accent (single, locked) — the leaf green off the logo.
     #597D32 is the leaf's darkest stop (#5D8235) taken about 2% darker, so
     white 15px bold button labels clear 4.5:1 (they land at 4.77:1). The
     shift is below the perceptual threshold; beside the artwork it reads as
     the same green. The literal stops are in the brand block below. */
  --accent:        #597D32;
  --accent-hover:  #46652A;   /* darker on hover: the ink is white */
  --accent-ink:    #FFFFFF;   /* text that sits on the accent */

  /* brand, read off the supplied logo system (02_Design/favicon-svg.zip).
     Reference values — the leaf and wordmark carry their own fills, so
     nothing here is applied to the artwork. See the ACCENT CONFLICT note
     in the header block above before using them in the interface. */
  --brand-green-dark:  #5d8235;   /* leaf gradient, dark stop */
  --brand-green:       #78a343;   /* leaf gradient, mid stop — theme-color */
  --brand-green-light: #93bb55;   /* leaf gradient, light stop */
  --brand-green-word:  #5da24a;   /* the "Inspired" half of the wordmark */
  --brand-ink:         #1a1a1a;   /* the "Grace" half of the wordmark */
  --brand-teal:        #5ba7b4;   /* the Sola Gratia tagline and its rule */

  /* persecution scale: a monochrome ramp of the one accent */
  --lvl-extreme:   #46652A;
  --lvl-veryhigh:  #78A343;
  --lvl-high:      #C0D79B;
  --lvl-base:      #E4E7EA;
  --lvl-active:    #35501F;

  /* neutrals: cool grey family, locked */
  --bg:            #FFFFFF;
  --surface:       #F4F5F6;
  --surface-2:     #FFFFFF;
  --text:          #26292B;
  --text-muted:    #5B6165;
  --line:          #E1E4E6;
  --scrim:         18, 20, 21;

  --radius-ui:     4px;
  --font: 'Ubuntu', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  /* The giving terms, and nothing else. A serif is the convention for terms
     and agreements and it marks the modal as a document rather than more of
     the page. Deliberately a system stack: a second webfont would be a second
     CDN request on every one of the ten pages, and the terms are read by one
     person in a hundred. Nothing in the interface uses this — see .terms. */
  --font-formal: 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, Cambria, 'Times New Roman', Times, serif;
  --ease: cubic-bezier(.16, 1, .3, 1);
  --shell: 1220px;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; }
/* The header is sticky and ~80px tall once the logo lockup is in it, so
   in-page anchors need to clear it or they land underneath. */
html { scroll-behavior: smooth; scroll-padding-top: 96px; }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
/* The <symbol> sprite in base.html. It has width/height 0 attributes already;
   this takes it out of flow too, so it can never open the page with a stray
   blank line above the skip link. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Park a finished section that is waiting on real content, without deleting
   the markup. `display: none` rather than visibility or opacity, so it is out
   of the layout and out of the accessibility tree — a screen reader will not
   read a placeholder to anyone. Note this is a class, not the HTML `hidden`
   attribute; the attribute would be overridden by any display rule on the
   element, which is exactly what section components set. */
.hidden { display: none !important; }
h1, h2, h3 { line-height: 1.1; color: var(--text); }

.shell { max-width: var(--shell); margin: 0 auto; padding-inline: 32px; }
/* Anything that shares an element with .shell — and most section components
   do, e.g. class="shell bento reveal" — must set its vertical rhythm with
   `padding-block`, never the `padding` shorthand. The shorthand resets
   left/right to 0, and because these rules sit later in the file at the same
   specificity they beat .shell and the section loses its gutters entirely.
   That is not visible above 1220px, where the max-width leaves slack either
   side, which is why it survived this long. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--text); color: var(--bg); padding: 10px 16px;
}
.skip:focus { left: 8px; top: 8px; }
:where(a, button, select, [tabindex]):focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px;
}

/* ---------- motion layer (MOTION_INTENSITY 4: fluid CSS only) ----------
   Justification per element:
   - .reveal  : storytelling. Sections enter in reading order on first view.
   - :hover   : feedback on interactive surfaces.
   - :active  : tactile confirmation of a press.
   No scroll listeners anywhere. IntersectionObserver drives .reveal.       */
.reveal { opacity: 0; transform: translateY(18px); }
.reveal.in {
  opacity: 1; transform: none;
  transition: opacity .55s var(--ease), transform .55s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal.in { opacity: 1; transform: none; transition: none; }
  .person, .people.in .person { opacity: 1; transform: none; transition-delay: 0s; }
  .cat-grid--covers .item:hover .buy i,
  .cat-grid--covers .item:focus-visible .buy i { transform: none; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 10px; white-space: nowrap;
  padding: 16px 30px; border: none; border-radius: var(--radius-ui);
  font-family: var(--font); font-weight: 700; font-size: 15px;
  letter-spacing: .06em; text-transform: uppercase; text-decoration: none;
  background: var(--accent); color: var(--accent-ink); cursor: pointer;
  transition: background .2s var(--ease), transform .12s var(--ease);
}
.btn:hover { background: var(--accent-hover); }
.btn:active { transform: translateY(1px); }
.btn--line {
  background: transparent; color: var(--text);
  box-shadow: inset 0 0 0 2px var(--line);
}
.btn--line:hover { background: var(--surface); box-shadow: inset 0 0 0 2px var(--text); }
/* Outlined in the accent, and only ever used beside a filled .btn: the pair
   reads secondary + primary. The filled one is always the ask; this one is
   the "more information" half. Never use it on its own. */
.btn--outline {
  background: transparent; color: var(--text);
  box-shadow: inset 0 0 0 2px var(--accent);
  transition: background .2s var(--ease), color .2s var(--ease), transform .12s var(--ease);
}
.btn--outline:hover { background: var(--accent); color: var(--accent-ink); }
/* on photography: solid scrim so the label always clears WCAG AA */
.btn--onphoto { background: var(--accent); color: var(--accent-ink); }

.tlink {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 700; color: var(--text); text-decoration: none;
  border-bottom: 3px solid var(--accent); padding-bottom: 2px;
  transition: gap .2s var(--ease);
}
.tlink:hover { gap: 13px; }

/* ---------- header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 80;
  background: var(--bg); border-bottom: 1px solid var(--line);
}
.bar { display: flex; align-items: center; justify-content: space-between; padding-block: 11px; }
.brand { display: flex; align-items: center; text-decoration: none; }
/* The lockup is 1000x457 with the leaf stacked over the wordmark, so the
   wordmark is only about 28% of the height. 58px is the smallest the whole
   thing can run before "GraceInspired" stops being readable. */
.brand__logo { height: 58px; width: auto; flex: 0 0 auto; }
.nav-right { display: flex; align-items: center; gap: 30px; }
.primary-nav ul { display: flex; align-items: center; gap: 30px; list-style: none; margin: 0; padding: 0; }
.primary-nav a {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 16px; font-weight: 500; color: var(--text); text-decoration: none;
  padding: 4px 0; border-bottom: 2px solid transparent; transition: border-color .2s var(--ease);
}
.primary-nav a:hover { border-bottom-color: var(--accent); }
.primary-nav a[aria-current="page"] { border-bottom-color: var(--accent); }
.primary-nav i { font-size: 13px; color: var(--text-muted); }
.iconbtn {
  width: 48px; height: 48px; display: flex; align-items: center; justify-content: center;
  background: var(--bg); color: var(--text-muted); cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius-ui); font-size: 19px;
  transition: border-color .2s var(--ease), color .2s var(--ease);
}
.iconbtn:hover { border-color: var(--text); color: var(--text); }
.burger { display: none; background: none; border: none; color: var(--text); font-size: 26px; cursor: pointer; }
/* The panel is display:none here and only becomes displayable inside the
   860px query, so it can never appear on a desktop width even if .open is
   left on the element by a resize. */
.mobile-nav { display: none; }
.mobile-nav a {
  display: block; padding: 13px 0; color: var(--text);
  text-decoration: none; border-bottom: 1px solid var(--line); font-size: 17px;
}
/* Body scroll lock, set by site.js while the panel is open. overflow alone,
   deliberately: the position:fixed trick would shift the sticky header out of
   view and take the burger — the only way to close the panel — with it. The
   panel itself is the scroll container and contains its own overscroll, so
   nothing behind it moves. */
body.nav-open { overflow: hidden; }

/* ---------- hero: full-bleed photo, left-aligned type ---------- */
.hero { position: relative; min-height: 78dvh; display: flex; align-items: center; overflow: hidden; background: var(--surface); }
.hero__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 72% center; }
.hero__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    rgba(var(--scrim), .82) 0%, rgba(var(--scrim), .62) 34%,
    rgba(var(--scrim), .18) 62%, rgba(var(--scrim), .05) 100%);
}
.hero .shell { position: relative; z-index: 2; width: 100%; padding-top: 40px; padding-bottom: 40px; }
.hero h1 {
  font-weight: 700; text-transform: uppercase; color: #FFF;
  font-size: clamp(42px, 5.6vw, 70px); max-width: 15ch;
}
.hero p { margin: 20px 0 30px; max-width: 44ch; font-size: 19px; color: rgba(255,255,255,.94); }

/* Centred variant (/institute/). The default scrim is a left-to-right ramp
   sized for left-aligned type — it fades to almost nothing past 62%, so
   centred text would sit on bare photograph. This one darkens evenly and
   leans on the vertical instead, and the photo re-centres because the 72%
   offset only exists to keep the subject clear of type on the left. */
.hero--center .hero__img { object-position: center; }
.hero--center .hero__scrim {
  background: linear-gradient(180deg,
    rgba(var(--scrim), .34) 0%, rgba(var(--scrim), .58) 46%,
    rgba(var(--scrim), .68) 100%);
}
.hero--center .shell { text-align: center; }
/* Both measures are set from rendered line counts, not guessed. At the
   clamped 70px, "GraceLife Institute" is 753px on one line and needs 20ch to
   hold it — the .hero default of 15ch breaks it in two. The lead then runs to
   three lines anywhere between 62ch and 86ch, and drops to two at 90ch; 70ch
   sits mid-band and puts the lead at 747px, within a few pixels of the
   headline above it. Both scale with the type, so the counts hold as the
   clamp shrinks. Below 560px the headline takes two lines whatever we do —
   34px type will not fit 19 characters across a phone. */
.hero--center h1 { max-width: 24ch; }
.hero--center p { max-width: 70ch; }
.hero--center h1, .hero--center p { margin-inline: auto; }

/* ---------- per-page overrides (body carries .page-<name>) ---------- */
/* /institute/ only: a 10px gap above every band after the hero. Every child
   of <main> on that page is a <section>, so `section + section` is exactly
   "every section with one before it" — the hero is first and keeps its flush
   edge. Nothing here sets margin-bottom, so there is nothing to collapse
   against and the gap stays 10px rather than becoming 10-or-20 depending on
   the neighbour. */
.page-institute main > section + section { margin-top: 10px; }

/* /institute/ curriculum only: 14px between the heading and the first
   cluster, down from 40px — 35% of it. That 40px is the section's grid
   `row-gap`, which applies to every row equally and cannot be set for one row
   alone, so the heading pulls the first cluster up by the 26px difference
   instead. Cluster-to-cluster spacing is untouched and stays 40px.
   `#syllabus` below it still runs the full 40px. */
.page-institute #curriculum > h2 { margin-bottom: -26px; }

/* ---------- campuses: three hoverable location cards ---------- */
.campuses { background: var(--surface); padding: 84px 0; }
.campuses h2 { font-size: clamp(28px, 3.4vw, 42px); font-weight: 700; }
.campus-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 34px; }
.campus {
  display: block; background: var(--surface-2); border: 1px solid var(--line);
  padding: 34px 32px; text-decoration: none; color: var(--text);
  transition: border-color .2s var(--ease), transform .2s var(--ease);
}
.campus:hover, .campus:focus-visible { border-color: var(--text); transform: translateY(-3px); }
.campus b { display: block; font-size: 23px; font-weight: 700; }
.campus address { margin-top: 12px; font-style: normal; font-size: 16px; color: var(--text-muted); }

/* ---------- cta: full width horizontal bands ----------
   Enroll, Give, Pray — one band each, one per line, heading and descriptive
   copy left, the button pair right. Each pair is an outlined "more
   information" link beside the filled ask; see .btn--outline. --photo swaps
   the flat background for a full-bleed image and a scrim, the same treatment
   .hero uses. Exactly one band per page should carry a picture. */
.cta { padding: 112px 0; }
.cta .shell { display: flex; align-items: center; justify-content: space-between; gap: 40px; flex-wrap: wrap; }
.cta h2 { font-size: clamp(30px, 4vw, 46px); font-weight: 700; text-transform: uppercase; max-width: 16ch; }
.cta p { margin-top: 14px; font-size: 18px; color: var(--text-muted); max-width: 52ch; }
.cta__actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.cta--tint { background: var(--surface); }
.cta--photo { position: relative; overflow: hidden; }
.cta__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 60% center; }
.cta__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    rgba(var(--scrim), .86) 0%, rgba(var(--scrim), .70) 44%, rgba(var(--scrim), .34) 100%);
}
.cta--photo .shell { position: relative; z-index: 2; }
.cta--photo h2 { color: #FFF; }
.cta--photo p { color: rgba(255,255,255,.92); }
/* the outline button sits on the scrim here, so its label goes white until
   the hover fills it with the accent */
.cta--photo .btn--outline { color: #FFF; }
.cta--photo .btn--outline:hover { color: var(--accent-ink); }

/* ---------- widgets: three column row of compact cards ----------
   The accent rule above each title runs the full column width but is scaled
   down to a stub; hovering (or tabbing into) the column releases it to 1.
   scaleX is transform-only, so the growth never reflows the cards below.  */
.widgets { background: var(--surface); padding: 78px 0 88px; }
.widgets-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; align-items: start; }
.widgets-row--two { grid-template-columns: repeat(2, 1fr); }
.widget__title { position: relative; padding-top: 20px; margin-bottom: 26px; font-size: clamp(23px, 2.4vw, 30px); font-weight: 700; }
.widget__title::before {
  content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 5px;
  background: var(--accent); transform: scaleX(var(--rule, .15)); transform-origin: left;
  transition: transform .45s var(--ease);
}
.widget:hover .widget__title::before,
.widget:focus-within .widget__title::before { --rule: 1; }
.widget__lead { font-size: 17px; color: var(--text-muted); max-width: 34ch; }
.widget .btn { margin-top: 26px; }
.widget__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px; }
.wcard { background: var(--surface-2); border: 1px solid var(--line); padding: 20px 22px; }
.wcard h3 { font-size: 17px; font-weight: 700; }
.wcard h3 a {
  color: var(--text); text-decoration: none;
  border-bottom: 2px solid var(--accent); padding-bottom: 1px;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.wcard h3 a:hover { background: var(--accent); color: var(--accent-ink); }
.wcard__meta { margin-top: 10px; display: flex; align-items: center; gap: 14px; font-size: 14.5px; color: var(--text-muted); }
.wcard__icon { display: inline-flex; color: var(--text-muted); font-size: 17px; text-decoration: none; transition: color .2s var(--ease); }
.wcard__icon:hover { color: var(--text); }

/* ---------- form controls ---------- */
.field { display: grid; gap: 8px; text-align: left; }
.field label { font-size: 14px; font-weight: 700; color: var(--text); }
.field .help { font-size: 13.5px; color: var(--text-muted); }
.field .err { font-size: 13.5px; font-weight: 700; color: var(--err, #B3261E); }
.control { position: relative; display: block; }
.control > i {
  position: absolute; right: 16px; top: 50%; transform: translateY(-50%);
  pointer-events: none; color: var(--text-muted); font-size: 16px;
}
select, input[type="text"], input[type="email"] {
  appearance: none; width: 100%; font-family: var(--font); font-size: 16px;
  padding: 16px 46px 16px 18px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-ui);
  transition: border-color .2s var(--ease);
}
input[type="text"], input[type="email"] { padding-right: 18px; }
select:hover, input:hover { border-color: var(--text-muted); }
input::placeholder { color: var(--text-muted); opacity: 1; }
[aria-invalid="true"] { border-color: var(--err, #B3261E); border-width: 2px; }

/* ---------- watch list: asymmetric map + rail ---------- */
.watch { padding: 84px 0; }
.watch h2 { font-size: clamp(29px, 3.8vw, 42px); font-weight: 700; }
.watch__lead { margin-top: 14px; max-width: 68ch; font-size: 18px; color: var(--text-muted); }
.map-grid { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: 34px; align-items: start; margin-top: 36px; }
.map-box { background: var(--surface); border: 1px solid var(--line); padding: 16px; }
.map-box svg { width: 100%; height: auto; display: block; }
.cty { fill: var(--lvl-base); stroke: var(--bg); stroke-width: .5; transition: fill .15s var(--ease); }
.cty.lvl-extreme  { fill: var(--lvl-extreme); }
.cty.lvl-veryhigh { fill: var(--lvl-veryhigh); }
.cty.lvl-high     { fill: var(--lvl-high); }
.cty[data-level] { cursor: pointer; }
.cty[data-level]:hover, .cty[data-level]:focus { fill: var(--lvl-active); stroke: var(--text); stroke-width: 1.2; }
.readout { min-height: 96px; }
.readout .rank { font-size: 13px; font-weight: 500; color: var(--text-muted); }
.readout .cname { font-size: 25px; font-weight: 700; margin: 2px 0 8px; }
.readout .lvl { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 500; }
.readout .empty { color: var(--text-muted); padding-top: 6px; }
.sw { width: 15px; height: 15px; border-radius: 2px; flex: 0 0 auto; box-shadow: inset 0 0 0 1px rgba(var(--scrim), .12); }
.rail h3 { font-size: 15px; font-weight: 700; margin-bottom: 12px; }
.scale { list-style: none; padding: 0; margin: 0 0 26px; display: grid; gap: 9px; }
.scale li { display: flex; align-items: center; gap: 10px; font-size: 15px; }
.figures { display: grid; grid-template-columns: repeat(5, 1fr); gap: 26px; margin-top: 58px; border-top: 1px solid var(--line); padding-top: 40px; }
.figures b { display: block; font-size: 33px; font-weight: 700; line-height: 1; }
.figures hr { width: 34px; height: 3px; background: var(--accent); border: none; margin: 12px 0; }
.figures p { font-size: 14px; color: var(--text-muted); }

/* ---------- split (text beside asset) ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; padding-block: 84px; }
.split--flip .split__media { order: -1; }
/* 85% of a full .split, band and media together: the padding drops from 84
   to 71, and the portrait from 4/5 (1.25w tall) to 16/17 (1.0625w). Used
   where the section is a summary pointing at the page that holds it in full,
   not a section in its own right. */
.split--compact { padding-block: 71px; }
/* A .split with nothing in the media column, so it collapses to one. Keeps
   the .split typography and band rhythm rather than making the section a
   one-off; .split p already holds the copy to 58ch so it does not run the
   full width of the shell. Used by the /give/ hero. */
.split--solo { grid-template-columns: 1fr; }
.split--compact .split__media img { aspect-ratio: 16/17; }
.split__media img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/5; }
/* Anchor the crop to the top of the source instead of its centre. For a
   portrait framed with the head near the top edge, a centred crop takes the
   forehead off — and it takes more off at the 4/3 mobile ratio than at 4/5.
   Used by the author photo on /books/. */
.split__media--top img { object-position: center top; }
.split h1 { font-size: clamp(38px, 4.8vw, 60px); font-weight: 700; text-transform: uppercase; }
.split h2 { font-size: clamp(28px, 3.4vw, 40px); font-weight: 700; }
.split p { margin-top: 18px; font-size: 18px; color: var(--text-muted); max-width: 58ch; }
.split .btn, .split .tlink { margin-top: 28px; }

/* ---------- full-bleed photo band with caption below ---------- */
.plate { padding: 0 0 84px; }
.plate img { width: 100%; height: clamp(320px, 46vh, 520px); object-fit: cover; }
.plate figcaption { max-width: 60ch; margin: 16px auto 0; padding: 0 32px; font-size: 15px; color: var(--text-muted); text-align: center; }

/* ---------- clusters (grouped rows, sparse dividers) ---------- */
.clusters { padding-block: 0 84px; display: grid; gap: 40px; }
.cluster { display: grid; grid-template-columns: 220px minmax(0,1fr); gap: 40px; padding-top: 28px; border-top: 2px solid var(--line); }
.cluster h3 { font-size: 21px; font-weight: 700; }
.cluster .rows { display: grid; gap: 20px; }
.cluster .row b { font-size: 17px; display: block; }
.cluster .row p { font-size: 16px; color: var(--text-muted); margin-top: 4px; max-width: 62ch; }
.cluster .row p + p { margin-top: 12px; }
/* scripture references: quieter than body copy, and never italic — these are
   citations, not emphasis. Used on the beliefs page and in What we do. */
.refs { font-size: 14px; color: var(--text-muted); opacity: .85; margin-top: 10px; padding-left: 13px; border-left: 3px solid var(--accent); }

/* ---------- catalogue grid (image + label per item) ---------- */
.catalogue { padding-block: 0 84px; }
.catalogue h2 { font-size: clamp(28px, 3.4vw, 40px); font-weight: 700; margin-bottom: 32px; }
.cat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }
.item { display: block; text-decoration: none; color: var(--text); }
.item img { aspect-ratio: 3/4; object-fit: cover; width: 100%; transition: opacity .2s var(--ease); }
.item:hover img { opacity: .88; }
.item b { display: block; margin-top: 14px; font-size: 18px; }
.item span { display: block; font-size: 15px; color: var(--text-muted); margin-top: 2px; }

/* Covers variant: the cover sits beside its label rather than above it.
   Two per row, not four: the shell is 1156px inside its padding, so a third
   column would leave the label about 200px and a fourth about 100px.

   THE COVER BOX IS FIXED AT 165x220 AND NEVER VARIES. Both dimensions are
   set explicitly, so no source image can change the size of the box — see
   "The book cover box" in the README before touching these three values. */
.cat-grid--covers { grid-template-columns: repeat(2, 1fr); gap: 40px 44px; }
/* Two children only — the cover and the .item__text that holds all three
   lines. The label MUST be wrapped: title, price and .buy loose in here would
   be three separate flex children sitting in a row beside the cover. */
.cat-grid--covers .item { display: flex; align-items: center; gap: 26px; }
.cat-grid--covers .item img { flex: none; width: 165px; height: 220px; aspect-ratio: 3/4; object-fit: cover; }
/* min-width: 0 or a long unbroken title pushes the cover out of the column. */
.cat-grid--covers .item__text { min-width: 0; }
.cat-grid--covers .item b { margin-top: 0; font-size: 19px; line-height: 1.3; }
.cat-grid--covers .item span { margin-top: 6px; }

/* "Buy now" is a span, never a button or a second <a>: .item is already the
   link to Payhip, and an interactive element nested inside an <a> is invalid
   markup. This only has to read as a button — the click it needs is the
   card's own. Specificity beats .item span above, so display and colour hold. */
.cat-grid--covers .item .buy {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 16px;
  font-size: 13px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent);
}
.cat-grid--covers .item .buy i { font-size: 1.15em; }
/* Feedback, and the only thing on the card that moves. 4px is far enough to
   read as a nudge toward the shop and short enough to stay tight against the
   word — much further and the caret looks detached from it. :focus-visible
   carries it for the keyboard, since the card is what takes focus. The
   reduced-motion block at the top of the file switches it off. */
.cat-grid--covers .item .buy i { transition: transform .18s var(--ease); }
.cat-grid--covers .item:hover .buy i,
.cat-grid--covers .item:focus-visible .buy i { transform: translateX(4px); }

/* ---------- video band (/outreach/) ---------- */
/* The 16:9 box is reserved before the frame exists, so the page does not jump
   when site.js drops the iframe in on scroll. The tinted background is what
   fills that box in the meantime — and what shows if the embed never arrives. */
.videoband { padding-block: 84px 0; }
.videoband__frame {
  position: relative; width: 100%; aspect-ratio: 16 / 9;
  background: var(--surface-2); overflow: hidden;
}
.videoband__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ---------- people (square portrait, small bio beneath) ---------- */
/* The photograph is the card: a 1:1 crop the full width of the cell, with a
   compact strip under it for the name and a short bio. The sources are
   cropped square on disk, so object-fit only has to absorb rounding. */
.people { padding-block: 0 84px; }
.people h2 { font-size: clamp(28px, 3.4vw, 40px); font-weight: 700; margin-bottom: 32px; }
.people-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }
.person { background: var(--surface-2); border: 1px solid var(--line); }
/* height: auto is load-bearing. The width/height attributes on the img are
   presentational hints, so height stays at the attribute's 800px unless it
   is overridden — aspect-ratio only applies when one axis is auto, and the
   card comes out 365 wide by 800 tall instead of square. */
.person img { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; }
.person__text { padding: 18px 20px 20px; }
.person b { display: block; font-size: 18px; font-weight: 700; }
.person p { margin-top: 8px; font-size: 15.5px; color: var(--text-muted); }

/* The cards arrive as a domino rather than as one block: the far-right card
   lands first and the wave runs back across to the left, which walks the eye
   to Barimah instead of leaving it stranded at the end of the row. The
   section keeps its own .reveal — that is what adds .in, and it carries the
   heading. Delays sit on the cards, so the two entrances layer. */
.person { opacity: 0; transform: translateX(18px); }
.people.in .person {
  opacity: 1; transform: none;
  transition: opacity .38s var(--ease), transform .38s var(--ease);
}
.people.in .person:nth-child(1) { transition-delay: .2s; }
.people.in .person:nth-child(2) { transition-delay: .1s; }
.people.in .person:nth-child(3) { transition-delay: 0s; }

/* ---------- bento (exact cell count, mixed backgrounds) ---------- */
.bento { padding-block: 0 84px; }
.bento h2 { font-size: clamp(28px, 3.4vw, 40px); font-weight: 700; margin-bottom: 32px; }
.bento-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.cell { padding: 32px; border: 1px solid var(--line); display: flex; flex-direction: column; justify-content: flex-end; min-height: 260px; }
.cell h3 { font-size: 21px; font-weight: 700; }
.cell p { margin-top: 10px; font-size: 16px; color: var(--text-muted); }
.cell--wide { grid-column: span 2; }
.cell--tall { grid-row: span 2; }
.cell--accent { background: var(--accent); border-color: var(--accent); }
.cell--accent h3, .cell--accent p { color: var(--accent-ink); }
.cell--tint { background: var(--surface); }
.cell--photo { position: relative; padding: 0; border: none; overflow: hidden; }
.cell--photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* ---------- steps (numbered stack) ---------- */
.steps { padding-block: 0 84px; }
.steps h2 { font-size: clamp(28px, 3.4vw, 40px); font-weight: 700; margin-bottom: 32px; }
.step { display: grid; grid-template-columns: 74px minmax(0,1fr); gap: 26px; padding: 26px 0; }
.step + .step { border-top: 1px solid var(--line); }
.step b { font-size: 34px; font-weight: 700; color: var(--accent-ink); background: var(--accent); border-radius: var(--radius-ui); width: 62px; height: 62px; display: flex; align-items: center; justify-content: center; }
.step h3 { font-size: 20px; font-weight: 700; }
.step p { margin-top: 6px; font-size: 16.5px; color: var(--text-muted); max-width: 62ch; }

/* ---------- quote ---------- */
.pull { padding-block: 0 84px; }
.pull blockquote { max-width: 30ch; font-size: clamp(24px, 3vw, 34px); font-weight: 700; line-height: 1.25; }
.pull .who { margin-top: 18px; font-size: 15px; color: var(--text-muted); }
.pull .who b { display: block; color: var(--text); font-size: 16px; }

/* ---------- signup ---------- */
.signup { background: var(--surface); padding: 78px 0; }
.signup h2 { font-size: clamp(28px, 3.4vw, 40px); font-weight: 700; }
.signup > .shell > p { margin-top: 14px; max-width: 56ch; font-size: 17px; color: var(--text-muted); }
/* The three signup sections are a mailto: link now rather than a posted form,
   so .signup form and the .formnote states went with it. The generic .field
   kit further up is deliberately left in place and unused, as the starting
   point if a real posted form ever comes back. */
.signup .btn { margin-top: 30px; }
/* The address in plain text under the button. This is the whole fallback for a
   visitor whose browser has no mail client registered, where the button above
   does nothing visible at all, so it has to be readable and selectable. The
   stylesheet sets no colour on a bare <a>, which is why this rule is explicit
   rather than inherited. */
/* Specificity: `.signup > .shell > p` above is (0,2,1) and would otherwise win
   on both font-size and margin-top, so this selector matches its shape. */
.signup > .shell > .mailnote { margin-top: 18px; font-size: 15px; color: var(--text-muted); }
.mailnote a { color: var(--text); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.mailnote a:hover { color: var(--accent); }

/* ---------- closing call ---------- */
.call { background: var(--accent); padding: 70px 0; }
.call .shell { display: flex; align-items: center; justify-content: space-between; gap: 34px; flex-wrap: wrap; }
.call h2 { color: var(--accent-ink); font-size: clamp(27px, 3.4vw, 40px); font-weight: 700; max-width: 22ch; }
/* The band is already the accent, so the button inverts to the dark neutral
   rather than reusing --accent-ink, which is now white. */
.call .btn { background: var(--text); color: #FFF; }
.call .btn:hover { background: #000; }

/* ---------- footer ---------- */
.site-footer { background: var(--text); color: var(--bg); }
.site-footer .shell { padding-top: 58px; padding-bottom: 40px; }
.site-footer h2 { font-size: 14px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: currentColor; opacity: .6; margin-bottom: 18px; }
.foot-cols { display: flex; justify-content: space-between; gap: 40px; flex-wrap: wrap; padding: 38px 0 32px; }
.foot-cols ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.foot-cols a { font-size: 15px; color: currentColor; opacity: .88; text-decoration: none; }
.foot-cols a:hover { opacity: 1; }
.foot-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: currentColor; }
.foot-brand__leaf { height: 46px; width: auto; flex: 0 0 auto; }
.foot-brand .name { font-weight: 700; font-size: 26px; }
.foot-brand .name i { font-style: italic; }
.foot-brandcol { display: flex; flex-direction: column; align-items: flex-start; gap: 24px; }
.copy { border-top: 1px solid rgba(255,255,255,.18); padding-top: 20px; font-size: 13px; opacity: .6; }

/* ---------- social links (footer + bottom of the mobile menu) ---------- */
/* One component in two colour contexts. Everything is currentColor, so the
   dark footer and the light mobile panel both work without a second rule —
   do not put a literal colour in here. */
.social { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: 12px; }
.social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; color: currentColor; text-decoration: none;
  border: 1px solid currentColor; border-radius: var(--radius-ui); opacity: .55;
  transition: opacity .2s var(--ease), background-color .2s var(--ease);
}
.social a:hover { opacity: 1; }
.social svg { width: 19px; height: 19px; display: block; fill: currentColor; }
/* The mobile panel styles every descendant <a> as a full-width bordered row.
   These three are buttons in a row instead, so the block rules are undone
   explicitly — .mobile-nav .social a outranks .mobile-nav a. */
.mobile-nav .social { padding: 20px 0 4px; }
.mobile-nav .social a { display: inline-flex; padding: 0; border-bottom: 1px solid currentColor; font-size: 0; }
.mobile-nav .social a:hover { background: var(--surface); }
.site-footer .social a:hover { background: rgba(255,255,255,.12); }

/* ---------- mobile collapse (explicit per layout) ---------- */
@media (max-width: 1120px) {
  /* Seven primary links plus the wordmark is the widest the bar ever gets.
     Tighten the gaps rather than dropping a link, down to the 860px burger. */
  .nav-right { gap: 20px; }
  .primary-nav ul { gap: 20px; }
  .primary-nav a { font-size: 15px; }
}
@media (max-width: 1024px) {
  .figures { grid-template-columns: repeat(2, 1fr); }
  .bento-grid { grid-template-columns: repeat(2, 1fr); }
  .cat-grid { grid-template-columns: repeat(2, 1fr); }
  .people-grid { grid-template-columns: repeat(2, 1fr); }
  /* Two across and then one below: there is no single "right" to start from,
     so the domino runs in reading order. Same specificity as the rules above,
     later in the file, so these win without !important. */
  .person { transform: translateY(18px); }
  .people.in .person:nth-child(1) { transition-delay: 0s; }
  .people.in .person:nth-child(2) { transition-delay: .1s; }
  .people.in .person:nth-child(3) { transition-delay: .2s; }
  .widgets-row { grid-template-columns: repeat(2, 1fr); gap: 34px; }
  .campus-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  .primary-nav, .nav-right .iconbtn { display: none; }
  .burger { display: block; }
  .brand__logo { height: 48px; }
  .shell { padding-inline: 20px; }

  /* The slide-in panel. It is a full-viewport overlay, not a block in the
     header's flow — in flow it pushed the page down and left the site
     scrolling behind it.

     It starts below the header rather than at y=0 so the burger stays on top
     of it and can close it; the header is opaque and z-index 80, the panel is
     70, so the two read as one white screen. --header-h is the only measured
     constant here: 48px logo + 11px padding top and bottom + the 1px border.
     If .brand__logo or .bar padding changes at this width, change it too.

     It is also its own scroll container. That plus overscroll-behavior is
     what stops a drag inside the panel from reaching the page behind it;
     min-height keeps it the scroll target even when the links are short. */
  :root { --header-h: 71px; }
  .mobile-nav {
    position: fixed; top: var(--header-h); left: 0; right: 0; bottom: 0;
    z-index: 70; background: var(--bg);
    overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-block: 8px 48px;
  }
  .mobile-nav.open { display: block; }
  .split, .split--flip { grid-template-columns: 1fr; gap: 32px; padding-block: 60px; }
  .split--flip .split__media { order: 0; }
  .split__media img { aspect-ratio: 4/3; }
  .split--compact { padding-block: 51px; }
  .split--compact .split__media img { aspect-ratio: 1.569; }  /* 85% of 4/3 */
  .map-grid { grid-template-columns: 1fr; }
  .cluster { grid-template-columns: 1fr; gap: 18px; }
  .widgets-row, .widgets-row--two { grid-template-columns: 1fr; gap: 34px; }
  .widgets { padding: 60px 0 66px; }
  .campuses { padding: 60px 0; }
  .cta { padding: 76px 0; }
  .cta .shell { flex-direction: column; align-items: flex-start; gap: 26px; }
  .cell--tall, .cell--wide { grid-row: span 1; grid-column: span 1; }
  /* Books go to block view: the cover sits above its own label, and the books
     run one after another down the page. The box stays 3/4 — 180x240 is the
     desktop 165x220 scaled up, not a different shape. */
  .cat-grid--covers { grid-template-columns: 1fr; gap: 36px; }
  .cat-grid--covers .item { flex-direction: column; align-items: flex-start; gap: 14px; }
  .cat-grid--covers .item img { width: 180px; height: 240px; }
}
@media (max-width: 560px) {
  .figures, .cat-grid, .bento-grid, .campus-grid, .people-grid { grid-template-columns: 1fr; }
  /* Type steps down; the cover box does not — it is fixed at 3/4 everywhere. */
  .cat-grid--covers .item b { font-size: 17px; }
  .hero h1 { font-size: clamp(34px, 9vw, 44px); }
}

/* ---------- giving terms modal ---------- */
/* The terms used to be a section of /give/ and pushed the second Give Now
   button below 114 lines of prose. They are a <dialog> now, opened from the
   note under the hero button and from the footer link on all ten pages.

   Two ways in, and exactly one of them is live on any given page load:

     [open]   site.js called showModal(). The dialog is in the top layer, so
              ::backdrop paints the scrim and the panel needs no z-index.
     :target  no JavaScript, /give/#giving-terms straight from the address bar
              or from another page's footer. There is no top layer and no
              ::backdrop here, so this rule paints its own scrim and its own
              z-index. It is what keeps the terms readable for Paystack's
              business review with scripting off — do not delete it.

   .has-terms-modal on <html> is site.js saying it has taken over, and it is
   what keeps the two apart. They must never both apply: :target stays matched
   after close() — removing a fragment with replaceState does not reliably
   stop it matching — and the panel would be left on screen with no way out. */
.terms {
  position: fixed; inset: 0; z-index: 90;
  width: 100%; max-width: none; height: 100%; max-height: none;
  margin: 0; padding: 20px; border: none; background: transparent;
  overflow: hidden;
  display: none;
}
.terms[open],
html:not(.has-terms-modal) .terms:target { display: grid; place-items: center; }
.terms::backdrop { background: rgba(var(--scrim), .62); }
html:not(.has-terms-modal) .terms:target { background: rgba(var(--scrim), .62); }

/* Scroll lock, set by site.js. showModal() does not stop the page behind the
   dialog scrolling; same overflow-only approach as body.nav-open. */
body.modal-open { overflow: hidden; }

.terms__panel {
  display: flex; flex-direction: column;
  width: min(760px, 100%); max-height: min(84dvh, 800px);
  background: var(--bg); color: var(--text);
  border-radius: var(--radius-ui);
  box-shadow: 0 30px 70px rgba(var(--scrim), .34);
  overflow: hidden;
}

/* Head and foot are fixed; only .terms__body scrolls. */
.terms__head {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 22px 28px; border-bottom: 1px solid var(--line); flex: 0 0 auto;
}
.terms__head h2 { font-size: 24px; font-weight: 700; }
.terms__close {
  flex: 0 0 auto; width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid transparent; border-radius: var(--radius-ui);
  color: var(--text-muted); font-size: 21px; cursor: pointer;
  transition: border-color .2s var(--ease), color .2s var(--ease);
}
.terms__close:hover { border-color: var(--line); color: var(--text); }

/* The document. Everything from here down is the serif, which is the only
   place on the site that is not var(--font). overscroll-behavior stops a
   flick at the end of the terms from scrolling the page behind the modal. */
.terms__body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 26px 28px 32px;
  font-family: var(--font-formal);
}
.terms__body:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.terms__lede { font-size: 17px; line-height: 1.6; margin-bottom: 26px; }
/* .clusters is a page layout — two columns, 84px of tail. Inside the modal it
   is a document, so the label sits above its paragraphs and the tail goes. */
.terms__body .clusters { padding-block: 0; gap: 28px; }
.terms__body .cluster { grid-template-columns: 1fr; gap: 14px; padding-top: 22px; border-top: 1px solid var(--line); }
.terms__body .cluster:first-child { padding-top: 0; border-top: none; }
.terms__body .cluster h3 { font-family: var(--font-formal); font-size: 20px; }
.terms__body .cluster .row b { font-size: 16.5px; }
.terms__body .cluster .row p { font-size: 16px; line-height: 1.62; color: var(--text); max-width: none; }
.terms__body .cluster .row .mailnote a { color: var(--accent); }

.terms__foot {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 18px 28px; border-top: 1px solid var(--line);
  background: var(--surface); flex: 0 0 auto;
}

/* The note under the hero button. It is the only route into the terms on this
   page, so it is not a .mailnote — it is a link that has to be seen. */
.givenote { margin-top: 18px; font-size: 15px; color: var(--text-muted); }
.givenote a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.givenote a:hover { color: var(--accent); }

/* Same link in the footer's legal line, on all ten pages. */
.copy a { color: currentColor; text-decoration: underline; text-underline-offset: 3px; }
.copy a:hover { opacity: 1; }

@media (max-width: 700px) {
  /* Full screen on a phone: a centred card with 20px of gutter wastes the
     only dimension a long document needs. */
  .terms { padding: 0; }
  .terms__panel { width: 100%; max-height: 100dvh; height: 100dvh; border-radius: 0; }
  .terms__head { padding: 18px 20px; }
  .terms__head h2 { font-size: 21px; }
  .terms__body { padding: 22px 20px 28px; }
  .terms__foot { padding: 14px 20px; }
  .terms__foot .btn { flex: 1 1 auto; justify-content: center; }
}

/* ---------- give options modal ---------- */
/* The dialog behind the three Give Now buttons. It borrows the shell of the
   giving terms — .terms, .terms__panel, .terms__head, .terms__close — because
   it is the same object on the same page and two modal shells would drift
   apart the first time either was touched. Everything below is the difference:
   the panel is narrower, it sizes to its content rather than filling the
   viewport, and it is set in var(--font), not the terms' serif.

   .has-give-modal on <html> is the same handshake .has-terms-modal is: site.js
   saying it has taken over, which switches off the :target fallback. Without
   the gate the two ways in would fight, because :target keeps matching after
   close(). The fallback itself must stay — with scripting off it is the only
   way /give/#give-options shows anything at all. */
.giveopts[open],
html:not(.has-give-modal) .giveopts:target { display: grid; place-items: center; }
html:not(.has-give-modal) .giveopts:target { background: rgba(var(--scrim), .62); }

.giveopts__panel { width: min(560px, 100%); max-height: min(84dvh, 720px); }

/* [hidden] is how the steps are swapped, and any display rule inside this
   modal would out-specify the attribute's UA style. Nothing here sets display
   on a step today; this is the guard so that adding one later cannot leave two
   steps on screen at once. */
.giveopts [hidden] { display: none !important; }

.giveopts__body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 24px 28px 28px;
}
.giveopts__lede { font-size: 16px; color: var(--text-muted); margin-bottom: 18px; }

/* The two choices. Cards that happen to be buttons: full width, so the whole
   row is the target rather than a word in it. */
.giveopts__choices { display: grid; gap: 12px; }
.givechoice {
  display: flex; align-items: center; gap: 16px; width: 100%; text-align: left;
  padding: 18px 20px; cursor: pointer;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius-ui);
  font-family: var(--font); font-size: 16px;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.givechoice:hover { background: var(--surface-2); border-color: var(--accent); }
.givechoice > .ph { font-size: 26px; color: var(--accent); flex: 0 0 auto; }
.givechoice__t { display: flex; flex-direction: column; gap: 2px; font-weight: 700; }
.givechoice__t small { font-weight: 400; font-size: 14px; color: var(--text-muted); }
.givechoice__go { margin-left: auto; color: var(--text-muted); flex: 0 0 auto; }
.givechoice:hover .givechoice__go { color: var(--accent); }

/* Step two. The back link reads as a link, not a third choice. */
.giveopts__back {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 18px;
  padding: 0; background: none; border: none; cursor: pointer;
  font-family: var(--font); font-size: 14px; color: var(--text-muted);
}
.giveopts__back:hover { color: var(--accent); }
.giveopts__h { font-size: 21px; font-weight: 700; }
.giveopts__h:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

.givedetail { margin-top: 18px; display: grid; gap: 2px; }
.givedetail__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 20px;
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.givedetail__row:first-child { border-top: 1px solid var(--line); }
.givedetail dt { font-size: 14px; color: var(--text-muted); flex: 0 0 auto; }
.givedetail dd { font-size: 17px; font-weight: 700; text-align: right; }
/* The number itself. Tabular figures so the three groups line up, and a size
   that can be read off a screen at arm's length while typing it into a phone.
   The pre-script fallback in this cell is a sentence, so the big type and the
   nowrap are scoped to the state where JS has replaced it with digits. */
.givedetail__num { font-size: 15px; font-weight: 400; }
.givedetail__num--set {
  font-size: 22px; font-weight: 700; white-space: nowrap;
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.givedetail__num a { color: var(--accent); }

/* Copy button, added by site.js only where the clipboard API exists. */
.givecopy {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 16px;
  padding: 10px 16px; cursor: pointer;
  background: none; color: var(--text); border: 1px solid var(--line);
  border-radius: var(--radius-ui); font-family: var(--font); font-size: 14px;
  transition: border-color .2s var(--ease), color .2s var(--ease);
}
.givecopy:hover { border-color: var(--accent); color: var(--accent); }

.giveopts__uc {
  display: flex; align-items: center; gap: 10px; margin-top: 18px;
  padding: 16px 18px; border-radius: var(--radius-ui);
  background: var(--surface); border: 1px dashed var(--line);
  font-weight: 700;
}
.giveopts__uc .ph { font-size: 20px; color: var(--accent); }
.giveopts__note { margin-top: 16px; font-size: 15px; line-height: 1.6; color: var(--text-muted); }
.giveopts__note a { color: var(--accent); }

@media (max-width: 700px) {
  /* The terms go full screen on a phone because they are a long document.
     This panel is short, so it stays a card and keeps its gutter — see the
     .terms override above, which this undoes for this dialog only. */
  .giveopts { padding: 20px; }
  .giveopts__panel { width: 100%; height: auto; max-height: min(88dvh, 720px); border-radius: var(--radius-ui); }
  .giveopts__body { padding: 20px; }
  .givedetail__row { flex-direction: column; align-items: flex-start; gap: 4px; }
  .givedetail dd { text-align: left; }
}
