/* ==========================================================================
   Site styles — Citizens' Climate Lobby 2026 website
   Layered on top of styles/tokens.css. All values come from the design
   system unless explicitly noted as a deviation (see DEVIATIONS.md).
   ========================================================================== */

/* ==========================================================================
   CONTENTS
   --------------------------------------------------------------------------
   Line numbers are a hint and WILL drift. Search the section TITLE instead --
   each one below appears verbatim in the file, and the ones in CAPS are banner
   comments you can jump straight to.

   Components are listed by the first class in their selector. A component's
   BEM children (__elem) and modifiers (--mod) live with it and aren't listed.

     GLOBALS
       88  overflow guard, .container / -wide / -narrow

     HEADER & NAVIGATION
      140  .site-header · .nav-toggle · .mobile-menu
      312  .header-actions · .header-search-toggle · .search-panel  (+ narrow-screen steps)
      447  .utility-bar · .lang-switch
      361  .section-nav  (the on-page third-tier nav)
      408  .breadcrumb

     TYPOGRAPHY & CONTROLS
      464  eyebrows — .eyebrow-blue / -green / -meta + their block styles
      495  .wp-block-separator
      509  buttons — .btn and the six variants
      642  type utilities — .display · .h1-bold · .h2-regular · .body-lead

     HEROES & SECTION FURNITURE
      694  .hero-t1 · .hdr-underline
      772  .split-feature
      801  .hero-t2
      882  give heroes — .give-hero-b · .give-hero · .give-press
      946  .lite-yt · .play-btn   (video poster + play affordance)
     1012  .section-header · .pillar-row · .pillar-card
     1080  .mobilized

     CARDS
     1169  .team-card  (also the story card -- see ccl_render_story_card)
     1234  .hm-approach   1315  .know-ccl   1426  .photo-tile

     1407  .ccl        (the body marker -- see the note there before editing)

   ── Banner sections from here down; each title below is searchable verbatim ──

     1472  QUOTES — one system, three components
     2053  TAKE ACTION SECTION
     2547  Events kit — shared conference/event presentation
     2764  Conference Agenda block
     3068  STORIES (blog index)
     3457  IMPACT SECTION
     3767  PAST PROGRESS
     4078  PAGE 3 — Our Team
     4463  OUR APPROACH
     5202  JOIN SUMMARY
     5602  State finder
     5681  Chapter finder
     5814  STATE HUB PAGE
     6073  ACTION TEAMS  (.at-*)
     6482  BRAND-INTENSITY tiers
     7559  TAKE ACTION ISSUE PAGES  (.section-band, .issue-pillar, …)
     7860  SITE SEARCH  (.site-search · .search-page · .search-result · .not-found)

   --------------------------------------------------------------------------
   WHERE DOES A RULE BELONG?  Four files style this site and the boundaries
   have drifted -- 13 selectors are currently defined in BOTH this file and
   patterns.css, where load order silently picks the winner. See TODO.md,
   "CSS consolidation". Short version: tokens.css = variables, this file = all
   component styles, patterns.css = only what's unique to native-block patterns.

   TWO TRAPS, both of which have bitten more than once:
   1. An extra element in a selector outranks a component's own class --
      `.team-card__body p` (0,1,1) beats `.team-card__link` (0,1,0). If a
      component's own rule "isn't working", check for a neighbour like that.
   2. `.ccl`-scoped rules apply on the front end (<body class="ccl">) but NOT
      in the block-editor canvas, which has no .ccl ancestor. A rule that shows
      in preview and vanishes while editing is this.
   ========================================================================== */

html { scroll-behavior: smooth; }
body { margin: 0; background: var(--bg-page); }
/* Guard against horizontal scrollbars from full-width/decorative content that
   pokes past the viewport (e.g. nested .alignfull compounding the root-padding
   breakout, or a hero's offset background). `clip` (not hidden) doesn't create a
   scroll container, so position:sticky still works. This is what makes the
   header/footer read full-width instead of margined when a page has such content. */
.wp-site-blocks { overflow-x: clip; }

/* Content containers (max-width + gutters). NOTE: there is deliberately NO `.page`
   rule here. The prototype frames the design in a <div class="page"> at 1440px, but
   WordPress's body_class() adds `page` to <body> on EVERY Page — so a bare `.page`
   max-width clamps the entire page (header + footer included) and centers it, which
   is not what we want (header/footer should be full-width). Constrain via these
   containers or the theme.json content/wide sizes instead. */
.container { max-width: 1128px; margin: 0 auto; padding: 0 var(--page-gutter); }
.container-wide { max-width: 1246px; margin: 0 auto; padding: 0 var(--page-gutter); }
.container-narrow { max-width: 780px; margin: 0 auto; padding: 0 var(--page-gutter); }

img { display: block; max-width: 100%; }

/* Focus ring — ONE definition for the whole site.

   The black boxes come from the parent theme, which sets width and style but no
   colour:

     :where(.wp-site-blocks *:focus) { outline-width: 2px; outline-style: solid }

   `outline-color` then falls back to `currentColor`, so the ring takes the
   element's TEXT colour -- near-black on nav links and card headings. It also
   keys off :focus rather than :focus-visible, which is why clicking a link with
   a mouse leaves a box behind.

   Both fixed here. Mouse focus is silent; keyboard focus gets a brand ring. The
   parent's :where() makes its rule zero-specificity, so a plain selector wins
   without !important.

   --ccl-blue because three focus rings in this file already use it (.tabs__tab
   and the two picker components), so the site ends up with one focus colour
   rather than four. No border-radius here: an outline follows the element's own
   radius, and forcing a value would square off the ring on rounded cards.

   NOT removed, only recoloured. A focus ring is how a keyboard user knows where
   they are; the components that legitimately suppress it (.us-map__link) swap in
   their own indicator instead. */
.wp-site-blocks :focus:not(:focus-visible) {
  outline: none;
}
.wp-site-blocks :focus-visible {
  outline: 2px solid var(--ccl-blue);
  outline-offset: 2px;
}

/* Figure margin reset now lives in canonical tokens.css as
   `:where(.ccl) figure { margin: 0 }`. Local rule removed. */

/* --------------------------------------------------------------------------
   Site header
   -------------------------------------------------------------------------- */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 96px;
  padding: 0 var(--container-pad);
  background: var(--ccl-grey-10);
  /* Blue→green gradient divider beneath the primary header (design system). */
  border-bottom: 3px solid transparent;
  border-image: var(--gradient-underline) 1;
}
.site-header .brand { display: inline-flex; text-decoration: none; flex: 0 0 auto; }
/* max-width:none so the CSS reset's max-width:100% can't clamp the logo width
   (with a fixed height that clamp squishes the mark). flex:0 0 auto above keeps
   the brand from shrinking in the flex row. */
.site-header .brand img { height: 38px; width: auto; max-width: none; }
/* Two-CTA cluster (Join + Donate) at the end of the header. */
.site-header .header-ctas { display: inline-flex; align-items: center; gap: var(--spacing-sm); margin-left: var(--spacing-md); flex: none; }
.site-header .header-cta { flex: none; }

/* Primary nav — core Navigation block (editable in the Site Editor), styled to
   match the prototype's fixed nav: display-font links, gradient underline on the
   active item. WP marks the current page's link with .current-menu-item /
   aria-current, so both are targeted. */
.site-header .wp-block-navigation { flex: 1; justify-content: center; }
.site-header .wp-block-navigation .wp-block-navigation__container { align-items: center; gap: var(--spacing-2xl); }
.site-header .wp-block-navigation .wp-block-navigation-item__content {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 16px;
  color: var(--grey-600);
  text-decoration: none;
  padding-bottom: 4px;
  border-bottom: 3px solid transparent; /* reserve space so the active underline doesn't shift layout */
}
.site-header .wp-block-navigation .wp-block-navigation-item__content:hover { color: var(--ccl-blue); }
.site-header .wp-block-navigation .current-menu-item > .wp-block-navigation-item__content,
.site-header .wp-block-navigation .wp-block-navigation-item__content[aria-current] {
  color: var(--ccl-blue);
  font-weight: 700;
  border-image: var(--gradient-underline) 1;
}
/* --------------------------------------------------------------------------
   Mobile navigation — hamburger + full-screen slide-in drawer, built by
   assets/js/mobile-nav.js from the header's nav (top level) + a slug-based
   sub-nav map. The Navigation block's own overlay is off (overlayMenu:"never"
   in parts/header.html). Everything here is inert above 900px; the display
   switches in the @media block below turn it on. Ported from the prototype.
   -------------------------------------------------------------------------- */
.nav-toggle {
  display: none; /* shown only at the mobile breakpoint */
  align-items: center; justify-content: center;
  appearance: none; border: 0; background: transparent; cursor: pointer;
  width: 44px; height: 44px; padding: 10px; margin-left: var(--spacing-sm);
  color: var(--grey-600); border-radius: var(--radius-pill);
}
/* Only on real pointing devices — on touch, :hover sticks after a tap. */
@media (hover: hover) { .nav-toggle:hover { background: var(--grey-200); } }
.nav-toggle svg { display: block; width: 24px; height: 24px; }
/* Scoped under .nav-toggle so it outranks the `.nav-toggle svg` rule above. */
.nav-toggle .nav-toggle__close { display: none; }
html.nav-open .nav-toggle__open  { display: none; }
html.nav-open .nav-toggle__close { display: block; }

.mobile-menu { display: none; }
/* theme.json underlines links on :hover (and it sticks after a tap on touch).
   The drawer signals state with colour + weight, not underlines, so suppress it
   on every link in the panel — logo, sub-links, CTAs. The :hover/:focus
   selectors (0,2,1) outrank theme.json's :root :where(a):hover (0,2,0). */
.mobile-menu a,
.mobile-menu a:hover,
.mobile-menu a:focus { text-decoration: none; }
.mobile-menu__panel {
  position: fixed; inset: 0; z-index: 100;
  background: var(--bg-page); overflow-y: auto; -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column; gap: var(--spacing-xl);
  padding: var(--spacing-lg) var(--spacing-lg) var(--spacing-2xl);
  transform: translateY(-8px); opacity: 0; visibility: hidden;
  transition: opacity .2s ease, transform .2s ease, visibility .2s ease;
}
html.nav-open .mobile-menu__panel { transform: none; opacity: 1; visibility: visible; }

.mobile-menu__bar {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: var(--spacing-md); border-bottom: 1px solid var(--grey-200);
}
.mobile-menu__bar img { height: 34px; width: auto; }
.mobile-menu__close {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  width: 44px; height: 44px; padding: 10px; color: var(--grey-600);
  border-radius: var(--radius-pill);
}
@media (hover: hover) { .mobile-menu__close:hover { background: var(--grey-200); } }
.mobile-menu__close svg { display: block; width: 24px; height: 24px; }

.mobile-menu__primary { display: flex; flex-direction: column; }

/* Each top-level section is an accordion: a disclosure button (expands its
   sub-pages) when it has children, else a plain navigating link. */
.mobile-menu__section { border-bottom: 1px solid var(--grey-100); }
.mobile-menu__row { display: flex; align-items: center; width: 100%; }
button.mobile-menu__row {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  font: inherit; color: inherit; text-align: left; padding: 0;
}
.mobile-menu__link {
  flex: 1; min-width: 0;
  font-family: var(--font-display); font-weight: 600; font-size: 22px;
  color: var(--grey-600); text-decoration: none; padding: 14px 0;
}
.mobile-menu__section--active > .mobile-menu__row > .mobile-menu__link,
a.mobile-menu__link.current {
  color: var(--ccl-blue); font-weight: 700;
}
.mobile-menu__expand {
  flex: 0 0 auto; width: 44px; height: 44px; margin-right: -10px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--grey-400);
}
.mobile-menu__expand svg { width: 22px; height: 22px; transition: transform .2s ease; }
.mobile-menu__section.is-open > .mobile-menu__row > .mobile-menu__expand svg { transform: rotate(180deg); }

/* Animated reveal via grid-rows 0fr→1fr (no fixed max-height needed). */
.mobile-menu__subwrap { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .24s ease; }
.mobile-menu__section.is-open > .mobile-menu__subwrap { grid-template-rows: 1fr; }
.mobile-menu__subinner { overflow: hidden; }

.mobile-menu__sub {
  display: flex; flex-direction: column;
  margin: 0 0 14px; padding-left: var(--spacing-md);
  border-left: 3px solid transparent; border-image: var(--gradient-underline) 1;
}
.mobile-menu__sub a {
  font-family: var(--font-body); font-size: 19px; color: var(--grey-500);
  text-decoration: none; padding: 9px 0;
}
.mobile-menu__sub a.current { color: var(--ccl-blue); font-weight: 700; }

.mobile-menu__cta { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.mobile-menu__cta .btn { width: 100%; justify-content: center; font-size: 17px; padding: 14px; }

.mobile-menu__utility {
  display: flex; flex-direction: column; gap: var(--spacing-md);
  padding-top: var(--spacing-lg); border-top: 1px solid var(--grey-200);
}
.mobile-menu__utility a {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display); font-weight: 600; font-size: 15px;
  color: var(--ccl-blue); text-decoration: none;
}
.mobile-menu__utility svg { width: 18px; height: 18px; }
.mobile-menu__utility .mobile-menu__lang { color: var(--grey-500); font-weight: 500; }

/* Background scroll-lock while the menu is open. */
html.nav-open, html.nav-open body { overflow: hidden; }

/* Below 900px: hide the desktop nav row + reveal the hamburger/drawer. The
   header CTAs drop at 700px (they're cloned into the drawer, so nothing's lost). */
@media (max-width: 900px) {
  .site-header .wp-block-navigation { display: none; }
  .nav-toggle { display: inline-flex; }
  .mobile-menu { display: block; }
}
@media (max-width: 700px) {
  .site-header .header-ctas { display: none; }
  /* Phone logo size: with the header's other narrow-screen steps below
     ("Narrow screens: what gives way first"), which come later in the file. */
}

/* --------------------------------------------------------------------------
   Header actions — Join + Donate + the Search toggle (ccl/header-actions), and
   the search panel the toggle opens (ccl/search-panel). No prototype design;
   agreed with the team 2026-09-29 (after an audit of GOV.UK, AARP, Medicare,
   Virginia Tech and peer climate orgs):
   - Search sits at the far right, icon then word, like the utility bar items.
   - Open, the toggle becomes a WHITE TAB, full header height, that breaks the
     gradient line and joins the white panel below; the line steps up over
     the tab's top in the gradient's own colour at that point. The magnifier
     becomes ✕. No underline on the tab — the nav's underline already means
     "this page".
   - The panel pushes the page down (no dimming), and the nav stays put.
   -------------------------------------------------------------------------- */
.site-header .header-actions {
  display: flex;
  align-items: center;
  align-self: stretch; /* so the open tab can run the header's full height */
  flex: none;
  margin-left: var(--spacing-md);
}
.site-header .header-actions .header-ctas { margin-left: 0; }
/* Header buttons fit their labels. The sitewide 133px minimum (the
   prototype's button spec) is right in page content; in the header it cost
   ~70px and wrapped the nav at 1200px. 96px keeps Join and Donate about the
   same width, so the leading button never looks like the lesser one. */
.site-header .header-cta.btn { min-width: 96px; padding-inline: 20px; }

.header-search-toggle {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  align-self: stretch;
  gap: 8px;
  margin-left: var(--spacing-sm);
  padding: 0 var(--spacing-md);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--grey-600);
  text-decoration: none;
  cursor: pointer;
}
.header-search-toggle__icon { display: inline-flex; }
.header-search-toggle svg { display: block; width: 22px; height: 22px; }
.header-search-toggle .header-search-toggle__close { display: none; }
@media (hover: hover) { .header-search-toggle:hover { color: var(--ccl-blue); } }
.header-search-toggle:focus-visible { outline: 2px solid var(--ccl-blue); outline-offset: -6px; border-radius: var(--radius-sm); }
/* Open: the white tab. margin-bottom:-3px carries it over the header's 3px
   gradient border into the panel; z-index paints it above that border. */
.header-search-toggle.is-open { background: #fff; margin-bottom: -3px; }
/* …and the gradient line steps up over it: a 3px bar across the tab's top in
   the colour the header's line has at that point (a slice of the same
   full-width gradient — header-search.js sets --tab-x / --header-w). */
.header-search-toggle.is-open::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--gradient-underline) no-repeat;
  background-size: var(--header-w, 100vw) 100%;
  background-position: calc(-1 * var(--tab-x, 0px)) 0;
}
.header-search-toggle.is-open .header-search-toggle__open { display: none; }
.header-search-toggle.is-open .header-search-toggle__close { display: block; color: var(--ccl-blue); }

.search-panel {
  position: relative;
  z-index: 1; /* its shadow falls on the page, not under it */
  padding: var(--spacing-xl) var(--container-pad) var(--spacing-2xl);
  background: #fff;
  border-bottom: 1px solid var(--grey-300);
  box-shadow: 0 8px 16px rgba(0, 0, 0, .06);
}
.search-panel[hidden] { display: none; }

/* ----- Narrow screens: what gives way first ------------------------------
   Breakpoints are computed, not guessed (measured 2026-09-29): logo 293
   (247 at 32px tall), nav items 307 + 4 gaps, Join 96, Donate 100, toggle
   113 with its word / 46 without, the header's 24px flex gaps + 16px before
   the actions, ~40px of breathing room. Least costly first:
     < 1230  nav gaps 40 → 24
     < 1170  the toggle drops its word (still its accessible name)
     < 1100  logo 38 → 32px tall, nav gaps 16
     < 1020  the button that doesn't lead today hides (data-rank="2";
             Appearance → Header buttons), and stays hidden at every smaller
             width — steps only ever take away. "Give" is still in the nav.
             Both buttons still fit a 1024px screen.
     ≤  900  nav → hamburger (the leading button + search stay)
     ≤  700  the button moves into the menu (both are there); logo 26px
             tall and tighter spacing so logo + search + hamburger breathe
             on a 360px phone; 22px under 375
   These also cover zoomed-in browsers: a 1440px laptop at 125% zoom is a
   1152px screen, common for our audience.                                  */
@media (max-width: 1229px) {
  .site-header .wp-block-navigation .wp-block-navigation__container { gap: var(--spacing-lg); }
}
@media (max-width: 1169px) {
  .header-search-toggle { padding: 0 12px; }
  .header-search-toggle__label {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
}
@media (max-width: 1099px) {
  .site-header .brand img { height: 32px; }
  .site-header .wp-block-navigation .wp-block-navigation__container { gap: var(--spacing-md); }
}
/* One way only: once it hides, it stays hidden in the header at every
   narrower width (it's still in the mobile menu, which isn't in .site-header). */
@media (max-width: 1019px) {
  .site-header .header-cta[data-rank="2"] { display: none; }
}
@media (max-width: 900px) {
  /* The nav is gone: keep the buttons + search at the right, by the hamburger. */
  .site-header .header-actions { margin-left: auto; }
  .header-search-toggle { margin-left: var(--spacing-xs); padding: 0 10px; }
}
@media (max-width: 700px) {
  /* .wp-block-group doubled: core prints the group's flex gap as its own rule. */
  .site-header.wp-block-group { column-gap: var(--spacing-2xs, 4px); }
  .header-search-toggle { margin-left: 0; }
  .site-header .nav-toggle { margin-left: 0; }
  /* After the < 1100 rule on purpose: same selector, so order decides. */
  .site-header .brand img { height: 26px; }
}
@media (max-width: 374px) {
  .site-header .brand img { height: 22px; }
}

/* --------------------------------------------------------------------------
   Utility (eyebrow) bar — slim strip above the main header for secondary
   actions: language switcher + Volunteer Portal. Quieter than the header so it
   stays subordinate. position/z-index let the language dropdown paint above the
   header that follows it in the DOM.
   -------------------------------------------------------------------------- */
.utility-bar {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing-md);
  padding: 7px var(--container-pad);
  background: var(--grey-200);
  font-family: var(--font-display);
  font-size: 13px;
  line-height: 1;
}
.utility-bar a { text-decoration: none; }
.utility-bar__sep { width: 1px; height: 14px; background: var(--grey-300); }
.utility-bar__portal { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; color: var(--ccl-blue); }
.utility-bar__portal:hover { color: var(--ccl-blue-dark); }
.utility-bar__portal svg { width: 15px; height: 15px; }

/* Language switcher — native <details> so it works without JS. Placeholder:
   the options don't translate yet. */
.lang-switch { position: relative; }
.lang-switch > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; color: var(--grey-600); }
.lang-switch > summary::-webkit-details-marker { display: none; }
.lang-switch > summary::marker { content: ""; }
.lang-switch svg { width: 15px; height: 15px; }
.lang-switch .chev { transition: transform .15s ease; }
.lang-switch[open] .chev { transform: rotate(180deg); }
.lang-switch__menu {
  position: absolute; right: 0; top: calc(100% + 7px);
  margin: 0; padding: 6px 0; list-style: none; min-width: 132px;
  background: #fff; border: 1px solid var(--grey-200); border-radius: 6px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .10);
}
.lang-switch__menu a { display: block; padding: 7px 16px; color: var(--grey-600); }
.lang-switch__menu a:hover { background: var(--grey-100); }

/* Drop the language switcher once the mobile drawer takes over (it carries the
   language + Volunteer Portal below 900px); keep the Portal in the bar. */
@media (max-width: 900px) {
  .utility-bar .lang-switch, .utility-bar .utility-bar__sep { display: none; }
  .utility-bar { justify-content: flex-end; }
}

/* --------------------------------------------------------------------------
   Section nav (page-internal "About Us" wayfinding row)
   -------------------------------------------------------------------------- */
.section-nav {
  position: relative; /* anchors the mobile scroll-strip edge fades */
  /* Sit flush under the header — cancel the root blockGap margin it inherits as
     a top-level template block (theme.json blockGap = spacing-50). */
  margin-block-start: 0;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--spacing-xl);
  padding: var(--spacing-sm) var(--page-gutter);
  border-bottom: 1px solid var(--grey-200);
}
.section-nav .section-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13px;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-400);
  margin: 0;
}
.section-nav .links { display: flex; align-items: center; gap: var(--spacing-2xs); }
.section-nav .links a {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 16px;
  line-height: 1;
  color: var(--grey-1000);
  text-decoration: none;
  padding: 8px 18px;
  border-radius: var(--radius-pill);
  transition: background-color .12s ease, color .12s ease;
}
.section-nav .links a:hover { background: var(--ccl-blue-bg); }
.section-nav .links a.current,
.section-nav .links a.current:hover {
  background: var(--ccl-blue);
  color: #fff;
  font-weight: 700;
}

/* --------------------------------------------------------------------------
   Breadcrumbs — Source Sans Pro tiny, chevron separators.
   Lives directly under the section-nav, above the page H1, per
   Hero System.md T3 pattern ("breadcrumb + eyebrow + H1 + one line").
   -------------------------------------------------------------------------- */
.breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  list-style: none;
  margin: 0;
  padding: var(--spacing-md) var(--page-gutter) 0;
  font-family: var(--font-body);
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
}
.breadcrumb li { display: flex; align-items: center; gap: var(--spacing-xs); }
.breadcrumb a {
  color: var(--grey-500);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color .12s ease, color .12s ease;
}
.breadcrumb a:hover { color: var(--ccl-blue); border-bottom-color: var(--ccl-blue); }
.breadcrumb li[aria-current="page"] {
  color: var(--ccl-black);
  font-weight: var(--fw-strong-body);
}
.breadcrumb .sep {
  color: var(--grey-300);
  font-size: 16px;
  line-height: 1;
}

/* Full-width (section-page) breadcrumb — placed align:full in page.html. Override
   the centered max-width:720 rule (in patterns.css, for the single-post context)
   so the crumb spans full width and its --page-gutter inset lines up with the
   section-nav above it. The 0,2,0 selector beats the plain .breadcrumb (0,1,0).
   The vertical spacing is restated here too: patterns.css's `margin: xl auto 0;
   padding: 0 …` also overrides the base rule above, which put the crumb 32px
   under the section nav instead of the prototype's 16px (margin 0, padding-top
   md). Zeroing the top margin also beats core's root block-gap. */
.breadcrumb.alignfull {
  max-width: none;
  margin-inline: 0;
  margin-block-start: 0;
  padding-top: var(--spacing-md);
  padding-inline: var(--page-gutter);
}
/* single-ccl_state.html nests the crumb inside the wash wrapper in <main>, so
   <main>'s root block-gap (24px) sits above it as well. Drop that so the state
   page gets the same 16px as every other page. */
main:has(> .state-wash:first-child) { margin-block-start: 0; }

/* Breadcrumb → first block. page.html / gradient.html put 56px between them
   (<main>'s root block-gap, 24px, + the wrapper's inline 32px padding-top). That
   suits a page that opens on a bare header (page-header, a heading). A hero or
   section that brings its own top padding stacked the two (e.g. hero-t1: 56 +
   80). So when one of those comes first, drop the template's share and let it
   own the gap, as in the prototype, where the breadcrumb sits directly above it.
   !important because the wrapper padding is inline in the template (same as
   the join-cta bottom rule). */
main:has(> .wp-block-group > .wp-block-post-content > :is(.hero-t1, .hero-t2, .mission-block):first-child) {
  margin-block-start: 0;
}
main > .wp-block-group:has(> .wp-block-post-content > :is(.hero-t1, .hero-t2, .mission-block):first-child) {
  padding-top: 0 !important;
}
/* --fluid heroes (conference, donate) on desktop: the photo is an absolute
   backdrop only 24px (top: lg) below the section's top edge, so without the
   template gap it would sit 24px under the breadcrumb. Move the whole hero
   down another 24px (a margin, so the photo and the in-flow card move together
   and their geometry is untouched): breadcrumb → photo is then 48px, the same
   as the base T2's padding gives Lobby Day. Below 900px the photo is in flow
   and the section's own padding is the gap (see "Mobile heroes"). (0,2,0)
   beats the constrained layout's first-child margin reset. */
@media (min-width: 901px) {
  .wp-block-post-content > .hero-t2--fluid:first-child { margin-block-start: var(--spacing-lg); }
}

/* Eyebrows — the single source of truth (moved here from tokens.css), UNSCOPED.
   The front end is <body class="ccl"> so a .ccl scope adds nothing there, but the
   block-editor canvas has NO .ccl ancestor — a .ccl-scoped rule renders in
   preview yet goes unstyled while editing (this is what made the conferences /
   monthly-meetings eyebrows look plain in the editor). ONE set covers BOTH the
   raw .eyebrow-* classes (emitted directly by those ACF blocks) AND the
   is-style-eyebrow-* block styles (the editor's Styles-panel picker). Tokens are
   on :root, so the vars resolve either way.

   THREE ROLES (see preview/eyebrows.html): .eyebrow-blue = page-level wayfinding
   (one/page); .eyebrow-green = block section-type (one/block); .eyebrow-meta =
   timeline/list label (repeats; lighter + tighter so a stack reads as calm). */
.eyebrow-blue,
.eyebrow-green,
.eyebrow-meta,
.explainer-step__text::before,
.is-style-eyebrow-blue,
.is-style-eyebrow-green {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 var(--spacing-sm);
  display: block;
}
.eyebrow-blue  { color: var(--ccl-blue); }
.eyebrow-green,
.explainer-step__text::before { color: var(--ccl-green-dark); } /* + Take Action's auto-numbered "Step N" */
/* The is-style picks list AFTER the raw ones so the editor's Styles-panel choice
   wins the (0,1,0) tie if a paragraph ever carries both a raw and an is-style
   class — the chosen color takes effect. */
.is-style-eyebrow-blue  { color: var(--ccl-blue); }
.is-style-eyebrow-green { color: var(--ccl-green-dark); }
.eyebrow-meta {
  color: var(--ccl-blue);
  font-weight: var(--fw-weak);
  font-size: var(--fs-tiny);
  line-height: calc(var(--lh-tiny) / var(--fs-tiny));
  letter-spacing: 0.14em;
}

/* "Gradient" separator (core/separator block style) — the brand blue→green rule,
   full-width under a heading (e.g. the monthly-meeting "three parts" cards). Uses
   the horizontal --gradient-underline token at 3px, matching the header/active-nav
   dividers. The :not()s mirror core's own separator-width selector so this beats
   its 100px default and spans the column. (Gradient/Wide/Dots are mutually
   exclusive block styles, so the :not()s only ever add specificity here.) */
/* --------------------------------------------------------------------------
   "What to expect" card (patterns/conference-what-to-expect) — a white card
   holding icon-and-line rows. Ported from the live conference page's .icon-box
   of .stat rows (dante-child/conference-2025.php).

   A list, not a row of pillars: each line is a sentence, and three of those
   across a 1166px row leaves each one four words wide. The green circle is
   baked into the icon image, so a row is only an Image beside a Paragraph.
   -------------------------------------------------------------------------- */
.expect-card {
  background: var(--grey-0);
  border-radius: var(--radius-lg);
  padding: var(--spacing-2xl);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.ccl .expect-card .expect-card__title { margin: 0 0 var(--spacing-xl); }
.expect-row {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: var(--spacing-lg);
  align-items: center;
}
/* Both children are grid items; is-layout-flow's `> * + *` would push the text
   down a line from the icon it belongs beside. */
.expect-row > * + * { margin-block-start: 0; }
.expect-row p { margin: 0; }
.expect-row img { width: 72px; height: 72px; display: block; object-fit: contain; }
@media (max-width: 620px) {
  .expect-card { padding: var(--spacing-lg); }
  .expect-row { grid-template-columns: 56px minmax(0, 1fr); gap: var(--spacing-md); }
  /* max-*, not just width/height: a resized Image block carries an inline
     `width:72px;height:72px`, which beats any stylesheet width or height, so
     the icon squashed to 56x72. A max- size still caps an inline one. */
  .expect-row img { width: 56px; height: 56px; max-width: 56px; max-height: 56px; }
}

/* --------------------------------------------------------------------------
   Registration band (patterns/conference-registration) — its own row, with a
   clean edge top and bottom.

   Deliberately NOT .is-style-gradient-wash, which fades to white at the bottom
   so the content after it sits on white without a seam. That is right for a
   section that flows into the page and wrong for this one: it should read as a
   distinct band. The gradient comes from the Pale wash theme.json preset, so
   an editor can change it from Color -> Background -> Gradient.
   -------------------------------------------------------------------------- */
.event-cta-band { padding-block: var(--spacing-5xl); }
@media (max-width: 900px) {
  .event-cta-band { padding-block: var(--spacing-3xl); }
}

/* "Handwritten" Paragraph style — the kicker above a section heading, e.g.
   "Tickets are going fast" over "Secure your spot". Ported from the live
   conference page's .classy-embed-prompt, which uses the same face. A style
   rather than a one-off class because the treatment is the same wherever it
   appears and an editor should be able to reach it from the Paragraph panel. */
.is-style-handwritten {
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--fs-h4);
  color: var(--grey-600);
  margin: 0 0 var(--spacing-xs);
}

.wp-block-separator.is-style-gradient:not(.is-style-wide):not(.is-style-dots) {
  border: 0;
  height: 3px;
  max-width: none;
  background: var(--gradient-underline);
  opacity: 1;
}

/* "Thick rule" — the section divider as a block. Same bar as the .divider-thick
   pattern (4px, --grey-200, 780px, centred) with one difference: it brings its
   own vertical margin. The pattern has none, so every use either added spacing
   by hand or sat flush against the next section.

   The :not() pair matches the gradient style above: core ships "Wide Line" and
   "Dots" as separator styles too, and without excluding them a user who picks
   one on top of this gets both sets of rules.

   Width is deliberately narrower than the 1166px content column — a rule that
   spans the full measure reads as a page break rather than a section change. */
.wp-block-separator.is-style-thick:not(.is-style-wide):not(.is-style-dots) {
  border: 0;
  height: 4px;
  width: 100%;
  max-width: 780px;
  background: var(--grey-200);
  opacity: 1;
  margin-block: var(--spacing-4xl);
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   Buttons — the single source of truth (moved here from tokens.css).
   UNSCOPED on purpose: the front end is <body class="ccl"> (a .ccl scope
   adds nothing there) and the editor canvas has NO .ccl — so a .ccl-scoped
   rule is invisible in the editor and drifts from the front end.
   -------------------------------------------------------------------------- */
.btn {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-md);
  line-height: 1;
  padding: 11px 18px;
  border-radius: var(--radius-pill); /* pill = action (matches the prototype) */
  border: 2px solid transparent;
  cursor: pointer;
  letter-spacing: 0.01em;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  min-width: 133px;
  white-space: nowrap;
  text-decoration: none;
}
.btn-primary {
  background: var(--ccl-green);
  color: var(--ccl-black);
  border-color: var(--ccl-green);
  font-weight: 600; /* a touch heavier on CCL-green to hold perceived weight with black ink */
}
.btn-primary:hover { background: var(--ccl-green-dark); border-color: var(--ccl-green-dark); color: #fff; }
.btn-primary:active,
.btn-primary.pressed { background: var(--ccl-green-pressed); border-color: var(--ccl-green-pressed); color: var(--ccl-black); }
.btn-primary[disabled] { background: var(--ccl-grey-50); border-color: var(--ccl-grey-50); color: var(--ccl-grey-80); cursor: not-allowed; }

/* Secondary — solid charcoal fill, white text. High-contrast alt to primary
   (the prototype's Donate button). Surfaced for core buttons via the
   register_block_style('core/button','secondary') mapping below. */
.btn-secondary {
  background: #2A2A2B;
  color: #fff;
  border-color: #2A2A2B;
}
.btn-secondary:hover { background: #000; border-color: #000; color: #fff; }
.btn-secondary:active,
.btn-secondary.pressed { background: #474748; border-color: #474748; color: #fff; }
.btn-secondary[disabled] { background: var(--ccl-green-pressed); border-color: var(--ccl-green-pressed); color: rgba(0,0,0,0.35); cursor: not-allowed; }

/* Tertiary — outlined button with dark ink. Sits below primary/secondary. */
.btn-tertiary {
  background: transparent;
  color: var(--ccl-black);
  border-color: var(--ccl-black);
}
.btn-tertiary:hover { background: var(--ccl-grey-10); color: var(--ccl-black); border-color: var(--ccl-black); }
.btn-tertiary:active,
.btn-tertiary.pressed { background: var(--ccl-grey-30); border-color: var(--ccl-black); color: var(--ccl-black); }
.btn-tertiary[disabled] { background: var(--ccl-grey-30); border-color: var(--ccl-grey-30); color: var(--ccl-grey-70); cursor: not-allowed; }
.btn-tertiary > .wp-block-button__link,
.wp-block-button.btn-tertiary > .wp-block-button__link {
  background-color: transparent;
  color: var(--ccl-black);
  border-color: var(--ccl-black);
}

.btn-tertiary > .wp-block-button__link:hover {
  background-color: var(--ccl-grey-10);
  color: var(--ccl-black);
  border-color: var(--ccl-black);
}

.btn-tertiary > .wp-block-button__link:active,
.btn-tertiary.pressed > .wp-block-button__link {
  background-color: var(--ccl-grey-30);
  color: var(--ccl-black);
  border-color: var(--ccl-black);
}

.btn-tertiary > .wp-block-button__link[disabled] { background: var(--ccl-grey-30); border-color: var(--ccl-grey-30); color: var(--ccl-grey-70); cursor: not-allowed; }

/* Low emphasis — light outline, dark ink. Use when a tertiary would feel too heavy. */
.btn-low {
  background: transparent;
  color: var(--ccl-text);
  border-color: var(--ccl-grey-50);
  border-width: 1px;
  padding: 12px 18px; /* +1 each side to keep the same total height with a 1px border */
}
.btn-low:hover { background: var(--ccl-grey-10); border-color: var(--ccl-grey-70); color: var(--ccl-text); }
.btn-low:active,
.btn-low.pressed { background: var(--ccl-grey-30); border-color: var(--ccl-grey-70); }
.btn-low[disabled] { border-color: var(--ccl-grey-30); color: var(--ccl-grey-70); cursor: not-allowed; }

/* Destructive — red outline + red ink. Confirmations for deletion / irreversible actions. */
.btn-danger {
  background: transparent;
  color: var(--ccl-alert-red);
  border-color: var(--ccl-alert-red);
}
.btn-danger:hover { background: var(--ccl-alert-red-bg); color: var(--ccl-alert-dark-red); border-color: var(--ccl-alert-dark-red); }
.btn-danger:active,
.btn-danger.pressed { background: var(--ccl-alert-red-light); color: var(--ccl-alert-dark-red); border-color: var(--ccl-alert-dark-red); }
.btn-danger[disabled] { border-color: var(--ccl-grey-50); color: var(--ccl-grey-70); cursor: not-allowed; }

/* Ghost on dark — translucent white fill, white ink. Use ONLY on dark
   backgrounds (navy CTA banners, dark hero scrim). On light use tertiary/low. */
.btn-ghost-on-dark {
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.5);
  backdrop-filter: blur(2px);
}
.btn-ghost-on-dark:hover  { background: rgba(255, 255, 255, 0.3);  border-color: rgba(255, 255, 255, 0.7); color: #fff; }
.btn-ghost-on-dark:active,
.btn-ghost-on-dark.pressed { background: rgba(255, 255, 255, 0.45); border-color: #fff; color: var(--ccl-black); }
.btn-ghost-on-dark[disabled] { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.2); color: rgba(255, 255, 255, 0.5); cursor: not-allowed; }

/* "Secondary" core-Button style (register_block_style core/button 'secondary') —
   the same charcoal fill as .btn-secondary, so native buttons and ACF-block
   buttons match. Radius/typography inherit from theme.json elements.button. */
.wp-block-button.is-style-secondary .wp-element-button {
  background-color: #2A2A2B;
  border-color: #2A2A2B;
  color: #fff;
}
.wp-block-button.is-style-secondary .wp-element-button:hover {
  background-color: #000;
  border-color: #000;
  color: #fff;
}

/* --------------------------------------------------------------------------
   Display + heading helpers
   -------------------------------------------------------------------------- */
/* Display heading — single unscoped source of truth (was also defined scoped in
   tokens.css; consolidated here with the front-end values so editor + front end
   match). Weight 700 (a real Ubuntu bold face exists; 600 was faux-bold) and a
   unitless line-height ratio (the old fixed 64px broke at the mobile font size). */
.display, .t-display {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h1-display);
  line-height: calc(var(--lh-h1-display) / var(--fs-h1-display));
  letter-spacing: -0.01em;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
/* Unscoped (was `.ccl .h1-bold`): a heading utility applied by name only, so the
   editor canvas (no .ccl ancestor) styles it too — patterns using .h1-bold now
   look right while editing, not just in preview. */
.h1-bold {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: var(--ccl-black);
  /* No margin here on purpose — typography utility, not layout. Each
     context (.section-header, .values-header, .action-blogs) sets its
     own spacing. */
}
.h2-regular {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0;
}
/* "Regular weight" — the Heading block style (ccl_register_heading_block_styles).
   Weight only: the level still sets the size, so an H1 stays H1-sized.
   (0,3,0) on purpose — the style is an explicit editor choice, so it has to
   beat every weight a placement can set: theme.json / tokens.css per-level
   weights (0,0,1), `.stories-hero h1` (0,1,1), and the component heading rules
   at (0,2,1) — `.hero-t1--media .hero-t1__text h1`, `.partnership-block .copy
   h2`, `.ccl .hm-statefinder__copy h2`. The repeated class is only there for
   the weight. */
.wp-block-heading.is-style-regular.is-style-regular { font-weight: var(--fw-weak); }
/* "Item title" — the Heading block style for a title inside a repeated item
   (tile, card, list item). The level stays semantic (an h3 under a section's
   h2); only the size changes, to --fs-item-title (24px). The one sanctioned
   exception to tag = size — see CLAUDE.md, "Headings: level vs style". Same
   (0,3,0) as Regular weight, for the same reason: it's an explicit choice and
   must beat per-level and component sizes. */
.wp-block-heading.is-style-item-title.is-style-item-title {
  font-size: var(--fs-item-title);
  line-height: calc(var(--lh-item-title) / var(--fs-item-title));
}
/* Lede paragraph -- the opening line of a state page, a section intro. It had
   been 19px, identical to body copy, so it did nothing. 20px (--fs-h5) is the
   size the theme's other ledes already use: .conference-hero__lede,
   .stories-hero p and .hero-t1__text p. Only the size and leading differ from
   body copy; everything else inherits. */
.body-lead {
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
}
/* "Subhead — Body" — reset a subhead to default body prose (--fs-body, 19px). */
.is-style-subhead-body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--leading-body);
}
/* --------------------------------------------------------------------------
   T1 hero (used on page 1)
   Two-column split, blue offset slot behind a photo on the right.
   Slot ratio for photo/video: 1.05fr 1fr (per Hero System.md)
   -------------------------------------------------------------------------- */
.hero-t1 {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: var(--spacing-5xl);
  padding: var(--spacing-5xl) var(--page-gutter);
  align-items: center;
}
.hero-t1__text { max-width: 560px; }

/* Hand-drawn underline — the brand's marker stroke under a word/phrase. Applied
   via the "Gradient underline" inline format (span.hdr-underline; see
   editor-formats.js) or by pattern/ACF markup. UNSCOPED so it renders in the
   editor canvas too. background-image + box-decoration-break: clone lets the
   stroke stretch per line when the phrase wraps. */
.hdr-underline {
  background-image: url('/wp-content/themes/twentytwentyfive-child/assets/brand/underlines/single-xlg.svg');
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.32em;
  padding-bottom: 0.28em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
/* At display size (hero headline, 56px) the stroke sits thicker + closer. Inherits
   the SVG + repeat/position/clone from the base rule above. (This previously
   pointed at a missing `underline-xlg.svgs` asset, so the hero underline was
   silently broken — now it reuses the fetched single-xlg.svg.) */
.hero-t1 .hdr-underline {
  background-size: 100% 18px;
  padding-bottom: 0.18em;
}
.hero-t1__text .display { margin-top: var(--spacing-md); margin-bottom: var(--spacing-lg); }
/* :not([class*="eyebrow"]) — this is the lede-paragraph rule; without the guard
   its color:black would override the eyebrow's own blue/green (the eyebrow is
   also a <p>, only 0,1,0, so this 0,1,1 rule wins). */
.hero-t1__text p:not([class*="eyebrow"]) {
  font-size: 20px;
  line-height: var(--spacing-xl);
  margin: 0 0 var(--spacing-lg);
}

.hero-t1__media {
  position: relative;
  width: 100%;
  z-index: 0;
  aspect-ratio: 16 / 9;
}
/* Modifier — use when the slot holds something other than a photo
   (a CongressWeb widget, an action card, a third-party embed). The
   blue offset stays (per Hero System.md T1 action-tool pattern) but the
   fixed aspect-ratio is dropped so the slot grows to fit content. */
.hero-t1__media--bare { aspect-ratio: auto; }
/* Blue offset slot — extends ABOVE and to the RIGHT of the photo, all four
   corners rounded at --radius-lg. Matches the .slot-bg pattern in the design
   system's Hero System CSS. */
.hero-t1__media::before {
  content: '';
  position: absolute;
  inset: -28px -28px 28px 28px;
  background: var(--ccl-blue);
  border-radius: var(--radius-lg);
  z-index: 0;
}
.hero-t1__media .photo {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.hero-t1__media .photo img { width: 100%; height: 100%; object-fit: cover; }
/* Ambient video in the slot (Monthly Meeting) — a core Video block with the
   `photo` class, Autoplay + Loop + Muted on, no controls. It fills and crops
   exactly like the photo; the block's own caption becomes a lower-third over
   the footage (prototype .hero-video-caption). The pause toggle is added by
   ccl_ambient_video_toggle() — see .video-toggle below. */
.hero-t1__media .photo video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.hero-t1__media .wp-block-embed {
  position: relative;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  z-index: 1;
}
.hero-t1__media iframe {
  display: block;
  width: 100%;
  min-height: 280px;
  border: 0;
  border-radius: var(--radius-lg);
}
.hero-t1__media .photo .wp-element-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  margin: 0;
  padding: var(--spacing-2xl) var(--spacing-lg) var(--spacing-md);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
  color: #fff;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.4;
  text-align: left;
}
.hero-t1__media .photo .wp-element-caption strong { font-weight: 700; }
/* On a phone the slot is ~200px tall; the desktop caption would cover 40% of it. */
@media (max-width: 600px) {
  .hero-t1__media .photo .wp-element-caption {
    padding: var(--spacing-lg) var(--spacing-md) var(--spacing-sm);
    font-size: 13px;
  }
}

/* Pause / play toggle for any looping autoplay core Video block (WCAG 2.2.2 —
   motion that runs past 5s needs a way to stop it). Rendered by
   ccl_ambient_video_toggle(), wired by assets/js/ambient-video.js. Top-right,
   so it never sits on a caption — the hero's lower-third or a normal caption
   under the video. */
.wp-block-video:has(> .video-toggle) { position: relative; }
.video-toggle {
  position: absolute;
  top: var(--spacing-md);
  right: var(--spacing-md);
  z-index: 3;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  cursor: pointer;
  transition: background .15s;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.video-toggle:hover { background: rgba(0, 0, 0, 0.75); }
.video-toggle:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.video-toggle__icon { width: 20px; height: 20px; fill: currentColor; }
/* Playing → show the pause glyph; paused → the play glyph. */
.video-toggle .video-toggle__icon--play,
.video-toggle.is-paused .video-toggle__icon--pause { display: none; }
.video-toggle.is-paused .video-toggle__icon--play { display: block; }

/* Slideshow — the Gallery block's "Slideshow" style (ccl_gallery_slideshow()
   + assets/js/gallery-slideshow.js). The photos stack in one 16:10 frame and
   crossfade; each image's caption is a chip bottom-left (a year, a place), and
   the controls (pause + a dot per photo) sit bottom-right on a dark pill so
   they read on any photo. .gallery-slideshow is added server-side on the front
   end only, so the editor keeps the normal grid and every photo stays
   editable. Width and margin need !important: core sizes gallery images with
   figure.wp-block-image:not(#individual-image), which carries ID weight. */
figure.wp-block-gallery.gallery-slideshow {
  display: grid;
  /* minmax(0, …): an auto track would grow to the photos' natural width and
     push the frame past a phone's edge. */
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  min-width: 0;
  gap: 0;
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  aspect-ratio: 16 / 10;
}
figure.wp-block-gallery.gallery-slideshow > figure.wp-block-image {
  grid-area: 1 / 1;
  width: 100% !important;
  height: 100%;
  margin: 0 !important;
  opacity: 0;
  transition: opacity .8s ease;
}
/* First photo shows before the script runs; after that, .is-active rules. */
figure.wp-block-gallery.gallery-slideshow:not(.is-ready) > figure.wp-block-image:first-child,
figure.wp-block-gallery.gallery-slideshow > figure.wp-block-image.is-active { opacity: 1; }
figure.wp-block-gallery.gallery-slideshow > figure.wp-block-image > a { height: 100%; }
figure.wp-block-gallery.gallery-slideshow > figure.wp-block-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (prefers-reduced-motion: reduce) {
  figure.wp-block-gallery.gallery-slideshow > figure.wp-block-image { transition: none; }
}
/* Caption → chip. Core overlays captions on a blurred gradient strip. */
figure.wp-block-gallery.is-style-slideshow > figure.wp-block-image:has(figcaption)::before { content: none; }
figure.wp-block-gallery.is-style-slideshow > figure.wp-block-image figcaption {
  position: absolute;
  left: var(--spacing-sm);
  right: auto;
  bottom: var(--spacing-sm);
  max-width: 55%;
  margin: 0;
  padding: var(--spacing-2xs) var(--spacing-sm);
  overflow: visible;
  background: rgba(255, 255, 255, .92);
  border-radius: var(--radius-sm);
  color: var(--ccl-black);
  text-shadow: none;
  text-align: left;
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-small);
  line-height: 1.3;
}
/* The gallery's own caption (under the whole block) has no place in a frame. */
figure.wp-block-gallery.gallery-slideshow > figcaption.blocks-gallery-caption { display: none; }
.slideshow-controls {
  position: absolute;
  right: var(--spacing-sm);
  bottom: var(--spacing-sm);
  z-index: 2;
  display: flex;
  align-items: center;
  padding: 2px 6px;
  border-radius: var(--radius-pill);
  background: rgba(0, 0, 0, .45);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
/* 24px targets (WCAG 2.5.8) around a 10px dot. */
.slideshow-toggle,
.slideshow-dot {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  cursor: pointer;
}
.slideshow-dot::before {
  content: '';
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .5);
  transition: background .15s;
}
.slideshow-dot:hover::before { background: rgba(255, 255, 255, .8); }
.slideshow-dot[aria-current]::before { background: #fff; }
.slideshow-toggle:focus-visible,
.slideshow-dot:focus-visible { outline: 2px solid #fff; outline-offset: -2px; border-radius: 50%; }
.slideshow-toggle__icon { width: 14px; height: 14px; fill: currentColor; }
.slideshow-toggle .slideshow-toggle__icon--play,
.slideshow-toggle.is-paused .slideshow-toggle__icon--pause { display: none; }
.slideshow-toggle.is-paused .slideshow-toggle__icon--play { display: block; }

/* Split feature — a section-level promo: eyebrow + heading + lead + button on
   one side, an image on the other (Events page: "Lobby Day", "Meetings in your
   community"). A lighter cousin of hero-t1 — no accent mark or blue-offset slot,
   an .h1-bold heading (not .display), a plain rounded photo. Drop the eyebrow
   for the no-label variant. Paragraph sizing targets .body-lead specifically so
   the eyebrow (also a <p>) keeps its own size. */
.split-feature {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: var(--spacing-5xl);
  align-items: center;
}
.split-feature__text { max-width: 560px; }
.split-feature__text .h1-bold { margin: 0 0 var(--spacing-md); }
.split-feature__text .body-lead { margin: 0 0 var(--spacing-lg); }
.split-feature__media .wp-block-image,
.split-feature__media figure { margin: 0; }
.split-feature__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
}
/* --media-first: photo on the left, copy on the right, equal columns — the
   prototype's .conference-callout (the conference venue section). The photo is
   cropped rather than left at its own ratio so a landscape hotel shot lines up
   with the copy block; align-items:center on the base component keeps the two
   sides balanced, which an overlaid card does not. */
.split-feature--media-first { grid-template-columns: 1fr 1fr; gap: var(--spacing-3xl); }
.split-feature--media-first .split-feature__media { order: -1; aspect-ratio: 3 / 2; border-radius: var(--radius-lg); overflow: hidden; background: var(--grey-200); }
.split-feature--media-first .split-feature__media img { height: 100%; object-fit: cover; border-radius: 0; }
.split-feature--media-first .split-feature__text { max-width: none; }

/* Stack on narrow screens — image drops below the copy. */
@media (max-width: 782px) {
  .split-feature { grid-template-columns: 1fr; gap: var(--spacing-xl); }
  .split-feature__text { max-width: none; }
}

/* Hero T2 — extensions for the conference "Registration hero" (reg-hero) mode.
   The base component (.hero-t2 / __photo / __card / eyebrow-blue / h1 / p) and
   .gradient-text already live in the Take Action section below — these only ADD
   what reg-hero needs on top: card event-meta spacing, full-bleed on alignfull,
   the --fluid variant (card in flow over a cover photo), and the mobile reflow.
   (Opt-in / higher-specificity selectors, so order vs the base doesn't matter.) */
.hero-t2__card .event-meta { margin: 0 0 var(--spacing-lg); }
/* … unless it ends the card: a recap with no replay link drops the CTA (see
   the conferences block), and that trailing margin would stack on the card's
   own padding. */
.hero-t2__card .event-meta:last-child { margin-bottom: 0; }
/* The CTA is the hero's primary action — larger than a default .btn (16px).
   Reg-hero only (PHP-rendered .btn): the prototype's T2 keeps default-size
   buttons, so the hero-t2 pattern's core Buttons are deliberately NOT matched
   here — two of them at this size wrap inside the 510px card. */
.hero-t2__card .btn { font-size: 18px; padding: 14px 30px; }

/* Full-bleed: only the reg-hero opts into true full width (its block Full align).
   The base's 1440px cap stays the default; alignfull releases it so the hero
   fills the viewport (keeping the --page-gutter side padding + rounded photo). */
.hero-t2.alignfull { max-width: none; }

/* --fluid — the card returns to normal flow and the photo stretches behind it as
   a cover background (the conference + donate pages). */
.hero-t2--fluid .hero-t2__photo {
  position: absolute;
  top: var(--spacing-lg);
  bottom: var(--spacing-lg);
  left: var(--page-gutter);
  right: var(--page-gutter);
  width: auto;
  aspect-ratio: auto;
}
.hero-t2--fluid .hero-t2__card {
  position: relative;
  top: auto;
  left: auto;
  transform: none;
  margin: var(--spacing-2xl) 0 var(--spacing-2xl) var(--spacing-5xl);
}
/* Tighten the reg-hero's vertical footprint (the base uses 3xl/5xl padding + 3xl
   bottom margin, which read as too much here). Scoped off --tight so the donate
   hero keeps the extra depth its press strip needs. Compound with .hero-t2 to win
   over the base padding, which sits later in this file. */
.hero-t2.hero-t2--fluid:not(.hero-t2--tight) {
  padding-block: var(--spacing-lg);
  margin-bottom: var(--spacing-lg);
}
/* Don't let the reg-hero's photo get flatter than 2.75:1 on wide screens. The
   photo's height comes from the card and its width from the viewport, so with
   nothing else setting it a 1920px screen gave a 3.4:1 strip and `cover` cut
   off people's heads. This minimum height grows with the width (the photo is the
   section minus the gutters and its lg insets), and the card stays centred in
   the extra height. Capped at 760px so very large monitors don't get a hero
   taller than the screen; past about 2130px the photo gets flatter again. Below
   about 1700px the card is already tall enough and nothing changes. Not on
   --tight (donate), where the widget card makes the box tall already. Desktop
   only: ≤900px puts the photo back in flow at its own 6:5. */
@media (min-width: 901px) {
  .hero-t2.hero-t2--fluid:not(.hero-t2--tight) {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: min(calc((100vw - 2 * var(--page-gutter)) / 2.75 + 2 * var(--spacing-lg)), 760px);
  }
}

/* Donate hero — the hero-t2 --widget variant (give.html): the floating card holds
   a live Classy donation embed + trust badges + a tax note, and an "As featured in"
   press strip overlays the photo's bottom edge. --tight adds photo depth so the
   strip clears the card. (Skipped the homepage-only `--tight + .ccl-stats` seam.) */
/* Photo placed as a wp:image (donate-hero pattern) rather than the reg-hero's raw
   <img> — reset the figure so it fills the absolute --fluid photo slot. */
.hero-t2__photo.wp-block-image { margin: 0; display: block; }
/* Compound selectors (.hero-t2__card.hero-t2__card--widget etc.) so these win by
   SPECIFICITY over the base .hero-t2__card rules, which sit later in this file —
   otherwise the base's 510px card + display headline + 5xl padding win the
   same-specificity tie, making the card narrow (4-line headline) and letting the
   press strip overlap it. (--fluid already wins this way.) */
.hero-t2__card.hero-t2__card--widget { max-width: 600px; width: 100%; }
.hero-t2--fluid .hero-t2__card--widget { margin: var(--spacing-3xl) 0 var(--spacing-3xl) var(--spacing-3xl); }
.hero-t2__card.hero-t2__card--widget h1 {
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
}
.hero-t2__card--widget .classy-inline-embed { min-height: 480px; margin-top: var(--spacing-sm); }
.hero-t2__card--widget .give-hero-b__trust { margin-top: var(--spacing-lg); }
.hero-t2__card--widget .give-hero__tax { margin: var(--spacing-md) 0 0; font-size: var(--fs-tiny); line-height: var(--lh-tiny); }
.hero-t2.hero-t2--tight { padding-bottom: calc(var(--spacing-5xl) + var(--spacing-3xl) + var(--spacing-md)); margin-bottom: 0; }
/* The press strip sits on the photo's bottom edge (its scrim's rounded bottom
   corners match the photo's), so with a strip the photo keeps the prototype's
   insets: it ends 5xl up, exactly where .give-press does. The base --fluid
   photo's lg insets are the reg hero's tightening (25a9269) — applied here they
   left 56px of photo hanging below the strip. ≤900px puts both back in flow. */
.hero-t2--fluid:has(> .give-press) > .hero-t2__photo {
  top: var(--spacing-3xl);
  bottom: var(--spacing-5xl);
}

/* Trust row — badges + "A charity you can trust." */
.give-hero-b__trust { display: flex; align-items: center; gap: var(--spacing-md); flex-wrap: wrap; }
.give-hero-b__trust img { display: block; height: 44px; width: auto; }
.give-hero-b__trust p {
  flex: 1;
  min-width: 200px;
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
  margin: 0;
}
.give-hero__tax {
  font-family: var(--font-body);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--grey-500);
  margin: var(--spacing-lg) 0 0;
}

/* "As featured in" press strip — overlays the photo's bottom edge on a dark scrim
   (the outlet logos are white art). Absolutely placed within the .hero-t2 section. */
.give-press {
  position: absolute;
  left: var(--page-gutter);
  right: var(--page-gutter);
  bottom: var(--spacing-5xl);
  padding: var(--spacing-2xl) var(--spacing-lg) var(--spacing-lg);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  text-align: center;
}
.give-press__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-tiny);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  margin: 0 0 var(--spacing-md);
}
.give-press__row {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: 1100px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--spacing-md) var(--spacing-2xl);
  overflow-x: auto;
  scrollbar-width: none;
}
.give-press__row::-webkit-scrollbar { display: none; }
.give-press__row li { flex: none; }
.give-press__row img { display: block; height: 26px; width: auto; }

/* ==========================================================================
   Funding breakdown — give.html's "Your money directly supports…" section
   (prototype .give-money). The pattern (funding-breakdown.php) is the section:
   a section header, the acf/ccl-funding-bar block (bar + legend + note), and a
   row of watchdog badges as core Images so they can be swapped each year.
   The .give-money wrapper's 900px cap is the pattern group's contentSize, and
   the page gutter is the template's, so neither is restated here.
   ========================================================================== */
.give-money__chart { margin-block: var(--spacing-2xl) 0; }
.give-money__bar {
  display: flex;
  height: 20px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin: 0 0 var(--spacing-md);
}
/* Colours go by position so editors never pick one: navy / blue / light blue
   (the live donate page's chart), then grey for a fourth share. The prototype's
   #3fb1ef has no token; --light-blue (#1FB3E1) is the theme's nearest. The
   legend swatches follow the same order. */
.give-money__bar span:nth-child(1),
.give-money__legend li:nth-child(1) .give-money__swatch { background: var(--ccl-blue-dark); }
.give-money__bar span:nth-child(2),
.give-money__legend li:nth-child(2) .give-money__swatch { background: var(--ccl-blue); }
.give-money__bar span:nth-child(3),
.give-money__legend li:nth-child(3) .give-money__swatch { background: var(--light-blue); }
.give-money__bar span:nth-child(4),
.give-money__legend li:nth-child(4) .give-money__swatch { background: var(--grey-300); }
.give-money__legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm) var(--spacing-xl);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--ccl-black);
}
.give-money__legend li { display: inline-flex; align-items: center; gap: var(--spacing-2xs); margin: 0; }
.give-money__legend b { font-weight: var(--fw-strong-body); }
.give-money__swatch { flex: none; width: 12px; height: 12px; border-radius: 3px; }
/* p.-qualified: theme.json sizes every paragraph with `:root :where(p)` at
   (0,1,0), which ties a bare class and wins in the editor canvas, where the
   global styles load after site.css (the note showed at 19px there). */
p.give-money__note {
  font-family: var(--font-body);
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
  margin: var(--spacing-sm) 0 0;
}
/* Watchdog seals — a centred row Group of core Images. Doubled onto
   .wp-block-image so the 100px width beats core's image sizing on any page. */
.give-money__badges { margin-block-start: var(--spacing-2xl); }
.give-money__badges .wp-block-image.give-money__badge { margin: 0; }
.give-money__badges .wp-block-image.give-money__badge img { display: block; width: 100px; height: auto; }
/* Three 100px seals + two 32px gaps need 364px; a 375px phone leaves 327.
   A 12px gap (324px) keeps them on one row. Doubled onto .wp-block-group to beat
   the gap core's layout prints for the Group's block-gap setting. */
@media (max-width: 600px) {
  .give-money__badges.wp-block-group { gap: var(--spacing-sm); }
}

/* ==========================================================================
   Chart — acf/ccl-chart (blocks/chart), a line chart over time. No prototype
   original: the prototype has no charts. Built to the dataviz rules: thin 2.5px
   lines, recessive gridlines, values and labels in text ink (never the series
   colour), a coloured key beside each name.
   Layout: the frame is a grid of [y labels | plot] over [· | year labels]. The
   lines are an SVG stretched to the plot; dots and labels are HTML positioned
   by % on top (render.php explains why). The plot keeps room on its right for
   the end-of-line values.
   ========================================================================== */
.ccl-chart { margin-block: var(--spacing-2xl) 0; font-family: var(--font-body); color: var(--ccl-black); --chart-h: 300px; }
.ccl-chart [data-series="1"] { --series: var(--chart-1); }
.ccl-chart [data-series="2"] { --series: var(--chart-2); }
.ccl-chart [data-series="3"] { --series: var(--chart-3); }
.ccl-chart [data-series="4"] { --series: var(--chart-4); }
/* Two classes deep: theme.json sizes h2–h4 at (0,1,0) and would tie. The level
   is the outline's; the look is the item-title size whatever the level. */
.ccl-chart .ccl-chart__title {
  font-family: var(--font-display);
  font-size: var(--fs-item-title);
  line-height: var(--lh-item-title);
  font-weight: var(--fw-strong-heading);
  margin: 0 0 var(--spacing-sm);
}
.ccl-chart__legend {
  list-style: none;
  margin: 0 0 var(--spacing-md);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs) var(--spacing-lg);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.ccl-chart__key { display: inline-flex; align-items: center; gap: var(--spacing-xs); margin: 0; }
.ccl-chart__key svg { flex: none; width: 28px; height: 4px; overflow: visible; }
.ccl-chart__key line { stroke: var(--series); stroke-width: 3; stroke-linecap: round; }

.ccl-chart__frame {
  display: grid;
  grid-template-columns: 3em minmax(0, 1fr);
  column-gap: var(--spacing-sm);
  padding-inline-end: 3.5em; /* the end-of-line values */
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  font-variant-numeric: tabular-nums;
}
.ccl-chart__yaxis { position: relative; height: var(--chart-h); color: var(--grey-500); }
.ccl-chart__yaxis span { position: absolute; right: 0; transform: translateY(-50%); white-space: nowrap; }
.ccl-chart__plot { position: relative; height: var(--chart-h); touch-action: pan-y; }
.ccl-chart__svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.ccl-chart__grid { stroke: var(--grey-200); stroke-width: 1; }
.ccl-chart__base { stroke: var(--grey-300); stroke-width: 1; }
.ccl-chart__line { fill: none; stroke: var(--series); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.ccl-chart__area { fill: var(--chart-1); opacity: 0.1; }
.ccl-chart__dot {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--series);
  box-shadow: 0 0 0 2px var(--grey-0);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.ccl-chart__end {
  position: absolute;
  left: calc(100% + var(--spacing-sm));
  transform: translateY(-50%);
  font-weight: var(--fw-strong-body);
  white-space: nowrap;
}
.ccl-chart__xaxis { grid-column: 2; position: relative; height: 32px; color: var(--grey-500); }
.ccl-chart__xaxis span { position: absolute; top: var(--spacing-xs); transform: translateX(-50%); white-space: nowrap; }

/* Hover readout (view.js). Hidden until the plot has .is-hovering. */
.ccl-chart__cross,
.ccl-chart__dot--hover,
.ccl-chart__tip { display: none; }
.ccl-chart__plot.is-hovering .ccl-chart__cross { display: block; position: absolute; top: 0; bottom: 0; width: 1px; background: var(--grey-400); pointer-events: none; }
.ccl-chart__plot.is-hovering .ccl-chart__dot--hover { display: block; z-index: 1; }
.ccl-chart__plot.is-hovering .ccl-chart__dot--hover[hidden] { display: none; }
.ccl-chart__plot.is-hovering .ccl-chart__tip {
  display: block;
  position: absolute;
  top: 0;
  z-index: 2;
  min-width: 150px;
  transform: translateX(var(--spacing-sm));
  padding: var(--spacing-xs) var(--spacing-sm);
  background: var(--grey-0);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
  pointer-events: none;
}
.ccl-chart__plot.is-hovering .ccl-chart__tip.is-flipped { transform: translateX(calc(-100% - var(--spacing-sm))); }
/* p.-qualified: theme.json sizes every paragraph at (0,1,0). */
p.ccl-chart__tip-head { margin: 0 0 var(--spacing-2xs); font-size: var(--fs-tiny); line-height: var(--lh-tiny); font-weight: var(--fw-strong-body); }
p.ccl-chart__tip-row { display: flex; align-items: center; gap: var(--spacing-xs); margin: 0; font-size: var(--fs-tiny); line-height: var(--lh-tiny); white-space: nowrap; }
p.ccl-chart__tip-row::before { content: ""; flex: none; width: 10px; height: 10px; border-radius: 2px; background: var(--series); }
p.ccl-chart__tip-row b { margin-inline-start: auto; padding-inline-start: var(--spacing-sm); font-weight: var(--fw-strong-body); }

p.ccl-chart__note {
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
  margin: var(--spacing-sm) 0 0;
}
.ccl-chart__data { margin-block-start: var(--spacing-sm); font-size: var(--fs-tiny); line-height: var(--lh-tiny); }
.ccl-chart__data > summary { cursor: pointer; color: var(--fg-link); font-weight: var(--fw-strong-body); width: fit-content; }
.ccl-chart__data > summary:hover { text-decoration: underline; }
.ccl-chart__table-wrap { overflow-x: auto; margin-block-start: var(--spacing-xs); }
.ccl-chart__data table { border-collapse: collapse; font-variant-numeric: tabular-nums; }
.ccl-chart__data th,
.ccl-chart__data td { padding: var(--spacing-2xs) var(--spacing-xs); border-bottom: 1px solid var(--grey-200); text-align: right; white-space: nowrap; }
.ccl-chart__data th[scope="row"] { text-align: left; }

/* Rings and donut (render-shares.php). Each ring is an SVG circle pair (grey
   track + coloured arc) with the number as HTML in the middle, so it stays
   real, selectable text at a fixed size however small the ring gets. */
.ccl-chart [data-series="other"] { --series: var(--grey-300); }
.ccl-chart__ring-art { position: relative; display: block; width: 100%; aspect-ratio: 1; }
.ccl-chart__ring-art svg { display: block; width: 100%; height: 100%; }
.ccl-chart__track { fill: none; stroke: var(--grey-200); stroke-width: 14; }
.ccl-chart__arc { fill: none; stroke: var(--chart-1); stroke-width: 14; } /* flat ends: round caps add ~5% of the ring to every arc */
.ccl-chart__slice { fill: none; stroke: var(--series, var(--grey-300)); stroke-width: 14; }
.ccl-chart__ring-value {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  font-weight: var(--fw-strong-heading);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.ccl-chart__ring-sub { font-family: var(--font-body); font-size: var(--fs-tiny); line-height: var(--lh-tiny); font-weight: var(--fw-weak); color: var(--grey-500); }

.ccl-chart__rings {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 180px));
  gap: var(--spacing-xl) var(--spacing-2xl);
}
.ccl-chart__ring { margin: 0; display: flex; flex-direction: column; align-items: center; gap: var(--spacing-sm); text-align: center; }
.ccl-chart__ring .ccl-chart__ring-art { max-width: 160px; }
.ccl-chart__ring-label { font-size: var(--fs-small); line-height: var(--lh-small); }

.ccl-chart__donut { display: flex; align-items: center; gap: var(--spacing-2xl); }
.ccl-chart__donut .ccl-chart__ring-art { flex: none; width: 200px; }
.ccl-chart__legend--shares { flex-direction: column; flex-wrap: nowrap; gap: var(--spacing-xs); margin: 0; }
.ccl-chart__legend--shares .ccl-chart__key b { font-weight: var(--fw-strong-body); font-variant-numeric: tabular-nums; }
.ccl-chart__swatch { flex: none; width: 12px; height: 12px; border-radius: 3px; background: var(--series); }

/* Bars (render-shares.php). One grid for the whole list, so every bar starts
   at the same x however long its label; each row joins it as a subgrid. Labels
   wrap inside their column ("Non-Denominational or Independent Church"). The
   bar's width is its share of the longest bar (--w, 0–1) times the track minus
   room for the number printed after it. Square at the baseline, 4px round at
   the data end. */
.ccl-chart__bars {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(6em, 15em) minmax(0, 1fr);
  gap: var(--spacing-xs) var(--spacing-md);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.ccl-chart__bar-row { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: center; margin: 0; }
.ccl-chart__bar-label { text-align: right; }
.ccl-chart__bar-track { display: flex; align-items: center; gap: var(--spacing-xs); min-width: 0; }
.ccl-chart__bar {
  flex: none;
  width: calc((100% - 4.5em) * var(--w));
  min-width: 2px;
  height: 16px;
  border-radius: 0 4px 4px 0;
  background: var(--chart-1);
}
.ccl-chart__bar-value { font-weight: var(--fw-strong-body); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Ring grid (render-grid.php): a real table, groups down, measures across, a
   ring in each cell. Sized to its content rather than stretched, so two
   measures don't end up a page-width apart. */
.ccl-chart__grid {
  width: auto;
  max-width: 100%;
  margin: 0;
  border-collapse: collapse;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.ccl-chart__grid th,
.ccl-chart__grid td {
  padding: var(--spacing-sm) var(--spacing-md);
  border: 0;
  border-bottom: 1px solid var(--grey-200);
  background: none;
  text-align: center;
  vertical-align: middle;
}
.ccl-chart__grid thead > tr > * { vertical-align: bottom; border-bottom-color: var(--grey-300); font-weight: var(--fw-strong-body); }
.ccl-chart__grid thead th { width: 8.5rem; }
.ccl-chart__grid tbody th { width: 14em; padding-inline-start: 0; text-align: left; font-weight: var(--fw-strong-body); }
.ccl-chart__grid tbody tr:last-child > * { border-bottom: 0; }
.ccl-chart__grid .ccl-chart__ring-art { width: 96px; margin-inline: auto; }
.ccl-chart__grid .ccl-chart__ring-value { font-size: var(--fs-small); line-height: 1; }
.ccl-chart__grid-empty { color: var(--grey-400); }
.ccl-chart__grid-wrap { overflow-x: auto; }

@media (max-width: 600px) {
  .ccl-chart { --chart-h: 240px; }
  .ccl-chart__grid { font-size: var(--fs-tiny); line-height: var(--lh-tiny); }
  .ccl-chart__grid th,
  .ccl-chart__grid td { padding: var(--spacing-xs); }
  .ccl-chart__grid thead th { width: auto; }
  .ccl-chart__grid tbody th { width: auto; padding-inline-start: 0; }
  .ccl-chart__grid .ccl-chart__ring-art { width: 72px; }
  .ccl-chart__grid .ccl-chart__ring-value { font-size: var(--fs-tiny); }
  /* Label above its bar: the label column would leave the bars too short. */
  .ccl-chart__bars { grid-template-columns: minmax(0, 1fr); row-gap: var(--spacing-sm); font-size: var(--fs-tiny); line-height: var(--lh-tiny); }
  .ccl-chart__bar-row { grid-template-columns: minmax(0, 1fr); row-gap: var(--spacing-2xs); }
  .ccl-chart__bar-label { text-align: left; }
  .ccl-chart__donut { flex-direction: column; align-items: flex-start; gap: var(--spacing-lg); }
  .ccl-chart__donut .ccl-chart__ring-art { width: 180px; }
  .ccl-chart__rings { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-lg); }
  .ccl-chart__frame { grid-template-columns: 2.5em minmax(0, 1fr); column-gap: var(--spacing-xs); padding-inline-end: 3em; }
  .ccl-chart__xaxis .is-minor { display: none; }
}
/* ==========================================================================
   Mobile heroes (≤900px, where the layouts reflow). ONE rule for the whole
   system: each hero keeps its desktop READING order when it stacks.
     • Brand heroes (T2 photo card, conference reg-hero) lead with the photo:
       it's the backdrop the card sits on, so it comes first, edge to edge.
     • Task heroes lead with the ask: T1 (text left, media right) stacks
       text-first (see the ≤900 block in the reflow section), and the donate
       hero, T2 on desktop, becomes text → form → trust → press on a phone,
       with the photo cut to a short strip.
   The overlay is dropped on phones: at 390px the card is as wide as the photo,
   so the overlap only covered the photo's bottom (usually the people) and read
   as a clipped photo, and it needed a negative margin + z-index to hold up.
   Every T2 variant is already photo → card (→ press strip) in the markup, so
   stacking is just normal flow. Tripled/compound selectors: these must beat
   the variants' desktop rules (--fluid's absolute photo, --tight's padding,
   the widget card's margins), several of which sit at (0,2,0) or (0,3,0).
   ========================================================================== */
@media (max-width: 900px) {
  /* Section: no side gutter, so the photo runs to the screen edges. The top
     padding is the breadcrumb → photo gap (the homepage sets its own inline).
     No bottom padding: the card's text ends the hero, and the section's own
     bottom margin (0 on --flush / --tight) is the seam to the next section. */
  .hero-t2.hero-t2.hero-t2 { padding: var(--spacing-lg) 0 0; }
  /* The homepage (front-page.html: no section nav or breadcrumb, post-content
     straight in <main>) runs the photo flush under the header's gradient
     line, as in the mockup: drop <main>'s root block-gap and the hero's top
     padding (the editor's inline spacing, hence !important). */
  main:has(> .wp-block-post-content > .hero-t2:first-child) { margin-block-start: 0; }
  main > .wp-block-post-content > .hero-t2:first-child { padding-top: 0 !important; }

  /* Photo: back in flow for every variant (--fluid makes it an absolute
     backdrop on desktop). Nearly square, like the mockup, capped so tablets
     don't get a 700px-tall photo. Square corners, no shadow at the edges. */
  .hero-t2 .hero-t2__photo.hero-t2__photo {
    position: relative;
    inset: auto;
    width: 100%;
    aspect-ratio: 6 / 5;
    max-height: 480px;
    border-radius: 0;
    box-shadow: none;
  }
  /* …and the image itself: theme.json gives every core Image's <img> the md
     radius, which the rounded, clipping photo frame hides on desktop. */
  .hero-t2 .hero-t2__photo img { border-radius: 0; }

  /* Card: plain page content under the photo, no card chrome. Children are
     capped so body copy keeps a readable measure on tablets. */
  .hero-t2 .hero-t2__card.hero-t2__card {
    position: static;
    inset: auto;
    transform: none;
    width: auto;
    max-width: none;
    margin: 0;
    padding: var(--spacing-xl) var(--page-gutter) 0;
    background: none;
    border-radius: 0;
    box-shadow: none;
  }
  .hero-t2 .hero-t2__card > * { max-width: 640px; }
  /* The headline keeps the display role: tokens.css already drops it a tier on
     phones (56 → 40px). Dropping it to --fs-h2 made it the same 36px as the
     section h2s right below it. */

  /* With the card chrome gone the hero's text runs straight into the next
     section, so close it with the section divider (the .divider-thick bar,
     at the gutter). Not on the donate hero, whose navy press band ends it, nor
     on a hero that ends the page (nothing to divide it from but the footer). */
  .hero-t2:not(:last-child):not(:has(> .hero-t2__card--widget))::after {
    content: '';
    display: block;
    height: 4px;
    margin: var(--spacing-2xl) var(--page-gutter) 0;
    background: var(--grey-200);
  }

  /* Donate (the widget card): the form is the point, so the photo shrinks to
     a short banner strip that keeps some warmth without pushing the form down. */
  .hero-t2:has(> .hero-t2__card--widget) > .hero-t2__photo.hero-t2__photo {
    aspect-ratio: 16 / 9;
    max-height: 220px;
  }
  /* Press strip: out of the photo (it overlays the photo's bottom on desktop)
     and into flow after the form, on the dark band its white logos need. The
     logos wrap and centre rather than scroll, so none are hidden off-screen. */
  .hero-t2 .give-press {
    position: static;
    margin-top: var(--spacing-2xl);
    padding: var(--spacing-xl) var(--page-gutter);
    background: var(--ccl-navy);
    border-radius: 0;
  }
  .give-press__row {
    flex-wrap: wrap;
    overflow-x: visible;
    gap: var(--spacing-md) var(--spacing-xl);
  }
  .give-press__row img { height: 22px; }
}

/* Lite YouTube embed container — base for the poster + play-button +
   later-injected iframe pattern. Every .lite-yt is its own positioning
   context so the absolutely-positioned .play-btn inside can't escape to
   an outer ancestor (regression we hit twice — see DEVIATIONS D6 notes).
   Context-specific overrides (founder-video, etc.) only add what they
   need (e.g. shadow) on top of this base. */
.lite-yt {
  position: relative;
  width: 100%;

  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
}
/* The WP block wrappers between .lite-yt and <iframe> need to pass size through */
.lite-yt .wp-block-image,
.lite-yt .wp-block-embed,
.lite-yt .wp-block-embed__wrapper {
  width: 100%;
  height: 100%;
  margin: 0;
}
.lite-yt figure {
  padding: 0;
  margin: 0;
}

.lite-yt img,
.lite-yt iframe {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
}
.ccl-video-embed-block.lite-yt {
    aspect-ratio: 16 / 9;
}
/* Play button — single base class + size modifiers. Apply by adding the
   class to any <button> sitting inside a positioned poster container
   (`.lite-yt`, `.hero-t1__media .photo`, `.founder-video .lite-yt`, etc.).
   Default is medium (74px). Use --lg for hero overlays, --sm for nested
   inset cards. The chrome (green circle + black arrow) is identical. */
.play-btn {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 74px;
  height: 74px;
  border-radius: 50%;
  background: var(--ccl-green);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-elevated);
  z-index: 2;
}
.play-btn::after {
  content: '';
  width: 0; height: 0;
  margin-left: 6px;
  border-style: solid;
  border-width: 14px 0 14px 22px;
  border-color: transparent transparent transparent var(--grey-1000);
}
.play-btn--lg { width: 96px; height: 96px; }
.play-btn--lg::after { margin-left: 8px; border-width: 18px 0 18px 28px; }
.play-btn--sm { width: 64px; height: 64px; }
.play-btn--sm::after { margin-left: 5px; border-width: 12px 0 12px 18px; }
.play-btn--corner {
  bottom: var(--spacing-sm);
  left: var(--spacing-sm);
  right: auto;
  top: auto;
}
/* Accent mark — sparkle squiggles in the negative space above-left of the
   offset block. Matches BrandMark kind="accent" placement in heroes.jsx. */
.hero-t1__media .accent-mark {
  position: absolute;
  top: -50px;
  left: -50px;
  width: 78px;
  height: auto;
  transform: rotate(-70deg);
  z-index: 3;
  pointer-events: none;
}
/* Stacked, the photo starts at (or 24px from) the screen edge, so the -50px
   hang put up to 27px of the mark off-screen. Pull it in to stay whole. */
@media (max-width: 900px) {
  .hero-t1__media .accent-mark { left: -16px; }
}
/* "Hand-drawn arrow" Image style — a marker arrow as a doodle under a hero's
   copy, pointing on down the page (Join an Action Team). Made for
   marks/arrow-slight-curve.svg, which is drawn in its final direction, so no
   rotation: down with a slight lean right, into the page and toward the next
   section. 60px wide = ~150px tall, the height of the prototype's
   .jat-hero-arrow (the 90-degree brand arrow at 120px); at that size the
   stroke matches the headline underline.
   Doubled core class: core's .wp-block-image rules set margin and img sizing
   at (0,1,x) and print inline, so a single class can lose (see CLAUDE.md).
   Hidden once the hero stacks (≤900px), as the prototype does. */
.wp-block-image.is-style-hand-arrow {
  width: 60px;
  margin: var(--spacing-md) 0 0 var(--spacing-6xl);
  pointer-events: none;
}
.wp-block-image.is-style-hand-arrow img {
  width: 100%;
  height: auto;
}
@media (max-width: 900px) {
  .wp-block-image.is-style-hand-arrow { display: none; }
}

/* --------------------------------------------------------------------------
   Centered section header (Our Approach, Our Team etc.)
   -------------------------------------------------------------------------- */
.section-header {
  text-align: center;
  /* WP adaptation: the prototype uses 3xl here, but WP also adds block-gap
     between this and adjacent blocks, so 3xl doubles up into too much space.
     Trimmed to md — the surrounding block spacing carries the rest. */
  padding: var(--spacing-3xl) var(--container-pad);
  margin: 0 auto;
}
/* 780px is only a fallback, so :where() keeps it at zero specificity. As a plain
   .section-header rule it tied with core's layout CSS and won by load order, so a
   parent Group's "Content width" (e.g. 900px on the Give page's funding
   breakdown) was silently ignored on the front end. Now any layout width wins,
   and 780px applies only where nothing else sets one: the flow-layout
   .section-band__inner bands, and groups with no layout parent. */
:where(.section-header) { max-width: 780px; }
/* Width is flexible: the pattern's group uses default (flow) layout, so the
   editor's Wide / Full width buttons widen it past the 780px default. Our own
   max-width would otherwise override WP's alignment widths, so restate them per
   alignment. */
.section-header.alignwide { max-width: var(--wp--style--global--wide-size, 1166px); }
.section-header.alignfull { max-width: none; }
/* Tight eyebrow→heading gap: zero the heading's top margin so the only space is
   the eyebrow's own margin-bottom (spacing-sm) — matches the prototype and the
   split-feature pattern. Without this, WP's block-gap adds a looser top margin. */
.section-header .h1-bold { margin-top: 0; margin-bottom: var(--spacing-sm); }
/* "Left aligned" group block style (scoped here) — the section intro flush-left
   instead of centered, for the Events page hero-intro. Un-centers the block and
   left-aligns the text. Pair with Wide/Full to widen a left intro. */
.section-header.is-style-left {
  text-align: left;
  margin-inline: 0;
}

/* Pillar cards (Reduce / Protect / Remove emissions) */
.pillar-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-md);
  max-width: 780px;
  margin: var(--spacing-lg) auto var(--spacing-3xl);
  padding: 0 var(--container-pad);
}
.pillar-card {
  background: var(--grey-100);
  border-radius: var(--radius-sm);
  padding: var(--spacing-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-lg);
  text-align: center;
}
.pillar-card .icon-circle {
  width: 116px;
  height: 116px;
  border-radius: 50%;
  background: var(--ccl-green);
  display: flex;
  align-items: center;
  justify-content: center;
}
.pillar-card .icon-circle img { width: 80px; height: 80px; }
.pillar-card h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  color: var(--ccl-black);
  margin: 0;
}

/* --------------------------------------------------------------------------
   "Last year we mobilized" + side gradient callout
   -------------------------------------------------------------------------- */
.mobilized {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 50px;
  padding: var(--spacing-md) var(--page-gutter);
  max-width: 1280px;
  margin: 0 auto;
}
.mobilized__list h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-sm);
}
/* Adapted from ImpactStats in the marketing kit — huge numeral with a
   CCL-green offset shadow, label stacked below. Hybrid size (56px instead
   of the kit's 88px) since these sit in a narrow column next to the
   gradient callout. */
.mobilized__stat { margin-bottom: var(--spacing-lg); }
.mobilized__stat .stat-n {
  position: relative;
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 56px;
  line-height: 0.95;
  letter-spacing: -0.02em;
  margin-bottom: var(--spacing-xs);
}
.mobilized__stat .stat-n-shadow {
  position: absolute;
  left: 3px;
  top: 3px;
  color: var(--brand);
  user-select: none;
}
.mobilized__stat .stat-n-fg {
  position: relative;
  color: var(--ccl-black);
}
.mobilized__stat .stat-l {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.35;
  color: var(--ccl-black);
}

.mobilized__callout {
  /* DEVIATION #3: design uses linear-gradient(to bottom,...), system says 135deg only. */
  background: var(--gradient-blue-green);
  border-radius: var(--radius-sm);
  padding: var(--spacing-md) var(--spacing-xl);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--spacing-md);
  color: #fff;
}
.mobilized__callout h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  margin: 0;
  color: #fff;
}
.mobilized__callout p {
  color: #fff;
  margin: 0;
  line-height: 1.4;
}
.mobilized__callout .btn-ghost-on-dark { align-self: flex-start; }
/* Note: .ghost-btn local rule removed in favor of canonical .btn-ghost-on-dark
   from tokens.css. Apply the canonical class on the <a> instead. */

/* --------------------------------------------------------------------------
   Team cards row (Staff / Boards / Volunteers on page 1)
   -------------------------------------------------------------------------- */
.team-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
  padding: var(--spacing-md) var(--page-gutter) var(--spacing-3xl);
  max-width: 1280px;
  margin: 0 auto;
}
.team-card {
  background: #fff;
  border: 1px solid rgba(0,0,0,0.1);
  border-radius: var(--radius-md);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  box-shadow: 0 2px 4px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04);
  display: flex;
  flex-direction: column;
}

/* A card that IS a link: arrow-link cards from blocks/card, and every story
   card. Ports the prototype's idiom -- `.story-card:hover h2, .post-row:hover h2
   { color: var(--fg-link-strong) }` -- which never came across when the Stories
   block was re-based from .story-card onto .team-card. That move gave the cards
   a full-card click target and simultaneously removed the only signal that they
   were clickable, which is why they've had no hover at all.

   The arrow lightens with the title: it's the part that reads as "link".

   Button cards get nothing here, deliberately. The button carries its own hover,
   and lighting up a container that isn't clickable would be a lie.

   :focus-visible matters more than usual now -- the card is the tab stop, so the
   ring belongs on the whole card, not just its heading. */
a.team-card {
  transition: box-shadow .15s ease, border-color .15s ease;
}
a.team-card:hover {
  border-color: rgba(0, 0, 0, 0.18);
  box-shadow: 0 4px 8px rgba(0, 0, 0, .10), 0 8px 20px rgba(0, 0, 0, .06);
}
a.team-card:hover h3,
a.team-card:focus-visible h3,
a.team-card:hover .team-card__link,
a.team-card:focus-visible .team-card__link {
  color: var(--fg-link-strong);
}
@media (prefers-reduced-motion: reduce) {
  a.team-card { transition: none; }
}
.team-card__image {
  height: 204px;
  background: var(--grey-200);
  overflow: hidden;
  border-bottom: 1px solid rgba(0,0,0,0.06);
}
.team-card__image img { width: 100%; height: 100%; object-fit: cover; }
/* Blog-post cards (ccl_render_story_card) take the blog's 16:9 rather than
   the team card's fixed 204px — at 3-up that was already ≈16:9, but only at
   that width. Team headshot cards keep the fixed height. */
.team-card--story .team-card__image { height: auto; aspect-ratio: 16 / 9; }
.team-card__body { padding: var(--spacing-xl); display: flex; flex-direction: column; gap: var(--spacing-lg); }

/* --------------------------------------------------------------------------
   A different approach — a white copy card overlapping the photo to its right,
   with a blue-to-green spine down the card's rounded left edge. Ported from the
   prototype's .hm-approach.

   Both children occupy grid row 1: the card in column 1 with a negative right
   margin so it laps over the photo in column 2. `overflow: hidden` on the card
   is what rounds the spine's ends to the card radius.

   Upstream pads this with --gutter and warns explicitly against --page-gutter,
   because there --page-gutter is edge-inset + gutter and would inset twice.
   This theme has no --edge-inset, so its --page-gutter IS upstream's --gutter
   and is the correct token here. Don't "fix" it back.
   -------------------------------------------------------------------------- */
.hm-approach {
  display: grid;
  grid-template-columns: 693fr 721fr;
  max-width: var(--frame-max);
  margin: 0 auto var(--spacing-5xl);
  padding: 0 var(--page-gutter);
}
/* Placed Full width, the section gets core's `.has-global-padding > .alignfull`
   negative margins, which replace the `auto` above: past 1440px it hugged the
   left edge. Keep the bleed to the edge below the cap, centre it above. */
.has-global-padding > .hm-approach.alignfull {
  margin-left: max(calc(var(--wp--style--root--padding-left) * -1), calc((100% - var(--frame-max)) / 2));
  margin-right: max(calc(var(--wp--style--root--padding-right) * -1), calc((100% - var(--frame-max)) / 2));
}
.hm-approach__card {
  grid-area: 1 / 1;
  position: relative;
  z-index: 1;
  margin-right: calc(-1 * var(--spacing-3xl));
  background: #fff;
  border-radius: var(--radius-md);
  box-shadow: 0 2px 10px rgba(0,0,0,0.16);
  overflow: hidden;
  /* Roomier left inset than right: the spine eats 14px of it, and the extra
     holds the headline to the design's two-line break. */
  padding: var(--spacing-2xl) var(--spacing-3xl) var(--spacing-3xl) var(--spacing-4xl);
}
.hm-approach__card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 14px;
  background: linear-gradient(180deg, var(--ccl-blue) 0%, var(--ccl-green) 100%);
}
/* Above the reflow breakpoint the card holds "bridge-builders" whole, so stop
   the browser breaking it at its hyphen — the underline is a per-line
   background, so a hyphen break splits it into two stubs. Desktop only: below
   900px the card's measure is narrower than the word. */
@media (min-width: 901px) {
  .hm-approach__card h2 .hdr-underline { white-space: nowrap; }
}
.hm-approach__card h2 {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h2);
  line-height: 54px;
  letter-spacing: -0.5px;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-lg);
}
.hm-approach__card p:last-child { margin-bottom: 0; }
/* The photo takes its height from the card rather than a fixed ratio, so the
   two stay in proportion however long the copy runs; the offsets reproduce the
   design's stagger — it starts below the card's top edge and hangs below its
   bottom one, and the section's bottom margin absorbs the hang. */
/* Scoped with the parent on purpose — this is a WP adaptation, not style. The
   photo is a core/image block, and core ships
   `.wp-block-image img { height: auto }` and `.wp-block-image { … }` at the same
   specificity as a bare `.hm-approach__photo`. A tie is decided by load order,
   and core's block styles win it, so the unscoped port lost `height: 100%`: the
   photo fell back to its natural height, the row stopped driving it, and the
   stagger collapsed to roughly level with the card. Doubling `.wp-block-image`
   onto our own class takes these to (0,2,x) and settles it regardless of load
   order — the same idiom already used on .hero-t2__photo. */
.hm-approach__photo.wp-block-image {
  grid-area: 1 / 2;
  margin: var(--spacing-2xl) 0 calc(-1 * var(--spacing-2xl));
  align-self: stretch; /* explicit: the offset only reads if the row drives height */
  min-height: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.hm-approach__photo.wp-block-image img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (max-width: 900px) {
  /* Card and photo un-overlap and stack; the spine stays on the card. */
  .hm-approach { grid-template-columns: 1fr; gap: var(--spacing-lg); }
  /* The desktop card's asymmetric inset is most of a phone card's width — it
     left about six characters a line. Even padding, and the copy can read. */
  .hm-approach__card { grid-area: auto; margin-right: 0; padding: var(--spacing-xl); }
  /* Stacked there's no card height to borrow, so the photo carries the crop. */
  /* Raised to match the scoped desktop rules above — unscoped it would now lose. */
  .hm-approach__photo.wp-block-image { grid-area: auto; margin: 0; aspect-ratio: 721 / 564; }
}

/* The "Get to know CCL" grid — 2×2 of horizontal Action Cards. Only the
   arrangement lives here; the cards are the block. Upstream (.hm-know) caps at
   1166px, which is the theme's alignwide measure, so the group handles it. */
.know-ccl {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-xl);
}
@media (max-width: 900px) {
  .know-ccl { grid-template-columns: 1fr; gap: var(--spacing-lg); }
}

/* Horizontal Action Card — copy left, media right. Ported from the prototype's
   .hm-know__card (the "Get to know CCL" panels), generalised onto .team-card so
   one component covers both arrangements instead of two competing ones.

   The base card is a flex column with a full-bleed image on top; the modifier
   re-declares it as a two-track grid, so the image becomes a fixed 130px column
   beside the copy rather than a band above it. */
.team-card--horizontal {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 130px;
  gap: var(--spacing-lg);
  align-items: center;
  padding: var(--spacing-xl);
  overflow: visible; /* the base clips its top image; nothing to clip here */
}
.team-card--horizontal .team-card__image {
  height: auto;
  border-bottom: 0;
  background: none; /* no grey placeholder band behind a transparent glyph */
  order: 2;
}
.team-card--horizontal .team-card__body {
  padding: 0; /* the card owns the padding now */
  gap: var(--spacing-sm);
  order: 1;
}

/* Photo fills and crops; an icon must sit whole inside its slot or the green
   circle goes oval. Both dimensions are pinned for the same reason. */
.team-card--horizontal .team-card__image img {
  width: 130px;
  height: 130px;
  object-fit: cover;
  border-radius: var(--radius-xs);
}
.team-card--icon .team-card__image img {
  object-fit: contain;
  border-radius: 0;
}

/* Below the layout breakpoint the 130px column plus copy is too tight, so the
   media drops under the copy rather than squeezing it to a few words a line. */
@media (max-width: 600px) {
  .team-card--horizontal { grid-template-columns: 1fr; }
  .team-card--horizontal .team-card__image { order: 2; }
  .team-card--horizontal .team-card__image img { margin-inline: auto; }
}
.team-card__body h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
}
/* Layout only -- body type comes from the canonical `p` rule in tokens.css.
   These used to set 16px and rgba(0,0,0,0.6), which is why card copy read as a
   lighter, smaller island next to every other section. Dropping the type also
   removes the (0,1,1) hijack that was beating .team-card__link at (0,1,0): the
   canonical rule is unscoped `p` at (0,0,1), so the CTA class now wins outright. */
.team-card__body p {
  margin: 0;
}
.team-card__link {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 19px;
  color: var(--ccl-navy);
  text-decoration: none;
}
.team-card__link::after { content: '→'; }
/* On the wrapping <p> (see below) inline-flex makes the <a> one flex item, so
   when its label wraps it fills the line and strands the arrow at the far
   right. A plain block lets the arrow follow the last word. */
p.team-card__link { display: block; }
p.team-card__link::after { margin-left: var(--spacing-xs); }
/* This class is applied to the WRAPPING <p>, with a bare <a> inside it
   (blocks/card/render.php, patterns/team-card.php) -- unlike the vertical story
   card, which uses a <span> and no <a> at all. That means the prose-link rule in
   tokens.css (`p > a:not([class])`) matches the inner <a> and underlines it,
   which is why the horizontal cards' CTA grew an underline the vertical ones
   never had. Upstream's "classed links are untouched" assumes the class sits on
   the <a>; ours sits on its parent.
   The wrapper owns the appearance, so the <a> inherits it. (0,2,1) beats the
   prose rule's (0,1,2). */
:where(.ccl) .team-card__link > a:not([class]) {
  color: inherit;
  font-family: inherit;
  font-weight: inherit;
  font-size: inherit;
  text-decoration: none;
}

/* Photo tiles (patterns/photo-tiles.php) — the prototype's .give-story tile +
   .give-gift__grid (give.html; impact.html reuses the shape), ported under a
   page-neutral name. Borderless: a rounded 16:10 photo, heading, paragraph. For
   explanatory trios with no per-item link — items with their own link are
   Action Cards. Built on core Columns: .photo-tiles is the Columns block (the
   grid), each Column is a .photo-tile. */
.photo-tiles.wp-block-columns {
  max-width: 1100px;
  margin-inline: auto;
  gap: var(--spacing-2xl);
}
.photo-tile.wp-block-column {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}
/* WP adaptation: the column's flow layout puts a blockGap margin on each child
   after the first; the tile's own gap owns that spacing. */
.photo-tile > * { margin-block-start: 0; margin-block-end: 0; }
.photo-tile__photo.wp-block-image { margin: 0; }
/* __icon — an icon in place of the photo, for a trio that has icons rather
   than pictures (Take Action "Issue pillars"). Same tile, same type. */
.photo-tile__icon.wp-block-image { margin: 0; }
.photo-tile__icon.wp-block-image img { width: 72px; height: 72px; }
.photo-tile__photo img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--radius-md);
  display: block;
}
/* A tile's title is an item title (the h3 tag's own weight and colour, at
   --fs-item-title) by default, so existing tiles — and ones an editor builds
   by hand — get it without choosing the "Item title" style, which the pattern
   also sets. The tile's flex gap does the spacing. */
.photo-tile h3 {
  font-size: var(--fs-item-title);
  line-height: calc(var(--lh-item-title) / var(--fs-item-title));
  margin: 0;
}
.photo-tile p {
  font-size: var(--fs-small);
  line-height: 1.55;
  margin: 0;
}
/* Prototype: single column under 900px, capped so tiles don't go letterbox. */
@media (max-width: 900px) {
  .photo-tiles.wp-block-columns { max-width: 560px; }
}
/* Card block "Button" CTA style — the prototype's action-card treatment (an
   outlined .btn-tertiary) on the same card. The body's flex gap spaces it. */
.team-card__cta { margin: 0; }
/* In a row (grid cell or core Column) let the body fill the stretched card and
   the text grow, so the CTA pins to the bottom across the row — the prototype's
   action-card behaviour (.action-card__body p { flex: 1 }). Inert on a lone
   card, whose height is just its content. Columns don't stretch their child
   the way grid cells do, so the Card block in Columns also takes height:100%. */
.team-card__body { flex: 1; }
.team-card__body > p:not(.team-card__link):not(.team-card__cta) { flex: 1; }
.wp-block-column > .team-card { height: 100%; }

/* ==========================================================================
   QUOTES — one system, three components (Quote Rules, 10–16 Sept 2026)

   Every quote on the site is the ccl/quote block, and every treatment renders
   the SAME shape — that's what lets `--subdued` be an honest modifier:

     <figure class="quote">
       <img class="quote__glyph">   or   <p class="quote__label">   (or neither)
       <blockquote class="quote__body"><p>“…”</p></blockquote>
       <figcaption class="quote__attrib">
         [<img|span class="quote__avatar">]                 44px, named speakers only
         <span class="quote__stack">
           <span class="quote__name">— Name</span>          Source Sans 700, leads with the dash
           <span class="quote__context">Role · place</span> Source Sans 400 italic grey-500
         </span>
       </figcaption>
     </figure>

   .quote             ONE quote, bold — gradient frame + glyph. On an open page,
                      usually the last thing before a call to action.
   .quote--subdued    the card — grey fill. Inside anything that already draws
                      its own lines (accordion panel, timeline era, another card):
                      lines collide with lines, a surface doesn't.
   .quotes            SEVERAL quotes, bold — a green rule over each column. Short
                      first-person lines, under ~90 characters.
   .quotes--subdued   the same card, in a grid. Paragraph-length quotes.
   .pull-quote        IN AN ARTICLE — green left rule, one setting. Kept because
                      the card doesn't *pull*: boxed, it reads as a callout beside
                      19px body copy rather than a lift out of it.

   Three chromes, each meaning one thing — gradient = the featured quote; solid
   green rule = a quiet line-based quote; grey fill = a subdued surface. No
   treatment uses two. The quote is always in the display face (Ubuntu), the
   attribution always in the body face (Source Sans) — the face change is what
   separates them, so the attribution never competes on size.

   Quotation marks are typed into the copy (render.php texturizes straight
   quotes to curly) — never generated here. The dash is written by render.php.
   Modifiers: --subdued · --source (label replaces glyph, linked document on
   the context line) · --large (body at H2, rare) · --fill (drop the 750px
   measure to fill a grid cell) · .quote__avatar.
   ========================================================================== */

/* ---- Shared structure + type (every treatment) --------------------------- */
.quote,
.pull-quote { margin: 0; }                    /* editor canvas has no .ccl figure reset */
.quote__body { margin: 0; }
.quote__body > p {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  margin: 0;
  letter-spacing: 0;
}
/* Gradient emphasis — one phrase, kept rare (~1 in 20), bold single ONLY.
   The editor applies it with the existing "Gradient text" toolbar format;
   .emph is the prototype's name for the same thing. Every other treatment
   neutralises it so the gradient stays the featured quote's signature. */
.quote__body .gradient-text,
.quote__body .emph {
  background: var(--gradient-blue-green);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: var(--fw-strong-heading);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.quote--subdued .quote__body .gradient-text,
.quote--subdued .quote__body .emph,
.quotes .quote__body .gradient-text,
.quotes .quote__body .emph,
.pull-quote .quote__body .gradient-text,
.pull-quote .quote__body .emph {
  background: none;
  color: inherit;
  font-weight: inherit;
}

/* Attribution — ONE spec, every treatment. Avatar (optional) to the left of a
   two-line stack. The dash rides on whichever line comes first: the name when
   there is one, otherwise the context line ("— Conference participant, June
   2026"). No trailing comma. */
.quote__attrib {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--spacing-sm);
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-style: normal;
  line-height: 1.4;
  margin: 0;
}
.quote__stack {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.quote__name {
  font-weight: 700;
  font-style: normal;
  color: var(--ccl-black);
}
.quote__context {
  font-weight: 400;
  font-style: italic;
  color: var(--grey-500);
}
.quote__context a {
  color: var(--ccl-blue-dark);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}
.quote__context a:hover { border-bottom-color: transparent; }
/* The byline's 44px pill; initials fallback on the documented avatar ramp. */
.quote__avatar {
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: var(--radius-pill);
  object-fit: cover;
  object-position: 50% 30%;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-tiny);
  line-height: 1;
  letter-spacing: 0.02em;
  color: #fff;
  background: var(--avatar-initials-1);
}
.quote__avatar[data-color="2"] { background: var(--avatar-initials-2); }
.quote__avatar[data-color="3"] { background: var(--avatar-initials-3); }
.quote__avatar[data-color="4"] { background: var(--avatar-initials-4); }
.quote__avatar[data-color="5"] { background: var(--avatar-initials-5); }
.quote__avatar[data-color="6"] { background: var(--avatar-initials-6); }

/* --source label — replaces the glyph when the quote is cited research, or
   whenever the container already carries an icon. */
.quote__label {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ccl-blue);
  margin: 0;
}

/* ---- ONE quote, bold — .quote ------------------------------------------- */
/* The three-sided green→blue frame. The glyph row above and the attribution
   below are pulled INTO the frame by half their height (negative margins) so
   the top and bottom rules run through their middles. Nothing paints a
   background: the rules are drawn only where they show —
     top     a green segment on the blockquote's own background, starting a
             --quote-gap after the glyph
     right   the blockquote's border (the gradient)
     bottom  a blue segment the attribution row draws after its text (::after,
             flex:1), so it starts a --quote-gap after the attribution however
             wide that is
   — so the quote sits on any surface (grey panel, tint, gradient, photo)
   with no per-parent setup. The left side is open, so glyph and attribution
   both start on the quote's left edge. */
.quote {
  --quote-glyph-row: 78px;   /* glyph row height; the top rule runs through its middle */
  --quote-glyph-w:   86px;
  --quote-attrib-h:  44px;   /* one line, two lines or two lines + avatar all centre on the bottom rule */
  --quote-gap:       2em;    /* space between the glyph / attribution and its rule */
  --quote-rule:      4px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 750px;
  margin: var(--spacing-3xl) auto;
  box-sizing: border-box;
}
.quote__glyph {
  display: block;
  width: var(--quote-glyph-w);
  height: var(--quote-glyph-row);
  object-fit: contain;
  object-position: left center;
  position: relative;        /* above the blockquote it overlaps */
}
.quote .quote__body {
  align-self: stretch;
  margin-top: calc(var(--quote-glyph-row) / -2);
  margin-bottom: calc(var(--quote-attrib-h) / -2);
  padding: 55px 1em 40px 0;
  border-width: var(--quote-rule);
  border-style: none solid none none;
  border-image: linear-gradient(180deg, var(--ccl-green) 7.45%, var(--ccl-blue) 92.22%) 1;
  /* Top rule: right-aligned in the padding box, so it butts into the right
     border (green at its top) and stops a --quote-gap short of the glyph. */
  background: linear-gradient(var(--ccl-green), var(--ccl-green)) right top / calc(100% - var(--quote-glyph-w) - var(--quote-gap)) var(--quote-rule) no-repeat;
}
/* No attribution — the bottom rule runs the full width on the blockquote. */
.quote .quote__body:last-child {
  margin-bottom: 0;
  border-bottom-style: solid;
}
.quote .quote__body > p {
  font-size: var(--fs-h4);
  line-height: calc(var(--lh-h4) / var(--fs-h4));
}
.quote .quote__attrib {
  align-self: stretch;
  min-height: var(--quote-attrib-h);
  position: relative;        /* above the blockquote it overlaps */
}
/* Bottom rule: fills the rest of the row and ends flush with the right border.
   Pinned to the top of the row (not centred) so it lands exactly on the
   blockquote's bottom edge even when the attribution wraps taller than 44px. */
.quote .quote__attrib::after {
  content: "";
  flex: 1 1 0;
  min-width: var(--spacing-lg);   /* a long attribution wraps before the rule vanishes */
  align-self: flex-start;
  height: var(--quote-rule);
  margin-top: calc(var(--quote-attrib-h) / 2 - var(--quote-rule));
  margin-left: calc(var(--quote-gap) - var(--spacing-sm));   /* the row's gap supplies the rest */
  background: var(--ccl-blue);
}
/* --large — body at H2 for a hero-scale moment. Rare. */
.quote--large .quote__body > p {
  font-size: var(--fs-h3);
  line-height: calc(var(--lh-h3) / var(--fs-h3));
}
/* --fill — drop the 750px measure and auto margins to fill a grid cell.
   Applied automatically inside a Columns cell. */
.quote--fill,
.wp-block-column > .quote {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}

/* ---- ONE quote, subdued — .quote--subdued (the card) -------------------- */
/* Also every cell of .quotes--subdued. Keeps the 750px measure, so it fills
   the accordion panel / timeline era it sits in and stays a readable object
   if someone drops it on an open page. The fill is --quote-card-bg: grey-100
   on white, white on anything else — any block with a background colour or
   gradient (WP's .has-background) flips it automatically, a white one flips it
   back, and a component with its own fill (.team-panel) sets the token itself.
   So the card stays a surface instead of dissolving into a grey section. It
   always sets its own text colour: it is always a light surface, even inside
   a dark section whose white text would otherwise vanish on it. */
:where(.has-background) { --quote-card-bg: #fff; }
:where(.has-white-background-color) { --quote-card-bg: var(--grey-100); }
.quote--subdued {
  background: var(--quote-card-bg);
  color: var(--wp--preset--color--grey-600);
  border-radius: var(--radius-md);
  padding: var(--spacing-xl);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--spacing-lg);
  margin: var(--spacing-lg) auto;
}
.quote--subdued .quote__glyph {
  width: 48px;
  height: auto;
}
.quote--subdued .quote__body {
  flex: 1;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
}
.quote--subdued .quote__body > p {
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
}
.quote--subdued .quote__attrib { min-height: 0; }
.quote--subdued .quote__attrib::after { content: none; }

/* ---- SEVERAL quotes — .quotes / .quotes--subdued ------------------------ */
/* ccl/quotes block. Columns run top-aligned and ragged-bottom, as designed:
   the attribution follows its quote rather than sitting on a shared baseline.
   render.php sets --quotes-cols to the number of quotes. */
.quotes {
  display: grid;
  grid-template-columns: repeat(var(--quotes-cols, 3), minmax(0, 1fr));
  gap: var(--spacing-xl);
  align-items: start;
  margin: var(--spacing-3xl) 0;
}
/* Cells fill their column; the grid owns the spacing. Card rows stretch to
   equal height so the attribution sits on one line across the row (the
   blockquote's flex:1 pushes it down); the bold row stays ragged-bottom. */
.quotes > .quote { max-width: none; margin: 0; }
.quotes--subdued { align-items: stretch; }
/* Bold row — the green rule with H3/600 makes a 50-character line carry a
   column. No glyph (render.php omits it). */
.quotes:not(.quotes--subdued) > .quote {
  border-top: 4px solid var(--ccl-green);
  padding-top: var(--spacing-lg);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--spacing-md);
}
.quotes:not(.quotes--subdued) > .quote .quote__body {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
}
.quotes:not(.quotes--subdued) > .quote .quote__body > p {
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: calc(var(--lh-h4) / var(--fs-h4));
}
.quotes:not(.quotes--subdued) > .quote .quote__attrib { min-height: 0; }
.quotes:not(.quotes--subdued) > .quote .quote__attrib::after { content: none; }

/* ---- IN AN ARTICLE — .pull-quote ---------------------------------------- */
/* Green, not blue: the rule was a one-off blue that sat beside the article's
   blue links and read as the same thing. 4px to match the row. The
   .article__body selectors out-specify the reading column's element rules
   (figure margin, figcaption italics, 19px paragraphs). */
.pull-quote,
.article__body .pull-quote {
  border-left: 4px solid var(--ccl-green);
  padding-left: var(--spacing-lg);
  margin: var(--spacing-xl) 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--spacing-sm);
}
.pull-quote .quote__body > p,
.article__body .pull-quote .quote__body > p {
  font-size: var(--fs-h4);
  line-height: calc(var(--lh-h4) / var(--fs-h4));
  margin: 0;
}
.article__body .pull-quote .quote__attrib {
  font-size: var(--text-md);
  font-style: normal;
  margin: 0;
}

/* ---- Responsive ---- */
/* The 86px glyph eats half a narrow row and the 2em gaps starve the line
   length; shrink the glyph keeping the half-over-the-rule math (the row
   height drives the negative margin via --quote-glyph-row). */
@media (max-width: 900px) {
  .quote {
    --quote-glyph-row: 56px;
    --quote-glyph-w:   56px;
    --quote-gap:       1em;
  }
  .quote .quote__body { padding: 36px 0.75em 32px 0; }
  .quotes { grid-template-columns: 1fr; }
}

/* ---- Legacy alias: raw-HTML copies of the Policy Commitments pattern ----
   Inserted copies of patterns/commitments_list.php still carry the old
   .value-quote-card markup (text directly in <blockquote>, column figcaption).
   Map them onto the card so there is one look. Remove once that content has
   been re-inserted. */
.value-quote-card {
  background: var(--quote-card-bg);
  border-radius: var(--radius-md);
  padding: var(--spacing-xl);
  margin: var(--spacing-lg) auto;
  max-width: 750px;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
}
.value-quote-card__label {
  font-family: var(--font-body); font-weight: 700; font-size: var(--fs-tiny); line-height: var(--lh-tiny);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--ccl-blue); margin: 0;
}
.value-quote-card > blockquote {
  font-family: var(--font-display); font-weight: var(--fw-weak); font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5)); color: var(--ccl-black); margin: 0; flex: 1;
}
.value-quote-card figcaption { display: flex; flex-direction: column; gap: 2px; font-family: var(--font-body); font-size: var(--text-md); line-height: 1.4; }
.value-quote-card__name { font-weight: 700; color: var(--ccl-black); }
.value-quote-card__since { font-style: italic; color: var(--grey-500); }
.value-quote-card__since a { color: var(--ccl-blue-dark); text-decoration: none; border-bottom: 1px solid currentColor; }

/* ---- LEGACY: `.conf-quote-block` — the retired "Pull quote (framed)" pattern
   Built from core Group/Heading blocks with wrapper divs, so inserted copies
   live on in page content and still need these rules. New quotes are the
   ccl/quote block above (same look, figure/blockquote/figcaption markup).
   Do not extend; re-insert the content as a Quote block and delete this. */
.conf-quote-block {
  display: grid;
  max-width: 750px;
  margin: var(--spacing-3xl) auto;
  box-sizing: border-box;
}
.conf-quote-block .quote-top,
.conf-quote-block .quote-bottom {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 2em;
}
.conf-quote-block .quote-top { min-height: 78px; }
.conf-quote-block .quote-icon {
  background-color: var(--quote-surface-bg);
  z-index: 500;
  padding-right: 2em;
  position: relative;
}
.conf-quote-block .quote-icon img { display: block; width: 86px; height: auto; }
.conf-quote-block .quote-border-top { height: 5px; width: 100%; }
.conf-quote-block .quote-middle { display: grid; grid-template-columns: 1fr auto; }
.conf-quote-block .quote-body {
  margin-top: -39px;
  padding-top: 55px;
  margin-bottom: -21px;
  padding-bottom: 39px;
  padding-right: 1em;
  border-image: linear-gradient(180deg, var(--ccl-green) 7.45%, var(--ccl-blue) 92.22%) 1;
  border-width: 4px;
  border-right-style: solid;
  border-top-style: solid;
  border-bottom-style: solid;
}
.conf-quote-block .quote-body p { margin: 0; }
.conf-quote-block .quote-body .emph {
  background: var(--gradient-blue-green);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: var(--fw-strong-heading);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.conf-quote-block .quote-author {
  padding-right: 2em;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background-color: var(--quote-surface-bg);
  position: relative;
  z-index: 500;
}
/* Attribution brought onto the one spec (Source Sans, upright 700 name). */
.conf-quote-block .quote-author-name {
  font-family: var(--font-body);
  font-weight: 700;
  font-style: normal;
  color: var(--ccl-black);
  font-size: var(--text-md);
  line-height: 1.4;
}
.conf-quote-block .quote-author-title {
  font-family: var(--font-body);
  font-style: italic;
  color: var(--grey-500);
  font-size: var(--text-md);
  line-height: 1.4;
  margin-top: 2px;
}
@media (max-width: 900px) {
  .conf-quote-block .quote-top,
  .conf-quote-block .quote-bottom { gap: 1em; }
  .conf-quote-block .quote-top { min-height: 56px; }
  .conf-quote-block .quote-icon { padding-right: 1em; }
  .conf-quote-block .quote-icon img { width: 56px; }
  .conf-quote-block .quote-body {
    margin-top: -28px;
    padding-top: 36px;
    padding-right: 0.75em;
  }
  .conf-quote-block .quote-author { padding-right: 1em; }
}

.divider-thick {
  width: 100%;
  max-width: 780px;
  height: 4px;
  background: var(--grey-200);
  margin: 0 auto;
}
/* Homepage modifiers (prototype § Homepage). The design's section rules run
   nearly frame-wide, not at the 780px the canonical divider uses — width-only
   modifier, colour and weight unchanged. --spaced gives the rule its own
   vertical beat between two sections that don't bring their own. */
.divider-thick--wide { max-width: 1087px; }
.divider-thick--spaced { margin-block: var(--spacing-4xl); }

/* --------------------------------------------------------------------------
   Site footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--grey-600);
  color: var(--grey-200);
}
.site-footer__cols {
  display: grid;
  /* Four column origins from the design (brand widest for the badge row). */
  grid-template-columns: 2.2fr 1.05fr 1fr 1.9fr;
  gap: var(--spacing-4xl);
  padding: var(--spacing-3xl) var(--page-gutter) var(--spacing-4xl);
}

/* Brand column — the logo asset is already white, so no invert filter. */
.site-footer__logo { width: 362px; max-width: 100%; height: auto; }
.site-footer__badges {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--spacing-lg);
  list-style: none;
  margin: var(--spacing-xl) 0 0;
  padding: 0;
}
.site-footer__badges img { max-width: 100%; height: auto; }

/* Link columns */
.site-footer__col h4 {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading, 700);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  margin: 0 0 var(--spacing-xs);
}
.site-footer__col ul { list-style: none; padding: 0; margin: 0; }
.site-footer__col ul:not(.site-footer__social) li + li { margin-top: var(--spacing-2xs); }
.site-footer__col a,
.site-footer__col .site-footer__item {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-2xs);
  color: var(--grey-200);
  font-size: var(--fs-small);
  line-height: calc(var(--lh-small) / var(--fs-small));
  text-decoration: none;
}
.site-footer__col a:hover,
.site-footer__col a:focus-visible { color: #fff; text-decoration: underline; }
.site-footer__col svg { width: 18px; height: 18px; flex: none; fill: currentColor; }

/* Social row — scoped through __col to outrank the `ul { margin: 0 }` reset. */
.site-footer__col .site-footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  list-style: none;
  margin: var(--spacing-lg) 0 0;
  padding: 0;
}
.site-footer__social li { display: flex; }
.site-footer__social img { width: 35px; height: 35px; }
.site-footer__social a { display: block; border-radius: var(--radius-pill); }
.site-footer__social a:hover img { opacity: 0.85; }

/* Legal bar */
.site-footer__legal {
  background: #1A1A1A;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--spacing-lg) var(--spacing-4xl);
  padding: var(--spacing-md) var(--page-gutter);
  min-height: 96px;
}
.site-footer__legal p {
  margin: 0;
  max-width: 640px;
  font-size: var(--fs-tiny);
  line-height: calc(var(--lh-tiny) / var(--fs-tiny));
  color: var(--grey-300);
}
.site-footer__legal p strong { color: #fff; font-weight: 700; }
.site-footer__policy {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-md) var(--spacing-xl);
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-footer__policy a,
.site-footer__policy .site-footer__item {
  color: #fff;
  font-size: var(--fs-tiny);
  line-height: calc(var(--lh-tiny) / var(--fs-tiny));
  text-decoration: none;
  white-space: nowrap;
}
.site-footer__policy a:hover,
.site-footer__policy a:focus-visible { text-decoration: underline; }

/* ==========================================================================
   TAKE ACTION SECTION — 838:1918, 841:5902, 1039:4500
   T2 photo-overlay hero, action cards (time-eyebrow + title + body + arrow
   link), light-blue info card, three-parts grid, green/blue callout panels,
   progress meter, current-action banner.
   ========================================================================== */

/* T2 hero — full-bleed photo behind a white overlay card on the left.
   White card has eyebrow + display headline (with optional gradient phrase
   + gradient underline) + sub + primary CTA. Anchored top + left. */
/* Even top/bottom padding: the card centres on the SECTION (top: 50% of its
   padding box), so uneven padding moves it off the photo's centre. The old 80px
   bottom (48px top) put it 16px low. It also gives the same room above and
   below at narrow desktop widths, where a centred card that's taller than the
   photo overhangs both edges equally. (The prototype's lobby-day.html set this
   same 3xl bottom as a page-level override.) --fluid / --tight / --flush and the
   ≤900px reflow set their own. */
.hero-t2 {
  position: relative;
  max-width: 1440px;
  margin: 0 auto var(--spacing-3xl);
  padding: var(--spacing-3xl) var(--page-gutter);
}
.hero-t2__photo {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 7.7;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
/* Scoped through the .hero-t2 parent on purpose: the photo arrives two ways — a
   core/image block from the hero-t2 / donate-hero patterns (figure.wp-block-image)
   and a plain <div> + wp_get_attachment_image() from the conferences block's
   Registration hero. A bare `.hero-t2__photo img` would cover both but ties with
   core's `.wp-block-image img { height: auto }` at (0,1,1), leaving source order
   to decide; the parent takes this to (0,2,1) so it wins outright either way.
   Without it the block's photo keeps its width/height attributes and stretches. */
.hero-t2 .hero-t2__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Where the crop keeps. The photo box is wider than most photos, so `cover`
     trims top and bottom. Centred, it trims them equally and takes heads off
     the people in the upper part of the frame, so by default it keeps the top
     30% and trims more from the bottom (the theme's people-photo rule, as on
     .person__photo). The conferences block's Registration hero sets the two
     custom properties inline from the conference's "keep in view" fields. */
  object-position: var(--hero-focus-x, 50%) var(--hero-focus-y, 30%);
}
.hero-t2__card {
  position: absolute;
  top: 50%;
  left: var(--spacing-5xl);
  transform: translateY(-50%);
  /* Zero the block-gap margin core's flow layout puts on every non-first child
     (`:root :where(.is-layout-flow) > *`, 24px): on an absolutely placed box a
     top margin ADDS to `top`, so the pattern's card sat 24px below centre. Same
     specificity, wins by source order (global styles print first); the --fluid
     and ≤900px rules set their own margins at higher specificity. */
  margin: 0;
  background: #fff;
  border-radius: var(--radius-md);
  box-shadow: 0 1px 10px rgba(0,0,0,0.25);
  padding: var(--spacing-2xl);
  max-width: 510px;
}
.hero-t2__card .eyebrow-blue,
.hero-t2__card .is-style-eyebrow-blue { /* the paragraph block style, in the hero-t2 pattern */
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ccl-blue);
  margin: 0 0 var(--spacing-sm);
}
.hero-t2__card h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h1-display);
  line-height: var(--lh-h1-display);
  letter-spacing: -1px;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
/* Direct child only (`> p`) — the card's generic body-paragraph rule must NOT
   bleed into the nested event-meta <p>s (label/value), whose own tight spacing
   + type it would otherwise clobber (0,1,1 beats .event-meta__label's 0,1,0). */
.hero-t2__card > p {
  margin: 0 0 var(--spacing-lg);
}
/* --flush (homepage hero) — hero → first section seam. The base T2 reserves 48px
   of padding plus a 48px margin under the photo for pages whose card overhangs
   its bottom edge. The homepage card sits fully inside the photo, so that
   reserve just stacks with the next section's own top margin. Zeroed so the
   seam is the page's standard beat. Desktop only by specificity: the ≤900px
   rule that puts the card back in flow (0,2,0) keeps its own bottom padding,
   which the card still needs there. Must sit after the base .hero-t2 rule. */
.hero-t2--flush { padding-bottom: 0; margin-bottom: 0; }
/* --wide-card — the prototype's lobby-day.html page-level override
   (`.hero-t2__card { max-width: 540px }`): 30px more room so a primary +
   secondary button pair sits on one line inside the card. Use with the
   two-button shape of the hero-t2 pattern; the one-button homepage shape
   keeps the base 510px. */
.hero-t2--wide-card .hero-t2__card { max-width: 540px; }
/* Keep an underlined phrase on one line in the T2 headline ("show up", "like
   you.") — the hand-drawn stroke reads as one mark, so it shouldn't split at a
   wrap. Also from the prototype's lobby-day page-level overrides. */
.hero-t2__card h1 .hdr-underline { white-space: nowrap; }

/* T1 variant with text-left + blue offset slot containing a video poster.
   Used on Monthly Meeting + Current Actions detail pages. Slightly
   different proportions from the About Us T1. */
.hero-t1--media {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-5xl);
  padding: var(--spacing-3xl) var(--page-gutter);
  align-items: center;
  max-width: 1440px;
  margin: 0 auto;
}
.hero-t1--media .hero-t1__text { max-width: 480px; }
.hero-t1--media .hero-t1__text h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h1-display);
  line-height: var(--lh-h1-display);
  letter-spacing: -1px;
  color: var(--ccl-black);
  margin: var(--spacing-md) 0 var(--spacing-lg);
}
.hero-t1--media .hero-t1__text p:not([class*="eyebrow"]) {
  margin: 0 0 var(--spacing-lg);
}
/* H3 Regular — parallel to .h2-regular; H3 size but weight 400 (not 700).
   Used as sub-headlines in T1-media heroes. */
.h3-regular,
.is-style-subhead-h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
}
.hero-t1--media .hero-t1__text .h3-regular { margin: 0 0 var(--spacing-xl); }

/* Action card — white card, image top, time eyebrow + heading + body +
   arrow link. Same chrome as a blog card but with an "in-card text link"
   instead of a click-the-whole-card pattern. */
.action-cards-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
  max-width: 1166px;
  margin: var(--spacing-md) auto var(--spacing-2xl);
  padding: 0 var(--container-pad);
}
/* Responsive (prototype): 3-up → 2-up → stacked. Was missing from the original
   port, so the row stayed 3 columns and overflowed phone viewports. */
@media (max-width: 900px) { .action-cards-row { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .action-cards-row { grid-template-columns: 1fr; } }
.action-card {
  background: #fff;
  border: 1px solid rgba(0,0,0,0.1);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: 0 2px 4px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04);
  display: flex;
  min-width: 0;
  flex-direction: column;
}

.action-card__link:hover { color: var(--ccl-blue); }
/* Visually hide the real checkbox but keep it focusable + functional */
.action-cards-block__toggle input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

/* Layout for the whole label: track + text side by side */
.action-cards-block__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  cursor: pointer;
}

/* Push the whole label to the right edge */
.action-cards-block__toggle-wrap {
  display: flex;
  justify-content: flex-end;
  margin-bottom: var(--spacing-md);
}

.action-cards-block__toggle-label {
  font-size: 16px;
  line-height: 1.4;
}

/* Move the knob when checked */
.action-cards-block__toggle input[type="checkbox"]:checked + .toggle::after {
  transform: translateX(32px);
}

/* Track color when checked (optional — pick your accent) */
.action-cards-block__toggle input[type="checkbox"]:checked + .toggle {
  background: var(--ccl-green);
  border-color: var(--ccl-green);
}

/* Smooth transitions */
.toggle,
.toggle::after {
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

/* Focus ring for keyboard users */
.action-cards-block__toggle input[type="checkbox"]:focus-visible + .toggle {
  outline: 2px solid var(--ccl-blue);
  outline-offset: 2px;
}
/* When "show quick actions" is checked, hide everything that ISN'T a quick action */
.action-cards-block--quick-only .action-card:not(.action-card--quick) {
  display: none;
}

.action-card__image {
  aspect-ratio: 16 / 9;
  background: var(--grey-200);
  overflow: hidden;
  border-bottom: 1px solid rgba(0,0,0,0.1);
}
.action-card__image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.action-card__body {
  padding: var(--spacing-xl);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  flex: 1;
}
.action-card__time {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(0,0,0,0.6);
  margin: 0;
}
.action-card__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  line-height: 28px;
  color: var(--ccl-black);
  margin: 0;
}
/* The body's description paragraph: flex:1 so the link is pushed to the card's
   bottom edge. The :not() is load-bearing. `.action-card__body p` is (0,1,1) and
   beats `.action-card__time` at (0,1,0), so without it the date eyebrow picked
   up flex:1 and absorbed every spare pixel in the column -- on a card with no
   image the body fills the stretched grid row, so the eyebrow grew and shoved
   the title and link to the bottom. It also overrode the eyebrow's intended
   14px/20px with 16px/24px.

   Past-meeting cards emit it: "Featuring: <speaker>", or the event's
   Description when no speaker is attached (.action-card__featuring / __desc). */
.action-card__body p:not(.action-card__time) {
  margin: 0;
  flex: 1;
}
.action-card__link {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 19px;
  /* --ccl-navy, not --ccl-black. Upstream styles this as one "card CTA
     link" family -- .read-more, .team-card__link, .action-card__link,
     .person__link share a single rule, and its comment is explicit about why:
     "one blue means link everywhere ... what marks this as the standalone
     variant is the ARROW and its placement, not a colour of its own."
     Our port coloured this one black, which made it the only card CTA in the
     theme that didn't read as a link. An interim fix matched .team-card__link's
     --fg-link-strong; both now use the family's real colour, --ccl-navy. */
  color: var(--ccl-navy);
  text-decoration: none;
  margin-top: auto;
}
.action-card__link::after { content: '→'; }
.action-card__link:hover { color: var(--ccl-blue); }

/* Toggle filter (e.g. "Only show quick actions") — visual-only switch */
.cards-toolbar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--spacing-sm);
  max-width: 1166px;
  margin: var(--spacing-md) auto 0;
  padding: 0 var(--container-pad);
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--ccl-black);
}
.toggle {
  display: inline-block;
  width: 64px;
  height: 32px;
  border-radius: 32px;
  background: rgba(0,0,0,0.04);
  border: 1px solid rgba(0,0,0,0.45);
  position: relative;
  cursor: pointer;
  vertical-align: middle;
}
.toggle::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}

/* Light-blue info pill — "Next meeting: …" / "When: …" — used on Monthly
   Meeting + Current Actions detail. Border + light tint + calendar icon. */
.info-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-md);
  background: #fff;
  border: 1px solid var(--ccl-blue);
  border-radius: 22px;
  padding: var(--spacing-xs) var(--spacing-lg);
  font-family: var(--font-body);
  font-size: 19px;
  letter-spacing: -0.285px;
  color: var(--ccl-black);
}
.info-pill__icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  /* simple calendar glyph drawn in CSS */
  background:
    linear-gradient(var(--ccl-blue), var(--ccl-blue)) 0 0/100% 4px no-repeat,
    linear-gradient(var(--ccl-blue), var(--ccl-blue)) 25% 0/2px 100% no-repeat,
    linear-gradient(var(--ccl-blue), var(--ccl-blue)) 75% 0/2px 100% no-repeat,
    transparent;
  border: 1.5px solid var(--ccl-blue);
  border-radius: 2px;
}
.info-pill strong { font-weight: 700; }
.info-pill a {
  color: var(--ccl-navy);
  font-weight: 700;
  text-decoration: underline;
}
.info-pill__sep { color: var(--grey-400); }
/* --tip — the same pill at chip size (--text-md, the documented size for
   chips/labels) for a one-line tip ("Two or three sentences is plenty", Take
   Action talking points). The pencil is a mask on ::before so the pill stays
   one paragraph (no icon span for an editor to delete). */
.info-pill.info-pill--tip {
  gap: var(--spacing-xs);
  font-size: var(--text-md);
  letter-spacing: 0;
}
.info-pill--tip::before {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background: var(--ccl-blue);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Three-parts grid — Learn. Celebrate. Act. on Monthly Meeting */
.three-parts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-3xl);
  max-width: 1213px;
  margin: var(--spacing-2xl) auto var(--spacing-3xl);
  padding: 0 var(--page-gutter);
}
.three-parts__col h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
  padding-bottom: var(--spacing-xs);
  position: relative;
}
.three-parts__col h3::after {
  content: '';
  display: block;
  width: 100%;
  height: 3px;
  background: var(--gradient-underline);
  margin-top: var(--spacing-xs);
}
.three-parts__col p {
  margin: var(--spacing-md) 0;
}
.three-parts__photo {
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: var(--spacing-md);
}
.three-parts__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* "Looking For More?" green-tinted callout card — light brand-green bg,
   green border, headline + body + centered button. */
.callout-green {
  background: var(--brand-lightest);
  border: 1px solid var(--ccl-green);
  border-radius: 13px;
  padding: var(--spacing-2xl) var(--spacing-3xl);
  max-width: 1192px;
  margin: var(--spacing-3xl) auto var(--spacing-5xl);
  text-align: center;
}
.callout-green h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--grey-600);
  margin: 0 0 var(--spacing-md);
}
.callout-green p {
  margin: 0 0 var(--spacing-lg);
  max-width: 1010px;
  margin-left: auto;
  margin-right: auto;
}

/* "Want to go deeper?" blue-tinted callout card — light blue bg, blue
   border, icon + title + body on left, button on right. */
.callout-blue {
  background: var(--grey-200);
  border: 1px solid var(--ccl-blue);
  border-radius: var(--radius-md);
  padding: var(--spacing-lg) var(--spacing-2xl);
  max-width: 802px;
  margin: var(--spacing-2xl) auto;
  display: grid;
  grid-template-columns: 84px 1fr auto;
  align-items: center;
  gap: var(--spacing-md);
}
.callout-blue__icon {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  background: var(--ccl-green);
  display: flex;
  align-items: center;
  justify-content: center;
}
.callout-blue__icon::after {
  content: '';
  display: block;
  width: 40px;
  height: 20px;
  border-left: 6px solid #fff;
  border-bottom: 6px solid #fff;
  transform: rotate(-45deg) translate(2px, -4px);
}
.callout-blue__copy h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
}
.callout-blue__copy p {
  margin: 0;
}

/* Info card — inline 2-column callout, copy + CTA. Same surface family as
   .callout-blue (light blue tint, blue border) but without the icon column.
   Used for "Next call: ..." / "Conference: ..." compact info blocks. */
.info-card {
  background: var(--ccl-blue-bg);
  border: 1px solid var(--ccl-blue);
  border-radius: var(--radius-md);
  padding: var(--spacing-lg) var(--spacing-2xl);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--spacing-md);
}
/* Icon is optional — cards without one keep the original 2-column rhythm. */
.info-card:not(:has(.info-card__icon)) { grid-template-columns: 1fr auto; }
.info-card__icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  color: var(--ccl-blue);
  align-self: start; /* aligns to the date heading, not the copy middle */
  margin-top: 3px;
}
@media (max-width: 640px) {
  .info-card { grid-template-columns: auto 1fr; }
  .info-card .btn { grid-column: 1 / -1; justify-self: start; }
}
/* Monthly Meetings block (acf/ccl-monthly-meetings) "Next call" wrapper — the
   .info-card component is shared; this only constrains it on the page (the
   prototype did the same with an inline max-width). "Past" mode needs no wrapper
   rule: .action-cards-row already self-constrains. */
.monthly-meetings--next {
  max-width: 1166px;
  margin: var(--spacing-lg) auto var(--spacing-3xl);
  padding: 0 var(--container-pad);
}
.monthly-meetings--next .info-card { max-width: 681px; }

/* "Next Meeting" section with the upcoming meeting's promo art on the right
   (patterns/monthly-meeting-next.php): a split-feature whose media column is
   the Monthly Meetings block in Promo mode. Copy gets the wider column because
   it carries the Next call card. Centred like the base split-feature: the copy
   is kept short (the "about the meeting" intro is its own section above), so
   the two columns come out close in height. */
.split-feature--meeting {
  grid-template-columns: 1.15fr 1fr;
  gap: var(--spacing-4xl);
}
.split-feature--meeting .split-feature__text { max-width: none; }
.split-feature--meeting .monthly-meetings--next {
  max-width: none;
  margin: var(--spacing-lg) 0;
  padding: 0;
}
/* Beside the promo, the half-width card can't fit the date and "Join the call"
   on one row, so the button takes its own row (the ≤640px layout, at every
   width). The card's 681px cap stays: it only bites when the column collapses. */
.split-feature--meeting:has(.meeting-promo) .info-card { grid-template-columns: auto 1fr; }
.split-feature--meeting:has(.meeting-promo) .info-card .btn { grid-column: 1 / -1; justify-self: start; }
/* Promo art is a lone image with its text baked in: its own shape, never
   cropped (see CLAUDE.md on aspect-ratio). width:auto so a small graphic isn't
   blown up past its real size when the columns stack. */
.meeting-promo { margin: 0; }
.split-feature--meeting .split-feature__media img {
  width: auto;
  max-width: 100%;
}
/* No art for the next meeting yet: drop the empty column and let the copy run
   full width, like the section before the promo existed. [data-type] keeps the
   column visible in the editor, where the block prints a notice instead. */
.split-feature--meeting:not(:has(.meeting-promo)) { grid-template-columns: 1fr; }
.split-feature--meeting .split-feature__media:not(:has(.meeting-promo, [data-type])) { display: none; }
@media (max-width: 782px) {
  .split-feature--meeting { grid-template-columns: 1fr; gap: var(--spacing-xl); }
}

/* ==========================================================================
   Events kit — shared conference/event presentation (Conferences + Monthly
   Meetings blocks). Ported from the prototype: .event-meta, .conference-events
   /.conference-event-card (attend-conference rows), plus a standardized
   .event-spotlight consolidating the prototype's ad-hoc .ta-conf/.conference-
   callout spotlights.
   ========================================================================== */

/* WHEN / WHERE meta pair. Unscoped (the prototype scopes label/value under .ccl
   for a hero-cascade reason that doesn't apply here) so it previews in the
   editor canvas too. */
.event-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm) var(--spacing-2xl);
  margin: 0 0 var(--spacing-md);
  padding: 0;
  list-style: none;
}
.event-meta__label {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-size: var(--fs-tiny);
  color: var(--ccl-blue-dark);
  margin: 0 0 2px;
}
.event-meta__value {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: 1.2;
  color: var(--ccl-black);
  margin: 0;
}

/* The one WYSIWYG Description body — paragraph and/or bulleted list. */
.event-desc p {
  margin: 0 0 var(--spacing-md);
}
.event-desc p:last-child { margin-bottom: 0; }
.event-desc ul { margin: 0 0 var(--spacing-md); padding-left: 1.25em; list-style: disc; }
.event-desc li {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.5;
  color: var(--fg2);
  margin: 0 0 var(--spacing-2xs);
}

/* Event cards (patterns/event-cards.php) — the prototype's .ld-days / .ld-day
   (lobby-day.html, "Three lobby days a year"), under a page-neutral name.
   Compact bordered cards for recurring events, each with its own button.
   --featured is the flagship: grey fill + blue border, so the design weight
   says which one is the main event. The grid (max 3 columns, min 280px) is
   the Group block's own grid layout; these rules only shape the card.
   Title = Item title (the pattern sets it; defaulted here too, as on tiles);
   description = the canonical p. */
.event-card.wp-block-group {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  padding: var(--spacing-lg);
}
.event-card--featured.wp-block-group {
  background: var(--grey-100);
  border-color: var(--ccl-blue);
}
/* WP adaptation: the group's flow layout puts a blockGap margin on each child
   after the first; the card's own gap owns that spacing. The button takes the
   leftover height instead, so a row's buttons line up along the bottom. */
.event-card.wp-block-group > * { margin-block: 0; }
.event-card.wp-block-group > .wp-block-buttons { margin-top: auto; }
.event-card h3 {
  font-size: var(--fs-item-title);
  line-height: calc(var(--lh-item-title) / var(--fs-item-title));
}
/* The label/value pairs are core Groups here, not the <ul> ccl_event_meta()
   prints; the card-sized gaps are the prototype's --compact ones (its smaller
   compact values aren't ported: at 18px they'd read as body copy). */
.event-card .event-meta { gap: var(--spacing-xs) var(--spacing-lg); }
.event-card .event-meta > * { margin: 0; }
/* 3 → 1 under 900px, as Photo tiles do: the grid's own 280px minimum would
   give 2 + 1 on a tablet, leaving the third card alone at half width. Doubled
   class to beat the grid layout's generated .wp-container-* rule. */
@media (max-width: 900px) {
  .event-cards.wp-block-group { grid-template-columns: minmax(0, 1fr); }
}

/* Card rows (list mode) — image one side, body the other; alternating. */
.conference-events {
  max-width: 1208px;
  margin: 0 auto var(--spacing-3xl);
  padding: 0 var(--page-gutter);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xl);
}
.conference-event-card {
  display: grid;
  grid-template-columns: minmax(0, 519px) 1fr;
  gap: var(--spacing-2xl);
  align-items: start;
}
.conference-event-card:nth-child(even) { grid-template-columns: 1fr minmax(0, 519px); }
.conference-event-card:nth-child(even) .conference-event-card__image { order: 2; }
.conference-event-card:nth-child(even) .conference-event-card__body { order: 1; }
.conference-event-card__image {
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: var(--grey-200);
}
.conference-event-card__image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.conference-event-card__body h3 { margin: 0 0 var(--spacing-sm); }
/* The CTA is a bare .btn after the description (no .button-row like the spotlight
   has), so give it breathing room from the text above it. */
.conference-event-card__body .btn { margin-top: var(--spacing-md); }
@media (max-width: 900px) {
  .conference-event-card,
  .conference-event-card:nth-child(even) { grid-template-columns: 1fr; }
  .conference-event-card:nth-child(even) .conference-event-card__image { order: 0; }
  .conference-event-card:nth-child(even) .conference-event-card__body { order: 0; }
}

/* Spotlight (spotlight mode) — 2-col featured promo. Standardized name; layout
   from the prototype's .ta-conf. Reused by the Monthly Meetings spotlight too. */
.event-spotlight-wrap { max-width: 1320px; margin: var(--spacing-3xl) auto; padding: 0 var(--spacing-4xl); }
.event-spotlight {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-3xl);
  align-items: center;
}
.event-spotlight__copy .eyebrow-green { font-size: 20px; margin-bottom: var(--spacing-sm); }
.event-spotlight__copy h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 32px;
  line-height: 40px;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.event-spotlight .event-meta { margin: var(--spacing-md) 0; }
/* No fixed ratio. The Monthly Meeting promo graphic carries typography inside
   the artwork -- the date, the time, ccl.org/youtube -- so a 4/3 slot with
   object-fit:cover cropped the left edge straight through it ("...12, 2026",
   "...ORG/YOUTUBE"). The slot takes the image's own ratio instead; the grid is
   align-items:center, so a short image still sits centred against the copy.
   :empty keeps the grey placeholder box for the no-image state, which would
   otherwise collapse to nothing. */
.event-spotlight__media {
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-200);
}
.event-spotlight__media img { width: 100%; height: auto; display: block; }
.event-spotlight__media:empty { aspect-ratio: 4 / 3; }
@media (max-width: 960px) {
  .event-spotlight-wrap { padding: 0 var(--spacing-lg); }
  .event-spotlight { grid-template-columns: 1fr; gap: var(--spacing-lg); }
  .event-spotlight__media { max-width: 560px; }
}

/* Spotlight CTA row */
.button-row { display: flex; flex-wrap: wrap; gap: var(--spacing-md); margin-top: var(--spacing-lg); }

/* Responsive YouTube embed — the monthly-meeting spotlight replay video (and
   reusable anywhere). 16:9, rounded to match the media slot. */
.video-embed {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-200);
}
.video-embed iframe { width: 100%; height: 100%; display: block; border: 0; }
/* The .video-embed inside carries its own 16/9, so the slot only needs its grey
   placeholder dropped -- otherwise it shows as a band while the iframe loads. */
.event-spotlight__media--video { background: transparent; }

/* ==========================================================================
   Join form — the FormAssembly form embedded inline via the Join form block.
   The form styles itself: its FormAssembly theme and the CSS in its custom
   HTML box arrive with the embed (see blocks/join-form/render.php). Don't add
   wForm overrides here — make brand changes in FormAssembly. This wrapper only
   constrains + centers the block.

   Font alias: the form's FormAssembly theme asks for 'Source Sans Pro' (the
   old name); this theme ships its successor 'Source Sans 3'. Alias the old name
   to the same variable font file (weights 200–900) so the form renders in the
   brand body font from our own files instead of falling back. (Ubuntu, used by the form
   title, is already registered via theme.json.)
   ========================================================================== */
@font-face {
  font-family: 'Source Sans Pro';
  font-weight: 200 900;
  font-style: normal;
  font-stretch: normal;
  font-display: swap;
  src: url('../fonts/source-sans-3-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Source Sans Pro';
  font-weight: 200 900;
  font-style: italic;
  font-stretch: normal;
  font-display: swap;
  src: url('../fonts/source-sans-3-latin-italic.woff2') format('woff2');
}
.join-form { max-width: var(--wp--style--global--content-size, 780px); margin-inline: auto; }
.join-form__terms p {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.5;
  color: var(--grey-500);
  margin: 0;
}
/* Join card — the standard wrapper for the join form (patterns/join-card.php),
   ported from the prototype's .join-split__card, and also the card in the
   state hero (blocks/state-hero). ONE card around heading +
   intro + form; the form block draws none of its own. The title and intro are
   sized here, not by heading level, so an editor can make the heading H2 or H3
   to fit the page outline without it changing size. Variants (a blue offset
   block behind it, say) should wrap .join-card, not restyle it. */
.join-card {
  background: var(--grey-0);
  border-radius: var(--radius-lg);
  padding: var(--spacing-xl);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.join-card .join-card__title {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  font-size: var(--fs-h4);
  line-height: calc(var(--lh-h4) / var(--fs-h4));
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
}
.join-card .join-card__lede {
  font-family: var(--font-body);
  font-size: var(--fs-h5); /* the theme's lede size (.body-lead), not the prototype's 19px */
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--grey-600);
  margin: 0 0 var(--spacing-lg);
}
/* Two classes deep on purpose: core's flow layout spaces a Group's children
   with a one-class rule, which a one-class reset would only tie with. */
.join-card .join-form { max-width: none; margin-block: 0; }
/* The Join form block's fine print (age, terms, privacy, unsubscribe —
   Appearance → Join form). Tiny grey type like the Volunteer page's hand-made
   version; its links are ordinary prose links. */
.join-form__fine-print p {
  font-family: var(--font-body);
  font-size: var(--wp--preset--font-size--tiny);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--grey-600);
  margin: var(--spacing-lg) 0 0;
}
/* WP adaptation: the prototype keeps 32px padding at every width, which
   leaves the form ~280px wide on a phone. */
@media (max-width: 480px) {
  .join-card { padding: var(--spacing-lg); }
}

/* Spotlight media as a replay link (Monthly Meetings overview) — play overlay. */
.event-spotlight__media--play { position: relative; display: block; cursor: pointer; }
.event-spotlight__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--ccl-green);
  display: grid;
  place-items: center;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .25);
  transition: transform .12s ease;
}
.event-spotlight__media--play:hover .event-spotlight__play { transform: scale(1.06); }
.event-spotlight__play svg { width: 30px; height: 30px; fill: var(--ccl-black); margin-left: 4px; }

/* Conference Hero mode (Conferences block, mode=hero) — the featured-conference
   content only: centered title, When/Where/Status, lede, CTAs. Ported from the
   prototype's .conference-hero__featured. The page header, wash, and video are
   separate blocks placed around it. */
.conferences--hero { text-align: center; }
.conference-hero__featured { max-width: 900px; margin: 0 auto; }
.conference-hero__featured h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 32px;
  line-height: 40px;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
}
.event-meta--center { justify-content: center; }
.conference-hero__lede {
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 28px;
  color: var(--ccl-black);
  margin: var(--spacing-md) 0 var(--spacing-lg);
}
.conference-hero__lede p { margin: 0; }
.conference-hero__ctas {
  display: flex;
  gap: var(--spacing-md);
  justify-content: center;
  flex-wrap: wrap;
}

/* Page header pattern — centered eyebrow / display title / subhead. Reusable
   page-top header; background-agnostic (wrap in a Wash group for a washed hero). */
.page-header { text-align: center; }
.page-header .display { margin: 0 0 var(--spacing-sm); }
/* Subhead position styling — stable across size swaps (the size itself comes
   from the .is-style-subhead-* block style the editor picks). */
.page-header .h3-regular, /* compat: legacy page-header instances placed before the __subhead rename */
.page-header__subhead { color: var(--ccl-black); margin: 0; }

/* "Rounded (16:9)" Video block style — hero/promo videos. */
.wp-block-video.is-style-rounded-16-9 { border-radius: var(--radius-md); overflow: hidden; }
.wp-block-video.is-style-rounded-16-9 video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-md);
  background: var(--grey-200);
}

/* Same "Rounded (16:9)" style, applied to the Embed block (a pasted
   YouTube/Vimeo URL). The embed already carries its own 16:9 aspect-ratio
   wrapper from core, so this only needs to round it -- no crop to force. */
.wp-block-embed.is-style-rounded-16-9 .wp-block-embed__wrapper {
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* ==========================================================================
   Conference Agenda block (acf/ccl-conference-agenda) — day tabs + session
   list. Ported from the prototype (.tabs/.tabs--lg, .sessions/.session). Tabs
   and session title/body are UNSCOPED (prototype scoped some under .ccl) so
   they preview in the editor canvas too.
   ========================================================================== */
.tabs {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--tabs-gap, var(--spacing-3xl));
  border-bottom: 1px solid var(--grey-300);
  margin: 0;
  padding: 0;
  list-style: none;
}
.tabs__tab {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  font-size: var(--tabs-size, var(--fs-h4));
  line-height: var(--tabs-lh, var(--lh-h4));
  color: var(--grey-500);
  text-decoration: none !important;
  outline: none;
  background: none;
  border: 0;
  border-bottom: 3px solid transparent;
  padding: 0 0 var(--spacing-md);
  margin-bottom: -1px;
  cursor: pointer;
  white-space: nowrap;
}
.tabs__tab:hover { color: var(--ccl-black); }
.tabs__tab[aria-selected="true"],
.tabs__tab[aria-current="page"],
.tabs__tab.active {
  font-weight: var(--fw-strong-heading);
  color: var(--ccl-black);
  border-image: var(--gradient-underline) 1;
}
.tabs__tab:focus-visible { outline: 2px solid var(--ccl-blue); outline-offset: 4px; border-radius: 2px; }
.tabs--lg { --tabs-size: var(--fs-h4); --tabs-lh: var(--lh-h4); --tabs-gap: var(--spacing-3xl); }
.tabs--sm {
  --tabs-size: var(--fs-small);
  --tabs-lh: var(--lh-small);
  --tabs-gap: var(--spacing-lg);
}
.tabs--md { --tabs-size: var(--fs-h5); --tabs-lh: var(--lh-h5); --tabs-gap: var(--spacing-xl); }
/* Dense rows: one line that scrolls sideways instead of wrapping. Wrapped, a
   tab row turns into a stack of lines on a phone, with the active underline
   floating mid-block and the track under only the last line. The prototype's
   modifier, plus what a scroll container needs:
   - the track becomes an inset shadow — a scroll box clips the -1px overlap
     the active underline relies on, and the underline paints over a shadow;
   - no visible scrollbar (touch swipes; the cut-off next tab shows there's
     more), and the focus ring moves inside so it isn't clipped;
   - scripts/apps/article-single.js scrolls the active tab into view on load.
   The blog's topic row (Stories page + category archives) gets it by context
   too, so the Stories page matches without editing its saved markup. */
.tabs--scroll,
.topic-tabs-wrap .tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  border-bottom: 0;
  box-shadow: inset 0 -1px 0 var(--grey-300);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tabs--scroll::-webkit-scrollbar,
.topic-tabs-wrap .tabs::-webkit-scrollbar { display: none; }
.tabs--scroll .tabs__tab,
.topic-tabs-wrap .tabs .tabs__tab { margin-bottom: 0; flex-shrink: 0; }
.tabs--scroll .tabs__tab:focus-visible,
.topic-tabs-wrap .tabs .tabs__tab:focus-visible { outline-offset: -2px; }
.sessions { display: grid; gap: var(--spacing-md); margin: 0; padding: 0; list-style: none; }
.session {
  display: grid;
  /* 168px, not 160: "10:20 am–10:30 am" is the longest real time range and it
     wrapped at 160. Fixed rather than max-content on purpose — each session row
     is its own grid, so content-sizing would give every row a different column
     width and the times would stop lining up down the page. */
  grid-template-columns: 168px minmax(0, 1fr);
  gap: var(--spacing-lg);
  padding-bottom: var(--spacing-md);
  border-bottom: 1px solid var(--grey-200);
}
.session:last-child { border-bottom: 0; padding-bottom: 0; }
.session__time { font-family: var(--font-display); font-weight: var(--fw-weak); font-size: var(--fs-small); color: var(--ccl-black); white-space: nowrap; }
.session__title {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-2xs);
}
.session__body { font-size: var(--fs-small); margin: 0; }

/* The live-stream note. Italic and quiet: it's a logistical aside about how to
   attend, not part of the session's pitch, and it reads as an aside rather than
   a second sentence of the blurb. Set from a checkbox, so the wording is fixed. */
.session__livestream {
  font-style: italic;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--grey-500);
  margin: var(--spacing-2xs) 0 0;
}

/* Session speakers — a list of people, so marked up as one: a <ul>, laid out
   inline and wrapping, so screen readers announce the count and the grouping
   rather than a run-on line. */
.session__speakers {
  list-style: none;
  margin: var(--spacing-md) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-md) var(--spacing-2xl);
}
/* Photo + name/role, the pairing the programme has always used. No separator
   between people is needed once each carries a portrait — the photos do that
   work, which is why the earlier text-only version needed a middot and this
   one doesn't. */
.session__speaker {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}
.session__speaker-photo {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: var(--grey-200);
}
.session__speaker-text { display: flex; flex-direction: column; min-width: 0; }
.session__speaker-name {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  line-height: 1.3;
  color: var(--ccl-black);
}
.session__speaker-sub {
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-400);
}

/* A break / lunch / any pause in the programme. It occupies a row like a
   session but isn't one — nothing to read, nowhere to be. Colour alone carries
   that: the weight stays as bold as a session title so the row still scans as a
   heading at a glance, and only the grey marks it as not-a-session. */
.session--break .session__title { color: var(--grey-400); }

/* Descriptions are rich text now, so the body is a <div> of prose rather than a
   single escaped <p>. Keep the agenda's compact rhythm: no leading/trailing
   margin, links visible, italics as authored. */
.session__body > :first-child,
.breakout__body > :first-child { margin-top: 0; }
.session__body > :last-child,
.breakout__body > :last-child { margin-bottom: 0; }
.session__body p,
.breakout__body p { margin: 0 0 var(--spacing-2xs); }
.session__body a,
.breakout__body a { color: var(--ccl-blue); text-underline-offset: 2px; }
.session__sub { margin: 0; padding: 0; list-style: none; }
@media (max-width: 700px) {
  .session { grid-template-columns: 1fr; gap: var(--spacing-2xs); }
}

/* Grey "panel" box around the whole agenda — same treatment as the Teams tabs
   shell (.team-panel), via the same tokens (grey-100 / radius-md / padding), but
   NOT the same class: they're separate tab systems, so we share the look, not
   the implementation. */
.conference-agenda {
  background: var(--grey-100);
  border-radius: var(--radius-md);
  max-width: 1166px;
  margin: var(--spacing-lg) auto var(--spacing-3xl);
  padding: var(--spacing-xl) var(--spacing-3xl) var(--spacing-4xl);
}
@media (max-width: 700px) {
  .conference-agenda { padding: var(--spacing-lg) var(--spacing-lg) var(--spacing-2xl); }
}
.conference-agenda [role="tabpanel"] { padding-top: var(--spacing-xl); }
.conference-agenda__day { font-family: var(--font-display); font-weight: var(--fw-strong-heading); font-size: var(--fs-h4); margin: 0 0 var(--spacing-md); }
/* Session header: title + a right-side affordance — a live Join button (only on
   the session's own day) or, for a Breakouts session, the accordion chevron. */
.session__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--spacing-md);
  margin-bottom: var(--spacing-2xs);
}
.session__head .session__title { margin: 0; }
.session__join { flex-shrink: 0; white-space: nowrap; }

/* Breakouts render as a collapsible accordion (native <details>). */
.session__accordion > summary { list-style: none; cursor: pointer; }
.session__accordion > summary::-webkit-details-marker { display: none; }
.session__chevron { flex-shrink: 0; color: var(--ccl-blue); transition: transform .15s ease; margin-top: 4px; }
.session__chevron svg { display: block; width: 22px; height: 22px; }
.session__accordion[open] .session__chevron { transform: rotate(180deg); }
.session__panel { margin-top: var(--spacing-md); }
.breakout { padding: var(--spacing-md) 0; border-top: 1px solid var(--grey-200); }
.breakout:first-child { border-top: 0; padding-top: 0; }
.breakout__title {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-2xs);
}
.breakout__body { font-size: var(--fs-small); margin: 0 0 var(--spacing-sm); }
.breakout .session__join { margin-top: 0; }
.info-card__copy h2,
.info-card__copy h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
}
.info-card__copy p {
  margin: 0;
}
/* --calendar: the calendar icon drawn in CSS, for an Info card built from
   blocks in a pattern (the Youth page's meeting cadence), where an <img> would
   be one more thing for an editor to delete. Icon column first, copy beside. */
.info-card.info-card--calendar { grid-template-columns: auto minmax(0, 1fr); }
.info-card--calendar::before {
  content: '';
  width: 24px;
  height: 24px;
  align-self: start;
  margin-top: 3px;
  background: url('/wp-content/themes/twentytwentyfive-child/assets/brand/marks/calendar.svg') center / contain no-repeat;
}
.info-card.info-card--calendar > * { margin: 0; }

/* Progress meter — "X/Y" count + gradient progress bar */
.progress-meter {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  margin: var(--spacing-md) 0;
}
.progress-meter__count {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--ccl-black);
  white-space: nowrap;
}
.progress-meter__count strong { font-weight: 700; }
.progress-meter__bar {
  flex: 1;
  height: 12px;
  background: var(--grey-200);
  border-radius: 6px;
  overflow: hidden;
}
.progress-meter__fill {
  height: 100%;
  background: linear-gradient(90deg, var(--ccl-blue) 0%, var(--ccl-green) 100%);
  border-radius: 6px;
}

/* Current Action banner — image left + content right, used in
   the Take Action landing's "Current Action" feature section. */
.current-action-list {
    max-width: 1024px;
    margin: 0 auto;
    padding: 0 var(--container-pad, 20px);
}
.current-action-band {
  background: var(--grey-100);
  padding: var(--spacing-4xl) var(--page-gutter);
}
.current-action-banner {
  display: grid;
  grid-template-columns: 494px 1fr;
  gap: 0;
  width: 100%;
  max-width: 1024px;
  min-height: 400px;
  margin: var(--spacing-2xl) auto var(--spacing-3xl);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: 0 2px 4px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04);
  border: 1px solid rgba(0,0,0,0.1);
}
.current-action-banner__photo {
  position: relative;
  background: var(--grey-200);
  overflow: hidden;
}

.current-action-banner__photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;    
  display: block;
}
.current-action-banner__body {
  padding: var(--spacing-xl);
  background: #fff;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}
.current-action-banner__body h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0;
}
.current-action-banner__body p {
  margin: 0;
}
.current-action-banner__body .button-row { display: flex; gap: var(--spacing-sm); flex-wrap: wrap; }
.current-action-banner__body .btn-primary {
  background: var(--ccl-green);
  color: var(--ccl-black);
  border-color: var(--ccl-green);
}
.current-action-banner__body a {
  font-weight: 600;
  font-family: var(--font-display);
  font-size: var(--text-md);
  line-height: 1;
  padding: 11px 18px;
  border-radius: var(--radius-pill);
  border: 2px solid transparent;
  cursor: pointer;
  letter-spacing: 0.01em;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  min-width: 133px;
  white-space: nowrap;
}
.current-action-banner .button-row {
	display: flex;
	flex-direction: row;
	align-items: flex-start;
	gap: 0.75rem;
}
.current-action-banner__body .btn-secondary {
  background: #2A2A2B;
  color: #fff;
  border-color: #2A2A2B;
}
@media (max-width: 768px) {
  .current-action-banner {
    grid-template-columns: 1fr;
    min-height: 0;
    margin: var(--spacing-lg) auto var(--spacing-xl);
  }

  /* Give the photo a height, since the absolutely positioned img can't */
  .current-action-banner__photo {
    aspect-ratio: 16 / 9;
  }

  .current-action-banner__body {
    padding: var(--spacing-lg);
  }

  /* Full-width buttons that can wrap long labels */
  .current-action-banner .button-row {
    align-items: stretch;
  }

  .current-action-banner__body .button-row a {
    width: 100%;
    min-width: 0;
    white-space: normal;
    text-align: center;
  }
}



.conference-bullets li { margin-bottom: 4px; }

/* "Catch up with CCL" cards (past monthly meetings) — same as action-card
   pattern but with blue uppercase date eyebrow + speaker bio styling. */
.past-meeting-card .action-card__time { color: var(--ccl-blue); }

/* .btn-secondary-dark removed — use canonical `.btn .btn-secondary` from
   tokens.css instead. Charcoal fill, white text. */

/* Spread the Word section header */
.spread-word {
  max-width: 1166px;
  margin: var(--spacing-3xl) auto var(--spacing-md);
  padding: 0 var(--container-pad);
}
.spread-word h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.spread-word p {
  margin: 0;
}

/* ==========================================================================
   STORIES (blog index) — 581:1121
   Featured 3-up (1 large + 2 stacked), newsletter signup banner,
   topic tabs, search bar, post list rows, pagination.
   ========================================================================== */

.stories-hero {
  text-align: center;
  max-width: 800px;
  margin: var(--spacing-4xl) auto var(--spacing-3xl);
  padding: 0 var(--container-pad);
}
.stories-hero h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h1-display);
  line-height: var(--lh-h1-display);
  letter-spacing: -1px;
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-sm);
}
.stories-hero p {
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  margin: 0;
}

/* --------------------------------------------------------------------------
   Featured section — Stories page and blog/category archive.
   Featured card on top; on the Stories page, a row of briefs under it.
   -------------------------------------------------------------------------- */
.stories-featured {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xl);
  max-width: 1166px;
  margin: var(--spacing-md) auto var(--spacing-2xl);
  padding: 0 var(--container-pad);
}
.stories-featured__more {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--spacing-xl);
  border-top: 1px solid var(--grey-200);
  padding-top: var(--spacing-xl);
}

/* Story card — base: padded, image over copy */
.story-card {
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.10);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  padding: var(--spacing-lg);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  text-decoration: none;
  color: inherit;
}
/* Whole-card link: the title lights up, like .post-row and a.team-card */
.story-card:hover h2 { color: var(--ccl-blue); }
.story-card__image {
  aspect-ratio: 16 / 9;
  background: var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  height:100%;
}
.story-card__image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.story-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  justify-content: center;
}
.story-card__head {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xs);
}
.story-card h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  letter-spacing: -0.015em;
  margin: 0;
  transition: color .2s ease;
}
.story-card p { margin: 0; }
.story-card--small h2 { font-size: 20px; line-height: 28px; }

/* Featured: photo flush left, copy right. Double class so it beats the base
   regardless of order. 1fr not 50%: two 50% columns plus a gap overflowed. */
.story-card.story-card--featured {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: 0;
  padding: 0;
}
.story-card--featured .story-card__image {
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}
.story-card--featured .story-card__body { padding: var(--spacing-lg); }
/* Desktop only: on phones the heading falls back to .h2-regular's size. */
@media (min-width: 901px) {
  .story-card--featured .story-card__head h2 { font-size: 36px; line-height: 44px; }
}

/* Story brief — the small cards in .stories-featured__more */
.story-brief {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  text-decoration: none;
  color: inherit;
}
.story-brief__thumb {
  aspect-ratio: 16 / 9;
  width: 100%;
  min-height: 180px;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-200);
  /* Centre the image when it's shorter than the box */
  display: flex;
  align-items: center;
  justify-content: center;
}
.story-brief__thumb img { width: 100%; height: auto; display: block; }
.story-brief__copy h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  font-size: var(--fs-h4);
  line-height: calc(var(--lh-h4) / var(--fs-h4));
  color: var(--fg2);
  margin: 0 0 var(--spacing-sm);
  transition: color .2s ease;
}
.story-brief:hover h3 { color: var(--ccl-blue); }
/* Pin "Read more" to the bottom so the three line up across the row */
.story-brief .read-more { margin-top: auto; }

.story-date {
  font-family: var(--font-body);
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
  letter-spacing: 0.01em;
  margin: 0;
}
.story-brief__excerpt {
  font-family: var(--font-body);
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
  margin: 0;
}
.featured-search {
  padding: var(--spacing-md) 0 var(--spacing-3xl) !important;
  justify-content: center;
  margin-top: var(--spacing-md) !important;
}

/* ≤900px: the featured card stacks, image over copy. The body keeps its
   --spacing-lg padding so the copy never touches the card edge. */
@media (max-width: 900px) {
  .story-card.story-card--featured { grid-template-columns: 1fr; }
  .story-card--featured .story-card__image {
    border-radius: var(--radius-md) var(--radius-md) 0 0;
  }
}
.read-more {
  /* --font-body with the rest of the card CTAs, not --font-display. Ubuntu is
     for headings and buttons; a card CTA is a link sitting in the card's text
     flow, and upstream's shared rule for this family sets --font-body. This was
     the only one of the five in Ubuntu. */
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 19px;
  color: var(--ccl-navy);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
}
.read-more::after { content: '→'; }

/* --------------------------------------------------------------------------
   Stories field — the "Stories from the field" section (acf/ccl-stories block,
   and the state hub's "CCLers in action" band): a centered heading, a 3-up
   grid of the latest posts in a category, and a button to the archive. The
   cards are .team-card (rendered by ccl_render_story_card()) — the prototype's
   component for these bands; only the grid/heading/CTA are section-specific.
   Collapses to a single column on narrow screens.
   -------------------------------------------------------------------------- */
.stories-field { padding-block: var(--spacing-3xl); }
.stories-field__inner {
  max-width: var(--wp--style--global--wide-size, 1166px);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}
/* Let the <h2> element drive size/weight/colour (the new tag = size scale: h2 =
   40px section header). This block only owns the section-specific centring +
   spacing — no hard-coded font-size, so it stays in step with the scale. */
.stories-field__heading {
  text-align: center;
  margin: 0 0 var(--spacing-2xl);
}
.stories-field__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
}
/* Whole-card link: the .team-card base already resets text-decoration/color
   for an <a>; give it a branded focus ring (was the browser default black). */
.team-card--story:focus-visible {
  outline: 2px solid var(--ccl-blue);
  outline-offset: 2px;
}
.stories-field__cta { text-align: center; margin-top: var(--spacing-2xl); }
/* .btn doesn't wrap, and inside the page's padding plus this block's, "More
   stories from the field" ran 29px out of the column on a phone. */
.stories-field__cta .btn { white-space: normal; max-width: 100%; }
@media (max-width: 900px) {
  .stories-field__grid {
    grid-template-columns: 1fr;
    max-width: 480px;
    margin-inline: auto;
  }
}

/* Newsletter subscribe banner — uses .cta-banner-navy as the base shape
   but with an inline form layout instead of a centered headline + CTA. */
.subscribe-banner {
  background: var(--ccl-navy);
  color: #fff;
  border-radius: var(--radius-md);
  padding: var(--spacing-2xl) var(--spacing-3xl);
  max-width: 1166px;
  /* The same inset as the post list and pager beside it, so the band lines up
     with the rows' edges and keeps a side gutter on phones (it ran edge to
     edge there, rounded corners and all). The patterns.css copy of this rule
     sets no width, so this holds wherever the banner appears. */
  width: min(calc(1166px - 2 * var(--container-pad)), calc(100% - 2 * var(--container-pad)));
  margin: var(--spacing-2xl) auto;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--spacing-lg);
}
.subscribe-banner h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: #fff;
  margin: 0;
  max-width: 343px;
}
.subscribe-banner__form {
  display: flex;
  gap: var(--spacing-md);
  justify-content: flex-end;
  align-items: center;
}
.subscribe-banner__form input {
  flex: 1;
  max-width: 319px;
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: #fff;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 16px;
  color: var(--grey-500);
}
.subscribe-banner__form input::placeholder { color: var(--grey-400); font-style: italic; }

/* Topic tabs — horizontal list with dividers between tabs, navy text */
.topic-tabs-wrap {
  max-width: 1190px;
  margin: var(--spacing-3xl) auto var(--spacing-md);
  padding: 0 var(--container-pad);
  text-align: center;
}
.topic-tabs-wrap > h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  letter-spacing: -0.015em;
  margin: 0 0 var(--spacing-lg);
}
.topic-tabs {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-md);
  border-top: 1px solid var(--grey-300);
  border-bottom: 1px solid var(--grey-300);
  padding: var(--spacing-md) 0;
  margin-bottom: var(--spacing-lg);
}
.topic-tabs a {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-navy);
  text-decoration: none;
  padding: 0 var(--spacing-md);
  text-align: center;
  letter-spacing: -0.015em;
}
.topic-tabs a:hover { color: var(--ccl-blue); }
.topic-tabs .sep {
  width: 1px;
  height: 32px;
  background: var(--grey-300);
}
.topic-tabs a.active { text-decoration: underline; text-underline-offset: 4px; }

/* Search bar — label inline with the input + Search button (secondary) */
.blog-topics-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--spacing-md);
  margin: var(--spacing-md) 0 var(--spacing-3xl);
}

.blog-topics-header .h2-regular {
  margin: 0;
}
.blog-topics-header .blog-search {
  margin-left: auto;   /* shoves the form to the right edge */
  padding: 0;
}
.blog-search {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  margin: 0;
  padding: var(--spacing-md) 0; 
  flex: 0 1 auto;
  width: auto;
}

.blog-search input {
  width: 100%;
  max-width: 320px;   /* tweak to taste */
  min-width: 250px;
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: #fff;
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--ccl-black);
}


/* On narrow screens: form drops to its own row and stretches full width */
@media (max-width: 768px) {
  .blog-topics-header {
    flex-direction: column;
    align-items: stretch;
  }

  .blog-search {
    width: 100%;
    padding-left: 0;
    padding-right: 0;
  }
  .blog-search input {
    width: auto;        /* release the fixed 476px */
    flex: 1 1 auto;     /* let it grow to fill remaining space */
    min-width: 0;       /* required so it can actually shrink inside a flex row */
  }

  .blog-topics-header .blog-search input[type="search"] {
    flex: 1 1 auto;
    max-width: none;
  }
}

/* Post list rows — horizontal: image left + content right */
.post-list {
  max-width: 1166px;
  margin: 0 auto var(--spacing-3xl);
  padding: 0 var(--container-pad);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xl);
}

.post-row {
  display: grid;
  grid-template-columns: 375px 1fr;
  gap: var(--spacing-lg);
  align-items: center;
  /* Ragged-right, not justified (a theme-only deviation; the prototype never
     justified these). Justified copy in a column this narrow opens wide gaps
     between words, titles included, and it's worst on a phone. Set, not just
     removed: on the Stories page the list sits inside .topic-tabs-wrap, which
     centers its text. */
  text-align: start;
  text-decoration: none;
  color: inherit;
}
.post-list a:hover,
.post-row,
.post-row *,
.post-row:hover,
.post-row:hover * {
  text-decoration: none !important;
}

.post-row__image {
  aspect-ratio: 16 / 9;
  width: 100%;
  min-height: 180px;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-200);
  display: flex;
  align-items: center;
  justify-content: center;
}
.post-row__image img { width: 100%; height: auto; display: block; }
.post-row__copy { display: flex; flex-direction: column; gap: var(--spacing-md); }
.post-row__copy h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  letter-spacing: -0.015em;
  margin: 0;
  transition: color 0.2s ease;
}

.post-row:hover .post-row__copy h2 {
  color: var(--ccl-blue);
}

.post-row__date {
  font-family: var(--font-body);
  font-size: 19px;
  letter-spacing: -0.285px;
  color: var(--grey-500);
  margin: 0;
}
.post-row__copy p {
  margin: 0;
}

/* A hairline between rows, spaced like the gap above it (the list's own
   --spacing-2xl), so each story reads as its own entry, as in the blog
   mockups. Between rows only: nothing above the first or below the last,
   where the section's spacing (or the pager's own divider) takes over.
   2px, not 1px: grey-200 at 1px all but disappears, and grey-300 reads as a
   hard line. The pager's divider matches. */
.post-list > .post-row + .post-row {
  padding-top: var(--spacing-2xl);
}
/* Excerpts stop at two lines so the rows scan evenly. Imported posts'
   auto-excerpts vary wildly (press releases open with a dateline paragraph);
   the full text is one click away. */
.post-row__copy .body-lead {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

/* ==========================================================================
   IMPACT SECTION (Our Impact landing, Past Progress, Policy Wins)
   These patterns follow the design system where one exists; the new ones
   (stat-impact, bills list, timeline rail) are flagged in DEVIATIONS.md.
   ========================================================================== */

/* ----- Impact Stats (canonical) ------------------------------------------
   Now a real design-system component (preview/impact-stats.html,
   ui_kits/marketing/ImpactStats.jsx). Class names match the system.
   Two-span numeral: offset shadow + foreground glyph, NOT CSS text-shadow,
   because layered spans give us a per-glyph offset that survives webfonts
   loading at different rates. */
.ccl-stats {
  background: #fff;
  padding: var(--spacing-4xl) var(--spacing-lg);
  margin: var(--spacing-3xl) auto;
  max-width: 1100px;
}
.ccl-stats .ccl-section-inner {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--spacing-lg);
}
.ccl-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
}
.ccl-stat-n {
  position: relative;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 88px;
  line-height: .95;
  letter-spacing: -0.02em;
}
.ccl-stat-n-shadow {
  position: absolute;
  left: 4px;
  top: 4px;
  color: var(--brand);
  user-select: none;
}
.ccl-stat-n-fg {
  position: relative;
  color: var(--ccl-black);
}
.ccl-stat-l {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.35;
  color: var(--ccl-black);
  white-space: pre-line;
}

/* ----- Bills list (Policy Wins card) ------------------------------------- */
/* Commitment tags (policy-win bill-rows) — ported from the prototype. Icon +
   name pill, small uppercase label. Rendered as <a> when the What We Do page
   exists (deep-links to that commitment's accordion), <span> otherwise. */
.commitment-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-sm);
  margin: 0 0 var(--spacing-md);
}
.commitment-tags__label {
  font-family: var(--font-body);
  font-size: var(--fs-tiny);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grey-400);
  font-weight: 700;
}
.commitment-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 16px 4px 4px;
  border-radius: var(--radius-pill);
  background: var(--ccl-green-bg);
  color: var(--ccl-black);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-tiny);
  line-height: calc(var(--lh-tiny) / var(--fs-tiny));
  text-decoration: none;
  transition: background .12s ease;
}
.commitment-tag img {
  width: 28px;
  height: 28px;
  object-fit: contain;
  flex-shrink: 0;
}
.commitment-tag:hover { background: var(--ccl-green-pressed); color: var(--ccl-black); }

/* Policy Wins overview "See all policy wins" — centered primary button. */
.policy-wins__more { text-align: center; padding: var(--spacing-xl) 0; }

.bills-card {
  position: relative;
  background: #fff;
  border-radius: var(--radius-md);
  padding: var(--spacing-xl) var(--spacing-3xl) var(--spacing-3xl);
  box-shadow: 0 2px 10px rgba(0,0,0,0.15);
  max-width: 1140px;
  margin: 0 auto;
  overflow: hidden;
}
.bills-card::before {
  /* Gradient left rail — blue→green, vertical (180deg twin of --gradient-underline). */
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 11px;
  background: linear-gradient(180deg, var(--ccl-blue) 0%, var(--ccl-green) 100%);
}
.bills-card h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
/* Bill accordion — native <details>/<summary>. Each bill is a closed
   row with + icon; opening expands to show CCL's involvement in the bill.
   The + rotates to × when the accordion is open (per chat2.md accordion spec). */
.bill-row {
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-xs);
  margin-top: var(--spacing-sm);
  background: #fff;
  transition: border-color .12s ease;
}
.bill-row[open] { border-color: var(--ccl-blue); }
.bill-row > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: var(--spacing-md) var(--spacing-lg);
  font-family: var(--font-body);
  font-size: 19px;
  letter-spacing: -0.285px;
  color: var(--ccl-black);
  cursor: pointer;
  list-style: none;
}
.bill-row > summary::-webkit-details-marker { display: none; }
.bill-row:hover { border-color: var(--ccl-blue); }
.bill-row strong { font-weight: 700; }
.bill-row__icon {
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  position: relative;
  transition: transform .15s ease;
}
.bill-row__icon::before,
.bill-row__icon::after {
  content: '';
  position: absolute;
  background: var(--grey-500);
}
.bill-row__icon::before { /* horizontal stroke */ inset: 6px 0; }
.bill-row__icon::after  { /* vertical stroke */   inset: 0 6px; }
.bill-row[open] .bill-row__icon { transform: rotate(45deg); }
.bill-row[open] .bill-row__icon::before,
.bill-row[open] .bill-row__icon::after { background: var(--ccl-blue); }
.bill-row__body {
  padding: 0 var(--spacing-lg) var(--spacing-md);
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 28px;
  color: var(--grey-600);
}
.bill-row__body p { margin: 0 0 12px; }
.bill-row__body p:last-child { margin-bottom: 0; }
.bill-row__body a { color: var(--ccl-navy); }
/* Commitment pills are links inside the body but keep their pill look: the
   (0,2,1) rule above would paint them navy, and theme.json underlines links on
   :hover. Same-specificity selectors placed after both, so the pill wins. */
.bill-row__body a.commitment-tag,
.bill-row__body a.commitment-tag:hover,
.bill-row__body a.commitment-tag:focus { color: var(--ccl-black); text-decoration: none; }

/* ----- Navy CTA banner — system pattern documented in SKILL.md ----------- */
.cta-banner-navy {
  background: var(--ccl-navy);
  color: #fff;
  border-radius: var(--radius-md);
  padding: var(--spacing-xl) var(--spacing-3xl);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-md);
  max-width: 780px;
  margin: var(--spacing-3xl) auto;
}
.cta-banner-navy h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: #fff;
  margin: 0;
  max-width: 580px;
}

/* ----- Conference callout (Policy Wins page bottom) ---------------------- */
.conference-callout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-3xl);
  align-items: center;
  max-width: 1140px;
  margin: var(--spacing-3xl) auto var(--spacing-5xl);
  padding: 0 var(--container-pad);
}
.conference-callout h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.conference-callout p {
  margin: 0 0 var(--spacing-lg);
}
.conference-callout__media {
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-200);
}
.conference-callout__media img { width: 100%; height: 100%; object-fit: cover; }

/* ----- Generic centered section header with optional green eyebrow ------- */
.section-header-centered {
  text-align: center;
  max-width: 913px;
  margin: var(--spacing-3xl) auto var(--spacing-xl);
  padding: 0 var(--container-pad);
}
.section-header-centered .h1-bold,
.section-header-centered h1 { margin: 0 0 var(--spacing-md); }
.section-header-centered .eyebrow-green { margin-bottom: var(--spacing-sm); }
.section-header-centered .body-lead { margin: 0 auto; max-width: 790px; }

/* ----- Partnership era block (Our Impact landing) ------------------------ */
.partnership-block {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-3xl);
  align-items: start;
  max-width: 1166px;
  margin: var(--spacing-3xl) auto var(--spacing-2xl);
  padding: 0 var(--container-pad);
}
.partnership-block .copy .eyebrow-meta { margin-bottom: var(--spacing-sm); }
.partnership-block .copy h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.partnership-block .copy p {
  margin: 0 0 18px;
}
.partnership-block .photo {
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.partnership-block .photo img { width: 100%; height: 100%; object-fit: cover; }

/* ==========================================================================
   PAST PROGRESS — vertical timeline of era cards
   ========================================================================== */

.timeline {
  position: relative;
  max-width: 1313px;
  margin: var(--spacing-3xl) auto var(--spacing-5xl);
  padding: 0 var(--page-gutter);
}
/* Vertical gradient rail behind the date labels */
.timeline::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 194px;
  /* Vertical 180deg twin of --gradient-underline (blue→green). */
  width: 4px;
  background: linear-gradient(180deg, var(--ccl-blue) 0%, var(--ccl-green) 100%);
  border-radius: 2px;
}
.timeline-era {
  position: relative;
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 60px;
  align-items: start;
  margin-bottom: var(--spacing-3xl);
}
.timeline-era__date {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  line-height: 28px;
  color: var(--grey-500);
  background: #fff;
  padding: var(--spacing-xs) 0;
  position: relative;
  z-index: 1;
  text-align: right;
  padding-right: var(--spacing-md);
}
.timeline-era__card {
  background: #fff;
  border-radius: var(--radius-md);
  padding: var(--spacing-lg);
  box-shadow: 0 4px 5px rgba(0,0,0,0.16);
  display: grid;
  grid-template-columns: 338px 1fr;
  gap: var(--spacing-md);
  align-items: start;
}
.timeline-era__card--stacked { display: block; }
.timeline-era__photo {
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: var(--grey-200);
}
.timeline-era__photo img { width: 100%; height: 100%; object-fit: cover; }
.timeline-era__copy { padding-top: 0; }
.timeline-era__copy .eyebrow-meta { margin-bottom: var(--spacing-xs); }
.timeline-era__copy h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.timeline-era__copy h2.h2-larger {
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
}
.timeline-era__copy p {
  margin: 0;
}
.timeline-era__copy p + p { margin-top: 18px; }

/* Case-study inset inside an era card */
.case-study {
  background: var(--grey-100);
  border-radius: var(--radius-lg);
  padding: var(--spacing-lg);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-xl);
  align-items: center;
  margin-top: var(--spacing-xl);
}
.case-study h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.case-study p {
  margin: 0 0 18px;
}
/* Case-study .lite-yt inherits everything from the base .lite-yt rule.
   Add `class="play-btn play-btn--sm"` on the nested play button. */

/* Impact Stats mobile collapse — 768px per the system spec, not 900px */
@media (max-width: 767px) {
  .ccl-stats .ccl-section-inner { grid-template-columns: repeat(2, 1fr); }
  .ccl-stat-n { font-size: 64px; }
}

/* Responsive: collapse era card to single column under 900px */
@media (max-width: 900px) {
  .conference-callout,
  .partnership-block { grid-template-columns: 1fr; }
  /* .timeline horizontal padding inherits --page-gutter (24px at this width). */
  .timeline::before { left: 12px; }
  .timeline-era { grid-template-columns: 1fr; gap: var(--spacing-sm); padding-left: 32px; }
  .timeline-era__date { text-align: left; padding-right: 0; padding-left: var(--spacing-sm); }
  .timeline-era__card { grid-template-columns: 1fr; }
  .case-study { grid-template-columns: 1fr; }
  .bills-card { padding: var(--spacing-lg) var(--spacing-md) var(--spacing-lg) var(--spacing-xl); }
  .bill-row { padding: var(--spacing-sm) var(--spacing-md); }
}

/* White card — the "White card" Group style (functions.php). A white panel on
   the page: hairline border, --radius-md, the card shadow, 2xl padding (from
   the prototype's .jat-interests__inner). Any Group can carry it. */
.wp-block-group.is-style-white-card {
  background: var(--grey-0);
  border: 1px solid rgba(0, 0, 0, 0.10);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--spacing-2xl);
}
.wp-block-group.is-style-white-card > :first-child { margin-top: 0; }
.wp-block-group.is-style-white-card > :last-child { margin-bottom: 0; }
@media (max-width: 600px) {
  .wp-block-group.is-style-white-card { padding: var(--spacing-lg); }
}

/* Split panel (patterns/split-panel.php) — main copy left, a narrow aside
   right behind a hairline divider (a button + a note), stacking under 900px
   with the divider turned horizontal. The divider is the aside's border, so
   there's no empty spacer block for an editor to trip over. Two classes deep
   for the children: core's flow layout spaces them at one. */
.split-panel {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--spacing-2xl);
}
.split-panel > .split-panel__main,
.split-panel > .split-panel__aside { margin: 0; }
.split-panel .split-panel__main > :first-child { margin-top: 0; }
.split-panel .split-panel__main > :last-child { margin-bottom: 0; }
.split-panel__aside {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--spacing-lg);
  max-width: 320px;
  padding-left: var(--spacing-2xl);
  border-left: 1px solid rgba(0, 0, 0, 0.10);
}
.split-panel .split-panel__aside > * { margin: 0; }
/* The team list: one list that splits into two balanced columns, so adding a
   team rebalances it instead of an editor moving items between two lists. */
.split-panel__list { columns: 2; column-gap: var(--spacing-2xl); max-width: 560px; }
/* Item spacing goes below, not above: a column break drops the top margin of
   the item it lands on, so the second column started 8px higher. */
.split-panel .split-panel__list li { break-inside: avoid; margin: 0 0 var(--spacing-xs); }
@media (max-width: 900px) {
  .split-panel { grid-template-columns: minmax(0, 1fr); }
  .split-panel__aside {
    max-width: none;
    padding: var(--spacing-2xl) 0 0;
    border-left: 0;
    border-top: 1px solid rgba(0, 0, 0, 0.10);
  }
}
@media (max-width: 600px) {
  .split-panel__list { columns: 1; }
}

/* Two washes, because a page wash and a section wash want opposite endings.

   .page-wash — applied to <main> by the "Page — gradient background" template.
   It runs to the end of the content with the footer below, so it has nowhere to
   fade back to and ends on the green.

   .is-style-gradient-wash — the "Gradient wash" Group style, for a section.
   Content continues below it on white, so it has to return to white or its
   bottom edge is a seam. Stops ported from the prototype's
   .conference-hero-wash, which exists for exactly this and says so: "Fades back
   to white at the bottom so 'Choose the right event' sits cleanly on white
   below."

   Both are vertical, not the design's tilt. Off vertical, one end of the TOP
   edge reaches the first colour stop before the other, which reads as a hard
   diagonal edge under the white breadcrumb. Two places in this codebase already
   found that independently — the prototype's .conference-hero-wash (rejecting
   187.57°) and our own .state-wash (rejecting 186°) — and the template puts the
   breadcrumb directly above <main>, so it applies here too.

   Upstream's .page-wash also carries 4xl padding top and bottom, and that is
   deliberately NOT ported. Upstream's <main> holds its sections directly, so
   that padding is the only inset. Ours is gradient.html, a copy of page.html,
   which wraps post-content in a group already padded to spacing|60 (32px) —
   so the ported 64px stacked on top of it and a gradient page opened 96px down
   where a normal Page opens 32px down. The template's group owns the inset;
   this rule owns only the gradient, which is the one thing it should differ by.

   DEVIATION #10: design uses a 197° gradient, system documents 135° NW→SE. */
.page-wash {
  background: linear-gradient(180deg, #FFFFFF 12%, #E8F3F9 30%, #EBF4DC 79%);
}
.is-style-gradient-wash {
  background: linear-gradient(180deg,
    #FFFFFF 0%,
    #E8F3F9 22%,
    #EBF4DC 70%,
    #FFFFFF 88%);
  padding: var(--spacing-2xl) 0 var(--spacing-4xl);
}

.mission-block { text-align: center; padding: var(--spacing-4xl) var(--container-pad) var(--spacing-3xl); max-width: 900px; margin: 0 auto; }
.mission-block .mission-headline {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: var(--ccl-black);
  margin: 0;
}
.mission-block .mission-headline strong { font-weight: 700; }
.mission-block .mission-headline .gradient-text {
  font-weight: 700;
  background: var(--gradient-blue-green);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
/* Pin the gradient underline to the emphasized phrase itself, not the
   page. background-image on an OUTER wrapper span so it doesn't conflict
   with .gradient-text's background-clip: text. box-decoration-break: clone
   makes the marker stretch per line when the phrase wraps on narrow widths. */
.mission-block .mission-underline {
  background-image: url('/wp-content/themes/twentytwentyfive-child/assets/brand/underlines/underline-xlg.svg');
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 14px;
  padding-bottom: 0.18em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
@media (max-width: 767px) {
  .mission-block .mission-underline {
    background-size: 100% 10px;
    padding-bottom: 0.15em;
  }
}

.values-header {
  text-align: center;
  padding: var(--spacing-3xl) var(--container-pad) var(--spacing-md);
  max-width: 900px;
  margin: 0 auto;
}
.values-header h1 { margin-top: var(--spacing-sm); margin-bottom: var(--spacing-sm); }
.values-header p { margin: 0; }

.values-mosaic {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-xl);
  max-width: 1140px;
  margin: var(--spacing-3xl) auto;
  padding: 0 var(--container-pad);
  align-items: start;
}
.values-mosaic .col {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xl);
}
.value-card {
  background: #fff;
  border-radius: var(--radius-md);
  box-shadow: 0 2px 4px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04);
  padding: var(--spacing-xl);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}
.value-card .icon-circle {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--ccl-green);
  display: flex;
  align-items: center;
  justify-content: center;
}
.value-card .icon-circle img { width: 60px; height: 60px; }
.value-card h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0;
}
.value-card p {
  font-size: 20px;
  line-height: var(--spacing-xl);
  letter-spacing: -0.3px;
  margin: 0;
}

.value-photo {
  width: 100%;
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 4 / 5; /* portrait — closer to the Figma orientation */
  box-shadow: 0 2px 4px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04);
}
.value-photo img { width: 100%; height: 100%; object-fit: cover; }

/* Cutout PNG — transparent-background portraits floating in the wash.
   No frame, no shadow, no aspect-ratio crop. Let the PNG be itself.
   Negative margin-bottom cancels the column's flex gap so the cutout
   sits flush against (or "stands on") the card below it. */
.value-cutout {
  display: block;
  width: 100%;
  margin-bottom: calc(var(--spacing-xl) * -1);
}
.value-cutout img { display: block; width: 100%; height: auto; }

/* Floating glyph icons — small decorative pops in negative space,
   not column-width hero blocks. */
.value-glyph {
  display: flex;
  justify-content: center;
  padding: var(--spacing-md) 0;
}
.value-glyph img {
  width: 250px;
  height: auto;
  opacity: 0.95;
}

/* Mission-in-action blog row (post-wash) */
.action-blogs {
  background: #fff;
  padding: var(--spacing-5xl) var(--page-gutter);
}
.action-blogs h2 {
  text-align: center;
  margin: 0 0 var(--spacing-2xl);
}
.action-blogs .grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-xl);
  max-width: 1166px;
  margin: 0 auto;
}

/* ==========================================================================
   PAGE 3 — Our Team
   ========================================================================== */

.team-header {
  text-align: center;
  padding: var(--spacing-3xl) var(--container-pad);
  max-width: 1200px;
  margin: 0 auto;
}
.team-header .display { margin-bottom: var(--spacing-md); }

.team-panel {
  background: var(--grey-100);
  /* Grey surface: a nested subdued card flips to white so it doesn't dissolve
     into the panel. */
  --quote-card-bg: #fff;
  border-radius: var(--radius-md);
  max-width: 1246px;
  margin: var(--spacing-md) auto var(--spacing-5xl);
  padding: var(--spacing-md) var(--spacing-3xl) var(--spacing-4xl);
}
.team-tabs {
  display: flex;
  gap: var(--spacing-3xl);
  border-bottom: 1px solid var(--grey-300);
  padding-bottom: var(--spacing-md);
  margin-bottom: var(--spacing-xl);
}
.team-tabs button {
  background: transparent;
  outline: none;
  border: 0;
  border-bottom: 3px solid transparent;
  padding: 0 0 var(--spacing-md);
  margin-bottom: -17px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: rgba(0,0,0,0.9);
  cursor: pointer;
}
.team-tabs button[aria-selected="true"] {
  font-weight: 600;
  border-image: var(--gradient-underline) 1;
}
.team-tabs button:focus-visible {
  outline: 2px solid var(--ccl-blue);
  outline-offset: 4px;
  border-radius: 2px;
}

/* Each tab panel has the same H2 (department name) — Ubuntu Semi-Bold H1. */
.team-panel [role="tabpanel"][hidden] { display: none; }
.team-panel [role="tabpanel"] > h2 { margin-bottom: var(--spacing-xl); }
.team-panel .panel-intro {
  font-family: var(--font-body);
  font-size: 19px;
  letter-spacing: -0.285px;
  line-height: 1.5;
  color: var(--fg2);
  margin: 0 0 var(--spacing-2xl);
  max-width: 1156px;
}
.team-panel h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: var(--ccl-black);
  margin: var(--spacing-md) 0 var(--spacing-xl);
}

.leadership-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--spacing-xl) var(--spacing-3xl);
}
/* min-width: 0 — grid items default to min-width:auto and won't shrink below
   their min-content, so a size-less/broken photo blows the tile's 1fr column out
   and squeezes the rest. This releases that floor so the columns stay even
   (overflow:hidden on .leader__photo clips the rest). */
.leader { display: flex; flex-direction: column; gap: var(--spacing-sm); min-width: 0; }
.leader__photo {
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--grey-200);
}
.leader__photo img { 
  width: 100%; 
  height: 100%; 
  object-fit: cover; 
}

/* Specificity-bumped (.ccl .leader__*) so they beat the .ccl h3 / .ccl p
   defaults from tokens.css — otherwise the heading/paragraph default
   bottom margins compound on top of the flex gap above. */
.ccl .leader__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h5);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0;
}
.ccl .leader__title {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  font-size: var(--text-md);
  line-height: 1.4;
  color: var(--grey-500);
  margin: 0;
}
.leader__link {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.285px;
  color: var(--ccl-navy);
  text-decoration: underline;
}
.leader__link::after {
    content: ' →';
}
/* Governing Board uses the same 4-col leadership grid; staff uses 5-col. */
.dept-group { margin-bottom: var(--spacing-2xl); }
/* Direct child only — otherwise this bleeds into the <h3 class="leader__name">
   h3s inside cards and renders them at H2 size (32px). */
.dept-group > h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-lg);
}
.staff-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--spacing-xl) var(--spacing-3xl);
}
/* Staff cards stay slightly smaller than leadership/board (denser 5-col
   layout). Title size now matches the universal .leader__title (20/28),
   so no title override needed here. */
.ccl .staff-grid .leader__name { font-size: 20px; line-height: 28px; }
.board-subgroup + .board-subgroup { margin-top: var(--spacing-3xl); }

/* Initials avatar — fallback for cards without a real headshot.
   Uses the documented --avatar-initials-1..6 palette from tokens.css. */
.leader__photo[data-initials] {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 48px;
  color: #fff;
  letter-spacing: 0.02em;
}
.leader__photo[data-initials]::before { content: attr(data-initials); }
.leader__photo[data-color="1"] { background: var(--avatar-initials-1); }
.leader__photo[data-color="2"] { background: var(--avatar-initials-2); }
.leader__photo[data-color="3"] { background: var(--avatar-initials-3); }
.leader__photo[data-color="4"] { background: var(--avatar-initials-4); }
.leader__photo[data-color="5"] { background: var(--avatar-initials-5); }
.leader__photo[data-color="6"] { background: var(--avatar-initials-6); }

/* Volunteers panel — text-left, photo-right split */
.volunteers-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-3xl);
  align-items: start;
}
.volunteers-split .copy p {
  margin: 0 0 18px;
}
.volunteers-split .copy p:first-child strong { font-family: var(--font-body); font-weight: 700; }
.volunteers-split .copy .dei-link { margin-bottom: var(--spacing-lg); }
.volunteers-split .copy .dei-link a { color: var(--ccl-navy); font-weight: 700; text-decoration: underline; }
.volunteers-split .photo {
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 3 / 2;
}
.volunteers-split .photo img { width: 100%; height: 100%; object-fit: cover; }

/* Founder's Story */
.founder {
  max-width: 815px;
  margin: 0 auto;
  padding: var(--spacing-5xl) var(--container-pad);
}
.founder header { text-align: center; margin-bottom: var(--spacing-2xl); }
.founder header .name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 20px;
  line-height: 28px;
  color: var(--ccl-black);
}
.founder header .dates {
  font-family: var(--font-body);
  font-size: 19px;
  letter-spacing: -0.285px;
  color: var(--fg2);
}
.founder header h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  margin: 0 0 var(--spacing-md);
  color: var(--ccl-black);
}
.founder p {
  margin: 0 0 18px;
}

.founder-video {
  margin: var(--spacing-2xl) 0;
  box-shadow: var(--shadow-card);
}

.cavalry-callout {
  background: var(--grey-100);
  padding: var(--spacing-xl) var(--spacing-3xl);
  margin: var(--spacing-2xl) 0;
  position: relative;
}

/* When the founder narrative sits inside a tabpanel, reset its standalone
   padding (the panel already has padding) and flip the cavalry callout to
   white so it stays distinguishable on the panel's grey-100 background. */
.team-panel .founder {
  padding-top: var(--spacing-md);
  padding-bottom: 0;
}
.team-panel .cavalry-callout {
  background: #fff;
  border: 1px solid var(--grey-200);
}
.cavalry-callout p {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  margin: 0;
  max-width: 691px;
}
.cavalry-callout .underline {
  display: block;
  margin-top: var(--spacing-sm);
  width: 215px;
}

/* In-text gradient text */
.gradient-text {
  background: var(--gradient-blue-green);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* --------------------------------------------------------------------------
   Responsive — reflow heavy layouts under 900px.
   Detailed mobile per-tier rules from Hero System.md are not implemented
   in this first pass (noted in DEVIATIONS.md #11).
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .hero-t1,
  .team-cards,
  .mobilized,
  .pillar-row,
  .leadership-grid,
  .staff-grid,
  .volunteers-split,
  .stories-featured,
  .subscribe-banner,
  .action-blogs .grid { grid-template-columns: 1fr; }
  .stories-featured__right { grid-template-rows: auto auto; }
  .topic-tabs { flex-wrap: wrap; gap: var(--spacing-sm); }
  .topic-tabs .sep { display: none; }
  .topic-tabs a { font-size: 18px; padding: var(--spacing-xs) var(--spacing-sm); }
  .blog-search { flex-direction: column; align-items: stretch; padding: 0 var(--spacing-lg); }
  .blog-search input { width: 100%; }
  .post-row { grid-template-columns: 1fr; }
  .subscribe-banner__form { flex-direction: column; align-items: stretch; }
  /* flex: none — the desktop `flex: 1` (= 1 1 0%) is a WIDTH share in the row;
     once the form stacks, the same 0% basis applies to HEIGHT and overrides
     height: 44px, collapsing the field to one text line (~20px). */
  .subscribe-banner__form input { flex: none; max-width: none; width: 100%; }
  .team-tabs { gap: var(--spacing-md); flex-wrap: wrap; }
  /* T1 on a phone (the task-hero half of "Mobile heroes" above): text stacks
     above the media (source order), at the mockup's tighter rhythm (40px in
     place of the desktop's 80px padding and gap). The blue offset drops to a
     12px accent peeking out bottom-right: the desktop's 28px up-and-right slab
     ran into the gutter and the text above it. */
  .hero-t1 {
    gap: var(--spacing-2xl);
    padding: var(--spacing-2xl) var(--page-gutter) var(--spacing-3xl);
  }
  .hero-t1__media::before { inset: 12px -12px -12px 12px; }
  /* Horizontal padding on site-header, section-nav, site-footer comes from
     --page-gutter now (tokens.css drops it to --spacing-lg below 900px);
     only layout-shape overrides stay here. */
  .site-header nav { display: none; }
  /* Section nav on mobile: a single-line horizontal scroll strip with edge
     fades, replacing the stacked two-line wrap this used to be. Ported whole
     from the prototype (upstream) — base row, strip, pills, both fades and
     their state classes.

     The .section-title is dropped on purpose: the row has to fit one line, and
     the <nav aria-label="…"> on the element still names the landmark for
     screen readers, so nothing is lost non-visually.

     Both fades start at opacity 0 and are switched on by .is-fade-start /
     .is-fade-end, which assets/js/section-nav.js toggles from scroll position.
     That means the left fade only shows once you've scrolled away from the
     start, the right fade hides when you reach the end, and with JS disabled
     you get a plain scroll strip rather than two gradients painted over
     stationary content.

     The strip runs edge to edge and carries the page gutter as its OWN inline
     padding, rather than sitting inside the nav's. That's load-bearing for the
     fades: with the nav keeping its 24px padding, content clipped 24px inside
     the element while the 28px fade sat at right:0 — so the gradient's opaque
     end covered blank gutter and only its ~14%-opacity tail reached any text.
     The fade was there and did nothing. Pills now clip at the true edge, under
     the fade, and the gutter still sets where the first and last pill land
     because a scroll container's inline padding is part of its scrollable
     width. */
  .section-nav { padding-block: var(--spacing-sm); padding-inline: 0; flex-direction: row; align-items: center; gap: 0; }
  .section-nav .section-title { display: none; }
  .section-nav .links {
    /* min-width: 0 is required — without it this flex item refuses to shrink
       below its content width and never becomes a scroll container at all. */
    flex: 1 1 auto; min-width: 0;
    flex-wrap: nowrap; overflow-x: auto; gap: var(--spacing-xs);
    padding-inline: var(--page-gutter);
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
  .section-nav .links::-webkit-scrollbar { display: none; }
  .section-nav .links a { flex: 0 0 auto; white-space: nowrap; }
  .section-nav::before, .section-nav::after {
    content: ""; position: absolute; top: 0; bottom: 0; width: 28px;
    pointer-events: none; opacity: 0; transition: opacity .15s ease; z-index: 1;
  }
  .section-nav::before { left: 0;  background: linear-gradient(to right, var(--bg-page), transparent); }
  .section-nav::after  { right: 0; background: linear-gradient(to left,  var(--bg-page), transparent); }
  .section-nav.is-fade-start::before { opacity: 1; }
  .section-nav.is-fade-end::after    { opacity: 1; }
  .site-footer__cols { grid-template-columns: 1fr; gap: var(--spacing-xl); padding-block: var(--spacing-3xl); }
  .site-footer__legal { justify-content: flex-start; }
  .site-footer__badges { gap: var(--spacing-sm); }
  .site-footer__badges img { height: 76px; width: auto; }

  /* Values mosaic — narrow widths
     - Collapse from 3-col grid to 1-col flow
     - Tighten the inter-item gap (it was 32px which made the stack huge)
     - Hide the standalone decorative glyph icons — they're atmospheric
       punctuation that doesn't add value when everything's in one column
     - Constrain photo/cutout max-width so they don't dominate the viewport
     - Recompute the cutout's negative margin to match the narrower gap */
  .values-mosaic {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 0 var(--spacing-lg);
  }
  .values-mosaic .col { gap: var(--spacing-lg); }
  .values-mosaic .col + .col { margin-top: var(--spacing-lg); }
  .values-mosaic .value-glyph { display: none; }
  .values-mosaic .value-photo,
  .values-mosaic .value-cutout {
    max-width: 420px;
    margin-left: auto;
    margin-right: auto;
  }
  .values-mosaic .value-cutout { margin-bottom: calc(var(--spacing-lg) * -1); }
  /* The live page builds the mosaic from a core Columns block set NOT to stack
     on mobile, so the grid/.col rules above never reach it and it stayed three
     squeezed columns, breaking words mid-syllable. Stack the core markup too.
     .is-layout-flex (a class core always prints there) lifts these over core's
     `.wp-block-columns.is-not-stacked-on-mobile` rules, which load later. */
  .values-mosaic.wp-block-columns.is-layout-flex { flex-direction: column; gap: var(--spacing-lg); padding-inline: 0; }
  .values-mosaic.wp-block-columns.is-layout-flex > .wp-block-column { flex-basis: auto; width: 100%; }

  /* Breadcrumb — drop the desktop 4xl horizontal padding */
  .breadcrumb { padding-left: var(--spacing-lg); padding-right: var(--spacing-lg); flex-wrap: wrap; }

  /* Mission/values page chrome — tighten vertical rhythm at narrow widths;
     horizontal padding comes from --page-gutter via the base rules. */
  .mission-block { padding-block: var(--spacing-3xl) var(--spacing-xl); }
  .values-header { padding-block: var(--spacing-xl) var(--spacing-md); }
  .action-blogs { padding-block: var(--spacing-3xl); }
}

/* ==========================================================================
   OUR APPROACH — Theory of Change, Policy Commitments, Quiz CTA, Strategic
   Plan download. Built from Figma 1781:4907. The page mostly reuses
   established primitives (hero-t1, section-header, eyebrow-blue,
   divider-thick, btn-primary) — these rules cover only the new patterns.
   ========================================================================== */

/* ---- Volunteer activity grid (5 expandable lever cards) -------------------
   Flexbox wrap so 3 cards land in row 1 and the remaining 2 center in row 2
   without leaving an awkward empty grid slot. Each card is an article
   toggled by JS; the icon/title/lead/cta sit in the body; the longer body
   reveals below. */
.activity-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--spacing-xl);
  max-width: 1100px;
  margin: var(--spacing-xl) auto var(--spacing-5xl);
  padding: 0 var(--container-pad);
  align-items: flex-start;
}
.activity-card {
  flex: 1 1 280px;
  max-width: 340px;
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
.activity-card.is-expanded {
  border-color: var(--ccl-blue);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
}

.activity-card__image {
  width: 100%;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--grey-200);
}
.activity-card__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.activity-card__body {
  padding: var(--spacing-lg) var(--spacing-xl) var(--spacing-xl);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  text-align: left;
}

/* Divider between body and the "more" text when expanded */
.activity-card.is-expanded .activity-card__body {
  border-bottom: 1px solid var(--grey-200);
}

.activity-card__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  color: var(--ccl-black);
  margin: 0;
}
.activity-card__lead {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.45;
  letter-spacing: -0.285px;
  color: var(--fg2);
  margin: 0;
}

/* "Read more" / "Show less" CTA at the bottom of the card body */
.activity-card__cta {
  margin-top: var(--spacing-xs);
  color: var(--ccl-navy);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 19px;
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
}
.activity-card__cta-close { display: none; }
.activity-card.is-expanded .activity-card__cta-open { display: none; }
.activity-card.is-expanded .activity-card__cta-close { display: inline; }

.activity-card__chevron {
  width: 10px;
  height: 10px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  margin-top: -3px;
  transition: transform .2s ease;
}
.activity-card.is-expanded .activity-card__chevron {
  transform: rotate(-135deg);
  margin-top: 3px;
}

/* The "more" text — hidden by default, revealed when expanded */
.activity-card__more {
  display: none;
  margin: 0;
  padding: var(--spacing-lg) var(--spacing-xl) var(--spacing-xl);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  color: var(--grey-600);
  text-align: left;
}
.activity-card.is-expanded .activity-card__more {
  display: block;
}

/* ---- Policy Commitments — accordion list + side photo --------------------- */
.commitments-layout {
  display: grid;
  grid-template-columns: 1fr 329px;
  gap: var(--spacing-3xl);
  align-items: start;
  max-width: 1204px;
  margin: var(--spacing-xl) auto var(--spacing-5xl);
  padding: 0 var(--page-gutter);
}
.commitments-list {
  display: flex;
  flex-direction: column;
  width: 100%;
}
.commitment {
  border-bottom: 1px solid var(--grey-200);
}
.commitment summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--spacing-lg);
  padding: var(--spacing-lg) 0;
  /* Subtle interactive treatment without losing the flat row look. */
  transition: color .12s ease;
}
.commitment summary::-webkit-details-marker { display: none; }
.commitment summary::marker { content: ''; }
.commitment summary:hover .commitment__title { color: var(--ccl-blue); }
.commitment__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  flex-shrink: 0;
}
.commitment__icon img {
  width: 48px;
  height: 48px;
  object-fit: contain;
}
/* Boxed colour treatment retired per design call — icons render at their
   natural fill against the white row. .commitment__icon--blue/--green/--brown
   classes left in markup as hooks in case a colour tint comes back. */
.commitment__title {
  flex: 1;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
}
.commitment__chevron {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  /* CSS-only chevron — two diagonal lines drawn with borders */
  border-right: 2px solid var(--grey-600);
  border-bottom: 2px solid var(--grey-600);
  transform: rotate(45deg);
  transform-origin: center;
  margin-top: -6px;
  transition: transform 0.2s ease;
}
.commitment[open] .commitment__chevron {
  transform: rotate(-135deg);
  margin-top: 4px;
}
.commitment__body {
  padding: 0 0 var(--spacing-xl);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
}
.commitment__body > p {
  margin: 0;
}

.commitments-photo {
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin: 0;
  aspect-ratio: 329 / 513;
  position: sticky;
  top: var(--spacing-xl);
}
.commitments-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ---- v2 commitments — open stacked rows (no accordion) -------------------
   Used on our-approach-v2.html. Three rows stacked top-to-bottom, each with
   the lever icon on the left and title + body on the right. Research Says
   quotes live in the .research-carousel below instead of inline. */
.commitments-stacked {
  max-width: 1166px;
  margin: var(--spacing-xl) auto var(--spacing-5xl);
  padding: 0 var(--page-gutter);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-3xl);
}
.commitment-row {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: var(--spacing-xl);
  align-items: start;
}
.commitment-row__icon {
  width: 80px;
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.commitment-row__icon img {
  width: 64px;
  height: 64px;
  object-fit: contain;
}
.commitment-row__content h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
}
.commitment-row__content p {
  margin: 0;
}

@media (max-width: 600px) {
  .commitment-row {
    grid-template-columns: 56px 1fr;
    gap: var(--spacing-md);
  }
  .commitment-row__icon { width: 56px; height: 56px; }
  .commitment-row__icon img { width: 48px; height: 48px; }
}

/* ---- v3 commitments — manifesto layout (numbered, side-by-side) ----------
   Used on our-approach-v3.html. Two-column grid per row: LEFT is the
   "Goal NN" eyebrow + icon-and-title pair, RIGHT is the body paragraph.
   Thin grey-200 divider above each row + below the last one. Reads as a
   declarative manifesto rather than the activity-card / lever pattern. */
.commitments-manifesto {
  max-width: 1166px;
  margin: var(--spacing-xl) auto 0;
  padding: 0 var(--page-gutter);
  display: flex;
  flex-direction: column;
}
/* When the Research Says section-header follows the manifesto rows
   directly, tighten its top padding so the carousel reads as part of
   the same Policy Commitments moment instead of a separate section. */
.commitments-manifesto + .section-header {
  padding-top: var(--spacing-lg);
}
.commitment-manifesto {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-3xl);
  align-items: start;
  padding: var(--spacing-3xl) 0;
  border-top: 1px solid var(--grey-200);
}
.commitment-manifesto:last-child {
  border-bottom: 1px solid var(--grey-200);
}
.commitment-manifesto__heading {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}
.commitment-manifesto__eyebrow {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--fs-tiny);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ccl-blue);
  margin: 0;
}
.commitment-manifesto__title-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
}
.commitment-manifesto__icon {
  width: 64px;
  height: 64px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.commitment-manifesto__icon img {
  width: 56px;
  height: 56px;
  object-fit: contain;
}
.commitment-manifesto__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0;
}
.commitment-manifesto__body p {
  margin: 0;
}

@media (max-width: 900px) {
  .commitment-manifesto {
    grid-template-columns: 1fr;
    gap: var(--spacing-lg);
    padding: var(--spacing-2xl) 0;
  }
}

/* ---- v3 next-steps — side-by-side Quiz + Strategic Plan ------------------
   Replaces the original two stacked sections (.quiz-cta + .strategic-plan)
   with a two-up card grid. Equal-weight cards, each with its own visual
   anchor (photo / cover), eyebrow differentiates path (green = volunteer
   onboarding / blue = strategy depth). Green wash dropped — green lives on
   the active CTA button only. Buttons asymmetric (primary green / tertiary
   outlined) so the quiz reads as the preferred next step. */
.next-steps {
  background: #fff;
  padding: var(--spacing-5xl) var(--page-gutter);
}
.next-steps__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-2xl);
  max-width: 1166px;
  margin: 0 auto;
  align-items: stretch;
}
.next-step-card {
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}
.next-step-card__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--grey-100);
}
.next-step-card__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Strategic-plan cover is portrait — fits a landscape slot badly with
   object-fit: cover (Capitol photo gets clipped off). Treat the cover
   as a PDF preview floating on a navy frame: contain instead of cover,
   ccl-blue-dark backdrop that matches the cover's own navy title bar
   so the two meet seamlessly, soft drop-shadow to lift the cover off
   the frame. Reads as "downloadable plan thumbnail," not "awkward crop". */
.next-step-card--plan .next-step-card__image {
  background: var(--ccl-blue-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-lg);
}
.next-step-card--plan .next-step-card__image img {
  width: auto;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  border-radius: var(--radius-xs);
}
.next-step-card__body {
  padding: var(--spacing-xl);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  flex: 1;
}
.next-step-card__body h2 {
  margin: 0;
}
.next-step-card__body > p {
  margin: 0;
  flex: 1;
}
.next-step-card__body .btn {
  align-self: flex-start;
}
/* The canonical .eyebrow-* utilities carry their own 12px margin-bottom
   for block-level use elsewhere on the site. Inside this card the 16px
   flex gap already governs spacing — stacking the margin on top pulls
   the title visually toward the body paragraph instead of the eyebrow
   above it. Zero the eyebrow's own margin here so every child of __body
   sits on a uniform 16px rhythm. */
.next-step-card__body .eyebrow-blue,
.next-step-card__body .eyebrow-green {
  margin-bottom: 0;
}

@media (max-width: 900px) {
  .next-steps__grid { grid-template-columns: 1fr; }
  .next-step-card__image { aspect-ratio: 16 / 10; }
}

/* ---- v1 bottom CTAs — split quiz hero + slim "go deeper" banner -----------
   Used on our-approach.html. Replaces the gradient-backdrop quiz card and
   the grey-100 strategic plan panel with two distinct moments: a big
   full-width split-card hero for the quiz (photo left, content right) and
   a thin "Go Deeper" banner for the strategic plan download (small cover
   thumb + title + outlined PDF button). No green wash on the quiz card. */
.quiz-hero {
  max-width: 1166px;
  margin: var(--spacing-5xl) auto var(--spacing-xl);
  padding: 0 var(--page-gutter);
}
.quiz-hero__inner {
  max-height: 442px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #fff;
  align-items: stretch;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
}
.quiz-hero__photo {
  max-height: 440px;
  width: 100%;
  overflow: hidden;
}
.quiz-hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.quiz-hero__body {
  padding: var(--spacing-3xl);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  justify-content: center;
  margin-top: 0;
}
.quiz-hero__body .eyebrow-green { margin-bottom: 0; }
.quiz-hero__body h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: var(--ccl-black);
  margin: 0;
}
.quiz-hero__body > p {
  margin: 0;
}
.quiz-hero__body .btn {
  align-self: flex-start;
  margin-top: var(--spacing-sm);
}
.quiz-hero__body > .eyebrow-green,
.quiz-hero__body > p.eyebrow-green {
    color: var(--ccl-green-dark);
    letter-spacing: 0.18em;
}
.quiz-go-band {
  background: var(--grey-100);
  padding: var(--spacing-5xl) 0;
}

/* "Go Deeper" thin banner — cover thumb + title + outlined PDF button. */
.go-deeper {
  max-width: 1166px;
  margin: 0 auto var(--spacing-5xl);
  padding: 0 var(--page-gutter);
}
.go-deeper__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--spacing-xl);
  align-items: center;
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  padding: var(--spacing-xl);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.03);
}
.go-deeper__cover {
  width: 100px;
  margin: 0;
}
.go-deeper__cover img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--radius-xs);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
.go-deeper__body {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xs);
}
.go-deeper__body .eyebrow-blue { margin-bottom: var(--spacing-2xs); }
.go-deeper__body h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0;
}
.go-deeper__body > p {
  font-size: 16px;
  line-height: 1.45;
  margin: 0;
}
.go-deeper__body > .eyebrow-green,
.go-deeper__body > p.eyebrow-green {
    color: var(--ccl-green-dark);
    letter-spacing: 0.18em;
}

@media (max-width: 900px) {
  .quiz-hero__inner { grid-template-columns: 1fr; }
  .quiz-hero__photo { min-height: 260px; }
  .quiz-hero__body { padding: var(--spacing-2xl); }
  .go-deeper__inner {
    grid-template-columns: 1fr;
    text-align: center;
    gap: var(--spacing-md);
    padding: var(--spacing-2xl);
  }
  .go-deeper__cover { margin: 0 auto; }
  .go-deeper__inner .btn { justify-self: center; }
}

/* ---- Pre-footer Join CTA ------------------------------------------------
   Sits between the last content section and the site footer on every page.
   Dark-blue gradient backdrop (the "navy + green" pairing we agreed on);
   big white headline, supporting line and primary green button, stacked and
   centred. Reusable component — same markup on every page so copy + link can
   be swapped once if anything ever needs to change.

   Diverges from the prototype on purpose (2026-10-30). The prototype puts the
   copy on the left and the button on the right of the 1166px row, but caps
   the copy at 600px, so on any desktop the button sat alone at the far edge
   with ~400px of empty band between them. Stacked, the three read as one
   ask at every width, and desktop now matches the phone layout. */
.join-cta {
  background: var(--gradient-dark-blue);
  padding: var(--spacing-5xl) var(--page-gutter);
  color: #fff;
}
/* Full-width band sits flush — no top/bottom margin (overrides block-gap). Two
   classes so it wins over the layout's block-gap rule regardless of load order. */
.wp-block-group.join-cta { margin-block: 0; }

/* When a FULL-WIDTH block is the last content block, butt it flush against the
   footer by
   dropping the page wrapper's bottom padding (set inline in page.html, hence the
   !important). :has() scopes this to a wrapper that actually ends in a band, so
   it's a no-op — never an overlap — on any page that doesn't.

   Two selectors because a band can sit one level in. A whole-page pattern
   wraps its sections in a container (.at-page is the one that does), and then
   the band is the last child of THAT, not of .wp-block-post-content. Matching
   only the direct child left those pages with a stripe of white below the
   band: 32px of wrapper padding plus the footer's 24px root block gap.

   Keyed on .alignfull rather than .join-cta. It began as a rule for the Join
   CTA, but the two things it cancels are not that band's -- they are the page
   wrapper's padding and the footer's block gap, neither of which is reachable
   from the editor. So ANY full-bleed block arriving last hit the same 56px of
   white and had no way to clear it: setting the block's own margins to 0 does
   nothing, because neither source is a margin on the block.

   To put a gap back on one page, give that last block its own bottom margin in
   Dimensions. WordPress writes that inline, so it beats both rules here -- and
   the spacing becomes a value someone can see and change, rather than 56px
   arriving from a template two levels up. */
.wp-block-group.alignfull:has(> .wp-block-post-content > .alignfull:last-child),
.wp-block-group.alignfull:has(> .wp-block-post-content > :last-child > .alignfull:last-child) {
  padding-bottom: 0 !important;
}
/* ...and the footer, as a top-level child of .wp-site-blocks, otherwise gets a
   root block-gap (margin-block-start: spacing-50). Zero it only when a band
   comes right before it, so the band reaches the footer while other pages keep
   the gap. Two ways a band gets there: as the last block of a page's content
   (inside <main>), or placed by the template itself after <main>, as
   archive.html does. */
main:has(.wp-block-post-content > .alignfull:last-child) ~ .wp-block-template-part,
main:has(.wp-block-post-content > :last-child > .alignfull:last-child) ~ .wp-block-template-part,
.alignfull + .wp-block-template-part {
  margin-block-start: 0;
}
.join-cta__inner {
  max-width: 1166px;
  margin: 0 auto;
  display: grid;
  justify-items: center;
  text-align: center;
  gap: var(--spacing-xl);
}
.join-cta__copy h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: #fff;
  margin: 0 auto var(--spacing-md);
  max-width: 800px;
}
.join-cta__copy p {
  color: #fff;
  margin: 0 auto;
  max-width: 560px;
  opacity: 0.92;
}
/* The inner group is a flow layout, so core gives the Buttons block the
   block-gap as a top margin. Inside the grid that stacked on top of the gap
   (and, back when the button sat beside the copy, dropped it 12px below
   centre). The grid gap is the only space it needs. Buttons is a flex row, so
   centring it takes justify-content, not the grid's justify-items. */
.join-cta__inner > .wp-block-buttons {
  margin-block-start: 0;
  justify-content: center;
}

@media (max-width: 900px) {
  .join-cta { padding-block: var(--spacing-4xl); }
  .join-cta__inner { gap: var(--spacing-lg); }
}

/* ---- Quiz CTA — full-bleed gradient backdrop + centered white card -------- */
.quiz-cta {
  background: var(--gradient-blue-green);
  padding: var(--spacing-5xl) var(--page-gutter);
  text-align: center;
}
.quiz-cta__card {
  background: #fff;
  border-radius: var(--radius-md);
  padding: var(--spacing-3xl) var(--spacing-3xl) var(--spacing-3xl);
  max-width: 700px;
  margin: 0 auto;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.10);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-md);
}
.quiz-cta__card h2 {
  margin: 0;
}
.quiz-cta__card > p {
  line-height: 1.45;
  margin: 0;
  max-width: 520px;
}
.quiz-cta__card .btn {
  margin-top: var(--spacing-sm);
}

/* ---- Strategic Plan download — grey-100 panel with cover image + form ----- */
.strategic-plan {
  background: #fff;
  padding: var(--spacing-5xl) var(--page-gutter);
}
.strategic-plan__inner {
  background: var(--grey-100);
  border-radius: var(--radius-md);
  display: grid;
  grid-template-columns: 382px 1fr;
  gap: var(--spacing-2xl);
  align-items: center;
  max-width: 1091px;
  margin: 0 auto;
  padding: var(--spacing-3xl);
}
.strategic-plan__cover {
  position: relative;
  aspect-ratio: 382 / 496;
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin: 0;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25);
}
.strategic-plan__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.strategic-plan__body {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  align-items: flex-start;
}
.strategic-plan__body h2 {
  margin: 0;
}
.strategic-plan__body > p {
  line-height: 1.45;
  margin: 0;
}
.strategic-plan__body .btn {
  margin-top: var(--spacing-sm);
}

/* --------------------------------------------------------------------------
   Hover-underline cleanup
   tokens.css ships a "subtle underline on hover" pattern via a transparent
   border-bottom that turns blue on `a:hover`. Any link that ALSO has
   text-decoration: underline as its default state ends up rendering TWO
   underlines (text-decoration line + border-bottom line) when hovered.
   For every such link, suppress the border-bottom on hover so only the
   text-decoration underline remains.
   -------------------------------------------------------------------------- */
.leader__link:hover,
.info-pill a:hover,
.topic-tabs a.active:hover,
.volunteers-split .copy .dei-link a:hover {
  border-bottom-color: transparent;
}

/* ==========================================================================
   JOIN SUMMARY — two-up Chapters / Action Teams choice cards, Power of
   Group Action video, More Stories CTA. Built from Figma 1475:13921.
   ========================================================================== */

/* ---- Two-up "Chapters" / "Action teams" choice cards ---------------------- */
.join-choices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-4xl);
  max-width: 1166px;
  margin: var(--spacing-xl) auto var(--spacing-5xl);
  padding: 0 var(--page-gutter);
  align-items: stretch;
}
.join-choice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--spacing-md);
}
.join-choice__photo {
  width: 100%;
  aspect-ratio: 556 / 270;
  border-radius: var(--radius-md);
  overflow: hidden;
  margin: 0;
}
.join-choice__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.join-choice h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: var(--spacing-sm) 0 0;
}
.join-choice p {
  line-height: 1.45;
  margin: 0;
}
/* Push the button to the bottom so both cards' CTAs line up even when
   the bodies differ in length. */
.join-choice .btn {
  margin-top: auto;
}

/* ---- Power of Group Action video — centered lite-yt embed ----------------- */
.group-action-video {
  max-width: 556px;
}
.group-action-video .lite-yt {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* ---- "More Stories" button under the action-blogs grid -------------------- */
.action-blogs__cta {
  display: flex;
  justify-content: center;
  margin-top: var(--spacing-2xl);
}

@media (max-width: 900px) {
  .join-choices {
    grid-template-columns: 1fr;
    gap: var(--spacing-2xl);
  }
  .join-choice__photo { aspect-ratio: 16 / 9; }
}

/* ---- Responsive collapse — match the 900px breakpoint elsewhere ----------- */
@media (max-width: 900px) {
  .activity-grid { grid-template-columns: repeat(2, 1fr); }
  .commitments-layout { grid-template-columns: 1fr; }
  .commitments-photo {
    max-width: 500px;
    margin: 0 auto;
    position: static;
    aspect-ratio: 4 / 3;
  }
  .strategic-plan__inner {
    grid-template-columns: 1fr;
    padding: var(--spacing-2xl);
  }
  .strategic-plan__cover { max-width: 320px; margin: 0 auto; }
  .quiz-cta__card { padding: var(--spacing-2xl); }
}
@media (max-width: 600px) {
  .activity-grid { grid-template-columns: 1fr; }
}

/*----------TEAM PROFILE - photo + bio, used on about/team--------------*/
.team-profile {
  max-width: 1166px;
  margin: var(--spacing-xl) auto var(--spacing-5xl);
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: var(--spacing-5xl);
  padding: var(--spacing-5xl) var(--page-gutter);
  align-items: start;
}

.team-profile__photo {
  border-radius: var(--radius-md);
  margin: 0;
}
.team-profile__image_container {
  border-radius: var(--radius-md);
  overflow: hidden;
  margin: 0;
}

.team-profile__image_container img {
  aspect-ratio: 3 / 4;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.team-profile__bio {
  display: block;
  flex-direction: column;
  gap: var(--spacing-md);
  align-items: justify-content;
}

.team-profile__button_link .wp-block-button__link,
.team-profile__button_link .wp-element-button {
  background: none;
  background-color: transparent;
  border: none;
  padding: 0;
  color: var(--ccl-blue);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 400;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}

.team-profile__button_link .wp-block-button__link:hover,
.team-profile__button_link .wp-element-button:hover {
  background: none;
  background-color: transparent;
  border: none;
  color: var(--ccl-blue-dark);
  text-decoration: underline;
}
.team-profile__role {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-md);
  line-height: var(--lh-md);
  color: var(--ccl-grey-80);
  margin: 0;
}

/* Responsive adjustment for small screens */
@media (max-width: 600px) {
  .team-profile {
    grid-template-columns: 1fr;
  }
}

.pagination__nav {
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 12px;
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--fg-link-strong);
  text-decoration: none;
  white-space: nowrap;
}

.pagination__nav.is-disabled {
  color: var(--grey-300);
  pointer-events: none;
}

.pagination__compact {
  display: none;
}

.pagination__tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 12px;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-pill);
  font-size: var(--text-md);
  color: var(--fg2);
  text-decoration: none;
  transition: border-color .12s ease, color .12s ease;
}

.pagination__tile.is-current {
  background: var(--fg-link-strong);
  border-color: var(--fg-link-strong);
  color: #fff;
  font-weight: 700;
}

.pagination__ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 40px;
  color: var(--grey-400);
  user-select: none;
}

/* The pager closes a post list, so it carries the same hairline the rows have
   between them (.post-row + .post-row) with room on both sides. The rule is
   drawn on a box inset by --container-pad — not across the padding box — so
   it lines up with the rows' rules instead of running past them into the
   gutter.

   This used to be two .pagination rules; the other came from the retired
   "Showing 10 20 50" layout (removed with its __showing/__pages rules — no
   markup uses them). Merged, they put the divider flush against the page
   tiles and wider than the list. */
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
  width: min(calc(1166px - 2 * var(--container-pad)), calc(100% - 2 * var(--container-pad)));
  margin: 0 auto var(--spacing-5xl);
  padding: var(--spacing-2xl) 0 0;
  border-top: 2px solid var(--grey-200);
  font-family: var(--font-body);
}
/* The Stories page ships an empty placeholder <nav class="pagination"> next to
   the one its script builds; empty, it would draw a stray rule. */
.pagination:empty { display: none; }
/* The rest of the prototype's pagination: tile hover, and below 480px the
   numeric tiles collapse to "← Previous · Page 1 of 12 · Next →". (The
   900px "flex-direction: column" this used to get belonged to the retired
   "Showing 10 20 50" layout, and stacked the tiles vertically on phones.) */
.pagination__tile:hover {
  border-color: var(--fg-link-strong);
  color: var(--fg-link-strong);
}
@media (max-width: 480px) {
  .pagination__tile, .pagination__ellipsis { display: none; }
  .pagination__compact {
    display: inline-flex;
    align-items: center;
    height: 40px;
    padding: 0 var(--spacing-xs);
    font-weight: 700;
    color: var(--fg2);
  }
}

/* ==========================================================================
   BLOG ARCHIVE — category / tag listings (ccl/post-archive in
   templates/archive.html). Deliberately almost nothing of its own: it is the
   Stories index's components (.stories-hero, .tabs--sm, .blog-search,
   .story-card--featured, .post-row, .subscribe-banner, .pagination,
   .stories-field) with the few additions a server-rendered, filterable list
   needs — a story count, tag chips on rows, an empty state, and the "Browse by
   topic" cards on tag pages.
   ========================================================================== */
.post-archive__hero a.eyebrow-blue { text-decoration: none; }
.post-archive__hero a.eyebrow-blue:hover { color: var(--fg-link-strong); }
.post-archive__hero .post-archive__count {
  margin-top: var(--spacing-md);
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  color: var(--grey-500);
}
.post-archive__hero > p + p { margin-top: var(--spacing-sm); }
.post-archive__tools { text-align: left; }
.post-archive__tools .blog-search { margin-top: var(--spacing-lg); }

/* Rows: the title link is stretched over the whole row, so the row stays one
   click target (as on the Stories page, where the row is an <a>) while the
   category and tag links inside it remain their own links. */
.post-archive__row { position: relative; }
.post-archive__row .post-archive__link { color: inherit; }
.post-archive__row .post-archive__link::after { content: ""; position: absolute; inset: 0; }
.post-archive__row .post-archive__link:focus-visible { outline: none; }
.post-archive__row .post-archive__link:focus-visible::after {
  outline: 2px solid var(--ccl-blue);
  outline-offset: 4px;
  border-radius: var(--radius-md);
}
.post-archive__row .category-tag,
.post-archive__tags { position: relative; z-index: 1; }
.post-archive__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.post-archive__empty {
  width: min(calc(1166px - 2 * var(--container-pad)), calc(100% - 2 * var(--container-pad)));
  margin: var(--spacing-2xl) auto var(--spacing-3xl);
  padding: var(--spacing-3xl) var(--spacing-lg);
  border: 1px dashed var(--grey-300);
  border-radius: var(--radius-md);
  text-align: center;
}
.post-archive__empty h2 {
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  font-weight: var(--fw-weak);
  margin: 0 0 var(--spacing-sm);
}
.post-archive__empty p { margin: 0 0 var(--spacing-lg); color: var(--grey-500); }

/* "Browse by topic" — one card per category, on tag pages. */
.topic-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--spacing-md);
}
.topic-cards .topic-card {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xs);
  padding: var(--spacing-md) var(--spacing-lg);
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  color: var(--ccl-black);
  text-decoration: none;
  transition: border-color .15s ease;
}
.topic-cards .topic-card:hover { border-color: var(--fg-link-strong); }
.topic-card__name {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.topic-card:hover .topic-card__name { color: var(--fg-link-strong); }
.topic-card__count { font-size: var(--fs-tiny); line-height: var(--lh-tiny); color: var(--grey-500); }

.pp-timeline {
  max-width: 1020px;
  margin: 0 auto;
  padding: var(--spacing-2xl) var(--container-pad) var(--spacing-xl);
  position: relative;
}

.pp-timeline::before {
  content: "";
  position: absolute;
  left: 19px;               /* wherever your line sits */
  top: 0;
  bottom: 0;
  width: 4px;
  background: linear-gradient(to bottom, rgb(150,192,63), rgb(17,91,138));
}

/* Fallback dot color for the editor (view.js doesn't run there) */
.pp-era {
    position: relative;
    padding: 0 0 var(--spacing-4xl) 72px;
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    gap: var(--spacing-xl);
    align-items: start;
}

.pp-era::before {
    content: '';
    position: absolute;
    left: calc(7px - var(--container-pad));
    top: 2px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #fff;
    border: 4px solid var(--pp-dot, var(--ccl-blue));
    box-shadow: 0 0 0 5px #fff;
}

/* Hidden initial state — only applied when animation is enabled */
.pp-era.pp-reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 600ms ease-out, transform 600ms ease-out;
  will-change: opacity, transform;
}

.pp-era.pp-reveal::before {
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 400ms ease-out 120ms, transform 400ms ease-out 120ms;
}

/* Revealed */
.pp-era.pp-reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.pp-era.pp-reveal.is-visible::before {
  opacity: 1;
  transform: scale(1);
}

/* Respect user OS-level preference */
@media (prefers-reduced-motion: reduce) {
  .pp-era.pp-reveal,
  .pp-era.pp-reveal::before {
      opacity: 1;
      transform: none;
      transition: none;
  }
}
/* Kill the animation when the timeline has it disabled */
.pp-timeline.pp-no-anim .pp-era.pp-reveal,
.pp-timeline.pp-no-anim .pp-era.pp-reveal::before {
  opacity: 1;
  transform: none;
  transition: none;
}
.pp-era__extra {
  grid-column: 1 / -1;
}
/* "Compact steps" style (block.json styles) — a short dated list on the same
   gradient rail, for a Take Action page's "Where things stand" beside one
   photo. One column, the h3's own tag style for the step title, and no photo per era (an era photo
   only shows if one is actually set). The date is the era's own
   .eyebrow-green (what the Timeline Era block inserts, as on Past Progress and
   Lobby Day) and the copy is the standard body paragraph. The LAST era is the highlighted "next up":
   both prototype timelines end on the ask, so it's a rule, not a style an
   editor has to move. Dots keep view.js's gradient colours. */
.pp-timeline.is-style-compact {
  max-width: none;
  margin: 0;
  padding: 0 0 0 var(--container-pad);
}
.pp-timeline.is-style-compact .pp-era {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--spacing-md);
  padding: 0 0 var(--spacing-xl) 56px;
}
.pp-timeline.is-style-compact .pp-era:last-child { padding-bottom: 0; }
.pp-timeline.is-style-compact .pp-era__photo:not(:has(img[src])) { display: none; }
.pp-timeline.is-style-compact .pp-era__copy > * { margin: 0; }
.pp-timeline.is-style-compact .pp-era__copy :is(h2, h3) { margin-bottom: var(--spacing-xs); }
.pp-timeline.is-style-compact .pp-era:last-child .pp-era__copy {
  margin: -18px 0 0 -22px;
  padding: 18px 22px 20px;
  background: var(--brand-lightest);
  border-radius: var(--radius-md);
}
.pp-era .eyebrow-green.pp-era__date {
  color: var(--pp-dot);
}
/* Mobile: stack everything in one column */
@media (max-width: 768px) {
  .pp-era {
    grid-template-columns: 1fr;
    gap: var(--spacing-lg);
    padding-left: 48px;  /* less room for the timeline line/dot */
  }

  /* Pull the dot closer to the edge on mobile */
  .pp-era::before {
    left: calc(0px - var(--container-pad));
  }

  /* Timeline line follows */
  .pp-timeline::before {
    left: 10px;
  }

  /* Images shouldn't overflow their new narrower container */
  .pp-era__photo img {
    width: 100%;
    height: auto;
  }
}
/* ==========================================================================
   State finder (acf/ccl-state-finder) — tinted panel, picker column beside the
   volunteer map. Ported from the prototype's .hm-statefinder.

   WP adaptations:
   - The prototype's outer max-width/--gutter wrapper is dropped. Width comes
     from the block's align class + theme.json content/wide sizes, like every
     other block here; --frame-max/--gutter don't exist in the theme's tokens.
   - .visually-hidden is added below because the theme had no hidden-label
     utility yet (the select's label needs one).
   ========================================================================== */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.hm-statefinder { margin: 0 auto var(--spacing-5xl); }
.hm-statefinder__panel {
  background: linear-gradient(180deg, var(--ccl-blue-bg) 0%, var(--brand-lightest) 100%);
  border-radius: var(--radius-lg);
  padding: var(--spacing-5xl) var(--spacing-4xl);
  display: grid;
  grid-template-columns: 444fr 743fr;
  gap: var(--spacing-4xl);
  align-items: center;
}
.hm-statefinder__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--spacing-lg);
}
.ccl .hm-statefinder__copy > * { margin: 0; }
.ccl .hm-statefinder__copy h2 {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: -0.5px;
  color: var(--ccl-black);
}
/* Native select styled as the design's field: white, 8px radius, own chevron
   (appearance:none drops the platform arrow along with the platform chrome). */
.hm-statefinder__select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  max-width: 364px;
  min-height: 48px;
  padding: 0 var(--spacing-2xl) 0 var(--spacing-md);
  background-color: #fff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--spacing-md) center;
  background-size: 24px 24px;
  border: 1px solid rgba(0,0,0,0.45);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--ccl-black);
  cursor: pointer;
}
.hm-statefinder__map { margin: 0; }
.hm-statefinder__map img { width: 100%; height: auto; display: block; }

/* Layout "Dropdown + button only": no panel, heading, copy or map — the select
   and CTA in a row on whatever background it's dropped onto. No outer margin
   of its own; the surrounding flow spaces it. Centers when its parent does
   (a centered Group / CTA band) via the .has-text-align-center / is-layout
   checks below. */
.hm-statefinder--picker {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-sm);
}
.ccl .hm-statefinder--picker > * { margin: 0; }
/* A set width, not the panel's 100%: in a shrink-to-fit parent (a flex Group)
   a percentage has nothing to resolve against and the row wraps. flex-grow
   still widens it to the panel's 364px max where there's room. */
.hm-statefinder--picker .hm-statefinder__select { width: 240px; flex: 1 1 240px; }
.is-content-justification-center > .hm-statefinder--picker,
.has-text-align-center > .hm-statefinder--picker { justify-content: center; }

@media (max-width: 900px) {
  .hm-statefinder__panel {
    grid-template-columns: 1fr;
    gap: var(--spacing-xl);
    padding: var(--spacing-2xl) var(--spacing-lg);
  }
}
@media (max-width: 600px) {
  .hm-statefinder--picker { flex-direction: column; align-items: stretch; }
  .hm-statefinder--picker .hm-statefinder__select { flex: none; width: 100%; max-width: none; }
}

/* ==========================================================================
   Chapter finder (acf/ccl-chapter-finder) — stat, state picker, clickable U.S.
   map. Ported from the prototype's .chapter-finder / .us-map on join-chapter.

   WP adaptations:
   - The prototype's city/state/zip <input> is a <select> (see render.php for
     why). It keeps the field shell, so .chapter-search__select is styled off
     the same rule the input used, plus the chevron our other selects carry.
   - States are wrapped in real <a>s server-side rather than being synthetic
     click targets, so the hover/focus styling hangs off .us-map__link — the
     anchor is what takes focus, not the <path>.
   - .us-map__selected and .us-map__state.is-selected are dropped: clicking a
     state now navigates, so there is no "selected but going nowhere" state
     left to announce.
   ========================================================================== */
.chapter-finder { background: var(--grey-100); padding: var(--spacing-6xl) var(--page-gutter); }
.chapter-finder__inner { max-width: 1140px; margin: 0 auto; }
.chapter-finder__stat { text-align: center; margin: 0 0 var(--spacing-2xl); }
.chapter-finder__stat-n {
  display: block;
  font-family: var(--font-hand);
  font-weight: 400;
  font-size: 68px;
  line-height: 1;
  letter-spacing: -1px;
  color: var(--ccl-blue);
}
.chapter-finder__stat-l {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 20px;
  line-height: 28px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey-400);
  margin-top: var(--spacing-sm);
}
.chapter-finder .section-header-centered { margin-bottom: var(--spacing-lg); }

.chapter-search {
  display: flex;
  gap: var(--spacing-sm);
  justify-content: center;
  max-width: 720px;
  margin: 0 auto var(--spacing-xl);
}
.chapter-search__field { position: relative; flex: 1; max-width: 480px; }
.chapter-search__select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 48px;
  padding: 0 var(--spacing-2xl) 0 16px;
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--text-md);
  color: var(--ccl-black);
  background-color: var(--grey-0);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--spacing-md) center;
  background-size: 24px 24px;
  cursor: pointer;
}
.chapter-search__select:focus {
  outline: none;
  border-color: var(--ccl-blue);
  box-shadow: 0 0 0 3px rgba(0, 129, 199, 0.18);
}

.chapter-finder__or {
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-lg);
}

/* ---- The map ---- */
.us-map-wrap { position: relative; max-width: 880px; margin: 0 auto; }
.us-map svg { display: block; width: 100%; height: auto; }
.us-map__state { cursor: pointer; transition: filter .12s ease, stroke .12s ease; }
.us-map__link:hover .us-map__state,
.us-map__link:focus-visible .us-map__state {
  filter: brightness(0.9);
  stroke: var(--brand-darkest);
  stroke-width: 1.5;
}
.us-map__link:focus-visible { outline: none; }
.us-map__tooltip {
  position: absolute;
  transform: translate(-50%, -135%);
  background: var(--brand-darkest);
  color: #fff;
  padding: 4px 10px;
  border-radius: 6px;
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.2;
  white-space: nowrap;
  pointer-events: none;
  z-index: 5;
}

.us-map-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-md);
  margin: var(--spacing-lg) 0 0;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  color: var(--grey-500);
}
.us-map-legend__label { font-weight: var(--fw-strong-body); color: var(--ccl-black); }
.us-map-legend__item { display: inline-flex; align-items: center; gap: var(--spacing-2xs); }
.us-map-legend__swatch {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: 1px solid rgba(0, 0, 0, 0.12);
}

@media (max-width: 900px) {
  .chapter-search { flex-direction: column; align-items: stretch; }
  .chapter-search__field { max-width: none; }
}

/* ==========================================================================
   STATE HUB PAGE (single-ccl_state.html) — the per-state bands.
   Ported from the prototype's volunteer-virginia.html, where these rules are
   INLINE in the page (its .vv-* block; not in the prototype's site.css, so
   bin/css-drift.sh can't track them). Named .state-* here after the
   component. Bands are template-placed blocks that self-hide when empty;
   .state-divider is the rule each band prints above itself (see
   ccl_state_band_divider()).
   ========================================================================== */
.state-divider { margin: var(--spacing-4xl) auto; }

/* ----- Page-top wash: breadcrumb + hero together -----
   The wash sits on a wrapper holding BOTH the breadcrumb and the hero, so the
   crumb sits inside the fade instead of on a white strip above it. Straight
   top-to-bottom, starting white: the prototype's 186° angle tints a wide
   hero's top-left corner before the first colour stop, which read as a hard
   edge under the breadcrumb in WP. Stops follow the prototype's. */
.state-wash {
  background: linear-gradient(180deg, #fff 8%, var(--ccl-blue-bg) 30%, var(--brand-lightest) 80%);
}
/* ----- Hero: "Volunteer in Virginia" + the join card -----
   Full-bleed (alignfull escapes the constrained <main>); the two-column grid
   inside is capped at 1440px like .hero-t2. */
.state-hero {
  padding: var(--spacing-2xl) var(--page-gutter) var(--spacing-4xl);
}
.state-hero__inner {
  max-width: 1440px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: var(--spacing-3xl);
  align-items: start;
}
.state-hero__copy { max-width: 640px; }
.state-hero .display { margin: var(--spacing-sm) 0 var(--spacing-lg); }
.state-hero__photo-block { margin-top: var(--spacing-xl); }
/* The link sits above the photo, left-aligned with the copy, so it reads as
   the next step in the argument rather than a caption on the image. */
.state-hero__photo-cta { text-align: left; margin: 0 0 var(--spacing-lg); }
/* A lone image, so it keeps its own shape (see CLAUDE.md → CSS, "Force an
   aspect-ratio only when items must line up"): full width, height from the
   photo, capped so a tall one can't push the hero long. Below the cap
   nothing is cropped; above it, cover trims rather than squashes. The <img>
   carries width/height attributes, so there's no layout shift. Was a fixed
   3:2 frame until 2026-09-30, which cut the tops and bottoms off anything
   squarer. */
.state-hero__photo {
  width: 100%;
  max-width: 560px;
  margin: 0; /* it's a <figure> */
}
.state-hero__photo img {
  display: block;
  width: 100%;
  height: auto;
  max-height: min(70vh, 500px);
  object-fit: cover;
  border-radius: var(--radius-md);
}
/* A state-shape icon stands in where a state has no usable photo yet. It's
   square artwork on a transparent background: shown whole, and smaller than
   a photo would be (560px square would read as a poster, not a badge). */
/* Centred in the column (photos stay left-aligned with the copy): a badge
   parked at the left edge of a wide column reads as a layout slip. */
.state-hero__photo--icon { max-width: 360px; margin-inline: auto; }
.state-hero__photo--icon img { object-fit: contain; border-radius: 0; }
/* The join card is the site's standard .join-card (card, title, intro — see
   the Join card section); these rules only place it in the hero. */
.state-hero__card {
  max-width: 511px;
  justify-self: end;
  width: 100%;
}
.state-hero__card-cta { margin: 0; }
@media (max-width: 1000px) {
  .state-hero__inner { grid-template-columns: 1fr; }
  .state-hero__card { justify-self: stretch; max-width: none; }
}

/* ----- "CCLers in action": the Stories block's layout + cards verbatim.
   The band divider already spaces it, so drop the block's own padding. ----- */
.state-actions.stories-field { padding-block: 0; }

/* ----- FAQ: the site's .ccl-accordion (patterns.css); only page spacing here ----- */
.state-faq {
  max-width: 1166px;
  margin: 0 auto;
  padding: 0 var(--container-pad) var(--spacing-5xl);
}

/* ----- Stats: "2025 Virginia stats" — the site's .ccl-stat-num / .ccl-stat-label
   (patterns.css, same as the stats patterns) in a 1–4 column grid ----- */
.state-stats {
  max-width: 1166px;
  margin: 0 auto;
  padding: 0 var(--container-pad);
  text-align: center;
}
.ccl .state-stats > h2 { margin-bottom: var(--spacing-2xl); }
/* --stat-cols is set by the block to the number of stats (max 4), so two
   stats sit as two wide columns rather than two of four. WP adaptation: the
   prototype hardcodes 4. */
.state-stats__grid {
  display: grid;
  grid-template-columns: repeat(var(--stat-cols, 4), 1fr);
  gap: var(--spacing-xl);
}
/* Narrow screens: two columns at most — but only as many as there are stats
   (--stat-cols-narrow), so a state left with one stat after zeros are dropped
   centres it instead of parking it in the left half. */
@media (max-width: 800px) {
  .state-stats__grid { grid-template-columns: repeat(var(--stat-cols-narrow, 2), 1fr); }
}

/* ----- Coordinators: "Meet the Virginia State Coordinators" ----- */
.state-coordinators {
  max-width: 1166px;
  margin: 0 auto;
  padding: 0 var(--container-pad);
}
/* Layout only — type comes from the base h2, same as every heading on the site. */
.ccl .state-coordinators > h2 {
  text-align: center;
  margin-bottom: var(--spacing-2xl);
}
.state-coordinator-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--spacing-3xl);
}
@media (max-width: 900px) {
  .state-coordinator-grid { grid-template-columns: 1fr; }
}
.state-coordinator-grid .person--spotlight { --person-photo: 170px; align-items: start; }
/* One coordinator: the card centred under the heading, and its bio given a
   readable line (~64 characters) instead of the half-width column the 2-up
   grid leaves it. A 150-word bio drops from ~22 lines to ~12. */
.state-coordinator-grid--single { grid-template-columns: minmax(0, 1fr); }
.state-coordinator-grid--single .person--spotlight {
  width: 100%;
  max-width: calc(var(--person-photo) + var(--spacing-2xl) + 64ch);
  margin-inline: auto;
}
/* "Read more" on a bio over 70 words (render.php + view.js). A text button in
   the site's link colour, under the bio, matching the bio's size. */
.person__bio-toggle {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin-top: var(--spacing-2xs);
  align-self: flex-start;
  font: inherit;
  font-size: var(--fs-small);
  font-weight: var(--fw-strong-body);
  color: var(--fg-link);
  cursor: pointer;
}
.person__bio-toggle:hover { text-decoration: underline; text-underline-offset: 0.15em; }
@media (max-width: 640px) {
  .person__bio-toggle { align-self: center; } /* the spotlight centres its copy on phones */
}


/* ----- .person — the prototype's people component, SPOTLIGHT subset -----
   The theme has two people vocabularies: .leader / .team-card (directory grid
   tiles, linked, via ccl_render_leader_tile) and this — a photo beside a
   role / name / bio, unlinked, for a handful of people presented as a
   feature. Ported from prototype site.css (.person, .person--spotlight);
   the --card / --inline / directory variants are deliberately NOT ported —
   nothing uses them yet. */
.person {
  --person-photo: 96px;
  flex: 0 1 calc((100% - 2 * var(--spacing-xl)) / 3);
  min-width: 220px;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xs);
}
/* 8px, per the person audit (person-audit.html, Decision 1: "square,
   --radius-sm (8px), everywhere"). Careful with the token NAME: this theme's
   --radius-xs and --radius-sm are swapped relative to the prototype, so 8px is
   --radius-xs here. Every other component was ported the same way, so the
   rendered radii match the design -- it is only the names that differ.
   .leader__photo already used the right one; this was the odd one out at 4px. */
.person__photo,
.person__avatar {
  width: var(--person-photo);
  height: var(--person-photo);
  border-radius: var(--radius-sm);
  display: block;
  margin-bottom: var(--spacing-xs);
  flex-shrink: 0;
  overflow: hidden;
}
.person__photo {
  object-fit: cover;
  object-position: 50% 30%;
  background: var(--grey-200);
}
/* Either shape works: <img class="person__photo"> or a wrapper div around an
   img (what the block emits, so WP's responsive img attributes ride inside). */
.person__photo > img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; display: block; }
.person__avatar {
  background: var(--ccl-blue-bg);
  color: var(--ccl-blue-dark);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: calc(var(--person-photo) / 3.4);
}
.ccl .person__name {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--ccl-black);
  margin: 0;
}
/* Grey, not blue: blue is the interaction signal, and this line isn't a link. */
.ccl .person__role {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  font-size: var(--text-md);
  line-height: 1.4;
  color: var(--grey-500);
  margin: 0;
}
.ccl .person__bio { font-size: var(--text-md); line-height: 1.5; margin: var(--spacing-2xs) 0 0; }

.person--spotlight {
  --person-photo: 200px;
  display: grid;
  grid-template-columns: var(--person-photo) minmax(0, 1fr);
  gap: var(--spacing-2xl);
  align-items: center;
  flex: initial;
}
.person--spotlight .person__photo,
.person--spotlight .person__avatar { margin-bottom: 0; border-radius: var(--radius-md); }
.person--spotlight .person__copy { display: flex; flex-direction: column; gap: var(--spacing-2xs); }
.ccl .person--spotlight .person__name {
  font-size: var(--fs-h4);
  line-height: calc(var(--lh-h4) / var(--fs-h4));
}
.ccl .person--spotlight .person__bio {
  font-size: var(--fs-small);
  line-height: calc(var(--lh-small) / var(--fs-small));
  margin-top: var(--spacing-xs);
}
@media (max-width: 640px) {
  .person--spotlight { grid-template-columns: 1fr; justify-items: center; text-align: center; }
}
/* Presenter variant — photo on top, text below, all left-aligned to match
   the "Presenter" heading above. All text in black. */
.person--spotlight.person--presenter {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--spacing-md);
  max-width: 320px;
  margin: var(--spacing-2xl) 0;
  text-align: left;
}
.person--spotlight.person--presenter .person__photo,
.person--spotlight.person--presenter .person__avatar {
  width: 100%;
  max-width: 240px;
}
.person--spotlight.person--presenter .person__photo img,
.person--spotlight.person--presenter .person__avatar {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-lg);
  display: block;
}
.person--spotlight.person--presenter .person__copy {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
  color: var(--ccl-black);
  width: 100%;
}
.person--spotlight.person--presenter .person__name {
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--ccl-black);
  margin: 0;
}
.person--spotlight.person--presenter .person__role {
  font-size: 16px;
  color: var(--ccl-black);
  margin: 0;
}
.person--spotlight.person--presenter .person__bio {
  font-size: 15px;
  line-height: 1.5;
  color: var(--ccl-black);
  margin: 0;
}
/* Mobile */
@media (max-width: 600px) {
  .person--spotlight.person--presenter {
      max-width: 100%;
  }
  .person--spotlight.person--presenter .person__photo,
  .person--spotlight.person--presenter .person__avatar {
      max-width: 200px;
  }
}
/* The outer section — this is what needs max-width and centering */
.vv-chapters {
  max-width: 1166px;
  margin: 0 auto;
  padding: var(--spacing-4xl) var(--container-pad) 0;
}

/* Layout only — type comes from the base h2 (40px), like the other state-page
   section headings. Was pinned to --fs-h3 (32px), which made it the one small
   heading on the page. */
.vv-chapters h2 {
  text-align: center;
  margin: 0 0 var(--spacing-md);
  unicode-bidi: isolate;
}

/* The content width (780px), not 640px: at 640 the one-sentence lead wrapped,
   leaving "nearest chapter." alone on a second line. */
.ccl .vv-chapters__lead {
  text-align: center;
  max-width: var(--wp--style--global--content-size, 780px);
  margin: 0 auto var(--spacing-xl);
}

/* Grid that fills the section fully */
.vv-chapter-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 var(--spacing-2xl);
  width: 100%;
}
/* Three columns plus 48px gaps cut the third column off on a phone. */
@media (max-width: 900px) { .vv-chapter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--spacing-lg); } }
@media (max-width: 560px) { .vv-chapter-grid { grid-template-columns: minmax(0, 1fr); } }

/* Individual chapter cards */
.vv-chapter {
  border-top: 1px solid var(--grey-200);
  padding: var(--spacing-sm) 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.vv-chapter__name {
  font-family: var(--font-body);
  font-weight: var(--fw-strong-body);
  font-size: var(--fs-small);
  color: var(--ccl-black);
  margin: 0;
}

.vv-chapter__area {
  font-size: var(--fs-tiny);
  line-height: calc(var(--lh-tiny) / var(--fs-tiny));
  color: var(--fg1);
  margin: 0;
}

/* ==========================================================================
   GALLERY  (.ccl-gallery) — plumbing only
   --------------------------------------------------------------------------
   The grid, and the two things WordPress breaks. The compositions themselves
   are patterns, not options here: Gallery — mosaic / feature / even each ship
   a fixed number of images with the spans already placed.

   That's deliberate, and it's a reversal. This started as one component with
   layout variants, then automatic variation via nth-child. Both worked, but
   there are four uses on this site and all four are a different arrangement --
   so every use was a one-off wearing a component's clothes, and each round of
   "make it flexible" added arithmetic an editor would have to reason about
   (half-cell holes, which item gets enlarged, whether a manual span fights the
   rhythm). A pattern has none of that: the composition is chosen, the item
   count is known, and there is nothing to learn beyond swapping photos.

   What stays here is what a pattern can't avoid needing:

   1. The grid. Sixteen tracks, and rows exactly as tall as a track is wide, so
      the unit is square and a default four-by-four cell is square with it. The
      fine grid is what buys the variety: a cell can be half, 1.5x or 2x in
      either direction, and two 1.5x cells sit side by side in three quarters of
      the row with no leftover sliver -- which is how the mosaic's bottom pair
      works without the nested sub-grid the prototype needed for it.
   2. Images fill their cell rather than carrying an aspect ratio -- the
      proportions already come from column width and row height.
   3. Two WordPress adaptations, both found by rendering rather than reading:
      images arrive wrapped in <figure class="wp-block-image">, so the FIGURE is
      the grid item and the prototype's <img>-targeted rules never reach it; and
      a Group brings is-layout-flow, whose `> * + *` margin staggers every child
      after the first.
   ========================================================================== */
.ccl-gallery {
  /* No CSS reads a grid's own track width, so the row height is computed from
     the measure the patterns sit in -- all three are alignwide, and 16 tracks
     plus 15 gaps fill it exactly. Redefining --gallery-tracks at a breakpoint
     re-resolves the unit with it, so the media queries below set only the track
     count and the template. */
  --gallery-gap: var(--spacing-lg);
  --gallery-tracks: 16;
  --gallery-measure: min(
    100vw - 2 * var(--container-pad),
    var(--wp--style--global--wide-size, 1166px)
  );
  --gallery-unit: calc(
    (var(--gallery-measure) - (var(--gallery-tracks) - 1) * var(--gallery-gap))
      / var(--gallery-tracks)
  );
  display: grid;
  grid-template-columns: repeat(16, minmax(0, 1fr));
  /* minmax, not a bare length: a row holding a long quote grows instead of the
     text spilling over the tile below it. Safe only because the images are
     taken out of flow below -- see the note there. */
  grid-auto-rows: minmax(var(--gallery-unit), auto);
  gap: var(--gallery-gap);
  grid-auto-flow: dense;
}
/* A cell is four tracks each way: a quarter of the row, and square. Four rather
   than one so every span below lands on whole tracks in both directions. */
.ccl-gallery > * {
  grid-column: span 4;
  grid-row: span 4;
  position: relative;
  margin: 0;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  border-radius: var(--radius-md);
}
.ccl-gallery > * + * { margin-block-start: 0; }
/* Out of flow, which is what lets the rows be minmax(). In-flow, `height: 100%`
   against a row that is allowed to grow resolves to auto -- the image asks for
   its natural height and every row explodes to full-resolution size. Absolute
   positioning makes the image contribute no height at all, so only real text
   can grow a row. (The prototype's .hm-mosaic__tile img does this for the same
   reason.)

   Scoped to images that ARE a cell, not every image inside one: `.ccl-gallery
   img` is (0,1,1) and beats `.quote__glyph` at (0,1,0), so it stretched the
   Quote block's 86px glyph to fill the whole cell and spill over the photo
   above it. Anything nested inside a cell -- a quote's glyph, an avatar --
   keeps its own sizing.

   Top-anchored, not centred: these are group shots with heads near the top of
   the frame, and the cells are wider than the sources, so `cover` crops
   vertically. A centred crop takes half of that off the top, through the faces;
   the foreground (tables, grass, feet) is what can go. Inert on cells that crop
   horizontally instead. */
.ccl-gallery > .wp-block-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
  margin: 0;
}

/* A video cell. Two cells wide, because a video wants a landscape frame: the
   feature pattern's 2x tile is 1:2.8 portrait, and a 16:9 video in it is a thin
   strip with most of the cell empty.

   Sized by its own ratio rather than by the row band, which is the one place a
   video differs from a photo here. A photograph can be cropped to whatever
   shape the cell is; a video frame can't -- crop it and the subject walks out
   of shot. So the cell takes 16:9 and the grid gives way: across 8 tracks that
   is taller than the four rows it spans, the minmax() rows above absorb the
   difference, and the photos beside it grow to match, so the band still lines
   up.

   Covers both blocks an editor can reach for -- Video (self-hosted) and Embed
   (a pasted YouTube or Vimeo URL) -- and .video-embed, the markup
   ccl_youtube_embed() returns, in case one is dropped in as Custom HTML. Core
   already absolutely positions an embed's iframe inside its wrapper when it
   knows the ratio; the iframe rule below covers the case where it doesn't
   (Vimeo, and anything oEmbed can't size). */
.ccl-gallery > .wp-block-video,
.ccl-gallery > .wp-block-embed,
.ccl-gallery > .video-embed {
  grid-column: span 8;
  grid-row: span 4;
  aspect-ratio: 16 / 9;
}
.ccl-gallery > .wp-block-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--grey-200);
}
.ccl-gallery > .wp-block-embed .wp-block-embed__wrapper {
  position: relative;
  height: 100%;
}
.ccl-gallery > .wp-block-embed .wp-block-embed__wrapper::before { display: none; }
.ccl-gallery > .wp-block-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Spans, placed by the patterns rather than chosen in the editor, plus
   .gallery-extra -- a cell that earns its place on a desktop but not on a
   phone. See the 620px block. */
.ccl-gallery > .gallery-narrow { grid-column: span 2; }   /* 0.5x */
.ccl-gallery > .gallery-wide   { grid-column: span 6; }   /* 1.5x */
.ccl-gallery > .gallery-wider  { grid-column: span 8; }   /* 2x   */
.ccl-gallery > .gallery-short  { grid-row: span 2; }      /* 0.5x */
.ccl-gallery > .gallery-tall   { grid-row: span 6; }      /* 1.5x */
.ccl-gallery > .gallery-taller { grid-row: span 8; }      /* 2x   */

/* A quote is text, not a cropped picture: it needs the height, keeps its own
   background, and is exempt from the clip that would cut a long one off. */
.ccl-gallery > .wp-block-quote,
.ccl-gallery > .quote,
.ccl-gallery > .conf-quote-block {
  align-self: center;
  overflow: visible;
  border-radius: 0;
  grid-row: span 8;
}

@media (max-width: 900px) {
  /* Two up: a quarter of a tablet is too narrow for a group shot to read. The
     WIDTH spans all flatten to one cell -- a 1.5x or 2x cell can't tile a
     two-column row, and every attempt leaves a cell-sized hole where the next
     item was too wide to follow. Height spans survive, and are what keeps the
     stack from reading as a plain two-column list. */
  .ccl-gallery {
    --gallery-tracks: 8;
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }
  .ccl-gallery > .gallery-narrow,
  .ccl-gallery > .gallery-wide,
  .ccl-gallery > .gallery-wider { grid-column: span 4; }
  /* A video is the exception: it goes wider here, not narrower. Half a tablet
     is about 350px, and a 16:9 frame that size is unwatchable. */
  .ccl-gallery > .wp-block-video,
  .ccl-gallery > .wp-block-embed,
  .ccl-gallery > .video-embed { grid-column: 1 / -1; }
  /* Full width and its own height. Centred in a 2x cell it sat in the middle of
     a screenful of white; `auto` takes one row and the minmax above grows it to
     whatever the words need. */
  .ccl-gallery > .wp-block-quote,
  .ccl-gallery > .quote,
  .ccl-gallery > .conf-quote-block { grid-column: 1 / -1; grid-row: auto; }
}
@media (max-width: 620px) {
  /* One up, and the height spans flatten too -- a 2x cell at full phone width
     is most of a screen. */
  .ccl-gallery {
    --gallery-tracks: 4;
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .ccl-gallery > .gallery-narrow,
  .ccl-gallery > .gallery-wide,
  .ccl-gallery > .gallery-wider,
  .ccl-gallery > .gallery-short,
  .ccl-gallery > .gallery-tall,
  .ccl-gallery > .gallery-taller { grid-column: 1 / -1; grid-row: span 4; }
  .ccl-gallery > * { grid-column: 1 / -1; }
  /* Every cell is a full-width square here, so a set that reads as a wall on a
     desktop reads as eight screenfuls of scrolling on a phone. The patterns mark
     alternate photos as extra and they drop out, leaving four -- enough to still
     be a gallery, short enough to scroll past. Alternating rather than trimming
     the tail is deliberate: the images are placeholders an editor replaces, so
     the choice has to be positional, not a judgement about these photos.
     (.at-gallery__extra in the prototype's action-team pages does the same.) */
  .ccl-gallery > .gallery-extra { display: none; }
}
/* ==========================================================================
   PHOTO SHOWCASE  (.photo-showcase) — portrait feature beside landscape rows
   --------------------------------------------------------------------------
   Ported from the prototype as itself, not rebuilt on .ccl-gallery, because it
   sizes on the opposite principle. The gallery crops every photo to whatever
   shape its cell is; this one derives the shapes so that nothing crops. Use it
   when the photos are all a similar aspect ratio -- CCL's library is nearly all
   3:2 landscape, so a unit grid of it just reads as an even grid and the size
   contrast has to come from the layout instead of the source images.

   Structure -- a feature, then a __grid of __rows holding two tiles each:
     .photo-showcase
       .photo-showcase__feature      portrait, 9:16
       .photo-showcase__grid
         .photo-showcase__row        even split
         .photo-showcase__row--wide  1.3 / 1 split
         .photo-showcase__row

   Alternating an off-balance row keeps the landscape tiles from marching in
   identical rectangles. The 1 : 1.75 column split is derived, not eyeballed:
   it's the ratio at which a 9:16 feature is exactly as tall as three rows of
   3:2 tiles, so nothing in an even row gets cropped. Change one of those three
   numbers and the other two have to move with it.
   ========================================================================== */
.photo-showcase {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.75fr);
  gap: var(--spacing-sm);
}
.photo-showcase__grid {
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  gap: var(--spacing-sm);
  min-height: 0;
}
.photo-showcase__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-sm);
  min-height: 0;
}
.photo-showcase__row--wide { grid-template-columns: 1.3fr 1fr; }
/* WordPress: the showcase, the grid and every row are Groups, so each one
   arrives with is-layout-flow and its `> * + *` margin -- which would push the
   second tile of every row down by 24px. */
.photo-showcase > * + *,
.photo-showcase__grid > * + *,
.photo-showcase__row > * + * { margin-block-start: 0; }
.photo-showcase__feature,
.photo-showcase__row > * {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  margin: 0;
  min-width: 0;
  min-height: 0;
}
/* Media is taken out of flow so the tiles contribute no intrinsic height. That
   makes the feature's 9:16 the only thing sizing the block: __grid stretches to
   it, its three 1fr rows split that evenly, and every tile fills its own share.
   Leave the images in flow and each one sizes to its natural height instead,
   and the two columns drift out of alignment. */
.photo-showcase img,
.photo-showcase__feature iframe,
.photo-showcase__feature video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border: 0;
  margin: 0;
}
/* The feature is the one slot on the site that fits portrait media, which is
   what makes it the right home for a vertical YouTube Short. */
.photo-showcase__feature { aspect-ratio: 9 / 16; }
/* Safety net for a published-but-unfinished slot. An Embed block with no URL
   saves nothing at all, so the showcase can reach the front end with only its
   __grid child -- which would sit in the 1fr column and squeeze six photos into
   a third of the width, behind an empty column. One child means no feature. */
/* No feature yet -- an Embed block with no URL saves nothing, so a page can
   reach the front end with photos in the rows and an empty feature slot.

   That does not just lose a column, it collapses the whole component. The
   feature's 9:16 is the ONLY thing giving the grid height (the media is taken
   out of flow above so the tiles contribute none), so with it gone every row
   computes to 0px and the photos vanish entirely -- which reads as "my images
   didn't save" rather than "the video is missing". The rows carry their own
   ratio instead, the same 3:1 the stacked layout falls back to. */
.photo-showcase:not(:has(> .photo-showcase__feature)) {
  grid-template-columns: 1fr;
}
.photo-showcase:not(:has(> .photo-showcase__feature)) .photo-showcase__row {
  aspect-ratio: 3 / 1;
}
/* An Embed block carries core's own 16:9 wrapper; the feature's 9:16 has to
   win, so the wrapper fills the cell and its ratio pseudo-element goes. */
.photo-showcase__feature .wp-block-embed__wrapper {
  position: static;
  height: 100%;
}
.photo-showcase__feature .wp-block-embed__wrapper::before { display: none; }
/* Caption sits under the whole thing, not under one tile. */
.photo-showcase-figure > * + * { margin-block-start: 0; }
.photo-showcase__caption {
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--fs-tiny);
  line-height: 1.5;
  color: var(--grey-500);
  margin: var(--spacing-sm) 0 0;
}

@media (max-width: 900px) {
  /* Side by side, the feature would have to be either tiny or crop-heavy, so
     stack it above the rows and cap it -- a full-bleed 9:16 fills the screen.
     Stacked, there's no feature height left to stretch into, so the rows carry
     their own ratio: two 3:2 tiles plus a gap sit at roughly 3:1. */
  .photo-showcase { grid-template-columns: 1fr; }
  /* `width: 100%` is load-bearing, not tidying. The feature's media is taken out
     of flow above, so the element's max-content width is zero -- and an auto
     inline margin overrides justify-self: stretch, which leaves it shrink-to-fit
     at nothing. It renders as a 0x0 box and the feature silently vanishes on a
     tablet. (The prototype has the same two lines and the same hole.) */
  .photo-showcase__feature {
    width: 100%;
    max-width: 300px;
    margin-inline: auto;
  }
  .photo-showcase__grid { grid-template-rows: repeat(3, auto); }
  .photo-showcase__row { aspect-ratio: 3 / 1; }
}

/* ==========================================================================
   PHOTO MASONRY  (.photo-masonry) — uneven heights, kept uneven
   --------------------------------------------------------------------------
   The third and last of the photo-set components, and the only one that does
   not decide the shape of anything. CSS columns, so every photo keeps its own
   height and nothing is cropped at all -- which is what makes it read as a
   gallery rather than a grid.

   That is also its one precondition, and the prototype states it against
   .photo-showcase: CCL's library is nearly all 3:2 landscape, and a columns
   masonry of photos that are all the same ratio just reads as an even grid. So
   this is the right component only when the set is genuinely mixed -- a
   screenshot, a portrait phone photo, a wide group shot. For a uniform set,
   .ccl-gallery imposes the variety instead and .photo-showcase derives it.

   Picking between the three:
     .ccl-gallery     crops every photo to a cell on a 16-track unit grid.
                      Full-width compositions only -- its row height is
                      computed from the alignwide measure, so in a narrow
                      column the rows stay tall while the columns go thin and
                      the cells come out as slivers.
     .photo-showcase  derives the shapes so nothing crops. Fixed 7 slots.
     .photo-masonry   imposes nothing. Any number of photos, any column width.
   ========================================================================== */
.photo-masonry { columns: 3; column-gap: var(--spacing-sm); }
.photo-masonry--2 { columns: 2; }
/* WordPress: the FIGURE is the column item, not the <img>, so the break rule
   and the spacing below the photo have to sit on it -- the prototype's
   <img>-targeted version never reaches anything here. A Group also brings
   is-layout-flow, whose `> * + *` margin would stack on top of that. */
.photo-masonry > * {
  break-inside: avoid;
  margin: 0 0 var(--spacing-sm);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.photo-masonry > * + * { margin-block-start: 0; }
.photo-masonry img {
  width: 100%;
  display: block;
  margin: 0;
}
@media (max-width: 900px) { .photo-masonry { columns: 2; } }
@media (max-width: 620px) {
  /* A swipeable strip, not a tall stack. Columns of full-width photos on a
     phone is a screenful each and nobody reaches the end. The negative margin
     lets the strip bleed to the screen edges so it reads as scrollable. */
  .photo-masonry {
    columns: auto;
    display: flex;
    gap: var(--spacing-sm);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    margin: 0 calc(-1 * var(--container-pad));
    padding: 0 var(--container-pad) var(--spacing-xs);
  }
  .photo-masonry > * {
    flex: 0 0 70%;
    height: 220px;
    margin: 0;
    scroll-snap-align: start;
  }
  .photo-masonry img { height: 100%; object-fit: cover; }
  /* Same marker the galleries use -- one class to learn for "not on a phone".
     A strip scrolls rather than stacks, so this is about keeping it short
     enough to reach the end, not about page length. */
  .photo-masonry > .gallery-extra { display: none; }
}


/* ==========================================================================
   ACTION TEAMS  (.at-*)
   --------------------------------------------------------------------------
   Ported from the prototype's action-team template. action-team-roc.html and
   action-team-pgm.html carry the same page-local <style> block and are the
   source here. action-team-youth-vivid.html is a hand-built variant with the
   intensity machinery stripped out, so it isn't the source for the base rules;
   its vivid-only pieces are ported under BRAND-INTENSITY → "The Youth page's
   vivid pieces" (patterns/youth-action-team-page.php).

   These are the LAYOUT pieces specific to an Action Team page. What sits inside
   them is already in this file -- buttons, eyebrows, .bills-card/.bill-row FAQ,
   lite-video, the join form. Don't re-implement those here.

   ---- BRAND INTENSITY -----------------------------------------------------
   Upstream dials the page with <body data-intensity="low|vivid">, mapped to
   audience: LOW for Congress / right-of-center / funders, MEDIUM the national
   default, HIGH for youth / affinity teams.

   LOW is a block style variation on the pattern's outer Group --
   `.is-style-at-low`, registered in functions.php. WordPress can't set a
   per-page body attribute without PHP, and a Styles-panel choice is what an
   editor can reach. MEDIUM stays the default: no class at all, as upstream.

   HIGH is NOT a style variation. `.at-vivid` is a plain class the Youth pattern
   carries in its own markup. Youth is expected to be the only page that uses it,
   and a picker entry appearing on every Group to serve one page is clutter that
   implies a system we don't have. It wouldn't be sufficient on its own either --
   upstream notes the masonry about-gallery and torn-paper hero are markup
   choices, so Youth needs its own pattern regardless, and that pattern is the
   natural place for the class.

   If a second team ever wants vivid, promoting it back is two lines: register
   the style and rename the four selectors.

   ---- ONE OTHER DEVIATION -------------------------------------------------
   Nine rules arrived as `.ccl .at-*`. They carried `.ccl` only to outrank the
   prototype's global type rules; ours are weaker (`:where(.ccl) h3` is (0,0,1)),
   so a bare `.at-*` class already wins. Unscoped here because a .ccl-scoped rule
   renders in preview but goes unstyled in the block-editor canvas, which has no
   .ccl ancestor -- the same reason the eyebrows above are unscoped.
   ========================================================================== */

/* --- Hero: gradient wash, copy + contact left, join form right ------------- */
.at-hero {
  background: linear-gradient(186deg, #fff 12.5%, var(--ccl-blue-bg) 29.7%, var(--brand-lightest) 79.4%);
  padding: var(--spacing-2xl) var(--page-gutter) var(--spacing-4xl);
  /* Past the 1440px frame the side padding grows, so on a big monitor the copy
     and the form stay together instead of drifting to opposite edges. */
  padding-inline: max(var(--page-gutter), calc((100% - var(--frame-max)) / 2 + var(--page-gutter)));
  display: grid;
  /* minmax(0, …), not bare fr: a bare fr track can't shrink below its widest
     child, and the slideshow's photos and the form's inputs pushed the hero
     off the right edge of a phone (and the form off at 1024px). */
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: var(--spacing-3xl);
  align-items: start;
}
/* 680, not the prototype's 640: at the 56px display size "Empowering voices
   from" (PGM) measures 642px, so a 640 cap broke the headline into three
   ragged lines. Editors had forced it onto one with non-breaking spaces,
   which instead ran it off the column on narrower screens. */
.at-hero__copy { max-width: 680px; }
.at-hero .display { margin: var(--spacing-sm) 0 var(--spacing-lg); }
/* Plain photo by default. VIVID option: replace the <img> with a pre-composited
   torn-paper hero (photo + frame baked in Canva, transparent edges) — then the
   torn edges feather onto the page and no extra CSS is needed. */
.at-hero__photo {
  position: relative;
  margin-top: var(--spacing-2xl);
  border-radius: var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 16 / 10;
  max-width: 600px;
}
.at-hero__photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* PGM: a Gallery in the Slideshow style can take the photo's place (same
   .at-hero__photo class, see Slideshow). In the editor it's a grid of every
   photo, so drop the frame there. */
.at-hero__photo.wp-block-gallery:not(.gallery-slideshow) { aspect-ratio: auto; overflow: visible; border-radius: 0; }
.at-hero__photo.wp-block-gallery:not(.gallery-slideshow) img { position: static; }
/* A plain paragraph: the prototype's inline-flex (icon + text) made the
   sentence and the link two flex items, so on a phone "Questions? Get in
   touch at" got squeezed into a narrow column beside the address. */
.at-contact {
  margin-top: var(--spacing-lg);
  font-size: var(--fs-small);
}

/* Form card — white panel; field styles come from .join-mock-form */
/* The card itself is the site's standard .join-card (see the Join card
   section); these rules only place it in the hero. Same split PR #98 made for
   .state-hero__card -- this was a near-duplicate of it, down to the 511px.
   The one real change is the shadow: .join-card's is soft and wide
   (0 8px 24px / .08) where this carried --shadow-card (0 2px 4px / .2). */
.at-form-card {
  max-width: 511px;
  justify-self: end;
  width: 100%;
}
@media (max-width: 1000px) {
  .at-hero { grid-template-columns: minmax(0, 1fr); }
  .at-form-card { justify-self: stretch; max-width: none; }
  .at-hero__photo { max-width: none; }
}

/* --- Shared section scaffolding -------------------------------------------- */
/* The prototype gives .at-section horizontal padding only and hand-tunes the
   vertical gap with an inline `style="padding-top: var(--spacing-5xl)"` on the
   two sections that need it. That doesn't survive contact with an editor who
   adds and removes sections, so the rhythm is a default here instead -- every
   at-section spaces itself, and a Group's own padding controls can override it
   where a page wants something different. */
.at-section { max-width: 1166px; margin: 0 auto; padding: var(--spacing-5xl) var(--container-pad) 0; }
/* A thick rule already spaces whatever follows it. Its own 64px margin-block
   plus the 80px above stacked to 144px before the next eyebrow, which reads as
   a gap rather than a rhythm -- the rule looked orphaned from the section it
   was introducing. The separator IS the break; the section does not repeat it. */
.wp-block-separator + .at-section { padding-top: 0; }
.at-section--narrow { max-width: 880px; }
.at-section > h2.at-section__title { text-align: center; margin-bottom: var(--spacing-md); }
.at-section__intro {
  max-width: 720px;
  margin: 0 auto var(--spacing-2xl);
  text-align: center;
}
.at-divider { margin: var(--spacing-4xl) auto; }
.at-eyebrow-center { text-align: center; }

/* --- What we do / Why we're important -------------------------------------- */
.at-about__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: var(--spacing-3xl);
  align-items: start;
}
@media (max-width: 900px) { .at-about__grid { grid-template-columns: minmax(0, 1fr); } }
.at-about__grid h2 { margin: 0 0 var(--spacing-md); }
.at-about__copy > p { margin: 0 0 var(--spacing-md); }
/* Default: a single sticky photo. */
.at-about__photo {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  position: sticky;
  top: var(--spacing-lg);
}
.at-about__photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 900px) { .at-about__photo { position: relative; aspect-ratio: 16 / 10; } }

/* --- Featured members: video grid + coordinator spotlight ------------------ */
.at-features { padding-bottom: var(--spacing-5xl); }
/* Card treatment for a .person in an Action Team's "Meet some of our team
   members" grid. In the prototype this lives in the shared stylesheet, not the
   page-local block, and it never came across when .person was ported for the
   state coordinator band -- so it is added here rather than in the ported
   section above. */
/* The features row on an Action Team page. Like .person--card this lives in the
   prototype's SHARED stylesheet, so it didn't come across with the page-local
   block. */
.people {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--spacing-xl);
  padding: 0;
  margin: 0;
  list-style: none;
}
/* Featured speakers (blocks/featured-speakers) — a few .person--spotlight rows.

   Two up, because a spotlight person is a 200px photo PLUS a measure of bio:
   three across at 1166px leaves the bio about twenty characters wide, and
   .people's plain flex-wrap would do exactly that. One up below 900px, where
   the spotlight itself already stacks photo over copy. Same shape as
   .state-coordinator-grid, which solved this for the same component.

   MUST stay after .people. That rule sets display:flex at the same specificity
   (0,1,0), so sitting earlier in the file -- next to the related
   .state-coordinator-grid rules, which is where this started -- meant flex won
   the tie and the grid never applied. The speakers wrapped and staggered down
   the page instead of pairing up. */
.people--speakers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--spacing-3xl);
  align-items: start;
}
/* A lone keynote centres rather than sitting against the left edge -- one
   featured speaker is the common case and should read as deliberate. */
.people--speakers > .person:only-child {
  grid-column: 1 / -1;
  max-width: 720px;
  margin-inline: auto;
}
@media (max-width: 900px) {
  .people--speakers { grid-template-columns: 1fr; }
}

.person--card {
  background: #fff;
  border: 1px solid rgba(0, 0, 0, .10);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--spacing-xl);
}
.at-features__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
}
@media (max-width: 760px) { .at-features__grid { grid-template-columns: 1fr; max-width: 420px; margin: 0 auto; } }
.at-feature { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.at-features__grid .at-feature > * { margin: 0; }
/* A featured member's spotlight (Team member spotlight block) under the grid. */
.at-features .person--spotlight { margin-top: var(--spacing-3xl); }
.at-feature__media { position: relative; box-shadow: var(--shadow-card); }
/* Play button anchored bottom-left so it never covers a face (see
   DESIGN-SYSTEM-FEEDBACK.md §2.4). The whole tile stays the click target. */
.at-feature__media::before {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 45%; height: 45%;
  background: radial-gradient(120% 120% at 0% 100%, rgba(0,0,0,.32), transparent 70%);
  border-radius: 0 0 0 var(--radius-md);
  pointer-events: none;
  z-index: 1;
}
.at-feature__media .play-btn {
  inset: auto auto var(--spacing-sm) var(--spacing-sm);
  margin: 0;
  width: 52px; height: 52px;
  transition: transform .15s ease;
}
.at-feature__media .play-btn::after { margin-left: 4px; border-width: 10px 0 10px 16px; }
.at-feature__media:hover .play-btn { transform: scale(1.08); }
.at-feature__name {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--ccl-black);
  text-align: center;
}
/* Photo variant (teams may use a still + quote instead of video) */
.at-feature__photo {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 16 / 9;
  box-shadow: var(--shadow-card);
}
.at-feature__photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.at-feature__quote { text-align: center; font-size: var(--fs-small); color: var(--grey-600); }

/* Coordinator spotlight */

/* --- Current campaigns (tinted band, handles multiple concurrent) ---------- */
.at-campaigns { background: var(--brand-lightest); padding: var(--spacing-5xl) 0; }
.at-campaigns .at-section { padding: 0 var(--container-pad); }
.at-campaign-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
  align-items: stretch;
}
@media (max-width: 900px) { .at-campaign-grid { grid-template-columns: 1fr; max-width: 480px; margin: 0 auto; } }
.at-campaign {
  background: #fff;
  border: 1px solid rgba(0,0,0,.10);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* Absolutely-positioned img so the box's aspect-ratio stays authoritative
   regardless of the source photo's ratio (portrait sources crop to fit). */
.at-campaign__image { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.at-campaign__image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Logo variant — a campaign badge/illustration (not a photo): show it whole
   (contain) on a flat panel instead of cropping it. */
.at-campaign__image--logo { background: var(--ccl-blue-bg); }
.at-campaign__image--logo img { object-fit: contain; padding: var(--spacing-sm); box-sizing: border-box; }
.at-campaign__body { padding: var(--spacing-xl); display: flex; flex-direction: column; gap: var(--spacing-sm); flex: 1; }
.at-campaign__title {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--ccl-black);
  margin: 0;
}
.at-campaign__body > p { margin: 0; }
.at-campaign .btn { margin-top: auto; align-self: flex-start; }
/* Built from blocks (the Youth pattern): the image is a core Image, so double
   the core class to beat `.wp-block-image img { height: auto }` (see CLAUDE.md,
   "A single-class port can TIE with core"); the buttons are a core Buttons row
   pinned to the card's foot; flow-layout margins are zeroed (gap spaces it). */
.at-campaign > * + * { margin-block-start: 0; }
.at-campaign__image.wp-block-image { margin: 0; }
.at-campaign__image.wp-block-image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.at-campaign__image--logo.wp-block-image img { object-fit: contain; padding: var(--spacing-sm); box-sizing: border-box; }
.at-campaign .at-campaign__body > * { margin: 0; }
.at-campaign .at-campaign__body > .wp-block-buttons { margin-top: auto; }

/* --- Stats: large figures + source ----------------------------------------- */
.at-stats { text-align: center; }
.at-stats__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--spacing-3xl);
  text-align: left;
  margin-top: var(--spacing-xl);
}
@media (max-width: 760px) { .at-stats__grid { grid-template-columns: 1fr; } }
/* Medium (default): gradient figures. LOW dials to solid; HIGH keeps gradient. */
.at-stat__n {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: 88px;
  line-height: 1;
  background: var(--gradient-blue-green);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin-bottom: var(--spacing-sm);
}
.at-stat__desc { font-size: var(--fs-small); margin: 0 0 var(--spacing-sm); }
.at-stat__source { font-size: var(--fs-tiny); color: var(--grey-500); }

/* --- Blog feed: 3-up cards + tag link -------------------------------------- */
.at-blog__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
}
@media (max-width: 900px) { .at-blog__grid { grid-template-columns: 1fr; max-width: 480px; margin: 0 auto; } }
.at-blog-card {
  background: #fff;
  border: 1px solid rgba(0,0,0,.10);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  color: inherit;
}
.at-blog-card:hover { box-shadow: var(--shadow-elevated); }
.at-blog-card__image { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.at-blog-card__image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.at-blog-card__body { padding: var(--spacing-lg); display: flex; flex-direction: column; gap: var(--spacing-xs); flex: 1; }
.at-blog-card__title {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  line-height: calc(var(--lh-h5) / var(--fs-h5));
  color: var(--ccl-black);
  margin: 0;
}
.at-blog-card .read-more { margin-top: auto; }
.at-blog__all { text-align: center; margin-top: var(--spacing-2xl); }

/* --- Resources: grouped link lists ----------------------------------------- */
.at-resources__groups {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-2xl);
  margin-top: var(--spacing-xl);
}
@media (max-width: 900px) { .at-resources__groups { grid-template-columns: 1fr; max-width: 520px; margin-left: auto; margin-right: auto; } }
.at-resource-group h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-h5);
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-md);
  padding-bottom: var(--spacing-xs);
  border-bottom: 2px solid var(--brand);
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}
/* Optional brand icon before each heading (assets/icons/*.png). Remove the
   <img> if a team prefers plain headings. */
.at-resource-group h3 img { width: 30px; height: 30px; flex-shrink: 0; }

/* "As part of our team, you may:" -- checkmark list in the About section
   (action-team-page pattern, a core List with the class). Ported from the
   prototype (action-team-template.html); it was never brought across, so the
   list rendered as plain bullets. */
.at-activities {
  list-style: none;
  margin: var(--spacing-md) 0 var(--spacing-lg);
  padding: 0;
  display: grid;
  gap: var(--spacing-sm);
}
.at-activities li {
  position: relative;
  padding-left: var(--spacing-2xl);
  font-size: var(--fs-small);
  line-height: calc(var(--lh-small) / var(--fs-small));
}
.at-activities li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 2px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--brand-lightest) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235A7931' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E") center / 14px no-repeat;
}
/* font-size: a UI link list, not prose -- keeps the 16px base the prototype
   renders it at now that the core List block defaults to body size. */
.at-resource-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-xs); font-size: var(--text-md); }
/* `li > a` (0,1,2), not `a`: these are unclassed links in a core List block, so
   the prose list-link rule in tokens.css (0,1,2) would otherwise turn them navy
   and underlined. Equal specificity, and site.css loads later. No underline at
   rest (the prototype's look); hover still underlines via the base a:hover. */
.at-resource-group li > a {
  display: inline-flex;
  align-items: baseline;
  gap: var(--spacing-xs);
  font-weight: var(--fw-strong-body);
  color: var(--fg-link-strong);
  text-decoration: none;
}
.at-resource-group a::before { content: '›'; color: var(--brand-dark); }

/* --- FAQ uses .bills-card / .bill-row from site.css ------------------------ */
.at-faq { padding: 0 var(--container-pad) var(--spacing-5xl); }

/* No bottom-margin hack here any more. This pulled the page up by 32px to
   cancel the wrapper padding under the closing band, because the general rule
   for "page ends in a band" (see the Join CTA section) only matched a band
   that was a direct child of .wp-block-post-content -- and this page's band
   sits inside .at-page. It only ever cancelled the wrapper's 32px, never the
   footer's 24px, which is the white that was left. The general rule handles
   the wrapped case now, so keeping this would turn it into a 32px overlap. */

/* .at-section carries top padding only -- the rhythm comes from the NEXT
   section's top. That leaves nothing under the last one, so a section running
   straight into a full-bleed band butts against it. The starter ends with the
   FAQ, which has its own bottom padding, but a team that deletes the FAQ would
   hit this. Belt and braces for whichever section ends up last. */
.at-section:has(+ .join-cta),
.at-section:has(+ .at-campaigns) {
  padding-bottom: var(--spacing-5xl);
}
.at-faq .bill-row__body ul { margin: var(--spacing-xs) 0 0; padding-left: var(--spacing-lg); }
.at-faq .bill-row__body ul ul { margin: var(--spacing-2xs) 0 var(--spacing-xs); }

/* --- Special event — reuses .conference-callout from site.css --------------- */
.at-event .conference-callout .copy ul {
  margin: var(--spacing-sm) 0 var(--spacing-md);
  padding-left: var(--spacing-lg);
  font-size: var(--fs-small);
  display: grid;
  gap: var(--spacing-2xs);
}
.at-event__when { font-weight: var(--fw-strong-body); color: var(--ccl-black); }

/* --- Three-stat variant of the stats grid ----------------------------------- */
/* WordPress's FLOW layout (.is-layout-flow, which every Group gets) adds
   `> * + * { margin-block-start: 24px }` to space stacked children. These
   containers are grids or flex rows where `gap` already does that -- but the
   flow margin still applies, and it SKIPS the first child. So every column
   except the first sat 24px lower than its neighbours: the stat figures looked
   staggered even though all three cells are identical.

   Same bug and same fix as .related__grid in patterns.css. It only shows up in
   WordPress, never in the prototype, because the prototype has no flow layout. */
.at-about__grid > * + *,
.at-features__grid > * + *,
.at-stats__grid > * + *,
.at-resources__groups > * + *,
.at-campaign-grid > * + *,
.at-blog__grid > * + *,
.ccl-gallery > * + *,
.people > * + * {
  margin-block-start: 0;
}

.at-stats__grid--three { grid-template-columns: repeat(3, 1fr); gap: var(--spacing-2xl); }
.at-stats__grid--three .at-stat__n { font-size: 72px; }
@media (max-width: 900px) { .at-stats__grid--three { grid-template-columns: 1fr; } }

/* ==========================================================================
   BRAND-INTENSITY tiers (see DESIGN-SYSTEM-FEEDBACK.md §7)
   Everything above is the MEDIUM default — the "normal" website baseline:
   gradient stat figures, soft brand-tinted campaign band, brand resource icons,
   Ubuntu captions. The two attributes dial it down or up:
     LOW  →  <body data-intensity="low">    Congress / right-of-center / funders
     HIGH →  <body data-intensity="vivid">  youth / affinity teams
   ========================================================================== */

/* ---- LOW: professional / institutional — consolidate to navy, drop the
   gradient + warm tints; keep the functional brand icons. ------------------- */
.is-style-at-low .at-stat__n {            /* solid figures (undo gradient) */
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--ccl-blue-dark);
}
.is-style-at-low .at-campaigns { background: var(--grey-100); } /* neutral band */
/* Both spellings: the prototype only has the bare .eyebrow-blue, but this theme
   also exposes it as a block style (.is-style-eyebrow-blue) and that IS what the
   patterns emit -- so the ported selector matched nothing. Same below for vivid. */
.is-style-at-low .eyebrow-blue,
.is-style-at-low .is-style-eyebrow-blue { color: var(--ccl-blue-dark); } /* navy eyebrows (keep the functional icons) */

/* ---- HIGH ("vivid"): turn colour / texture / handwriting up --------------- */
/* Hero eyebrow → blue→green gradient text */
.at-vivid .at-hero__copy .eyebrow-blue,
.at-vivid .at-hero__copy .is-style-eyebrow-blue {
  background: var(--gradient-blue-green);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  width: fit-content;
}
/* Hero wash → add a faint notebook-grid texture */
.at-vivid .at-hero {
  background-color: var(--brand-lightest);
  background-image:
    linear-gradient(rgba(0,129,199,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,129,199,.05) 1px, transparent 1px),
    linear-gradient(186deg, #fff 12.5%, var(--ccl-blue-bg) 29.7%, var(--brand-lightest) 79.4%);
  background-size: 26px 26px, 26px 26px, 100% 100%;
}
/* Member captions → handwriting */
.at-vivid .at-feature__name {
  font-family: var(--font-hand);
  font-weight: 400;
  font-size: 28px;
  line-height: 1.1;
  color: var(--ccl-blue);
}
/* Campaign band → saturated green→blue wash + grid texture */
.at-vivid .at-campaigns {
  background-color: #E1EFCB;
  background-image:
    linear-gradient(rgba(0,129,199,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,129,199,.05) 1px, transparent 1px),
    linear-gradient(135deg, rgba(155,194,59,.32) 0%, rgba(0,129,199,.24) 100%);
  background-size: 28px 28px, 28px 28px, 100% 100%;
}

/* ---- The Youth page's vivid pieces (patterns/youth-action-team-page.php) --
   Ported from action-team-youth-vivid.html's page-local <style>. All scoped
   to .at-vivid, so the medium/low Action Team pages are untouched. Images are
   CSS backgrounds (tape, arrow, megaphone): decoration an editor can't delete
   or misplace. Asset URLs are root-relative, like .hdr-underline's, so they
   resolve in the editor canvas too. */

/* Hero: the cutout pair stands on the band's bottom edge — no bottom padding,
   and the photo pinned to the foot of the copy column (.at-hero__main). The
   cutout (outline, burst lines, sparkles, globe baked in) is a plain image at
   its own shape, not the default 16:10 crop. It fills the column up to 760px:
   any smaller left a tall empty gap under the copy, since the join card sets
   the band's height. */
.at-vivid .at-hero { padding-bottom: 0; }
.at-vivid .at-hero__main { display: flex; flex-direction: column; align-self: stretch; }
.at-vivid .at-hero__photo.wp-block-image {
  margin-top: auto;
  padding-top: var(--spacing-xl);
  max-width: 760px;
  aspect-ratio: auto;
  border-radius: 0;
  overflow: visible;
}
.at-vivid .at-hero__photo.wp-block-image img { position: static; width: 100%; height: auto; border-radius: 0; }

/* Kraft-tape label in place of the eyebrow — handwritten, title case (a
   script face reads as shouting when tracked out in caps). */
.at-vivid .at-tape-label {
  display: inline-block;
  margin: 0;
  padding: 12px 28px;
  font-family: var(--font-hand);
  font-weight: 400;
  font-size: 28px;
  line-height: 1.2;
  letter-spacing: 0.01em;
  color: var(--ccl-black);
  background: url('/wp-content/themes/twentytwentyfive-child/assets/brand/tape-kraft.webp') center / 100% 100% no-repeat;
  transform: rotate(-1.5deg);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .12));
}
@media (max-width: 600px) {
  .at-vivid .at-tape-label { white-space: nowrap; font-size: 22px; padding: 9px 20px; }
}

/* Kraft tape on the join card. The hero's bottom padding moves onto the
   card: the cutout stays on the band's edge, but the card (often the taller
   column) keeps the standard hero's breathing room below it. */
.at-vivid .at-form-card { position: relative; margin-bottom: var(--spacing-4xl); }
.at-vivid .at-form-card::before {
  content: '';
  position: absolute;
  top: -16px;
  left: 50%;
  width: 150px;
  height: 34px;
  transform: translateX(-50%) rotate(-3deg);
  background: url('/wp-content/themes/twentytwentyfive-child/assets/brand/tape-kraft.webp') center / cover no-repeat;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .12));
  pointer-events: none;
}

/* "Start here" nudge — a paragraph at the top of the join card, hung in the
   column gap with the brand arrow pointing into the card. Hidden once the gap
   is too narrow to hold it. */
.at-vivid .at-form-card > .at-nudge {
  position: absolute;
  right: calc(100% + var(--spacing-sm));
  top: -6px;
  width: 112px;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-family: var(--font-hand);
  font-size: 26px;
  line-height: 1;
  color: var(--ccl-black);
  white-space: nowrap;
  pointer-events: none;
}
.at-vivid .at-form-card > .at-nudge::after {
  content: '';
  width: 64px;
  aspect-ratio: 284 / 352;
  margin: 4px 18px 0 0;
  background: url('/wp-content/themes/twentytwentyfive-child/assets/brand/marks/arrow-point-right.svg') center / contain no-repeat;
}
@media (max-width: 1180px) { .at-vivid .at-form-card > .at-nudge { display: none; } }

/* Hero stack (≤1000px): copy, then the form, then the cutout closing the band. */
@media (max-width: 1000px) {
  .at-vivid .at-hero__main { display: contents; }
  .at-vivid .at-hero__copy { order: 1; }
  .at-vivid .at-form-card { order: 2; margin-bottom: 0; }
  .at-vivid .at-hero__photo.wp-block-image { order: 3; margin: 0 auto; padding-top: 0; max-width: 520px; }
}

/* Megaphone doodle hung off the campaigns title's left edge, so the centred
   title stays centred. Its bolt is a white stroke — the hairline shadow keeps
   it visible on the light band. */
.at-vivid .at-campaigns__title { position: relative; display: inline-block; }
.at-vivid .at-campaigns__title::before {
  content: '';
  position: absolute;
  right: calc(100% + var(--spacing-sm));
  top: 50%;
  width: 76px;
  aspect-ratio: 389 / 400;
  background: url('/wp-content/themes/twentytwentyfive-child/assets/brand/doodles/megaphone.webp') center / contain no-repeat;
  transform: translateY(-62%) rotate(-14deg);
  filter: drop-shadow(0 0 .6px rgba(0, 0, 0, .55));
  pointer-events: none;
}
@media (max-width: 760px) {
  .at-vivid .at-campaigns__title::before { position: static; display: block; width: 60px; margin: 0 auto var(--spacing-xs); transform: rotate(-14deg); }
}

/* ==========================================================================
   TAKE ACTION ISSUE PAGES
   The per-issue "write Congress" pages under Volunteer → Current Actions
   (take-action-page starter + its section patterns). Ported from the
   prototype's take-action-{permitting,sequoias,forest-service}.html, whose CSS
   is page-local (an inline <style>), not in the prototype's site.css — so
   bin/css-drift.sh can't see these. Diff against those pages by hand.

   Renames from the prototype, so nothing collides with existing components:
     .band / .wrap / .sec-head   → .section-band / __inner / .section-header
     .pillars / .pillar          → Photo tiles (.photo-tiles) with the
                                   .photo-tile__icon modifier
     .carbon-note                → .closing-note
     .explain / __item           → .explainer-steps / .explainer-step
                                   (photos, not icons — see the pattern)
     .talk__grid / __aside       → .talking-points / __aside
     .story__grid / .tl-item     → .story-timeline + the CCL Timeline
                                   block, "Compact steps" style
     .talk__aside .tip           → .info-pill.info-pill--tip
     .talk__list li (h4 + p)     → an ordered core List, .talking-points__list
     .hero (workhorse)           → .hero-t1.hero-t1--action (it IS the T1)
     .widget (mock form)         → .action-widget (the real CongressWeb iframe)
   TYPE follows the theme, not the prototype (Alaina, 2026-09-28): body copy is
   the canonical `p` (19px --fs-body, --fg2), prose links are the canonical
   `p > a` rule, headings are their tag's own style (tag = size: no .h1-bold,
   no shrunken h3s), the "Step N" label is Eyebrow green,
   captions are the figcaption spec. The prototype's 15.5–22px one-offs and
   grey-500 body text are NOT ported; nothing here restates body type.

   The prototype's --accent / --accent-inkable / --accent-tint are its "green"
   accent: --brand / --brand-dark / --brand-lightest here. The "blue" accent
   tweak wasn't used by any page and isn't ported.

   Grid/flex children below zero their margins at (0,2,0): they sit in
   flow-layout Groups, whose block gap (`:root :where(.is-layout-flow) > *`,
   0,1,0) would otherwise push every item after the first out of line. Any
   margin a child DOES want is then written at (0,2,1) or more, with the
   component's parent class in front, or the reset beats it.
   ========================================================================== */

/* --- Section band ----------------------------------------------------------
   A full-width section with the prototype's vertical rhythm (84px there; the
   80px step here). Background is the Group's own Color → Background, not a
   modifier class, so an editor can re-alternate bands after removing one.
   __inner is the alignwide (1166px) column. Bands butt against each other:
   no block gap between them. */
.wp-block-group.section-band {
  margin-block: 0;
  padding: var(--spacing-5xl) var(--page-gutter);
}
.section-band .section-header {
  padding: 0;
  margin-bottom: 44px;
}
/* Section headings are plain h2s (the tag's own style — no .h1-bold); this is
   only the eyebrow→heading spacing .section-header gives .h1-bold. */
.section-band .section-header h2 { margin-top: 0; margin-bottom: var(--spacing-sm); }
.section-band .section-header.is-style-left { max-width: 760px; }
.section-band .section-header .body-lead { margin: var(--spacing-md) 0 0; }
.section-band__inner > .body-lead,
.section-band__inner > p { max-width: 760px; }
/* Navy — the "billboard moment" band (the impact-navy mock; replaces the old,
   unused .ccl-stats--navy). Chosen in the editor as Color → Background →
   Gradient → Dark Blue, the theme.json preset; the grey version is just the
   Grey 100 background colour. Type flips to white; the stat numbers keep their
   green offset. */
.section-band.has-dark-blue-gradient-background :is(h2, h3, .ccl-stat-num),
.section-band.has-dark-blue-gradient-background .ccl-stat-label { color: #fff; }
.section-band.has-dark-blue-gradient-background p:not([class*="eyebrow"]) { color: rgba(255, 255, 255, 0.85); }
.section-band.has-dark-blue-gradient-background .is-style-eyebrow-green { color: var(--brand-medium); }

/* --- Hero: T1 with the CongressWeb tool in the slot -------------------------
   Proportions are the prototype's workhorse hero; the rest (padding, blue
   offset, stacking) is the T1's own. The headline is the standard .display —
   the prototype's smaller 50px isn't ported. */
/* The prototype's hero sits in the same 1200px .wrap as the bands under it, so
   its copy lines up with theirs. The T1 elsewhere runs to the page gutter; here
   the gutter grows to meet the 1166px column (below that, it's the gutter).
   `100%` is the post content's box, which is the root padding narrower on each
   side than this full-bleed hero, so the root padding is added back to get the
   hero's own width. */
.hero-t1.hero-t1--action {
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1fr);
  padding-inline: max(
    var(--page-gutter),
    calc((100% + var(--wp--style--root--padding-left, 0px) + var(--wp--style--root--padding-right, 0px) - var(--wp--style--global--wide-size, 1166px)) / 2)
  );
}
/* Restate the T1's one-column stack: the two-class rule above outranks it. */
@media (max-width: 900px) {
  .hero-t1.hero-t1--action { grid-template-columns: minmax(0, 1fr); }
}
/* An issue page built before its CongressWeb action exists: the block has no
   letter group ID, so on the live page it outputs nothing, and the slot would
   be an empty blue box. :not(:has(*)) is "no elements inside" (whitespace
   doesn't count, unlike :empty). Drop the slot and let the copy have the row.
   The row rule says the same thing without nesting :has() (browsers drop a
   rule that nests it): "no element inside the slot". In the editor the block
   shows its "set a letter group ID" notice, so the slot isn't empty there. */
.hero-t1--action .hero-t1__media--bare:not(:has(*)) { display: none; }
.hero-t1.hero-t1--action:not(:has(> .hero-t1__media--bare *)) { grid-template-columns: minmax(0, 1fr); }
/* The CongressWeb websticker (acf/ccl-action-widget). The iframe is
   cross-origin, so all we style is its frame: rounded, clipped, above the T1's
   blue offset. The placeholder is the editor preview (and the "no ID yet"
   state), sized like the websticker so the hero lays out as it will live. */
.action-widget {
  position: relative;
  z-index: 1;
  width: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  clip-path: inset(0 round var(--radius-lg));
}
.action-widget iframe { display: block; width: 100%; border: 0; }
.action-widget__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 460px;
  padding: var(--spacing-lg);
  background: #fff;
  border: 1px dashed #c3c4c7;
  border-radius: var(--radius-lg);
  text-align: center;
}
.action-widget__placeholder p { margin: 0; font-size: 13px; color: #646970; }

/* Featured action block (acf/ccl-featured-action) — it renders the chosen
   issue page's own hero, so it has no styles of its own; this is only the
   editor notice when no page is picked (or the page has no hero). */
.featured-action__notice {
  padding: var(--spacing-lg);
  border: 1px dashed #c3c4c7;
  border-radius: var(--radius-md);
  text-align: center;
}
.featured-action__notice p { margin: 0; font-size: 13px; color: #646970; }

/* --- Issue pillars + closing note ------------------------------------------
   The pillars ARE Photo tiles (.photo-tiles / .photo-tile, with the
   .photo-tile__icon modifier beside those rules): an explanatory trio with no
   per-item link, so tiles, not cards. Inside a band the row takes the band's
   column rather than the pattern's 1100px, so it lines up with the header. */
.section-band .photo-tiles.wp-block-columns { max-width: none; }

.wp-block-group.closing-note {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 30px;
  padding: 30px 36px;
  background: var(--c-dec-1);
  border-radius: var(--radius-lg);
  color: #fff;
}
.wp-block-group.closing-note > * { margin: 0; }
.closing-note__icon.wp-block-image { flex: 0 0 auto; }
.closing-note__icon.wp-block-image img { width: 64px; height: 64px; }
.closing-note p { color: #fff; }
.closing-note strong,
.closing-note b { color: var(--brand-medium); }
@media (max-width: 620px) {
  .wp-block-group.closing-note { flex-direction: column; text-align: center; }
}

/* --- Stats band ------------------------------------------------------------
   The existing stat atoms; the prototype's 4-up drops to two columns on
   phones, where core Columns would otherwise stack them one per row. */
@media (max-width: 781px) {
  .section-band .ccl-stat-cols.wp-block-columns {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 44px;
  }
  .section-band .ccl-stat-cols.wp-block-columns > .wp-block-column { margin: 0; text-align: center; }
}

/* --- Explainer steps -------------------------------------------------------
   A photo beside each step (the pillars carry the page's icons). No card: the
   steps aren't links. "Step N" is a counter, so steps renumber when reordered.
   The photos are forced to one ratio because they stack in a column and should
   line up; a step without a photo yet drops to a single text column. */
.explainer-steps {
  display: grid;
  gap: var(--spacing-2xl);
  counter-reset: explainer-step;
}
.explainer-steps > .explainer-step { margin: 0; }
.explainer-step {
  counter-increment: explainer-step;
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: var(--spacing-2xl);
  align-items: center;
}
.explainer-step:not(:has(.explainer-step__photo img[src])) { grid-template-columns: minmax(0, 1fr); max-width: 760px; }
.explainer-step:not(:has(.explainer-step__photo img[src])) .explainer-step__photo { display: none; }
.explainer-steps .explainer-step > * { margin: 0; }
.explainer-step__photo.wp-block-image img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-md);
}
/* The label is an Eyebrow green — its selector is added to the eyebrow rules
   rather than restated here. */
.explainer-step__text::before { content: "Step " counter(explainer-step); }
.explainer-steps .explainer-step__text > * { margin: 0; }
.explainer-step__text { max-width: 680px; }
.explainer-steps .explainer-step__text h3 { margin-bottom: var(--spacing-xs); }
@media (max-width: 680px) {
  .explainer-step { grid-template-columns: minmax(0, 1fr); gap: var(--spacing-md); }
}

/* --- Talking points ------------------------------------------------------- */
.section-band__inner.talking-points {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 48px;
  align-items: start;
}
.section-band__inner.talking-points > * { margin: 0; }
@media (max-width: 900px) {
  .section-band__inner.talking-points { grid-template-columns: minmax(0, 1fr); gap: 28px; }
}
.talking-points__aside.wp-block-group > * { margin: 0; }
.talking-points__aside .is-style-eyebrow-green { margin-bottom: var(--spacing-sm); }
.talking-points__aside.wp-block-group h2 { margin-bottom: 18px; }
.talking-points__aside p:not([class*="eyebrow"]):not(.info-pill) { margin-bottom: 18px; }
/* The tips are an ordered core List (see the pattern): list semantics, not
   four h3s. Each item is a card with a counter badge; its bold first phrase is
   the title line, at the item-title size. The class rules beat the core
   List's prose defaults (:where(.wp-block-list), 0,0,0). */
.talking-points__list.wp-block-list {
  display: grid;
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: talking-point;
}
.talking-points__list.wp-block-list > li {
  counter-increment: talking-point;
  position: relative;
  margin: 0;
  padding: 20px 22px 20px 74px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  font-size: var(--fs-small);
  line-height: calc(var(--lh-small) / var(--fs-small));
}
.talking-points__list.wp-block-list > li::before {
  content: counter(talking-point);
  position: absolute;
  left: 22px;
  top: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: var(--brand);
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--text-md);
  color: var(--ccl-green-darkest);
}
/* The title line: the item's leading bold phrase, set like an Item title. */
.talking-points__list.wp-block-list > li > strong:first-child {
  display: block;
  margin-bottom: var(--spacing-2xs);
  font-family: var(--font-display);
  font-weight: var(--fw-strong-heading);
  font-size: var(--fs-item-title, 24px);
  line-height: calc(var(--lh-item-title, 32px) / var(--fs-item-title, 24px));
  color: var(--fg2);
}

/* --- Story timeline --------------------------------------------------------
   Layout only: a sticky photo beside the site's CCL Timeline block in its
   "Compact steps" style (.pp-timeline.is-style-compact, styled with the
   timeline in PAST PROGRESS). The photo is a lone image: own shape, capped,
   per CLAUDE.md, not the prototype's forced 4:5. */
.story-timeline {
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: 52px;
  align-items: start;
}
.story-timeline > * { margin: 0; }
.story-timeline__media { position: sticky; top: 100px; }
.story-timeline__media.wp-block-group > * { margin: 0; }
.story-timeline__photo.wp-block-image img {
  display: block;
  width: 100%;
  height: auto;
  max-height: min(70vh, 620px);
  object-fit: cover;
  border-radius: var(--radius-lg);
}
@media (max-width: 920px) {
  .story-timeline { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .story-timeline__media { position: static; }
}

/* --- Video section (video-section pattern) --------------------------------
   A core Embed in the "Rounded (16:9)" style under a centered header, capped
   at the FAQ card's 880px so it reads as part of the section. */
.section-band .section-band__video.wp-block-embed {
  max-width: 880px;
  margin: 0 auto;
}

/* --- FAQ band: the standard accordion card, at the prototype's measure ---- */
.section-band--faq .ccl-accordion { max-width: 880px; margin-inline: auto; }

/* ==========================================================================
   SITE SEARCH — the search form (.site-search: the search page, the 404 page,
   the header's search panel), the search page (ccl/search-results in
   templates/search.html; its list is .search-hits, NOT .search-results —
   WordPress puts that class on <body> on every search page) and the 404 page (ccl/not-found in 404.html).
   The prototype has no search design; these are built from the theme's tokens
   and the Stories components they sit beside (.stories-hero for the header,
   .topic-cards for the section links, .pagination). Sizes lean large on
   purpose — our audience skews older: a 56px field with 18px text, a visible
   label, blue linked titles that read as links without hovering.
   ========================================================================== */
.site-search {
  width: min(880px, 100%);
  margin-inline: auto;
  text-align: start;
}
.site-search__label {
  display: block;
  margin: 0 0 var(--spacing-sm);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
  color: var(--ccl-black);
}
.site-search__row { display: flex; gap: var(--spacing-sm); }
.site-search__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 56px;
  padding: 0 18px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: #fff;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  color: var(--ccl-black);
}
/* The design system's field focus (tokens.css .input, .chapter-search__select):
   blue border + a soft halo, and no outline — the sitewide :focus-visible
   outline on top of it drew a second ring. */
.site-search__input { transition: border-color .15s ease, box-shadow .15s ease; }
.site-search__input:focus {
  outline: none;
  border-color: var(--ccl-blue);
  box-shadow: 0 0 0 3px rgba(0, 129, 199, 0.2);
}
.site-search__submit.btn { min-height: 56px; padding-inline: 28px; font-size: var(--fs-small); }
@media (max-width: 600px) {
  .site-search__row { flex-direction: column; }
  /* flex:none — in a column, flex:1 would size the field's HEIGHT from 0. */
  .site-search__input,
  .site-search__submit.btn { flex: none; width: 100%; height: 52px; min-height: 52px; }
}

/* ----- The search page ----- */
.search-page { padding-inline: var(--container-pad); }
.search-page__hero { margin-bottom: var(--spacing-xl); }
.search-page__count {
  width: min(880px, 100%);
  margin: var(--spacing-md) auto 0;
  font-size: var(--text-md);
  color: var(--grey-500);
}
.search-page--empty { padding-bottom: var(--spacing-2xl); }

.search-suggested,
.search-hits,
.search-empty,
.search-sections { width: min(880px, 100%); margin-inline: auto; }
.search-suggested { margin-top: var(--spacing-2xl); }
.search-hits { margin-top: var(--spacing-2xl); margin-bottom: var(--spacing-2xl); }
.search-hits__list { list-style: none; margin: 0; padding: 0; }

/* One result: where it lives, the linked title, a snippet, an optional image.
   The title link stretches over the row (::after), so the whole row is one
   click target, like the blog's post rows. */
.search-result {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-lg);
  padding: var(--spacing-lg) 0;
}
.search-hits__list > .search-result + .search-result { border-top: 2px solid var(--grey-200); }
.search-hits > .search-hits__list > .search-result:first-child { padding-top: 0; }
.search-result__copy {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}
.search-result__context {
  margin: 0;
  font-size: var(--text-md);
  line-height: 1.4;
  color: var(--grey-500);
}
.search-result__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
}
.search-result__title a { color: var(--fg-link-strong); text-decoration: none; }
.search-result__title a::after { content: ""; position: absolute; inset: 0; }
.search-result:hover .search-result__title a { text-decoration: underline; }
.search-result__title a:focus-visible { outline: none; }
.search-result__title a:focus-visible::after {
  outline: 2px solid var(--ccl-blue);
  outline-offset: 4px;
  border-radius: var(--radius-md);
}
.search-result__excerpt { margin: 0; color: var(--fg2); }
/* The words that matched (Relevanssi's <mark>): bold on a light green wash. */
.search-result__excerpt mark {
  padding: 0 2px;
  border-radius: 2px;
  background: var(--ccl-green-bg);
  color: inherit;
  font-weight: 700;
}
.search-result__image {
  flex: 0 0 200px;
  aspect-ratio: 16 / 9; /* the blog's one thumbnail shape */
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--grey-200);
}
.search-result__image img { display: block; width: 100%; height: 100%; object-fit: cover; }
.search-result--person .search-result__image { flex-basis: 96px; aspect-ratio: 1; border-radius: 50%; }
/* Phones: no thumbnails beside the copy — at this width they squeeze titles
   to three words a line. A person's small round photo stays. */
@media (max-width: 600px) {
  .search-result { gap: var(--spacing-md); }
  .search-result__image { display: none; }
  .search-result--person .search-result__image { display: block; flex-basis: 64px; }
}

/* Suggested pages: set apart on a light blue panel above the results. */
.search-suggested {
  padding: var(--spacing-md) var(--spacing-lg);
  border-radius: var(--radius-md);
  background: var(--ccl-blue-bg);
}
.search-suggested__label {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg-link-strong);
}
.search-suggested .search-result { padding: var(--spacing-sm) 0; }
.search-suggested .search-result + .search-result { border-top-color: rgba(0, 129, 199, .15); }

.search-empty { margin-top: var(--spacing-2xl); }
.search-empty h2 {
  margin: 0 0 var(--spacing-sm);
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
}
.search-empty ul { margin: 0; padding-left: 1.2em; }

/* "Or start from one of these": the menu's sections, as the blog's topic cards. */
.search-sections { margin-top: var(--spacing-2xl); margin-bottom: var(--spacing-4xl); }
.search-sections__heading {
  margin: 0 0 var(--spacing-md);
  font-size: var(--fs-h5);
  line-height: var(--lh-h5);
}
.search-sections .topic-cards { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); } /* the menu's five on one row; two a row on phones */
.search-sections .topic-card { justify-content: center; min-height: 64px; }
.search-sections .topic-card__name { font-weight: 700; color: var(--fg-link-strong); }

/* ----- 404 ----- */
.not-found__earth { display: block; width: 200px; height: auto; margin: 0 auto var(--spacing-lg); }
@media (max-width: 600px) { .not-found__earth { width: 150px; } }
.not-found__hero .eyebrow-blue { display: block; margin: 0 0 var(--spacing-sm); }
.not-found__hero h1 { font-size: var(--fs-h2); line-height: var(--lh-h2); }
.info-session-hero {
  max-width: 1024px;
  margin: var(--spacing-2xl) auto var(--spacing-3xl);
  padding: 0 var(--gutter);
  text-align: center;
}

.info-session-hero__lede {
font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.5;
  letter-spacing: -0.285px;
  color: var(--ccl-black) !important;
  margin: 0 0 var(--spacing-md);
  text-align: left;
}
.info-session-callout {
  background: var(--ccl-blue-bg);
  border-radius: var(--radius-xs);
  padding: var(--spacing-xl) var(--spacing-2xl);
  margin-top: var(--spacing-xl);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-sm);
}
.info-session-callout__title {
  font-family: var(--font-display);
  font-size: 24px !important;
  line-height: 1.3;
  letter-spacing: -0.36px;
  color: var(--ccl-black);
  margin: 0;
}

.info-session-callout__alt {
  margin: 0;
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.5;
  letter-spacing: -0.285px;
}
.info-session-split {
  max-width: 1208px;
  margin: 0 auto var(--spacing-3xl);
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--spacing-3xl);
  position: relative;
}
.info-session-split::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc((100% - var(--spacing-3xl)) * 2 / 3);
  width: 1px;
  background: var(--grey-200);
}

.info-session-learn__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.register-row {
  background: var(--grey-100);
  /* The row owns the screen edge (Full width), and this padding replaces core's
     global padding, so it needs side padding of its own: with 0 the card and
     the "Can't make it live?" copy touched the edges below ~1260px. */
  padding: var(--spacing-3xl) var(--page-gutter);
  margin: var(--spacing-2xl) 0;
}
.register-row__inner {
  max-width: 1208px;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 459px) 1fr;
  gap: var(--spacing-3xl);
  align-items: start;
}
.register-card {
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius-md);
  padding: var(--spacing-xl);
}
.info-session-faq {
  max-width: 1208px;
  margin: 0 auto var(--spacing-3xl) !important;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-xl) var(--spacing-3xl);
}

.info-session-faq__item h3 {
  margin: 0 0 var(--spacing-xs);
}
.info-session-faq__item p {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.5;
  letter-spacing: -0.285px;
  margin: 0;
}

/* Phones: the prototype's ≤900 rules, restated for the live page's markup.
   The split is a core Columns block set not to stack and the FAQ a core Group
   grid, so the prototype's grid rules don't reach them; .is-layout-* (core
   always prints it) lifts these over core's own layout rules. The register
   row's Columns stacks by itself. */
@media (max-width: 900px) {
  .info-session-split.wp-block-columns.is-layout-flex { flex-direction: column; }
  .info-session-split.wp-block-columns.is-layout-flex > .wp-block-column { flex-basis: auto; width: 100%; }
  .info-session-split::before { display: none; }
  .info-session-faq.is-layout-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Hide extras by default when a toggle exists */
.vv-chapters--has-extras:not(.is-expanded) .vv-chapter--extra {
  display: none;
}

.vv-chapters__toggle {
  display: block;
  margin: var(--spacing-xl) auto 0;
}

.join-split__form-title {
  font-family: var(--font-display);
  font-weight: var(--fw-weak);
  font-size: var(--fs-h3);
  line-height: calc(var(--lh-h3) / var(--fs-h3));
  color: var(--ccl-black);
  margin: 0 0 var(--spacing-xs);
}
.join-split__form-lede {
  font-family: var(--font-body);
  font-size: 19px;
  line-height: 1.5;
  color: var(--grey-600);
  margin: 0 0 var(--spacing-lg);
}

.fa-form-hold {
  background: var(--grey-0);
  background-image: none;
  padding: var(--spacing-xl);
  align-items: stretch;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  min-height: 520px;
  border-radius: var(--radius-lg);
  justify-content: center;
}
/* ==========================================================================
   VOLUNTEER QUIZ (Find Your Fit) — .fyf-*, built by assets/js/quiz.js
   from blocks/quiz. Layout = design direction "A3" on the design canvas:
   a reflection header with a "Your answers" panel, Thick rule separators,
   a compact action card, a grey Going deeper panel (chapter details left,
   state photo right), photo cards for support, a navy closing aside.
   Built from theme parts: .eyebrow-green, .hdr-underline, .btn-*, the Thick
   separator, .person__photo/.person__avatar, item-title headings.
   ========================================================================== */
.fyf__placeholder { margin: 0; padding: 12px 16px; border: 1px dashed #c3c4c7; border-radius: 6px; color: #646970; font-size: 13px; }
.fyf-result { display: flex; flex-direction: column; gap: var(--spacing-3xl); }
/* Matches the Thick style's own :not() pair so the flex gap does the spacing. */
.fyf-result .wp-block-separator.is-style-thick:not(.is-style-wide):not(.is-style-dots) { margin-block: 0; }
.fyf-result h2 { margin: 0; }
.fyf-result p { margin: 0; }

.fyf-result__head { display: flex; flex-wrap: wrap; gap: var(--spacing-xl) var(--spacing-3xl); align-items: center; }
.fyf-result__intro { flex: 3 1 460px; min-width: 0; display: flex; flex-direction: column; gap: var(--spacing-md); }
.fyf-result__intro .eyebrow-green { margin: 0; }
.fyf-result__reflect { font-size: 22px; line-height: 34px; color: var(--ccl-black); }
.fyf-answers { flex: 2 1 300px; min-width: 0; background: var(--grey-100); border-radius: var(--radius-lg); padding: var(--spacing-xl); display: flex; flex-direction: column; gap: var(--spacing-md); }
.fyf-answers dl { display: grid; grid-template-columns: auto 1fr; gap: 6px var(--spacing-md); margin: 0; font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); }
.fyf-answers dt { font-weight: 600; color: var(--grey-500); }
.fyf-answers dd { margin: 0; color: var(--ccl-black); }
.fyf-answers__change { font-size: var(--fs-small); }

/* Small caps labels: "Your answers", "This month's action", "Next call". */
.fyf-label,
.fyf-labels {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--fs-tiny);
  line-height: var(--lh-tiny);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #595959;
}
.fyf-labels { display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--spacing-sm); }
.fyf-date { display: inline-block; padding: 2px 12px; border-radius: var(--radius-pill); background: var(--ccl-blue-bg); color: var(--ccl-navy); font-weight: 700; font-size: 15px; line-height: 24px; letter-spacing: 0; text-transform: none; }

.fyf-section { display: flex; flex-direction: column; gap: var(--spacing-lg); }
.fyf-note { font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); color: var(--grey-500); }

/* Cards: the theme's bordered card (.team-card), photo flush. */
.fyf-card { background: #fff; border: 1px solid rgba(0,0,0,0.1); border-radius: var(--radius-md); overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.08), 0 4px 8px rgba(0,0,0,0.04); display: flex; flex-direction: column; }
.fyf-card__img { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.fyf-card__body { padding: var(--spacing-lg) var(--spacing-xl) var(--spacing-xl); display: flex; flex-direction: column; gap: var(--spacing-sm); flex: 1; }
.fyf-card__body h3 { margin: 0; }
.fyf-card__foot { margin-top: auto; padding-top: var(--spacing-xs); display: flex; flex-wrap: wrap; gap: var(--spacing-md) var(--spacing-xl); align-items: flex-end; }
.fyf-card__month { flex-basis: 100%; font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); }
.fyf-card__buttons { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); }
.fyf-card__month strong { color: var(--ccl-black); }

/* Full-width cards (the action card, other Now / Keep going cards): photo
   left, content right; stacks under 700px. */
.fyf-card--action,
.fyf-card--side { display: grid; grid-template-columns: 260px minmax(0, 1fr); }
.fyf-card--action.fyf-card--no-img,
.fyf-card--side.fyf-card--no-img { grid-template-columns: minmax(0, 1fr); }
.fyf-card--action .fyf-card__img,
.fyf-card--side .fyf-card__img { height: 100%; min-height: 180px; aspect-ratio: auto; }
.fyf-card--action .fyf-card__foot { border-top: 1px solid var(--grey-200); padding-top: var(--spacing-md); }
.fyf-campaign { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 10px; }

/* A number with its line: "331 of them from Texas", "63 outreach events…". */
.fyf-stat { display: flex; gap: 14px; align-items: baseline; font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); color: var(--ccl-text); }
.fyf-stat b { font-family: var(--font-display); font-weight: 700; font-size: 30px; line-height: 1; color: var(--ccl-black); text-shadow: 2px 2px 0 var(--ccl-green); white-space: nowrap; }
.fyf-card__body > .fyf-stat { margin-top: auto; border-top: 1px solid var(--grey-200); padding-top: var(--spacing-sm); }
.fyf-bar { height: 8px; background: var(--grey-200); border-radius: 4px; overflow: hidden; }
.fyf-bar span { display: block; height: 100%; background: linear-gradient(90deg, var(--ccl-blue) 0%, var(--ccl-green) 100%); border-radius: 4px; }

.fyf-cards { display: grid; gap: var(--spacing-lg); grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); align-items: stretch; }

/* Grey panels: Going deeper, If more time opens up. */
.fyf-panel { background: var(--grey-100); border-radius: var(--radius-lg); padding: clamp(var(--spacing-lg), 4vw, var(--spacing-2xl)); display: flex; flex-direction: column; gap: var(--spacing-md); }
.fyf-panel--group { gap: var(--spacing-xl); }
.fyf-panel h3 { margin: 0; }
.fyf-panel__cols { display: grid; gap: var(--spacing-xl) var(--spacing-2xl); grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); align-items: stretch; }
.fyf-panel__cols--one { grid-template-columns: minmax(0, 1fr); }
.fyf-panel__text { display: flex; flex-direction: column; gap: var(--spacing-md); }
.fyf-panel__cta { margin-top: auto; padding-top: var(--spacing-xs); }
/* The state's photo fills the right column at whatever height the text sets. */
.fyf-panel__photo { position: relative; min-height: 280px; }
.fyf-panel__photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-md); display: block; }
/* Promo art carries text, so it's shown whole, not cropped. */
.fyf-panel__photo--art { min-height: 0; display: flex; align-items: center; }
.fyf-panel__photo--art img { position: static; height: auto; object-fit: contain; }
.fyf-next { background: #fff; border-radius: var(--radius-md); padding: var(--spacing-xl); display: flex; flex-direction: column; gap: var(--spacing-xs); justify-content: center; }
.fyf-next__date { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3); line-height: var(--lh-h3); color: var(--ccl-black); }
.fyf-chapters { font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); }
.fyf-chapters strong { color: var(--ccl-black); }
.fyf-chapters--many { display: flex; flex-direction: column; gap: 6px; font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); }

.fyf-people { display: flex; flex-direction: column; gap: var(--spacing-sm); padding-top: 4px; }
.fyf-people__row { display: flex; flex-wrap: wrap; gap: 14px 28px; }
.fyf-person { display: flex; gap: var(--spacing-md); align-items: center; }
.fyf-person--stack { flex-wrap: wrap; gap: var(--spacing-sm) var(--spacing-md); }
.fyf-person--stack p { font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); }
.fyf-person .person__photo,
.fyf-person .person__avatar { --person-photo: 64px; margin: 0; }
.fyf-person__name { font-family: var(--font-display); font-weight: 700; color: var(--ccl-black); font-size: var(--fs-body); line-height: 1.3; }
.fyf-person__role { font-size: var(--fs-small); line-height: var(--lh-small); }
/* Three or more coordinators: overlapping round faces, then names. */
.fyf-stack { display: flex; flex-shrink: 0; padding-left: 12px; }
.fyf-stack .person__photo,
.fyf-stack .person__avatar { --person-photo: 48px; margin: 0 0 0 -12px; border: 3px solid var(--grey-100); border-radius: var(--radius-pill); box-sizing: border-box; }

.fyf-company { background: var(--ccl-navy); color: #fff; border-radius: var(--radius-lg); padding: clamp(var(--spacing-xl), 5vw, var(--spacing-3xl)); display: flex; flex-direction: column; gap: 14px; }
.fyf-company h2 { color: #fff; font-size: var(--fs-h3); line-height: var(--lh-h3); }
.fyf-company p { max-width: 760px; color: #fff; }
.fyf-company a { color: #fff; font-weight: 600; }

@media (max-width: 700px) {
  .fyf-result { gap: var(--spacing-2xl); }
  .fyf-card--action,
  .fyf-card--side { grid-template-columns: minmax(0, 1fr); }
  .fyf-card--action .fyf-card__img,
  .fyf-card--side .fyf-card__img { height: auto; min-height: 0; aspect-ratio: 16 / 9; }
  .fyf-card__body { padding: var(--spacing-lg); }
  .fyf-result__reflect { font-size: 20px; line-height: 30px; }
}

/* ---- The questions: ported from the prototype's find-your-fit.html (.fyf-*),
   tokens translated (prototype --fs-h3 = theme --fs-h4; --gutter = --page-gutter).
   Intro band, then one white card (.fyf-step; .fyf-card is the result's
   item card) on a grey band: progress, the question,
   lettered options (rectangles, not pills: selectable surfaces, not actions),
   Back / Next. The band goes full width inside the block's own width. */
.fyf-intro { max-width: 780px; margin: 0 auto; padding: 0 0 var(--spacing-xl); text-align: center; }
.fyf-intro h1 { margin: 0 0 var(--spacing-md); }
.fyf-intro .eyebrow-blue { margin-bottom: var(--spacing-sm); }
.fyf-intro__lead { font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); color: var(--fg3); margin: 0 auto; max-width: 620px; }
.fyf-intro__meta { font-family: var(--font-body); font-weight: var(--fw-strong-body); font-size: var(--fs-tiny); line-height: calc(var(--lh-tiny) / var(--fs-tiny)); letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-muted); margin: var(--spacing-md) 0 0; }
.fyf-band { background: var(--grey-100); border-radius: var(--radius-lg); padding: var(--spacing-3xl) var(--page-gutter) var(--spacing-5xl); }
.fyf-step { max-width: 720px; margin: 0 auto; background: #fff; border: 1px solid rgba(0, 0, 0, 0.10); border-radius: var(--radius-lg); box-shadow: var(--shadow-card); padding: var(--spacing-2xl); }
.fyf-progress { background: var(--grey-200); border-radius: var(--radius-pill); height: 6px; overflow: hidden; margin-bottom: var(--spacing-lg); }
.fyf-progress__fill { height: 100%; width: 0; background: var(--gradient-underline); border-radius: var(--radius-pill); transition: width .45s ease; }
.fyf-meta { font-family: var(--font-body); font-weight: var(--fw-strong-body); font-size: var(--fs-tiny); line-height: calc(var(--lh-tiny) / var(--fs-tiny)); letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-muted); margin: 0 0 var(--spacing-xs); }
/* The question and the result title take focus when the step changes, so
   screen readers and keyboards land on the new content. No ring for that
   programmatic focus; :focus-visible still shows one. */
.fyf-question:focus:not(:focus-visible),
.fyf-result__title:focus:not(:focus-visible) { outline: none; }
.fyf-question { font-family: var(--font-display); font-weight: var(--fw-strong-heading); font-size: var(--fs-h4); line-height: calc(var(--lh-h4) / var(--fs-h4)); color: var(--ccl-black); margin: 0 0 var(--spacing-lg); }
.fyf-hint { margin: calc(-1 * var(--spacing-md)) 0 var(--spacing-md); font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); color: var(--fg-muted); }
.fyf-options { display: flex; flex-direction: column; gap: var(--spacing-xs); }
.fyf-option { display: flex; align-items: flex-start; gap: var(--spacing-sm); width: 100%; text-align: left; background: #fff; border: 1.5px solid var(--grey-200); border-radius: var(--radius-sm); padding: var(--spacing-sm) var(--spacing-md); font-family: var(--font-body); font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); color: var(--fg2); cursor: pointer; transition: border-color .15s ease, background-color .15s ease; }
.fyf-option:hover:not(:disabled) { border-color: var(--ccl-blue); background: var(--ccl-blue-bg); }
.fyf-option:focus-visible { outline: none; border-color: var(--ccl-blue); box-shadow: 0 0 0 3px rgba(0, 129, 199, 0.25); }
.fyf-option[aria-pressed="true"] { border-color: var(--ccl-green-dark); background: var(--ccl-green-bg); }
.fyf-option:disabled { opacity: .5; cursor: not-allowed; }
.fyf-option__letter { font-weight: var(--fw-strong-body); font-size: var(--fs-tiny); color: var(--ccl-blue); min-width: 14px; margin-top: 3px; flex-shrink: 0; }
.fyf-option[aria-pressed="true"] .fyf-option__letter { color: var(--ccl-green-dark); }
.fyf-select { width: 100%; font: inherit; font-size: var(--fs-body); padding: var(--spacing-sm) var(--spacing-md); border: 1.5px solid var(--grey-300); border-radius: var(--radius-sm); background: #fff; color: var(--fg2); }
.fyf-select:focus-visible { outline: none; border-color: var(--ccl-blue); box-shadow: 0 0 0 3px rgba(0, 129, 199, 0.25); }
.fyf-fact { display: grid; grid-template-rows: 0fr; opacity: 0; margin-top: var(--spacing-md); transition: grid-template-rows .35s ease, opacity .25s ease; }
.fyf-fact.is-open { grid-template-rows: 1fr; opacity: 1; }
.fyf-fact__clip { overflow: hidden; }
.fyf-fact__inner { margin: 0; background: var(--ccl-green-bg); border-left: 4px solid var(--ccl-green-dark); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; padding: var(--spacing-sm) var(--spacing-md); font-size: var(--fs-body); line-height: var(--wp--custom--line-height--body); color: var(--brand-darkest); }
.fyf-nav { display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-md); margin-top: var(--spacing-lg); }
.fyf-nav .btn { min-width: 0; }
.fyf-nav__back { visibility: hidden; }
.fyf-nav__back.is-shown { visibility: visible; }
.fyf-quiz[hidden] { display: none; }
.fyf__noscript { margin: 0; padding: var(--spacing-lg); background: var(--grey-100); border-radius: var(--radius-md); }

@media (max-width: 600px) {
  .fyf-band { padding: var(--spacing-lg) var(--spacing-sm) var(--spacing-3xl); border-radius: var(--radius-md); }
  .fyf-step { padding: var(--spacing-lg); }
  /* column-reverse against DOM order [Back, Next] puts Next on top, under the thumb. */
  .fyf-nav { flex-direction: column-reverse; align-items: stretch; }
  .fyf-nav .btn { width: 100%; }
  .fyf-nav__back:not(.is-shown) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .fyf-progress__fill, .fyf-fact { transition: none; }
}

/* Editor preview panel (logged-in editors only). */
.fyf-preview { margin: 0 0 var(--spacing-3xl); padding: var(--spacing-lg); border: 2px dashed var(--ccl-blue); border-radius: var(--radius-md); background: var(--ccl-blue-bg); font-size: 16px; line-height: 1.4; }
.fyf-preview summary { cursor: pointer; }
.fyf-preview form { margin-top: var(--spacing-md); }
.fyf-preview__grid { display: grid; gap: var(--spacing-md); grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); }
.fyf-preview label { display: flex; flex-direction: column; gap: 4px; font-weight: 600; }
.fyf-preview select,
.fyf-preview input[type="date"] { font: inherit; font-weight: 400; padding: 6px 8px; }
.fyf-preview fieldset { grid-column: 1 / -1; margin: 0; padding: var(--spacing-sm) var(--spacing-md); border: 1px solid var(--grey-300); border-radius: var(--radius-sm); display: flex; flex-wrap: wrap; gap: 6px var(--spacing-lg); }
.fyf-preview legend { font-weight: 600; padding: 0 4px; }
.fyf-preview .fyf-preview__check { flex-direction: row; align-items: center; gap: 6px; font-weight: 400; }
.fyf-preview__empty { padding: var(--spacing-xl); }
