/*
Theme Name: CommunityIMPACT
Theme URI: https://communityimpact.net
Author: CommunityIMPACT, Inc.
Author URI: https://communityimpact.net
Description: Custom theme for the CommunityIMPACT, Inc. county-facing marketing site. Secular, county-administrator audience. Drives every page toward "Schedule a Connect."
Version: 1.2.0
Requires at least: 6.4
Requires PHP: 8.0
Text Domain: communityimpact
*/

/* ==========================================================================
   1. Design tokens  --  v1.2.0 palette

   Four brand colors, each given ONE job. Contrast is computed from WCAG 2.1
   relative luminance, never eyeballed.

     blue    #004a98   8.63:1 on white   ACTION & SYSTEM
     purple  #675186   6.78:1 on white   VOICE & BRAND
     green   #60b138   2.68:1 on white   ACCENT -- decorative fill only
     gold    #c29a16   2.65:1 on white   ACCENT -- decorative fill only

   Three rules fall out of those numbers, and they are load-bearing:

   (1) GREEN AND GOLD ARE NEVER TEXT ON A LIGHT GROUND. At 2.68 and 2.65
       they fail not only AA body (4.5) and AA large (3.0) but also the
       WCAG 1.4.11 non-text floor (3.0). So they cannot be a form-control
       border, a focus ring, or any boundary that *conveys* something on
       white either -- only decorative fill inside an icon that has a text
       label beside it. Where green or gold must be text on white, use
       --ci-green-text (#437b27, 5.12:1) or --ci-gold-text (#876b0f,
       5.07:1). Both were chosen with real margin on purpose; v1.1.0
       shipped a 4.51:1 gold that had to be corrected, and the 4.5x
       candidates here (#48842a / #917310) would repeat that mistake.

       The finding worth keeping: green and gold's problem is *white*, not
       green and gold. Both clear AA body on ink (6.58 / 6.65). They are
       the accent that lives on dark surfaces. That is a real job.

   (2) PURPLE AND BLUE ARE 1.27:1 AGAINST EACH OTHER. They are all but
       identical in luminance, so they can never carry hierarchy by
       contrast. Never purple text on blue or blue text on purple, at any
       size. When the two sit together, separation has to come from weight,
       size or ground -- not colour. This is the single most consequential
       property of this palette.

   (3) DARK TEXT GROUNDS ARE --ci-ink AND --ci-purple-deep ONLY.
       --ci-purple-dark (#4a3a61) carries white fine (10.15) but green
       measures only 3.79 on it, so it is a decorative ground, not a text
       one. The hero's purple radial is capped at .34 alpha for the same
       reason -- see the measured note on .ci-hero in section 7. On that
       band gold is the only safe accent: green reaches just 3.90:1 at the
       radial's bright point, where the eyebrow happens to sit.

   --ci-line-strong (4.11:1) is the form-control border, because WCAG
   1.4.11 holds a control boundary to 3:1 and --ci-line (1.25:1) does not
   meet it. --ci-line stays for decorative rules only.

   The focus ring is deliberately TWO-TONE. Gold alone is 12.23:1 on ink
   but 1.44:1 on white; ink alone is 17.63:1 on white but invisible on the
   dark bands. Neither works everywhere, so both ship concentrically and at
   least one always carries. See section 4.
   ========================================================================== */
:root {
	/* Brand -- ACTION & SYSTEM.
	   Blue is the highest-contrast colour available (8.63:1) and reads as
	   civic rather than charitable, which is the right register for a county
	   administrator. It owns every "do this" affordance: buttons, links,
	   focus, form controls, and the single most important heading on a page. */
	--ci-blue: #004a98;         /* 8.63:1 on white -- AA body */
	--ci-blue-deep: #003772;    /* 11.74:1 -- hover / dark ground */
	--ci-blue-tint: #eef3fa;

	/* Brand -- VOICE & BRAND.
	   Purple carries the brand's own speaking voice: display headings, chrome,
	   and the hue base of the dark bands. See rule (2) above -- it must never
	   meet blue as text-on-colour. */
	--ci-purple: #675186;       /* 6.78:1 on white -- AA body */
	--ci-purple-dark: #4a3a61;  /* decorative dark ground ONLY, see rule (3) */
	--ci-purple-deep: #2e2440;  /* 14.56:1 vs white -- a real text ground */
	--ci-purple-tint: #f4f1f8;

	/* Brand -- ACCENT. Decorative fill on light grounds, text on dark ones.
	   Never a border, focus ring or any boundary that conveys meaning on
	   white: 2.68 and 2.65 miss even the 3:1 non-text floor. */
	--ci-green: #60b138;        /* 2.68:1 on white / 6.58:1 on ink */
	--ci-green-text: #437b27;   /* 5.12:1 on white -- AA body */
	--ci-green-tint: #eef7e9;
	--ci-gold: #c29a16;         /* 2.65:1 on white / 6.65:1 on ink */
	--ci-gold-text: #876b0f;    /* 5.07:1 on white -- AA body */
	/* The gold reserved for text on dark bands. Measured against the hero's
	   lightest composite at the 0.08 overlay cap: 5.3:1. Base #c29a16 stays
	   the decorative fill, where no contrast floor applies. */
	--ci-gold-on-dark: #d4ac28;
	--ci-gold-tint: #f9f5e8;

	/* Neutrals -- blue-leaning now that the palette's centre of gravity has
	   moved from purple to blue. The old ink (#231832) read visibly warm
	   beside #004a98. */
	--ci-ink: #12182b;          /* 17.63:1 on white */
	--ci-body: #3c4257;         /*  9.96:1 on white */
	--ci-muted: #5d6478;        /*  5.90:1 on white */
	--ci-white: #ffffff;
	--ci-bg-soft: #f8f9fb;
	--ci-line: #e3e6ed;         /* 1.25:1 -- decorative rules ONLY */
	--ci-line-strong: #767d90;  /* 4.11:1 -- form-control borders (needs 3:1) */
	--ci-on-dark: #e9e6f0;      /* body copy on ink: 14.31:1 */
	/* Two-tone focus ring -- see the note at the top of this file.
	   Gold: 12.23:1 on ink, 1.44:1 on white.  Ink: 17.63:1 on white.
	   Shipped concentrically so one of them always carries. */
	--ci-focus: #ffd166;
	--ci-focus-companion: #12182b;

	/* Type */
	--ci-font-display: 'Source Serif 4', Georgia, 'Times New Roman', serif;
	--ci-font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

	/* Scale */
	--ci-space-2xs: 0.375rem;
	--ci-space-xs: 0.625rem;
	--ci-space-sm: 1rem;
	--ci-space-md: 1.75rem;
	--ci-space-lg: 3rem;
	--ci-space-xl: 5rem;
	--ci-space-2xl: 7rem;

	--ci-radius: 12px;
	--ci-radius-sm: 6px;
	--ci-container: 1160px;
	/* The page's column system, as grid tracks: gutter | content | gutter.
	   Every top-level section uses these SAME tracks, so they all resolve to
	   an identical left rail at every width.

	   Tracks rather than a padding formula on purpose. Two earlier attempts
	   both failed a real measurement:
	     - `calc(50vw - container/2)` -- vw counts the classic scrollbar but
	       the layout viewport does not, so full-bleed bands landed 7px left
	       of everything else and overflowed 7px off the right edge.
	     - `calc(50% - container/2)` -- resolved to the 28px floor instead of
	       the real gutter at 1440px wide, leaving sections at x=28 while the
	       header sat at x=161.
	   minmax() tracks need neither a percentage nor a viewport unit, so
	   neither failure mode applies. */
	--ci-track-gutter: minmax(var(--ci-space-md), 1fr);
	--ci-track-content: minmax(0, var(--ci-container));
	--ci-measure: 68ch;

	--ci-rail-w: 3px;
	--ci-node: 84px;
	/* rgb(18, 24, 43) == --ci-ink, so shadows tint with the new blue-leaning
	   neutral rather than the retired purple one. */
	--ci-shadow: 0 1px 2px rgba(18, 24, 43, .06), 0 8px 28px -12px rgba(18, 24, 43, .18);
}

/* ==========================================================================
   2. Reset & base
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html {
	-webkit-text-size-adjust: 100%;
	/* clip, not hidden: `hidden` on a scroll container silently disables
	   position: sticky on the site header. */
	overflow-x: clip;
}
body {
	margin: 0;
	font-family: var(--ci-font-body);
	font-size: 1.0625rem;
	line-height: 1.65;
	color: var(--ci-body);
	background: var(--ci-white);
	font-synthesis-weight: none;
	-webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--ci-blue); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:hover { color: var(--ci-blue-deep); }

h1, h2, h3, h4 {
	font-family: var(--ci-font-display);
	color: var(--ci-ink);
	line-height: 1.14;
	letter-spacing: -0.015em;
	margin: 0 0 var(--ci-space-sm);
	text-wrap: balance;
}
h1 { font-size: clamp(2.1rem, 1.35rem + 3.2vw, 3.6rem); font-weight: 600; }
h2 { font-size: clamp(1.6rem, 1.2rem + 1.7vw, 2.4rem); font-weight: 600; }
h3 { font-size: clamp(1.2rem, 1.08rem + 0.5vw, 1.45rem); font-weight: 600; letter-spacing: -0.01em; }
h4 { font-size: 1.0625rem; font-weight: 600; }
p { margin: 0 0 var(--ci-space-sm); }
p:last-child { margin-bottom: 0; }

/* Two-tone focus ring.

   v1.1.0 used gold alone here and claimed it was "visible on both light and
   dark grounds". Measured, that is false: #ffd166 is 12.23:1 on ink but
   **1.44:1 on white** -- essentially invisible on every light page, which is
   most of the site. Ink alone has the mirror problem (17.63:1 on white, lost
   entirely on the hero and CTA bands).

   So both ship, concentrically: the gold sits tight against the control
   (box-shadow, 0-3px) and the ink outline sits just outside it (offset 3px,
   so the two rings abut rather than overlap). On a light ground the ink ring
   carries; on a dark one the gold does. One of them always clears 3:1. */
:where(a, button, input, textarea, select, summary):focus-visible {
	outline: 3px solid var(--ci-focus-companion);
	outline-offset: 3px;
	box-shadow: 0 0 0 3px var(--ci-focus);
	border-radius: 3px;
}
/* Inverted on the dark bands: there the ink ring is the invisible one, so
   gold takes the outline and ink becomes the inner companion. Same two rings,
   swapped, so the ordering always puts the visible one outermost. */
.ci-hero :where(a, button):focus-visible,
.ci-cta-banner :where(a, button):focus-visible,
.site-footer :where(a, button):focus-visible {
	outline-color: var(--ci-focus);
	box-shadow: 0 0 0 3px var(--ci-focus-companion);
}

.container { max-width: var(--ci-container); margin: 0 auto; padding: 0 var(--ci-space-md); }
.visually-hidden, .screen-reader-shortcut:not(:focus) {
	position: absolute; width: 1px; height: 1px; overflow: hidden;
	clip-path: inset(50%); white-space: nowrap;
}

/* ==========================================================================
   3. The eyebrow rule -- the spine motif, reduced to a section marker.
   Gold on light surfaces is decoration (a 6px rule), never text: the label
   itself is set in ink or gold-text, both of which clear AA.
   ========================================================================== */
.ci-eyebrow {
	font-family: var(--ci-font-body);
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ci-gold-text);
	margin: 0 0 var(--ci-space-xs);
	display: flex;
	align-items: center;
	gap: 0.7rem;
}
.ci-eyebrow::before {
	content: "";
	width: 34px;
	height: 3px;
	background: var(--ci-gold);
	flex: 0 0 auto;
}
/* On dark grounds gold IS text-safe (6.35:1 on ink), so it carries the label. */
.ci-hero .ci-eyebrow,
.ci-cta-banner .ci-eyebrow,
.site-footer .ci-eyebrow { color: var(--ci-gold-on-dark); }
.ci-eyebrow.is-centered { justify-content: center; }

/* ==========================================================================
   4. Skip link
   ========================================================================== */
.skip-link {
	position: absolute; left: 0; top: -100%;
	background: var(--ci-ink); color: var(--ci-white);
	padding: 0.8rem 1.4rem; z-index: 1000;
	border-radius: 0 0 var(--ci-radius-sm) 0;
	font-weight: 600; text-decoration: none;
}
.skip-link:focus { top: 0; color: var(--ci-white); }

/* ==========================================================================
   5. Buttons
   ========================================================================== */
.btn, .wp-block-button__link.btn {
	display: inline-flex; align-items: center; justify-content: center;
	font-family: var(--ci-font-body);
	font-weight: 600;
	font-size: 1rem;
	padding: 0.85rem 1.7rem;
	border-radius: 999px;
	text-decoration: none;
	border: 2px solid transparent;
	cursor: pointer;
	transition: background-color .18s ease, color .18s ease, border-color .18s ease, box-shadow .18s ease;
}
/* Blue owns every action. White on blue is 8.63:1 -- the strongest pairing
   in the palette -- and blue reads civic rather than charitable, which is the
   register a county administrator is scanning for. */
.btn-primary { background: var(--ci-blue); color: var(--ci-white); box-shadow: var(--ci-shadow); }
.btn-primary:hover { background: var(--ci-blue-deep); color: var(--ci-white); }
.btn-outline { background: transparent; border-color: rgba(255,255,255,.65); color: var(--ci-white); }
.btn-outline:hover { background: var(--ci-white); color: var(--ci-blue-deep); border-color: var(--ci-white); }
.btn-ghost { background: transparent; border-color: var(--ci-blue); color: var(--ci-blue); }
.btn-ghost:hover { background: var(--ci-blue-tint); color: var(--ci-blue-deep); }
/* Gold-filled button: ink on gold is 6.65:1 -- the inverse pairing, and one
   of the two places raw gold is allowed to sit under text. */
.btn-gold { background: var(--ci-gold); color: var(--ci-ink); }
.btn-gold:hover { background: var(--ci-gold-on-dark); color: var(--ci-ink); }

/* ==========================================================================
   6. Site header
   ========================================================================== */
.site-header {
	border-bottom: 1px solid var(--ci-line);
	background: rgba(255,255,255,.92);
	backdrop-filter: saturate(1.4) blur(8px);
	position: sticky; top: 0; z-index: 500;
	/* Same tracks as #main, so the logo sits on the identical left rail as
	   the hero headline, the spine nodes and the card grid. Previously
	   .header-inner added its own 28px inset on top of the container edge,
	   putting the logo 28px right of everything below it. */
	display: grid;
	grid-template-columns: var(--ci-track-gutter) var(--ci-track-content) var(--ci-track-gutter);
}
.header-inner {
	grid-column: 2;
	display: flex; align-items: center; justify-content: space-between;
	gap: var(--ci-space-md);
	padding: 0.8rem 0;
	max-width: none; margin: 0;
}
/* Spans all three tracks so its border-top runs edge to edge; hidden until
   the burger opens it, and only reachable below the 900px breakpoint. */
.mobile-nav { grid-column: 1 / -1; display: none; }
/* The logo is now a tight 1.82:1 crop, so height alone sizes it correctly.
   The previous 500x500 asset made this a 48x48 box with the wordmark
   floating inside it -- that, not a broken path, was the real logo bug. */
.site-logo { display: block; flex: 0 0 auto; }
.site-logo img { height: 46px; width: auto; }

.main-nav ul { list-style: none; display: flex; gap: var(--ci-space-md); margin: 0; padding: 0; }
.main-nav a {
	color: var(--ci-ink); font-weight: 500; text-decoration: none;
	font-size: 0.97rem; padding: 0.35rem 0; position: relative;
}
.main-nav a::after {
	content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
	height: 3px; background: var(--ci-green); border-radius: 2px;
	transform: scaleX(0); transform-origin: left;
	transition: transform .2s ease;
}
.main-nav a:hover, .main-nav a[aria-current="page"] { color: var(--ci-blue); }
.main-nav a:hover::after,
.main-nav a[aria-current="page"]::after { transform: scaleX(1); }

.header-ctas { display: flex; align-items: center; gap: var(--ci-space-sm); }
.header-ctas .btn { padding: 0.7rem 1.35rem; font-size: 0.95rem; }
.nav-toggle {
	display: none; background: none;
	border: 2px solid var(--ci-blue); border-radius: var(--ci-radius-sm);
	padding: 0.4rem 0.65rem; font-size: 1.25rem; line-height: 1;
	color: var(--ci-blue); cursor: pointer;
}

@media (max-width: 900px) {
	.main-nav { display: none; }
	.nav-toggle { display: inline-flex; }
	.mobile-nav.is-open { display: block; border-top: 1px solid var(--ci-line); background: var(--ci-white); }
	.mobile-nav ul {
		list-style: none; margin: 0;
		/* The nav spans all three tracks, so it supplies its own gutter --
		   matching the 28px content rail rather than hugging the edge. */
		padding: var(--ci-space-sm) var(--ci-space-md) var(--ci-space-md);
		display: flex; flex-direction: column; gap: 0;
		max-width: var(--ci-container); margin-inline: auto; width: 100%;
	}
	.mobile-nav li + li { border-top: 1px solid var(--ci-line); }
	.mobile-nav a {
		color: var(--ci-ink); font-weight: 600; text-decoration: none;
		display: block; padding: 0.85rem 0;
	}
}
@media (max-width: 560px) {
	.site-logo img { height: 38px; }
	.header-ctas .btn-primary { display: none; } /* the footer + banner CTAs carry it on small screens */
}

/* ==========================================================================
   7. Hero -- SIGNATURE SURFACE
   No stock-photo band and no soft centered gradient. The ground is deep ink,
   and the visual is the brand's own house/heart geometry drawn oversized as
   an inline SVG that bleeds off the right edge. Text is left-aligned against
   it, so the mark and the headline share the frame instead of the headline
   sitting on top of a photo.

   Because the mark is a data-URI SVG background, this restyles the EXISTING
   .ci-hero markup already live on staging -- no re-paste needed.
   ========================================================================== */
.ci-hero {
	position: relative;
	isolation: isolate;
	background:
		/* rgb(103, 81, 134) == --ci-purple. Alpha is capped at .34 for a
		   contrast reason, not a visual one: the radial is brightest exactly
		   where the gold eyebrow sits, and at .45 the composite (#483860)
		   drops gold-on-dark to 4.84:1 -- a pass, but the same no-margin pass
		   that had to be corrected in v1.1.0. At .34 it measures 5.3:1.
		   Green is NOT text-safe anywhere in this band (3.90:1 at the bright
		   point), so the hero's accent colour is gold only. */
		radial-gradient(120% 90% at 12% 8%, rgba(103,81,134,.34) 0%, rgba(103,81,134,0) 60%),
		linear-gradient(158deg, var(--ci-purple-deep) 0%, var(--ci-ink) 52%, #0d1a30 100%);
	color: var(--ci-on-dark);
	/* The horizontal inset centres the content column itself on wide
	   screens, which is why the children below use margin-inline: 0 rather
	   than auto. Centring the children instead would centre the headline --
	   it has a 22ch max-width, so `margin-inline: auto` pushed it into the
	   middle of the band and quietly undid the asymmetric layout. */
	padding-block: clamp(3.5rem, 7vw, 7rem);
	padding-inline: 0;
	display: grid;
	grid-template-columns: var(--ci-track-gutter) var(--ci-track-content) var(--ci-track-gutter);
	text-align: left;
	overflow: hidden;
}
/* Both hero pseudo-elements are absolutely positioned, so neither becomes a
   grid item and neither disturbs the tracks above. */
/* The mark. stroke is white at low opacity so it reads as embossed line-art
   rather than a pasted logo. */
.ci-hero::before {
	content: "";
	position: absolute;
	z-index: -1;
	top: 50%;
	right: clamp(-14rem, -6vw, -4rem);
	transform: translateY(-50%);
	width: clamp(22rem, 42vw, 40rem);
	aspect-ratio: 1;
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='%23ffffff' stroke-width='5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 92 L100 22 L188 92'/%3E%3Cpath d='M158 57 L158 40'/%3E%3Cpath d='M30 84 L30 150'/%3E%3Cpath d='M170 84 L170 150'/%3E%3Cpath d='M30 150 C 62 152, 84 144, 100 130'/%3E%3Cpath d='M170 150 C 138 152, 116 144, 100 130'/%3E%3Cpath d='M100 128 C 76 108, 58 96, 58 78 C 58 64, 70 56, 82 56 C 91 56, 97 61, 100 66 C 103 61, 109 56, 118 56 C 130 56, 142 64, 142 78 C 142 96, 124 108, 100 128 Z'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
	opacity: .17;
	pointer-events: none;
}
/* A hairline of brand color along the bottom edge -- the spine motif again. */
.ci-hero::after {
	content: "";
	position: absolute; inset: auto 0 0 0; height: 4px;
	background: linear-gradient(90deg, var(--ci-blue) 0%, var(--ci-purple) 34%, var(--ci-green) 72%, var(--ci-gold) 100%);
}
.ci-hero > * { position: relative; grid-column: 2; margin-inline: 0; }
.ci-hero .container { max-width: none; padding: 0; margin-inline: 0; }
.ci-hero h1 {
	color: var(--ci-white);
	max-width: 22ch;
	margin-bottom: var(--ci-space-md);
	/* No text-shadow needed any more: the ground is a controlled gradient,
	   not a photograph, so white-on-ink is a fixed 16.8:1 everywhere. The
	   old hero needed a shadow to survive a bright patch of sky. */
}
.ci-hero p {
	color: var(--ci-on-dark);
	font-size: clamp(1.06rem, 1rem + 0.4vw, 1.28rem);
	max-width: 54ch;
	margin-bottom: var(--ci-space-md);
}
.ci-hero-ctas { display: flex; gap: var(--ci-space-sm); flex-wrap: wrap; margin-top: var(--ci-space-md); justify-content: flex-start; }
.ci-hero .wp-block-buttons { justify-content: flex-start; }

@media (max-width: 780px) {
	/* On narrow screens the mark stops competing for the text column and
	   moves behind it as a large, very quiet watermark. */
	.ci-hero::before {
		right: -30%; top: auto; bottom: -12%; transform: none;
		width: 26rem; opacity: .11;
	}
	.ci-hero h1 { max-width: none; }
}

/* ==========================================================================
   8. Thesis band -- the one large statement under the hero.
   ========================================================================== */
.ci-thesis {
	padding-block: clamp(3rem, 6vw, 5.5rem);
	display: grid;
	grid-template-columns: var(--ci-track-gutter) var(--ci-track-content) var(--ci-track-gutter);
	background: var(--ci-bg-soft);
	border-bottom: 1px solid var(--ci-line);
}
/* Left-aligned, not centred: it shares the same left rail as the hero
   headline, the spine nodes and the card grid, so the eye tracks one edge
   down the whole page. */
.ci-thesis > * { grid-column: 2; }
.ci-thesis-inner { max-width: 46rem; margin-inline: 0; }

/* ---------------------------------------------------------------------
   THE THREAD -- the signature.

   The spine's rail does not begin at the spine. It enters here, at the
   thesis band, runs behind this section's text, and hands off to the
   first Connect node below. That is the difference between "there is a
   diagram of the process on this page" and "the process is the page's
   structure": by the time a reader reaches the numbered steps, the line
   they are following is already established.

   Built as a grid item in column 2, deliberately NOT as an absolutely
   positioned element with a calc()'d left offset. Two such formulas were
   already measured failing on this site -- `calc(50vw - container/2)`
   drifted 7px because vw counts the classic scrollbar and the layout
   viewport does not, and `calc(50% - container/2)` collapsed to the gutter
   floor at wide widths. Sharing the real track is the only approach here
   that has held up under measurement, so the thread shares it too and
   lands on the identical rail as the nodes below.

   grid-row: 1 / -1 makes it span the section without consuming a row of
   its own, so it overlaps the text cell rather than displacing it; the
   indent below is what actually keeps the copy clear of it.
   --------------------------------------------------------------------- */
/* Applied to .ci-thesis-inner directly, not to an opt-in class, for the
   same reason .ci-path is styled identically to .ci-spine: the thesis
   markup is ALREADY PUBLISHED on staging. Hanging the thread off a new
   class would mean it only appeared on pages someone re-pasted. This way
   the deploy upgrades the existing Home page on its own. .ci-thread is the
   same treatment, available to any future section that wants to join the
   line.

   The thread hangs off the INNER wrapper rather than the section, so its
   containing block is a plain box in the content column and `left` measures
   from that column's edge. Two alternatives were rejected:
     - a grid item at `grid-row: 1 / -1` -- in an implicit grid `-1` refers
       to the explicit grid's end line, so it silently spans row 1 only and
       would break the moment a second block was added to the section;
     - an absolutely positioned element on the section with a calc()'d left
       offset -- the same shape as the two centring formulas already
       measured failing on this site (see --ci-track-gutter).
   Measuring from a box that is already in the right column needs neither. */
.ci-thesis > *, .ci-thread > * {
	/* Clears the thread by exactly the spine's node column, so the thesis
	   text and the spine's step text share one left edge. */
	padding-left: calc(var(--ci-node) + clamp(1.25rem, 3vw, 2.5rem));
	position: relative;
}
.ci-thesis > *::before, .ci-thread > *::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: calc(var(--ci-node) / 2 - var(--ci-rail-w) / 2);
	width: var(--ci-rail-w);
	border-radius: var(--ci-rail-w);
	/* Fades in from nothing at the top: the thread should look like it is
	   arriving from the hero above, not starting abruptly at a section
	   boundary. */
	background: linear-gradient(180deg, transparent 0%, var(--ci-line) 22%, var(--ci-line) 100%);
}
/* The measure is preserved: without this the node column would eat ~124px
   out of the 46rem the statement was set to read at. */
.ci-thesis-inner {
	max-width: calc(46rem + var(--ci-node) + clamp(1.25rem, 3vw, 2.5rem));
}
.ci-thesis p {
	font-family: var(--ci-font-display);
	font-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);
	line-height: 1.42;
	color: var(--ci-ink);
	letter-spacing: -0.012em;
}
.ci-thesis strong { color: var(--ci-purple); font-weight: 600; }

/* ==========================================================================
   9. THE SPINE -- Connect / Studio / Cohort
   This is the page's structural argument, so it is not three equal cards.
   Three equal cards read as a *menu of options*; Connect -> Studio -> Cohort
   is a *sequence with duration*, and a county administrator needs to know
   the order, the commitment at each stage, and what is asked of them.

   The rail is drawn in CSS (no extra markup), the step numbers come from a
   CSS counter, and the rail's gradient runs purple -> green -> gold so the
   palette itself carries the progression.

   Both class families are styled: .ci-spine* is what the new pattern emits,
   and .ci-path* is the legacy markup ALREADY LIVE on staging. Styling both
   means the deploy upgrades the existing Home page with no re-paste.
   ========================================================================== */
.ci-spine, .ci-path {
	padding-block: clamp(3rem, 6vw, 5.5rem);
	padding-inline: 0;
	position: relative;
}
/* The thread, continued.

   The thesis band above hands the line off here, but the list's own rail
   cannot start at the section's top edge -- it has to start at the first
   node, several rem below the section heading. Left alone that leaves a
   visible break exactly where the reader is meant to understand that the
   thesis and the process are one argument.

   So the section carries a full-height segment at the same x and in the
   same colour as the list's rail. The two are indistinguishable where they
   overlap, and it closes both gaps at once: above the first node, and
   below the last one where the thread continues toward the CTA.

   No calc()'d centring is involved: .ci-spine already sits in #main's
   content column, so its own left edge IS the rail's origin. */
.ci-spine::before, .ci-path::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: calc(var(--ci-node) / 2 - var(--ci-rail-w) / 2);
	width: var(--ci-rail-w);
	border-radius: var(--ci-rail-w);
	background: var(--ci-line);
	/* Behind the node plates, which are opaque white and mask it. */
	z-index: 0;
}
.ci-spine > *, .ci-path > * { position: relative; z-index: 1; }
/* The terminus. The thread does not simply stop at the section edge -- it
   ends in a mark, immediately above the "Schedule a Connect" banner. The
   sequence has a last step, and the last step is talking to us. Gold fill
   with no text on it, so no contrast floor applies. */
.ci-spine::after, .ci-path::after {
	content: "";
	position: absolute;
	bottom: calc(-1 * var(--ci-space-xs));
	left: calc(var(--ci-node) / 2 - 7px);
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: var(--ci-gold);
	z-index: 1;
}
/* Everything in the section's head sits in the body column, on the same left
   edge as the step text below it -- so the thread passes to its left rather
   than through it.

   This has to cover EVERY direct child except the step list, not just the
   h2. Indenting the heading alone left the eyebrow and the intro paragraph
   stranded out at the rail while the heading between them was inset, which
   read as a broken column rather than a deliberate one. The list is excluded
   because it carries its own node column and is already on the rail. */
.ci-spine > *:not(.ci-spine-list):not(.ci-path-grid),
.ci-path  > *:not(.ci-spine-list):not(.ci-path-grid) {
	padding-left: calc(var(--ci-node) + clamp(1.25rem, 3vw, 2.5rem));
}
.ci-spine > h2, .ci-path > h2 {
	text-align: left;
	max-width: calc(24ch + var(--ci-node) + clamp(1.25rem, 3vw, 2.5rem));
}
.ci-spine-list, .ci-path-grid {
	position: relative;
	display: block !important;   /* overrides wp-block-columns' flex row */
	list-style: none;
	margin: var(--ci-space-lg) 0 0;
	padding: 0;
	counter-reset: ci-step;
	max-width: 62rem;
	margin-inline: 0;
	gap: 0 !important;
}
/* The rail itself. */
.ci-spine-list::before, .ci-path-grid::before {
	content: "";
	position: absolute;
	left: calc(var(--ci-node) / 2 - var(--ci-rail-w) / 2);
	top: var(--ci-node);
	bottom: var(--ci-node);
	width: var(--ci-rail-w);
	border-radius: var(--ci-rail-w);
	background: var(--ci-line);
}
/* The lit portion of the rail. --ci-fill is set by assets/js/spine.js as the
   steps scroll into view; with JS off or reduced-motion on it is 100%. */
.ci-spine-list::after, .ci-path-grid::after {
	content: "";
	position: absolute;
	left: calc(var(--ci-node) / 2 - var(--ci-rail-w) / 2);
	top: var(--ci-node);
	width: var(--ci-rail-w);
	height: var(--ci-fill, 100%);
	max-height: calc(100% - var(--ci-node) * 2);
	border-radius: var(--ci-rail-w);
	background: linear-gradient(180deg, var(--ci-blue) 0%, var(--ci-purple) 34%, var(--ci-green) 72%, var(--ci-gold) 100%);
	transition: height .65s cubic-bezier(.22,.61,.36,1);
}

.ci-spine-step, .ci-path-step {
	position: relative;
	counter-increment: ci-step;
	display: grid;
	grid-template-columns: var(--ci-node) 1fr;
	column-gap: clamp(1.25rem, 3vw, 2.5rem);
	align-items: start;
	text-align: left !important;
	padding: 0 0 clamp(2.25rem, 4vw, 3.5rem);
	margin: 0 !important;
	flex-basis: auto !important;
}
.ci-spine-step:last-child, .ci-path-step:last-child { padding-bottom: 0; }

/* The node: a white plate that masks the rail, holding the program icon.

   position/z-index are load-bearing, not decoration. The opaque background
   alone does NOT mask the rail, because of paint order: `.ci-spine-list::after`
   -- the lit gradient rail -- is an ::after, so it is the list's *last child*
   and, being positioned, paints above every static descendant of the steps.
   The node plate was static, so the coloured rail drew straight over each
   icon circle.

   Note this only ever affected the LIT rail. The grey `::before` rail is the
   list's *first* child and so has always painted underneath, which is why the
   section looked correct until a step lit up and the bug appeared to come and
   go with scrolling.

   Making the plate positioned with z-index 2 puts it above both rails.
   `.ci-spine-list` already carries `z-index: 1` from the `.ci-spine > *` rule,
   so it is a stacking context and this value is scoped to it -- it cannot
   escape and interfere with the sticky header (500) or the skip link (1000).
   `.ci-spine-step` is `position: relative` with z-index auto, which is not a
   stacking context, so the value resolves against the rails as intended. */
.ci-spine-step > :first-child,
.ci-path-step > :first-child {
	grid-column: 1;
	grid-row: 1;
	position: relative;
	z-index: 2;
	width: var(--ci-node);
	height: var(--ci-node);
	margin: 0 !important;
	border-radius: 50%;
	background: var(--ci-white);
	border: var(--ci-rail-w) solid var(--ci-line);
	display: grid;
	place-items: center;
	transition: border-color .45s ease, box-shadow .45s ease, transform .45s ease;
}
.ci-spine-step img, .ci-path-step img {
	width: 48px !important;
	height: auto !important;
	margin: 0 !important;
	filter: saturate(.25) opacity(.55);
	transition: filter .45s ease;
}
/* Everything after the icon is the body column. */
.ci-spine-step > :not(:first-child),
.ci-path-step > :not(:first-child) {
	grid-column: 2;
	max-width: 46rem;
}
.ci-spine-step > :nth-child(2), .ci-path-step > :nth-child(2) { grid-row: 1; }

/* Step number, from the counter -- no markup needed. */
.ci-spine-step h3::before, .ci-path-step h3::before {
	content: "0" counter(ci-step);
	display: block;
	font-family: var(--ci-font-body);
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	color: var(--ci-muted);
	margin-bottom: var(--ci-space-2xs);
	transition: color .45s ease;
}
.ci-spine-step h3, .ci-path-step h3 {
	color: var(--ci-ink);
	margin-top: 0;
	padding-top: 0.55rem;
	text-transform: none;
	font-size: clamp(1.3rem, 1.1rem + 0.7vw, 1.65rem);
}
.ci-spine-step p, .ci-path-step p { color: var(--ci-body); }
.ci-spine-step > p:first-of-type, .ci-path-step > p:first-of-type {
	font-size: 1.09rem;
	color: var(--ci-ink);
}

/* Lit state. One transition per node, driven by a single observer. */
.ci-spine-step.is-lit > :first-child,
.ci-path-step.is-lit > :first-child {
	border-color: var(--ci-green);
	box-shadow: 0 0 0 6px rgba(96, 177, 56, .16);
}
.ci-spine-step.is-lit img, .ci-path-step.is-lit img { filter: none; }
.ci-spine-step.is-lit h3::before, .ci-path-step.is-lit h3::before { color: var(--ci-gold-text); }

/* "What you're asked for" fact list under each step. */
.ci-spine-facts, .ci-path-step ul {
	list-style: none;
	margin: var(--ci-space-sm) 0 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: var(--ci-space-2xs) var(--ci-space-sm);
}
.ci-spine-facts li, .ci-path-step ul li {
	font-size: 0.87rem;
	font-weight: 500;
	color: var(--ci-ink);
	background: var(--ci-purple-tint);
	border-radius: 999px;
	padding: 0.3rem 0.85rem;
}

@media (max-width: 640px) {
	:root { --ci-node: 60px; }
	.ci-spine-step, .ci-path-step { column-gap: 1rem; }
	.ci-spine-step img, .ci-path-step img { width: 34px !important; }
	.ci-spine-step h3, .ci-path-step h3 { padding-top: 0.15rem; }
}

/* MOBILE: the thread stops outside the step list.

   Measured at 375px, the node column plus its gap reserves 76px of a 319px
   content width -- nearly a quarter of the line -- and the thesis statement
   dropped to about four words per line. The through-line is worth a lot on a
   wide screen and is not worth that.

   Below 640px the thread therefore renders only where the sequence actually
   lives: inside the step list, which keeps its own rail, its nodes and its
   01/02/03 numbering. The thesis and the section head get their full measure
   back. The sequence still reads; it just stops being a full-page device on
   a screen with no room for one. */
@media (max-width: 640px) {
	.ci-thesis > *::before, .ci-thread > *::before,
	.ci-spine::before, .ci-path::before,
	.ci-spine::after,  .ci-path::after {
		content: none;
	}
	.ci-thesis > *, .ci-thread > *,
	.ci-spine > *:not(.ci-spine-list):not(.ci-path-grid),
	.ci-path  > *:not(.ci-spine-list):not(.ci-path-grid) {
		padding-left: 0;
	}
	.ci-spine > h2, .ci-path > h2 { max-width: 24ch; }
	.ci-thesis-inner { max-width: 46rem; }
}

/* ==========================================================================
   10. Card grids (Strategic Programs / Counties)
   ========================================================================== */
.ci-section {
	padding-block: clamp(3rem, 6vw, 5.5rem);
	padding-inline: 0;
}
.ci-section-head { max-width: var(--ci-measure); margin: 0 0 var(--ci-space-lg); }
.ci-section-head p { max-width: var(--ci-measure); }

/* A statement block: body copy that opens a page, with the first paragraph
   set larger so the eye lands on the problem before the response. Kept to a
   narrower measure than the default, because these are short declarative
   sentences and a full 68ch line makes them read as a run-on. */
.ci-statement p { max-width: 58ch; color: var(--ci-body); }
.ci-statement p + p { margin-top: var(--ci-space-sm); }
.ci-lead {
	font-family: var(--ci-font-display);
	font-size: clamp(1.15rem, 1.02rem + 0.55vw, 1.45rem);
	line-height: 1.45;
	color: var(--ci-ink);
	letter-spacing: -0.008em;
}

/* Safety net for `.wp-block-group__inner-container`.

   The real fix is in inc/theme-setup.php, which removes the core filter that
   injects that wrapper -- see the long note there for why. This rule is only
   a fallback for the cases that would reintroduce it: a theme.json being
   added later, or a plugin wrapping group content itself.

   It is a PARTIAL fallback and worth being honest about the limit: it fixes
   layout, because the children become grid items of the group again, but it
   does not fix selectors. `display: contents` removes the box, not the node,
   so `.ci-spine > h2` and friends would still match the wrapper. If the
   wrapper ever comes back, those rules need the wrapper level added too.

   How this shipped in the first place: the local harness hand-authored the
   card markup as direct children, so it was verifying an assumption about
   WordPress's output rather than the output itself. Perfect four-up grid
   locally, single stacked column live. */
.ci-card-grid > .wp-block-group__inner-container,
.ci-program-grid > .wp-block-group__inner-container,
.ci-needs > .wp-block-group__inner-container {
	display: contents;
}

.ci-card-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(15.5rem, 1fr));
	gap: var(--ci-space-md);
}
.ci-card {
	position: relative;
	border: 1px solid var(--ci-line);
	border-radius: var(--ci-radius);
	padding: var(--ci-space-md);
	background: var(--ci-white);
	transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
	overflow: hidden;
}
/* The rule sits inside the card as a top edge -- green as a fill, never text. */
.ci-card::before {
	content: "";
	position: absolute; inset: 0 0 auto 0; height: 4px;
	background: var(--ci-green);
}
.ci-card:hover { border-color: var(--ci-line-strong); box-shadow: var(--ci-shadow); }
.ci-card h3 { margin-bottom: var(--ci-space-2xs); color: var(--ci-ink); }
.ci-card p { color: var(--ci-body); margin-bottom: 0; }
.ci-card--gold::before { background: var(--ci-gold); }
.ci-card--purple::before { background: var(--ci-purple); }

/* Text-safe accent utilities. Both values below clear 4.5:1 on white --
   the base --ci-green / --ci-gold tones do not and must never be text here. */
.ci-text-gold { color: var(--ci-gold-text); }
.ci-text-green { color: var(--ci-green-text); }

/* ==========================================================================
   10a. WHY WE EXIST -- the six service areas

   Two columns of prose, not six cards. Bordered cards in a grid read as a
   menu of things being sold; these six passages describe one problem in six
   domains and have to read as continuous argument. The only chrome is a
   short rule above each heading, which cycles the four brand colours so the
   set is marked by the whole palette rather than by one accent.
   ========================================================================== */
.ci-needs {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--ci-space-lg) clamp(2rem, 5vw, 4rem);
}
@media (max-width: 52rem) { .ci-needs { grid-template-columns: minmax(0, 1fr); } }

.ci-need > h3 {
	margin: 0 0 var(--ci-space-2xs);
	color: var(--ci-ink);
	font-size: 1.2rem;
}
/* Decorative rule only -- it carries no information the heading beside it
   does not, so raw green and gold are legitimate here. */
.ci-need > h3::before {
	content: "";
	display: block;
	width: 34px;
	height: 3px;
	margin-bottom: var(--ci-space-xs);
	background: var(--ci-blue);
}
.ci-needs > .ci-need:nth-child(4n+2) > h3::before { background: var(--ci-purple); }
.ci-needs > .ci-need:nth-child(4n+3) > h3::before { background: var(--ci-green); }
.ci-needs > .ci-need:nth-child(4n+4) > h3::before { background: var(--ci-gold); }
.ci-need > p { color: var(--ci-body); margin-bottom: 0; max-width: 54ch; }

/* ==========================================================================
   10b. STRATEGIC PROGRAMS -- a 4 + 1 grid

   Five programs, but not five equal slots. Mission of Hope is an established
   sub-brand with its own multicolour identity; the other four share one icon
   family drawn in inc/program-icons.php. Forcing all five into one row would
   either flatten Mission of Hope's identity or make it look like the one that
   went wrong.

   So the section is a feature panel plus a four-up grid. Mission of Hope
   leads on plain white -- the only ground its palette sits correctly on --
   and the matched four follow in identical containers below. The difference
   reads as seniority rather than as an error, and it tracks what the copy
   already says: it is usually a county's first visible win.
   ========================================================================== */
.ci-feature {
	display: grid;
	grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
	gap: clamp(var(--ci-space-md), 4vw, var(--ci-space-lg));
	align-items: center;
	background: var(--ci-white);
	border: 1px solid var(--ci-line);
	border-radius: var(--ci-radius);
	padding: clamp(var(--ci-space-md), 3vw, var(--ci-space-lg));
	margin-bottom: var(--ci-space-md);
}
/* Four colours in the rule, so the feature is marked by the whole palette
   rather than by one of the four programs' accents. */
.ci-feature::before {
	content: "";
	grid-column: 1 / -1;
	height: 4px;
	margin: calc(-1 * clamp(var(--ci-space-md), 3vw, var(--ci-space-lg)))
	        calc(-1 * clamp(var(--ci-space-md), 3vw, var(--ci-space-lg))) 0;
	background: linear-gradient(90deg, var(--ci-blue) 0%, var(--ci-purple) 34%, var(--ci-green) 72%, var(--ci-gold) 100%);
	border-radius: var(--ci-radius) var(--ci-radius) 0 0;
}
.ci-feature-media { display: flex; justify-content: center; }
.ci-feature-media img {
	width: 100%;
	max-width: 15rem;
	height: auto;
}
/* Reserved slot for the Mission of Hope asset, which is not in the repo yet.
   Sized to the artwork's eventual footprint so dropping the file in causes no
   reflow. Dashed, muted, and aria-hidden -- it is scaffolding, not content. */
.ci-feature-slot {
	display: block;
	width: 100%;
	max-width: 15rem;
	aspect-ratio: 1;
	border: 2px dashed var(--ci-line-strong);
	border-radius: var(--ci-radius);
	opacity: .4;
}
.ci-feature-body h3 { margin-bottom: var(--ci-space-2xs); color: var(--ci-ink); }
.ci-feature-body p { color: var(--ci-body); margin-bottom: 0; max-width: 52ch; }

@media (max-width: 40rem) {
	.ci-feature { grid-template-columns: minmax(0, 1fr); }
	.ci-feature-media img, .ci-feature-slot { max-width: 11rem; }
}

/* The matched four. auto-fit would collapse them to 3 + 1 at some widths,
   which reintroduces exactly the odd-one-out problem this layout exists to
   avoid -- so the count is explicit: 4, then 2, then 1. */
.ci-program-grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--ci-space-md);
}
@media (max-width: 62rem) { .ci-program-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 34rem) { .ci-program-grid { grid-template-columns: minmax(0, 1fr); } }

.ci-program-card {
	border: 1px solid var(--ci-line);
	border-radius: var(--ci-radius);
	padding: var(--ci-space-md);
	background: var(--ci-white);
	transition: border-color .2s ease, box-shadow .2s ease;
}
.ci-program-card:hover { border-color: var(--ci-line-strong); box-shadow: var(--ci-shadow); }
.ci-program-card h3 {
	margin: var(--ci-space-sm) 0 var(--ci-space-2xs);
	color: var(--ci-ink);
	font-size: 1.15rem;
}
.ci-program-card p { color: var(--ci-body); margin-bottom: 0; font-size: 0.975rem; }

/* The program icons.

   CommunityIMPACT's own supplied artwork, extracted from the .svg files (see
   the note at the top of inc/program-icons.php -- they were PNGs in an SVG
   wrapper with the transparency held in a separate luminance mask).

   Height-constrained, width auto, so each icon keeps its own aspect ratio.
   They are NOT padded to a common square: the four differ by up to 15px in
   width and forcing them to match would letterbox three of them.

   This replaces a hand-drawn inline-SVG family whose fills were recoloured
   from the palette and alternated green/gold down the row. The real artwork
   carries its own colour, so those rules are gone rather than left as dead
   selectors -- green and gold still appear here, but as the artwork's own
   ink rather than as anything CSS controls. Being imagery beside a real text
   label, no contrast floor applies. */
.ci-picon {
	display: block;
	height: 76px;
	width: auto;
}
@media (max-width: 34rem) {
	/* One card per row on small screens, so there is room to go slightly
	   larger where the artwork's detail needs it most. */
	.ci-picon { height: 88px; }
}

/* ==========================================================================
   11. Context band -- the one place the photograph appears.
   ========================================================================== */
/* No horizontal padding: .ci-context always sits inside a .ci-section,
   which already owns the gutter. Adding another here stacked a third 28px
   inset on top of .entry-content's and .ci-section's, which crushed this
   band to 207px of a 375px screen. Gutters are owned by exactly one
   ancestor -- see the .entry-content rules in section 15. */
.ci-context {
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: 1.05fr 1fr;
	gap: clamp(1.5rem, 4vw, 3.5rem);
	align-items: center;
}
.ci-context img { border-radius: var(--ci-radius); box-shadow: var(--ci-shadow); }
@media (max-width: 780px) { .ci-context { grid-template-columns: 1fr; } }

/* ==========================================================================
   12. CTA banner -- ink ground, so gold can do real work here.
   ========================================================================== */
.ci-cta-banner {
	position: relative;
	background: linear-gradient(152deg, var(--ci-purple-deep) 0%, var(--ci-ink) 100%);
	border: 0;
	border-radius: var(--ci-radius);
	padding: clamp(2.5rem, 5vw, 4rem) var(--ci-space-md);
	text-align: center;
	margin-block: var(--ci-space-xl);
	overflow: hidden;
	color: var(--ci-on-dark);
}
.ci-cta-banner::after {
	content: "";
	position: absolute; inset: auto 0 0 0; height: 4px;
	background: linear-gradient(90deg, var(--ci-blue) 0%, var(--ci-purple) 34%, var(--ci-green) 72%, var(--ci-gold) 100%);
}
.ci-cta-banner h2 { color: var(--ci-white); max-width: 26ch; margin-inline: auto; }
.ci-cta-banner p { color: var(--ci-on-dark); max-width: 46ch; margin-inline: auto; }
.ci-cta-banner .wp-block-buttons { justify-content: center; margin-top: var(--ci-space-md); }
.ci-cta-banner .btn-primary { background: var(--ci-white); color: var(--ci-blue); }
.ci-cta-banner .btn-primary:hover { background: var(--ci-gold); color: var(--ci-ink); }

/* ==========================================================================
   13. Connect form
   Input borders use --ci-line-strong (3.96:1), not --ci-line (1.36:1):
   WCAG 1.4.11 holds control boundaries to 3:1, and the old value failed it.
   ========================================================================== */
.ci-connect-form { max-width: 40rem; margin: 0; }
.ci-connect-form .field { margin-bottom: var(--ci-space-sm); }
.ci-connect-form label {
	display: block; font-weight: 600; margin-bottom: 0.35rem;
	color: var(--ci-ink); font-size: 0.95rem;
}
.ci-connect-form input, .ci-connect-form textarea, .ci-connect-form select {
	width: 100%;
	padding: 0.75rem 0.9rem;
	border: 1px solid var(--ci-line-strong);
	border-radius: var(--ci-radius-sm);
	font: inherit;
	color: var(--ci-ink);
	background: var(--ci-white);
	transition: border-color .15s ease, box-shadow .15s ease;
}
/* Form controls are system, so they are blue. rgb(0, 74, 152) == --ci-blue. */
.ci-connect-form input:hover, .ci-connect-form textarea:hover { border-color: var(--ci-blue); }
.ci-connect-form input:focus, .ci-connect-form textarea:focus {
	border-color: var(--ci-blue);
	box-shadow: 0 0 0 3px rgba(0, 74, 152, .16);
}
/* 8.63:1. The required marker must not rely on colour alone, so the asterisk
   is also announced to screen readers by the field label itself. */
.ci-connect-form .required { color: var(--ci-blue); font-weight: 700; }
.ci-form-note { font-size: 0.9rem; color: var(--ci-muted); }
.ci-form-success, .ci-form-error {
	padding: var(--ci-space-sm) var(--ci-space-md);
	border-radius: var(--ci-radius);
	margin-bottom: var(--ci-space-md);
	border-left: 4px solid;
}
.ci-form-success { background: var(--ci-green-tint); border-color: var(--ci-green-text); color: var(--ci-ink); }
.ci-form-error { background: #fbeaea; border-color: #a5281b; color: var(--ci-ink); }

/* ==========================================================================
   14. Footer
   ========================================================================== */
.site-footer {
	background: var(--ci-ink);
	color: var(--ci-on-dark);
	display: grid;
	grid-template-columns: var(--ci-track-gutter) var(--ci-track-content) var(--ci-track-gutter);
	padding: var(--ci-space-xl) 0 var(--ci-space-md);
	margin-top: var(--ci-space-2xl);
	border-top: 4px solid transparent;
	border-image: linear-gradient(90deg, var(--ci-blue), var(--ci-purple) 34%, var(--ci-green) 72%, var(--ci-gold)) 1;
}
.site-footer a { color: var(--ci-white); text-decoration-color: rgba(255,255,255,.4); }
.site-footer a:hover { color: var(--ci-gold-on-dark); }
.site-footer > * { grid-column: 2; }
.footer-cta { text-align: center; margin: 0 auto var(--ci-space-xl); }
.footer-inner {
	max-width: none; margin: 0;
	display: flex; flex-wrap: wrap; justify-content: space-between;
	gap: var(--ci-space-lg); align-items: flex-start;
}
/* The footer logo sits on a white plate, and it has to.

   logo-vertical.png is 85.8% dark artwork (measured: average of the opaque
   pixels is rgb(78, 22, 93), a deep purple) because it was drawn for a white
   ground. On --ci-ink the house outline and the "IMPACT" wordmark all but
   disappeared -- only the green "COMMUNITY" survived.

   Three ways to fix that; this is the least destructive:
     - Flipping the whole footer to white would remove the dark band that
       closes every page and carries the four-colour rule, and would mean
       re-working the gold eyebrow and white link colours that depend on it.
     - A white knockout of the logo would read cleanly but throws away the
       brand colour, and no knockout version exists in brand-source/.
     - A white plate gives the logo exactly the ground it was designed for
       while the footer stays dark. It is also what a brand kit would specify
       for a dark surface in the absence of a knockout.

   White is the brand's own background colour, so this introduces no new
   value. Generous padding keeps it reading as a lockup rather than a sticker. */
.footer-brand {
	display: inline-block;
	background: var(--ci-white);
	border-radius: var(--ci-radius);
	padding: var(--ci-space-sm) var(--ci-space-md);
}
/* 96px, up from 76 (+26%). The ceiling here is the source asset, not the
   layout: logo-vertical.png is 157x220, so a 2x display wants 192px of natural
   height and there are 220. 96px is comfortably inside that; much past ~110px
   would start upscaling on retina and the mark would go soft.

   At 96px the plate is ~125px wide -- 39% of the 319px content column at
   375px -- and .footer-inner is flex-wrap: wrap, so the brand and the nav wrap
   onto separate rows on mobile rather than competing for width. */
.footer-brand img { height: 96px; width: auto; display: block; }
.footer-nav ul {
	list-style: none; margin: 0; padding: 0;
	display: flex; gap: var(--ci-space-md); flex-wrap: wrap;
}
.footer-nav a { font-weight: 500; text-decoration: none; }
.footer-legal {
	max-width: none; margin: var(--ci-space-lg) 0 0;
	padding-top: var(--ci-space-md);
	border-top: 1px solid rgba(255,255,255,.14);
	font-size: 0.85rem; color: #c3b8cd;
	display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--ci-space-sm);
}
.footer-legal p { margin: 0; }

/* ==========================================================================
   15. Gutenberg content defaults
   ========================================================================== */
/*
 * The wrapper is FULL WIDTH and carries no gutter of its own. Each section
 * centres its own content column with the --ci-gutter formula above.
 *
 * This is deliberate, and replaces an earlier arrangement where
 * .entry-content was measure-constrained and full-bleed bands broke out of
 * it with `width: 100vw; margin-inline: calc(50% - 50vw)`. Two problems with
 * that, both measured:
 *
 *   1. 100vw counts the classic scrollbar but the layout viewport does not,
 *      so on an 820px window every full-bleed band sat 7px left of every
 *      in-flow section and overflowed 7px off the right edge. Resolving the
 *      gutter against 50% of a full-width wrapper instead of 50vw removes
 *      the discrepancy entirely -- no scrollbar maths, no negative margins.
 *   2. The wrapper's own vertical padding pushed a white strip between the
 *      sticky header and the dark hero band.
 */
/*
 * THE COLUMN SYSTEM lives on #main, not on .entry-content.
 *
 * That is not a stylistic preference -- it is what the templates actually
 * emit. front-page.php calls the_content() with NO wrapper, so on Home the
 * blocks are direct children of <main>. page.php wraps its blocks in
 * article.entry-content. Putting the grid only on .entry-content therefore
 * left the entire front page ungoverned, and .alignwide additionally capped
 * that wrapper at the container width, which pinned every section to x=28
 * while the header sat at x=161.
 *
 * So #main owns the tracks, and an .entry-content wrapper spans them and
 * re-declares the same tracks -- which makes both template paths lay out
 * identically.
 */
#main {
	display: grid;
	grid-template-columns: var(--ci-track-gutter) var(--ci-track-content) var(--ci-track-gutter);
	align-content: start;
}
#main > * { grid-column: 2; }
#main > .ci-hero,
#main > .ci-thesis { grid-column: 1 / -1; }

/* Higher specificity than .alignwide on purpose, so the wrapper is never
   re-capped at the container width. */
#main > .entry-content {
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: var(--ci-track-gutter) var(--ci-track-content) var(--ci-track-gutter);
	align-content: start;
	max-width: none;
	margin: 0;
	padding: 0 0 var(--ci-space-xl);
}
.entry-content > * { grid-column: 2; }
.entry-content > .ci-hero,
.entry-content > .ci-thesis { grid-column: 1 / -1; }

/* Prose typed straight into the editor gets a readable measure, left-aligned
   on the same rail as every section rather than centred in the column. */
:where(#main, .entry-content) > :where(p, h1, h2, h3, h4, ul, ol, dl, blockquote, pre, table, figure, .wp-block-image, .wp-block-quote, .wp-block-embed) {
	max-width: var(--ci-measure);
	margin-inline: 0;
}
:where(#main, .entry-content) > .entry-title { margin-top: var(--ci-space-xl); margin-bottom: var(--ci-space-md); }
:where(#main, .entry-content) > h2 { margin-top: var(--ci-space-lg); }
.alignwide { max-width: var(--ci-container); }
.alignfull { max-width: none; }
/* The closing CTA is an inset card, not a full-bleed band: it already sits
   in the content column, so its left edge is on the shared rail. */
:where(#main, .entry-content) > .ci-cta-banner { max-width: none; margin-inline: 0; }

/* ==========================================================================
   16. Motion
   One scroll moment (the rail + its nodes) and short hover transitions.
   Reduced motion removes all of it and renders the rail fully drawn.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
	html { scroll-behavior: smooth; }
}
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: .001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .001ms !important;
		scroll-behavior: auto !important;
	}
	.ci-spine-list::after, .ci-path-grid::after { height: 100% !important; }
	.ci-spine-step > :first-child, .ci-path-step > :first-child {
		border-color: var(--ci-green);
	}
	.ci-spine-step img, .ci-path-step img { filter: none; }
	.ci-spine-step h3::before, .ci-path-step h3::before { color: var(--ci-gold-text); }
}

/* ==========================================================================
   17. Print
   ========================================================================== */
@media print {
	.site-header, .footer-cta, .nav-toggle, .mobile-nav, .ci-cta-banner { display: none !important; }
	.ci-hero { background: none !important; color: #000 !important; }
	.ci-hero::before, .ci-hero::after { display: none !important; }
	.ci-hero h1, .ci-hero p { color: #000 !important; }
	body { color: #000; }
}
