/* =============================================
   Easterseals Arkansas - Programs
   Program single pages, the /programs/ archive, and the two audience hubs.
   Builds on css/base.css + css/site.css tokens. Brand tokens only.
   Navy #004473 headings, orange #cf4b04 CTAs, yellow #ffa300 accents,
   circular image crops, 80px section rhythm.
   ============================================= */

/* 2026 program hero. Measured directly off the dev WordPress implementation
   at /programs/little-rock-developmental-preschool/ (2026-09-15), which is a
   better reference than the Figma frame because it is what the client actually
   has. Structure there:

     .subnav-hero-block   flex, bg #ffc464 + white pattern, padding-left 5%
     .subnav-hero-content flex 0 1 55%, #007cb1, radius 0 0 30px 30px, pad 70/56
     .subnav-hero-image   flex 1 1 45%, photo to the viewport edge

   The amber is the BLOCK's own background showing through the left gutter --
   not a swirl graphic, which is what I assumed from the mockup.

   CONTRAST: #007cb1 gives white 4.65:1. It passes with almost no margin, so
   every token on the panel is pure #fff -- a yellow eyebrow is 2.32:1 here and
   even rgba(255,255,255,.92) composites to 4.20:1. */
.program-hero {
  position: relative;
  display: flex;
  align-items: flex-start;
  padding: 0 0 0 5%;
  color: #fff;
}
.program-hero-copy {
  position: relative;
  z-index: 1;
  flex: 0 1 55%;
  /* Fill the hero's height. .program-hero is a flex row, so its height is
     max(panel, media column). From 901px up nothing in the media column adds
     height (#160, the min-width: 901px block below), so the panel's content
     sets the hero's height on every page and the column stretches to it. The
     stretch here stays as a guard: a 2:1 photo used to outgrow the panel past
     ~1700px and the amber ground showed through below the panel. */
  align-self: stretch;
  background: var(--eas-blue); /* #007cb1 */
  /* Bottom corners belong to .program-secnav-bar, which sits directly beneath
     and reads as this panel's bottom row. */
  border-radius: 0;
  padding: 80px 56px 50px;
}
/* Orange panel variant. The Figma gives the two hub pages (/get-support/ and
   /start-here/) an orange hero where the 20 program detail pages keep the blue
   one. /start-here/ has since gone back to the blue panel (eas-easterseals#194,
   "very aggressive"), so only /get-support/ carries this class. A modifier, so it only takes effect on an element carrying the class:
   the other 20 pages are untouched. Specificity (0,2,0) beats the base
   .program-hero-copy rule (0,1,0) regardless of source order.
   The amber sliver from .program-hero-media::before is deliberately unchanged. */
.program-hero--accent .program-hero-copy {
  background: var(--color-primary);
}

.program-hero-media {
  position: relative;
  flex: 1 1 45%;
}
/* The amber ground is painted from the MEDIA column, not from .program-hero,
   so its height tracks the column. From 901px up every media column, photo or
   pattern, stretches to the panel's height (#160, the min-width: 901px block
   below), so the amber runs the full height of the panel on every hero. The
   hero's overhang, its defining move, is the section nav: .program-secnav-bar
   hangs below the column and the amber ground and onto the section below. */
.program-hero-media::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 100%;
  width: 100vw;
  background-color: #ffc464;
  background-image: url('/img/decor/background-pattern-white-v3.png');
  background-repeat: repeat;
  pointer-events: none;
}
.program-hero-media img {
  width: 100%;
  /* A 2:1 crop is the fallback only. From 901px up the photo fills the column
     (#160, the min-width: 901px block below) and at 900px and below the
     stacked layout caps its height (the max-width: 900px block). */
  aspect-ratio: 2 / 1;
  object-fit: cover;
  border-radius: 0;
}

.program-hero--no-media .program-hero-copy {
  flex: 1 1 auto;
  max-width: 860px;
}

/* ---------- Hero with no photograph (the /programs/ hub, and the 2 programs
   whose only image is the shared gallery-placeholder graphic) ----------
   The amber ground lives on the MEDIA column, so dropping the column drops the
   hero. The pattern variant keeps the column and fills it with the amber ground
   itself rather than a photo. It is sized like every other media column: from
   901px up it stretches to the hero's height (the min-width: 901px block
   below), so the amber runs the full height of the panel and the hero is as
   tall as the panel's content. The column used to be pinned to
   clamp(240px, 19vw, 270px) with the panel held 70px taller so it overhung
   onto white; #160 dropped both, because the overhang is now the section nav
   bar on every page that has one. The hub has no section nav, so its panel
   ends flat with square corners, the same as /start-here/ (rounded corners
   would show the amber in their cut-outs). At 900px and below the column is
   hidden (the max-width: 900px block). */
.program-hero-media--pattern {
  background-color: #ffc464;
  background-image: url('/img/decor/background-pattern-white-v3.png');
  background-repeat: repeat;
}

/* ---------- Desktop hero fill (#160) ----------
   From 901px up every hero in this family is as tall as its panel's content,
   and the media column, photo or pattern, is exactly as tall as the hero, so
   the amber ground beside the panel runs its full height on every page. The
   column stretches. A photo is taken out of flow and pinned to the column's
   edges (picture.img-webp is display: contents, so the column is its
   containing block) and covers it (object-fit: cover is on the base rule).
   Nothing in the column adds height of its own, so a wide viewport cannot
   make the photo push the hero taller, and the accent heroes (/get-support/,
   /start-here/) follow the same rule: their eyebrow, heading and intro set
   the height. Nothing here applies at 900px and below. */
@media (min-width: 901px) {
  .program-hero-media {
    align-self: stretch;
  }
  .program-hero-media img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
  }
}
.program-hero-eyebrow {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: #fff; /* was yellow: 2.32:1 on the #007cb1 panel. White = 4.65:1. */
  margin-bottom: 10px;
}
.program-hero h1 {
  color: #fff;
  font-size: clamp(2rem, 4vw, 3rem);
  font-weight: 800;
  line-height: 1.1;
  margin: 0 0 16px;
}
.program-hero-intro {
  font-size: 1.125rem;
  color: #fff; /* NOT rgba: 92% white composites to 4.20:1 on #007cb1 */
  line-height: 1.6;
  margin-bottom: 26px;
}
.program-hero-ctas {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}
/* CD-230 follow-up: give the primary CTA a visible boundary on the blue panel.
   .program-hero-copy paints itself --eas-blue #007cb1 and .btn-primary fills
   with --color-primary #cf4b04. Those two are 1.03:1 apart in LUMINANCE, so
   although the orange reads clearly in colour, the button has no edge at all
   under luminance-only perception (greyscale, many forms of colour vision
   deficiency, low vision, bright sunlight), and WCAG 1.4.11 wants 3:1 for a UI
   component boundary. Its sibling .btn-outline-light already carries a 2px white
   border at 4.65:1, so the two CTAs were inconsistent as well as inaccessible.
   The same white border here gives the boundary at 4.65:1 and keeps the brand
   orange as the primary fill.

   The padding is reduced by exactly the border width so the button's rendered
   box does not change. box-sizing:border-box (base.css:35) does NOT cover this:
   the button is an auto-width inline-flex element with no set width, so a border
   adds to its outer size rather than eating into it. The effective padding here
   is 14px 32px from .btn-primary (base.css:118), NOT the 13px 28px on .btn, so
   the compensation is 12px 30px. */
.program-hero-ctas .btn-primary {
  border: 2px solid #fff;
  padding: 12px 30px;
}

/* ---------- Figma 2026 section headings ----------
   The frame renders the major centered section headings and the About benefit
   line in brand orange (#cf4b04, >= 4.5:1 on white, and large-text on the
   pale-yellow staff panel). Overrides the default navy section h2 (site.css). */
.program-audiences .section-head h2,
.program-locations .section-head h2,
.program-staff .section-head h2,
.program-about-copy h2 {
  color: var(--color-primary);
}

/* ---------- Program staff panel (Figma pale-yellow rounded ground) ----------
   Circular-photo staff cards sit on a pale-yellow inset panel, matching the
   frame. The section itself carries no band background; the panel is the
   inner container. */
.program-staff--panel {
  padding: var(--section-spacing) 0;
}
.program-staff--panel > .container {
  background: var(--eas-pale-yellow); /* #ffe3b3 */
  border-radius: 20px;
  padding: 56px clamp(24px, 4vw, 56px);
}

/* ---------- Section nav: the hero's bottom row, pinning as a blue sliver ----
   A SIBLING of .program-hero, not a child of the panel. position:sticky is
   confined to its parent's box, so a nav inside .program-hero-copy stops
   sticking the moment the panel scrolls past (measured -477px). As a direct
   child of <article class="program"> its containing block spans the page.

   At rest it reads as the panel's bottom row: same 5% left offset, same 55%
   width, and it carries the 30px bottom corners the panel gives up. It is the
   hero's overhang: on desktop it hangs below the photo and the amber ground,
   over the top of the next section (#160, the block after these rules). */
.program-secnav {
  position: sticky;
  top: var(--eas-header-h, 96px);
  z-index: 40;
  margin-left: 5%;
}
.program-secnav-bar {
  width: 55%;
  display: flex;
  gap: 24px;
  padding: 14px 56px 15px;
  background: var(--eas-blue);
  border-radius: 0 0 30px 30px;
  transition: box-shadow 0.18s ease, width 0.18s ease;
}
.program-secnav.is-stuck .program-secnav-bar {
  box-shadow: 0 6px 18px rgba(0, 68, 115, 0.18);
}
/* Pinned, the bar widens from 55% to 95% of the nav, so the sliver under the
   header reads as a full-width bar instead of half the page
   (iprov-agency/eas-easterseals#185 on /get-support/,
   iprov-agency/eas-easterseals#195 on the program pages), and its row of
   links is centred in it (Jen, 2026-10-20). The left edge stays on the 5%
   line. Only the width changes, never the height, so nothing below moves.
   The width eases over 0.18s with the shadow (the transition above) instead
   of jumping about 550px in one frame at 1440; justify-content cannot
   transition, so the row moves to the centre of the bar's current width at
   once and rides that centre as the bar grows. `safe`: on /get-support/ the
   row is already wider than the 55% bar at 1440 and below, and plain
   `center` would push it out past the bar's LEFT edge (off screen at 901)
   for the first frames; safe keeps it left-aligned until it fits, where the
   two agree, so it never jumps. The plain `center` before it is the
   fallback for a browser without `safe`. At rest the row stays left-aligned
   under the hero copy. Desktop only: at 900px and below the bar is already
   100% wide (and spreads its links with space-between), and this selector
   (0,3,0) would otherwise beat those `.program-secnav-bar` rules (0,1,0). */
@media (min-width: 901px) {
  .program-secnav.is-stuck .program-secnav-bar {
    width: 95%;
    justify-content: center;
    justify-content: safe center;
  }
}
/* Reduced motion: the bar takes its pinned width and shadow at once. */
@media (prefers-reduced-motion: reduce) {
  .program-secnav-bar { transition: none; }
}
.program-secnav a {
  color: #fff; /* 4.65:1 on #007cb1; do not tint */
  font-size: 1rem;
  font-weight: 700;
  white-space: nowrap;
  border-bottom: 3px solid transparent;
  padding-bottom: 3px;
  transition: border-color 0.2s, opacity 0.2s;
}
/* NO opacity or tint on these links. White on #007cb1 is 4.65:1 -- almost no
   margin -- and opacity:.85 composites to #d9ebf3 = 3.79:1, which failed on 20
   pages (caught 2026-09-15). The active/inactive distinction is carried by the
   underline alone, which needs no colour change to read. */
.program-secnav a:hover { border-bottom-color: rgba(255, 255, 255, 0.55); }
.program-secnav a[aria-current="true"] {
  border-bottom-color: var(--color-accent); /* amber underline */
}

/* ---------- The next section runs under the nav (#160) ----------
   Desktop only. Only the 55% bar is painted, so the rest of the strip showed
   white between the hero and the next band. The section after the nav is
   pulled up under the strip by the strip's height and given that height back
   as top padding: its background runs under the nav, its content stays put.
   --program-secnav-h is on :root because the section is the nav's sibling and
   cannot read the nav's own properties. The strip is pinned to it, so the pull
   always equals the strip. The value is the bar's own arithmetic: the links'
   1.6 line height plus 3px underline padding and 3px border, plus the bar's
   vertical padding (14+15, then 13+14 at 1180 and below, 12+13 at 1000 and
   below). In rem, so it grows with a larger default font size.
   The section is not positioned, so it paints beneath the z-index 40 nav. All
   21 pages with the nav follow it with a section padded var(--section-spacing)
   at the top. scroll-margin-top drops by the same height so a jump to that
   section (only /get-support/'s #areas-of-support has an id) lands its
   content where it did. */
@media (min-width: 901px) {
  :root { --program-secnav-h: calc(1.6rem + 35px); }
  .program-secnav { height: var(--program-secnav-h); }
  .program-secnav + section {
    margin-top: calc(-1 * var(--program-secnav-h));
    padding-top: calc(var(--section-spacing) + var(--program-secnav-h));
  }
  .program .program-secnav + section[id] {
    scroll-margin-top: calc(var(--eas-header-h, 96px) + 64px - var(--program-secnav-h));
  }
}
@media (min-width: 901px) and (max-width: 1180px) {
  :root { --program-secnav-h: calc(1.6rem + 33px); }
}
@media (min-width: 901px) and (max-width: 1000px) {
  :root { --program-secnav-h: calc(1.6rem + 31px); }
}

/* Anchor jumps must clear the site header AND the pinned sliver (~52px). */
.program [id] {
  scroll-margin-top: calc(var(--eas-header-h, 96px) + 64px);
}

/* ---------- Who This Program Serves ---------- */
/* Only the section WRAPPER lives here. The .audience-badge* tiles inside it
   moved to css/site.css on 2026-10-01: the homepage renders the same component
   in its "Who We Serve" and "Areas of Support" bands and loads only base.css +
   site.css. Every page that uses the tiles loads site.css before this file and
   nothing loads between the two, so the move left the cascade unchanged. */
.program-audiences {
  padding: var(--section-spacing) 0;
}
/* The tile is now an <a> (scripts/generate_programs.py render_audience_tile), so
   it needs the column layout and the bottom-aligned link that css/site.css gives
   the homepage's .audience-badges--wide variant. Borrowing --wide itself was the
   first attempt and it is wrong here: --wide is a grid whose column count is
   STATED, and a program carries 1 or 2 audiences, so a stated 4-column grid
   strands a single tile at a quarter width against the left edge. The centred
   220px flex row already handles 1, 2 and 3 tiles, so only these two
   declarations are needed, and both are scoped to .program-audiences so the
   homepage and /get-support/ tiles are untouched. */
.program-audiences .audience-badge {
  display: flex;
  flex-direction: column;
}
/* Without this the link rides directly under the sub-label and staggers across
   the row, because families-caregivers is the one audience record with an
   empty subheading and it shares a row with another record on 6 of the 20
   pages. */
.program-audiences .audience-badge .link-arrow {
  margin-top: auto;
  padding-top: 14px;
}
/* The whole tile is the link, so the whole tile carries the affordance.
   .link-arrow:hover in site.css only fires when the pointer is on the span. */
.program-audiences a.audience-badge:hover .link-arrow {
  color: var(--color-primary-dark);
}
/* Same indicator the chips and the form controls use: 3px of --focus-ring-color
   at a 2px offset. The radius is here because the tile has none of its own and a
   square ring around a circular photo and two text lines reads as a glitch. */
.program-audiences a.audience-badge:focus-visible {
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 4px;
  border-radius: 14px;
}

/* ---------- Areas of Support cross-link ----------
   The second row of the same band. Every program record carries 1 to 4
   area_slugs and all nine /areas-of-support/<slug>/ pages exist, and before
   2026-10-02 no program page linked to any of them while /programs/ filtered on
   exactly that field.

   The pill is .filter-chip's resting state, so the hub's filter and this
   cross-link read as the same taxonomy. These are <a> elements rather than
   buttons: no aria-pressed, no pressed fill, and the hover is the chip's hover
   plus the border. Navy #004473 on the light-gray band is 9.12:1
   (scripts/check-contrast.mjs), so the label needs no size floor. */
.program-areas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px 16px;
  margin-top: 44px;
}
.program-areas-label {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--color-secondary);
  margin: 0;
}
.area-chip {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-secondary);
  background: var(--color-white);
  border: 2px solid var(--color-border);
  border-radius: 50px;
  padding: 9px 18px;
  transition: background 0.2s, border-color 0.2s;
}
.area-chip:hover {
  border-color: var(--color-secondary);
  background: var(--color-light);
}
.area-chip:focus-visible {
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 2px;
}

/* ---------- About (circle content block) ---------- */
.program-about-copy .text-sub {
  display: block;
  margin-bottom: 10px;
}
.program-about-copy h2 {
  color: var(--color-secondary);
  margin-bottom: 16px;
}
.program-about-copy p {
  font-size: 1.125rem;
  color: var(--color-text-body);
  line-height: 1.75;
  margin-bottom: 16px;
}
.program-about-copy p:last-child {
  margin-bottom: 0;
}
.program-about--no-media {
  display: block;
  max-width: 820px;
  margin: 0 auto;
}

/* ---------- What Sets Us Apart: check-badge benefit grid ----------
   WP signature 6: an orange circular check badge with a soft gold offset dot,
   a navy heading, and gray copy, in a responsive 3-up grid (production renders
   2x3 and longer). The check is inline SVG; the offset dot is CSS-drawn. */
.program-benefits .section-head { margin-bottom: 40px; }
.program-benefits .section-head h2 { color: var(--color-secondary); }
.benefit-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 44px 36px;
}
.benefit-item { text-align: center; }
.benefit-badge {
  position: relative;
  display: inline-flex;
  margin-bottom: 18px;
}
.benefit-badge::after {
  content: '';
  position: absolute;
  right: -5px;
  bottom: 1px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--color-accent);
  z-index: 0;
}
.benefit-check {
  position: relative;
  z-index: 1;
  display: block;
}
.benefit-title {
  color: var(--color-secondary);
  font-size: 1.15rem;
  line-height: 1.3;
  margin-bottom: 10px;
}
.benefit-text {
  font-size: 1rem;
  color: var(--color-text-body);
  line-height: 1.6;
  max-width: 340px;
  margin: 0 auto;
}

/* ---------- Locations ----------
   The column count is STATED by the generator, not inferred from a track width.
   It used to be repeat(auto-fit, minmax(260px, 1fr)): auto-fit collapses the
   empty tracks and stretches a single card across all of them, which measured a
   1152px-wide, 166px-tall card holding a name, one address line and a link at
   1440px. 13 of the 20 programs reference exactly 1 location and 2 reference 2,
   so that was the common case. */
.loc-grid {
  display: grid;
  gap: 24px;
}
.loc-grid--1 { grid-template-columns: minmax(0, 1fr); }
.loc-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.loc-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.loc-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  transition: box-shadow 0.3s, transform 0.3s;
}
.loc-card:hover {
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
  transform: translateY(-4px);
}
.loc-card:focus-visible {
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 3px;
}
/* A single location gets the full container width either way, so it gets a
   composition to fill it: photo beside the details rather than one line of text
   across 1152px. The photo column is a PERCENTAGE rather than a fixed width so
   the split holds from 1440 (483px photo) down to the 900px stack. */
.loc-card--wide {
  flex-direction: row;
  align-items: stretch;
  /* inpatient-rehabilitation is the one program whose single location has no
     photograph, so its media column is the amber brand tile, which has no
     intrinsic height and let the card collapse to 174px against the 324px the
     photo cases measure. The floor only ever raises a card, so the photo cases
     are unchanged. */
  min-height: 260px;
}
.loc-card--wide .loc-card-img {
  flex: 0 0 42%;
  aspect-ratio: auto;
}
.loc-card--wide .loc-card-body {
  flex: 1 1 auto;
  justify-content: center;
  padding: 32px 36px;
}
.loc-card-img {
  aspect-ratio: 400 / 260;
  overflow: hidden;
}
.loc-card-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The amber brand tile /programs/ already uses for a card with no photograph.
   childrens-rehabilitation-center and corporate-office both carry
   /img/locations/location-placeholder.jpg in about_image, which real_image()
   resolves to None, so inpatient-rehabilitation lands here. */
.loc-card-img--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--eas-pale-yellow);
}
.loc-card-img--placeholder img {
  width: auto;
  height: auto;
  max-width: 150px;
  object-fit: contain;
}
.loc-card-body {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  padding: 26px 26px 28px;
}
.loc-card h3 {
  color: var(--color-secondary);
  font-size: 1.2rem;
  margin-bottom: 8px;
}
.loc-card-addr {
  font-size: 1rem;
  color: var(--color-text-body);
  line-height: 1.6;
  margin-bottom: 18px;
  flex-grow: 1;
}
/* With an hours line under it the address stops absorbing the spare height, so
   the hours line does, and the link stays pinned to the card's foot. */
.loc-card-addr--tight {
  flex-grow: 0;
  margin-bottom: 6px;
}
.loc-card-hours {
  font-size: 1rem;
  color: var(--color-text-body);
  line-height: 1.6;
  margin-bottom: 18px;
  flex-grow: 1;
}
.loc-card-link {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-primary);
}

/* ---------- Program staff ---------- */
.staff-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 28px;
}
/* A lone staff card, which is 7 of the 20 programs. auto-fit collapses the
   empty tracks and stretches the single card across all of them: measured
   1088px wide at 1920 against the 530px a two-up card gets, so one headshot and
   two short lines sat in a white slab across the whole pale-yellow panel
   (beacon #198, "I don't love the big block of white in the middle of the
   yellow"). The same defect was fixed the same way for .loc-grid above.

   530px is not a new number. It is exactly the two-up width the other 10
   programs already render: the panel's grid measures 1088px and the gap is
   28px, so (1088 - 28) / 2 = 530.

   Scoped to :only-child rather than a generator-stated .staff-grid--1, so the
   2, 3 and 4 card cases cannot be reached by it at any viewport, no program
   page has to be regenerated, and auto-fit keeps doing the responsive column
   count it already does. width:100% is load bearing: with auto margins and an
   auto width the item would shrink to fit-content instead of the cap.
   Measured at 1920/1440/1280/900/600/390: the 13 multi-card pages are
   unchanged at every width, and below 530px of container the card still fills
   it (342px at 390). */
.staff-grid > .staff-card:only-child {
  width: 100%;
  max-width: 530px;
  margin-inline: auto;
}
.staff-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 28px 22px;
  transition: box-shadow 0.3s, transform 0.3s;
}
.staff-card:hover {
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
  transform: translateY(-4px);
}
.staff-card-photo {
  width: 132px;
  height: 132px;
  margin-bottom: 18px;
  border-radius: 50%;
  overflow: hidden;
  border: 5px solid var(--color-white);
  box-shadow: 0 6px 20px rgba(0, 68, 115, 0.12);
}
.staff-card-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Headshots are 2:3 portraits (900x1350, card thumbs 300x450). Centered,
     the square circle trims top and bottom equally and cuts off the crown;
     15% from the top keeps the whole head and the shoulders. */
  object-position: 50% 15%;
}
.staff-card-photo--initials {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-secondary);
  color: var(--color-white);
  font-size: 2rem;
  font-weight: 800;
  letter-spacing: 1px;
}
.staff-card h3 {
  color: var(--color-secondary);
  font-size: 1.1rem;
  margin-bottom: 4px;
}
.staff-card-role {
  font-size: 1rem;
  color: var(--color-text-light);
  line-height: 1.4;
}

/* ---------- Program inquiry form ---------- */
.program-inquiry-inner {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 56px;
  align-items: start;
}
.program-inquiry-intro .text-sub {
  display: block;
  margin-bottom: 10px;
}
.program-inquiry-intro h2 {
  color: var(--color-secondary);
  margin-bottom: 14px;
}


/* ---------- Program CTA banner (Figma 2026 inset navy panel) ----------
   "Ready to Get Started?" closes the page on a navy rounded panel (inset, not
   full-bleed) with an orange button, matching frame 107:990. */
.program-cta {
  padding: var(--section-spacing) 0;
}
.program-cta > .container {
  background: var(--color-secondary); /* navy #004473 */
  color: #fff;
  border-radius: 20px;
  padding: 56px clamp(24px, 4vw, 56px);
  text-align: center;
}
.program-cta h2 {
  color: #fff;
  margin-bottom: 12px;
}
.program-cta p {
  max-width: 640px;
  margin: 0 auto 26px;
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.9);
  line-height: 1.6;
}
.program-cta-btns {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}

/* Light yellow closing band (iprov-agency/eas-easterseals#199), the same
   decision as .page-cta--cream (css/pages.css) and .cta-banner--cream
   (css/template-kit.css). The reviewer asked for full width as well as the
   colour, so the paint moves off the inset .container panel and onto the
   section: --color-cream #ffe3b3 edge to edge, with the container back to its
   base.css gutter so the copy still stops at --max-width.

   A modifier rather than a repaint of .program-cta, because render_support()
   in scripts/generate_programs.py reuses the same shell for the ACE
   Scholarships panel (section.program-cta#support on
   /programs/easterseals-academy/), which is not a closing CTA and stays navy.
   render_cta() sets this class, so it lands on the 20 program pages and the
   /programs/ hub and nowhere else.

   Measured on #ffe3b3: navy heading 8.14:1, body-gray copy 6.08:1, the orange
   .btn-primary's white label 4.51:1 with a 3.62:1 fill edge against the band.
   The gold hover fill the navy band uses (css/site.css .program-cta
   .btn-primary:hover, gold #ffa300) is 1.61:1 on cream and would erase the
   button, so it returns to base.css's navy fill with a white label, exactly as
   .involve-band--cream does (css/site.css). programs.css loads after site.css,
   so this wins on source order at equal specificity. */
.program-cta--cream {
  background: var(--color-cream);
  color: var(--color-text-body);
}
.program-cta--cream > .container {
  background: transparent;
  color: var(--color-text-body);
  border-radius: 0;
  padding: 0 24px;
}
.program-cta--cream h2 { color: var(--color-secondary); }
.program-cta--cream p { color: var(--color-text-body); }
.program-cta--cream .btn-primary:hover {
  background: var(--color-primary-dark);
  color: var(--color-white);
}

/* =============================================
   /programs/ filter row
   ============================================= */
/* PROGRESSIVE ENHANCEMENT. The section ships with the hidden attribute still on
   it and the inline script at the end of the page removes it only after the
   chips are wired, so a visitor with no JS never sees a control that does
   nothing and the 20-card grid below is already the complete list.

   Every [hidden] in this block is restated in CSS on purpose. The rules here set
   a display value on the same elements, and an author display declaration beats
   the UA stylesheet's [hidden] { display: none }, so without these the hidden
   attribute would silently stop hiding anything. */
.program-filters-section {
  padding: 48px 0 0;
}
.program-filters-section[hidden] { display: none; }
.program-filters-section + .archive-group { padding-top: 36px; }
/* The chips live in a native <details>. On desktop it is always open and the
   summary is not a control anyone needs, so it is removed from the page
   entirely; below 900px the summary becomes the visible disclosure and the
   script closes the panel. A closed <details> takes its contents out of the tab
   order for free, which the max-height:0 accordions elsewhere on this site do
   not. */
.program-filters-summary { display: none; }
.filter-group + .filter-group { margin-top: 22px; }
.filter-group-label {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--color-secondary);
  margin-bottom: 12px;
}
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.filter-chip {
  font-family: var(--font-base);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-secondary);
  background: var(--color-white);
  border: 2px solid var(--color-border);
  border-radius: 50px;
  padding: 10px 20px;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.filter-chip:hover { border-color: var(--color-secondary); }
/* Pressed state is a full fill inversion, matching .btn-outline:hover, not a
   hue swap: navy ground with white type is 10.1:1, and the change in luminance
   reads without relying on colour perception (WCAG 1.4.1). A ::before tick was
   the other candidate and was rejected because it changes the chip's width,
   which reflows the row under the pointer that just clicked it. */
.filter-chip[aria-pressed="true"] {
  background: var(--color-secondary);
  border-color: var(--color-secondary);
  color: var(--color-white);
}
.filter-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  margin-top: 24px;
}
.filter-status {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-secondary);
}
/* 1.1875rem/700 to match .link-arrow, the site's existing orange text link.
   #cf4b04 on white is 4.51:1 (scripts/check-contrast.mjs), so it clears normal
   text here and the size is not load-bearing on white. It becomes load-bearing
   the moment this band gains a tint: the same orange measures 4.06 on the light
   gray and 3.62 on the pale yellow, where only large text (>= 14.25pt bold =
   19px/700) clears. Do not drop it below 1.1875rem while it is orange. */
.filter-clear {
  font-family: var(--font-base);
  font-size: 1.1875rem;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--color-primary);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.filter-clear[hidden] { display: none; }
.filter-clear:hover { color: var(--color-primary-dark); }
/* Same focus indicator the form controls got sitewide on 2026-10-01: 3px of
   --focus-ring-color (navy, 10.1:1 on white, far over the 3:1 WCAG 1.4.11 asks)
   at a 2px offset, which keeps the ring on white even when the chip itself is
   filled navy. Matching the token rather than picking a colour here means a
   later change to the site's focus ring reaches these controls too. */
.filter-chip:focus-visible,
.filter-clear:focus-visible,
.program-filters-summary:focus-visible {
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 2px;
}
.archive-empty {
  font-size: 1.125rem;
  color: var(--color-text-body);
  line-height: 1.6;
}
.archive-empty[hidden] { display: none; }

/* =============================================
   Archive + hub pages
   ============================================= */
/* Archive/hub intro sits below the shared amber .hero-band (site.css). */
.archive-hero-intro {
  max-width: 720px;
  margin: 0 auto 26px;
  font-size: 1.0625rem;
  color: var(--color-text-body);
  line-height: 1.65;
}
.archive-hero-nav {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}
.archive-group .section-head {
  margin-bottom: 36px;
}
.archive-group .section-head h2 {
  color: var(--color-secondary);
}
.archive-group-intro {
  font-size: 1rem;
  color: var(--color-text-body);
  margin-top: 8px;
  max-width: 720px;
}
.archive-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.program-card {
  display: flex;
  flex-direction: column;
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: box-shadow 0.3s, transform 0.3s;
}
.program-card:hover {
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.1);
  transform: translateY(-4px);
}
.program-card-img {
  aspect-ratio: 3 / 2;
  overflow: hidden;
}
.program-card-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* No usable photo (real_image in scripts/generate_programs.py): the tile becomes
   the same amber pattern ground the pattern hero uses, carrying the brand mark,
   so "there is no photo for this one yet" reads as a deliberate brand tile in the
   page's own visual language. Replaces a navy gradient that was unreachable in
   practice until the gallery-placeholder graphic stopped counting as a photo. */
.program-card-img--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #ffc464;
  background-image: url('/img/decor/background-pattern-white-v3.png');
  background-repeat: repeat;
}
.program-card-img--placeholder img {
  width: auto;
  height: auto;
  max-width: 58%;
  object-fit: contain;
}
/* A filtered-out card must leave the tab order as well as the page, so the
   filter sets the hidden attribute rather than a class. .program-card sets
   display:flex, which would beat the UA stylesheet's [hidden] rule. */
.program-card[hidden] { display: none; }
.program-card-body {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  padding: 26px 24px;
}
.program-card-eyebrow {
  font-size: 1rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 1.5px;
  color: var(--color-primary);
  margin-bottom: 8px;
}
.program-card-body h3 {
  color: var(--color-secondary);
  font-size: 1.25rem;
  line-height: 1.3;
  margin-bottom: 10px;
}
.program-card-body p {
  font-size: 1rem;
  color: var(--color-text-body);
  line-height: 1.6;
  margin-bottom: 18px;
  flex-grow: 1;
}
/* BASELINE ALIGNMENT ACROSS A ROW. Measured at 1000px before this: a two-line
   card title (52px) beside a one-line title (26px) started its blurb 13px lower
   in the same row, and a row containing a two-line title was 26px taller than
   one that did not (529 vs 503). Reserving two lines for the title and four for
   the blurb lines the blurbs up and evens the rows out. These are min-heights,
   not line clamps: a three-line title still grows and nothing is ever clipped. */
.program-card-body h3 {
  min-height: calc(2 * 1.3em);
}
.program-card-body .program-card-blurb {
  min-height: calc(4 * 1.6em);
}
/* .program-card-body p also matches .program-card-eyebrow, so the eyebrow was
   sharing the card's slack with the blurb and could push the title down. Only
   the blurb should absorb it. */
.program-card-body .program-card-eyebrow {
  flex-grow: 0;
}
.program-card .link-arrow {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-primary);
  /* Declarative bottom pin, so a program with no intro_text cannot float the
     affordance up the card the way relying on the blurb's flex-grow would. */
  margin-top: auto;
}

/* ---------- Responsive ---------- */
/* The panel's 80/56 padding eats most of a narrow column: at 901px it left only
   ~359px for the copy. Step it down before the layout stacks. */
@media (max-width: 1180px) {
  .program-hero-copy { padding: 52px 40px 28px; }
  .program-secnav-bar { padding: 13px 40px 14px; gap: 20px; }
}
@media (max-width: 1000px) {
  .program-hero-copy { padding: 42px 30px 24px; }
  .program-secnav-bar { padding: 12px 30px 13px; gap: 16px; }
  /* Option A (Casey, 2026-09-15): the panel is too narrow here for two CTAs
     side by side, but two full-width buttons make a navigation link compete
     with the page's actual call to action. Primary stays a button; the
     secondary becomes an underlined text link beneath it. Also keeps the hero
     shorter, which matters with the photo already above it. */
  .program-hero-ctas { flex-direction: column; align-items: flex-start; gap: 12px; }
  .program-hero-ctas .btn-primary { width: 100%; justify-content: center; }
  .program-hero-ctas .btn-outline-light {
    border: 0;
    padding: 0;
    width: auto;
    font-size: 1rem;
    letter-spacing: 0;
    text-decoration: underline;
    text-underline-offset: 3px;
  }
  .program-hero-ctas .btn-outline-light:hover {
    background: transparent;
    color: #fff;
    text-decoration-thickness: 2px;
  }
}

@media (max-width: 900px) {
  /* Stack: photo first, then the panel. The 5% left gutter is dropped so the
     amber does not eat usable width on a narrow screen. */
  .program-hero {
    flex-direction: column;
    padding-left: 0;
  }
  /* flex:0 0 auto left the photo at its intrinsic 646px, so between 646 and
     900 it sat short of the right edge with a gap beside it. */
  .program-hero-media { order: -1; flex: 0 0 auto; width: 100%; }
  .program-hero-media::before { display: none; } /* strip is desktop-only */
  /* 16/9 at full width is 506px tall at 900px and pushes every word of the
     hero below the fold. Cap the height and crop instead. */
  .program-hero-media img {
    aspect-ratio: auto;
    height: clamp(190px, 34vw, 300px);
    object-fit: cover;
  }
  /* The sliver has to go full width HERE, at the same point the panel does.
     It previously waited until 600px, so 600-900 showed a full-width panel
     with a 55%-wide sliver hanging under it. */
  .program-secnav { margin-left: 0; }
  .program-secnav-bar {
    width: 100%;
    border-radius: 0;
    padding: 12px 24px 13px;
    /* Distribute across the bar. Left-aligned, the last link ended at x=314 in
       a 390px bar and left ~76px of dead blue. space-between fills it while
       keeping the first link aligned with the copy above. */
    justify-content: space-between;
    gap: 10px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .program-secnav-bar::-webkit-scrollbar { display: none; }
  .program-hero-copy {
    flex: 0 0 auto;
    border-radius: 0;
    padding: 36px 24px 34px;
  }
  /* The pattern column is pure decoration with nothing to read in it, and
     .program-hero-media::before (the amber strip) is already desktop-only here,
     so a stacked amber block would be an empty box eating the fold. Drop it and
     let the panel run full width. */
  .program-hero-media--pattern { display: none; }
  /* 13 chips at one per row pushed the first card about 1300px down the page.
     The summary becomes the visible control here and the script closes the
     panel. Styled as the page's outline button so it reads as a control. */
  .program-filters-summary {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    width: auto;
    padding: 11px 22px;
    border: 2px solid var(--color-primary);
    border-radius: 50px;
    color: var(--color-primary);
    font-size: 1.1875rem;
    font-weight: 700;
    letter-spacing: 1px;
    cursor: pointer;
    list-style: none;
  }
  .program-filters-summary::-webkit-details-marker { display: none; }
  .program-filters-summary::after {
    content: "+";
    font-size: 1.25rem;
    line-height: 1;
  }
  .program-filters[open] > .program-filters-summary::after { content: "\2212"; }
  .program-filters[open] > .program-filters-summary { margin-bottom: 22px; }
  .program-inquiry-inner {
    grid-template-columns: 1fr;
    gap: 32px;
  }
  .archive-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .benefit-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 36px 32px;
  }
  /* A 42% photo column is 144px at 390px wide, which is a thumbnail, not a
     photograph. Stack, the same point the hero does. */
  .loc-card--wide { flex-direction: column; min-height: 0; }
  .loc-card--wide .loc-card-img { flex: 0 0 auto; aspect-ratio: 400 / 260; }
  .loc-card--wide .loc-card-body { padding: 26px 26px 28px; }
  /* Stacked, the 400/260 ratio is a function of the card's width, and a single
     location still gets the whole container: at 900px that measured an 852px
     card with a 554px photo and a 716px card height, and for
     inpatient-rehabilitation a 554px tall amber tile holding a 150px logo. Crop
     instead, the same move .program-hero-media img makes at this breakpoint.
     Harmless at the widths that do not reach it: a 2-up card is 414px wide here
     (269px photo) and 340px at 390px (221px). */
  .loc-card-img { max-height: 300px; }
  .loc-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 600px) {
  /* NOTE: the old `.program-hero { padding: 40px 0 44px }` lived here, left
     over from the original full-bleed navy band. Against the current
     panel+photo structure it was pure white space -- a 40px band between the
     breadcrumb and the photo, and 44px under the sliver. Removed. */
  .benefit-grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }
  .archive-grid {
    grid-template-columns: 1fr;
  }
  .loc-grid--2,
  .loc-grid--3 { grid-template-columns: minmax(0, 1fr); }
  /* 4 chips at 1 per row is the worst case and it is 4 rows, so the row stays a
     wrap rather than a scroller. Left-aligned here: a centred ragged wrap of 2
     and then 1 reads as a mistake at this width. */
  .program-areas { justify-content: flex-start; }
  /* One column, so there is no row to align across and the reserved lines are
     pure white space. Release them. */
  .program-card-body h3 { min-height: 0; }
  .program-card-body .program-card-blurb { min-height: 0; }

  /* Handled at 900px now; this block only tightens the small-screen spacing. */
  .program-hero-copy { padding: 30px 20px 26px; }
  .program-secnav-bar { padding: 10px 20px 11px; gap: 18px; }
}

/* ==========================================================================
   Program content sections (scripts/program_sections.py, eas-easterseals#226)
   Only pages whose data/programs.json record carries a `sections` list emit
   these classes; every other program page is untouched by this block. Built
   from existing parts (.section-head, .offer-block + .eas-img circles,
   .value-card, .benefit-badge, and the .resource-list card in css/site.css),
   so only the glue lives here.
   ========================================================================== */
.pgs-section { padding: var(--section-spacing) 0; }
.pgs-section--alt { background: var(--color-light); }
.pgs-section .section-head { max-width: 760px; margin-left: auto; margin-right: auto; }
.pgs-section .section-head:not(.text-center) { margin-left: 0; margin-bottom: 24px; }
.pgs-lead { margin-top: 12px; color: var(--color-text-body); }
.pgs-copy p + p { margin-top: 12px; }
.pgs-narrow { max-width: 760px; }

/* intro: icon + one line */
.pgs-intro { padding: 64px 0; }
.pgs-intro-icon { margin-bottom: 16px; }
.pgs-intro-heading { color: var(--color-primary); }
.pgs-intro-text { max-width: 720px; margin: 12px auto 0; font-size: 1.15rem; }

/* media: copy beside a 16:9 video */
.pgs-media .pgs-media-grid { align-items: center; }
.pgs-video {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--color-secondary);
}
.pgs-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* feature_rows: a row without a photo reads as a narrow column */
.pgs-row--text { max-width: 760px; }
.pgs-feature-rows .text-sub { margin-bottom: 6px; }

/* card_grid */
.pgs-card-grid .pgs-card { text-align: left; }
.pgs-card h3 { color: var(--color-secondary); font-size: 1.2rem; }
.pgs-after-video { max-width: 860px; margin: 48px auto 0; }

/* checklist */
.pgs-checklist-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 14px; }
.pgs-checklist-list li { display: flex; gap: 14px; align-items: flex-start; font-size: 1.05rem; }
.pgs-checklist .pgs-check { flex: 0 0 auto; }
.pgs-check .benefit-check { width: 30px; height: 30px; }

/* quotes */
.pgs-quotes .pgs-quote-grid { align-items: stretch; gap: 24px; }
.pgs-quote {
  margin: 0;
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-left: 6px solid var(--eas-blue);
  border-radius: var(--radius);
  padding: 32px 28px;
}
.pgs-quote blockquote { margin: 0 0 16px; font-size: 1.05rem; line-height: 1.6; color: var(--color-text); }
.pgs-quote figcaption { font-weight: 700; color: var(--color-secondary); }

/* resources: the shared .resource-list card, left-aligned under the copy */
.pgs-resources .resource-list { margin: 20px 0 0; padding: 0; }
.pgs-resources .resource-list a { text-decoration: none; }

@media (max-width: 900px) {
  .pgs-media-grid,
  .pgs-checklist-grid,
  .pgs-quote-grid,
  .pgs-section .grid-3.pgs-cards { grid-template-columns: 1fr; }
}
