/* ============================================================
   Northumberland Humane Society — site additions to the design system

   Everything in nhs-tokens.css / nhs-styles.css is Big Red Truck's, ships
   byte-identical, and is never edited (see CLAUDE.md). This file holds only
   what the CMS section library needs that the 201-class system does not yet
   have: naming follows the system's own nhs- / BEM-ish / token-only rules,
   so every addition here is a drop-in candidate for a v1.2 nhs-styles.css.
   Sent back to Rawle as a delta for NHS_DESIGN_SYSTEM_SPEC.md — see the
   changelog note at the foot of each block.

   Load AFTER nhs-styles.css. Never restate a system value; reference the
   token. Never invent a hex.
   ============================================================ */


/* nhs-tokens.css declares @font-face "omnes-fallback" but omits it from
   --font-sans, so the metric matching never applies and text reflows when
   Omnes swaps in. Restores the handoff reference build (archive-v1.0).
   Kept here, not in nhs-tokens.css, so that file stays byte-identical to the
   Big Red Truck handoff. Remove once Rawle ships a corrected design system. */
:root {
  --font-sans: "omnes-pro", "omnes-fallback", "Poppins", "Century Gothic",
               ui-rounded, "Segoe UI", system-ui, -apple-system, sans-serif;
}


/* ------------------------------------------------------------
   Accordion on <details>/<summary> — zero JS
   The section library's accordion section (FAQ pages, 2 uses) has no open/
   close behaviour to wire, so it renders on native <details>/<summary>
   rather than pairing nhs-header.js-style script with every instance.
   nhs-styles.css keys the chevron rotation off [aria-expanded="true"],
   which <details> never sets — this is the one rule needed to let the
   native element carry the rest of the component's styling untouched.
   Delta: one rule, ships alongside the trigger/icon/panel rules it extends.
   ------------------------------------------------------------ */
.nhs-accordion__item[open] > .nhs-accordion__trigger .nhs-accordion__icon {
  transform: rotate(180deg);
}
/* <summary> ships a default disclosure triangle; the system's chevron icon
   already carries that affordance. */
.nhs-accordion__trigger { list-style: none; }
.nhs-accordion__trigger::-webkit-details-marker { display: none; }


/* ------------------------------------------------------------
   Step numbering — §13b .nhs-step__number
   Rawle's own example hard-codes the numeral as markup text; the CMS's
   steps repeat has no per-item number field to fill it with (only title +
   body), so the ordinal comes from the <ol> via a CSS counter instead —
   the same technique the pre-existing engine already used for this exact
   component. .nhs-step__number stays empty in the section template.
   ------------------------------------------------------------ */
.nhs-steps { counter-reset: nhs-step; }
.nhs-step__number { counter-increment: nhs-step; }
.nhs-step__number::before { content: counter(nhs-step); }


/* ------------------------------------------------------------
   Notice box — label + heading + rich body + CTAs, boxed
   Used site-wide (18 instances) for asides the wireframes call out
   ("Before you begin", "Current foster need", status strips). No shipped
   component is this shape: §7 callout is a figure+label stat, not a body-
   text box. Built from the system's own boxed-card precedent — the white
   fill + border-default hairline .nhs-action--surface and .nhs-step already
   use so a box still reads against a --tint band (white-on-tint is 1.05;
   the border alone carries the 3:1 boundary, same reasoning as those two).

   Three tones, matching the schema's documented (not all yet authored)
   values:
     blank   — plain aside, tone-neutral
     status  — a live/operational note, teal accent (state-info)
     dark    — forest fill, reversed text, for a section that needs weight
   ------------------------------------------------------------ */
.nhs-notice {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: flex-start;
  padding: var(--space-7);
  background: var(--nhs-white);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
}
.nhs-notice__label {
  font-size: var(--fs-overline);
  line-height: var(--lh-overline);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-overline);
  text-transform: uppercase;
  color: var(--text-accent-teal-on-light);
}
.nhs-notice__heading {
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  font-weight: var(--fw-semibold);
}
.nhs-notice__body { max-width: var(--measure-max); }
.nhs-notice__body :where(a) { color: var(--text-link); }

.nhs-notice--status {
  border-color: var(--border-accent-teal);
  border-width: 2px;
}
.nhs-notice--status .nhs-notice__icon { color: var(--text-accent-teal-on-light); }

.nhs-notice--dark {
  background: var(--bg-inverse);
  color: var(--text-inverse);
  border-color: var(--bg-inverse);
}
.nhs-notice--dark .nhs-notice__label { color: var(--nhs-green-300); }
.nhs-notice--dark .nhs-notice__body :where(a) { color: var(--nhs-green-300); }
/* The section template's CTAs are the same two classes on every tone
   (.nhs-btn--secondary, .nhs-link--standalone) — both are forest, which
   disappears on this tone's forest fill. Recolour them here rather than
   branching the template per tone; same relationship .nhs-btn--inverse-
   primary / .nhs-link--inverse already use on a forest surface, same
   tokens, just scoped as an override instead of a different class. */
.nhs-notice--dark .nhs-btn--secondary { background: var(--nhs-green-500); color: var(--nhs-forest-500); }
.nhs-notice--dark .nhs-btn--secondary:hover { background: var(--nhs-green-400); }
.nhs-notice--dark .nhs-link--standalone { color: var(--nhs-green-300); }
.nhs-notice--dark .nhs-link--standalone:hover { color: var(--nhs-green-200); }


/* ------------------------------------------------------------
   Accordion side card
   The FAQ pages' "make your gift today"-style dark panel beside the
   questions (accordion.schema.json's optional aside group). No component
   in the system is this shape; built from the same forest/tint pairing
   the footer newsletter already establishes as safe on a forest ground,
   and only appears when the side card actually has a heading — an empty
   aside column collapses rather than reserving dead space.
   ------------------------------------------------------------ */
.nhs-accordion-layout { display: flex; gap: var(--space-7); align-items: flex-start; }
.nhs-accordion-layout__main { flex: 1 1 auto; min-width: 0; }
.nhs-accordion-layout__aside { display: none; }
.nhs-accordion-layout__aside:has(.nhs-h5:not(:empty)) {
  display: block;
  flex: 0 0 300px;
  background: var(--bg-inverse);
  color: var(--text-inverse);
  border-radius: var(--radius-xl);
  padding: var(--space-7);
}
.nhs-accordion-layout__aside p { color: var(--nhs-tint); }
@media (max-width: 767px) {
  .nhs-accordion-layout { flex-direction: column; }
  .nhs-accordion-layout__aside:has(.nhs-h5:not(:empty)) { flex-basis: auto; width: 100%; }
}

/* "Read more" reveal (Sept 3 aesthetic review, v2.93): reuses the accordion's
   native <details>/<summary> markup for a single expandable block instead of
   a list of FAQ questions (About Us and similar long pages). tone:plain
   drops the question-list affordances -- item border and chevron -- that
   would otherwise make a single item read as a one-question FAQ. */
.nhs-accordion--plain .nhs-accordion__item { border-bottom: none; }
.nhs-accordion--plain .nhs-accordion__icon { display: none; }


/* ------------------------------------------------------------
   CTA banner, centred layout
   cta.schema.json's "layout: center" (3 uses) has no home in §11, which is
   one fixed row (title | button). Reflows the same .nhs-cta box to a
   centred stack — no new colour, no new geometry, just a flex-direction
   swap and a capped measure so the heading does not run edge to edge.
   ------------------------------------------------------------ */
.nhs-cta--center {
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.nhs-cta--center .nhs-cta__title { max-width: 48ch; }
.nhs-cta--center .nhs-btn-group { justify-content: center; }


/* ------------------------------------------------------------
   Two-column "cards" tone
   twocol.schema.json's "tone: cards" (8 uses) bordered-panel columns —
   same box treatment as .nhs-notice above, applied per column.
   ------------------------------------------------------------ */
.nhs-twocol--cards .nhs-twocol__col {
  padding: var(--space-7);
  background: var(--nhs-white);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
}


/* ------------------------------------------------------------
   Feature split — image side
   feature.schema.json's "image_side: left" (4 of 8 uses; default is right)
   flips a two-column media/detail split. The section markup puts the detail
   column first (so blank/default already reads media-right with no CSS),
   and this is the one rule that reorders it for "left". The mobile stack
   order (media always on top) comes free from .nhs-campaign__media's own
   responsive rule — the media wrapper below is deliberately
   .nhs-campaign__media plus this modifier, reusing its sizing/image
   treatment rather than redeclaring it. The token lands directly in the
   section wrapper's modifier class name (`nhs-feature--{{image_side}}`),
   the same pattern the pre-existing engine already used for this field.
   ------------------------------------------------------------ */
.nhs-feature--left .nhs-feature__media { order: -1; }

/* Detail column: meta rows (dates, locations) and stacked links, neither of
   which nhs-campaign carries (it is photo + heading + one CTA only). */
.nhs-feature__meta { display: flex; flex-direction: column; gap: var(--space-2); }
.nhs-feature__meta-row { display: flex; gap: var(--space-2); font-size: var(--fs-body-md); line-height: var(--lh-body-md); }
.nhs-feature__meta-row dt { font-weight: var(--fw-semibold); color: var(--text-muted); }
.nhs-feature__links { display: flex; flex-direction: column; gap: var(--space-2); }


/* ------------------------------------------------------------
   Stat row — dark tone
   stats.schema.json's "tone: dark" (2 uses) reads as every tile going
   forest rather than the section band itself — the section stays on its
   normal ground so a --forest tile still pops. tone blank cycles the
   existing tint/green/teal tile fills below (v2.91; this comment used to
   claim that cycle already existed and it didn't -- no per-stat tone field
   exists to choose one deliberately, colour is by position, same as the
   splash paths and card rows above).
   ------------------------------------------------------------ */
.nhs-stats--dark .nhs-stat { background: var(--bg-inverse); color: var(--text-inverse); }

/* Accent colours on stat tiles (Sept 3 aesthetic review, v2.91). No orange
   tile: forest-on-orange-500 fails the 16px label size (nhs-styles.css §13
   comment). Guarded off .nhs-stats--dark, which already forces every tile
   to --forest at higher specificity -- without the guard this cycle's
   :nth-child specificity would outrank that override and break dark tiles.
   1-of-3 stays the default --green (stats.html's hardcoded class); a 3-stat
   row (the common case) then shows exactly one accent tile. */
.nhs-stats:not(.nhs-stats--dark) .nhs-stat:nth-child(3n+2) { background: var(--nhs-teal-600); color: var(--nhs-white); }
.nhs-stats:not(.nhs-stats--dark) .nhs-stat:nth-child(3n+3) { background: var(--bg-subtle);     color: var(--text-default); }


/* ------------------------------------------------------------
   Species filter — /adopt/available-animals only
   A pressed-state pill row over the live PetPoint grid. State goes through
   aria-pressed, per the handoff's ARIA-not-classes rule — the section's
   inline script (cms/sections/animals.html) toggles the attribute.
   ------------------------------------------------------------ */
.nhs-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.nhs-filter__btn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-5);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-full);
  background: var(--nhs-white);
  font-family: inherit;
  font-size: var(--fs-body-md);
  line-height: var(--lh-body-md);
  font-weight: var(--fw-semibold);
  color: var(--text-default);
  cursor: pointer;
}
.nhs-filter__btn:hover { border-color: var(--text-default); background: var(--bg-subtle); }
.nhs-filter__btn[aria-pressed="true"] {
  background: var(--nhs-forest-500);
  border-color: var(--nhs-forest-500);
  color: var(--text-inverse);
}
.nhs-filter__clear {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-3);
  background: none;
  border: 0;
  font-family: inherit;
  font-size: var(--fs-body-md);
  font-weight: var(--fw-semibold);
  color: var(--text-link);
  text-decoration: underline;
  cursor: pointer;
}
.nhs-filter__clear[hidden] { display: none; }

/* nhs-styles.css's .nhs-card has no [hidden] pairing, so the filter script's
   card.hidden = true (cms/sections/animals.html) had no visible effect, the
   UA default display:none lost to .nhs-card's own display:flex. Whole-card
   click target: one real link (the existing "View {{name}}'s profile"
   anchor) stretched over the card via ::after, rather than a second nested
   anchor around the image/title. */
.nhs-card[hidden] { display: none; }
.nhs-card { position: relative; cursor: pointer; }
.nhs-card__foot .nhs-btn::after { content: ""; position: absolute; inset: 0; }

/* PetPoint grid images rendering at inconsistent heights (v2.90): .nhs-card__media
   is a flex item inside .nhs-card's column flow, and a flex item's automatic
   min-height:auto floors it at its content's intrinsic size, which overrides
   aspect-ratio:4/3 from nhs-styles.css. Petango photos arrive at arbitrary
   aspect ratios with no resize, so every card ended up a different height
   depending on its animal's photo. overflow:hidden establishes a new
   min-height:0, letting aspect-ratio win, exactly like .nhs-action__media
   already does for the same shape of card (nhs-styles.css). */
.nhs-card__media { overflow: hidden; }


/* Typography utility gap: nhs-tokens.css ships --fs-body-sm/--lh-body-sm (used
   internally by the footer legal bar and validation text) but nhs-styles.css
   never turns it into a public utility class the way .nhs-body-lg / .nhs-body-md
   are — fine print (cta, steps, giving) needs exactly this size. */
.nhs-body-sm { font-size: var(--fs-body-sm); line-height: var(--lh-body-sm); }

/* Required-field asterisk. §18 has no marker for this; never colour alone
   is preserved because the required/aria-required attributes carry the
   actual signal (render.php form_fields_html()) — this is the visible echo. */
.nhs-field__required { color: var(--state-error); }


/* ------------------------------------------------------------
   Embed — map / DonorPerfect iframe
   16:9 responsive wrapper. No component in the system frames third-party
   embedded content.
   ------------------------------------------------------------ */
.nhs-embed {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--bg-subtle);
}
.nhs-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}


/* ------------------------------------------------------------
   Donation form — Givecloud inline widget, /donate only
   Rendered in-page (not a cross-origin iframe) by the bridge script in
   head.html, which hydrates the [data-fundraising-form] div below. Real DOM,
   so it sizes to its own natural height and NHS branding (fonts/colors/
   layout) is set in Givecloud's own form styler, confirmed stylable.
   ------------------------------------------------------------ */
.nhs-giving {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: var(--space-10);
  align-items: start;
}
@media (max-width: 1023px) { .nhs-giving { grid-template-columns: 1fr; } }

.nhs-giving__frame {
  border-radius: var(--radius-xl);
  background: var(--bg-subtle);
}


/* ------------------------------------------------------------
   Animal profile page — /adopt/<slug>-<id>/
   Photo gallery (one large photo + stacked thumbnails) and the fact list
   (Age/Sex/Breed/…) are specific to this one page and have no shipped
   component. The fact rows reuse .nhs-feature__meta-row's dt/dd pairing
   but need their own spacing: feature's meta rows are compact label-value
   pairs (a date, a location); an animal's fact list is a bordered table
   the wireframe specifies, so this scopes a different row treatment onto
   the same element rather than forcing one visual to fit both contexts.
   ------------------------------------------------------------ */
.nhs-animal__photo-main {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius-xl);
  background: var(--bg-subtle);
}
.nhs-animal__photo-thumb {
  width: 100%;
  margin-top: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--bg-subtle);
}
.nhs-animal__facts .nhs-feature__meta-row {
  justify-content: space-between;
  padding-block: var(--space-2);
  border-bottom: 1px solid var(--nhs-forest-100);
}
.nhs-animal__facts .nhs-feature__meta-row dt { min-width: 0; }


/* ------------------------------------------------------------
   Optional-field collapse
   The token engine has no conditionals (render.php render_tokens()), so an
   optional schema field that is left blank still renders its wrapper tag —
   an empty <p>, or worse, an empty *pill-shaped, bordered* .nhs-btn with
   nothing in it. The previous site.css carried a matching :empty rule for
   every one of its own optional-field classes; this is that same
   convention ported to the nhs- vocabulary. Blanket per shared class
   (same class serves both optional and always-filled contexts in a few
   places) rather than one rule per section, matching the old file's own
   scope — an accidentally-empty required field collapsing cleanly is
   still strictly better than an empty box.
   ------------------------------------------------------------ */
.nhs-overline:empty,
.nhs-intro__title:empty, .nhs-intro__body:empty,
.nhs-h2:empty, .nhs-h3:empty, .nhs-h4:empty, .nhs-h5:empty,
.nhs-body-lg:empty, .nhs-body-md:empty, .nhs-body-sm:empty,
.nhs-action__body:empty,
.nhs-card__meta:empty,
.nhs-notice__label:empty,
.nhs-feature__meta:empty, .nhs-feature__links:empty,
.nhs-giving__note:empty,
.nhs-btn:empty,
.nhs-link--standalone:empty {
  display: none;
}


/* ------------------------------------------------------------
   CMS review chrome — staging only, never shipped in a client deliverable
   ------------------------------------------------------------ */

/* [Client copy needed: …] markers mark_pending() (render.php) wraps —
   visible so a reviewer cannot miss an unresolved placeholder, never
   colour alone (it is also literal bracketed text). */
.pending-copy {
  background: #fff3cd;
  color: #7a5300;
  border-radius: 4px;
  padding: 0 4px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* Skip link — nhs-styles.css ships .nhs-visually-hidden with no
   focus-reveal partner (README, "Behaviour the CSS does not implement"
   list has no entry for this one either — a one-rule gap, not an
   oversight). */
.nhs-skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 70;
  padding: var(--space-3) var(--space-5);
  background: var(--nhs-white);
  border-radius: var(--radius-full);
  transform: translateY(-200%);
}
.nhs-skip-link:focus { transform: none; }


/* ------------------------------------------------------------
   Aug 26 alignment meeting: tighten section spacing
   .nhs-band was 120px block padding (--space-13) on desktop; Kim/Rebecca
   flagged excessive white space between sections. One step down the same
   scale, each breakpoint moved down a notch too. Must follow nhs-styles.css's
   own --tight/--xtight block (same specificity, source order decides), see
   that file's comment at its §padding block.

   Sept 3 aesthetic review: tightened one step further on desktop only
   (96 -> 80, the same value nhs-styles.css's own --tight modifier already
   uses for notice.html, not a new number). render.php's band alternation
   (v2.87) means two adjacent sections are now reliably different colours,
   so the same-colour padding merge below almost never fires any more --
   worth revisiting together if the gap still reads as too much once Rawle
   has seen it live. Tablet/mobile left alone: they already matched
   --tight's own values at those breakpoints before this change.
   ------------------------------------------------------------ */
.nhs-band { padding-block: var(--space-11); }  /* 80, was 96 */
@media (max-width: 1023px) { .nhs-band { padding-block: var(--space-10); } }  /* 64, unchanged */
@media (max-width: 767px)  { .nhs-band { padding-block: var(--space-9);  } }  /* 48, unchanged */
/* 480px step (--space-9, 48) already matched the new 767px step, left as-is. */


/* ------------------------------------------------------------
   Rich-text paragraph spacing
   nhs-styles.css:30 zeroes all <p> margins and the system spaces siblings
   with flex gap instead. Several section types drop rich body text straight
   into a plain wrapper (no .nhs-measure, no .nhs-stack), so multi-paragraph
   copy ran together with no visible break (Aug 26 meeting: "text spacing/
   paragraph breaks not rendering properly"). Bare .nhs-body-md/-lg covers
   cta.body and steps[].body too (v2.74 rich-text promotion, no .nhs-measure
   wrapper there); rich.html and twocol.html already use an .nhs-stack and
   need no fix.
   ------------------------------------------------------------ */
.nhs-notice__body > p + p,
.nhs-accordion__panel > p + p,
.nhs-action__body > p + p,
.nhs-intro__body > p + p,
.nhs-hero__body > p + p,
.nhs-body-md > p + p,
.nhs-body-lg > p + p {
  margin-block-start: var(--space-4);
}


/* ------------------------------------------------------------
   Intro measure widened
   .nhs-intro (nhs-styles.css:917) caps at 60ch, narrower than the system's
   own 72ch prose measure (--measure-max) that .nhs-measure uses everywhere
   else. Flagged at the Aug 26 meeting on the Volunteer Opportunities intro,
   but .nhs-intro is shared by 7 section types, so this widens all of them
   rather than a one-off override on that one page.
   ------------------------------------------------------------ */
.nhs-intro { max-width: var(--measure-max); }

/* .nhs-intro__body and .nhs-action__body already collapse when empty (see
   the :empty block above); .nhs-hero__body was missing from that list, so a
   blank hero body still ate a flex gap. */
.nhs-hero__body:empty { display: none; }


/* ------------------------------------------------------------
   Footer social icons more prominent (Aug 26 meeting)
   Facebook now leads (footer.html), glyphs bumped 19px -> 24px inline in
   the SVGs themselves. The 44x44 .nhs-footer__social-link hit target
   (nhs-styles.css §5) is an accessibility minimum and stays untouched;
   only the gap between the two circles grows to match the bigger glyphs.
   ------------------------------------------------------------ */
.nhs-footer__social { gap: var(--space-3); }


/* ------------------------------------------------------------
   Animal cards stop stretching when a row doesn't fill
   nhs-styles.css:136 .nhs-grid--4 is repeat(auto-fit, minmax(240px, 1fr)):
   auto-fit collapses empty tracks and lets 1fr redistribute the freed space,
   stretching whatever cards ARE there to fill the row. Correct for cards.html
   (an intentional, fixed count of cards should fill its row evenly), wrong
   for animals.html: 20 real animals rarely divides evenly by however many
   columns fit at a given width, and the JS species filter can drop the
   visible count to 1 or 2 at any time, either way stretching a leftover
   card to full row width, badly (reported live, both the homepage teaser
   and /adopt/available-animals). auto-fill reserves the same track count
   but leaves unused ones empty instead of collapsing them, so real cards
   keep their natural minmax size; a completely full row renders identically
   either way, this only changes an incomplete one.
   ------------------------------------------------------------ */
.nhs-animals .nhs-grid--4 { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }


/* ------------------------------------------------------------
   Splash pop-over (Aug 31 meeting action item, Rawle)
   New section type; the section script (splash.html) toggles [hidden] and
   locks body scroll, this only styles the two states. z-index 80 clears
   the header (50), mobile drawer (60) and skip link (70), the tallest
   stack already on the page.
   ------------------------------------------------------------ */
.nhs-splash {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
}
.nhs-splash[hidden] { display: none; }
.nhs-splash__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 27, 14, 0.55); /* nhs-forest-500 wash, matches --bg-inverse's hue */
}
.nhs-splash__dialog {
  position: relative;
  width: min(480px, 100%);
  max-height: 100%;
  overflow-y: auto;
  background: var(--bg-page);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-overlay);
  padding: var(--space-8) var(--space-6) var(--space-6);
}
.nhs-splash__close {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--text-default);
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--text-default);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.nhs-splash__media { margin-block-end: var(--space-4); }
.nhs-splash__media img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-md);
}
.nhs-splash__dismiss { align-self: center; }

/* Splash paths (v2.85) — the three-path wayfinder inside the pop-over.
   Explicit repeat(3,1fr), NOT .nhs-grid--3: auto-fit's 324px floor orphans a
   third card onto its own row between roughly 1080 and 1128px, which reads as
   broken inside a modal. */
.nhs-splash__paths { display: grid; gap: var(--space-6); grid-template-columns: 1fr; }

/* position: relative is the containing block for the stretched link below.
   The background is the fallback for a 4th+ card; 1-3 are recoloured next. */
.nhs-splash__paths .nhs-action {
  position: relative;
  background: var(--bg-subtle);
  color: var(--text-default);
}

/* Colour by position, not by a schema field: the palette is a design decision,
   not an editorial one, so staff cannot produce a mismatched set.
   ponytail: nth-child, add a `fill` select only if NHS ever needs to reorder
   the paths without reordering the colours. */
.nhs-splash__paths .nhs-action:nth-child(1) { background: var(--nhs-green-500);  color: var(--text-on-primary); }
.nhs-splash__paths .nhs-action:nth-child(2) { background: var(--nhs-orange-500); color: var(--text-on-accent-orange); }
.nhs-splash__paths .nhs-action:nth-child(3) { background: var(--nhs-teal-600);   color: var(--nhs-white); }

/* Whole card is the click target. The button stays the only real link, so the
   accessible name is its label and there is one tab stop per path. */
.nhs-splash__paths .nhs-action .nhs-btn::after { content: ""; position: absolute; inset: 0; }

/* Wide only when it is actually carrying paths — an empty repeat still renders
   the wrapper, so this tests for a card, not the container. The announcement
   variant keeps its 480px. */
.nhs-splash__dialog:has(.nhs-splash__paths .nhs-action) { width: min(1080px, 100%); }

@media (min-width: 1024px) {
  .nhs-splash__paths { grid-template-columns: repeat(3, 1fr); }
  /* 16:9, not the card default 4:3 — saves ~55px per card, the difference
     between fitting and scrolling on a 768px-tall laptop. */
  .nhs-splash__paths .nhs-action__media { aspect-ratio: 16 / 9; }
}
@media (max-width: 1023px) {
  .nhs-splash__paths .nhs-action__media { display: none; }
  .nhs-splash__paths .nhs-action { padding: var(--space-5); gap: var(--space-2); }
}

/* Teal outline button fix: §13 gives teal cards white text, but
   .nhs-btn--tertiary is a forest border/label by default, under 3:1 on
   teal-600 (effectively invisible). Unscoped to .nhs-action--teal generally,
   not just the splash, so every future teal card benefits. */
.nhs-action--teal .nhs-btn--tertiary,
.nhs-splash__paths .nhs-action:nth-child(3) .nhs-btn--tertiary,
.nhs-cards .nhs-action:nth-child(4n+2) .nhs-btn--tertiary {
  color: var(--nhs-white);
  border-color: var(--nhs-white);
}
.nhs-action--teal .nhs-btn--tertiary:hover,
.nhs-splash__paths .nhs-action:nth-child(3) .nhs-btn--tertiary:hover,
.nhs-cards .nhs-action:nth-child(4n+2) .nhs-btn--tertiary:hover {
  background: var(--nhs-white);
  color: var(--nhs-teal-600);
}

/* Accent colours on card rows (Sept 3 aesthetic review, v2.91): the design
   system ships four .nhs-action fills (tint/teal/orange/green) with
   documented contrast ratios, but cards.html hardcodes --tint on every card,
   so teal and coral/orange never reached a page outside the splash
   pop-over. Same "colour by position, not by a schema field" precedent as
   the splash paths above (this is a design decision, not an editorial one).
   1-of-4 stays the existing --tint default (card 1's class in cards.html);
   this only overrides the other three so a 3-card row (the common case)
   shows one accent colour, not two, keeping this well inside Rawle's
   <=20% page coverage guidance. */
.nhs-cards .nhs-action:nth-child(4n+2) { background: var(--nhs-teal-600);   color: var(--nhs-white); }
.nhs-cards .nhs-action:nth-child(4n+3) { background: var(--nhs-orange-500); color: var(--text-on-accent-orange); }
.nhs-cards .nhs-action:nth-child(4n+4) { background: var(--nhs-green-500);  color: var(--text-on-primary); }


/* ------------------------------------------------------------
   Buttons wrap instead of clipping (Kim/Philip, Sept 2026)
   nhs-styles.css:155 sets white-space: nowrap and a fixed height on every
   .nhs-btn, so a long label ("Apply for a Thrift Store Role", the bracketed
   placeholders) overflows its pill on narrow screens. Let the label wrap and
   the pill grow; a one-line button is pixel-identical (min-height equals the
   old fixed height and inline-flex still centres it).
   ------------------------------------------------------------ */
.nhs-btn { white-space: normal; height: auto; text-align: center; }
.nhs-btn--lg { min-height: var(--btn-h-lg); padding-block: var(--space-2); }
.nhs-btn--md { min-height: var(--btn-h-md); padding-block: var(--space-1); }
.nhs-btn--sm { min-height: var(--btn-h-sm); padding-block: var(--space-1); }


/* ------------------------------------------------------------
   Logo row (partners / sponsors / memberships), section type "logos"
   Kim, Sept 2 review: "Our Community Partners" before the footer, plus
   Humane Canada / Medicine Wheel / Pride marks. One grid of equal cells,
   logos scaled to fit a fixed box so mismatched artwork sits on one line;
   caption underneath. A cell with no link still renders as a plain block
   (an empty href is stripped like any other blank CTA).
   ------------------------------------------------------------ */
.nhs-logos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-6);
  align-items: start;
}
.nhs-logos__item { text-align: center; }
.nhs-logos__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  color: inherit;
}
.nhs-logos__media {
  width: 100%;
  height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.nhs-logos__media img { max-width: 160px; max-height: 96px; width: auto; height: auto; object-fit: contain; }
.nhs-logos__caption { color: var(--text-muted); }
a.nhs-logos__link:hover .nhs-logos__caption { text-decoration: underline; }

/* Scrolling marquee variant (Sept 3 aesthetic review, v2.93). Off by
   default: logos.html always renders two copies of the same repeat (one
   aria-hidden), but only scroll:on switches the layout to run them side by
   side; the duplicate stays hidden and the grid above is untouched
   otherwise. The scroller's own width is content-sized (2x one track) and
   translating it by exactly -50% moves exactly one track-width, so the loop
   has no visible seam or jump back to start. Paused on hover so a caption
   or logo can actually be read, and dropped back to the static grid under
   reduced motion -- a moving row of logos is exactly the kind of motion
   that preference exists to opt out of. */
.nhs-logos__track--dup { display: none; }
.nhs-logos--scroll .nhs-logos-scroller {
  overflow: hidden;
}
/* ponytail: no gap between the two tracks so translateX(-50%) lands exactly
   at the seam (a scroller-level gap would need extra math to stay exact);
   the one seam between the last logo of track 1 and the first of track 2
   sits flush instead of at the --space-6 item rhythm. Add gap-aware width
   math only if that seam is visibly bothersome with real logos in place. */
.nhs-logos--scroll .nhs-logos__track {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--space-6);
}
.nhs-logos--scroll .nhs-logos__item { flex: 0 0 160px; }
@media (prefers-reduced-motion: no-preference) {
  .nhs-logos--scroll .nhs-logos-scroller {
    display: flex;
    width: max-content;
    animation: nhs-logos-scroll 30s linear infinite;
  }
  .nhs-logos--scroll .nhs-logos-scroller:hover,
  .nhs-logos--scroll .nhs-logos-scroller:focus-within {
    animation-play-state: paused;
  }
  .nhs-logos--scroll .nhs-logos__track--dup {
    display: flex;
  }
}
@keyframes nhs-logos-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}


/* ------------------------------------------------------------
   Header collapse moves from 767 to 1023 (Philip, Sept 3: "the menu on
   smaller screens tends to collapse"). Screenshots at 800 and 1024 showed
   every multi-word label wrapping onto two or three lines ("Get / Involved",
   "Programs / & / Services") because the right-hand stack cannot fit four or
   five labels plus chevrons beside the logo. nhs-styles.css's own §2 comment
   anticipated this: "If the real link set proves too wide at 768, the collapse
   moves to 1023." Tablets get the drawer; desktop labels stop wrapping.
   ponytail: if the campaign item returns to the nav and 1024 to ~1140 wraps
   again, move this breakpoint to 1279, do not shrink the type.
   ------------------------------------------------------------ */
.nhs-nav__link { white-space: nowrap; }
@media (max-width: 1023px) {
  .nhs-nav__list { display: none; }
  .nhs-nav__toggle { display: inline-flex; }
  .nhs-header__row--utility { display: none; }
}


/* ------------------------------------------------------------
   Image focal point (v2.87, replaced the img_align preset select) and image
   fit (v2.89, cover/contain per placement -- the "Call or Email" card holds
   the NHS logo, not a photo, and cover cropped its wordmark unpredictably;
   contain is the escape hatch, chosen per placement in the admin, default
   stays cover so every existing photo placement is unaffected). render.php
   composes --focal / --fit as inline custom properties on the media
   wrapper from the admin's picker (index.php); this is just the
   object-fit/object-position hookup. Focal point still works under contain:
   it positions the whole unclipped image within the box instead of choosing
   a crop point. Unset falls back to a centered cover crop, today's existing
   default. A separate mobile focal value shipped in v2.87 and was removed in
   v2.90: a photo's subject doesn't move when the viewport narrows, so a
   second picker per image was redundant complexity for staff.
   ------------------------------------------------------------ */
.nhs-hero__media img,
.nhs-action__media img,
.nhs-campaign__media img {
  object-fit: var(--fit, cover);
  object-position: var(--focal, 50% 50%);
}


/* ------------------------------------------------------------
   Hero and feature media height cap at desktop (v2.89, replaces the v2.88
   aspect-ratio + align-self:center rule -- confirmed wrong: it floated a
   small image with an empty tint gap above AND below on a tall panel, which
   read as broken rather than intentional). .nhs-hero and .nhs-campaign
   (feature.html's desktop split) are both 50/50 grids (nhs-styles.css §6,
   §12); grid items default to align-items: stretch, so the media column
   always stretches to match the panel's height, and the panel's height is
   unbounded on a long headline. Leaving align-items: stretch alone (the
   default, unchanged) keeps today's existing look for every normal-length
   headline -- the photo tracks the panel's height exactly like it always
   has. max-height only bites for a genuine outlier: per the CSS box
   alignment spec, a stretched item whose used size is clamped by max-height
   falls back to start-alignment for the leftover space, so the photo
   anchors near the top of its column (beside the panel's own top-aligned
   content) with the section's tint background showing below it, not a gap
   on both sides. 720px is tuned for roughly a 3-line headline's panel
   height; adjust if a future headline still looks off.
   ------------------------------------------------------------ */
@media (min-width: 1024px) {
  .nhs-hero__media,
  .nhs-campaign__media { max-height: 720px; }
}


/* ------------------------------------------------------------
   Hero headline scaling (v2.89). --fs-display-xl (nhs-tokens.css) is a
   vw-based clamp: it scales against the VIEWPORT, but .nhs-hero__title
   actually lives in a column that is only ~50% of the viewport (the hero's
   50/50 grid). Two compounding problems, not just one: the clamp scales
   too fast for a half-width column, AND its 5.25rem/84px ceiling is itself
   too large for that column -- even scaled down gently, 84px bold text
   needs roughly 46px per character, so a ~600px column (the widest this
   column gets, container capped at nhs-container's 1440px max) still can't
   fit more than a word or two per line at that size, regardless of the
   growth rate. A headline like "Making New Best Friends Since 1966" wrapped
   to six short lines instead of the two or three the design intends -- and
   that inflated the panel's height in the first place (see the cap above).
   Scopes a container query to .nhs-hero so the title scales against its
   own column's REAL rendered width (self-adjusting if the hero's
   proportions ever change again, unlike a hand-tuned vw coefficient), with
   both a gentler growth rate and a lower ceiling (4.5rem/72px, tuned so
   "Making New" / "Best Friends" / "Since 1966" each fit one line at the
   widest hero width -- three lines, matching the "reference hero" precedent
   nhs-styles.css §6 already documents as normal). Only established at
   >=1024, matching where the 50/50 grid is actually active; below that the
   hero stacks to one column and the token's own viewport-relative sizing
   already behaves correctly at full width. .nhs-hero__title is not used
   outside hero.html, so this is safely scoped to one selector.

   Excludes .nhs-hero--bleed (v2.93): a full-bleed hero's panel column is the
   FULL container width, not the 50/50 split this clamp was tuned for, so it
   would jump straight to the 4.5rem ceiling on a short headline and undo
   the whole point of this fix. The token's own viewport-relative clamp
   already behaves correctly there.
   ------------------------------------------------------------ */
@media (min-width: 1024px) {
  .nhs-hero:not(.nhs-hero--bleed) { container-type: inline-size; }
}
@container (min-width: 1px) {
  /* line-height as a unitless ratio (not a matching clamp) so it always tracks
     the font-size above correctly -- the inherited --lh-display-xl clamp was
     tuned for the original 84px ceiling and reads too loose against 72px. */
  .nhs-hero:not(.nhs-hero--bleed) .nhs-hero__title { font-size: clamp(2.5rem, 0.2rem + 5.75cqw, 4.5rem); line-height: 1.1; }
}


/* ------------------------------------------------------------
   Full-bleed hero (Sept 3 aesthetic review, v2.93). nhs-styles.css already
   declares .nhs-hero--bleed (single column, transparent panel) but never
   finishes it: nothing emits the class, and the media has no positioning to
   sit BEHIND the panel, so both would have just stacked in the single
   column. Completed here rather than in that file (kept byte-identical to
   the handoff, see this file's own header): the image goes absolute/inset:0
   as the section's only sizing content, the panel floats on top, and a
   gradient scrim keeps the white text (already set by the base rule)
   readable regardless of the photo underneath. hero.schema.json's new
   `layout` field interpolates the class, same as feature.html's
   nhs-feature--{{image_side}}; blank layout is today's 50/50 split,
   unaffected. */
.nhs-hero--bleed {
  min-height: min(640px, 80vh);
}
.nhs-hero--bleed .nhs-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.nhs-hero--bleed .nhs-hero__panel {
  z-index: 1;
  max-width: 640px;
  background: linear-gradient(90deg, rgba(0, 27, 14, 0.75) 0%, rgba(0, 27, 14, 0.35) 70%, transparent 100%);
}


/* ------------------------------------------------------------
   Blank-image guard for the hero media box (v2.93). render.php's
   strip_empty_elements() removes .nhs-hero__media entirely when {{img}} is
   blank, IF its only content is the bare <img src="">. The carousel markup
   below (hero.html) always renders the carousel-nav buttons even with zero
   slides (a repeat with no items still leaves the static prev/next/pause
   buttons in the template), so that PHP stripping can no longer match. CSS
   fills the gap instead: hide the whole box outright when the base image
   has no src, same visual outcome as the old removal (an empty grid
   column), no PHP change needed since the carousel nav is already
   display:none whenever there are no real slides (below) regardless of
   whether the base image itself is set. */
.nhs-hero__media:has(> img[src=""]) { display: none; }


/* ------------------------------------------------------------
   Hero carousel (Sept 3 aesthetic review, v2.93). hero.schema.json's new
   "slides" repeat lets staff add extra images to rotate through; 0 or 1
   slide leaves the section exactly as it always rendered (single static
   image, nav hidden below). 2+ slides hides the base image and shows the
   slide stack instead -- .nhs-hero__slide images are absolutely positioned
   over each other and hero.html's inline script (scoped via
   .closest('.nhs-hero'), same convention as splash.html/animals.html)
   toggles which one is [hidden]. No state classes: current slide via
   [hidden], current dot via [aria-current], play state via the pause
   button's [aria-pressed] -- all ARIA/attribute driven per nhs-header.js's
   house rule.
   ------------------------------------------------------------ */
.nhs-hero__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: var(--fit, cover);
  object-position: var(--focal, 50% 50%);
}
.nhs-hero__media:has(.nhs-hero__slide) > img:not(.nhs-hero__slide) { display: none; }

.nhs-hero__carousel-nav {
  display: none;
  position: absolute;
  inset-inline: var(--space-4);
  inset-block-end: var(--space-4);
  z-index: 1;
  align-items: center;
  gap: var(--space-3);
}
.nhs-hero__media:has(.nhs-hero__slide) .nhs-hero__carousel-nav {
  display: flex;
}
.nhs-hero__carousel-btn {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  border: none;
  background: rgba(0, 27, 14, 0.55);
  color: var(--nhs-white);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.nhs-hero__carousel-btn:hover { background: rgba(0, 27, 14, 0.75); }
.nhs-hero__carousel-pause { margin-inline-start: auto; }
/* Play/pause glyph is CSS-drawn (two bars vs. a triangle), not markup text,
   so the button's accessible name stays the JS-managed aria-label alone. */
.nhs-hero__carousel-pause::before { content: "\275A\275A"; font-size: 0.7rem; }
.nhs-hero__carousel-pause[aria-pressed="true"]::before { content: "\25B6"; }
.nhs-hero__carousel-dots {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.nhs-hero__carousel-dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border-radius: var(--radius-full);
  border: 2px solid var(--nhs-white);
  background: transparent;
  cursor: pointer;
}
.nhs-hero__carousel-dot[aria-current="true"] { background: var(--nhs-white); }


/* ------------------------------------------------------------
   Hidden-state CSS bug (v2.88). Both .nhs-validation (nhs-styles.css) and
   .nhs-notice (above) set display directly on the class with no [hidden]
   exception, so an author rule of equal specificity always beats the
   browser's built-in [hidden]{display:none} UA rule -- the contact form's
   success and error messages rendered visible together regardless of the
   hidden attribute render.php/form.html's JS correctly set. Confirmed safe:
   .nhs-notice is also used by the always-visible `notice` section type
   (cms/sections/notice.html), which never carries hidden, so this only
   affects elements that already opted into being hidden.
   ------------------------------------------------------------ */
.nhs-notice[hidden],
.nhs-validation[hidden] { display: none; }


/* ------------------------------------------------------------
   Mobile drawer sub-nav (v2.87). Sub-pages were desktop-hover-only --
   unreachable on mobile/tablet once the header collapse above moved to
   1023 -- so render.php's nav_drawer_html() wraps a parent that has
   children in a native <details>/<summary>, no JS required, keyboard and
   screen-reader correct for free. .nhs-drawer__link already reserved a
   trailing gap for a chevron (nhs-styles.css §2); this fills it and styles
   the indented sublist underneath.
   ------------------------------------------------------------ */
.nhs-drawer__summary {
  cursor: pointer;
  list-style: none;
}
.nhs-drawer__summary::-webkit-details-marker { display: none; }
.nhs-drawer__summary .nhs-nav__chevron { transition: transform var(--motion-fast) var(--motion-ease); }
.nhs-drawer__details[open] > .nhs-drawer__summary .nhs-nav__chevron { transform: rotate(180deg); }
.nhs-drawer__sublist { display: flex; flex-direction: column; padding-inline-start: var(--space-4); }
.nhs-drawer__sublink {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-body-md);
  line-height: var(--lh-body-md);
  color: var(--text-default);
  text-decoration: none;
  border-bottom: 1px solid var(--nhs-forest-100);
}
.nhs-drawer__sublist li:last-child .nhs-drawer__sublink { border-bottom: none; }
.nhs-drawer__sublink[aria-current="page"] { color: var(--text-primary-on-light); }


/* ------------------------------------------------------------
   Footer recognition row + credit line (Kim, Sept 2 review)
   Humane Canada membership, the Medicine Wheel beside the land
   acknowledgement link's column, the Progress Pride mark, and a thank-you to
   the two agencies. Marks sit on the forest ground at a fixed height so
   mismatched artwork lines up; the credit is body-sm tint like the legal row.
   Each mark's wrapper is stripped when its image is blank (see
   strip_empty_elements), so the row collapses cleanly with none set.
   ------------------------------------------------------------ */
.nhs-footer__recognition {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding-block: var(--space-6);
  border-top: 1px solid var(--nhs-forest-400);
}
.nhs-footer__badges { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-6); }
.nhs-footer__badge { display: flex; align-items: center; height: 64px; }
.nhs-footer__badge img { height: 64px; width: auto; max-width: 160px; object-fit: contain; }
.nhs-footer__credit {
  max-width: 44ch;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--nhs-tint);
}
.nhs-footer__credit a { color: inherit; }
@media (max-width: 767px) {
  .nhs-footer__recognition { flex-direction: column; align-items: flex-start; }
}
