/* ==========================================================================
   Shared chrome for every page below the home page: the coat of arms page
   transition, the menu, and the sub-page header.
   Loaded by home.html and every tab destination.
   ========================================================================== */

/* ---- the transition. Gold and blue close over the page with the coat of arms
   on the seam, then part again on the far side. Same language as the cold
   open, so arriving anywhere on the site feels like the same door. ---- */
.cofa { position: fixed; inset: 0; z-index: 200; display: none; overflow: hidden;
  pointer-events: none; }
.cofa.on { display: block; pointer-events: auto; }
.cofa span { position: absolute; left: 0; width: 100%; height: 50.5%;
  transform: scaleY(0); transition: transform 720ms var(--ease); }
.cofa__gold { top: 0; transform-origin: top; background: var(--gold); }
.cofa__blue { bottom: 0; transform-origin: bottom; background: var(--blue); }
.cofa.close span { transform: scaleY(1); }
.cofa__mark { position: absolute; top: 50%; left: 50%; width: min(30vw, 13rem);
  transform: translate(-50%, -50%) scale(.55); opacity: 0;
  transition: opacity 360ms var(--ease), transform 820ms var(--ease); }
.cofa.close .cofa__mark { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.cofa.open span { transform: scaleY(0); transition-duration: 860ms; }
.cofa.open .cofa__mark { opacity: 0; transform: translate(-50%, -50%) scale(1.4); }

/* Arriving pages fade up behind the parting panels rather than snapping in. */
@keyframes aepi-arrive { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: none } }
.arrive { animation: aepi-arrive 820ms var(--ease) both; }

/* ---- menu ---- */
.menu__btn { position: fixed; top: 1.5rem; right: 1.5rem; z-index: 90;
  font: 700 11px/1 var(--body); letter-spacing: .2em; text-transform: uppercase;
  color: var(--ground); background: var(--gold); border: 0; border-radius: 999px;
  padding: 11px 18px; cursor: pointer; }
.menu__btn:hover { background: var(--bone); }
.menu { position: fixed; inset: 0; z-index: 89; background: var(--ground);
  display: grid; place-content: center; gap: .5rem; text-align: center;
  opacity: 0; visibility: hidden; transition: opacity var(--med) var(--ease), visibility var(--med); }
.menu.on { opacity: 1; visibility: visible; }
.menu a { text-decoration: none; color: var(--bone); font-family: var(--display);
  font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  font-size: clamp(2rem, 7vw, 4.5rem); line-height: 1.05;
  transition: color var(--fast) var(--ease); }
.menu a:hover { color: var(--gold); }
.menu .label { margin-bottom: 1.5rem; }
/* Donate is the only link in here that leaves the site, and the only one that
   asks for something. At destination size it would outrank Rush, so it sits
   below a rule at body scale, gold, reading as an action rather than a page. */
.menu__give { margin-top: 1.75rem; padding-top: 1.75rem;
  border-top: 1px solid var(--rule); color: var(--gold) !important;
  font-family: var(--body) !important; font-weight: 700 !important;
  font-size: var(--t-sm) !important; letter-spacing: .2em !important; }
.menu__give:hover { color: var(--bone) !important; }

/* ---- sub-page header, shared by every tab destination ---- */
.sub { position: relative; min-height: 62vh; display: grid; align-items: end;
  overflow: hidden; border-bottom: 1px solid var(--rule); }
.sub__img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; filter: brightness(.4) saturate(.8); }
.sub__grad { position: absolute; inset: 0;
  background: linear-gradient(to top, var(--ground) 4%, transparent 70%); }
.sub__inner { position: relative; padding-block: 3rem 4rem; }
/* Ben Akoka, Aug 2026: "move that back Sigma Beta button all the way to the top
   corner so it's not cluttered." It used to sit on the headline stack, one line
   above a "Sigma Beta" eyebrow that said the same thing. Now it pins to the
   top-left of every page header, opposite the menu button, on the wrap's left
   edge whatever the header's width. Every header it lives in is positioned. */
.sub__back { position: absolute; z-index: 2; top: 1.65rem;
  left: max(var(--gutter), calc((100% - var(--max)) / 2 + var(--gutter)));
  margin: 0; text-decoration: none;
  font: 600 11px/1 var(--body); letter-spacing: .2em; text-transform: uppercase;
  color: var(--gold); transition: color var(--fast) var(--ease); }
.sub__back:hover, .sub__back:focus-visible { color: var(--bone); }
.sub .display { color: var(--bone); }

/* ---- a photo wall that is not a carousel: everything visible at once, sized
   by how much it matters, no sideways scrolling. ---- */
.wall { display: grid; gap: 10px; padding-block: 3rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.wall figure { margin: 0; position: relative; overflow: hidden; background: var(--ground-2); }
.wall img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--slow) var(--ease), filter var(--med) var(--ease);
  filter: saturate(.85); }
.wall figure:hover img { transform: scale(1.05); filter: none; }
.wall .wide { grid-column: span 2; }
@media (max-width: 48rem) { .wall .wide { grid-column: span 1; } }

/* ==========================================================================
   SCROLL REVEALS
   Everything below the fold arrives rather than being there already. Children
   stagger off --d so a photo wall deals itself in instead of flashing at once.
   ========================================================================== */
html.js-reveal .reveal { opacity: 0; transform: translateY(22px);
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
  transition-delay: calc(var(--d, 0) * 65ms); }
html.js-reveal .reveal.is-in { opacity: 1; transform: none; }

/* Photos get a touch of scale so the wall feels like it settles. (Rails are
   not revealed at all any more; see the REVEAL list in aepi-page.js.) */
html.js-reveal .wall figure.reveal { transform: translateY(26px) scale(.97); }
html.js-reveal .wall figure.reveal.is-in { transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.js-reveal .reveal { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   MOSAIC — the brotherhood layout.
   A wall of equal rectangles reads as a contact sheet. This deals the same
   photos out at three weights so the eye has somewhere to land: a full-bleed
   hero every fifth landscape frame, wides, and the odd portrait running tall.
   grid-auto-flow: dense backfills the holes those spans leave behind.
   ========================================================================== */
/* Masonry, not a cropped grid. Jake: "make sure you can see the full photos in
   the galleries without clicking on them." A fixed-row grid with object-fit
   cover trims the top and bottom off every portrait frame, which on a page of
   group photos means cutting people out of their own picture. Columns let each
   figure keep its natural height, so nothing is cropped at any size. The
   is-hero/is-wide/is-tall classes still come off aepi-wall.js but no longer
   resize anything: the photograph's own shape decides now. */
.mosaic { columns: 3 16rem; column-gap: 10px; padding-block: 3rem; }
.mosaic figure { margin: 0 0 10px; position: relative; overflow: hidden;
  background: var(--ground-2); cursor: zoom-in; break-inside: avoid; }
.mosaic img { width: 100%; height: auto; display: block;
  filter: saturate(.82) brightness(.92);
  transition: transform var(--slow) var(--ease), filter var(--med) var(--ease); }
.mosaic figure:hover img, .mosaic figure:focus-visible img {
  transform: scale(1.06); filter: none; }
/* A gold hairline on hover, so the grid feels handled rather than printed. */
.mosaic figure::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 0 0 var(--gold); transition: box-shadow var(--med) var(--ease); }
.mosaic figure:hover::after, .mosaic figure:focus-visible::after {
  box-shadow: inset 0 0 0 2px var(--gold); }
.mosaic figure:focus-visible { outline: none; }

@media (max-width: 60rem) { .mosaic { columns: 2 12rem; } }
@media (max-width: 34rem) { .mosaic { columns: 1; } }
@media (max-width: 40rem) {
  .mosaic { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 7.5rem; }
  .mosaic figure, .mosaic figure.is-wide, .mosaic figure.is-hero { grid-column: span 2; }
  .mosaic figure.is-tall { grid-column: span 2; grid-row: span 2; }
}

/* Mosaic cells deal themselves in on scroll like the wall does — by opacity
   only. .mosaic and .montage are CSS multi-column boxes, and WebKit mislays
   column children that carry a transform mid-transition: a figure can paint
   as an empty slab until something forces a repaint, which is the "blank
   photo" Ben saw on the brotherhood wall in Aug 2026. No transform, no slab. */
html.js-reveal .mosaic figure.reveal, html.js-reveal .montage figure.reveal {
  opacity: 0; transform: none; }
html.js-reveal .mosaic figure.reveal.is-in, html.js-reveal .montage figure.reveal.is-in {
  opacity: 1; transform: none; }

/* ==========================================================================
   LIGHTBOX — "if you click on it you see the thing"
   ========================================================================== */
.lb { position: fixed; inset: 0; z-index: 210; display: grid; place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: color-mix(in srgb, var(--ground) 94%, transparent);
  opacity: 0; visibility: hidden; cursor: zoom-out;
  transition: opacity var(--med) var(--ease), visibility var(--med); }
.lb.on { opacity: 1; visibility: visible; }
/* The whole photograph, as large as the window allows and never cropped.
   width/height auto rather than a percentage so a portrait frame is limited by
   the viewport height and a landscape one by its width, instead of both being
   squeezed into the same box. */
.lb img { width: auto; height: auto; max-width: 100%;
  max-height: calc(100vh - 2 * clamp(1rem, 4vw, 3rem)); object-fit: contain;
  border: 1px solid var(--rule); transform: scale(.97);
  transition: transform var(--med) var(--ease); }
.lb.on img { transform: none; }
.lb__x { position: absolute; top: 1.25rem; right: 1.5rem; z-index: 1;
  font: 400 28px/1 var(--body); color: var(--ground); background: var(--gold);
  border: 0; border-radius: 999px; width: 44px; height: 44px; cursor: pointer; }
.lb__x:hover { background: var(--bone); }

/* ==========================================================================
   THE RUSH DOOR — deliberately not the coat of arms.
   Rush is the centrepiece, so it gets its own way in: UC Santa Barbara navy
   sweeping LEFT TO RIGHT rather than top to bottom, with RUSH riding the edge.
   ========================================================================== */
.rushdoor { position: fixed; inset: 0; z-index: 200; display: none; overflow: hidden;
  pointer-events: none; }
.rushdoor.on { display: block; pointer-events: auto; }
/* Notes 23 and 24: "that rush animation needs to be a little bit slower, like
   soak it in" and "take your time on these transitions, close and open, it
   should be very smooth." Every duration here and on the coat of arms was
   raised, and aepi-page.js waits the full close before it navigates. */
.rushdoor span { position: absolute; top: 0; height: 100%; width: 100%;
  transform: scaleX(0); transition: transform 780ms var(--ease); }
/* Two plates, offset, so the sweep has a leading edge instead of a flat wall. */
.rushdoor__navy { left: 0; transform-origin: left; background: var(--ucsb-navy, #003660); }
.rushdoor__surf { left: 0; transform-origin: left; background: var(--ucsb-gold, #febc11);
  transition-duration: 620ms; }
.rushdoor.close span { transform: scaleX(1); }
.rushdoor.close .rushdoor__navy { transition-delay: 130ms; }
.rushdoor__word { position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%) translateX(-14vw);
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(3rem, 16vw, 12rem); letter-spacing: .12em; line-height: 1;
  color: var(--ucsb-gold, #febc11); opacity: 0; white-space: nowrap;
  transition: opacity 380ms var(--ease), transform 860ms var(--ease); }
.rushdoor.close .rushdoor__word { opacity: 1; transform: translate(-50%, -50%); }
/* Out the far side the plates retract to the right edge, so the colour opens
   off the page the way it closed onto it: every transition closes and opens. */
.rushdoor.open span { transform-origin: right; transform: scaleX(0);
  transition-duration: 900ms; }
.rushdoor.open .rushdoor__word { opacity: 0; transform: translate(-50%, -50%) translateX(16vw); }

@media (prefers-reduced-motion: reduce) {
  .rushdoor span, .rushdoor__word { transition-duration: 1ms; }
}

/* ==========================================================================
   COUNTING YEARS — "1988 to today", animated
   ========================================================================== */
.years { display: inline-flex; align-items: baseline; gap: .5rem;
  font-family: var(--display); font-weight: 800; color: var(--gold);
  letter-spacing: .04em; }
.years__n { font-variant-numeric: tabular-nums; }
.years__to { color: var(--bone-dim); font-family: var(--plate); font-weight: 400;
  font-size: .6em; letter-spacing: .18em; text-transform: uppercase; }

/* ---- honest placeholder, shared: pages flag gaps rather than faking them.
   Was defined only on home, so every other page rendered it unstyled. ---- */
.gap { border: 1px dashed var(--rule); padding: 2rem; text-align: center;
  color: var(--slate); }
.gap strong { color: var(--gold); font-weight: 600; }

/* ---- carousel: for the sets too small or too uniform for a wall. Scrolls
   sideways under the thumb, snaps, and never hides the fact there is more. ---- */
.rail__head { display: flex; align-items: baseline; gap: 1rem; justify-content: space-between;
  border-top: 1px solid var(--rule-dim); padding-top: 1.25rem; margin-top: 3rem; }
.rail__head h3 { font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(1.4rem, 3vw, 2.1rem); margin: 0; color: var(--bone); }
.rail__n { font-family: var(--plate); letter-spacing: .14em; color: var(--gold);
  font-size: var(--t-sm); }
.rail { display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 1.5rem 0 2rem; scrollbar-width: thin; }
.rail figure { margin: 0; flex: 0 0 auto; width: clamp(11rem, 22vw, 15rem);
  scroll-snap-align: start; background: var(--ground-2); overflow: hidden; }
.rail img { width: 100%; height: 100%; object-fit: cover; display: block;
  filter: saturate(.85); transition: filter var(--med) var(--ease), transform var(--slow) var(--ease); }
.rail figure:hover img { filter: none; transform: scale(1.04); }

/* ==========================================================================
   MONTAGE — for pages where the honest photo count is small
   Notes 21 and 22: "have the photos be bigger and have it more like a montage
   than anything, because I don't want to show them like, oh, we only have five
   photos." A uniform grid of equal cards counts itself. Varied spans read as
   one composed picture instead, so a handful of good frames fill the width and
   none of them looks like a placeholder waiting for the next one.
   ========================================================================== */
/* Same masonry as .mosaic, for the same reason: the varied spans below used to
   set each cell's size and crop the photo to fit it. Full photographs win over
   a tidier block, so the spans are gone and the images keep their own shape. */
.montage { columns: 3 17rem; column-gap: 10px; }
.montage figure { margin: 0 0 10px; overflow: hidden; background: var(--ground-2);
  position: relative; break-inside: avoid; }
.montage img { width: 100%; height: auto; display: block;
  filter: saturate(.88) brightness(.95);
  transition: transform var(--slow) var(--ease), filter var(--med) var(--ease); }
.montage figure:hover img, .montage figure:focus-visible img {
  transform: scale(1.05); filter: none; }
.montage figure::after { content: ""; position: absolute; inset: 0;
  pointer-events: none; box-shadow: inset 0 0 0 0 var(--gold);
  transition: box-shadow var(--med) var(--ease); }
.montage figure:hover::after, .montage figure:focus-visible::after {
  box-shadow: inset 0 0 0 2px var(--gold); }
@media (max-width: 52rem) { .montage { columns: 2 13rem; } }
@media (max-width: 34rem) { .montage { columns: 1; } }
@media (prefers-reduced-motion: reduce) { .montage img { transition: none; } }

/* ==========================================================================
   ROUTES — pick a way to get in touch (note 22, "make this more interactive")
   Two real channels, side by side, each one a whole clickable panel rather
   than a link buried in a paragraph.
   ========================================================================== */
.routes { display: grid; gap: 1px; margin-top: 2.5rem;
  background: var(--rule-dim); border: 1px solid var(--rule-dim);
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
.route { display: flex; flex-direction: column; gap: .45rem; text-decoration: none;
  background: var(--ground); padding: clamp(1.5rem, 3vw, 2.25rem);
  transition: background var(--med) var(--ease); }
.route:hover, .route:focus-visible { background: var(--ground-2); }
.route:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
.route__k { font-family: var(--body); font-weight: 600; font-size: var(--t-xs);
  letter-spacing: .18em; text-transform: uppercase; color: var(--gold); }
/* sigmabetaaepi@gmail.com is 23 characters of plate type and it did not fit the
   card: the tail ran past the edge and the next panel's background painted over
   it, so the address read "SIGMABETAAEPI@GMAIL.CO". Long unbroken values wrap
   inside their own card now. Same family of bug as the clipped $5,000+. */
.route__v { font-family: var(--plate); font-size: var(--t-lg); color: var(--bone);
  letter-spacing: .04em; overflow-wrap: anywhere; }
.route__n { color: var(--slate); font-size: var(--t-sm); line-height: 1.5; }
.route__v::after { content: " \2192"; color: var(--gold); display: inline-block;
  transition: transform var(--med) var(--ease); }
.route:hover .route__v::after, .route:focus-visible .route__v::after { transform: translateX(5px); }
@media (prefers-reduced-motion: reduce) { .route, .route__v::after { transition: none; } }

/* Dani, 4 Sep 2026, alumni: four cards instead of three. auto-fit would land
   them 3 + 1 at mid widths and the empty track paints a rule-coloured slab —
   the same bug that made "By the numbers" look broken — so the steps are fixed
   at 1 / 2 / 4, none of which can orphan a card. contact.html keeps auto-fit. */
.routes--four { grid-template-columns: 1fr; }
@media (min-width: 40rem) { .routes--four { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .routes--four { grid-template-columns: repeat(4, 1fr); } }
/* Four to a row leaves ~200px of content per card, and the plate face at
   --t-lg was breaking "Update your info" and "Sigma Beta chapter support"
   mid-phrase. One step down fits them; the email still breaks at its hand-placed
   <wbr>, which is the same break it takes on the contact page. */
@media (min-width: 68rem) {
  .routes--four .route__v, .routes--four .route__go { font-size: var(--t-md); }
}

/* "Merge those top 2 boxes... to be like a contact the chapter, and then it
   gives you the option to email, and to message the chapter." One card holding
   two destinations cannot itself be a link, so the card is inert and each
   destination is its own anchor inside it. */
.route--multi { cursor: default; }
.route--multi:hover, .route--multi:focus-within { background: var(--ground); }
.route__go { font-family: var(--plate); font-size: var(--t-lg); color: var(--bone);
  letter-spacing: .04em; overflow-wrap: anywhere; text-decoration: none;
  transition: color var(--fast) var(--ease); }
.route__go::after { content: " \2192"; color: var(--gold); display: inline-block;
  transition: transform var(--med) var(--ease); }
.route__go:hover, .route__go:focus-visible { color: var(--gold); }
.route__go:hover::after, .route__go:focus-visible::after { transform: translateX(5px); }
.route__go:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* "Join the newsletter and then have a coming soon." Nothing to click yet, so
   the card does not pretend: no arrow, no hover, and the value sits back in the
   note colour so the eye reads it as a status rather than a destination. */
.route--soon { cursor: default; }
.route--soon:hover, .route--soon:focus-within { background: var(--ground); }
.route__v--flat { color: var(--slate); }
.route__v--flat::after { content: none; }

@media (prefers-reduced-motion: reduce) { .route__go, .route__go::after { transition: none; } }

/* ==========================================================================
   DRAWER — a .route that opens in place instead of going anywhere.
   Dani, 10 Aug 2026: "just put it on the alumni page if you click a button.
   Like it should probably be collapsed by default." Same panel language as the
   routes above it, so the page reads as one set of choices; the arrow points
   down rather than right because nothing here is a departure.
   ========================================================================== */
.drawer { margin-top: 2.5rem; border: 1px solid var(--rule-dim); background: var(--ground); }
.drawer__btn { display: flex; flex-direction: column; gap: .45rem; cursor: pointer;
  padding: clamp(1.5rem, 3vw, 2.25rem); list-style: none;
  transition: background var(--med) var(--ease); }
/* Safari still needs the vendor pseudo-element to drop the disclosure triangle. */
.drawer__btn::-webkit-details-marker { display: none; }
.drawer__btn:hover, .drawer__btn:focus-visible { background: var(--ground-2); }
.drawer__btn:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
.drawer__k { font-family: var(--body); font-weight: 600; font-size: var(--t-xs);
  letter-spacing: .18em; text-transform: uppercase; color: var(--gold); }
.drawer__v { font-family: var(--plate); font-size: var(--t-lg); color: var(--bone);
  letter-spacing: .04em; }
.drawer__v::after { content: "\2193"; color: var(--gold); display: inline-block;
  margin-left: .4em; transition: transform var(--med) var(--ease); }
.drawer[open] .drawer__v::after { transform: rotate(180deg); }
.drawer__n { color: var(--slate); font-size: var(--t-sm); line-height: 1.5;
  max-width: 46ch; }
.drawer__body { padding: 0 clamp(1.5rem, 3vw, 2.25rem) clamp(1.5rem, 3vw, 2.25rem); }
/* The rail inside a drawer carries the drawer's own heading, so it starts flush
   rather than under the margin a standalone rail head would have left. */
.drawer__body .rail { margin-top: 0; }
@media (prefers-reduced-motion: reduce) { .drawer__btn, .drawer__v::after { transition: none; } }

/* ==========================================================================
   LEADERSHIP
   ========================================================================== */
.board { display: grid; gap: 0; }
.officer { display: grid; grid-template-columns: 1fr auto; gap: 1rem; align-items: baseline;
  padding-block: 0.9rem; border-bottom: 1px solid var(--rule-dim); }
.officer__role { font-family: var(--body); font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: 0.2em; color: var(--gold); }
.officer__name { font-family: var(--plate); font-size: var(--t-md); letter-spacing: 0.08em; }
.officer__home { font-size: var(--t-sm); color: var(--slate); }

/* Board portraits. The chapter's own carousel already burns the name and
   title into each frame, so the caption below sits under the photo rather
   than over it and never fights the artwork. */
.board { grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: 1px;
  background: var(--rule-dim); border: 1px solid var(--rule-dim); }
.mug { margin: 0; background: var(--ground); display: flex; flex-direction: column; }
.mug img, .mug__none { width: 100%; aspect-ratio: 4 / 5; object-fit: cover;
  object-position: top center; display: block; filter: saturate(.9);
  transition: filter var(--med) var(--ease), transform var(--slow) var(--ease); }
.mug:hover img { filter: none; transform: scale(1.03); }
.mug { overflow: hidden; }
.mug__none { display: grid; place-items: center; background: var(--ground-2);
  font-family: var(--display); font-weight: 800; font-size: var(--t-2xl);
  color: var(--rule); }
.mug figcaption { padding: 1.1rem 1.15rem 1.35rem; }
.mug__role { display: block; font-family: var(--display); font-weight: 800;
  text-transform: uppercase; font-size: clamp(1.15rem, 1.9vw, 1.65rem);
  line-height: 1; letter-spacing: .02em; color: var(--gold); }
.mug__name { display: block; font-family: var(--plate); font-weight: 600;
  font-size: var(--t-base); letter-spacing: .06em; color: var(--bone);
  margin-top: .35rem; }
.mug__what { display: block; margin-top: .6rem; color: var(--bone-dim);
  font-size: var(--t-sm); line-height: 1.45; }

/* Dani, 4 Sep 2026: the disclosure ("What the Brother Master does") is gone —
   the one-line description under the name is the whole caption now, so the
   toggle, its caret, the open-state tint and the reveal keyframes went with it.
   figcaption keeps the column layout so captions of unequal length still sit
   flush to the top of their cards. */
.mug figcaption { flex: 1; display: flex; flex-direction: column; align-items: flex-start; }

/* ==========================================================================
   NUMBERS — shared with the home page's record, needed by donate.html
   ========================================================================== */
/* Dani, 10 Aug 2026: "this part looks ass now that it was reformatted." The
   auto-fit track was the problem: six tiles across the wrap landed five on the
   first row and one on the second, and the empty track painted the rule colour
   as a slab half the width of the page. The column count is fixed to something
   the tile counts divide into instead — two and three both do, and the 3-up
   step only applies to a block of exactly three or six. */
.stats { display: grid; grid-template-columns: 1fr; gap: 1px;
  background: var(--rule-dim); border: 1px solid var(--rule-dim); }
@media (min-width: 40rem) { .stats { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) {
  .stats:has(.stat:nth-child(3):last-child),
  .stats:has(.stat:nth-child(6):last-child) { grid-template-columns: repeat(3, 1fr); }
}
.stat { background: var(--ground); padding: 2rem 1.5rem; container-type: inline-size; }
.stat__n { font-family: var(--display); font-weight: 800; font-size: var(--t-2xl);
  line-height: 0.85; color: var(--gold); white-space: nowrap; }
@media (max-width: 40rem) { .stat__n { font-weight: 700; letter-spacing: .02em; } }
.stat__l { font-family: var(--plate); font-size: var(--t-sm); letter-spacing: 0.1em;
  color: var(--bone-dim); margin-top: 0.75rem; display: block; }
@supports (font-size: 1cqi) {
  .stat__n { font-size: min(var(--t-2xl), 29cqi); }
}
