/**
 * Fulton Dems — supplemental styles.
 * Everything theme.json cannot express: hover motion, focus rings, the accent
 * mechanic (--fd-accent / --fd-accent-deep, injected per-region by the
 * fulton-dems-core render_block filter), header/footer chrome, and block-style
 * variants. Tokens come from theme.json presets — never hardcode brand hex here.
 */

/* ---- Base ---------------------------------------------------------------- */

a:focus-visible,
button:focus-visible,
input:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var(--wp--preset--color--sky);
	outline-offset: 2px;
}

body {
	-webkit-font-smoothing: antialiased;
}

/* Full-bleed sections stack flush: kill the root block gap between template-level
   blocks and between the section groups inside main. Sections own their spacing
   via padding.

   The third selector matters. When the front page moved from rendering a pattern
   inline to rendering wp:post-content, WordPress wrapped the sections in
   `div.wp-block-post-content.is-layout-flow` — so they stopped being direct
   children of `main` and the rule above stopped reaching them. Core's 24px flow
   gap came back, and on full-bleed coloured bands that reads as a paper-coloured
   seam between every section.

   Matching the wrapper's children rather than `main > * > * + *` on purpose:
   this should apply to the post-content level and nowhere deeper. */
body .wp-site-blocks > * + *,
main.wp-block-group > * + *,
main.wp-block-group > .wp-block-post-content > * + * {
	margin-block-start: 0;
}

/* Uppercase tracked label (eyebrows, field labels, captain cities). */
.fd-eyebrow {
	text-transform: uppercase;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--eyebrow);
}

/* Hover lift for cards and tiles. */
.fd-lift {
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.fd-lift:hover {
	transform: translateY(-4px);
	box-shadow: var(--wp--preset--shadow--lift);
}

/* Make the lift affordance true (P1-1).
   `.fd-lift` promises a click: the card rises on hover and casts a shadow. On 14 cards across
   /get-involved/, /how-to-vote/ and /voting-guides/ it was a <div>, so the promise was false —
   only the small "Open →" link at the bottom actually did anything.

   The link is stretched over the card instead of the affordance being removed, because every
   one of those 14 cards contains exactly ONE link, so there is no ambiguity about where the
   card goes. It also enlarges a small text link into a card-sized target, which is the same
   problem P2-14 is about.

   `:not(a)` matters: `.fd-lift` is also worn by `<a class="fd-doc-card fd-lift">`, which is
   already a link end to end. Stretching a child link inside an anchor would nest clickable
   areas for no gain. */
.fd-lift:not(a) {
	position: relative;
}
.fd-lift:not(a) .fd-arrow-link::after {
	content: "";
	position: absolute;
	inset: 0;
	/* Above the card's own background, below anything that needs its own click. Nothing in
	   these cards does today — that is the precondition checked before writing this. */
	z-index: 1;
}

.fd-arrow-link {
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	gap: 6px;
}
.fd-arrow-link:hover {
	gap: 10px;
}

/* ---- Header -------------------------------------------------------------- */

/* No backdrop-filter here: a filter on the header creates a containing block
   that traps the nav block's position:fixed mobile overlay inside the header
   strip. At 0.97 alpha the blur was invisible anyway. */
.fd-header {
	background: rgba(22, 41, 57, 0.97);
	border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.fd-header__brand-name {
	font-weight: 800;
	font-size: var(--wp--preset--font-size--body);
	color: var(--wp--preset--color--snow);
	letter-spacing: -0.01em;
	line-height: 1;
}
.fd-header__brand-sub {
	font-weight: 600;
	font-size: 0.62rem;
	/* Mist, not Stone. Stone on the header navy measured 1.93:1 against the
	   sticky ground and 2.43:1 against the scrolled one, both far under the 4.5
	   floor for 9.9px text — the Muted Split Rule the footer already follows
	   correctly. Mist gives 8.72:1 and 10.98:1 respectively. */
	color: var(--wp--preset--color--mist);
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	text-transform: uppercase;
	line-height: 1;
}

.fd-header__brand-name a {
	color: var(--wp--preset--color--snow);
	text-decoration: none;
}

/* Compact icon-only search button on the dark header. */
.fd-header__search .wp-block-search__button {
	background: rgba(255, 255, 255, 0.05);
	border: 1.5px solid rgba(255, 255, 255, 0.18);
	border-radius: var(--wp--custom--radius--pill);
	color: var(--wp--preset--color--mist);
	padding: 8px 14px;
	transition: border-color 0.18s ease;
}
.fd-header__search .wp-block-search__button:hover {
	border-color: var(--wp--preset--color--sky);
}

/* Nav row sits on a darker strip, like the prototype. */
.fd-header__nav-row {
	border-top: 1px solid rgba(255, 255, 255, 0.08);
	/* navy-deep (#0E1C28) at 39%, not black at 16%. Black is not in the palette —
	   the darkest entry is ink #10202E — and a neutral overlay greys the navy it
	   sits on rather than deepening it. Alpha chosen by compositing against the
	   real stack (paper -> header at 97% -> this strip): it reproduces the former
	   colour to within 1.16/255 on the worst channel, so nothing shifts visually. */
	background: rgba(14, 28, 40, 0.39);
}

/* Navigation block: top-level links. */
.fd-header .wp-block-navigation .wp-block-navigation-item__content {
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	text-decoration: none;
	transition: color 0.18s ease;
	padding: 15px 15px;
}
.fd-header .wp-block-navigation .wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--snow);
}
.fd-header .wp-block-navigation .wp-block-navigation__submenu-icon {
	color: var(--wp--preset--color--mist);
}

/* Dropdown panel. A floating menu earns a shadow for separation, but a narrow
   one (card, not the 30px lift) reads cleaner beside its hairline than the
   thin-border + wide-shadow "AI panel" combo.

   The `.has-child` is defensive: core's navigation stylesheet declares
   `background: inherit` at the same specificity, and matching core's own
   `.has-child` outranks it so this wins on specificity rather than on load
   order. Order alone would in fact be enough on the front end — both sheets are
   in the head and this one is printed last — but the editor canvas
   (add_editor_style) is a separate cascade and a CSS-combine on staging can
   reorder, and specificity holds in all three. */
.fd-header .wp-block-navigation .has-child .wp-block-navigation__submenu-container {
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--card);
	padding: 8px;
	min-width: 234px;
}
.fd-header .wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	padding: 9px 14px;
	border-radius: var(--wp--custom--radius--sharp);
	white-space: nowrap;
	transition: background 0.14s ease, color 0.14s ease;
}
.fd-header .wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--sky-deep);
}

/* Mobile nav. The core hamburger/close buttons inherit the page ink color —
   invisible on the dark strip — and the overlay inherits no background. Snow
   buttons, full-screen navy overlay, submenus flattened to an indented list
   (the white dropdown card is a desktop treatment).

   The overlay is painted here rather than with the nav block's
   overlayBackgroundColor/overlayTextColor attrs: core stamps those onto the
   submenu containers too, as `.has-navy-background-color`, which global styles
   declare `!important` — that repaints the desktop dropdown navy and no
   ordinary rule can outrank it. */
.fd-header .wp-block-navigation__responsive-container-open {
	color: var(--wp--preset--color--snow);
	padding: 12px;
}
.fd-header .wp-block-navigation__responsive-container-close {
	color: var(--wp--preset--color--snow);
	padding: 10px;
}
/* Mirrors core's own `:not(.has-background)` overlay default so the two rules
   stay conditioned alike. WP 7.0 added `:not(.disable-default-overlay)` to
   core's white-overlay rule, which made it specificity-equal to this one — the
   extra `.fd-header__nav-row` restores a strict win rather than a source-order
   tie that a CSS-combine on staging could invert. The container is
   position:fixed when open but is still a DOM descendant of the nav row. */
.fd-header .fd-header__nav-row .wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open {
	background: var(--wp--preset--color--navy);
	padding: 72px 28px 28px;
}
.fd-header .is-menu-open .wp-block-navigation-item__content {
	font-size: var(--wp--preset--font-size--lede);
	padding: 10px 0;
}
/* Six classes deliberately: core flattens the overlay submenu at (0,5,0) with
   `padding-left/right: 2rem; min-width: 200px`, which beat this rule's previous
   (0,4,0) and rendered a 32px indent instead of 18px. Core also sets
   `padding-top` at (0,4,0) — an exact tie that only source order was deciding.
   (0,6,0) wins all three outright. */
.fd-header .fd-header__nav-row .wp-block-navigation .is-menu-open .has-child .wp-block-navigation__submenu-container {
	background: transparent;
	border: 0;
	box-shadow: none;
	padding: 0 0 8px 18px;
	min-width: 0;
}
.fd-header .is-menu-open .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--body);
	white-space: normal;
	padding: 8px 0;
}
.fd-header .is-menu-open .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover {
	background: transparent;
	color: var(--wp--preset--color--snow);
}

/* Mobile-nav breakpoint. Core defaults the nav block to overlayMenu:"mobile",
   which drops the hamburger at 600px — but these six items measure 656px and
   need ~710px of viewport before they sit on one row. Between 600px and 709px
   core had already taken the hamburger away while the menu was still wrapping
   to two rows, so there was no way to reach the nav at all. Hold the overlay
   treatment to 781.98px: the menu goes horizontal only at 782px (72px of
   headroom), reusing the same breakpoint as the grid rules at the end of this
   file, and matching WP's admin-bar breakpoint so the open overlay's close
   button clears the admin bar when logged in.

   Both rules outspecify core rather than relying on load order:
     core (0,2,0)  .wp-block-navigation__responsive-container-open:not(.always-shown)
     here (0,3,0)  .fd-header .wp-block-navigation .…-open
     core (0,3,0)  .…__responsive-container:not(.hidden-by-default):not(.is-menu-open)
     here (0,4,0)  .fd-header .wp-block-navigation .…-container:not(.is-menu-open)
   `:not(.is-menu-open)` stops the second rule matching the moment the overlay
   opens, so the open overlay keeps exactly the cascade it has already. Use
   781.98 rather than 781 so fractional viewports (zoom, non-integer DPR) can't
   land in a 1px gap with neither control. */
@media (max-width: 781.98px) {
	.fd-header .wp-block-navigation .wp-block-navigation__responsive-container-open {
		display: flex;
	}
	.fd-header .wp-block-navigation .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}
}

/* ---- Region hero ---------------------------------------------------------- */

/* .fd-hero is worn by SIX templates — home, page, archive, press-release
   archive, the regions archive and single-region. Everything shared stays here;
   the photo band is .fd-hero--photo below and must not leak.

   Adding the photo treatment to the base class broke the other five: the scrim
   painted a 0.94-alpha veil over their headings (white read as grey on "Find
   your region"), because `> * { position: relative }` is what lifts their
   content above the ::before layer and they have no .fd-hero__body to carry a
   z-index of their own. */
.fd-hero {
	position: relative;
	overflow: hidden;
	border-top: 6px solid var(--fd-accent, var(--wp--custom--accent-fallback));
}
.fd-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	background-image: var(--fd-map-watermark);
	background-repeat: no-repeat;
	background-position: right -80px center;
	background-size: 640px auto;
	opacity: 0.1;
	pointer-events: none;
}
.fd-hero > * {
	position: relative;
}

/* ---- Region hero: photo band (single-region only) ------------------------- */

/* The chapter photograph carries the band. The county-map watermark is
   suppressed here because the photograph occupies that layer; the 6px accent
   top border stays, being the only thing that tells the three chapters apart
   above the fold.

   THE SCRIM IS MEASURED, NOT CHOSEN. The mockup specified 0.95 across the text
   half, which rendered all three photographs as near-black rectangles — the band
   cost a photograph and delivered a texture. Measured against the brightest pixel
   actually visible under the text at the live band size (not an assumed white),
   snow clears AA at 0.58 and AAA at 0.72:

     north  rgb(249,243,231)  AA 0.58  AAA 0.72
     mid    rgb(241,246,249)  AA 0.57  AAA 0.71
     south  rgb(231,246,252)  AA 0.57  AAA 0.71

   0.72 holds AAA on the worst of the three with the photograph still legible;
   the right side falls to 0.30 because no text sits there. Re-measure if the
   photographs are replaced. */
.fd-hero--photo {
	background: var(--wp--preset--color--navy);
	isolation: isolate;
}
.fd-hero--photo::before {
	content: none;
}

/* Two classes deep on purpose, and it must stay that way.
   This figure is a `core/post-featured-image`, so THREE other rules declare
   `position` on it, all at 0,1,0:

     .wp-block-post-featured-image      relative   (WordPress core's own block CSS)
     .fd-hero > *                       relative   (line ~316, below)
     .wp-block-post-featured-image      relative   (line ~3531, the credit anchor)

   At equal specificity the last one wins, so when 105d5b4 appended the credit
   anchor to the end of this file the hero backdrop silently fell back into
   normal flow: the photograph became a ~1000px block and pushed <h1> to 1477px
   on /north-fulton/ and /mid-fulton/, 1355px on /south-fulton/ — below the fold
   on all three. /events/ uses the same class and was affected too.

   `.fd-hero .fd-hero__media` is 0,2,0 and beats all three regardless of source
   order, which matters because one of them is core's and its print position is
   an enqueue-order accident we do not control. Deleting the credit anchor would
   also "work" today for exactly that accidental reason; specificity is the fix
   that stays fixed. See the :where() at ~3531.

   NOTE for whoever credits a hero photograph one day: `z-index: 0` here creates
   a stacking context, so a .fd-photo-credit injected INSIDE this figure can
   never rise above .fd-hero--photo::after (z-index 1) and would render
   invisible under the scrim. Render hero credits as a sibling of
   .fd-hero__body instead. No hero photo carries a credit today. */
.fd-hero .fd-hero__media {
	position: absolute;
	inset: 0;
	margin: 0;
	z-index: 0;
}
.fd-hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Subjects sit around the middle of all three frames; biasing slightly up
	   keeps faces in shot when the band goes tall on a phone. */
	object-position: 50% 42%;
	display: block;
}

.fd-hero--photo::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: linear-gradient(
		100deg,
		rgba(14, 28, 40, 0.94) 0%,
		rgba(14, 28, 40, 0.72) 58%,
		rgba(14, 28, 40, 0.30) 100%
	);
}

.fd-hero__body {
	position: relative;
	z-index: 2;
}

/* The band turns portrait on a phone (0.58:1 at 390px), and a horizontal ramp
   then puts almost the whole photograph in its dark half — the image stops doing
   any work. Below the two-column breakpoint the ramp runs vertically instead, so
   the photograph reads at the top and the text sits on the dark floor.

   Both stops respect the same measured floors: 0.62 at the top clears the 0.58
   AA minimum for the snow tabs, 0.86 at the bottom is past the 0.72 AAA figure
   for the heading and body copy. */
@media (max-width: 782px) {
	.fd-hero--photo::after {
		background: linear-gradient(
			180deg,
			rgba(14, 28, 40, 0.62) 0%,
			rgba(14, 28, 40, 0.72) 38%,
			rgba(14, 28, 40, 0.86) 100%
		);
	}
	.fd-hero__media img {
		object-position: 50% 34%;
	}
}

/* The text stops well short of the right edge so the photograph has somewhere to
   be seen. The cap goes on the CHILDREN, not on .fd-hero__lede itself:
   constrained layout writes margin-left/right:auto !important onto its children,
   so capping the lede centred a 620px column in the middle of the band. */
.fd-hero__lede > * {
	max-width: 620px;
	margin-left: 0;
	margin-right: auto;
}

/* Accent carries as a RULE, not as the type. Measured against the composited
   band, the raw accent on this small uppercase text came out at 3.48:1 on North
   (sky) and 4.48:1 on Mid (peach) — both below 4.5:1. Only South (gold) passed,
   at 7.53:1. Snow is 9.2-9.8:1 on every chapter, and the 28px accent bar keeps
   the region cue. */
.fd-hero__kicker {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 10px;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	text-transform: uppercase;
	color: var(--wp--preset--color--snow);
}
.fd-hero__kicker::before {
	content: "";
	flex: none;
	width: 28px;
	height: 3px;
	/* Pill, not a literal 2px. At 3px tall the radius clamps to 1.5px either way,
	   so this renders identically — but 2px was a fifth value in a four-step
	   scale, and the only fifth value DESIGN.md sanctions is the square corner on
	   gala buttons. */
	border-radius: var(--wp--custom--radius--pill);
	background: var(--fd-accent, var(--wp--custom--accent-fallback));
}

/* One button plus text links, replacing four competing buttons. */
.fd-hero__actions {
	align-items: center;
	gap: 12px 22px;
}

/* These are core buttons, not a paragraph of links — "Join a committee" binds to
   fdc_join_url so each chapter sends volunteers to its own Google Form, and only
   core/button carries a url binding. theme.json gives every wp-element-button a
   sky-deep pill background, so it has to be undone here or three solid pills
   appear beside the one real primary action. */
.fd-hero__links {
	display: flex;
	flex-wrap: wrap;
	gap: 18px;
	margin: 0;
}
.fd-hero__links .wp-block-button,
.fd-hero__links .wp-block-button__link {
	margin: 0;
}
/* One rule, not a reset plus an override: `border: 0` here is (0,2,0) and beats
   a `.fd-hero__links a` underline at (0,1,1), so splitting them silently drops
   the underline. */
.fd-hero__links .wp-block-button__link,
.fd-hero__links a {
	background: transparent;
	background-color: transparent;
	border: 0;
	border-bottom: 1px solid rgba(255, 255, 255, 0.4);
	border-radius: 0;
	padding: 0 0 2px;
	color: var(--wp--preset--color--snow);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}
.fd-hero__links .wp-block-button__link:hover,
.fd-hero__links .wp-block-button__link:focus-visible,
.fd-hero__links a:hover,
.fd-hero__links a:focus-visible {
	background: transparent;
	border-bottom-color: var(--wp--preset--color--snow);
	filter: none;
}

/* Hero headings overflow their own padding on phones. The size is authored as
   `clamp(2.6rem, 5vw, 3.9rem)` (and `h-1` in theme.json as `clamp(2.6rem, 7vw,
   5rem)`), so on any phone the 2.6rem *floor* wins at 41.6px — the vw term
   never gets to shrink it. "announcements" then needs 343px inside the 342px
   the 24px page padding leaves at 390px, so it sits flush to the edge with no
   right margin, and at 320px it forces the whole page to scroll sideways.

   Re-floor it for small screens so the vw term can do its job. Capped at
   2.05rem, which is the largest size that still clears a 320px viewport.
   `!important` is required: four templates set this as an inline style, which
   no selector can outrank. Scoped to `.fd-hero h1` so only hero titles move —
   body copy already wrapped correctly. */
@media (max-width: 600px) {
	.fd-hero h1 {
		font-size: clamp(1.8rem, 8vw, 2.05rem) !important;
	}
}

.fd-breadcrumb {
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--caption);
}
.fd-breadcrumb a {
	color: var(--wp--preset--color--mist);
	text-decoration: none;
}
.fd-breadcrumb a:hover {
	color: var(--wp--preset--color--snow);
}

/* ---- Region switcher (fulton-dems/region-switcher block) ----------------- */

/* Chapter tabs. Restyle of the existing region-switcher block — a <nav
   aria-label="Fulton regions"> with aria-current="page" on the active chapter,
   ordered by menu_order. Underline tabs rather than the previous white pills, so
   the three chapters read as one set rather than three buttons. Behaviour and
   markup are untouched; this is styling only. */
.fd-region-switcher {
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.18);
	margin-bottom: var(--wp--preset--spacing--50);
}

.fd-region-switcher__tab {
	padding: 11px 20px;
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
	/* 0.72 rather than the mockup's 0.6: on the composited band 0.6 lands under
	   4.5:1, and an inactive tab is still a link people are meant to read. */
	color: rgba(255, 255, 255, 0.72);
	text-decoration: none;
	border-bottom: 3px solid transparent;
	transition: color 0.15s ease, border-color 0.15s ease;
}
.fd-region-switcher__tab:hover {
	color: var(--wp--preset--color--snow);
	border-bottom-color: rgba(255, 255, 255, 0.4);
}
.fd-region-switcher__tab.is-active {
	color: var(--wp--preset--color--snow);
	border-bottom-color: var(--fd-accent, var(--wp--custom--accent-fallback));
}
.fd-region-switcher__tab:focus-visible {
	outline: 3px solid var(--wp--preset--color--snow);
	outline-offset: -3px;
}

/* Chair avatar: circular with the region accent ring. */
.fd-avatar img {
	border-radius: 50%;
	border: 3px solid var(--fd-accent, var(--wp--custom--accent-fallback));
	object-fit: cover;
	aspect-ratio: 1;
}

/* Fallback when no headshot exists yet: initials on the region accent —
   a person, not a generic logo. Ink stays AA on every accent (large text). */
.fd-avatar__monogram {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 110px;
	height: 110px;
	margin: 0 auto;
	border-radius: 50%;
	border: 3px solid var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	background: var(--fd-accent, var(--wp--custom--accent-fallback));
	color: var(--wp--preset--color--ink);
	font-weight: 700;
	font-size: 2.4rem;
	line-height: 1;
	letter-spacing: 0.02em;
}

/* ---- Chapter card --------------------------------------------------------- */

/* Bridges the photo band and the paper below it, replacing a 41%/59% pair of
   mismatched cards (chair | meeting) that sat above a second 42%/58% pair. Three
   equal-weight cells, every field backed by real region meta.

   The negative margin is what makes it read as a bridge rather than a third
   card; z-index keeps it above the band's ::after scrim. */
/* Selector is deliberately (0,2,0): WP's layout rule
   `:root :where(.is-layout-flow) > :first-child { margin-block-start: 0 }` is
   (0,1,1) — :first-child scores as a class — so a bare .fd-chapter-card lost the
   cascade and the overlap silently computed to 0. */
.wp-block-group > .fd-chapter-card {
	position: relative;
	z-index: 2;
	margin-top: -56px;
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: center;
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--lift);
	overflow: hidden;
}

.fd-chapter-card__cell {
	padding: 22px 24px;
}
.fd-chapter-card__cell + .fd-chapter-card__cell {
	border-left: 1px solid var(--wp--preset--color--line);
}

.fd-chapter-card__chair {
	display: flex;
	align-items: center;
	gap: 14px;
}
/* The monogram filter emits an aligncenter figure with `margin: 0 auto`; in a
   flex row that shoves it off its baseline. */
.fd-chapter-card .fd-avatar,
.fd-chapter-card .fd-avatar img {
	margin: 0;
	flex: none;
}

.fd-chapter-card__name {
	margin: 2px 0 0;
	font-size: var(--wp--preset--font-size--body);
	font-weight: 800;
	line-height: var(--wp--custom--line-height--snug);
	color: var(--wp--preset--color--ink);
}

.fd-chapter-card__where {
	margin: 3px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	line-height: var(--wp--custom--line-height--body);
	color: var(--wp--preset--color--stone);
}

.fd-chapter-card__link {
	margin-top: 2px;
}
.fd-chapter-card__link .wp-block-button__link {
	padding: 0;
}

.fd-chapter-card__action .wp-block-button__link {
	background-color: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--snow);
	white-space: nowrap;
}

/* Three cells side by side stop working long before the grid does — the meeting
   venue is a full street address. Stack before it crushes. */
@media (max-width: 860px) {
	.wp-block-group > .fd-chapter-card {
		grid-template-columns: 1fr;
		margin-top: -40px;
	}
	.fd-chapter-card__cell + .fd-chapter-card__cell {
		border-left: 0;
		border-top: 1px solid var(--wp--preset--color--line);
	}
}

/* 60px variant for the Elected Democrats roster, whose cards lay the avatar out
   as a flex row item — `margin: 0 auto` above would shove it off its baseline.
   These sat on the shared 800x500 FD lockup before, so each circle showed a
   crop of the middle of the wordmark, ten times down one page.

   The chapter card selects on the ancestor rather than a modifier class because
   functions.php's monogram filter rebuilds the <figure> from scratch and drops
   whatever className the block carried — a fd-avatar--sm on the block never
   survives to the page. */
.fd-avatar__monogram--sm,
.fd-chapter-card .fd-avatar__monogram {
	width: 60px;
	height: 60px;
	margin: 0;
	flex: none;
	border-width: 2px;
	font-size: var(--wp--preset--font-size--lede);
}

/* Meeting card "When / Where" labels. */
/* A card's title is a section heading in the page outline, not emphasised body text (P1-5).
   /get-involved/ and /how-to-vote/ shipped 18 of them as <p style="font-weight:700">, which
   left /how-to-vote/ with two headings for 34 paragraphs — heading navigation skipped every
   card on a page whose whole job is routing someone to the right one.

   The tag changes and the pixels do not: this reproduces exactly what those paragraphs
   computed to, 16px / 700 / 1.6, so a heading's UA size and margin never show through.
   Colour is inherited rather than set, because three of these sit on navy and already carry
   has-snow-color. Spacing stays the block layout's job, same as .fd-label above. */
.fd-card-title {
	margin: 0;
	font-size: var(--wp--preset--font-size--body);
	font-weight: 700;
	line-height: var(--wp--custom--line-height--body);
	color: inherit;
}

.fd-label {
	/* Zeroed because .fd-label is worn by both a <p> (the filter bar's control label) and an
	   <h3> (the governing-body group headings, P1-5). A heading brings UA margins a paragraph
	   in a block layout does not, so without this the same class would space differently
	   depending on its tag. Spacing here is the block layout's job either way. */
	margin: 0;
	text-transform: uppercase;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--eyebrow);
	color: var(--wp--preset--color--stone);
}

/* ---- Cities pills (core/post-terms is-style-fd-pills) --------------------- */

.is-style-fd-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}
.is-style-fd-pills .wp-block-post-terms__separator {
	display: none;
}
.is-style-fd-pills a {
	display: inline-block;
	padding: 6px 14px;
	border-radius: var(--wp--custom--radius--pill);
	border: 1.5px solid var(--fd-accent, var(--wp--preset--color--line));
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 600;
	text-decoration: none;
	pointer-events: none;
}

/* ---- Candidate-by-city filter (region template, JS-injected) -------------- */

.fd-candfilter {
	margin-bottom: var(--wp--preset--spacing--50);
}
.fd-candfilter__lead {
	margin: 0 0 10px;
}
.fd-candfilter__pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}
.fd-candfilter__pill {
	padding: 6px 14px;
	border-radius: var(--wp--custom--radius--pill);
	border: 1.5px solid var(--wp--preset--color--line);
	background: var(--wp--preset--color--snow);
	color: var(--wp--preset--color--ink);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 600;
	cursor: pointer;
	transition: border-color 0.15s ease, background-color 0.15s ease;
}
.fd-candfilter__pill:hover {
	border-color: var(--fd-accent, var(--wp--preset--color--sky));
}
.fd-candfilter__pill.is-active {
	border-color: var(--fd-accent, var(--wp--preset--color--sky));
	background: var(--fd-accent, var(--wp--preset--color--sky));
}
.fd-candfilter__pill:focus-visible {
	outline: 3px solid var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	outline-offset: 2px;
}
.fd-candfilter__status {
	margin: 12px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
}
.fd-candfilter__reset {
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	font-weight: 600;
	cursor: pointer;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
}

/* ── Down-ballot candidate card ─────────────────────────────────────────────
   Vertical card: full-bleed square photograph, a region-accent rule, then the
   office, name, incumbency and district, and one outline button to the
   candidate's site. Replaced the 56px-avatar row once all forty headshots
   landed — that card was shaped by not having photographs.

   NOW THE ONLY CANDIDATE CARD ON THE SITE. It replaced .fd-slate-card on
   /slate/ too, so the statewide eleven and the down-ballot thirty-eight are one
   component rather than two card languages on one page. Keep it flat at rest:
   no scrim, no resting shadow, no .fd-lift, and never make the whole card a
   link. .fd-lift in particular is out — a card that lifts on hover while being
   unclickable is backlog P1-1 verbatim, and the retired navy card failed it.

   Nothing here touches .is-style-fd-card (a dozen other seeded pages use it) or
   .fd-candidates__grid (eight other pages, at columnCount 2 and 4).

   NOTE: .is-style-fd-card had no CSS at all when that was written — see the
   card-surface rule at the end of this file. */
.fd-cand {
	display: flex;
	flex-direction: column;
	/* Clips the photograph to the card radius, and gives the correct inner
	   radius against the 1px border without a calc(). Same idiom as
	   .fd-cta-card and .fd-news-card. */
	overflow: hidden;
}

.fd-cand__inner {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
}

.fd-cand__media {
	position: relative;
	display: block;
	flex: 0 0 auto;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background: var(--wp--preset--color--mist);
}

.fd-cand__photo {
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Every crop is already square and face-normalised, so this is inert for
	   them. It only bites if a future upload is small enough that the square
	   fd-avatar derivative is never generated and WP falls back to the original:
	   biasing up keeps the face rather than the chin. */
	object-position: 50% 30%;
	display: block;
}

/* No candidate uses this today. It has to stay right for the next one added. */
.fd-cand__monogram {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--wp--preset--color--mist);
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--stat);
	font-weight: 800;
	letter-spacing: 0.02em;
	line-height: 1;
}

/* Two jobs in one element: the region's identity, and the divider that would
   otherwise be a 1px line under the photograph. Full-bleed rather than an inset
   tick — a short bar floating under a full-bleed photo reads as an orphaned
   decoration.

   --fd-accent-deep, not --fd-accent. On a snow card the raw accents measure
   2.68:1 (sky), 2.05:1 (peach) and 1.29:1 (gold) — gold would simply vanish.
   The -deep companions are 5.14 / 5.15 / 5.39, which is exactly what
   includes/accent.php documents them for: functional markers on light. */
.fd-cand__rule {
	display: block;
	flex: 0 0 auto;
	height: 3px;
	background: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
}

.fd-cand__body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	padding: 18px;
}

/* Absorbs the slack so the button sits on one baseline across a row. Deliberately
   not margin-top:auto on the button — that collapses to a 0px gap on a card whose
   text happens to fill the column. */
.fd-cand__text {
	flex: 1 1 auto;
}

.fd-cand__flagline {
	margin: 8px 0 0;
}

/* .fd-meta-line hardcodes Sky Deep and is shared with .fd-news-card, so this
   scopes rather than edits. It also fixes a live inconsistency: the office line
   was rendering North's blue on /mid-fulton/ and /south-fulton/, the only
   accent-adjacent element on those pages still wearing another region's colour. */
.fd-cand .fd-meta-line {
	margin: 3px 0 0;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
}

.fd-cand__name {
	margin: 0;
	font-size: var(--wp--preset--font-size--body);
	font-weight: 800;
	line-height: var(--wp--custom--line-height--snug);
	letter-spacing: -0.01em;
	color: var(--wp--preset--color--ink);
}

.fd-cand__coverage {
	margin: 6px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	line-height: var(--wp--custom--line-height--body);
	color: var(--wp--preset--color--stone);
}

/* Outline rather than the theme's solid pill: twenty filled buttons on a page
   out-shout twenty headshots. Component-scoped, not the core button style —
   .fd-btn-outline already exists but requires .wp-block-button__link and ships
   only with the minutes-list block, so it cannot match here.

   The fill colour must be -deep: snow on the raw accents is 2.68 / 2.05 / 1.29,
   all failing. Snow on the -deep companions is 5.14 / 5.15 / 5.39, and the same
   token carries the resting border and label. */
.fd-cand__cta {
	display: flex;
	align-items: center;
	justify-content: center;
	margin-top: 14px;
	min-height: 44px;
	padding: 10px 16px;
	border: 1.5px solid var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	border-radius: var(--wp--custom--radius--pill);
	background: transparent;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	line-height: var(--wp--custom--line-height--snug);
	text-align: center;
	text-decoration: none;
	transition: background-color 0.18s ease, color 0.18s ease;
}
.fd-cand__cta:hover,
.fd-cand__cta:focus-visible {
	background: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	color: var(--wp--preset--color--snow);
}
/* In-region ring rather than the global sky one, which would go blue on Mid and
   South. Matches .fd-candfilter__pill:focus-visible, the nearest sibling. */
.fd-cand__cta:focus-visible {
	outline: 3px solid var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	outline-offset: 2px;
}

/* Extends the CTA's accessible name past the visible "Learn more" so forty links
   don't share one name (P2-7). Scoped copy of core's screen-reader-text: this is
   seeded into post_content, so it must not depend on the block library's
   stylesheet being enqueued. */
.fd-cand__sr {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.is-cand-hidden {
	display: none !important;
}
/* Candidate count appended to the section heading — subordinate to the title. */
.fd-count {
	font-weight: 400;
	font-size: 0.6em;
	color: var(--wp--preset--color--stone);
	letter-spacing: 0;
}
/* Affordance under the region map linking it to the candidate filter. */
.fd-map-hint {
	margin: 10px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 600;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
}

/* ---- Captains grid (post content) ----------------------------------------- */

.fd-captain {
	padding: var(--wp--preset--spacing--50);
}
.fd-captain__city {
	text-transform: uppercase;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--eyebrow);
	color: var(--wp--preset--color--stone);
	margin-bottom: var(--wp--preset--spacing--10);
}
.fd-captain__name {
	font-weight: 700;
	margin-top: 0;
}
.fd-captain__contact a {
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

/* ---- FAQ (core/details) ---------------------------------------------------- */

.fd-faq .wp-block-details {
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
}
.fd-faq .wp-block-details summary {
	font-weight: 600;
	cursor: pointer;
	list-style: none;
	position: relative;
	padding-right: 28px;
}
.fd-faq .wp-block-details summary::-webkit-details-marker {
	display: none;
}
.fd-faq .wp-block-details summary::after {
	content: "+";
	position: absolute;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	font-weight: 700;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	transition: transform 0.15s ease;
}
.fd-faq .wp-block-details[open] summary::after {
	content: "–";
}

/* ---- Buttons --------------------------------------------------------------- */

.wp-block-button__link {
	transition: filter 0.2s ease, transform 0.15s ease;
}
.wp-block-button__link:hover {
	filter: brightness(1.08);
}
.wp-block-button__link:active {
	transform: translateY(1px);
	filter: brightness(0.92);
}

.is-style-fd-gold .wp-block-button__link {
	background-color: var(--wp--preset--color--gold);
	color: var(--wp--preset--color--navy);
}

.is-style-fd-outline-on-dark .wp-block-button__link {
	background-color: transparent;
	border: 1.5px solid rgba(255, 255, 255, 0.35);
	color: var(--wp--preset--color--snow);
}
.is-style-fd-outline-on-dark .wp-block-button__link:hover {
	border-color: var(--wp--preset--color--snow);
	filter: none;
}

/* Text-style "arrow" button used for bound contact links. */
.fd-arrow-button .wp-block-button__link {
	background: transparent;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	padding: 0;
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
}
.fd-arrow-button .wp-block-button__link:hover {
	filter: none;
	text-decoration: underline;
}

/* Read-more link on hub cards. */

/* ---- Newsletter band -------------------------------------------------------- */

.fd-news-input {
	height: 46px;
	border-radius: var(--wp--custom--radius--pill);
	border: 1.5px solid rgba(255, 255, 255, 0.25);
	background: rgba(255, 255, 255, 0.06);
	padding: 0 18px;
	color: var(--wp--preset--color--snow);
	font-size: var(--wp--preset--font-size--small);
	min-width: 260px;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.fd-news-input::placeholder {
	color: var(--wp--preset--color--mist);
}
.fd-news-input:focus {
	outline: none;
	border-color: var(--wp--preset--color--sky);
	box-shadow: 0 0 0 3px rgba(42, 169, 224, 0.55);
}

/* Subscribe submit buttons (hero + newsletter band). Explicit, high-specificity
   styling so third-party global button CSS can't override it — theme.json emits
   button styles inside :where() (zero specificity), which Elementor's global kit
   (`.elementor-kit-* button`) otherwise beats, rendering white-on-white. */
.fd-subscribe button[type="submit"] {
	flex: none;
	height: 46px;
	padding: 0 24px;
	border: none;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--sky-deep);
	color: var(--wp--preset--color--snow);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.15s;
}
.fd-subscribe button[type="submit"]:hover {
	background-color: var(--wp--preset--color--sky);
}
.fd-subscribe button[type="submit"]:focus-visible {
	outline: 3px solid var(--wp--preset--color--gold);
	outline-offset: 2px;
}

.fd-newsletter-form {
	display: flex;
	gap: 10px;
	flex-wrap: wrap;
	align-items: center;
}

/* Honeypot field: visually gone, still in the DOM for bots. */
.fd-hp {
	position: absolute !important;
	left: -9999px !important;
	width: 1px;
	height: 1px;
	opacity: 0;
}

.fd-form-note {
	flex-basis: 100%;
	margin: 6px 0 0;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--mist);
}
/* Both bands sit on navy, so these are the on-dark pair. Success carries a
   little more weight than the resting note: converting is the highest-value
   moment on the page and it used to be its quietest element. */
.fd-form-note.is-success {
	color: var(--wp--preset--color--snow);
	font-weight: 600;
}
/* Peach, not coral-by-hex. subscribe.js previously set #F15A45 inline, which put
   a colour outside the stylesheet and outside the palette. */
.fd-form-note.is-error {
	color: var(--wp--preset--color--peach);
}
/* The chapter link inside a success note is on navy; .fd-arrow-link resolves
   from sky-deep, which is tuned for light backgrounds. */
.fd-form-note .fd-arrow-link {
	color: var(--wp--preset--color--sky);
}

/* ---- Footer ------------------------------------------------------------------ */

.fd-footer a {
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	transition: color 0.18s ease;
}
.fd-footer a:hover {
	color: var(--wp--preset--color--snow);
}
.fd-footer__heading {
	color: var(--wp--preset--color--snow);
	text-transform: uppercase;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--eyebrow);
}
.fd-footer__legal {
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--caption);
}

/* ---- Home page ----------------------------------------------------------------- */

/* Hero map watermark, centered (home) — .fd-hero keeps the right-side variant. */
.fd-hero--home::before {
	background-position: center;
	background-size: cover;
}
.fd-hero--home {
	border-top: none;
}

/* Sky highlight box behind hero emphasis text. The raised line-height keeps
   the opaque box from painting over the previous line's descenders when the
   headline wraps (h1 runs at 1.02). */
.fd-highlight {
	background: var(--wp--preset--color--sky);
	color: var(--wp--preset--color--navy);
	padding: 0.02em 0.16em;
	border-radius: var(--wp--custom--radius--sharp);
	line-height: 1.22;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}

.fd-eyebrow--wide {
	letter-spacing: 0.26em;
}

.fd-gold-bar {
	width: 48px;
	height: 4px;
	background: var(--wp--preset--color--gold);
	border-radius: var(--wp--custom--radius--pill);
}

/* Signup capture form (hero) — placeholder until the real embed lands. */
.fd-capture-form {
	display: flex;
	gap: 12px;
	flex-wrap: wrap;
	align-items: stretch;
}
.fd-capture-form input[type="email"],
.fd-capture-form input[type="text"],
.fd-capture-form input[type="tel"] {
	height: 58px;
	border-radius: var(--wp--custom--radius--base);
	border: 1.5px solid transparent;
	background: var(--wp--preset--color--snow);
	padding: 0 20px;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--body);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.fd-capture-form input:focus {
	outline: none;
	border-color: var(--wp--preset--color--sky);
	box-shadow: 0 0 0 3px rgba(42, 169, 224, 0.55);
}
.fd-capture-consent {
	display: flex;
	gap: 10px;
	align-items: flex-start;
	/* Now a flex item of .fd-capture-form: claim a full row so it still sits
	   under the fields. 6px + the form's 12px row-gap = the 18px it had before. */
	flex-basis: 100%;
	margin-top: 6px;
	max-width: 720px;
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--caption);
	line-height: 1.5;
}
.fd-capture-consent input[type="checkbox"] {
	flex: none;
	/* 24px, not the 18px this started at (P2-14). The wrapping <label> already
	   made the whole consent sentence clickable so the effective target was
	   never really 18px — but this is the control that records agreement to be
	   texted, and it gets aimed at with a thumb. */
	width: 24px;
	height: 24px;
	margin-top: 1px;
	accent-color: var(--wp--preset--color--sky);
}
.fd-capture-consent a {
	color: var(--wp--preset--color--sky);
	font-weight: 600;
}

/* The ZIP hint (P1-7). A flex item of .fd-capture-form claiming a full row, so
   it lands between the fields and the button — the visitor reads why the ZIP is
   wanted at the moment they are deciding whether to give it, rather than after.
   Caption/Mist matches the consent line beneath it: both are the form talking
   about itself rather than asking for something. */
.fd-capture-hint {
	flex-basis: 100%;
	max-width: 720px;
	margin: 0;
	color: var(--wp--preset--color--mist);
	font-size: var(--wp--preset--font-size--caption);
	line-height: 1.5;
}

/* The same form on a LIGHT surface (/text-updates/, inside .is-style-fd-card).
   Every colour above was chosen for the navy hero, where this form was born and
   where Mist is 9.47:1. On the white card each one inverts into a failure, and
   the worst of them lands on the sentence a carrier reviewer reads first:

     consent + hint text   Mist  1.57:1  ->  Stone     7.11:1
     consent links         Sky   2.68:1  ->  Sky Deep  5.08:1
     field border          transparent, over a snow field on a snow card — the
                           inputs had no visible edge at all, so the placeholders
                           read as floating text rather than as things you fill in.
                           Line (#DEE5EC) is the divider tone at 1.27:1 and is not
                           a control boundary; Slate is 3.64:1, which clears the
                           3:1 that WCAG 1.4.11 asks of a UI component and still
                           sits quieter than the 7.11:1 Stone would draw.

   Scoped to the card rather than to the page, so the hero keeps its own palette
   and any future light-surface placement of this form inherits the fix. */
.is-style-fd-card .fd-capture-consent,
.is-style-fd-card .fd-capture-hint {
	color: var(--wp--preset--color--stone);
}
.is-style-fd-card .fd-capture-consent a {
	color: var(--wp--preset--color--sky-deep);
}
.is-style-fd-card .fd-capture-form input[type="email"],
.is-style-fd-card .fd-capture-form input[type="text"],
.is-style-fd-card .fd-capture-form input[type="tel"] {
	border-color: var(--wp--preset--color--slate);
}

/* "I want to…" tile cluster. */
.fd-tiles {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 6px;
}
/* One navy step for all four tiles. The cluster used to alternate navy-2 and
   navy-3 in a checkerboard, which existed to give four identical flat fills some
   structure — a job the photographs now do. Dropping it also removes a bug in
   waiting: the alternation was hardcoded per tile rather than :nth-child, so a
   one-column grid rendered A B B A, which reads as two doubled pairs. */
.fd-tile {
	position: relative;
	min-height: 252px;
	padding: 26px;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	text-decoration: none;
	background: var(--wp--preset--color--navy-2);
}

/* Photograph layer. The scrim lives here rather than on .fd-tile so the blend
   group is exactly the photo: the tile's own background is never multiplied into
   near-black, no :has() or modifier class is needed to know whether a photo
   exists, and a missing or 404'd image degrades to the flat navy-2 fill above —
   i.e. the tile as it was before photographs. */
.fd-tile__photo {
	position: absolute;
	inset: 0;
	z-index: 0;
	/* Load-bearing. Without it the multiply below reaches past the tile and
	   composites against the section's navy backdrop. */
	isolation: isolate;
	overflow: hidden;
}
.fd-tile__img {
	width: 100%;
	height: 100%;
	display: block;
	object-fit: cover;
	/* Biased above centre so a 4:3 hard crop of a portrait-ish frame keeps heads
	   in shot. Per-tile override: style="--fd-tile-focus:50% 22%". */
	object-position: var(--fd-tile-focus, 50% 35%);
	transition: transform 0.35s ease;
}

/* THE CONTRAST GUARANTEE — read the arithmetic before changing the opacity.
   multiply is per-channel out = photo x navy / 255, and at opacity a the
   composite is a*(photo x navy/255) + (1-a)*photo. The worst photograph is pure
   white, so the backdrop can never be lighter than a*navy + (1-a)*255 — a hard
   ceiling that holds for ANY frame, which is what makes this a proof rather than
   a measurement. WCAG luminance is a positive-weighted sum of monotonically
   increasing per-channel functions, so the contrast floor follows directly:

     opacity   worst-case backdrop   Mist #C2D0DC
       1.00    rgb( 26, 55, 90)        7.68:1
       0.90    rgb( 49, 75,107)        5.69:1   <- current
       0.85    rgb( 60, 85,115)        4.87:1   <- hard floor, do not go below
       0.80    rgb( 72, 95,123)        4.18:1   FAILS AA

   Dropped to 0.90 on 2026-08-18 so more of each photograph reads through. Where
   the label and title actually sit the bottom scrim below adds its own darkening,
   measuring 8.71:1 for Mist and 13.70:1 for the Snow title — the figures above are
   the conservative case that ignores it.

   Still true: any LIGHTENING filter on the tile breaks this outright, which is why
   the old `filter: brightness(1.12)` hover is gone rather than kept. */
.fd-tile__photo::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: var(--wp--preset--color--navy-2);
	mix-blend-mode: multiply;
	opacity: 0.9;
}
/* Aesthetic only: sinks the bottom where the label and title sit. Normal blend
   and darkening, so it can only strengthen the floor above. */
.fd-tile__photo::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
	background: linear-gradient(
		to top,
		color-mix(in srgb, var(--wp--preset--color--navy-deep) 60%, transparent) 0%,
		color-mix(in srgb, var(--wp--preset--color--navy-deep) 18%, transparent) 42%,
		transparent 72%
	);
}

/* Named wrapper, not `.fd-tile > *`: that would also catch .fd-tile__photo and
   kill its position:absolute, and at (0,1,1) it would out-specify
   .fd-tile__arrow (0,1,0) and drop the arrow into the flex flow. */
.fd-tile__content {
	position: relative;
	z-index: 2;
}

/* Replaces `filter: brightness(1.12)`. A brightness lift washes a photograph out
   rather than lifting it, it composites the whole tile, and it is the one edit
   that quietly erodes the contrast floor above. */
.fd-tile:hover .fd-tile__img,
.fd-tile:focus-visible .fd-tile__img {
	transform: scale(1.045);
}
/* These links previously had only the UA focus ring, which over a photograph can
   be invisible. Inset so it is not clipped by the 6px grid seam. */
.fd-tile:focus-visible {
	outline: 3px solid var(--wp--preset--color--gold);
	outline-offset: -3px;
}
.fd-tile__label {
	display: block;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	text-transform: uppercase;
	/* Muted-on-dark is Mist, per the Muted Split Rule. Clears AA on both tile
	   steps (7.68:1 on navy-2, 4.65:1 on navy-3). */
	color: var(--wp--preset--color--mist);
}
.fd-tile__title {
	display: block;
	font-weight: 700;
	font-size: var(--wp--preset--font-size--h-4);
	line-height: 1.12;
	color: var(--wp--preset--color--snow);
	margin-top: 8px;
}
.fd-tile__arrow {
	position: absolute;
	z-index: 2;
	top: 22px;
	right: 22px;
	width: 38px;
	height: 38px;
	border-radius: 50%;
	border: 1.5px solid rgba(255, 255, 255, 0.4);
	color: rgba(255, 255, 255, 0.85);
	display: flex;
	align-items: center;
	justify-content: center;
	transition: all 0.2s ease;
}
.fd-tile:hover .fd-tile__arrow {
	background: rgba(255, 255, 255, 0.14);
	border-color: rgba(255, 255, 255, 0.7);
}

/* One column below 600px. The cluster had no media query at any width, so at
   390px each tile was 168px wide with 116px of text — and "candidates" (141px)
   and "Volunteer" (122px) broke mid-word. 2-up survives above ~440px by
   arithmetic; 600px is chosen instead because it matches the hero breakpoint
   above and because a 216px-wide tile is too small to carry a photograph.
   min-height is kept, not dropped: a 90px-tall tile photo is nothing. */
@media (max-width: 600px) {
	.fd-tiles {
		grid-template-columns: 1fr;
	}
	.fd-tile {
		min-height: 190px;
		padding: 20px;
	}
}

/* News/related cards. */
.fd-news-card {
	overflow: hidden;
}
.fd-news-card .wp-block-post-featured-image img {
	aspect-ratio: 8 / 5;
	object-fit: cover;
	border-bottom: 1px solid var(--wp--preset--color--line);
}
/* The Label style — dates, category names, "For Immediate Release", section eyebrows.
   DESIGN.md specifies it exactly: `meta-line: textColor: {colors.stone}` and Label as
   600 / 0.72rem / +0.16em / uppercase. This rule had drifted from both (P3-1).

   COLOUR IS SPLIT FROM THE SHARED PROPERTIES ON PURPOSE. Sky Deep is the link colour,
   and painting the whole line with it made dates and office lines look as clickable as
   the category beside them — on the news and press cards the category genuinely IS an
   <a> and the date is not, so one selector list gave both the same affordance. After the
   split only a real link wears the link colour.

   Stone is not a contrast compromise, it is an improvement: measured against the real
   grounds it gives 7.11:1 on white and 6.61:1 on Paper, against Sky Deep's 5.08:1. Worth
   saying because an earlier pass moved this rule TO sky-deep to fix a 2.49:1 failure and
   logged that as P3-1 being fixed. It fixed the contrast by borrowing the link colour.
   DESIGN.md's Muted Split Rule is the answer to both — Stone on light, Mist on dark.

   The 4 instances that sit on navy carry `has-sky-color` from the block and are untouched
   by this rule; the 68 candidate office lines are governed by `.fd-cand .fd-meta-line`
   above, which keeps its region accent deliberately. */
.fd-meta-line,
.fd-meta-line a {
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	text-transform: uppercase;
	text-decoration: none;
}
.fd-meta-line {
	color: var(--wp--preset--color--stone);
}
.fd-meta-line a {
	color: var(--wp--preset--color--sky-deep);
}

/* Consequence of the tracking above, found by measuring rather than after the fact.
   0.16em is 0.23px per character wider than the 0.14em it replaced, which is invisible
   everywhere except the press-release cards at phone width: "FOR IMMEDIATE RELEASE ·"
   grew just far enough to wrap, and because the flex row is `is-nowrap` from the block,
   it broke between RELEASE and the separator — leaving a lone "·" on its own line beside
   a date that had also split into two.

   Letting the row wrap puts the label on one line and the date on the next, which is what
   it should have done. Scoped to 430px, the theme's existing phone breakpoint, so the
   block's own nowrap still governs every width where it works. text-wrap: balance and
   pretty were both tried first and changed nothing — the break is between flex children,
   not inside a text run. */
@media (max-width: 430px) {
	.fd-meta-line.is-layout-flex {
		flex-wrap: wrap;
	}
}
.fd-news-card .wp-block-post-title a {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

/* Event list cards (home events section). */
/* The fulton-dems/events-list block renders these; its render.php carries only
   classes so the sizes stay on the ramp instead of being inlined past it. */
.fd-events-list {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	max-width: 720px;
}
.fd-event-card {
	display: flex;
	align-items: center;
	gap: 16px;
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	padding: 14px 16px;
}
.fd-event-card__body {
	flex: 1;
	min-width: 0;
}
.fd-event-card__title {
	font-weight: 700;
	font-size: var(--wp--preset--font-size--body);
	color: var(--wp--preset--color--ink);
	line-height: 1.2;
}
.fd-event-card__meta {
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
	margin-top: 2px;
}
.fd-event-card__cta {
	font-size: var(--wp--preset--font-size--caption);
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
}

/* The horizontal card needs roughly 420px to work: the date chip and the CTA
   take ~140px between them, and below that the title column collapses. That
   happens in two unrelated places — the 320px sidebar on /meeting-minutes/ at
   DESKTOP width, and any full-width card on a phone — so a viewport media query
   is the wrong instrument. Measured before this rule: 74px of title in the
   desktop sidebar and 81px on a 390px phone, both wrapping "Fulton County
   Monthly Meeting" onto four lines, while a 768px tablet was fine at 459px.
   Key on the container's width, which is the thing that actually decides it. */
.fd-events-list {
	container-type: inline-size;
}
@container (max-width: 420px) {
	.fd-event-card {
		flex-direction: column;
		align-items: stretch;
		gap: 10px;
	}
	/* stretch would blow these out to the card edge; they keep their own size */
	.fd-event-card .fd-date-chip,
	.fd-event-card__cta {
		align-self: flex-start;
	}
}
.fd-date-chip {
	flex: none;
	width: 58px;
	text-align: center;
	background: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--sharp);
	padding: 7px 0;
}
.fd-date-chip__mon {
	/* Was a <div>; now a <span> inside a <time>, because <time> is phrasing content and
	   cannot legally contain flow content — an invalid nesting a browser may reparent.
	   The stacking it relied on from the div default has to be stated. */
	display: block;
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sky-deep);
}
.fd-date-chip__day {
	display: block;
	font-size: 1.4rem;
	font-weight: 800;
	line-height: 1;
	color: var(--wp--preset--color--ink);
}
/* Month-precision chip (meeting minutes are filed per month, so the lower line
   is a 4-digit year rather than a 1–2 digit day). 1.4rem would need ~52px of a
   58px chip and overflow at the first narrow-viewport nudge; 1rem sits it
   comfortably and keeps the month the emphasised line, which is what the eye
   scans in a list that is already grouped by year. */
.fd-date-chip--month .fd-date-chip__day {
	font-size: 1rem;
	letter-spacing: 0.01em;
}

.fd-section-relative {
	position: relative;
	overflow: hidden;
}

/* Region cards (home) accent strip. */
.fd-accent-strip {
	height: 6px;
	background: var(--fd-accent, var(--wp--custom--accent-fallback));
}

/* ---- About / directory pages ----------------------------------------------------- */

/* Governing-document link cards on navy sections. */
.fd-doc-card {
	display: flex;
	gap: 14px;
	align-items: flex-start;
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid rgba(255, 255, 255, 0.12);
	border-radius: var(--wp--custom--radius--sharp);
	padding: 20px;
	text-decoration: none;
}
.fd-doc-card__tag {
	display: block;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sky);
}
.fd-doc-card__title {
	display: block;
	font-weight: 700;
	font-size: 1.08rem;
	color: var(--wp--preset--color--snow);
	margin-top: 3px;
}
.fd-doc-card__cta {
	display: inline-block;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--mist);
	margin-top: 8px;
	/* At caption size this is a ~16px-tall target. It was decorative until the
	   slate's step cards started using it as their only link, so it has to clear
	   the WCAG 2.5.8 24x24 floor on its own. */
	min-height: 24px;
	padding-block: 4px;
}

/* Stacked variant: label above body (numbered step cards). */
.fd-doc-card.wp-block-group {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

/* Directory member card (State Committee, Elected Democrats). */
.fd-badge {
	display: inline-block;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sky-deep);
	background: rgba(42, 169, 224, 0.14);
	padding: 2px 9px;
	border-radius: var(--wp--custom--radius--pill);
}

/* Candidate badges (Slate). */
.fd-badge--gold {
	display: inline-block;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--navy);
	background: var(--wp--preset--color--gold);
	padding: 3px 11px;
	border-radius: var(--wp--custom--radius--pill);
}
.fd-badge--muted {
	display: inline-block;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--stone);
	background: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--line);
	padding: 3px 11px;
	border-radius: var(--wp--custom--radius--pill);
}

/* Open seat: no incumbent on the ballot. Hairline and unfilled so it reads as a
   statement of fact rather than a contest, which is what --gold and --muted both
   imply. Stone (7.11:1 on paper), not Slate — DESIGN.md's Named Rules put Slate
   out of bounds for small text on light. */
.fd-badge--open {
	display: inline-block;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--stone);
	background: transparent;
	border: 1px solid var(--wp--preset--color--line);
	padding: 3px 11px;
	border-radius: var(--wp--custom--radius--pill);
}

/* Key-date chips (Slate hero band). */
.fd-date-stat {
	background: rgba(255, 255, 255, 0.06);
	border: 1px solid rgba(255, 255, 255, 0.14);
	border-radius: var(--wp--custom--radius--base);
	padding: 12px 18px;
}
.fd-date-stat--gold {
	background: rgba(241, 232, 25, 0.12);
	border-color: rgba(241, 232, 25, 0.4);
}

/* Org-structure chart (Our Party). */
.fd-connector {
	width: 2px;
	height: 26px;
	background: var(--wp--preset--color--line);
	margin: 0 auto;
}

/* Info notice banner. */
.fd-notice {
	background: rgba(42, 169, 224, 0.08);
	border: 1px solid rgba(42, 169, 224, 0.3);
	border-radius: var(--wp--custom--radius--base);
	padding: 14px 18px;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--stone);
}

/* Roster list (State Committee members, grouped under a district label). Names
   only — the committee has no member photos, and a card grid of empty avatar
   circles carried no information. Hairline rules between rows give the roster
   its "official record" reading without cards. */
.fd-roster {
	list-style: none;
	margin: 0;
	padding: 0;
}
.fd-roster li {
	padding: 7px 0;
	border-top: 1px solid var(--wp--preset--color--line);
}
.fd-roster li:first-child {
	border-top: 0;
	padding-top: 0;
}

/* Leadership roster: name / role / contact per row, grouped under a section
   heading. Same reasoning as .fd-roster — no officer headshots exist, and a
   dozen identical placeholder discs said nothing the names didn't. Roles use
   the standard .fd-label; contacts use .fd-arrow-link. */
.fd-people > .fd-person {
	display: grid;
	grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) auto;
	align-items: baseline;
	gap: 2px 20px;
	padding: 12px 0;
	border-top: 1px solid var(--wp--preset--color--line);
}
.fd-people > .fd-person:first-child {
	border-top: 0;
	padding-top: 0;
}
.fd-people .fd-person > * {
	margin: 0;
}
.fd-person__name {
	font-weight: 700;
}
/* Three columns of text need real width; below this the row stacks name over
   role over contact rather than squeezing each into a third of a phone. */
@media (max-width: 600px) {
	.fd-people > .fd-person {
		grid-template-columns: 1fr;
		gap: 2px;
		padding: 14px 0;
	}
}

/* Charter quote callout. */
.fd-charter-quote {
	border-left: 3px solid var(--wp--preset--color--sky);
	padding: 4px 0 4px 20px;
	margin: 0;
	font-weight: 500;
}
.fd-charter-quote cite {
	display: block;
	font-style: normal;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
	margin-top: 10px;
}

/* ---- Article ------------------------------------------------------------------- */

.fd-article .wp-block-post-content p {
	font-size: 1.08rem;
	line-height: 1.78;
}
.fd-article .wp-block-post-content > p:first-child {
	font-size: 1.24rem;
	line-height: 1.65;
	font-weight: 500;
	color: var(--wp--preset--color--ink);
}
.fd-article .wp-block-post-content blockquote {
	margin: 34px 0;
	padding: 6px 0 6px 26px;
	border-left: 4px solid var(--wp--preset--color--peach);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--h-4);
	line-height: 1.35;
	color: var(--wp--preset--color--ink);
}
/* `.fd-media-lead`, not `.wp-block-post-featured-image`. `.fd-article` is on
   <main>, so the unscoped selector also reached the three "More from the
   newsroom" thumbnails at the foot of every article: each one was pulled 36px
   up into the card that clips it, and given the hero's radius, shadow and 1px
   border on top of the border-bottom the card already draws. Measured before
   the change — all three read margin-top: -36px. */
/* Long-form prose on a plain page — the privacy policy, terms, anything meant to be read
   start to finish rather than scanned. theme.json's h-2 is a fluid clamp for full-width band
   titles, so on a document it renders 44.8px under a 62.4px H1: a section head almost the size
   of the page title. Same correction as the article body below, applied by class because these
   pages are not .fd-article. Measure is set in the content by a constrained group, where the
   decision stays visible. */
.fd-prose h2 {
	font-size: var(--wp--preset--font-size--h-3);
	line-height: var(--wp--custom--line-height--snug);
}
.fd-prose h3 {
	font-size: var(--wp--preset--font-size--h-4);
	line-height: var(--wp--custom--line-height--snug);
}

/* An in-body heading is not a band title (P1-5).
   theme.json's h-2 is a fluid clamp built for full-width section heads on a 1120px band, and
   an <h2> written inside an article inherited it: 44.8px against the article's own 51.2px H1,
   a ratio of 1.14:1. Two H2s then sat on the same page 47% apart — the body's at 44.8px and
   the template's "More from the newsroom" at 30.4px — so the level said "same rank" and the
   type said otherwise.

   Scoped to the post content only, and to the h-3 step, which is what the template's own
   section heads already use. That reads as 1.68:1 under the H1. The theme.json preset is not
   touched: band titles elsewhere still want the clamp. */
.fd-article .wp-block-post-content h2 {
	font-size: var(--wp--preset--font-size--h-3);
	line-height: var(--wp--custom--line-height--snug);
}
.fd-article .wp-block-post-content h3 {
	font-size: var(--wp--preset--font-size--h-4);
	line-height: var(--wp--custom--line-height--snug);
}

.fd-article .fd-media-lead img {
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--lift);
	border: 1px solid var(--wp--preset--color--line);
}
.fd-article .fd-media-lead {
	margin-top: -36px;
}
/* The pill is the wrapper. core/post-terms renders <div class="fd-cat-pill"><a>…</a></div>,
   so styling both the div AND the a painted two translucent layers: a 150x28px
   outer pill plus a 124x18px inner one, and where they overlapped the 18% sky
   doubled to ~33%. It read as a brighter pill inside a fainter pill. Only the
   wrapper carries the background, padding and radius; the link just inherits. */
.fd-cat-pill {
	display: inline-block;
	background: rgba(42, 169, 224, 0.18);
	color: var(--wp--preset--color--sky);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	/* Padding moved to the anchor below (P2-2). The wrapper keeps the background and the
	   radius, so the pill paints identically — but the padding is what makes the pill look
	   150x28, and while it sat here the clickable area was only the 124x16 text inside it.
	   A pill that is visibly 28px tall and clickable at 16px is a target that lies about
	   where it is. */
	padding: 0;
	border-radius: var(--wp--custom--radius--pill);
	text-decoration: none;
}
.fd-cat-pill a {
	/* block, so the anchor fills the wrapper and the whole painted pill is the target */
	display: block;
	padding: 5px 13px;
	color: inherit;
	text-decoration: none;
}

/* News listing: horizontal list cards + sidebar. */
.fd-list-card {
	overflow: hidden;
}
/* The card is a nowrap flex row, so the image block is shrinkable by default.
   With the short seeded excerpts nothing shrank; the longer legacy excerpts
   squeezed it to ~60px and `overflow: hidden` clipped the image to an
   unreadable sliver. Pin the track so the text column absorbs the difference.

   `align-self: stretch` overrides the card's `align-items: center`: a fixed
   148px image inside a 241px card was being centred, leaving ~46px of dead
   space above and below it. The image is then taken out of flow so it fills
   whatever height the text needs without ever *driving* that height — with
   `height: 100%` in flow, a portrait image falls back to its intrinsic ratio
   and stretches the card to 251px instead. */
.fd-list-card .wp-block-post-featured-image {
	flex: 0 0 200px;
	align-self: stretch;
	position: relative;
	min-height: 148px;
	margin: 0;
}
.fd-list-card .wp-block-post-featured-image a,
.fd-list-card .wp-block-post-featured-image img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}
/* Core renders the block's `width` attribute as an INLINE style on the img —
   `height:auto;width:200px;object-fit:cover` — and an inline declaration
   outranks every selector, so the `height:100%` above never took effect. Each
   thumbnail sat at its own intrinsic ratio inside the square frame, top-aligned
   with dead white below it, and the raggedness tracked the source aspect ratios
   (1.90 down to one 1:1 poster) rather than anything in the design. It read as
   broken thumbnails because the card, not the crop, was setting the shape.

   Same trap as the `width:100% !important` in the phone breakpoint below, which
   already documents it, and as the attribute height that squashed the region
   band photo: a dimension carried inline beats a stylesheet. `!important` is
   the only thing that outranks an inline style short of filtering the block's
   output in PHP.

   BOTH dimensions, not just height. The inline `width:200px` happens to equal
   100% of today's 200px track, so it is right by coincidence and would break
   silently the moment that track changes. */
.fd-list-card .wp-block-post-featured-image img {
	width: 100% !important;
	height: 100% !important;
	border-right: 1px solid var(--wp--preset--color--line);
}

/* Keep cards near-uniform. Legacy excerpts run far longer than the seeded ones,
   and an unclamped card grows tall enough that the 200px-wide crop window turns
   poster-style graphics into an unreadable middle strip. Visual truncation
   only — the full excerpt stays in the DOM for screen readers and crawlers. */
.fd-list-card .wp-block-post-title,
.fd-list-card .wp-block-post-excerpt {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.fd-list-card .wp-block-post-title {
	-webkit-line-clamp: 2;
}
.fd-list-card .wp-block-post-excerpt {
	-webkit-line-clamp: 2;
}

/* Phones: the row has no business staying a row. At 375px the fixed 200px image
   left a 66px text column, breaking titles mid-word and running cards to
   1470px. Stack instead. `flex-direction` rather than `flex-wrap`, so the
   editor's inline `flex-wrap: nowrap` is sidestepped rather than fought. */
@media (max-width: 600px) {
	.fd-list-card {
		flex-direction: column;
		align-items: stretch;
	}
	/* `!important` is load-bearing, not laziness: the post-featured-image block
	   renders its `width` attribute as an inline style, which no stylesheet
	   selector can outrank. It also survives someone re-setting that width in
	   the Site Editor, which editing the template markup would not. */
	.fd-list-card .wp-block-post-featured-image {
		flex: 0 0 auto;
		width: 100% !important;
		height: 180px;
	}
	.fd-list-card .wp-block-post-featured-image img {
		border-right: 0;
		border-bottom: 1px solid var(--wp--preset--color--line);
	}
	/* The text column is authored with padding on three sides only — in the row
	   layout the image supplies the left edge and the 22px blockGap does the
	   separating. Stacked, that leaves the text 1px off the card border while
	   the right side keeps 22px. Restore the fourth side. */
	.fd-list-card > .wp-block-group {
		padding-left: 22px;
	}
	.fd-list-card .wp-block-post-excerpt {
		-webkit-line-clamp: 3;
	}
}
.fd-sidebar-card {
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--card);
	padding: 22px;
}
.fd-sidebar-card .wp-block-categories {
	list-style: none;
	padding: 0;
	margin: 0;
}
.fd-sidebar-card .wp-block-categories li {
	padding: 6px 0;
	border-bottom: 1px solid var(--wp--preset--color--paper);
}
.fd-sidebar-card .wp-block-categories a {
	color: var(--wp--preset--color--ink);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}
.fd-sidebar-card .wp-block-categories a:hover {
	color: var(--wp--preset--color--sky-deep);
}

/* Query pagination, prototype-style boxes. */
.wp-block-query-pagination .wp-block-query-pagination-numbers .page-numbers,
.wp-block-query-pagination-previous,
.wp-block-query-pagination-next {
	min-width: 38px;
	height: 38px;
	border-radius: 8px;
	border: 1.5px solid var(--wp--preset--color--line);
	background: var(--wp--preset--color--snow);
	color: var(--wp--preset--color--stone);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	padding: 0 10px;
}
.wp-block-query-pagination .page-numbers.current {
	border-color: var(--wp--preset--color--navy);
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--snow);
}

/* Same prototype-style boxes for the plugin blocks' server-side pagination
   (minutes-list, newsletter-archive). */
.fd-pagenav {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	margin-top: 24px;
}
.fd-pagenav a,
.fd-pagenav [aria-current="page"] {
	min-width: 38px;
	height: 38px;
	border-radius: 8px;
	border: 1.5px solid var(--wp--preset--color--line);
	background: var(--wp--preset--color--snow);
	color: var(--wp--preset--color--stone);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	padding: 0 10px;
}
.fd-pagenav [aria-current="page"] {
	border-color: var(--wp--preset--color--navy);
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--snow);
	font-weight: 700;
}

/* Status pill (approved records — minutes archive). */
.fd-status-pill {
	display: inline-block;
	padding: 3px 11px;
	border-radius: var(--wp--custom--radius--pill);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	white-space: nowrap;
}
.fd-status-pill--approved {
	color: var(--wp--preset--color--green);
	background: color-mix(in srgb, var(--wp--preset--color--green) 12%, transparent);
}

/* Browse-by-year link stacks rendered by the blocks' "years" display. */
.fd-yearlist {
	display: flex;
	flex-direction: column;
}
.fd-yearlist a {
	display: block;
	padding: 6px 0;
	border-bottom: 1px solid var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}
.fd-yearlist a:hover,
.fd-yearlist a[aria-current] {
	color: var(--wp--preset--color--sky-deep);
}
.fd-yearlist a:last-child {
	border-bottom: 0;
}

/* Stacked subscribe form (sidebar cards) — same .fd-subscribe behavior
   (subscribe.js binds it), column layout instead of the band's row. */
.fd-subscribe--stack {
	display: flex;
	flex-direction: column;
	gap: 10px;
}
.fd-subscribe--stack .fd-news-input {
	/* content-box + width:100% rendered this 310px inside a 272px card: the 18px
	   padding and 1px border were added on top of the 100%, so it jutted past
	   both the Subscribe button and the card edge. The button looked right only
	   because flex stretch sizes the border box. border-box makes 100% mean the
	   whole control, so the two now agree exactly.
	   min-width is the same bug from the other end — 260px + 38px = 298px in a
	   249px card at 360px — and the stack variant is always full-width, so the
	   floor is dead weight here. The band form keeps its own min-width; it needs
	   one to survive sharing a row with the button. */
	box-sizing: border-box;
	width: 100%;
	min-width: 0;
}

/* Sticky sidebar column (minutes / newsletter-archive pages). */
.fd-sticky-col {
	position: sticky;
	top: 88px;
}
@media (max-width: 781px) {
	/* Columns stack at WP's mobile breakpoint — sticky makes no sense there. */
	.fd-sticky-col {
		position: static;
	}
}

/* ---- Reduced motion ----------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		transition-duration: 0.001ms !important;
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
	}
	.fd-lift:hover {
		transform: none;
	}
	.fd-arrow-link:hover {
		gap: 6px;
	}
	.fd-tile:hover .fd-tile__img,
	.fd-tile:focus-visible .fd-tile__img {
		transform: none;
	}
}

/* Responsive grids: WordPress grid blocks with an explicit columnCount keep
   that column count at every width (they don't collapse). Force card grids to
   fewer columns on small screens. Specificity (0,2,0) beats WP's per-container
   (0,1,0) rule; !important guards against source-order surprises.

   BOTH selectors are needed. `wp:group` with a grid layout renders
   `.wp-block-group.is-layout-grid`, but `wp:post-template` renders
   `.wp-block-post-template.is-layout-grid` — a different class entirely. Only
   the group form was covered here, so every query-driven card grid on the site
   ("Latest news" and "Find your region" on the home page, the news and region
   archives, "More from the newsroom") stayed three-across on a phone. */
@media (max-width: 782px) {
	.wp-block-group.is-layout-grid,
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
	}
}
/* Phones get one card per row. A news or region card is a photograph, a title
   and two or three lines of supporting text — at half of a 390px screen the
   image is a thumbnail and the excerpt breaks every few words.

   700px to match the prose card grids below. This was the theme's usual 600px,
   which left the query-driven grids (home page "Latest news" and "Find your
   region", the news and region archives, "More from the newsroom") turning at a
   different width from every other card grid on the site. One number now. */
@media (max-width: 700px) {
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: 1fr !important;
	}
}
/* Candidate cards carry a headshot + several lines — one per row on small phones. */
@media (max-width: 430px) {
	.wp-block-group.is-layout-grid.fd-candidates__grid {
		grid-template-columns: 1fr !important;
	}
}
/* Roster names need horizontal room: at two columns a 390px phone leaves each
   name ~152px, which wraps most three-part names onto a second line. */
@media (max-width: 600px) {
	.wp-block-group.is-layout-grid.fd-roster-grid {
		grid-template-columns: 1fr !important;
	}
}
/* Prose card grids get one card per row on a phone. The 782px rule above takes
   every grid to two columns, which is right for a tablet and wrong for a 390px
   phone: two columns leave a bylaws card or a "Who's a member" card about 170px
   wide and the text breaks every few words.

   Reported on /our-party/ and /who-we-are/, and those two pages are the whole
   population — they hold the only `wp:group` grid layouts on the site with no
   className. Every other grid is either .fd-candidates__grid, .fd-roster-grid or
   a wp:post-template, and all three already have a phone rule above. So this
   closes the gap rather than adding a competing rule.

   .fd-candidates__grid is excluded on purpose: it holds short step cards
   ("1 · Apply", "U.S. citizen") that still read fine two-up, and it has its own
   threshold at 430px. Excluding it here keeps that behaviour exactly as it was
   instead of quietly overriding it.

   700px is the card-stacking breakpoint across the site — the post-template rule
   above uses it too. It is deliberately not the theme's general 600px, which
   still governs unrelated layout rules elsewhere in this file.

   This selector also matches .fd-roster-grid, at equal specificity and with the
   same declaration, so the roster grid rides along. Same outcome either way,
   since roster names want the width. */
@media (max-width: 700px) {
	.wp-block-group.is-layout-grid:not(.fd-candidates__grid) {
		grid-template-columns: 1fr !important;
	}
}

/* ── Hero slider ────────────────────────────────────────────────────────────
   Progressive enhancement. Without JS the three slides stack and everything is
   readable; hero-slider.js adds .is-enhanced and builds the controls itself, so
   a no-JS visitor never sees dots that do nothing.

   Auto-advance is opt-in via data-fd-slider-autoplay on the wrapper and is NOT
   set on the home page. Slide 1 is the signup form — the page's primary
   conversion — and rotating away from it every few seconds costs more than the
   other two slides gain. Turn it on only with a reason. */

/* A slide turned off from the editor. hero-slider.js filters these out of the
   rotation entirely, but the rule has to exist here too: with JavaScript off the
   slides stack and every one of them is readable, so without this a "hidden"
   slide would still be on the page for exactly the visitors least able to deal
   with it. Set from Pages → Home via Advanced → Additional CSS class. */
.fd-slide--off {
	display: none;
}

.fd-slider {
	position: relative;
}

/* min-height only once enhanced: while stacked there is nothing to stabilise,
   and reserving 560px would just add dead space for a no-JS visitor. */
.fd-slider.is-enhanced {
	min-height: 560px;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

.fd-slider.is-enhanced .fd-slide[hidden] {
	display: none;
}

.fd-slider__controls {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 0 24px 24px;
}

.fd-slider__dots {
	display: flex;
	align-items: center;
	/* The 10px gap moved inside the button below. A 24px target with a 10px gap
	   between dots would overlap its neighbour, and two overlapping targets are a
	   worse outcome than one small one — you hit the slide you did not want. */
	gap: 0;
}

/* The button is the target; ::before is the dot (P2-14).
   Measured at 10x10 with a 20px pitch, so both the size and the spacing failed
   2.5.8. Painting the dot in a pseudo-element lets the button be a full 24x24
   while the dot stays exactly the 10px the design asks for — and it keeps the
   active state's scale() on the dot, so the *target* never grows and can never
   overlap the dot beside it. */
.fd-slider__dot {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	padding: 0;
	border: none;
	background: none;
	cursor: pointer;
}
.fd-slider__dot::before {
	content: "";
	width: 10px;
	height: 10px;
	border-radius: var(--wp--custom--radius--pill);
	background: rgba(255, 255, 255, 0.34);
	transition: background 0.18s ease, transform 0.18s ease;
}
.fd-slider__dot.is-active::before {
	background: var(--wp--preset--color--gold);
	transform: scale(1.25);
}

.fd-slider__nav {
	display: flex;
	align-items: center;
	gap: 8px;
}

.fd-slider__arrow,
.fd-slider__pause {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border-radius: var(--wp--custom--radius--pill);
	border: 1px solid rgba(255, 255, 255, 0.28);
	background: transparent;
	color: var(--wp--preset--color--snow);
	cursor: pointer;
	transition: border-color 0.18s ease, background 0.18s ease;
}
.fd-slider__arrow:hover,
.fd-slider__pause:hover {
	border-color: var(--wp--preset--color--sky);
	background: rgba(42, 169, 224, 0.18);
}

.fd-slider__arrow:focus-visible,
.fd-slider__pause:focus-visible,
.fd-slide:focus-visible {
	outline: 3px solid var(--wp--preset--color--gold);
	outline-offset: 3px;
}

/* The panel is focusable so keyboard users can reach non-focusable slide
   content, but it should not paint a ring when focus arrives by click. */
.fd-slide:focus:not(:focus-visible) {
	outline: none;
}

/* The dot's target is 24px but the dot is 10px, so the ring goes on the dot.
   Ringing the invisible box would float a halo 7px clear of anything visible. */
.fd-slider__dot:focus-visible {
	outline: none;
}
.fd-slider__dot:focus-visible::before {
	outline: 3px solid var(--wp--preset--color--gold);
	outline-offset: 3px;
}

/* The mockup pins the controls absolutely at bottom:26px over the slide. At
   phone width slide 1's capture form stacks to ~5 rows and collides with them.
   In flow instead — the slider is already a flex column, so the controls simply
   sit under the active slide at every width. */
@media (max-width: 600px) {
	.fd-slider.is-enhanced {
		min-height: 0;
	}
	.fd-slider__controls {
		padding: 0 24px 20px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.fd-slider__dot::before,
	.fd-slider__arrow,
	.fd-slider__pause {
		transition: none;
	}
	.fd-slider__dot.is-active::before {
		transform: none;
	}
}

/* ── Numbered step cards ────────────────────────────────────────────────────
   Ported from "Component Mockups (standalone).html" — the four-fronts grid.
   The idea worth keeping is the emphasis slot: a row of quiet numbered cards
   with exactly one inverted, so the eye starts in the right place.

   The mockup sits on a light ground with the emphasis card in navy. This band
   is already navy, so the relationship is flipped rather than copied: the quiet
   cards keep the translucent-white treatment the rest of this band uses
   (matching .fd-doc-card so the page stays coherent), and the emphasis card
   lifts to solid navy-2 with a gold numeral. Gold on navy-2 is 9.38:1 and
   satisfies the Gold-on-Navy-Only rule in DESIGN.md.

   Contrast on the quiet card ground rgb(34,52,67): snow title 12.80:1, mist
   body 8.14:1, gold link 9.94:1, and the slate numeral 3.52:1 — which is the
   tightest figure here and is fine because it is a 2.6rem decorative numeral,
   the one job DESIGN.md reserves Slate for. Do not reuse Slate at body size. */

.fd-steps {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 20px;
}

.fd-step {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid rgba(255, 255, 255, 0.12);
	border-radius: var(--wp--custom--radius--base);
	padding: 30px 26px 26px;
}

.fd-step__num {
	font-size: var(--wp--preset--font-size--headline);
	font-weight: 800;
	line-height: 1;
	letter-spacing: -0.02em;
	/* Mist, not Slate. Slate on this dark card measured 3.52:1 at 16px/800 —
	   under the 4.5 floor, since 800 weight only counts as large text at 18.66px
	   and over. Same DESIGN.md rule as the header sub-line, inverted ground:
	   "Slate is decorative only, never small body text". Mist gives 8.14:1. */
	color: var(--wp--preset--color--mist);
	font-variant-numeric: tabular-nums;
}

.fd-step__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--title);
	font-weight: 800;
	line-height: var(--wp--custom--line-height--snug);
	color: var(--wp--preset--color--snow);
}

.fd-step__body {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	line-height: var(--wp--custom--line-height--body);
	color: var(--wp--preset--color--mist);
}

.fd-step__cta {
	margin-top: auto;
	padding-top: 6px;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	color: var(--wp--preset--color--gold);
	text-decoration: none;
}
.fd-step__cta:hover,
.fd-step__cta:focus-visible {
	text-decoration: underline;
}

/* The emphasis slot. One per grid — more than one and there is no emphasis. */
.fd-step.is-emphasis {
	background: var(--wp--preset--color--navy-2);
	border-color: rgba(241, 232, 25, 0.35);
}
.fd-step.is-emphasis .fd-step__num {
	color: var(--wp--preset--color--gold);
}

@media (max-width: 782px) {
	.fd-steps {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
@media (max-width: 600px) {
	.fd-steps {
		grid-template-columns: 1fr;
	}
	.fd-step {
		padding: 24px 20px 22px;
	}
}

/* ── Region bands (the /regions/ hub) ───────────────────────────────────────
   Emitted only by blocks/region-bands. Built from the .fd-chapter-card idioms —
   grid, dividers, overflow:hidden, stack at 860px — with ONE deliberate
   omission: no height. A fixed height is exactly what broke the page this
   replaces, where the archive's Query Loop inherited .fd-region-card's 340px and
   clipped 485px of content.

   Not clickable: no .fd-lift, no hover transform, no cursor:pointer. A card that
   lifts while being unclickable is backlog P1-1. */
.fd-region-bands > .fd-region-band {
	display: grid;
	grid-template-columns: 260px 1fr;
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--card);
	overflow: hidden;
}

/* THE WASH IS MEASURED, AND IT DECIDES WHAT THE TYPE CAN BE. A 12% accent mix
   over navy puts snow at 10.4–11.8:1 and mist at 6.6–7.5:1 on all three
   chapters — but the RAW accent as text on that same wash is 4.4:1 on sky, i.e.
   below AA. So panel text is snow and mist only, and the accent carries as the
   rule above the name. Same finding .fd-hero__kicker already records.

   Capped at 12%: past roughly 18% the white starts dropping AND peach and gold
   mix toward mud (#3E3E43, #3D4B33). Navy has to stay recognisably navy. */
.fd-region-band__panel {
	position: relative;
	display: flex;
	flex-direction: column;
	padding: 16px;
	background:
		linear-gradient(
			180deg,
			color-mix(in srgb, var(--fd-accent, var(--wp--custom--accent-fallback)) 12%, transparent) 0%,
			transparent 62%
		),
		var(--wp--preset--color--navy);
}

/* Falls back to flat navy when a region has no featured image, rather than the
   collapsed empty figure that made these cards silently disappear once.

   height:auto is load-bearing, not tidiness. wp_get_attachment_image() emits
   width="1024" height="768", and those attributes are presentational hints that
   outrank aspect-ratio — without this the photo rendered 228x768 and every band
   came out ~1100px tall instead of ~310px. It did not show in a screenshot,
   because force-decoding the photo for the capture substituted an element with
   no width/height attributes, which then obeyed aspect-ratio correctly. The
   measurement caught what the picture hid. */
.fd-region-band__img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	border-radius: var(--wp--custom--radius--sharp);
	/* Shows only while the photograph is still painting, or through a transparent
	   one. Navy Deep at 0.2 rather than pure black: DESIGN.md already records the
	   two card scrims hardcoding rgba(12,26,38) as a known deviation, and a third
	   dark neutral — a different one — is how a palette stops being a palette. */
	background: rgba(12, 26, 38, 0.2);
}

.fd-region-band__plate {
	margin-top: 14px;
}

.fd-region-band__rule {
	display: block;
	width: 40px;
	height: 4px;
	/* Same as the hero kicker: at 4px tall, pill clamps to exactly the 2px this
	   used to hardcode. Identical pixels, one fewer off-scale value. */
	border-radius: var(--wp--custom--radius--pill);
	margin-bottom: 10px;
	background: var(--fd-accent, var(--wp--custom--accent-fallback));
}

.fd-region-band__name {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-4);
	font-weight: 800;
	line-height: var(--wp--custom--line-height--snug);
	letter-spacing: -0.01em;
	color: var(--wp--preset--color--snow);
}

.fd-region-band__count {
	margin: 3px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 600;
	color: var(--wp--preset--color--mist);
}

.fd-region-band__blurb {
	margin: 12px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	line-height: var(--wp--custom--line-height--body);
	color: var(--wp--preset--color--mist);
}

.fd-region-band__chair {
	margin: 16px 0 0;
	padding-top: 16px;
	border-top: 1px solid rgba(255, 255, 255, 0.18);
}
.fd-region-band__chair .fd-label {
	display: block;
	color: var(--wp--preset--color--mist);
}
.fd-region-band__chair-name {
	display: block;
	margin-top: 3px;
	font-weight: 800;
	color: var(--wp--preset--color--snow);
}

.fd-region-band__body {
	display: flex;
	flex-direction: column;
	padding: 22px 26px;
	border-left: 1px solid var(--wp--preset--color--line);
}

/* The single highest-risk declaration in this block. Raw gold on snow is 1.24:1
   — invisible. --fd-accent-deep maps it to bronze at 5.39:1, and render.php sets
   that property inline. The second var() argument is mandatory, not stylistic: a
   bare var() on an undefined custom property computes to `unset` and inherits,
   silently unstyling this line. */
.fd-region-band__eyebrow {
	margin: 0 0 14px;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	text-transform: uppercase;
	color: var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
}

.fd-region-band__places {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	/* Was a flat 10px when each place was a bordered box and the border did the
	   separating. Without it the rows need their own vertical rhythm. */
	row-gap: 12px;
	column-gap: 22px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Boxed chips became a caret-marked list 2026-08-24. The bordered version put
   a 1.5px outline around every place name, which at a dozen places per band was
   a wall of rounded rectangles competing with the panel itself.

   The caret takes --fd-accent-DEEP, not --fd-accent, and that is the whole
   reason this rule is commented. The old border could use the raw accent
   because a 1.5px rule reads as decoration; a 6px glyph that replaces the
   bullet is the only thing marking the row, and South's accent is gold at
   1.24:1 on snow — it would have vanished entirely, leaving that one band
   looking like unstyled text. fdc_accent_deep() maps gold to bronze at 5.39:1.

   The second var() argument stays mandatory: a bare var() on an undefined
   custom property computes to `unset` and inherits. */
.fd-place {
	position: relative;
	padding: 2px 0 2px 18px;
}

.fd-place::before {
	content: "";
	position: absolute;
	left: 1px;
	top: 0.48em;
	width: 5px;
	height: 5px;
	border-right: 2px solid var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	border-bottom: 2px solid var(--fd-accent-deep, var(--wp--preset--color--sky-deep));
	transform: rotate(-45deg);
}
.fd-place__name {
	display: block;
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
}
.fd-place__captain {
	display: block;
	margin-top: 2px;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
}

/* margin-top:auto pins the actions to the floor so bands of different chip
   counts still line their CTAs up with the panel's bottom edge. The separator
   rule below must NOT set margin-top — `:not(:first-child)` scores (0,2,0) and
   would beat the auto at (0,1,0), which left North's row floating with dead
   space under it. */
.fd-region-band__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px 18px;
	margin-top: auto;
	padding-top: 18px;
}
.fd-region-band__actions:not(:first-child) {
	border-top: 1px solid var(--wp--preset--color--line);
}

/* One filled primary among two arrow links, so nine links across the page read
   as three groups of one action rather than nine equal arrows. */
.fd-region-band__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 10px 20px;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--snow);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	text-decoration: none;
}
.fd-region-band__cta:hover,
.fd-region-band__cta:focus-visible {
	background: var(--wp--preset--color--navy-2);
	color: var(--wp--preset--color--snow);
}

/* 860px is where .fd-chapter-card stacks and for the same reason: a two-column
   chip grid beside a 260px panel stops working before the grid itself does. The
   photo goes wide at that point — a full-width 4:3 would eat the fold. */
@media (max-width: 860px) {
	.fd-region-bands > .fd-region-band {
		grid-template-columns: 1fr;
	}
	.fd-region-band__body {
		border-left: 0;
		border-top: 1px solid var(--wp--preset--color--line);
	}
	.fd-region-band__img {
		aspect-ratio: 16 / 9;
	}
}
@media (max-width: 600px) {
	.fd-region-band__places {
		grid-template-columns: 1fr;
	}
}

/* Shared visually-hidden utility. NOT a refactor of .fd-cand__sr — that one is a
   scoped copy on purpose, because it is seeded into post_content and must not
   depend on any other stylesheet surviving. */
.fd-sr {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ── Region cards (option 1c) ───────────────────────────────────────────────
   Ported from "Regional Card Explorations.dc.html" in the Claude Design
   project — option 1c, "Full-bleed photo, scrim plate".

   The accent rule and the link colour come from --fd-accent, which
   includes/accent.php injects per card from each region's fdc_accent_color
   meta. North sky, Mid peach, South gold — the same trio the exploration used.

   THE SCRIM IS NOT THE MOCKUP'S. Its gradient reaches 0.5 alpha by 40%, but the
   plate here runs to about 46% of the card, so the name would sit in the weak
   part of the ramp. That is the same failure measured on the candidate cards,
   where the lightest photograph put the name at 3.25:1. Holding 0.88 to 50%
   keeps every plate element dark-backed; verified against all three real region
   photographs rather than assumed. */

/* Scoped to its own container. This class was hand-written by the regions
   archive's Query Loop until 2026-08-23, so the rule below silently applied a
   340px fixed height and a navy ground to a light text card and clipped it.
   The archive now uses blocks/region-bands and writes no classes of its own;
   scoping means a future stray class cannot reach this rule either. */
.fd-region-cards > .fd-region-card {
	position: relative;
	display: block;
	height: 340px;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--base);
	background: var(--wp--preset--color--navy);
	box-shadow: 0 12px 30px rgba(22, 41, 57, 0.18);
	text-decoration: none;
	isolation: isolate;
}

.fd-region-card__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.35s ease;
}

.fd-region-card__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
		to top,
		rgba(12, 26, 38, 0.96) 0%,
		rgba(12, 26, 38, 0.88) 50%,
		rgba(12, 26, 38, 0.34) 74%,
		rgba(12, 26, 38, 0) 100%
	);
}

.fd-region-card__plate {
	position: absolute;
	inset: auto 24px 22px 24px;
}

/* 40x4 accent rule, straight from the exploration. */
.fd-region-card__rule {
	display: block;
	width: 40px;
	height: 4px;
	margin-bottom: 14px;
	background: var(--fd-accent, var(--wp--preset--color--sky));
}

.fd-region-card__name {
	display: block;
	font-size: var(--wp--preset--font-size--title);
	font-weight: 800;
	letter-spacing: -0.02em;
	line-height: var(--wp--custom--line-height--snug);
	color: var(--wp--preset--color--snow);
}

/* The exploration puts a written blurb here. This keeps the city list instead:
   the section is called "Find your region" and asks the reader to look up the
   city they know, so the cities ARE the mechanism. Dropping them for prose
   would leave the heading writing a cheque the cards no longer cash. */
.fd-region-card__cities {
	display: block;
	margin: 8px 0 14px;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.55;
	color: rgba(255, 255, 255, 0.82);
}

.fd-region-card__cta {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 700;
	color: var(--fd-accent, var(--wp--preset--color--sky));
	transition: gap 0.18s ease;
}

.fd-region-card:hover .fd-region-card__img,
.fd-region-card:focus-visible .fd-region-card__img {
	transform: scale(1.04);
}
.fd-region-card:hover .fd-region-card__cta {
	gap: 11px;
}
.fd-region-card:focus-visible {
	outline: 3px solid var(--wp--preset--color--gold);
	outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
	.fd-region-card__img,
	.fd-region-card__cta {
		transition: none;
	}
	.fd-region-card:hover .fd-region-card__img {
		transform: none;
	}
}

/* ── Newsletter aside (sidebar signup) ──────────────────────────────────────
   Option 3b from "Newsletter Signup Explorations.dc.html" — the light card with
   the inline pill row — with a ZIP field added.

   WHY 3b AND NOT ONE OF THE NAVY ONES. Both templates that carry this already
   end with the full-width navy newsletter band, and the article adds the voter
   action and donate bands on top of that. A second navy newsletter block on the
   same page reads as a repeat rather than a second chance. This one sits quietly
   beside the prose and lets the band below do the loud version.

   WHY ZIP AND NOT FIRST NAME. The exploration offers a name as the second field.
   A name personalises an email; the ZIP decides which of the three chapters a
   subscriber reaches, because includes/mailerlite.php resolves the region group
   from it and the confirmation echoes the chapter back. Without it, a signup
   from an article has no region context at all and lands in the general group.
   It is the field that earns the extra tap.

   The form carries .fd-subscribe, so assets/subscribe.js picks it up and posts
   to the same /fdc/v1/subscribe endpoint as every other form on the site. No
   second integration. */

.fd-news-aside {
	background: var(--wp--preset--color--snow);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: 0 1px 2px rgba(22, 41, 57, 0.06);
	padding: 22px 20px;
}

.fd-news-aside__head {
	display: flex;
	align-items: center;
	gap: 9px;
	margin-bottom: 10px;
	color: var(--wp--preset--color--sky-deep);
}

.fd-news-aside__title {
	font-size: var(--wp--preset--font-size--body);
	font-weight: 800;
	letter-spacing: -0.01em;
	color: var(--wp--preset--color--ink);
}

.fd-news-aside__body {
	margin: 0 0 14px;
	font-size: var(--wp--preset--font-size--small);
	line-height: var(--wp--custom--line-height--body);
	color: var(--wp--preset--color--stone);
}

.fd-news-aside__form {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.fd-news-aside__field {
	width: 100%;
	/* Inputs are content-box by default here, so a bare height plus the 1px
	   border rendered 48px against the button's 46 and the row sat crooked. */
	box-sizing: border-box;
	/* 46px to match .fd-subscribe button[type="submit"], so the ZIP field and the
	   button sit on one baseline. */
	height: 46px;
	padding: 0 16px;
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--snow);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
}
/* Stone, not Slate. DESIGN.md reserves Slate for decoration and says explicitly
   it is never small text on a light ground — and here the placeholder is the
   only visible label, so it has to be readable. Slate measured 3.64:1. */
.fd-news-aside__field::placeholder {
	color: var(--wp--preset--color--stone);
}
.fd-news-aside__field:focus {
	outline: none;
	border-color: var(--wp--preset--color--sky);
	box-shadow: 0 0 0 3px rgba(42, 169, 224, 0.18);
}

/* The exploration puts field and button on one row. With ZIP that would be
   three controls in a 340px column, so the email keeps its own full-width row
   and ZIP shares the second with the button — which also puts the fields in the
   order they are filled, before the control that submits them. */
.fd-news-aside__row {
	display: flex;
	gap: 8px;
}

.fd-news-aside__field--zip {
	flex: 0 0 38%;
	min-width: 0;
	/* A five-digit code should not reflow the row as it is typed. */
	font-variant-numeric: tabular-nums;
}

/* Only the flex. Everything else — pill radius, sky-deep fill, snow label, 46px,
   the gold focus ring, the hover to Sky — comes from
   `.fd-subscribe button[type="submit"]`, which already styles every subscribe
   button on the site. That rule is (0,1,1) and beats a lone class, which is how
   this was found: the exploration draws a navy button, and overriding to navy
   would have made this the one subscribe button that does not match the others.
   Inheriting is the better answer, so this sets nothing it does not have to. */
.fd-news-aside .fd-subscribe button[type="submit"] {
	/* Matches the shared rule's own shape (class + attribute + type) and adds one
	   more class, because `.fd-news-aside .fd-news-aside__submit` is (0,2,0) and
	   loses to `.fd-subscribe button[type="submit"]` at (0,2,1) — the element
	   selector is what tips it. The button stayed `flex: none` and the row never
	   filled. */
	flex: 1 1 auto;
	padding: 0 16px;
}

.fd-news-aside__fine {
	margin: 10px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	line-height: 1.55;
	color: var(--wp--preset--color--stone);
}

/* subscribe.js appends its status note inside the form. */
/* subscribe.js appends .fd-form-note to whichever form it handles, and the base
   rules for it are the on-dark pair — both newsletter bands sit on navy. This
   card is snow, so is-success inherited snow-on-snow and the confirmation was
   invisible at 1:1. Everything below is the on-light equivalent.

   Success is ink at 600 rather than the palette's green: green is 4.33:1 on
   snow, under AA for text this size, and DESIGN.md reserves it for the status
   pill, which carries a tint behind it. The success signal is the sentence and
   the chapter link, not the hue — which also survives colour-blindness. */
.fd-news-aside .fd-form-note {
	margin-top: 10px;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
}
.fd-news-aside .fd-form-note.is-success {
	color: var(--wp--preset--color--ink);
}
/* Alert Red, the same on-light error colour the announcement bar settled on
   (4.76:1). Peach is the on-navy error and is far too light here. */
.fd-news-aside .fd-form-note.is-error {
	color: var(--wp--preset--color--red);
}
/* Base sets this to sky for navy. Back to sky-deep, which .fd-arrow-link is
   already tuned to for light grounds. */
.fd-news-aside .fd-form-note .fd-arrow-link {
	color: var(--wp--preset--color--sky-deep);
}

.fd-news-aside :focus-visible {
	outline: 3px solid var(--wp--preset--color--sky);
	outline-offset: 2px;
}

/* Below WP's column-stacking breakpoint the aside drops under the article, and
   a sticky element in a stacked column is meaningless. .fd-sticky-col already
   handles that — it was in this stylesheet, unused, before this part existed. */
@media (max-width: 781px) {
	.fd-news-aside {
		margin-top: 32px;
	}

	/* Stacked, the card spans the whole article measure, and the 38%/rest split
	   that reads well inside a 330px column becomes a stubby ZIP against a very
	   wide Join — worst around tablet portrait, where the stacked card is at its
	   widest. Each control gets its own full-width row instead. */
	.fd-news-aside__row {
		flex-direction: column;
	}

	/* flex-basis follows the MAIN axis, which is now vertical — so the 38% above
	   would set this field's HEIGHT, not its width, and the row would come apart.
	   Back to auto so the shared 46px holds. */
	.fd-news-aside__field--zip {
		flex: 0 0 auto;
	}

	/* Same selector shape as the desktop override, later in the file, so it wins
	   on order rather than by escalating specificity again. */
	.fd-news-aside .fd-subscribe button[type="submit"] {
		flex: 0 0 auto;
		width: 100%;
	}
}

/* ---- About Us band (home) ----------------------------------------------------

   Exploration 4b: an offset collage of three overlapping frames, copy to the
   right. Its job is structural before it is decorative — this is the only light
   surface in the first 1,600px of the page, and it is what stops the hero and
   the tile grid reading as one continuous navy mass.

   The frames are positioned in PERCENTAGES inside an aspect-ratio box rather
   than the exploration's fixed 440px height, so the composition scales with the
   column instead of coming apart at intermediate widths. */

.fd-about__grid {
	display: grid;
	grid-template-columns: 1.1fr 1fr;
	gap: 72px;
	align-items: center;
}

/* Copy is FIRST in the markup so reading and tab order reach the mission
   statement before the photographs; this puts it back on the right visually.
   Doing it this way round also means the mobile stack needs no order reset. */
.fd-about__collage {
	order: -1;
	position: relative;
	/* Matches the exploration's 440px against its ~549px column. */
	aspect-ratio: 5 / 4;
}

.fd-about__eyebrow {
	margin: 0;
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sky-deep);
}

/* h-3 at 800, matching the section headings this one sits between — "Find a way
   to get involved today" and "Latest news" both render 1.9rem/800.

   Two wrong answers were tried first. The exploration's literal
   clamp(2rem, 3.4vw, 2.7rem) was a near-miss on all three numbers against a
   documented step, the same quiet drift logged for breakpoints in P3-11. Then
   h-2, which IS the step DESIGN.md calls `section` — but on this page that
   resolves to 44.8px against its neighbours' 30.4px, so the About band would
   have out-shouted the section beneath it. The page's own convention wins over
   the token's name; DESIGN.md documents 1.9rem as `headline`, so this is still
   on the ramp. */
.fd-about__title {
	margin: 14px 0 18px;
	font-size: var(--wp--preset--font-size--h-3);
	font-weight: 800;
	line-height: 1.15;
	color: var(--wp--preset--color--ink);
}

/* Stone, not Slate — the Muted Split Rule: Stone on light, Mist on dark. */
.fd-about__body {
	margin: 0 0 16px;
	max-width: 32em;
	/* The lede step. 1.06rem came from the exploration and sat between the
	   documented body (1rem) and lede (1.18rem) steps, belonging to neither. */
	font-size: var(--wp--preset--font-size--lede);
	line-height: 1.6;
	color: var(--wp--preset--color--stone);
}

.fd-about__cta {
	display: inline-flex;
	align-items: center;
	margin-top: 12px;
}

/* ---- The frames --- */

.fd-about__frame {
	position: absolute;
	border-radius: var(--wp--custom--radius--base);
	overflow: hidden;
	/* The tint an unfilled frame shows. Every slot is empty today, so this is
	   what the section actually renders as until the photographs are cleared —
	   the same trick the tiles use, where an unfilled slot falls back to the
	   colour the filled ones multiply to, and a half-filled set still reads as
	   deliberate rather than broken. */
	background: var(--wp--preset--color--paper);
}

.fd-about__frame--lg {
	left: 0;
	top: 0;
	width: 78%;
	height: 78%;
	box-shadow: 0 18px 44px rgba(22, 41, 57, 0.22);
}

/* The two small frames overlap the large one. The white ring is doing real
   work: without it the overlap reads as a collision rather than as separate
   photographs, and it is the only thing separating two images that may well
   share a palette. Snow via the preset — never a hardcoded #fff. */
.fd-about__frame--a,
.fd-about__frame--b {
	box-shadow: 0 0 0 4px var(--wp--preset--color--snow), 0 12px 30px rgba(22, 41, 57, 0.18);
}

.fd-about__frame--a {
	right: 0;
	top: 18%;
	width: 44%;
	height: 40%;
}

.fd-about__frame--b {
	right: 8%;
	bottom: 0;
	width: 50%;
	height: 36%;
}

/* An awaiting-photo frame reads as a deliberate placeholder, not a glitch.
   Paper on snow is about 1.02:1 — near enough invisible that three empty frames
   look like a rendering fault to anyone reviewing the page, which is exactly the
   wrong signal to send a committee looking at staging. The dashed hairline says
   "photograph pending" without a word of copy.

   Scoped with :not(:has()) so it disappears by itself the moment a slot is
   filled — there is no second edit to remember, and no way to leave a dashed
   border around a real photograph. */
.fd-about__frame:not(:has(.fd-about__photo)) {
	border: 1px dashed var(--wp--preset--color--line);
	box-shadow: none;
}

.fd-about__photo,
.fd-about__img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
}

.fd-about__img {
	object-fit: cover;
	object-position: var(--fd-about-focus, 50% 40%);
}

/* No scrim on any frame, deliberately. Nothing sits on these photographs — the
   exploration's peach stat card was dropped and the copy lives in its own
   column — so a gradient over them would be decoration over content, which the
   Don't list rules out. If a caption ever comes back, reuse one of the three
   ramps that already exist (tile multiply, region cards 0.88@50%, candidate
   cards 0.86@45%) rather than inventing a fourth. */

@media (max-width: 782px) {
	.fd-about__grid {
		grid-template-columns: 1fr;
		gap: 40px;
	}
	/* Copy leads on a phone, so the desktop order:-1 is undone. And absolute
	   positioning cannot survive this width — the percentages are tuned to a
	   two-column composition — so the collage resets to a plain grid rather than
	   getting a second set of tuned numbers to maintain. */
	.fd-about__collage {
		order: 0;
		aspect-ratio: auto;
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 14px;
	}
	.fd-about__frame {
		position: relative;
		left: auto;
		right: auto;
		top: auto;
		bottom: auto;
		width: auto;
		height: auto;
		aspect-ratio: 8 / 5;
	}
	.fd-about__frame--lg {
		grid-column: 1 / -1;
		aspect-ratio: 16 / 9;
	}
	/* The ring exists to separate overlapping frames. Nothing overlaps once this
	   is a grid, so it becomes a stray white outline — down to the shared card
	   shadow. */
	.fd-about__frame--a,
	.fd-about__frame--b {
		box-shadow: 0 12px 30px rgba(22, 41, 57, 0.18);
	}
}


/* ---- Card surface — the block style "Card" (core/group) ------------------- */
/* register_block_style() in functions.php registers this variation's NAME and
   label and nothing else; it emits no CSS. So .is-style-fd-card rendered as a
   bare, transparent div in all 187 places it is used across 27 files, and
   .fd-lift below was a hover shadow on a surface that did not exist —
   .fd-news-card and .fd-list-card only ever styled the image INSIDE the card,
   which is what gave the omission away.

   Every usage sits on snow or paper, so this is a light surface; nothing here
   assumes a dark parent. The :not(.has-background) guard leaves the one gold
   card (and any future explicit background) alone — those set the colour
   themselves and only want the border, radius and shadow.

   Deliberately NOT applied to .fd-cand: it opts out of a resting shadow on
   purpose (see the note above .fd-cand). */
.is-style-fd-card {
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--base);
	box-shadow: var(--wp--preset--shadow--card);
}

.is-style-fd-card:not(.has-background) {
	background-color: var(--wp--preset--color--snow);
}

/* ---- Guide cards (/voting-guides/) --------------------------------------- */
/* The 2026 panels are portrait PNGs, 1200x1800 and 1294x2000. wp_image emits
   width and height attributes, and an explicit height attribute outranks any
   aspect-ratio we set — the same trap that squashed the region band photo to
   228px. height:auto is what actually lets these scale. */
.fd-guide-thumb img {
	width: 100%;
	height: auto;
	display: block;
	border-radius: var(--wp--custom--radius--sharp);
	border: 1px solid var(--wp--preset--color--line);
}

/* The slate row is a flex pair (thumb + text) rather than a grid cell, so its
   thumbnail is capped instead of filling. */
.is-style-fd-card > .fd-guide-thumb {
	flex: 0 0 auto;
	max-width: 128px;
	margin: 0;
}

/* Three panel links stacked in one paragraph — <br> separated, so they need
   their own line-height to stay legible at caption size. */
.fd-guide-cards .fd-arrow-link {
	display: inline-block;
	line-height: 1.9;
}

/* Constrained layout writes margin-inline:auto on children, which centres the
   capped columns; the grid wants them stretched edge to edge. */
.fd-guide-cards > .wp-block-group {
	margin-left: 0;
	margin-right: 0;

	/* The three regions have blurbs of different lengths — South names eight
	   municipalities and wraps to a third line — so the link stacks started at
	   three different heights. Column flex plus margin-top:auto pins them to the
	   bottom of every card instead.

	   The selector below has to outrank the layout rule that sets a top margin
	   on every child but the first: that is `*:not(:first-child)` at (0,2,0),
	   which quietly beat a bare `margin-top: auto` on the candidate CTA row
	   once already. This lands at (0,3,1). */
	display: flex;
	flex-direction: column;
}

.fd-guide-cards > .wp-block-group > p:last-child {
	margin-top: auto;
	padding-top: 4px;
}

/* ---- Step cards on /how-to-vote/ ----------------------------------------- */
/* The three-step row (Register / Make a plan / Vote) is the page's spine, but
   it was rendered in exactly the same white card as the eight destination cards
   below it, and its headings were .fd-meta-line at 0.72rem against 1rem on
   those — so the section that should read as a summary read as a quieter
   version of the list. Navy inverts it.

   The background comes from the block's own navy preset rather than a rule
   here, which is what makes .is-style-fd-card:not(.has-background) skip the
   white fill; see the card-surface note at the end of this file. Only the
   border needs overriding — the shared #DEE5EC would draw a bright outline
   around a dark card.

   Text colours are set on the blocks, not here, so the editor shows them
   truthfully: snow is 14.89:1 on navy and mist is 9.47:1. The stone these
   descriptions used to carry is 2.09:1 there and had to go. */
.fd-step-card {
	border-color: rgba(255, 255, 255, 0.12);
}

/* ---- Events page: detail rows and format badges -------------------------- */
/* The compact .fd-event-card above is unchanged and still what home, the region
   pages and the minutes sidebar render. These rules only apply inside
   .fd-events-list--detail, which only /events/ asks for. */
.fd-events-list--detail {
	max-width: none;
}

.fd-event-card--detail {
	align-items: flex-start;
	padding: 16px 18px;
	gap: 16px;
}

.fd-event-card--detail .fd-date-chip {
	width: 62px;
	padding: 8px 0;
}

.fd-event-card--detail .fd-event-card__title {
	font-size: 1.08rem;
}

.fd-event-card__badges {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	margin: 0 0 5px;
}

/* Navy on sky is 5.57:1 and navy on peach is 7.25:1, both measured. White on
   either fails badly — white on sky is 2.68:1 — which is why the badge text
   colour is fixed here rather than inherited from whatever contains it. */
.fd-event-badge {
	font-size: var(--wp--preset--font-size--eyebrow, 0.72rem);
	font-weight: 800;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--wp--preset--color--navy, #162939);
	padding: 2px 9px;
	border-radius: var(--wp--custom--radius--pill, 99px);
	white-space: nowrap;
}

.fd-event-badge--in-person {
	background: var(--wp--preset--color--sky, #2aa9e0);
}

.fd-event-badge--zoom {
	background: var(--wp--preset--color--peach, #f7a072);
}

/* The override reason ("Officer elections require in-person voting") explains a
   month that breaks the usual pattern. It sits beside the badge rather than in
   the meta line so it reads as a caveat on the format, not as venue detail. */
.fd-event-card__why {
	font-size: var(--wp--preset--font-size--caption, 0.84rem);
	color: var(--wp--preset--color--stone, #4a5a68);
}

/* ---- Events page: sticky calendar column --------------------------------- */
/* 88px clears the fixed header, so a keyboard user tabbing into the calendar is
   not scrolled under it. Sticky is dropped below the two-column breakpoint,
   where the calendar sits above the list and pinning it would cover the list.

   782px, not 783: core's columns stylesheet stacks at max-width 781px and goes
   nowrap at min-width 782px, so 783 left exactly one pixel of viewport where the
   columns were side by side and the calendar did not stick. */
@media (min-width: 782px) {
	.fd-events-aside {
		position: sticky;
		top: 88px;
	}
}

/* ---- Events page: recurring cadence panel -------------------------------- */
/* Rows are links, so the whole row is the target rather than the name alone —
   a two-line row with only its first line clickable is a small target and an
   inconsistent one. */
.fd-cadence {
	list-style: none;
	margin: 10px 0 0;
	padding: 0;
}

.fd-cadence__row + .fd-cadence__row {
	border-top: 1px solid var(--wp--preset--color--line);
}

.fd-cadence__link {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 10px;
	align-items: center;
	padding: 9px 0;
	text-decoration: none;
	color: inherit;
}

.fd-cadence__link:hover .fd-cadence__name,
.fd-cadence__link:focus-visible .fd-cadence__name {
	color: var(--wp--preset--color--sky-deep);
}

/* The dot carries the same colour each region uses everywhere else, so the four
   rows are scannable by hue before they are read. It is decoration — the name
   beside it is the actual label — hence aria-hidden in the markup. */
.fd-cadence__dot {
	width: 8px;
	height: 8px;
	border-radius: var(--wp--custom--radius--pill, 99px);
	flex: none;
}

.fd-cadence__text {
	min-width: 0;
}

.fd-cadence__name {
	display: block;
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
}

.fd-cadence__when {
	display: block;
	margin-top: 1px;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
}

/* ---- Events hero: a floor on the band height ----------------------------- */
/* The region heroes carry tabs, a button, text links and an overlapping chapter
   card, so they are tall because of their contents. This one holds a breadcrumb,
   an H1 and one line of intro — at 2545px wide it collapsed to 247px, a 10:1
   letterbox that cropped through the faces in the photograph.

   clamp() ties the floor to viewport width so the band grows as the page does
   and the crop stays roughly as deep on a wide monitor as on a laptop, rather
   than going panoramic. Scoped to --tall so .fd-hero--photo keeps behaving
   exactly as it does on the three region pages. */
.fd-hero--tall {
	min-height: clamp(360px, 32vw, 540px);
	display: flex;
	align-items: center;
}

.fd-hero--tall .fd-hero__body {
	width: 100%;
}

/* ---- Events list pager --------------------------------------------------- */
/* Disabled ends are rendered as spans, not as anchors with a dead href, so
   nothing focusable does nothing — the same rule that keeps the month chevrons
   off this page. */
.fd-events-pager {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	flex-wrap: wrap;
	margin-top: var(--wp--preset--spacing--40);
	padding-top: 14px;
	border-top: 1px solid var(--wp--preset--color--line);
}

.fd-events-pager__step {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	color: var(--wp--preset--color--sky-deep);
	text-decoration: none;
	white-space: nowrap;
}

.fd-events-pager__step:hover,
.fd-events-pager__step:focus-visible {
	text-decoration: underline;
}

.fd-events-pager__step.is-disabled {
	color: var(--wp--preset--color--stone);
	opacity: 0.45;
}

.fd-events-pager__nums {
	display: flex;
	align-items: center;
	gap: 4px;
}

.fd-events-pager__num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* 40px, not the 28px the numeral needs — a page control is a touch target
	   before it is a number. */
	min-width: 40px;
	height: 40px;
	padding: 0 6px;
	border-radius: var(--wp--custom--radius--sharp);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	color: var(--wp--preset--color--sky-deep);
	text-decoration: none;
}

.fd-events-pager__num:hover,
.fd-events-pager__num:focus-visible {
	background: var(--wp--preset--color--paper);
}

.fd-events-pager__num.is-current {
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--snow);
}

.fd-events-pager__count {
	margin: 8px 0 0;
	font-size: var(--wp--preset--font-size--caption);
	color: var(--wp--preset--color--stone);
}

/* ---- Page banners -------------------------------------------------------- */
/* .fd-hero-img has been the page-banner class since the About cluster shipped,
   and until now NOTHING styled it. The 3:1 band came entirely from the
   fd-banner generated size being 2200x734 — which works right up until a source
   is narrower than 2200px, because then WordPress cannot produce that crop and
   falls back to something taller. A 1280x960 photograph rendered the minutes
   band at 615px where every sibling sat at 358px.

   Pinning the ratio here makes the band's shape a property of the band rather
   than of whichever file happens to fill it. An undersized source now costs
   sharpness, which is visible and recoverable, instead of layout, which looks
   like a bug.

   height:auto is load-bearing, not tidying: wp_get_attachment_image() emits
   width and height ATTRIBUTES, and a height attribute outranks aspect-ratio. */
.fd-hero-img img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 1;
	object-fit: cover;
}

/* Photo credit ------------------------------------------------------------
   Rendered only for an attachment that carries one (fulton-dems-core
   includes/images.php), which today is a single CC BY-SA image on the
   press-release archive. Overlaid rather than stacked so a credited card
   occupies exactly the same box as an uncredited one — no reflow, and the
   200px figure stays the flex item it already was.

   `position: relative` is set unconditionally rather than through :has(),
   which would leave the credit positioning against the wrong ancestor on any
   browser that lacks it. On an uncredited figure it changes nothing.

   In :where() so it is 0,0,0 — a floor, not a claim. Written bare it was 0,1,0
   and outranked `.fd-hero__media` (line ~348) purely by sitting later in the
   file, which collapsed the hero on all three region pages. "Changes nothing on
   an uncredited figure" is what the sentence above always meant; :where() is
   what makes it true. (:has() was rejected above for support reasons — :where()
   is a different feature and has been Baseline since 2021.)

   Anything that needs a real positioned ancestor still declares it itself:
   .fd-list-card .wp-block-post-featured-image below, and .fd-hero .fd-hero__media. */
:where(.wp-block-post-featured-image) {
	position: relative;
}
/* The credit is position:absolute, and until now the ONLY thing offering it a
   positioning context was the :where() above — which matches featured images and
   nothing else. A credited photograph placed as a page banner is a core/image
   (fdc_slot_image_block writes one into post_content), so its credit escaped the
   figure entirely and anchored to some ancestor further up: present in the HTML,
   correct in the DOM, invisible on the page. That is the worst way for a credit
   to fail, because every check short of looking at it passes.

   .fd-hero-img is named explicitly rather than relying only on :has(), so the
   banner case does not depend on selector support. The :has() rule then covers
   any other core/image that gains a credit later.

   NOT the same thing as the .fd-hero .fd-hero__media warning at ~368: that is the
   navy hero's background photograph, which has a scrim above it in the stacking
   order. This is the in-content banner figure, which has nothing over it. */
.fd-hero-img,
.wp-block-image:has(> .fd-photo-credit) {
	position: relative;
}

/* The hero variant sits OUTSIDE .fd-hero__media (see the note beside that rule, and
   includes/images.php which emits it as a sibling). Being a direct child of .fd-hero, it is
   no longer trapped in the figure's stacking context and z-index 2 clears the scrim at 1.

   .fd-hero > * is position:relative at ~316; this needs absolute, and (0,2,0) beats it. */
.fd-hero .fd-photo-credit--hero {
	position: absolute;
	z-index: 2;
	left: 0;
	right: auto;
	bottom: 0;
	width: 100%;
}

.fd-photo-credit {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	padding: 5px 7px 4px;
	font-size: 10px;
	line-height: 1.3;
	letter-spacing: 0.01em;
	color: var(--wp--preset--color--snow);
	/* Scrim, because the credit sits over a photograph whose brightness is
	   unknown — a night vigil today, something else tomorrow. */
	background: linear-gradient(to top, rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0));
	pointer-events: auto;
}
/* The licence link has to be exempted from the card-link rules by name.
   `.wp-block-post-featured-image a { display:block; height:100% }` and
   `.fd-list-card .wp-block-post-featured-image a { position:absolute; inset:0;
   width:100%; height:100% }` were written for the ONE anchor that used to exist
   in a featured image — the card link wrapping the img. A second anchor inside
   the figure inherits both, and the licence link was being stretched over the
   whole thumbnail: it looked like overlapping text, but it was also swallowing
   every click meant for the card. Specificity here matches the 0,3,1 of the
   card-link rule and wins on order. */
.fd-list-card .wp-block-post-featured-image .fd-photo-credit a,
.wp-block-post-featured-image .fd-photo-credit a {
	position: static;
	display: inline;
	inset: auto;
	width: auto;
	height: auto;
	object-fit: fill;
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 2px;
}
.fd-photo-credit a:hover,
.fd-photo-credit a:focus-visible {
	text-decoration-thickness: 2px;
}

/* ── Touch targets ──────────────────────────────────────────────────────────
   P2-14. The backlog recorded "14 sitewide"; measured against the rendered
   page it is 25 on the home page alone — but only after discarding 51 false
   positives the original count had swept in: 30 admin-bar links (logged-in
   chrome, not the site), the skip link (visually hidden by design), 6 core
   submenu arrows that sit inside their parent link's target, 2 honeypot inputs
   that MUST stay tiny, and 5 inline links inside prose, which 2.5.8 exempts.

   The 25 that are real collapse into four shapes, and none of them needs the
   design to change — only the box around it. Where the element is a hair under
   24px, min-height on a flex box is enough and shifts nothing; where it is a
   small icon, the target has to grow properly. */

/* Footer link columns: 20px tall with 29.6px of air between them, so the space
   to be a legal target was already there — the box simply was not claiming it.
   Scoped to `p > a` so the social icons below, which are also `.fd-footer a`,
   keep their own treatment. */
.fd-footer p > a {
	display: inline-flex;
	align-items: center;
	min-height: 24px;
}

/* Social icons are 14.4px on a 23.4px pitch — 0.6px short of allowing a 24px
   target. Padding on the anchor buys it: the icon does not change size, the
   anchor becomes 24.4px, and the pattern's blockGap drops to 0 so the visual
   spacing between icons stays the ~10px the footer was designed with. */
.fd-footer .is-style-logos-only .wp-block-social-link-anchor {
	padding: 5px;
}

/* Both 1-1.5px short. `.fd-arrow-link` is already inline-flex; the brand link
   becomes one. Deliberately NOT an ::after overlay: `.fd-arrow-link` already
   carries one (line ~76) to stretch it over `.fd-lift` cards, and a second
   overlay would take that card-sized target away — trading a fixed 23px link
   for a broken 300px one. */
.fd-arrow-link {
	min-height: 24px;
}
.fd-header__brand-name a {
	display: inline-flex;
	align-items: center;
	min-height: 24px;
}

/* Breadcrumb links, 40x19. Same treatment; the trail is a single line with its
   own separators, so a taller link box changes nothing about how it reads. */
.fd-breadcrumb a {
	display: inline-flex;
	align-items: center;
	min-height: 24px;
	vertical-align: middle;
}

/* ── Header search: the field never opened ──────────────────────────────────
   Separate defect, found while measuring the above — the search input reported
   0px wide, which is not a small target but an unusable one.

   The block is `buttonPosition: button-only`, so core ships a script that drops
   `…__searchfield-hidden` and focuses the field. That half works: the class is
   removed, the form animates 55px → 218px, and focus really does land in the
   input. The input itself stays 0px wide with `flex-grow: 0`, so a keyboard or
   screen-reader user is placed inside a box they cannot see and a mouse user
   clicks the icon and watches nothing happen. Typing goes nowhere.

   Core's own expanded rule (`flex-basis: 100%`) matches but loses; the only
   other rule reaching the input is a zero-specificity `:where()`. Rather than
   depend on that cascade the theme states the open state itself — this header
   already overrides the block's look, so owning its behaviour belongs here.

   Verified by measurement: the field goes to 163px and accepts text. */
.fd-header__search:not(.wp-block-search__searchfield-hidden) .wp-block-search__input {
	flex-grow: 1;
	flex-basis: auto;
	width: auto;
	padding: 8px 14px;
	border-radius: var(--wp--custom--radius--pill);
}
.fd-header__search .wp-block-search__input:focus-visible {
	outline: 3px solid var(--wp--preset--color--gold);
	outline-offset: 2px;
}

/* Geometry only, deliberately. A first version also recoloured the field to sit
   on the navy — white text on a 5% white fill — and none of the colour
   declarations took effect; the field renders as a normal white input. Rather
   than escalate specificity to win an argument, the declarations came out: they
   were describing an appearance the page does not have, which is the kind of
   thing that reads as intent to whoever edits this next.

   It is also the better result. The open field sits directly above the hero's
   Email / ZIP / Phone inputs, which are white on the same navy — so a white
   search field is the consistent choice, not a compromise. */

/* The 1px shortfall. Three separate links measured 23px tall — the events pager,
   the region "Contact →" button and the contact address — and all three for the
   same reason: 14.4px text on a 1.6 line-height is a 23.04px box, and the nine
   PDF links on /meeting-minutes/ are the same box again. Nothing about the
   design is wrong; it just lands a single pixel under the threshold. */
.fd-events-pager__step,
.fd-arrow-button .wp-block-button__link,
.fd-minutes-row__files a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 24px;
}

/* An address is one unbreakable token, so inline-flex costs no wrapping here.
   In-sentence links are exempt from 2.5.8 anyway — this only has to be right
   for the ones standing alone as their paragraph, which is how both the
   contact address and the phone number are written. */
a[href^="mailto:"],
a[href^="tel:"] {
	display: inline-flex;
	align-items: center;
	min-height: 24px;
}
