/*
 * MSWC homepage v3 — the cinematic layer.
 *
 * Loaded ONLY on the front page (see functions.php), so nothing in here can
 * move the parity pages. Everything is prefixed .mswc-v3- and the markup that
 * carries these classes is emitted by migration/tools/gen_home_v3.py.
 *
 * Design contract (redesign-spec + the approved v3 plan):
 * - film-first: full-viewport hero, dark "cinema" bands, sticky chapters
 * - brand untouched: palette, Alegreya Sans SC display, Open Sans text
 * - content fully readable with JS disabled; all motion opt-out via
 *   prefers-reduced-motion; the hero video is an ENHANCEMENT over a poster
 *   that is designed to stand on its own.
 */

:root {
	--v3-ink: var(--wp--preset--color--ink, #14181a);
	--v3-ink-soft: var(--wp--preset--color--ink-soft, #1f2629);
	--v3-lime: var(--wp--preset--color--lime, #c9e45c);
	--v3-accent: var(--wp--preset--color--accent, #017ab7);
	--v3-sage: var(--wp--preset--color--sage, #d2e0d2);
	--v3-body: #3f3f50;
	/*
	 * Blog band accent only (eyebrow, links, Read more). 5.09:1 on that
	 * band's #f7f5f1 ground. The site accent #017ab7 measures 4.32:1 there
	 * and fails, which is why the band does not use it. Do not use olive
	 * anywhere else.
	 */
	--v3-olive: #6b6b3a;
	--v3-on-dark: rgba(255, 255, 255, 0.85);
	--v3-h1: clamp(2.5rem, 4.8vw, 4rem);            /* 64px @1456 — was 84px: 6 lines, 65% of the hero */
	--v3-h2: clamp(2.125rem, 3.3vw, 3rem);          /* 48px @1456 */
	--v3-stat: clamp(3.5rem, 8vw, 6.5rem);          /* 104px @1456, standing alone */
	--v3-band-pad: clamp(4rem, 9vw, 7.5rem);
	--v3-wrap: 1200px;
	--v3-prose: 46rem;

	/*
	 * Height of the sticky topbar, subtracted from the viewport to size the
	 * hero. home-v4.js overwrites this with the measured value (floored) on
	 * load and on resize.
	 *
	 * The fallback is deliberately a pixel or two UNDER the real height
	 * (measured: 137.2 desktop, 116.7 mobile). Erring high leaves a white
	 * sliver under the hero — 138px against a 137.2px bar produced exactly
	 * that, a 0.8px line of white against a dark photograph, which is far more
	 * visible than it sounds. Erring low costs a sub-pixel of overflow that
	 * nobody can see.
	 */
	--v3-topbar-h: 136px;
}

@media (max-width: 781px) {
	:root {
		--v3-topbar-h: 115px;
	}
}

@media (prefers-reduced-motion: no-preference) {
	html {
		scroll-behavior: smooth;
	}
}

/* ------------------------------------------------------------------ topbar */

/*
 * ⚠️ THE HEADER IS A TEMPLATE PART AND ITS WRAPPER MUST GENERATE NO BOX.
 *
 * parts/header.html carries the topbar for every template on the site, so the
 * bar is one object with one set of rules. WordPress wraps a template part in
 * a <div class="wp-block-template-part">, and that wrapper is exactly as tall
 * as the bar inside it — which would make it the sticky element's containing
 * block and pin the bar for precisely its own height, i.e. not at all.
 *
 * `display: contents` removes the wrapper's box without removing the element,
 * so the bar's containing block becomes the document root again and sticky
 * behaves as it did while the markup was inline in front-page.html. The class
 * comes from the template-part call, so this cannot leak to the footer part,
 * whose wrapper IS the <footer> element and must keep its box.
 */
.mswc-v3-headerpart {
	display: contents;
}

.mswc-v3-topbar {
	position: sticky;
	top: 0;
	z-index: 100;
	background: rgba(255, 255, 255, 0.86);
	-webkit-backdrop-filter: blur(14px);
	backdrop-filter: blur(14px);
	border-bottom: 1px solid rgba(20, 24, 26, 0.08);
	padding: 10px 0;
}

.mswc-v3-topbar .wp-block-site-logo img {
	width: 170px;
	height: auto;
	display: block;
}

.mswc-v3-topbar .wp-block-navigation {
	font-size: 0.9375rem;
	gap: 2rem;
}

/* ---------------------------------------------------- band fundamentals */

/*
 * The generator emits each band as a top-level element inside the constrained
 * post-content. Kill the theme's 36px blockGap between bands: the bands own
 * their spacing (their padding), and any inherited gap shows as white seams
 * between dark bands. :where() in core's layout rule keeps specificity low,
 * so no !important is needed.
 */
body.home .wp-block-post-content > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* The root blockGap also wedges 36px of white between the topbar and whatever
 * opens the page (main is the topbar's flow sibling). Every v4 page opens on a
 * band that owns that edge itself, so the gap is never wanted. */
main.wp-block-group {
	margin-block-start: 0;
}

/*
 * The same blockGap reset as `body.home` gets, keyed on the BAND rather than on
 * the body, so the four inner pages rebuilt on this vocabulary get it too.
 * (0,2,0) beats core's layout rule, which wraps its selector in :where().
 */
.wp-block-post-content > .mswc-v3-band,
.wp-block-post-content > .mswc-v3-hero,
.wp-block-post-content > .mswc-v3-closing,
.wp-block-post-content > .mswc-v3-pagehero {
	margin-block-start: 0;
	margin-block-end: 0;
}

.mswc-v3-band {
	padding: var(--v3-band-pad) 24px;
}

.mswc-v3-wrap {
	max-width: var(--v3-wrap);
	margin-inline: auto;
}

.mswc-v3-prose {
	max-width: var(--v3-prose);
	font-size: 1.0625rem;
	line-height: 1.7;
	color: var(--v3-body);
	margin: 24px 0 0;
}

.mswc-v3-deck {
	font-size: 1.25rem;
	line-height: 1.55;
}

div.mswc-v3-band h2.mswc-v3-h2 {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--v3-h2);
	line-height: 1.12;
	letter-spacing: -0.01em;
	font-weight: 700;
	color: #1f1f1f;
	margin: 16px 0 0;
	text-wrap: balance;
}

.mswc-v3-band .mswc-eyebrow {
	margin: 0;
}

/* dark bands — the cinema */
.mswc-v3-dark {
	background: var(--v3-ink);
	color: var(--v3-on-dark);
}

div.mswc-v3-dark h2.mswc-v3-h2 {
	color: #ffffff;
}

.mswc-v3-dark .mswc-v3-prose {
	color: var(--v3-on-dark);
}

.mswc-v3-dark .mswc-eyebrow {
	color: var(--v3-lime);
}

.mswc-v3-dark a:not(.mswc-v3-btn):not(.mswc-v3-ghost) {
	color: var(--v3-lime);
}

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

.mswc-v3-hero {
	position: relative;
	min-height: max(560px, calc(100svh - var(--v3-topbar-h)));
	display: flex;
	align-items: flex-end;
	overflow: hidden;
	background: var(--v3-ink);
	color: #fff;
}

.mswc-v3-hero-media,
.mswc-v3-hero-media img,
.mswc-v3-hero-video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
}

.mswc-v3-hero-media img {
	object-fit: cover;
	/* Ken Burns: the poster is the hero until (and unless) the film arrives. */
	animation: mswc-v3-kenburns 26s ease-in-out infinite alternate;
}

@keyframes mswc-v3-kenburns {
	from { transform: scale(1); }
	to   { transform: scale(1.08); }
}

@media (prefers-reduced-motion: reduce) {
	.mswc-v3-hero-media img {
		animation: none;
	}
}

/*
 * The background film. JS injects the iframe and reveals it ONLY after the
 * Vimeo player confirms playback (postMessage `play` event) — if background
 * autoplay is not allowed on the account's plan, the iframe stays invisible
 * behind the poster instead of showing a paused player with controls.
 */
.mswc-v3-hero-video {
	border: 0;
	pointer-events: none;
	opacity: 0;
	transition: opacity 1.2s ease;
	/*
	 * Cover-fit a 16:9 iframe over the hero. Order matters: `inset: auto`
	 * FIRST (it cancels the shared `inset: 0`), THEN left/top — the first
	 * deploy had them reversed and the shorthand reset left/top to auto,
	 * painting the film at x=-728. And the sitewide `iframe{max-width:100%}`
	 * must be overridden or the cover width caps at the hero's width.
	 */
	inset: auto;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	max-width: none;
	/*
	 * The film is CINEMASCOPE (~2.39:1), letterboxed inside Vimeo's 16:9
	 * player — sized merely to cover, the letterbox bars showed as black
	 * strips at the hero's top and bottom (measured: video 1780/746 ≈ 2.39).
	 * The 240vh term sizes the player so the 2.39:1 picture itself covers
	 * the full hero height; the bars land outside the crop.
	 */
	width: max(100vw, 240vh);
	height: auto;
	aspect-ratio: 16 / 9;
}

.mswc-v3-hero.has-video .mswc-v3-hero-video {
	opacity: 1;
}

.mswc-v3-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
	/*
	 * Two scrims: bottom-up for the deck/buttons, and a diagonal wash from
	 * the left so the H1's upper lines hold up over bright sky — white on
	 * cloud was borderline without it.
	 */
	background:
		linear-gradient(105deg, rgba(10, 14, 15, 0.62) 0%, rgba(10, 14, 15, 0.3) 42%, rgba(10, 14, 15, 0) 68%),
		linear-gradient(to top, rgba(10, 14, 15, 0.88) 0%, rgba(10, 14, 15, 0.55) 34%, rgba(10, 14, 15, 0.12) 62%, rgba(10, 14, 15, 0.2) 100%);
}

.mswc-v3-hero-content {
	position: relative;
	z-index: 3;
	width: 100%;
	max-width: var(--v3-wrap);
	margin-inline: auto;
	padding: 0 24px clamp(3rem, 8vh, 5.5rem);
}

.mswc-v3-hero .mswc-eyebrow {
	color: var(--v3-lime);
	margin: 0 0 16px;
}

.mswc-v3-hero h1 {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--v3-h1);
	line-height: 1.05;
	letter-spacing: -0.02em;
	font-weight: 700;
	color: #ffffff;
	margin: 0;
	/* 79 fixed characters: 24ch at 64px balances to 4 lines (~270px) instead
	 * of the old 15ch/84px wall (6 lines, 529px) that pushed the buttons past
	 * the 900px fold and clipped the eyebrow above the hero's top edge. */
	max-width: 24ch;
	text-wrap: balance;
}

.mswc-v3-hero .mswc-v3-deck {
	color: rgba(255, 255, 255, 0.9);
	max-width: 44ch;
	margin: 24px 0 0;
}

.mswc-v3-hero-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	align-items: center;
	margin-top: 40px;
}

.mswc-v3-scroll-cue {
	position: absolute;
	z-index: 3;
	left: 50%;
	bottom: 14px;
	transform: translateX(-50%);
	color: rgba(255, 255, 255, 0.7);
	font-size: 22px;
	line-height: 1;
	animation: mswc-v3-cue 2.2s ease-in-out infinite;
}

@keyframes mswc-v3-cue {
	0%, 100% { transform: translate(-50%, 0); opacity: 0.7; }
	50%      { transform: translate(-50%, 8px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
	.mswc-v3-scroll-cue {
		animation: none;
	}
}

/* --------------------------------------------------------------- buttons */

.mswc-v3-btn {
	display: inline-block;
	background: var(--v3-lime);
	color: #1d1d22;
	font-size: 1rem;
	line-height: 1.6;
	font-weight: 400;
	text-decoration: none;
	border-radius: 9999px;
	padding: 14px 32px;
	transition: background 0.2s ease, transform 0.2s ease;
}

.mswc-v3-btn:hover {
	background: #b9d64e;
	transform: translateY(-1px);
}

.mswc-v3-ghost {
	display: inline-block;
	color: #ffffff;
	font-size: 1rem;
	line-height: 1.6;
	text-decoration: none;
	border: 1.5px solid rgba(255, 255, 255, 0.75);
	border-radius: 9999px;
	padding: 13px 30px;
	transition: background 0.2s ease, border-color 0.2s ease;
}

.mswc-v3-ghost:hover {
	background: rgba(255, 255, 255, 0.12);
	border-color: #ffffff;
}

.mswc-v3-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	margin-top: 40px;
}

/* ----------------------------------------------------------------- stats */

.mswc-v3-stats {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 40px;
	margin-top: 64px;
}

/*
 * Each statistic sits in a dial. Only the two PERCENTAGES get the lime arc:
 * 2,098 leaders trained is a count, not a proportion, and an arc would assert
 * that it is one. It keeps the same dim track and the same footprint so the
 * row still reads as a set, which is what makes the bright arc unambiguously
 * mean "share of" wherever it appears.
 */
/*
 * The dial treatment is opt-in: the generator adds .mswc-v3-stats--dials when
 * its DIALS constant is on, and everything the dials need hangs off that.
 * With it off the band is the original 104px lime numerals ranged left, and
 * none of the rules below can reach anything, so the two versions can be
 * compared by flipping one constant.
 */
.mswc-v3-stats--dials {
	--v3-stat: clamp(2rem, 3.4vw, 3rem);            /* 48px @1456, inside the dial */
}

.mswc-v3-stats--dials .mswc-v3-stat {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}

.mswc-v3-dial {
	position: relative;
	width: clamp(140px, 13.7vw, 200px);
	aspect-ratio: 1;
	display: grid;
	place-items: center;
}

.mswc-v3-dial-svg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	/* Sweep from twelve o'clock, not from three. */
	transform: rotate(-90deg);
}

.mswc-v3-dial-track,
.mswc-v3-dial-arc {
	fill: none;
	stroke-width: 8;
}

.mswc-v3-dial-track {
	stroke: rgba(255, 255, 255, 0.15);
}

/*
 * The arc is drawn with stroke-dasharray = the full circumference and
 * stroke-dashoffset = the undrawn remainder, both printed into the MARKUP at
 * their final values. home-v4.js empties the offset on init (only for dials
 * still below the fold, the same rule the reveals use) and animates it back,
 * so a visitor with no JavaScript gets finished dials rather than empty rings.
 */
.mswc-v3-dial-arc {
	stroke: var(--v3-lime);
	stroke-linecap: round;
}

.mswc-v3-stat-n {
	display: block;
	position: relative;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--v3-stat);
	line-height: 1;
	letter-spacing: -0.03em;
	font-weight: 600;
	color: var(--v3-lime);
	font-variant-numeric: tabular-nums;
}

.mswc-v3-stat-cap {
	display: block;
	font-size: 0.9375rem;
	line-height: 1.5;
	color: var(--v3-on-dark);
	margin-top: 12px;
	max-width: 24ch;
	text-wrap: balance;
}

.mswc-v3-stats--dials .mswc-v3-stat-cap {
	margin-top: 18px;
}

.mswc-v3-source {
	font-size: 0.8125rem;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.62);
	margin: 40px 0 0;
}

/* ----------------------------------------------------- sticky chapters */

.mswc-v3-chapter {
	display: grid;
	grid-template-columns: 5fr 6fr;
	gap: clamp(40px, 6vw, 88px);
	align-items: start;
	margin-top: 40px;
}

.mswc-v3-chapter-text {
	/*
	 * TWO BUGS lived here, and together they made the band look glitchy.
	 *
	 * 1. `top: 110px` against a 137px topbar with z-index 100 and no z-index
	 *    of its own: when the column pinned, it pinned 27px UNDERNEATH the
	 *    bar and slid behind the blur. It now clears the bar by 24px, from
	 *    the live measured variable rather than another guess.
	 *
	 * 2. The programme band is 892px tall and this column is 809px, so there
	 *    was 83px of travel. The column twitched and released. Sticky with
	 *    almost no travel reads as broken, worse than no sticky at all.
	 */
	position: sticky;
	top: calc(var(--v3-topbar-h) + 24px);
	z-index: 1;
}

/*
 * Only pin when the column actually fits below the bar. 900px of viewport
 * minus a 161px offset leaves 739px against an 809px column, so on a laptop
 * it would pin already cut off. Below that height it behaves as an ordinary
 * two-column band, which is what it looked like anyway once travel ran out.
 */
@media (max-height: 1023px) {
	.mswc-v3-chapter-text {
		position: static;
	}
}

.mswc-v3-chapter-media {
	display: grid;
	gap: 32px;
	margin: 0;
	/* Give the sticky column something to travel against on tall screens. */
	align-content: start;
}

.mswc-v3-card {
	margin: 0;
}

.mswc-v3-card img {
	width: 100%;
	height: auto;
	border-radius: 10px;
	display: block;
}

.mswc-v3-card figcaption {
	font-size: 0.875rem;
	line-height: 1.55;
	color: var(--v3-body);
	margin-top: 10px;
}

.mswc-v3-dark .mswc-v3-card figcaption,
.mswc-v3-accent .mswc-v3-card figcaption {
	color: var(--v3-on-dark);
}

/* ------------------------------------------------------------ film band */

div.mswc-v3-band h2.mswc-v3-film-title {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(2.5rem, 4.5vw, 4rem);
	line-height: 1.05;
	letter-spacing: -0.015em;
	font-weight: 700;
	color: #ffffff;
	margin: 16px 0 0;
	text-wrap: balance;
}

/*
 * The poster frame is a background on the wrapper, so it costs no extra
 * element and the iframe simply paints over it when it loads.
 *
 * It exists because Vimeo's own thumbnail for the film is PURE BLACK: the
 * film opens on a black logo card, the same reason the hero starts at #t=35s.
 * The embed was a black rectangle before the player loaded AND after it
 * loaded, until you pressed play. `background: #000` stays as the last-resort
 * backing under the poster.
 */
.mswc-v3-embed {
	position: relative;
	margin: 48px 0 0;
	border-radius: 12px;
	overflow: hidden;
	background-color: #000;
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	/*
	 * The wrapper holds its OWN shape. Without this it took its height from
	 * the iframe, so the poster had a box to paint in only for as long as the
	 * iframe was there to give it one: remove or fail the embed and the
	 * wrapper collapsed to zero and the poster silently vanished. The point
	 * of a poster is to be the thing that survives the embed not arriving.
	 */
	aspect-ratio: 16 / 9;
}

.mswc-v3-embed iframe {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	height: auto;
	border: 0;
}

/* ------------------------------------------------------------ photo rail */

.mswc-v3-rail {
	display: flex;
	gap: 16px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	padding: 8px 4px 16px;
	margin-top: 48px;
	scrollbar-width: thin;
	scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}

.mswc-v3-rail figure {
	flex: 0 0 min(380px, 76vw);
	scroll-snap-align: start;
	margin: 0;
}

.mswc-v3-rail img {
	width: 100%;
	height: 480px;
	object-fit: cover;
	border-radius: 10px;
	display: block;
}

/* ---------------------------------------------------------- accent band */

.mswc-v3-accent {
	background: var(--v3-accent);
	color: #ffffff;
}

div.mswc-v3-accent h2.mswc-v3-h2 {
	color: #ffffff;
}

.mswc-v3-accent .mswc-v3-prose {
	color: #ffffff;
}

.mswc-v3-accent .mswc-eyebrow {
	color: #ffffff;
}

/* ---------------------------------------------------------- problem plate */

/*
 * "The problem": a very pale watercolour savanna (rhino and calf, acacia,
 * hazy hills) bleeding off the right edge of an otherwise white band,
 * dissolving into the white well before it reaches the words.
 *
 * The blend IS the fade, and mix-blend-mode: multiply is the whole trick.
 * The artwork's own ground is #fefefe, so multiplying it against the white
 * band makes that ground vanish exactly, at every edge, with no mask and no
 * seam to keep in sync. A mask-image fade was the alternative, but it only
 * fixes the left edge and still leaves a visible straight cut at the top
 * and bottom.
 */
.mswc-v3-plate {
	position: relative;
	overflow: hidden;
	min-height: clamp(360px, 34vw, 460px);
}

/*
 * The copy paints over the art and gets NO background of its own: the art is
 * transparent to the eye where the text sits, and the contrast sweep measures
 * ink on white either way.
 *
 * Centred, not top-aligned. Top-aligned it sat in the upper third with 400px
 * of empty white under it, and the art read as a separate picture parked
 * alongside a paragraph rather than a ground the words sit on.
 */
.mswc-v3-plate .mswc-v3-wrap {
	position: relative;
	/* 2, not 1: the veil is 1 and has to come between the art and the words.
	 * The three layers are art 0, veil 1, copy 2, and they are numbered rather
	 * than left to document order because the art is emitted BEFORE the wrap
	 * while ::before generates ahead of both. */
	z-index: 2;
	display: flex;
	flex-direction: column;
	justify-content: center;
	min-height: inherit;
}

/*
 * FULL WIDTH, NATURAL HEIGHT, FLUSH WITH THE BAND'S BOTTOM. No object-fit at
 * all, which is the only arrangement here that crops nothing and cuts nothing.
 *
 * The plate is a 2.33:1 panorama whose own left 35% is faded to white in the
 * file. The band is 1456x700 at the wide breakpoint, aspect 2.08, and neither
 * fit works in that box:
 *
 * - `cover` scales to the height and throws away 174px of WIDTH. It would take
 *   the easel and part of the hut off the right and eat into the fade on the
 *   left. (The previous plate had the opposite aspect and cover cropped its
 *   height, which is why the rule used to say the opposite. The fit that is
 *   safe flips every time the file's proportions do, which is the argument for
 *   not using one.)
 * - `contain` keeps the whole panorama but letterboxes it 37px top and bottom,
 *   and the file BLEEDS at the bottom: its last row is the seated group's
 *   chairs, luminance 170, not white. So contain drew a hard horizontal edge
 *   across the band 37px above its bottom, which is visible and looks broken.
 *
 * Sized by width and anchored to the bottom, the file's bleeding edge lands
 * exactly on the band's own edge, where an edge is expected, and the space
 * left above the picture is the file's own top row, which measures 242+ and
 * multiplies into the white band invisibly. The full left-to-right fade
 * survives at every width.
 */
.mswc-v3-plate-art {
	position: absolute;
	/*
	 * 30px OFF THE BOTTOM, so the picture sits about centred in the band rather
	 * than sitting on its edge: 624px of artwork in a 700px band leaves 76, and
	 * this splits it 46/30.
	 *
	 * That re-exposes the file's bleeding bottom edge — its last row is artwork
	 * at luminance 217, which is why this was flush in the first place — so the
	 * band's ::after fades it out. The two move together: lift this and the
	 * fade has to still cover the cut.
	 */
	inset: auto 0 30px 0;
	margin: 0;
	pointer-events: none;
	z-index: 0;
}

.mswc-v3-plate-art img {
	width: 100%;
	height: auto;
	display: block;
	mix-blend-mode: multiply;
}

/*
 * THE VEIL. A white ramp between the artwork and the copy, painted across the
 * left of the band.
 *
 * The file's own fade is not enough on its own and cannot be: it runs out at
 * about 35% of the image, which is x=510 at the wide breakpoint, while the h2
 * sets to roughly x=900. Everything between those two numbers is a heading on
 * top of a picture. Widening the fade inside the file instead would mean
 * throwing away a third of the artwork to protect one line of type, and the
 * line the type happens to end at changes with the viewport anyway.
 *
 * So the fade that protects the words is done in CSS, where it can be a
 * fraction of the band rather than a fraction of the file, and the fade in the
 * file stays what it is: the artwork's own soft left edge.
 *
 * The stops are measured, not guessed. `.mswc-v3-plate` is white, so the veil
 * is white at whatever alpha the darkest glyph pixel under it needs; the
 * measurement is taken from a real screenshot inside each element's glyph
 * bounds, because nothing in the computed styles can see through multiply.
 *
 * pointer-events: none is required. This covers the whole band, including the
 * copy, and without it the veil would eat every click and text selection in
 * the section.
 */
/*
 * THE BOTTOM FADE, a second veil running up from the band's own edge.
 *
 * It does two things at once. It dissolves the artwork's cut bottom edge, which
 * the 30px lift above re-exposed, so the picture ends in the band rather than
 * stopping in it. And it settles the band into the dark evidence band below,
 * which the plate used to meet at full strength.
 *
 * Pixel stops, not percentages: it has to cover a 30px offset and a hard edge,
 * both of which are fixed sizes, while the band's height is not.
 */
.mswc-v3-plate::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 190px;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		to top,
		#ffffff 0px,
		#ffffff 46px,
		rgba(255, 255, 255, 0.72) 92px,
		rgba(255, 255, 255, 0.28) 140px,
		rgba(255, 255, 255, 0) 190px
	);
}

.mswc-v3-plate::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	/*
	 * Lightened for the fifth plate. The stops used to run 0.97/0.88/0.50/0.16
	 * out to 84%, sized for a file whose first ink was at 35% and whose figures
	 * were considerably darker. Against this one — first ink at 47.4%, darkest
	 * pixel 107 — that veil was erasing the artwork rather than holding the copy
	 * up. Verified by measurement, not by eye: the check is the two-shot glyph
	 * sweep, because nothing in the computed styles can see through multiply.
	 */
	background: linear-gradient(
		to right,
		#ffffff 0%,
		rgba(255, 255, 255, 0.96) 26%,
		rgba(255, 255, 255, 0.82) 44%,
		rgba(255, 255, 255, 0.45) 58%,
		rgba(255, 255, 255, 0.14) 70%,
		rgba(255, 255, 255, 0) 80%
	);
}


/* ------------------------------------------------------------- story band */

/*
 * "One story": the Mayanai film as a full-viewport cinema panel. films.js
 * injects .mswc-v3-story-video into .mswc-v3-story-media near the fold and
 * adds .has-video only once Vimeo confirms playback; home-v4.js adds
 * .story-enhanced on init and collapses the panel, toggles .story-open, and
 * adds .story-playing (plus the .mswc-v3-story-player iframe and the
 * .mswc-v3-story-close button) when the visitor asks for sound. Five
 * states, all styled below. The no-JS state is the panel OPEN on the plain
 * accent band, and it must be genuinely good, not merely legible.
 *
 * The solid accent background (inherited from .mswc-v3-accent) is NOT
 * decorative. The contrast sweep measures white text against that computed
 * background and gets 4.71:1, which is the honest worst case: every real
 * pixel is the film under a scrim at least that dark. Make the band
 * transparent and the sweep starts reporting a contrast nobody ever sees.
 */
.mswc-v3-story {
	position: relative;
	overflow: hidden;
	padding: 0;
	min-height: max(620px, calc(100svh - var(--v3-topbar-h)));
	display: flex;
	align-items: flex-end;
}

.mswc-v3-story-media {
	position: absolute;
	inset: 0;
	z-index: 0;
}

/*
 * Cover-fit the 16:9 iframe, the same pattern as .mswc-v3-hero-video and
 * the same two traps: `inset: auto` must come BEFORE left/top (the
 * shorthand would reset them to auto), and `max-width: none` is required or
 * the sitewide `iframe { max-width: 100% }` caps the cover width. This film
 * really is 16:9, so 177.8vh covers; the cinemascope hero film needs 240vh.
 */
.mswc-v3-story-video {
	position: absolute;
	border: 0;
	pointer-events: none;
	opacity: 0;
	transition: opacity 1.2s ease;
	inset: auto;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	max-width: none;
	width: max(100vw, 177.8vh);
	aspect-ratio: 16 / 9;
	height: auto;
}

.mswc-v3-story.has-video .mswc-v3-story-video {
	opacity: 1;
}

/*
 * Scrim in the band's own INK, weighted to the LEFT because that is where the
 * words and the panel live. This is deliberately the same recipe as the hero's
 * scrim: they are the page's two full-bleed film sections and they should read
 * as a pair. It was accent blue until 0.10.4, which occurred exactly once on
 * the page and TINTED the footage instead of darkening it. White text sits on this: tune the stops if
 * justified, but do not weaken them.
 */
.mswc-v3-story::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
	pointer-events: none;
	/*
	 * PULLED BACK from the first pass, which put 0.24 alpha across the middle
	 * and 0.10 across the whole top: the two gradients compounded and the
	 * film was a blue wash everywhere instead of a picture. This band exists
	 * because the film is worth looking at, so the scrim now clears entirely
	 * above the copy and to the right of it, and only stays heavy in the
	 * bottom-left corner where the words and the panel actually sit.
	 *
	 * Safe to tune because the BAND still declares the solid accent behind
	 * all of this, so the contrast sweep keeps measuring white on #017ab7
	 * (4.71:1) no matter what the gradients do. Lightening the scrim can make
	 * the picture better; it cannot make the text fail.
	 */
	background:
		linear-gradient(95deg, rgba(10, 14, 15, 0.92) 0%, rgba(10, 14, 15, 0.64) 26%, rgba(10, 14, 15, 0.14) 54%, rgba(10, 14, 15, 0) 72%),
		linear-gradient(to top, rgba(10, 14, 15, 0.9) 0%, rgba(10, 14, 15, 0.38) 28%, rgba(10, 14, 15, 0) 56%);
	transition: background 0.45s ease;
}

/*
 * The scrim is STATE-DEPENDENT, and this is the one rule in the band that is
 * really about honesty rather than looks.
 *
 * Collapsed, the only text is the title in the bottom-left corner, where the
 * bottom-up wash is already at 0.9, so the rest of the frame can stay clean
 * and the film can be the film. Open, three paragraphs of white body copy run
 * out to roughly half the width, over a picture that is CHANGING: a frame that
 * clears 4.5:1 at second 12 can fail at second 13, and nothing in the harness
 * can catch that because the harness measures the band's solid background.
 *
 * So when the panel opens, the left half steps up to a weight that holds white
 * copy against any frame the film can produce. Reading and looking want
 * different scrims; the page now uses the one that matches what you are doing.
 */
.mswc-v3-story.story-open::after {
	background:
		linear-gradient(95deg, rgba(10, 14, 15, 0.94) 0%, rgba(10, 14, 15, 0.84) 30%, rgba(10, 14, 15, 0.6) 52%, rgba(10, 14, 15, 0.16) 72%, rgba(10, 14, 15, 0) 86%),
		linear-gradient(to top, rgba(10, 14, 15, 0.9) 0%, rgba(10, 14, 15, 0.44) 34%, rgba(10, 14, 15, 0.06) 64%);
}

.mswc-v3-story .mswc-v3-wrap {
	position: relative;
	z-index: 3;
	width: 100%;
	padding: 0 24px clamp(3rem, 8vh, 5.5rem);
}

.mswc-v3-story-inner {
	max-width: 640px;
}

/*
 * The toggle carries .mswc-v3-ghost, but a <button> brings UA styles an
 * <a> never sees (a small system font, a grey background, its own text
 * colour). Reset with font: inherit, then RESTATE the ghost type: this rule
 * sits after .mswc-v3-ghost at equal specificity and would otherwise win
 * the cascade, and the computed type is contractually 16px / 25.6px /
 * rgb(255,255,255) / Open Sans 400.
 */
.mswc-v3-story-toggle {
	font: inherit;
	font-size: 1rem;
	line-height: 1.6;
	color: #ffffff;
	background: none;
	cursor: pointer;
	margin-top: 28px;
	/*
	 * A <button> defaults to text-align: center. Its sibling ghost <a> in the
	 * hero computes `start`, and the intent manifest declares `start` for both,
	 * so leaving the UA default here reported as a real difference. Visually
	 * identical on a one-line pill; the point is that the two controls agree.
	 */
	text-align: start;
}

.mswc-v3-story-toggle:focus-visible {
	outline: 2px solid #ffffff;
	outline-offset: 2px;
}

/*
 * Small chevron that flips with the aria-expanded state the JS maintains.
 * border-right + border-bottom rotated 45deg reads as "down" (collapsed,
 * opens downward); 225deg reads as "up" (open).
 */
.mswc-v3-story-toggle::after {
	content: "";
	display: inline-block;
	width: 7px;
	height: 7px;
	margin-left: 10px;
	border-right: 1.5px solid currentColor;
	border-bottom: 1.5px solid currentColor;
	transform: rotate(45deg);
	transition: transform 0.25s ease;
}

.mswc-v3-story-toggle[aria-expanded="true"]::after {
	transform: rotate(225deg);
}

/*
 * The panel. The no-JS default (the state in the HTML) is fully visible and
 * in flow; .story-enhanced collapses it, .story-open slides it in from the
 * left. Collapse with max-height / opacity / transform ONLY: the harness
 * diffs computed type values in the collapsed state, so display: none,
 * visibility: hidden or font-size: 0 would all read as defects (it is also
 * what keeps the panel reachable to a screen reader once open). The band is
 * bottom-aligned, so an opening panel pushes the title upward; that push is
 * the intended effect, do not fight it.
 */
.mswc-v3-story-panel {
	margin-top: 28px;
	max-width: 640px;
}

.mswc-v3-story.story-enhanced .mswc-v3-story-panel {
	overflow: hidden;
	max-height: 0;
	opacity: 0;
	transform: translateX(-32px);
	margin-top: 0;
	transition: max-height 0.55s ease, opacity 0.35s ease, transform 0.45s ease;
}

.mswc-v3-story.story-open .mswc-v3-story-panel {
	max-height: 40rem;
	opacity: 1;
	transform: none;
	margin-top: 28px;
}

.mswc-v3-story-panel .mswc-v3-prose {
	color: #ffffff;
	margin: 20px 0 0;
}

.mswc-v3-story-panel .mswc-v3-prose:first-child {
	margin-top: 0;
}

/*
 * The JS focuses the panel for screen readers; a focus ring around a whole
 * paragraph block is noise.
 */
.mswc-v3-story-panel:focus {
	outline: none;
}

.mswc-v3-story-watch {
	display: inline-flex;
	margin-top: 28px;
}

/* Sound player: the player owns the band, scrim and copy fade out. */
.mswc-v3-story-player {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
	z-index: 4;
}

.mswc-v3-story.story-playing::after,
.mswc-v3-story.story-playing .mswc-v3-wrap {
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.3s;
}

.mswc-v3-story-close {
	position: absolute;
	top: 20px;
	right: 20px;
	z-index: 5;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(0, 0, 0, 0.55);
	color: #ffffff;
	font-size: 20px;
	line-height: 1;
	cursor: pointer;
}

.mswc-v3-story-close:focus-visible {
	outline: 2px solid #ffffff;
	outline-offset: 2px;
}

/* Every transition in this band dies under reduced motion, no exceptions. */
@media (prefers-reduced-motion: reduce) {
	.mswc-v3-story-video,
	.mswc-v3-story-toggle::after,
	.mswc-v3-story::after,
	.mswc-v3-story.story-enhanced .mswc-v3-story-panel,
	.mswc-v3-story.story-playing::after,
	.mswc-v3-story.story-playing .mswc-v3-wrap {
		transition: none;
	}
}

/*
 * Below 768px no film is ever mounted and the JS does not collapse the
 * panel either, so this falls back to an ordinary accent band: normal band
 * padding back on, scrim off, toggle hidden (it controls nothing), panel
 * guaranteed visible and in flow even if a stray story-enhanced somehow
 * lands here. The "Watch with sound" link stays visible.
 */
@media (max-width: 767px) {
	.mswc-v3-story {
		display: block;
		min-height: auto;
		padding: var(--v3-band-pad) 24px;
	}

	.mswc-v3-story::after {
		content: none;
	}

	.mswc-v3-story .mswc-v3-wrap {
		padding: 0;
	}

	.mswc-v3-story-toggle {
		display: none;
	}

	.mswc-v3-story .mswc-v3-story-panel,
	.mswc-v3-story.story-enhanced .mswc-v3-story-panel {
		overflow: visible;
		max-height: none;
		opacity: 1;
		transform: none;
		margin-top: 28px;
	}
}

/* ------------------------------------------------------------ voice cards */

.mswc-v3-cols {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 32px;
	margin-top: 40px;
	/*
	 * Cards size to their own content. Stretched (the grid default) a card
	 * with a shorter caption than its neighbour paints its white background
	 * down to the taller card's baseline, which reads as a rendering fault
	 * rather than as space. Both cards now carry a caption, so they are close
	 * to level anyway; this makes the layout correct rather than lucky.
	 */
	align-items: start;
}

.mswc-v3-voice {
	background: #ffffff;
	border: 1px solid rgba(20, 24, 26, 0.08);
	border-radius: 12px;
	overflow: hidden;
	transition: transform 0.25s ease, box-shadow 0.25s ease;
	margin: 0;
}

.mswc-v3-voice:hover {
	transform: translateY(-4px);
	box-shadow: 0 18px 40px rgba(20, 24, 26, 0.12);
}

.mswc-v3-voice iframe {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	height: auto;
	border: 0;
	/* Match .mswc-v3-embed: while the player loads, the card shows a dark
	 * 16:9 slab instead of a blank white hole. */
	background: #000;
}

.mswc-v3-voice figcaption {
	font-size: 0.875rem;
	line-height: 1.55;
	color: var(--v3-body);
	padding: 16px 20px 20px;
}

/* --------------------------------------------------------------- blog band */

/*
 * The closing content bands used to float in white: a hairline-bordered card
 * on a white field read as a draft next to the dark cinema bands. The band
 * now takes sage — freed up by the homepage footer going ink — and the card
 * becomes a white sheet on it, so the story reads as an object with edges,
 * not a leftover. The accent spine stays: it ties the card to the inline
 * link colour and to the Mayanai band.
 *
 * The band carries no distinguishing class (the generator emits .mswc-v3-band
 * for every band), so the sage is applied with :has() against the card.
 * A browser without :has() simply keeps the white band; the card restyle
 * stands on its own either way. Only the eyebrow sits directly on sage —
 * body #535353 on sage #d2e0d2 measures ~5.6:1 — everything else is on the
 * white card, where the accent link keeps its 4.7:1.
 */
/*
 * The band declares its own ground on its own class. It used to be sage,
 * applied with `:has(.mswc-v3-blogcard)` because no band carried a
 * distinguishing class, and a browser without :has() lost the colour
 * entirely. The generator now emits .mswc-v3-blogfeature, so that fragility
 * is retired rather than worked around.
 *
 * #f7f5f1 comes from the closing wrapper, which paints both bands so they read
 * as one movement with no seam between them. The plate no longer depends on
 * matching it: its shape carries ALPHA, so whatever this ground is shows
 * through the cut exactly. It used to bake the colour in, and lossy WebP
 * returned it one level out in G and B, which drew a visible rectangle around
 * the plate.
 */
.mswc-v3-blogfeature {
	background: transparent;
	position: relative;
	padding: 0;
	min-height: clamp(440px, 40vw, 560px);
}

/*
 * The two closing bands share a GROUND, not a plate.
 *
 * ⚠️ The wrapper used to own the artwork so it could run behind both bands, and
 * that is deliberately over: a picture crossing the boundary made the donation
 * ask read as a caption on the blog band instead of as its own section. What
 * the wrapper still does is keep one continuous #f7f5f1 under both, so there is
 * no seam where one ends and the next begins.
 */
.mswc-v3-closing {
	position: relative;
	background: #f7f5f1;
}

.mswc-v3-closing .mswc-v3-wrap {
	position: relative;
	z-index: 1;
}

/*
 * THE BLOG BAND'S PLATE, and nothing else's.
 *
 * `contain`, never `cover`. The shape is cut into the FILE with a known margin
 * on all four sides, and contain is the only fit that guarantees that margin
 * survives; cover would scale until the box is full and crop the difference,
 * which is the defect this plate was re-cut to avoid. The space contain leaves
 * over is transparent, so it is simply the band.
 *
 * No blend mode, unlike the problem plate. That one is a pale wash on white and
 * multiply erases its ground; this is a full-value photograph and multiply
 * would darken its sky against the band. This one carries alpha instead, which
 * is exact where a blend mode is only approximately invisible.
 */
.mswc-v3-blogart {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: min(52%, 860px);
	margin: 0;
	pointer-events: none;
	z-index: 0;
}

/*
 * THE RECAP IS BACK BESIDE THE ASK, on plain ground.
 *
 * It keeps the right-hand column Alex asked for, and it keeps the rule that
 * separates it from the ask, because with the artwork gone from this band the
 * rule is the only thing marking the two apart. The cream mist that made it
 * readable over a full-value photograph went with the photograph: a pale
 * ellipse on a pale band is a smudge, not a scrim.
 */
.mswc-v3-closing .mswc-v3-support {
	grid-template-columns: minmax(0, 46%) minmax(0, 1fr);
	gap: clamp(40px, 5vw, 72px);
	max-width: none;
	align-items: start;
}

.mswc-v3-closing .mswc-v3-support-proof {
	margin-top: 0;
	max-width: 26rem;
}

.mswc-v3-blogart img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	object-position: right center;
	display: block;
}

.mswc-v3-blogfeature .mswc-v3-wrap {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	min-height: inherit;
	padding: clamp(3rem, 6vw, 5rem) 24px;
}

/*
 * 34rem, not the 46rem prose measure. The copy has to clear the artwork's
 * contour, and the contour is the point of the artwork.
 */
.mswc-v3-blogcard {
	max-width: 34rem;
}

.mswc-v3-blogfeature .mswc-eyebrow {
	color: var(--v3-olive);
}

/* The short rule under the eyebrow, from Alex's reference. */
.mswc-v3-blogfeature .mswc-eyebrow::after {
	content: "";
	display: block;
	width: 64px;
	height: 1px;
	background: currentColor;
	opacity: 0.55;
	margin-top: 14px;
}

/*
 * Guy asked that the link to post 994 survive the removal of the Shivani
 * band. It used to be the tail of a sentence; it is now its own line, which
 * is the most visible it has ever been. The build asserts it is still here.
 */
.mswc-v3-bloglink {
	display: block;
	margin-top: 26px;
	color: var(--v3-olive);
	font-size: 1.0625rem;
	line-height: 1.7;
	text-decoration: underline;
	text-underline-offset: 4px;
	text-decoration-thickness: 1px;
}

/*
 * The Ewaso link, one tier below the featured article. Guy's 07-31 instruction
 * (keep the 994 link) and his 08-15 instruction (flag the Vigne op-ed) share
 * this band since cutover; the tiering is what lets one band say both.
 */
.mswc-v3-bloglink-quiet {
	font-size: 0.9375rem;
	margin-top: 12px;
}

.mswc-v3-more {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	margin-top: 34px;
	color: var(--v3-olive);
	font-size: 0.9375rem;
	line-height: 1.6;
	text-decoration: none;
	border-bottom: 1px solid currentColor;
	padding-bottom: 6px;
}

/*
 * The arrow is a pseudo-element, not a span. Decoration in the text layer gets
 * swept up by textContent, and the harness read the whole link as "Read more→"
 * (which is also what a screen reader announcing raw text would get).
 */
.mswc-v3-more::after {
	content: "\2192";
	display: inline-block;
	transition: transform 0.25s ease;
}

.mswc-v3-more:hover::after,
.mswc-v3-more:focus-visible::after {
	transform: translateX(4px);
}

.mswc-v3-bloglink:focus-visible,
.mswc-v3-more:focus-visible {
	outline: 2px solid var(--v3-olive);
	outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
	.mswc-v3-more::after {
		transition: none;
	}
}

/* ---------------------------------------------------------------- support */

/*
 * Deliberately the quietest band on the page — the appeal must not read as a
 * fundraising drive — but quiet is not the same as unfinished. The craft is
 * in the details: the PayPal graphic is capped and tidied (it rendered at
 * whatever size the uploaded image happened to be, with raw edges), and the
 * 501(c)(3) note becomes a colophon under a hairline rule, so the band closes
 * with intention instead of trailing off. No new colour, no button, no
 * urgency — the ask keeps its place at the bottom of the page.
 */
/*
 * The ask, rebuilt. Three things carry it, and they are the three things the
 * strongest donation sections have in common: the NUMBER persuades rather
 * than adjectives, there is exactly ONE primary action, and the reassurance
 * sits beside that action instead of in fine print below it.
 *
 * The ground is the blog band's off-white. That was the choice that made
 * olive a system colour rather than a one-off: the page now closes on two
 * warm bands that belong to each other.
 */
.mswc-v3-supportband {
	background: transparent;
	position: relative;
}

.mswc-v3-support {
	display: grid;
	grid-template-columns: 7fr 5fr;
	gap: clamp(40px, 6vw, 88px);
	align-items: start;
}

.mswc-v3-supportband .mswc-eyebrow {
	color: var(--v3-olive);
}

.mswc-v3-supportband .mswc-eyebrow::after {
	content: "";
	display: block;
	width: 64px;
	height: 1px;
	background: currentColor;
	opacity: 0.55;
	margin-top: 14px;
}

.mswc-v3-donate {
	margin-top: 40px;
}

/*
 * A real <button> in place of PayPal's 2020 PNG. The form around it is
 * untouched, so this changes how the control looks and nothing about where
 * the money goes.
 */
.mswc-v3-donate-btn {
	display: inline-flex;
	align-items: center;
	gap: 14px;
	font: inherit;
	font-size: 1rem;
	line-height: 1.6;
	font-weight: 600;
	letter-spacing: 0.02em;
	color: #ffffff;
	/* A <button> defaults to text-align: center; the manifest declares start
	 * for every control on the page, as the ghost anchors compute. Same fix
	 * the story toggle needed. */
	text-align: start;
	/* 5.54:1 for white on this olive, and it is the blog band's olive. */
	background: var(--v3-olive);
	border: 0;
	border-radius: 9999px;
	padding: 17px 40px;
	min-height: 44px;
	cursor: pointer;
	transition: background 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.mswc-v3-donate-btn:hover {
	background: #575c2e;
	transform: translateY(-2px);
	box-shadow: 0 12px 26px rgba(20, 24, 26, 0.16);
}

.mswc-v3-donate-btn:focus-visible {
	outline: 2px solid var(--v3-olive);
	outline-offset: 3px;
}

.mswc-v3-donate-btn::after {
	content: "\2192";
	display: inline-block;
	transition: transform 0.25s ease;
}

.mswc-v3-donate-btn:hover::after {
	transform: translateX(4px);
}

/* Adjacent to the button, not buried under it. */
.mswc-v3-donate-secure {
	font-size: 0.875rem;
	line-height: 1.6;
	color: var(--v3-body);
	margin: 18px 0 0;
	max-width: 34rem;
}

/*
 * The recap. The page argued a thesis, proved it with the LAMP evidence, and
 * closes by pointing the ask back at that proof. It is the same figure from
 * the evidence band, in Guy's own words: no new claim is made here.
 */
.mswc-v3-support-proof {
	border-left: 2px solid rgba(107, 107, 58, 0.35);
	padding-left: clamp(24px, 3vw, 40px);
	margin-top: 8px;
}

.mswc-v3-recap-n {
	display: block;
	font-family: var(--wp--preset--font-family--body);
	font-size: 3.5rem;
	line-height: 1;
	letter-spacing: -0.03em;
	font-weight: 600;
	color: var(--v3-olive);
	font-variant-numeric: tabular-nums;
}

.mswc-v3-recap-cap {
	display: block;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--v3-body);
	margin-top: 14px;
	max-width: 26ch;
}

.mswc-v3-501 {
	font-size: 0.8125rem;
	line-height: 1.6;
	color: var(--v3-body);
	margin: 32px 0 0;
	padding-top: 24px;
	border-top: 1px solid rgba(20, 24, 26, 0.12);
	max-width: 46rem;
}

@media (prefers-reduced-motion: reduce) {
	.mswc-v3-donate-btn,
	.mswc-v3-donate-btn::after {
		transition: none;
	}

	.mswc-v3-donate-btn:hover {
		transform: none;
	}
}

@media (max-width: 781px) {
	.mswc-v3-support {
		grid-template-columns: 1fr;
		gap: 48px;
	}

	.mswc-v3-support-proof {
		border-left: 0;
		border-top: 2px solid rgba(107, 107, 58, 0.35);
		padding-left: 0;
		padding-top: 32px;
	}
}

/* ------------------------------------------------------- footer landscape */

/*
 * The page settles into a misty watercolour savanna. Alex's brief was "simple
 * yet immersive", and the immersion here is doing LESS: no columns, no
 * newsletter box, no invented links. A landscape, the mark, one row.
 *
 * The artwork's own top fades to transparent in the FILE (a 483px alpha
 * ramp), so the band needs no gradient of its own and joins whatever sits
 * above it without an edge. Its bottom row is #d8c9af, which is what the real
 * <footer> underneath is painted, so the two read as one continuous field.
 */
.mswc-v3-sitefoot {
	position: relative;
	/*
	 * Border-box so the two paddings are inside the height rather than added to
	 * it. It matters less than it did — this band's height came from
	 * `aspect-ratio` for two versions, and under content-box sizing that ratio
	 * measured the CONTENT box and then had 743px of percentage padding added
	 * on top, which is where the first "huge dead space above the copyright"
	 * came from: 1944px of band holding 1184px of artwork. The ratio is gone
	 * now (see below) but the sizing stays honest.
	 */
	box-sizing: border-box;
	/*
	 * ⚠️ THE ARTWORK IS A THEME ASSET NOW, NOT A MEDIA-LIBRARY UPLOAD (0.16.0).
	 *
	 * It used to arrive as an inline `--v3-foot-art` custom property emitted by
	 * gen_home_v4.py, because the file lived in STAGING's library and had to be
	 * addressed through the build's url-base. That put it on the cutover list
	 * with four other plates, each of them a chance to hit the WordPress
	 * re-upload rename trap and serve superseded art from a page that looked
	 * fine locally.
	 *
	 * A CSS url() resolves against the STYLESHEET, which is inside the theme,
	 * so this one line is correct on staging, on production and in any future
	 * clone, and the file travels in the theme zip. The band is also chrome now
	 * — it is in parts/footer.html, on every page — and chrome should not
	 * depend on somebody having uploaded a picture.
	 */
	--v3-foot-art: url(../img/mswc-footer-plain-b.webp);
	/*
	 * THE COLOUR THE BAND JOINS AT ITS TOP — i.e. the ground of whatever sits
	 * above the footer on this page. #f7f5f1 is the homepage support band's
	 * ground, and while it was hard-coded here the join was seamless on the
	 * homepage and a faint but full-width horizontal line on every page that
	 * ends on white — which after 0.20.0 is most of the site. The overrides at
	 * the bottom of this file set it per page type; this default keeps the
	 * homepage and the ink-ending pages exactly as they were.
	 */
	--v3-foot-join: #f7f5f1;
	/*
	 * A vertical ramp UNDER the artwork, doing two joins at once. The art's
	 * own top is transparent (a baked 483px alpha ramp) so it dissolves into
	 * #f7f5f1, the support band's ground directly above. Its bottom continues
	 * into the same colour, so anything the art does not cover reads as more
	 * ground rather than as a strip.
	 *
	 * ⚠️ #ede9dc, not #efebe1. Re-sampled: the file's last rows composite to
	 * rgb(237, 233, 220) and the band was painted rgb(239, 235, 225), which is
	 * close enough to look right until the narrow layout put 380px of flat
	 * ground directly under the picture and the 2/2/5 difference became a
	 * visible horizontal step. The crop below did not change it: the rows that
	 * were removed were the same colour as the rows that remain.
	 *
	 * 30%: the ramp under the artwork has to reach its final colour before the
	 * artwork's own alpha does, or the semi-transparent top composites over a
	 * lighter ground than intended and shows as a pale band. The artwork's
	 * alpha closes at row 350 of 1520, which is 0.171 of the band's WIDTH on
	 * screen; 30% of the band's height clears that at every width the band
	 * takes now that its height is content-driven.
	 */
	background-color: #ede9dc;
	/*
	 * THREE LAYERS, and the first one is not decoration.
	 *
	 * The artwork's alpha ramp does not start at exactly zero — its first rows
	 * carry a few counts of a mid-tone — so where the band begins it darkened
	 * the ground by 2-3 levels against the #f7f5f1 above it. Two levels is
	 * nothing on its own and a hard horizontal line of it across 1920px is not:
	 * measured (247,245,241) above the join and (245,243,239) below.
	 *
	 * The top layer is 72px of that exact ground fading out, so the band starts
	 * at the colour of the section above it and arrives at the artwork
	 * gradually. It has to stay the FIRST layer: background layers paint first
	 * on top.
	 */
	background-image:
		linear-gradient(to bottom, var(--v3-foot-join) 0px, transparent 72px),
		var(--v3-foot-art),
		linear-gradient(var(--v3-foot-join) 0%, #ede9dc 30%);
	/*
	 * `100% auto`, NOT cover. Cover fills the band by scaling until both axes
	 * are covered and throws away whatever does not fit, which cropped the
	 * landscape at top AND bottom. Sized by width, the picture is complete from
	 * its top down to wherever the band ends.
	 *
	 * ⚠️ NO `min-height`, AND NO `aspect-ratio`. They are a trap together:
	 * aspect-ratio works in both directions, so a min-height the ratio cannot
	 * reach makes the box WIDEN to satisfy it. `min-height: 420px` did exactly
	 * that at 390px — the band came out 517px wide inside a 390px viewport and
	 * the whole document scrolled sideways.
	 */
	background-size: 100% 72px, 100% auto, 100% 100%;
	background-position: center top, center top, center;
	background-repeat: no-repeat, no-repeat, no-repeat;
	/*
	 * ⚠️ NO `aspect-ratio`, AND THAT IS THE FIX FOR THE GAP ABOVE THE COPYRIGHT.
	 *
	 * While the band's height came from the artwork's proportions it grew with
	 * the VIEWPORT while the stack inside it barely did: the wordmark clamps at
	 * 520px and the link row is a fixed 41px, so every pixel of extra width
	 * became empty ground under the links. Measured, the gap between the links
	 * and the copyright was 53px at 1456 and 138px at 1920 — the same CSS,
	 * looking fine on one machine and broken on another. Cropping the file
	 * further only moves that; it does not fix it.
	 *
	 * So the CONTENT sets the height now and the artwork is what yields. It is
	 * still painted `100% auto` from the top, so it is complete down to
	 * whatever the band's bottom is and clipped after that — and what gets
	 * clipped is the flat foreground the crop already established varies by
	 * about two levels, against a band painted the same #ede9dc. There is
	 * nothing to see, at any width.
	 */
	display: flex;
	flex-direction: column;
	align-items: center;
	/*
	 * THE SCENE'S RHINOS ARE THE MARK. Everything below is positioned off them.
	 *
	 * Measured on the file: the pair spans x 37.5-64.1% and stands on a line at
	 * 52.2% of the artwork's height. A full MSWC logo printed here put its own
	 * rhino and calf under the painted ones — four animals, one band — so what
	 * is printed now is the REST of the lockup and nothing else.
	 *
	 * The wordmark does NOT go tight against the feet. Immediately below them
	 * is the densest scrub in the picture, and measured against the wordmark's
	 * ink the darkest pixel there is 1.2:1 between 52% and 58% and still only
	 * 3.4:1 at 64%. The ground is calm from 65.5% down, which is where the
	 * wordmark starts, and 4.5:1 or better under every glyph of it.
	 *
	 * Percentages are of the BAND, and the band is exactly as tall as the
	 * artwork (see box-sizing above), so these numbers are the file's own
	 * coordinates and hold at every width.
	 */
	justify-content: flex-start;
	gap: clamp(24px, 2.6vw, 38px);
	/*
	 * vw, NOT %. Percentage padding resolves against the CONTAINING BLOCK's
	 * width, and this band is `alignfull` inside an `.entry-content` that is
	 * narrower than it by the theme's global padding — so a percentage here
	 * measures the wrong box, and by a different amount at every breakpoint.
	 * The band is the viewport's width, so vw measures the band.
	 *
	 * 53.25vw is 65.5% of the artwork's height: 0.655 * (1665/2048). The one
	 * inaccuracy left is a classic scrollbar, which 100vw includes and the band
	 * does not; that is 0.6% of the band's height and it moves the wordmark
	 * about 8px down its calm strip, which has 10 points of luminance to spare.
	 */
	/*
	 * A FIXED bottom padding, not a proportional one: it is the room the
	 * copyright is pulled up into, and the pull below is fixed too. The two
	 * only stay a constant distance apart if neither of them tracks the width.
	 */
	padding: 53.25vw 24px 7.5rem;
	/*
	 * THE BACKSTOP FOR THE WHITE STRIP AT THE FOOT OF THE PAGE, and it is a
	 * box-shadow on purpose.
	 *
	 * ⚠️ DO NOT DO THIS BY PAINTING `body`. I tried that and it was wrong in a
	 * way worth recording: every LIGHT band on this page is transparent and
	 * takes its white from the canvas, so colouring the body tinted the problem
	 * band, the programme band and the voices band cream. Only the dark bands
	 * and the closing wrapper paint their own.
	 *
	 * An offset shadow with no blur and no spread paints one band-shaped
	 * rectangle 40px lower, which is visible only below this element and cannot
	 * reach anything else. The strip itself is fixed by geometry — the
	 * copyright's pull now exceeds its own height — and this catches whatever
	 * a rounding or a zoom level does to that.
	 */
	box-shadow: 0 40px 0 0 #ede9dc;
	/*
	 * Pulled UP over the donation section's bottom padding. The artwork's own
	 * top is a 350px alpha ramp, so the picture does not actually begin until
	 * about 250px into this band at 1456 and 330px at 1920; butted underneath,
	 * that read as a long white gap between the ask and the landscape. Lifting
	 * the band puts the start of the ramp inside the section above, so the two
	 * dissolve into each other instead of meeting.
	 *
	 * The ceiling is the donation band's own bottom padding (120px measured):
	 * this may eat that space, and must not reach the copy above it. What
	 * overlaps is the gradient's top stop, #f7f5f1, which is exactly the colour
	 * of the closing wrapper it covers, so the overlap itself is invisible.
	 */
	text-align: center;
}

/*
 * ⚠️ THIS SELECTOR IS THE RULE, not decoration. The pull has to beat
 * `body.home .wp-block-post-content > *`, the blockGap reset near the top of
 * this file, which is (0,2,1) and zeroed every band's margin.
 *
 * ⚠️ THE BAND MOVED OUT OF THE PAGE AND INTO parts/footer.html (0.16.0), so it
 * is no longer a child of .wp-block-post-content and no longer needs to beat
 * that rule. What it needs to beat now is the root blockGap on the footer part
 * wrapper's own children, which is core's :where()-wrapped layout rule, so a
 * single class is enough.
 */
.mswc-v3-sitefoot {
	margin-block-start: calc(-1 * clamp(3rem, 8vw, 9rem));
}

/*
 * ⚠️ AND THE ROOT BLOCK GAP ABOVE THE FOOTER PART HAS TO GO WITH IT.
 *
 * Core spaces the children of `.wp-site-blocks` with the root blockGap, so the
 * <footer> template part carries 36px of margin-top. The band's own negative
 * margin COLLAPSES with it (the wrapper has no padding and no border), which
 * quietly cancels 36px of a 116px pull and leaves a pale gap between the last
 * band and the start of the artwork's alpha ramp.
 *
 * This is the same class of bug as the margin that lost to
 * `body.home .wp-block-post-content > *` in August: the declaration ships, the
 * computed value is wrong, and nothing errors. It was NOT caught by the preview
 * harness, which did not model that rule; it was reasoned out from where the
 * band now sits in the document. Worth re-checking on staging.
 */
.wp-site-blocks > footer.wp-block-template-part {
	margin-block-start: 0;
}

/*
 * The band is a flow-layout group, so core wants to space its two children
 * with the root blockGap. The band is a flex column with its own `gap`; both
 * would apply and the wordmark would sit 36px further from the links than the
 * design says.
 */
.mswc-v3-sitefoot > * {
	margin-block: 0;
}

/*
 * THE WORDMARK. The bottom block of the real logo file, set under the painted
 * animals so the two read as one lockup.
 *
 * Sized off the RHINOS, not off the band: the pair is 26.6% of the band wide,
 * and in the original logo the wordmark is about 1.35x the width of the mark
 * above it. 34% keeps that relationship, which is what makes it read as the
 * same object rather than as a caption that happens to be nearby.
 *
 * Centred on the ANIMALS (50.8%), not on the band. The half-point difference
 * is 12px at the wide breakpoint, which is small and is exactly the kind of
 * small that looks like carelessness rather than like nothing.
 */
/*
 * ⚠️ A PAINTED DIV, NOT AN <img>, AND THE REASON IS THE TEMPLATE PART.
 *
 * The band lives in parts/footer.html now, and a static block template cannot
 * work out the theme's URL — only PHP or a CSS url() can. So the mark is a
 * background-image with `role="img"` and an `aria-label`, which is exactly what
 * an <img> with alt text exposes: one image node with an accessible name. The
 * intrinsic ratio the <img> used to supply is restated as `aspect-ratio` from
 * the file's own 1377x363, so the box is the same shape at every width.
 */
.mswc-v3-footwordmark {
	width: clamp(230px, 34%, 520px);
	aspect-ratio: 1377 / 363;
	display: block;
	margin-left: 1.6%;
	background-image: url(../img/mswc-wordmark.webp);
	background-size: contain;
	background-position: center;
	background-repeat: no-repeat;
}

/*
 * ⚠️ THE FOOTER LINKS ARE THE SITE MENU NOW (0.16.0), NOT A HAND-WRITTEN LIST.
 *
 * gen_home_v4.py used to emit six <a class="mswc-v3-footlink"> with URLs built
 * from the build's url-base. The band is a template part now, on every page, and
 * a static block template cannot build a URL — but core's navigation block can,
 * and it resolves to the same single menu the topbar uses. That is the Tier 2
 * promise ("one navigation menu instead of two") kept in the one place the site
 * was still keeping a second copy of it, and it means a menu edit in the Site
 * Editor reaches the footer too.
 *
 * So these rules target core's markup. `overlayMenu: "never"` in the part keeps
 * it a flat row at every width — a hamburger in a footer would be absurd.
 */
.mswc-v3-footnav {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
}

/*
 * theme.json gives core/navigation a 3rem blockGap for the topbar, where the
 * items have no padding of their own. These do, and the separators sit on the
 * item boxes, so any gap here would push the hairlines away from the words they
 * divide. The padding below IS the spacing.
 */
.mswc-v3-footnav .wp-block-navigation__container,
.mswc-v3-footnav ul {
	gap: 0;
}

.mswc-v3-footnav .wp-block-navigation-item__content {
	font-size: 0.8125rem;
	line-height: 1.6;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--v3-body);
	text-decoration: none;
	padding: 10px 20px;
	transition: color 0.2s ease;
}

/* Hairline separators between links, never before the first one. */
.mswc-v3-footnav .wp-block-navigation-item + .wp-block-navigation-item {
	border-left: 1px solid rgba(63, 63, 80, 0.28);
}

.mswc-v3-footnav .wp-block-navigation-item__content:hover,
.mswc-v3-footnav .wp-block-navigation-item__content:focus {
	color: var(--v3-olive);
}

.mswc-v3-footnav .wp-block-navigation-item__content:focus-visible {
	outline: 2px solid var(--v3-olive);
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.mswc-v3-footnav .wp-block-navigation-item__content {
		transition: none;
	}
}

@media (max-width: 600px) {
	/* Stacked, the separators become horizontal rules between rows, which
	 * reads as a broken table. Drop them and let the spacing do it. */
	.mswc-v3-footnav .wp-block-navigation-item + .wp-block-navigation-item {
		border-left: 0;
	}

	.mswc-v3-footnav .wp-block-navigation__container,
	.mswc-v3-footnav ul {
		gap: 4px 12px;
	}
}

/* ----------------------------------------------------------------- footer */

/*
 * ⚠️ SITE-WIDE NOW (0.16.0), AND THE MARKUP CHANGED WITH IT.
 *
 * This block used to be scoped to body.home and fought parts/footer.html on
 * three fronts: a sage preset background (which WordPress emits with
 * !important, so no selector could beat it), an inline 30px padding pair and an
 * inline 20px margin on the paragraph. Two of the theme's three !importants
 * were here, each one against an inline style.
 *
 * The part now states what the design actually wants — no background colour, no
 * top padding, no paragraph margin — so every one of those fights is gone and
 * so are both !importants. What is left below is the part CSS has to do: paint
 * the line, and lift it onto the artwork.
 */
.mswc-v3-copyright {
	/*
	 * Pulled up onto the landscape above it.
	 *
	 * The first attempt painted this strip the artwork's mean bottom colour
	 * (#d5c6ac) and butted it underneath. That mean is not what the eye sees:
	 * the bottom row is grass texture varying across its width, so a flat
	 * strip of the average showed a seam wherever the local colour differed.
	 * Printing the line ON the image removes the join instead of matching it.
	 *
	 * The negative margin is doing real work and is not a nudge: it lifts the
	 * whole footer onto the open ground the artwork leaves below the link row,
	 * which is roughly the band's last 190px once .mswc-v3-sitefoot's height is
	 * the artwork's height. Take the pull away and the copyright falls off the
	 * bottom of the picture onto white.
	 *
	 * The element stays a <footer>: that tag only exposes the contentinfo
	 * landmark when it is NOT inside <main>, and it is the site's only one.
	 */
	position: relative;
	z-index: 1;
	/*
	 * FIXED, not a clamp, and it is half of a pair: .mswc-v3-sitefoot reserves
	 * 7.5rem of bottom padding and this lifts the whole footer 6.25rem into it,
	 * which leaves the copyright about 56px under the link row and its own
	 * bottom edge inside the band. Both numbers are fixed on purpose — while
	 * this was a vw clamp against a band whose height tracked the viewport, the
	 * distance between the links and the copyright changed with the window.
	 *
	 * ⚠️ The pull must also EXCEED this element's own height, or its last rows
	 * fall past the artwork onto the page background. That is what the white
	 * strip at the bottom of the page was: 10px of transparent <footer> over a
	 * white body.
	 */
	margin-block-start: -6.25rem;
}

.mswc-v3-copyright p {
	/* 7.15:1 on the artwork's #ede9dc ground, measured inside the glyph
	 * bounds off a screenshot. Re-measured, not adjusted: the
	 * last time this footer changed colour the old value inverted to sage on
	 * sage at 1.00:1, and only the contrast sweep caught it. */
	color: #4c4a3f;
	font-size: 0.8125rem;
	letter-spacing: 0.03em;
	/*
	 * 1.857 was an INLINE style in parts/footer.html until 0.16.0. Rewriting
	 * that part to stop fighting inline styles nearly dropped it, which would
	 * have shortened the line's box by about 4px and moved the copyright up
	 * inside the artwork — a change nobody asked for, on a footer Guy approved
	 * on 4 September. Restated here so the line sits exactly where it did.
	 */
	line-height: 1.857;
}

/*
 * The lime dash is gone. It was the sign-off for an INK footer, echoing the
 * stat numerals; on the landscape it is a bright green chip on a dusty
 * watercolour and the only saturated thing in the whole band. The artwork is
 * the sign-off now.
 */

/* --------------------------------------------------------------- reveals */

/*
 * Visible by default. JS adds `will-reveal` only to elements still below the
 * fold (never above it, so nothing flashes), then `is-in` when they enter.
 * With JS off or reduced motion, none of this applies and everything shows.
 * migration/tools/settle.js force-finishes these before any measurement,
 * exactly as it does for production's nfd-wb-animate.
 */
.mswc-v3-reveal.will-reveal {
	opacity: 0;
	transform: translateY(26px);
	transition: opacity 0.7s ease, transform 0.7s ease;
}

.mswc-v3-reveal.will-reveal.is-in {
	opacity: 1;
	transform: none;
}

/* -------------------------------------------------------------- responsive */

@media (max-width: 1023px) {
	.mswc-v3-chapter {
		grid-template-columns: 1fr;
	}

	.mswc-v3-chapter-text {
		position: static;
	}
}

@media (max-width: 781px) {
	.mswc-v3-stats {
		grid-template-columns: 1fr;
		gap: 40px;
		margin-top: 48px;
	}

	.mswc-v3-cols {
		grid-template-columns: 1fr;
	}

	.mswc-v3-rail img {
		height: 380px;
	}

	/*
	 * Both plates come out of absolute positioning and become ordinary blocks.
	 * They sit in source order BEFORE .mswc-v3-wrap, so without help the art
	 * would land above the copy in both bands. That reads fine for the problem
	 * band (a pale wash introducing the section) and wrong for the blog band,
	 * where the reference puts the photograph after the words. Hence the flex
	 * column and the order swap on that one only.
	 */
	.mswc-v3-plate {
		min-height: 0;
	}

	/*
	 * ⚠️ NO PICTURE IN THIS BAND ON A PHONE. This is a decision, not an
	 * oversight, and it survived three attempts to make one work — see the
	 * long note above ILLUS_URL in gen_home_v4.py for the full history.
	 * Alex judged each one on his own phone; the last verdict was that even a
	 * 200px spot illustration was not earning its place beside the heading.
	 *
	 * `display: none` rather than removing the markup, because the picture is
	 * still the whole point of this band on a desktop. It costs no bytes: the
	 * <img> carries loading="lazy", and an image with no layout box never
	 * intersects the viewport, so the phone never requests it. Verified on a
	 * COLD browser profile at 390, with the band scrolled into view — zero
	 * requests for either plate file.
	 *
	 * ⚠️ MEASURE THAT ON A COLD PROFILE OR NOT AT ALL. Checked in a session
	 * that had already viewed this page at 1456, it looks like the image IS
	 * being fetched: a resource-timing entry appears for
	 * `mswc-plate-peers-e.webp` with initiatorType `img`. It is
	 * `deliveryType: "cache"` and `transferSize: 0` — the memory cache
	 * re-registering an entry for a file that earlier load already had. I
	 * wrote the opposite conclusion into this comment for one commit on the
	 * strength of it.
	 *
	 * If a picture is ever wanted back here, `mswc-plate-peers-m.webp` (the
	 * portrait redraw, 768x812, 26.5 KB) is already in the staging library.
	 */
	.mswc-v3-plate-art {
		display: none;
	}

	/*
	 * The band's own veil and bottom fade stay switched off here (below), and
	 * with the picture gone there is nothing left for them to do anyway: they
	 * exist to hold copy up against artwork that is no longer there.
	 */

	/*
	 * No veil here. It exists to hold a heading up against artwork that is
	 * BEHIND it, and at this width the artwork is a block above the words
	 * instead. Left switched on it would wash out the left of the picture to
	 * protect type that is nowhere near it.
	 */
	.mswc-v3-plate::before,
	.mswc-v3-plate::after {
		display: none;
	}

	.mswc-v3-blogfeature {
		min-height: 0;
		padding: var(--v3-band-pad) 0;
	}

	.mswc-v3-blogfeature .mswc-v3-wrap {
		display: block;
		min-height: 0;
		padding: 0 24px;
	}

	.mswc-v3-blogcard {
		max-width: none;
	}

	/*
	 * The plate goes BEHIND the blog band's copy at low opacity rather than
	 * becoming a block above it. Stacked as an element it would push the words
	 * down half a screen to show a picture the words do not depend on.
	 */
	/*
	 * A WASH, NOT A BLOB.
	 *
	 * `contain` + `right top` printed the file at its own proportions inside a
	 * 390x571 box, and this file carries an oval vignette on white, so what
	 * landed behind the copy was a beige ellipse with a visible edge, clipped
	 * by the right gutter. At 0.3 it was solid enough to read as a stray
	 * shape rather than as a ground — a rendering fault, not artwork.
	 *
	 * `cover` fills the band so the Kilimanjaro/acacia scene runs edge to
	 * edge; the mask dissolves the vignette's curved bottom before it can be
	 * seen; and the opacity buys back the contrast that filling the band
	 * spends. 30% vertical anchoring keeps the horizon under the copy rather
	 * than behind the heading.
	 *
	 * ⚠️ 0.18 IS A MEASURED CEILING, not a taste. At 0.22 the "Ewaso Lions:
	 * The Power of Community-Led Conservation." link measured 4.46:1 against
	 * the 4.5 it needs — and unlike a bad worst-pixel this was flat across the
	 * whole run (median 4.66), because filling the band put the acacia's dark
	 * trunk under the link's full width. Raising the wash toward white is the
	 * lever; 0.18 measures 4.9 and leaves margin for the file being reworked.
	 */
	.mswc-v3-blogart {
		width: 100%;
		opacity: 0.18;
		-webkit-mask-image: linear-gradient(to bottom, #000 55%, rgba(0, 0, 0, 0) 92%);
		mask-image: linear-gradient(to bottom, #000 55%, rgba(0, 0, 0, 0) 92%);
	}

	.mswc-v3-blogart img {
		object-fit: cover;
		object-position: 50% 30%;
	}

	/*
	 * ONE COLUMN.
	 *
	 * ⚠️ `max-width: none` is load-bearing. The desktop rule caps this grid at
	 * the ask's 46% and, left in place here, squeezed the entire donation
	 * section into 46% of a phone.
	 */
	.mswc-v3-closing .mswc-v3-support {
		grid-template-columns: 1fr;
		gap: 44px;
		max-width: none;
	}

	.mswc-v3-closing .mswc-v3-support-proof {
		max-width: none;
	}

	/*
	 * THE LOCKUP COMES OFF THE PICTURE.
	 *
	 * At 390px the artwork is 317px tall and the wordmark, five links and the
	 * copyright want about 250 of that. Printed on it they would be stacked
	 * over the rhinos with nothing left as landscape, which is the opposite of
	 * "simple yet immersive". So the picture keeps the top of the band and
	 * everything else sits on the pale ground below it — the same #ede9dc the
	 * file ends on, so there is no join to see.
	 *
	 * The ratio goes with it. It exists to make the band exactly as tall as
	 * the artwork, and here the band has to be taller than the artwork on
	 * purpose; left on, it would also fight the padding for control of the
	 * width (see the note on min-height above).
	 */
	.mswc-v3-sitefoot {
		/* 78vw against the cropped artwork's own 74.2vw: the picture in full,
		 * then a little air before the wordmark starts.
		 *
		 * The bottom padding is not spacing, it is the room the copyright is
		 * pulled up INTO, and it works with the pull below or not at all. The
		 * copyright's position is (band bottom - pull), so ADDING padding here
		 * moves the band's bottom and the copyright with it: 5.5rem and 8rem
		 * both left the same 24px of "© 2026 Management Skills..." hanging off
		 * the band onto white. The pull is the lever; this is the room. */
		padding: 78vw 24px clamp(9rem, 30vw, 11rem);
		gap: 26px;
	}

	/*
	 * A DEEPER PULL THAN THE WIDE BREAKPOINT, because at this width the
	 * copyright wraps to two lines: the whole <footer> is about 112px tall
	 * here against 58px at 1456, and the pull has to clear the element, not
	 * the line. 4rem left its last 24px below the artwork.
	 */
	.mswc-v3-copyright {
		margin-block-start: calc(-1 * clamp(7.5rem, 32vw, 9rem));
	}

	.mswc-v3-hero {
		/* was `- 76px`, a guess: the mobile topbar is 116.7px, so the hero
		 * overflowed the fold by 41px and pushed the CTAs out of view. */
		min-height: max(520px, calc(100svh - var(--v3-topbar-h)));
	}

	/*
	 * THE H1's SCRIM IS A DIFFERENT SHAPE ON A PHONE, because the headline is.
	 *
	 * The desktop pair is a DIAGONAL wash (105deg, out to 68% of the width)
	 * plus a bottom-up one. That works at 1456, where the h1 occupies the left
	 * half and the wash covers all of it: measured there, the headline is
	 * 6.37:1 at the tenth percentile of its own ground and 11.87:1 at the
	 * median. Fine.
	 *
	 * At 390 the h1 is full-bleed — 24px to 366px — so it runs a third of its
	 * width past where the diagonal has faded to nothing, and what is behind
	 * that third is bright cloud. Measured with the two-shot sweep: 1.41:1 at
	 * the worst pixel, 1.79:1 at the TENTH PERCENTILE. The percentile is the
	 * number that matters — a bad worst-pixel can be one stem over one bright
	 * spot, but a tenth of the ground under a headline at 1.79:1 is white type
	 * on white cloud over a real area.
	 *
	 * So at this width the diagonal is replaced by a vertical band sized to
	 * the headline's own position rather than to a horizontal fraction that
	 * has no meaning here. Re-measured after: worst 4.14, tenth 4.45, against
	 * the 3.0 that 40px bold needs. The deck, both CTAs and the eyebrow all
	 * pass with room.
	 *
	 * ⚠️ This is a MOBILE-ONLY declaration and the desktop hero is byte-for-
	 * byte what it was. Verified at 1456 after the change, not assumed.
	 */
	.mswc-v3-hero::after {
		background:
			linear-gradient(
				to bottom,
				rgba(10, 14, 15, 0.28) 0%,
				rgba(10, 14, 15, 0.5) 26%,
				rgba(10, 14, 15, 0.5) 58%,
				rgba(10, 14, 15, 0.26) 76%,
				rgba(10, 14, 15, 0.1) 100%
			),
			linear-gradient(
				to top,
				rgba(10, 14, 15, 0.88) 0%,
				rgba(10, 14, 15, 0.55) 34%,
				rgba(10, 14, 15, 0.12) 62%,
				rgba(10, 14, 15, 0.2) 100%
			);
	}

	/*
	 * THE BAR NEEDS ITS OWN GUTTERS AT THIS WIDTH.
	 *
	 * `has-global-padding` computes 0 here, so the logo sat at x=0 and the
	 * hamburger's right edge at x=390 — both literally touching the screen
	 * edges, with the button also falling inside the thumb-reject zone of a
	 * phone's curved glass.
	 *
	 * 20px rather than the bands' 24px: the logo is optically inset by its own
	 * transparent margin, so matching the bands numerically over-indents it.
	 */
	.mswc-v3-topbar {
		padding: 8px 20px;
	}

	/*
	 * 120px, down from 140. The bar is sticky, so its height is spent on every
	 * screen of a 10,000px page: at 140 the logo was 96px tall and the bar 117,
	 * which is 14% of a 844px phone permanently occupied by chrome. The mark is
	 * still legible at 120 — it is a wordmark under a rhino, not fine print.
	 *
	 * Nothing downstream needs updating by hand: home-v4.js measures the bar on
	 * load and on resize and rewrites --v3-topbar-h, which is what sizes the
	 * hero and (below) the anchor offsets.
	 */
	.mswc-v3-topbar .wp-block-site-logo img {
		width: 120px;
	}

	/*
	 * ANCHOR TARGETS CLEAR THE STICKY BAR.
	 *
	 * Both hero CTAs are in-page jumps (#film, #evidence) and neither landed
	 * correctly: the band's top went to y=0, which put its eyebrow at y=90
	 * under a 117px bar. Tapping "See the evidence" — the primary call to
	 * action on the page — delivered the reader to a section whose label was
	 * behind the header.
	 *
	 * The variable is the measured bar height, so this tracks the logo size
	 * above rather than restating it.
	 */
	.mswc-v3-band[id],
	.mswc-v3-hero[id],
	.mswc-v3-closing[id] {
		scroll-margin-top: calc(var(--v3-topbar-h) + 12px);
	}
}

/* ------------------------------------------------- background film cost */

/*
 * Stop the Ken Burns pan once the film is up.
 *
 * The poster keeps its infinite 26s scale animation even when a video is
 * painted over it at full opacity. Nobody can see it, and the compositor
 * animates a 2560px image underneath a scaled cross-origin video every single
 * frame for as long as the hero is on screen. Switching it off when the film
 * confirms costs nothing visually and gives that work back.
 */
.mswc-v3-hero.has-video .mswc-v3-hero-media img {
	animation: none;
}

/*
 * Stand the topbar's blur down while a film is under it.
 *
 * `backdrop-filter: blur(14px)` has to re-read and re-blur whatever is behind
 * the bar on every frame, and behind the bar is live video. The bar keeps its
 * translucent white, so the change is invisible over a dark hero; what goes is
 * a per-frame blur pass over a moving source. films.js sets the flag on <html>
 * whenever the hero or the story band is intersecting.
 */
html.mswc-film-onscreen .mswc-v3-topbar {
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
	background: rgba(255, 255, 255, 0.92);
}

/*
 * ⚠️ THE BLUR HAS TO GO WHILE THE MOBILE MENU IS OPEN, and this is a
 * correctness fix, not a cosmetic one.
 *
 * `backdrop-filter` makes an element the CONTAINING BLOCK for every
 * position: fixed descendant, exactly as `transform` and `filter` do. Core's
 * overlay menu is `position: fixed; inset: 0` inside this bar, so it resolved
 * against a 390x117 bar instead of the viewport: the panel was 117px tall,
 * five of the six links were clipped out of it, and the homepage could not be
 * navigated on a phone at all.
 *
 * The film rule directly above drops the blur too, and it is worth being
 * precise about why that never helped: it fires on `html.mswc-film-onscreen`,
 * which films.js only ever sets when a background film has mounted, and the
 * film is gated at `innerWidth >= 768`. Core's overlay menu appears below
 * 600px. The two ranges do not overlap, so on a phone the blur was ALWAYS on
 * and the menu was ALWAYS broken — not sometimes, always. Between 600 and
 * 768 there is no overlay button to press.
 *
 * `has-modal-open` is core's own flag — its navigation script puts it on
 * <html> while the overlay is up — so this costs nothing when the menu is shut
 * and the bar keeps its blur everywhere else.
 */
html.has-modal-open .mswc-v3-topbar {
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
	background: #ffffff;
}

/* ==========================================================================
 * THE INNER PAGES — About, What We Do, Testimonials, Contact
 * ==========================================================================
 *
 * Added 2026-09-05 (0.16.0), after Guy approved the homepage on 4 September and
 * asked for the rest of the site to match it.
 *
 * Everything above this line is the homepage's and is reused as-is: the bands,
 * the eyebrow, the h2, the prose measure, the buttons, the reveals, the chapter
 * layout. What is below is only what these four pages have and the homepage
 * does not — a page title that is not a hero, thirteen faces, six partner
 * logos, a numbered practice list, a video wall and two forms.
 *
 * The seam this closes was real and one click wide: from the redesigned
 * homepage, "About Us" landed on production's 11.25px type under a 340px sage
 * logo band. Guy would have found it immediately.
 */

/* --------------------------------------------------------------- page hero */

/*
 * NOT a 100svh film hero. That hero exists to make an argument before the
 * visitor scrolls; an inner page has already been chosen and its job is to name
 * itself and get out of the way. So: the same eyebrow and the same display
 * face, a third of the height, no picture, and a hairline underneath instead of
 * a scrim.
 *
 * The top padding clears the sticky bar. It is the ONE place on these pages
 * that has to know the bar exists, because every other band is preceded by a
 * band.
 */
.mswc-v3-pagehero {
	padding-top: clamp(3rem, 6vw, 5rem);
	padding-bottom: clamp(2.5rem, 4.5vw, 4rem);
	border-bottom: 1px solid rgba(20, 24, 26, 0.09);
}

.mswc-v3-pagetitle {
	font-family: var(--wp--preset--font-family--display);
	/* 56px at 1456. Deliberately under the homepage h1's 64px: that headline is
	 * an argument set over a photograph and this one is a label. */
	font-size: clamp(2.5rem, 4.2vw, 3.5rem);
	line-height: 1.06;
	letter-spacing: -0.02em;
	font-weight: 700;
	color: #1f1f1f;
	margin: 12px 0 0;
	text-wrap: balance;
}

/*
 * The deck on an inner page is dark-on-light, so it cannot inherit the hero's
 * white. It also sets one step down from the homepage's 20px, because here it
 * runs a full measure rather than 44 characters over a picture.
 */
.mswc-v3-pagehero .mswc-v3-deck {
	font-size: 1.1875rem;
	line-height: 1.6;
	color: var(--v3-body);
	max-width: 52ch;
	margin-top: 20px;
}

/* ------------------------------------------------------------ tinted band */

/*
 * The one extra ground these pages needed. Two white bands of faces in a row
 * read as one long list that lost its heading halfway down, and a dark band
 * there would have been three dark bands on the About page.
 *
 * #f7f5f1 is not a new colour: it is the blog band's ground on the homepage,
 * which is why --v3-olive exists (the site accent measures 4.32:1 on it and
 * fails). Any link or eyebrow placed on this band must use olive for the same
 * reason. That is not a preference, it is the measurement.
 */
.mswc-v3-tint {
	background: #f7f5f1;
}

.mswc-v3-tint .mswc-eyebrow,
.mswc-v3-tint a:not(.mswc-v3-btn):not(.mswc-v3-ghost) {
	color: var(--v3-olive);
}

/* --------------------------------------------------------------- headings */

/*
 * ⚠️ THE GHOST BUTTON WAS WHITE ON WHITE, AND THIS IS THE FIX.
 *
 * `.mswc-v3-ghost` was written for the homepage, where it only ever appears on
 * the hero and on dark bands, so it is white type in a white hairline box. The
 * first What We Do build put one on the closing LIGHT band ("About MSWC" beside
 * "Support the work") and it computed at 1.00:1 — a button that is simply not
 * there. The preview harness caught it; no screenshot was available this
 * session and a screenshot would have shown an empty gap that read as spacing.
 *
 * Scoped by what the band is NOT rather than by adding a modifier class, so any
 * future ghost on any future light band is right by default. This is the same
 * failure the footer had in August (sage on sage, 1.00:1, found by the contrast
 * sweep and invisible to the eye as "a deliberately minimal band"), and the
 * lesson is the same one: a colour is only correct relative to the ground it
 * lands on, and a component that carries its colour but not its ground will
 * eventually be put somewhere it disappears.
 */
.mswc-v3-band:not(.mswc-v3-dark):not(.mswc-v3-accent) .mswc-v3-ghost {
	color: #1d1d22;
	border-color: rgba(29, 29, 34, 0.35);
}

.mswc-v3-band:not(.mswc-v3-dark):not(.mswc-v3-accent) .mswc-v3-ghost:hover,
.mswc-v3-band:not(.mswc-v3-dark):not(.mswc-v3-accent) .mswc-v3-ghost:focus-visible {
	border-color: #1d1d22;
	background: rgba(29, 29, 34, 0.05);
}

.mswc-v3-h3 {
	font-family: var(--wp--preset--font-family--body);
	font-size: 1.1875rem;
	line-height: 1.35;
	letter-spacing: -0.01em;
	font-weight: 600;
	color: #1f1f1f;
	margin: 0 0 10px;
}

.mswc-v3-dark .mswc-v3-h3 {
	color: #fff;
}

.mswc-v3-band .mswc-v3-prose + .mswc-v3-prose {
	margin-top: 20px;
}

/*
 * The Testimonials link on the About page. It is a sentence, not a button (see
 * gen_about_v4.py), so it needs to look clickable without looking like a
 * control: the accent blue the rest of the site uses for links, and a rule that
 * thickens on hover rather than appearing on it.
 */
.mswc-v3-prose-link a {
	color: var(--v3-accent);
	text-decoration: none;
	border-bottom: 1px solid rgba(1, 122, 183, 0.4);
	transition: border-color 0.2s ease;
}

.mswc-v3-prose-link a:hover,
.mswc-v3-prose-link a:focus-visible {
	border-bottom-color: var(--v3-accent);
}

/* ------------------------------------------------------------ people grid */

/*
 * Nine directors and four advisory members.
 *
 * `minmax(200px, 1fr)` against the 1200px measure gives FIVE columns (5 x 200 +
 * 4 x 28 = 1112, six would need 1340), so the board reads 5 + 4 and the advisory
 * board is one full row. That was chosen by arithmetic rather than by eye
 * because the count has changed twice this year and will change again: Shivani
 * Bhalla joined in July, Rob Vember left, and a hard-coded column count would
 * quietly strand somebody on a row of their own.
 */
/*
 * ⚠️ THE COLUMN COUNT IS DECLARED, NOT DISCOVERED. `auto-fill minmax(200px)`
 * gave five columns at the 1200px measure, so the nine directors set as 5 + 4
 * and the band ended on a ragged half-row with a hole in it. Nine is 3 x 3 and
 * four is 4 x 1, and both of those are whole. The generator states which it
 * wants, because it is the only thing that knows how many people there are.
 */
.mswc-v3-people {
	display: grid;
	grid-template-columns: repeat(var(--v3-people-cols, 3), minmax(0, 1fr));
	gap: clamp(36px, 4vw, 56px) clamp(24px, 3vw, 44px);
	margin-top: 48px;
}

.mswc-v3-people--4 {
	--v3-people-cols: 4;
}

.mswc-v3-person {
	margin: 0;
	text-align: center;
}

/*
 * ⚠️ THE CIRCLE IS `aspect-ratio` + `object-fit`, NOT a border-radius on a
 * naturally-sized image. These thirteen photographs are every shape there is:
 * 388x388, 999x1024, 1024x895, 1024x1009. Production got its circles from
 * `.nfd-rounded-full`, a page-builder class the rebuild strips, and the first
 * migration of this page shipped them square because the radius was restated
 * without the sizing that made it a circle rather than an oval.
 */
.mswc-v3-portrait {
	display: block;
	width: min(160px, 100%);
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: 50%;
	margin: 0 auto 16px;
	background: #f0efec;
}

.mswc-v3-person figcaption {
	display: block;
}

.mswc-v3-person-name {
	display: block;
	font-size: 0.9375rem;
	line-height: 1.35;
	font-weight: 600;
	color: #1f1f1f;
	letter-spacing: 0.01em;
}

/*
 * ⚠️ THE NAMES ARE LINKS AND MUST NOT BE BLUE. Nine of the thirteen link to a
 * bio page and four do not, so a blue underlined name would divide the board
 * into people who look important and people who look like plain text. The link
 * announces itself on hover and on focus instead. (The mirror-image mistake is
 * already in this project's history: the first About migration rendered every
 * board member's name as a blue link and Alex caught it by eye in seconds.)
 */
.mswc-v3-person-name a {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid transparent;
	transition: border-color 0.2s ease;
}

.mswc-v3-person-name a:hover,
.mswc-v3-person-name a:focus-visible {
	border-bottom-color: currentColor;
}

.mswc-v3-person-role {
	display: block;
	margin-top: 5px;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--v3-body);
	text-wrap: pretty;
}

/* ---------------------------------------------------------- partner logos */

/*
 * A flex row rather than a grid, because these six files have wildly different
 * proportions (a 1024x307 wordmark next to a 600x540 roundel). Normalising them
 * on HEIGHT is what makes them read as a set; a grid would normalise them on
 * width and print one logo four times the optical size of its neighbour.
 */
.mswc-v3-logos {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 40px 56px;
	margin-top: 48px;
	padding: 8px 0;
}

.mswc-v3-logo {
	display: block;
	line-height: 0;
	opacity: 0.85;
	transition: opacity 0.2s ease;
}

.mswc-v3-logo:hover,
.mswc-v3-logo:focus-visible {
	opacity: 1;
}

.mswc-v3-logo img {
	display: block;
	height: clamp(38px, 4vw, 54px);
	width: auto;
	max-width: 220px;
	object-fit: contain;
}

.mswc-v3-partner-cta {
	margin-top: 56px;
	padding-top: 40px;
	border-top: 1px solid rgba(20, 24, 26, 0.09);
}

.mswc-v3-partner-cta .mswc-v3-prose {
	font-size: 1.1875rem;
	line-height: 1.6;
	color: #1f1f1f;
	margin-top: 0;
}

/* --------------------------------------------------- numbered practice list */

/*
 * The six areas of practice.
 *
 * ⚠️ THE NUMBERS ARE A CSS COUNTER, NOT PARAGRAPHS. Production prints "01"
 * through "06" as ordinary paragraph blocks in their own columns, which puts
 * six bare numerals into the document's reading order between the headings.
 * As a counter they belong to the list they number.
 */
/*
 * AN INDEX, NOT SIX FEATURE CARDS.
 *
 * This was three columns of identical cells, each a hairline, a 13px tracked
 * numeral, a bold heading and a grey paragraph, all six weighted the same. That
 * is the single most recognisable shape in machine-made web design — "identical
 * cards in a uniform grid, numbered 01..06" — and it is worth naming why it is
 * also WRONG here rather than merely common: these six are not six equal
 * features. The first is the whole training programme and the sixth is support
 * for one conference. A grid that renders them identically is making a claim
 * about MSWC's work that MSWC would not make.
 *
 * Two columns, rules that run across the row rather than boxing each cell, and
 * the numeral OUTDENTED into the margin in the display face. That is how a
 * contents page is set, it gives the copy a longer measure, and the rules line
 * up across both columns so the band has a grid instead of six floating boxes.
 */
.mswc-v3-steps {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0 clamp(48px, 6vw, 104px);
	margin-top: 56px;
	counter-reset: mswc-step;
}

.mswc-v3-step {
	counter-increment: mswc-step;
	position: relative;
	padding: 28px 0 32px 76px;
	border-top: 1px solid rgba(20, 24, 26, 0.16);
}

/*
 * Two digits, zero-padded, the way production wrote them.
 * `decimal-leading-zero` keeps "06" rather than "6" without anybody having to
 * remember the zero.
 *
 * ⚠️ IT HANGS IN THE MARGIN AND THAT IS THE POINT. Set inline above the
 * heading it reads as a badge, which is the tell; set in the margin at display
 * size it reads as editorial numbering, which is what it actually is. It is
 * also `aria-hidden` by construction — generated content is not in the DOM, and
 * the list is announced as six headings and six paragraphs, which is right.
 */
.mswc-v3-step::before {
	content: counter(mswc-step, decimal-leading-zero);
	position: absolute;
	left: 0;
	top: 24px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.75rem;
	line-height: 1;
	font-weight: 700;
	letter-spacing: 0;
	/*
	 * ⚠️ 0.55, NOT 0.28. The first pass set these at 0.28 alpha to keep them
	 * quiet and that computed to about 1.9:1 on the band's own tint — a numeral
	 * carrying the order of the list, too faint to read. Generated content is
	 * not a DOM text node, so the glyph sweep cannot see it and reported the
	 * band clean; this one has to be judged by eye and by arithmetic.
	 */
	color: rgba(20, 24, 26, 0.55);
	font-variant-numeric: lining-nums tabular-nums;
}

.mswc-v3-step .mswc-v3-h3 {
	margin-top: 0;
}

.mswc-v3-step .mswc-v3-prose {
	margin-top: 10px;
	max-width: 42ch;
}

/* --------------------------------------------------------- LAMP sessions */

/*
 * Production sets these as "SESSION" and a digit in two separate paragraphs
 * beside each module name, inside an accent box that had to be pinned with
 * `.mswc-shrink0` because a `selfStretch:fill` sibling crushed it until the
 * word SESSION wrapped letter by letter. An <ol> says the same thing, needs no
 * pinning, and cannot come apart.
 */
.mswc-v3-sessions {
	list-style: none;
	margin: 48px 0 0;
	padding: 0;
	counter-reset: mswc-session;
	display: grid;
	/*
	 * 420px, not 300px, and the number is arithmetic rather than taste: there
	 * are FOUR sessions, and at the 1200px measure a 300px minimum gives three
	 * columns, so the fourth module sat alone on a row of its own. 420 gives
	 * two, and four divides by two.
	 */
	grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
	gap: 40px 48px;
}

.mswc-v3-session {
	counter-increment: mswc-session;
	padding-left: 76px;
	position: relative;
}

/*
 * ⚠️ ONE NUMBERING TREATMENT ON THIS PAGE, NOT TWO. These were 44px lime
 * outlined circles, i.e. numbered badge chips — the same tell as the practice
 * grid above wearing a different costume, and the page carried both at once.
 * They are now the identical hanging display numeral the practice index uses,
 * in lime because this band is ink. Numbering these IS honest: they are
 * sequential modules of one course. What was wrong was decorating the fact.
 */
.mswc-v3-session::before {
	content: counter(mswc-session, decimal-leading-zero);
	position: absolute;
	left: 0;
	top: -2px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.75rem;
	line-height: 1;
	font-weight: 700;
	color: rgba(201, 228, 92, 0.85);
	font-variant-numeric: lining-nums tabular-nums;
}

.mswc-v3-session .mswc-v3-prose {
	margin-top: 0;
	color: var(--v3-on-dark);
}

/* ------------------------------------------------------------------ quotes */

.mswc-v3-quote {
	margin: 0;
	padding: 0;
	border: 0;
}

.mswc-v3-quote p {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.5rem, 2.4vw, 2rem);
	line-height: 1.35;
	font-weight: 700;
	letter-spacing: -0.01em;
	color: #1f1f1f;
	margin: 0;
	text-wrap: balance;
}

.mswc-v3-dark .mswc-v3-quote p {
	color: #fff;
}

.mswc-v3-quote footer {
	margin-top: 24px;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--v3-body);
}

.mswc-v3-dark .mswc-v3-quote footer {
	color: var(--v3-on-dark);
}

.mswc-v3-quote cite {
	display: block;
	font-style: normal;
	font-weight: 600;
	color: inherit;
}

.mswc-v3-quote-meta {
	display: block;
	margin-top: 2px;
	font-size: 0.8125rem;
	opacity: 0.8;
}

/* The borrowed statistic on What We Do, and the statement on Testimonials.
 * Both are one sentence alone on a dark band, so both are centred and neither
 * needs the 46rem prose measure. */
.mswc-v3-quoteband .mswc-v3-quote,
.mswc-v3-statement .mswc-v3-h2 {
	max-width: 30ch;
	margin-inline: auto;
	text-align: center;
}

.mswc-v3-statement .mswc-v3-h2 {
	max-width: 24ch;
}

/* --------------------------------------------------------- testimony pairs */

/*
 * A quote and a photograph, side by side, alternating which side each is on.
 * Production stacked the two quotes and the two photographs with no relation
 * between them; pairing a face with a voice is the entire point of the page.
 */
.mswc-v3-testimony {
	display: grid;
	grid-template-columns: 1.1fr 0.9fr;
	align-items: center;
	gap: 48px;
	margin-top: 56px;
}

.mswc-v3-testimony--flip > :first-child {
	order: 2;
}

.mswc-v3-testimony .mswc-v3-card img {
	width: 100%;
	height: 100%;
	max-height: 420px;
	object-fit: cover;
	border-radius: 3px;
	display: block;
}

/* ------------------------------------------------------------- video wall */

/*
 * TEN videos, so the column count has to divide ten: two or five. Five puts a
 * 16:9 player at 224px wide, which is a thumbnail of a person speaking rather
 * than a video anybody would watch. Two gives 584px at the 1200px measure and
 * five clean rows. A 300px minimum gave three columns and left the tenth
 * testimonial standing alone at the bottom of the wall.
 */
.mswc-v3-videos {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(420px, 100%), 1fr));
	gap: 44px 32px;
	margin-top: 48px;
}

.mswc-v3-video {
	margin: 0;
}

/*
 * ⚠️ THE RATIO IS ON THE WRAPPER, NOT THE IFRAME, and the iframe is absolutely
 * positioned inside it. A YouTube iframe with `aspect-ratio` and no explicit
 * height still reports its attribute height during layout in some engines,
 * which is what put a black strip under every player in the first draft.
 */
.mswc-v3-video-frame {
	position: relative;
	aspect-ratio: 16 / 9;
	background: #000;
	border-radius: 3px;
	overflow: hidden;
}

.mswc-v3-video-frame iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

.mswc-v3-video figcaption {
	margin-top: 14px;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--v3-on-dark);
	text-wrap: pretty;
}

/* ------------------------------------------------------ What We Do closing */

.mswc-v3-wwdart {
	margin: 64px 0 0;
}

.mswc-v3-wwdart img {
	display: block;
	width: 100%;
	height: clamp(220px, 26vw, 380px);
	object-fit: cover;
	border-radius: 3px;
}

.mswc-v3-wwdart figcaption {
	margin-top: 12px;
	font-size: 0.8125rem;
	line-height: 1.6;
	color: #6b6b6b;
}

/* ------------------------------------------------------------- the forms */

/*
 * Guy's number one priority at the 24 July lunch was the contact flow, and the
 * reason is on the record: five genuine enquiries, one of them a speaking
 * invitation, sat unread under years of form spam. The filtering is Cloudflare
 * Turnstile, built 2026-08-01 and living inside the Ninja Forms block. None of
 * it is styled here — what is styled is everything around it, so the form looks
 * like it belongs to the site rather than to the plugin.
 *
 * ⚠️ EVERY FONT SIZE ON A CONTROL IS `max(16px, ...)`. Under 16px, iOS Safari
 * zooms the page on focus and does not zoom back out, which strands a phone
 * visitor mid-form at 1.3x with no way back. That rule was learned on the
 * Mailchimp embed during the mobile pass and applies to every input on the site.
 */
.mswc-v3-formband .nf-form-cont,
.mswc-v3-formband .nf-form-wrap {
	max-width: 46rem;
	margin-top: 32px;
}

.mswc-v3-formband .nf-field-label label,
.mswc-v3-formband .nf-field-label .nf-label-span {
	font-size: 0.875rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--v3-body);
	margin-bottom: 8px;
}

.mswc-v3-formband input[type="text"],
.mswc-v3-formband input[type="email"],
.mswc-v3-formband input[type="tel"],
.mswc-v3-formband textarea {
	width: 100%;
	font-family: inherit;
	font-size: max(16px, 1rem);
	line-height: 1.5;
	color: #1f1f1f;
	background: #fff;
	border: 1px solid rgba(20, 24, 26, 0.22);
	border-radius: 3px;
	padding: 12px 14px;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.mswc-v3-formband input:focus,
.mswc-v3-formband textarea:focus {
	outline: none;
	border-color: var(--v3-accent);
	box-shadow: 0 0 0 3px rgba(1, 122, 183, 0.16);
}

.mswc-v3-formband textarea {
	min-height: 170px;
	resize: vertical;
}

/*
 * The submit button, matched to .mswc-v3-btn rather than sharing its class:
 * the plugin owns that element and adding a class to it means filtering the
 * markup, which the Ninja Forms block does not offer.
 */
.mswc-v3-formband input[type="button"],
.mswc-v3-formband input[type="submit"],
.mswc-v3-formband .nf-form-content button {
	appearance: none;
	-webkit-appearance: none;
	display: inline-flex;
	align-items: center;
	font-family: inherit;
	font-size: max(16px, 1rem);
	line-height: 1.6;
	font-weight: 400;
	color: #1d1d22;
	background: var(--v3-lime);
	border: 0;
	border-radius: 9999px;
	padding: 14px 32px;
	cursor: pointer;
	transition: background 0.2s ease;
}

.mswc-v3-formband input[type="button"]:hover,
.mswc-v3-formband input[type="submit"]:hover,
.mswc-v3-formband .nf-form-content button:hover {
	background: #b9d64e;
}

.mswc-v3-contactmail {
	margin-top: 32px;
	padding-top: 24px;
	border-top: 1px solid rgba(20, 24, 26, 0.09);
}

.mswc-v3-contactmail a {
	color: var(--v3-accent);
}

/*
 * The Mailchimp embed. Its own markup carries an inline
 * `#mc_embed_signup{background:#fff; font:14px Helvetica,...}` block, which is
 * why these rules are as specific as they are: an ID selector is what it takes,
 * and the shorthand `font` it sets resets family, size and line-height together.
 *
 * The embed is copied through BYTE FOR BYTE by gen_contact_v4.py, honeypot and
 * all. A signup form that has been tidied is a signup form that has been broken.
 * So it is styled from here and never edited there.
 *
 * ⚠️ SCOPED ON THE ID, NOT ON A BAND, AND THAT IS THE FIX FOR A REAL REGRESSION.
 * These rules used to be scoped to `.mswc-v3-signupband`. 0.17.0 merged the
 * signup into the contact form's own band so the page stopped being two forms
 * stacked with nothing else on it, the signup band ceased to exist, and every
 * rule below silently stopped matching: the Subscribe button reverted to
 * Mailchimp's own grey #aaa 4px-radius default, sitting directly beside our lime
 * pill Submit. Nothing failed. The selector simply matched nothing, which is the
 * quietest way for CSS to break. `#mc_embed_signup` is unique to this one embed
 * on this one page, so the band is not needed to disambiguate it.
 *
 * ⚠️ AND THE CONTROLS NEED THE ELEMENT AND THE ID, not just the wrapper id.
 * The embed also pulls Mailchimp's OWN stylesheet,
 * `cdn-images.mailchimp.com/embedcode/slim-10_7.css`, whose `#mc_embed_signup
 * .button` is (1,1,0) — exactly the specificity a wrapper-id rule of ours has.
 * That link sits in the page content, so it loads AFTER the theme stylesheet and
 * an equal-specificity tie goes to whoever comes last, which is Mailchimp. The
 * button stayed grey through a deploy that reported OK. Matching the input's own
 * id takes it to (2,0,1) and settles it without an `!important`, which this
 * theme spends only on inline styles emitted by a block's own attributes.
 */
#mc_embed_signup {
	background: transparent;
	font: inherit;
	max-width: 34rem;
	margin-top: 24px;
}

#mc_embed_signup label {
	display: block;
	font-size: 1.1875rem;
	line-height: 1.4;
	font-weight: 600;
	color: #1f1f1f;
	margin-bottom: 14px;
}

#mc_embed_signup input#mce-EMAIL.email {
	/*
	 * ⚠️ BORDER-BOX, AND IT IS THE WHOLE OF A HORIZONTAL-OVERFLOW BUG.
	 * Mailchimp's stylesheet leaves this input `content-box`, so `width: 100%`
	 * resolved to the 331.7px content box and then ADDED 14px of padding each
	 * side and a border: 362px of input in a 342px column, starting 10px in
	 * from the form's own 3% left padding. Contact scrolled sideways at 390 by
	 * exactly 6px. Same family as every other box on this project sized
	 * independently of its content.
	 */
	box-sizing: border-box;
	width: 100%;
	font-family: inherit;
	font-size: max(16px, 1rem);
	line-height: 1.5;
	color: #1f1f1f;
	background: #fff;
	border: 1px solid rgba(20, 24, 26, 0.22);
	border-radius: 3px;
	padding: 12px 14px;
	margin: 0 0 14px;
}

#mc_embed_signup input#mce-EMAIL.email:focus {
	outline: none;
	border-color: var(--v3-olive);
	box-shadow: 0 0 0 3px rgba(107, 107, 58, 0.16);
}

#mc_embed_signup input#mc-embedded-subscribe.button {
	box-sizing: border-box;
	appearance: none;
	-webkit-appearance: none;
	font-family: inherit;
	font-size: max(16px, 1rem);
	line-height: 1.6;
	color: #1d1d22;
	background: var(--v3-lime);
	border: 0;
	border-radius: 9999px;
	padding: 13px 30px;
	height: auto;
	cursor: pointer;
	transition: background 0.2s ease;
}

#mc_embed_signup input#mc-embedded-subscribe.button:hover {
	background: #b9d64e;
}

/* ------------------------------------------------- the stats pipeline line */

/*
 * "A further 167 are in training in LAMP courses now." (Guy, 2026-09-04.)
 *
 * ⚠️ IT IS NOT A FOURTH STATISTIC AND MUST NOT BECOME ONE. 167 people are
 * part-way through a course; set at 104px beside three completed-outcome
 * figures it would read as 167 more graduates, on a band a funder screenshots.
 */
.mswc-v3-stats-note {
	max-width: 46rem;
	margin: 28px 0 0;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.72);
}

/* -------------------------------------------------- inner pages, responsive */

@media (max-width: 1023px) {
	.mswc-v3-testimony {
		grid-template-columns: 1fr;
		gap: 32px;
	}

	/* The flip is a two-column device. Stacked, it would put the photograph
	 * above the words it illustrates in one pair and below them in the other. */
	.mswc-v3-testimony--flip > :first-child {
		order: 0;
	}
}

@media (max-width: 781px) {
	.mswc-v3-people {
		grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
		gap: 32px 20px;
	}

	.mswc-v3-portrait {
		width: min(120px, 100%);
	}

	.mswc-v3-steps,
	.mswc-v3-sessions,
	.mswc-v3-videos {
		grid-template-columns: 1fr;
		gap: 36px;
	}

	.mswc-v3-logos {
		gap: 28px 36px;
	}

	.mswc-v3-partner-cta {
		margin-top: 40px;
		padding-top: 28px;
	}

	.mswc-v3-wwdart {
		margin-top: 44px;
	}
}

/* ==========================================================================
 * THE INNER PAGES — 0.17.0
 *
 * Added because the four inner pages had the homepage's TOKENS and none of its
 * IDENTITY. Type, colour and buttons matched; the things that actually make the
 * homepage look like itself did not travel: a photograph at full bleed, a
 * change of ground partway down, a number set large enough to be read across a
 * room, and a second column that is not empty.
 *
 * Nothing below is a new design language. Every rule here either extends a
 * homepage component with a modifier or arranges homepage components into a
 * layout the homepage did not happen to need. That is deliberate: two design
 * systems on one site is how the seam Guy would have clicked into got there in
 * the first place.
 * ====================================================================== */

/* --------------------------------------- the last band before the footer */

/*
 * ⚠️ THE FOOTER OVERLAPS WHATEVER IS ABOVE IT BY UP TO 116px, ON PURPOSE, and
 * on an inner page that ate the call to action.
 *
 * `.mswc-v3-sitefoot` carries `margin-block-start: calc(-1 * clamp(3rem, 8vw,
 * 9rem))` so the landscape's alpha ramp begins INSIDE the band above it rather
 * than below it. On the homepage the band it climbs into is the donation band,
 * which is light and has room, so the overlap is invisible and correct.
 *
 * The inner pages end on an ink band whose last element is a button, and the
 * footer simply covered it: the About page's "Get in touch" pill photographed
 * sliced in half by the top edge of the landscape. Nothing measured it, because
 * the element is still there at its right size with its right colours and the
 * document is still exactly as tall as the sum of its parts. It is a painting
 * order problem and only a picture shows it.
 *
 * So the last band on a page reserves the pull as extra bottom padding. The
 * homepage is untouched by construction: its last child is `.mswc-v3-closing`,
 * not a `.mswc-v3-band`, which is why this is keyed on the band.
 */
.wp-block-post-content > .mswc-v3-band:last-child {
	padding-bottom: calc(var(--v3-band-pad) + clamp(3rem, 8vw, 9rem));
}

/* ------------------------------------------------- the inner-page hero */

/*
 * `.mswc-v3-hero--page` is the homepage hero, shorter. It inherits the scrim,
 * the Ken Burns pan and its reduced-motion opt-out, the cover fit and the lime
 * eyebrow, so none of that can drift out of sync with the homepage.
 *
 * The height is the one real difference. The homepage hero is a full viewport
 * because it has to make an argument before anyone scrolls. An inner page has
 * been chosen already, so it takes a little over half: enough for the picture
 * to be a photograph rather than a strip, short enough that the first body
 * paragraph is on screen at 900px.
 */
.mswc-v3-hero--page {
	min-height: clamp(420px, 62svh, 620px);
}

/* The pan is for the homepage, where the hero holds still under a film for
 * twenty seconds at a time. On a page you scroll straight past it is motion
 * for its own sake. */
.mswc-v3-hero--page .mswc-v3-hero-media img {
	animation: none;
}

.mswc-v3-hero--page .mswc-v3-hero-content {
	padding-bottom: clamp(2.5rem, 6vh, 4rem);
	/*
	 * ⚠️ THE TOP PADDING IS FOR PHONES, where it is the whole fix. The content
	 * is bottom-anchored, so on desktop this padding is invisible slack. On a
	 * phone the deck wraps to seven lines, the buttons stack, and the content
	 * OUTGROWS the hero's min-height — the flex box stretches to fit and the
	 * H1 ends up touching the topbar (Alex: "too close to the top"). When the
	 * content drives the height, this is the air above the title.
	 */
	padding-top: clamp(4rem, 12vw, 6rem);
}

/*
 * A HEAVIER SCRIM THAN THE HOMEPAGE'S, and the reason is that the homepage is
 * paying for its lighter one. There, the scrim sits over a film that has to
 * remain watchable, so it is held to the minimum that gets the H1 over a bright
 * sky. Nothing plays under an inner-page hero, so the picture costs nothing to
 * darken and the type gets a ground it can rely on whatever photograph is
 * chosen later.
 *
 * Measured: the About hero's lime eyebrow ran 4.00 at the tenth percentile
 * against the 4.5 small text needs, over the bright beadwork in that frame.
 * With this it clears. Re-measure with `tools/glyph-shoot.mjs` +
 * `tools/glyph-contrast.py` after changing any hero photograph — a scrim tuned
 * to one picture is not tuned to the next one.
 */
.mswc-v3-hero--page::after {
	/*
	 * ⚠️ CONTRAST IS NOT LEGIBILITY, and this is the second time that has cost
	 * something on this project. The glyph sweep passed every hero at 1456 and
	 * 390 with zero failures, and Alex read the pages and said the text was hard
	 * to read. Both are true. WCAG contrast compares the type's luminance
	 * against the worst ground pixel; it says nothing about how BUSY that ground
	 * is, and white type over Samburu beadwork or a pinstriped shirt is fighting
	 * high-frequency detail, not low contrast.
	 *
	 * The old scrim was a 105deg wash that reached 0.45 by 48% of the width —
	 * and the deck's last lines end at about 47%, exactly where it had given up.
	 * It was tuned to be subtle against the picture rather than to serve the
	 * copy sitting on it.
	 *
	 * This one is horizontal, so its strength does not drift with height, and it
	 * holds above 0.7 across the whole measure before releasing the right half
	 * of the frame where the photograph's subject actually is. It is deliberately
	 * generous, because the hero photographs are not final — Guy has an open
	 * question about the opening image — and a scrim tuned to one picture is not
	 * tuned to the next one.
	 */
	background:
		linear-gradient(to right,
			rgba(10, 14, 15, 0.88) 0%,
			rgba(10, 14, 15, 0.84) 32%,
			rgba(10, 14, 15, 0.70) 48%,
			rgba(10, 14, 15, 0.34) 66%,
			rgba(10, 14, 15, 0.08) 84%,
			rgba(10, 14, 15, 0) 94%),
		linear-gradient(to top, rgba(10, 14, 15, 0.92) 0%, rgba(10, 14, 15, 0.62) 38%, rgba(10, 14, 15, 0.22) 68%, rgba(10, 14, 15, 0.28) 100%);
}

/*
 * And the type carries a little of its own ground. A wide, soft shadow at low
 * opacity reads as no shadow at all — there is no visible halo at this radius —
 * but it separates a stem from a bead or a pinstripe directly behind it, which
 * is the actual failure mode here. It also means the scrim does not have to be
 * pushed dark enough to flatten the photograph to do the whole job alone.
 *
 * ⚠️ Page heroes only. The homepage hero is Guy's approved design and its type
 * sits over a film; nothing here touches it.
 */
.mswc-v3-hero--page h1,
.mswc-v3-hero--page .mswc-v3-deck {
	text-shadow: 0 1px 18px rgba(10, 14, 15, 0.55);
}

/* An inner-page title is one or two words, so the homepage's 24ch balance
 * measure does nothing for it and its 4rem ceiling leaves it looking timid
 * against a full-bleed photograph. */
.mswc-v3-hero--page h1 {
	max-width: 18ch;
	font-size: clamp(2.75rem, 5.4vw, 4.5rem);
}

.mswc-v3-hero--page .mswc-v3-deck {
	max-width: 40ch;
}

/*
 * WHEN AN INK BAND FOLLOWS THE HERO DIRECTLY, THE HERO ENDS ON THAT INK.
 * Testimonials is the page: photograph, then the statement band, and the
 * bottom scrim only reaches 0.92 alpha — and in a different dark (10,14,15)
 * than the band's #14181a — so the photograph ended on a visible line. Alex
 * asked for the hero→statement transition to be smooth. The extra first layer
 * takes the last sixth of the hero to exactly the band's ink, so the picture
 * sinks into the band instead of stopping at it.
 *
 * :has(), same fallback contract as the join overrides below: a browser
 * without it shows today's subtle line, never a new artifact. Pages whose
 * hero is followed by a light band match nothing and keep the standard scrim.
 */
.mswc-v3-hero--page:has(+ .mswc-v3-band.mswc-v3-dark)::after {
	background:
		linear-gradient(to top,
			#14181a 0%,
			rgba(20, 24, 26, 0.65) 14%,
			rgba(20, 24, 26, 0) 42%),
		linear-gradient(to right,
			rgba(10, 14, 15, 0.88) 0%,
			rgba(10, 14, 15, 0.84) 32%,
			rgba(10, 14, 15, 0.70) 48%,
			rgba(10, 14, 15, 0.34) 66%,
			rgba(10, 14, 15, 0.08) 84%,
			rgba(10, 14, 15, 0) 94%),
		linear-gradient(to top, rgba(10, 14, 15, 0.92) 0%, rgba(10, 14, 15, 0.62) 38%, rgba(10, 14, 15, 0.22) 68%, rgba(10, 14, 15, 0.28) 100%);
}

/* --------------------------------------------- the statement band */

/*
 * One sentence of Guy's, alone on ink, at display size. This is the beat that
 * every inner page was missing: the homepage changes GROUND four times and the
 * inner pages never changed it once, which is most of why they read as
 * documents and the homepage reads as a site.
 */
.mswc-v3-statement-line {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.75rem, 3vw, 2.75rem);
	line-height: 1.2;
	letter-spacing: -0.01em;
	font-weight: 700;
	color: #ffffff;
	max-width: 22ch;
	margin: 0;
	text-wrap: balance;
}

/*
 * A display measure is a function of how long the sentence is, and these
 * sentences are Guy's rather than a designer's, so their length is not
 * negotiable. At 22ch the About page's closing sentence set to NINE lines of
 * 44px small caps, which is not a statement, it is a wall. The generator adds
 * this class past roughly 120 characters: wider measure, smaller type, so a
 * long sentence lands at four or five lines like a short one does.
 */
.mswc-v3-statement-line--long {
	font-size: clamp(1.5rem, 2.2vw, 2rem);
	max-width: 34ch;
	line-height: 1.25;
}

.mswc-v3-statementband {
	/* Tighter than a content band: it holds one sentence, and the standard
	 * 7.5rem of padding around a single line reads as a mistake. */
	padding-block: clamp(3.5rem, 7vw, 6rem);
}

.mswc-v3-statementband .mswc-v3-source {
	margin-top: 24px;
}

/* ----------------------------------------------------- the split band */

/*
 * The measure, and something beside it. Every one of the four pages had at
 * least one band that was a 46rem column of prose inside a 1200px wrap with
 * nothing at all in the other 30%.
 */
.mswc-v3-split {
	display: grid;
	grid-template-columns: 1.15fr 0.85fr;
	gap: clamp(40px, 5.5vw, 80px);
	align-items: start;
	margin-top: 40px;
}

.mswc-v3-split--flip > .mswc-v3-split-main {
	order: 2;
}

/* Inside a split the prose column IS the measure, so the 46rem cap would
 * leave a second empty gutter inside the first one. */
.mswc-v3-split-main .mswc-v3-prose {
	max-width: none;
}

.mswc-v3-split-aside {
	display: grid;
	gap: 28px;
	/* Optically aligns the top of a photograph with the x-height of the
	 * paragraph beside it rather than with its ascender line. */
	padding-top: 6px;
}

.mswc-v3-split-aside .mswc-v3-card img {
	width: 100%;
	height: auto;
	display: block;
}

/* --------------------------------------------- board and advisory bands */

/*
 * The portraits carried production's radius but nothing else, so thirteen
 * people sat as flat grey discs on flat white. A ring in the band's own ground
 * plus a hairline gives them an edge without inventing a border colour that is
 * not in the palette.
 */
.mswc-v3-boardband .mswc-v3-portrait {
	box-shadow: 0 0 0 1px rgba(31, 31, 31, 0.1);
}

.mswc-v3-boardband .mswc-v3-people {
	margin-top: 56px;
}

/* --------------------------------------------------- the closing band */

/*
 * The homepage ends on artwork: the blog band's plate, then the landscape the
 * footer paints. The inner pages ended on a paragraph and a button against
 * nothing. This gives each of them the same closing shape.
 */
/*
 * ⚠️ NO ARTWORK IN THIS BAND, AND THAT IS THE DECISION, NOT AN OMISSION.
 * It shipped with the homepage's blog plate masked in from the right at 0.3
 * over ink, and photographed as nothing at all: a light beige illustration at
 * 30% over #14181a is #14181a. Raising the opacity far enough to see it puts a
 * picture directly above the footer's own full-bleed landscape, which is two
 * illustrated bands stacked with 40px between them. The band is plain ink, the
 * footer carries the artwork, and the page ends on the contrast between them.
 */

/* --------------------------------------------------- contact page */

/*
 * The contact form was a column of inputs floating in white with two thirds of
 * the band empty beside it. The form keeps the measure; what goes next to it is
 * the address and the answer to "who reads this", which is the one thing a
 * contact page is actually asked.
 */
.mswc-v3-contactgrid {
	display: grid;
	grid-template-columns: 1.1fr 0.9fr;
	gap: clamp(40px, 6vw, 88px);
	align-items: start;
	margin-top: 40px;
}

.mswc-v3-contactaside .mswc-v3-h3 {
	margin-top: 0;
}

.mswc-v3-contactaside .mswc-v3-prose {
	max-width: none;
}

.mswc-v3-contactaside-item + .mswc-v3-contactaside-item {
	margin-top: 32px;
	padding-top: 32px;
	border-top: 1px solid rgba(31, 31, 31, 0.12);
}

/* --------------------------------------------------- testimonial quotes */

/*
 * A pull quote on this site is Alegreya Sans SC, a SMALL-CAPS display face. It
 * is right for "1 in every 12 jobs in Kenya is linked to wildlife" and wrong for
 * Abdikadir Bagajo's five-line testimonial, which shipped set entirely in small
 * caps and could not be read at speed.
 *
 * ⚠️ SCOPED TO `--long` ON PURPOSE. The first version of this rule was on
 * `.mswc-v3-quote` and it also caught What We Do's one-line pull quote, which
 * went from a statement on ink to a caption. The generator adds the class past
 * roughly 120 characters; short quotes keep the display face and the scale.
 */
.mswc-v3-quote--long p {
	font-family: var(--wp--preset--font-family--body);
	font-size: clamp(1.125rem, 1.6vw, 1.375rem);
	line-height: 1.6;
	letter-spacing: 0;
	font-weight: 400;
	text-transform: none;
}

/* ------------------------------------------------------------- mobile */

@media (max-width: 900px) {
	.mswc-v3-split,
	.mswc-v3-contactgrid {
		grid-template-columns: 1fr;
		gap: 40px;
	}

	/* `order` on the main column would leave the picture above the prose on a
	 * phone, which puts an illustration before the sentence it illustrates. */
	.mswc-v3-split--flip > .mswc-v3-split-main {
		order: 0;
	}
}

@media (max-width: 781px) {
	.mswc-v3-hero--page {
		min-height: clamp(340px, 46svh, 460px);
	}

	.mswc-v3-hero--page h1 {
		font-size: clamp(2.125rem, 9vw, 2.75rem);
	}

	.mswc-v3-statement-line {
		max-width: none;
	}

}

/* ==========================================================================
 * THE INNER PAGES, SECOND PASS — 0.18.0
 *
 * An audit against the published catalogues of machine-made-design tells
 * (identical cards in uniform grids, numbered badge chips, all-caps labels on
 * every section, one generic fade-in on every element, metronomic section
 * padding) plus the craft side those lists imply: hierarchy, asymmetry, rhythm,
 * and typographic detail.
 *
 * ⚠️ EVERY RULE HERE THAT TOUCHES A COMPONENT THE HOMEPAGE ALSO USES IS SCOPED
 * `body:not(.home)`. Alex's instruction was to improve the four inner pages and
 * leave the homepage alone; the homepage is the page Guy approved on 4 September
 * and it is not in scope. `.mswc-v3-steps`, `.mswc-v3-sessions`,
 * `.mswc-v3-people` and `.mswc-v3-quote` appear on inner pages ONLY (checked, in
 * the built markup, not assumed), so those needed no scope. `.mswc-eyebrow` and
 * `.mswc-v3-reveal` are shared, so they do.
 * ====================================================================== */

/* ------------------------------------------------- motion, made purposeful */

/*
 * "The same generic fade-in on every element" is on every list of tells, and it
 * was literally true here: the generators put `.mswc-v3-reveal` on eyebrows,
 * headings, every paragraph, every button row, every portrait and every logo —
 * 22 of them on About, 24 on What We Do. Twenty-four things sliding up 26px in
 * sequence is not motion design, it is a page that cannot sit still.
 *
 * Headings and pictures still arrive, because that is the part a reader
 * notices. Body copy, labels, controls, portraits and logos are simply present.
 * Nothing is removed from the markup: `will-reveal` is JS's flag and this
 * cancels its effect, so with JS off the behaviour is identical to what it
 * already was.
 */
body:not(.home) .mswc-v3-prose.mswc-v3-reveal.will-reveal,
body:not(.home) .mswc-eyebrow.mswc-v3-reveal.will-reveal,
body:not(.home) .mswc-v3-actions.mswc-v3-reveal.will-reveal,
body:not(.home) .mswc-v3-person.mswc-v3-reveal.will-reveal,
body:not(.home) .mswc-v3-logos.mswc-v3-reveal.will-reveal,
body:not(.home) .mswc-v3-step.mswc-v3-reveal.will-reveal,
body:not(.home) .mswc-v3-session.mswc-v3-reveal.will-reveal {
	opacity: 1;
	transform: none;
	transition: none;
}

/* ------------------------------------------------------ typographic detail */

/*
 * `pretty` costs nothing and stops a paragraph ending on a single word. The
 * homepage is excluded because its line breaking was reviewed and signed off as
 * it stands, and this changes where lines break.
 */
body:not(.home) .mswc-v3-prose {
	text-wrap: pretty;
}

/*
 * HANGING PUNCTUATION. Abdikadir Bagajo's testimonial opens on a left double
 * quote, and set flush the quote mark pushes the first line visibly right of
 * every line under it — the ragged left edge that separates typeset text from
 * text that was merely placed. `hanging-punctuation` is still Safari-only, so
 * this is the manual version: outdent by the quote's own width and put it back
 * for anything that does not start with one.
 */
.mswc-v3-quote--long p {
	text-indent: -0.42em;
}

/* --------------------------------------------------------- band cadence */

/*
 * Every band carried the identical `--v3-band-pad`, so the page kept perfect
 * time and read like a metronome: announce, content, announce, content. A band
 * that CONTINUES the one above it should not restate itself at full volume.
 * The Advisory Board is the second half of the governance section, not a new
 * argument, so it comes in quieter and lets the change of ground do the work.
 */
.mswc-v3-band--quiet {
	padding-block: clamp(3rem, 5.5vw, 4.5rem);
}

/* ------------------------------------------------------------ the board */

/*
 * ⚠️ THE PORTRAIT SIZE FOLLOWS THE COLUMN COUNT, and getting that backwards is
 * why this needed a second look. Reducing them to 136px was right while the
 * grid was five columns of 240px cells. At three columns the cells are 400px
 * wide, and a 136px circle centred in a 400px cell is a small thing floating in
 * a large empty box. Fewer columns means bigger cells means bigger portraits.
 *
 * The four advisory members stay at four columns and 136px, where the cell is
 * 280px and that is the right relationship.
 */
.mswc-v3-boardband .mswc-v3-people:not(.mswc-v3-people--4) .mswc-v3-portrait {
	width: min(182px, 100%);
}

.mswc-v3-boardband .mswc-v3-people--4 .mswc-v3-portrait {
	width: min(136px, 100%);
}

.mswc-v3-person-role {
	color: rgba(63, 63, 80, 0.78);
}

/* ------------------------------------------------------------- contact */

/*
 * The aside opened on a rule with nothing above it, which reads as the bottom
 * edge of something missing rather than the top edge of something present.
 */
.mswc-v3-contactaside .mswc-v3-contactmail {
	border-top: 0;
	padding-top: 0;
	margin-top: 0;
}

/* -------------------------------------------------------------- mobile */

@media (max-width: 900px) {
	.mswc-v3-steps {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 781px) {
	.mswc-v3-people {
		--v3-people-cols: 2;
	}

	.mswc-v3-people--4 {
		--v3-people-cols: 2;
	}

	.mswc-v3-step {
		padding-left: 58px;
	}

	.mswc-v3-step::before,
	.mswc-v3-session::before {
		font-size: 1.375rem;
	}

	.mswc-v3-session {
		padding-left: 58px;
	}
}

/* --------------------------------------------------------- the site credit */

/*
 * A designer credit beside the copyright. Quieter than the copyright itself,
 * because the organisation's name is the one that matters on its own site and
 * this line should be findable rather than noticeable.
 *
 * ⚠️ THIS IS THE FIRST CHANGE THAT DELIBERATELY REACHES THE HOMEPAGE. The
 * footer is one template part on every page, so the "homepage unchanged, 0
 * changed pixels" guarantee that held through 0.17.0 to 0.18.3 ends here, by
 * request rather than by accident.
 *
 * ⚠️ AND IT IS NOT AGREED YET. Guy raised putting Alex on the site and has not
 * seen this. It is on staging so he can look at it; it is one line in
 * parts/footer.html and one rule here, so removing it is trivial if he would
 * rather it were not there. Do not treat its presence on staging as his
 * approval of it.
 */
.mswc-v3-credit {
	white-space: nowrap;
}

/*
 * ⚠️ 48rem, NOT the root 42rem, and it is the credit that needs it.
 *
 * `.mswc-v3-copyright` is a constrained group, so core caps this paragraph at
 * the root contentSize of 672px. The line needs 688px — measured with a Range
 * over the paragraph's own contents, because the <p> is a block and its
 * bounding rect is the container's width, not the text's.
 *
 * It fitted at 0.19.0 and stopped fitting when Alex asked for "Site by" ->
 * "Website by" on 2026-09-08: four characters, 24px, 16px over the measure, and
 * because `.mswc-v3-credit` is `nowrap` the whole credit dropped to a second
 * line rather than breaking. A 42rem measure is for reading paragraphs; this is
 * one centred sentence of 13px type and has no use for it.
 */
.mswc-v3-copyright p {
	max-width: 48rem;
}

.mswc-v3-credit-sep {
	margin-inline: 0.5em;
	opacity: 0.45;
}

.mswc-v3-copyright a {
	color: inherit;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
	text-decoration-color: rgba(31, 31, 31, 0.35);
	transition: text-decoration-color 0.2s ease;
}

.mswc-v3-copyright a:hover {
	text-decoration-color: currentColor;
}

@media (max-width: 640px) {
	/*
	 * The whole line is one sentence of x-small type. At 390 the credit and the
	 * copyright together overrun, so the credit drops to its own line and the
	 * middot goes with it rather than dangling at the end of the first.
	 */
	.mswc-v3-credit {
		display: block;
		white-space: normal;
		margin-top: 0.35em;
	}

	.mswc-v3-credit-sep {
		display: none;
	}
}

/* ======================================================================
 * 0.20.0 — THE BLOG, AND THE OVERLAP THAT ATE THE END OF EVERY FLOW PAGE
 * ====================================================================== */

/*
 * ⚠️ THE SAME FOOTER OVERLAP AS THE INNER PAGES, ON A DIFFERENT SET OF PAGES.
 *
 * `.mswc-v3-sitefoot` climbs up to 116px into whatever precedes it (see "the
 * last band before the footer" above), and the fix written for the four v4
 * pages was keyed on `.mswc-v3-band:last-child` — a band. The bio pages, the
 * blog index, single posts, search and 404 do not end in a band, so they never
 * got it, and the landscape painted straight over their last paragraph.
 *
 * Alex found it on Guy's own bio page: the third paragraph was cut off
 * mid-sentence and the "← Back to the Board" link was gone entirely. Measured:
 * main ended at y=792 and the footer part started at y=689. Nothing about the
 * document was wrong — every element was present at its right size — so only a
 * picture could show it. That is now twice this exact class of bug has shipped;
 * both times the reservation was attached to a specific component instead of to
 * the page.
 *
 * So this one is keyed on the MAIN element, by an explicit class the flow
 * templates carry. The homepage and the four v4 pages are untouched by
 * construction: they do not carry `.mswc-v3-flowmain`, and their deliberate
 * overlap (the artwork's alpha ramp beginning inside the band above it) is what
 * makes the footer join the page instead of sitting under it.
 *
 * The extra term past the pull is air, not safety margin: reserving exactly the
 * pull puts the last line of text on the artwork's top edge, where the alpha is
 * zero and it is technically legible and visibly cramped.
 */
main.mswc-v3-flowmain {
	padding-bottom: calc(clamp(3rem, 8vw, 9rem) + clamp(1.5rem, 3vw, 3rem));
}

/*
 * ⚠️ AND NOT BOTH AT ONCE. The blog index and the category archive DO end in a
 * band, so they take the band-keyed reservation above and must not also carry
 * `.mswc-v3-flowmain` — the first draft did both and left 335px of white
 * between the last article and the landscape. One reservation per page: the
 * band if there is one, the main element if there is not.
 */
main.mswc-v3-blogmain > .mswc-v3-band:last-child {
	padding-bottom: calc(var(--v3-band-pad) + clamp(3rem, 8vw, 9rem));
}

/* ------------------------------------------------------ the blog hero art */

/*
 * The photograph is a THEME ASSET, not a media-library upload, for the reason
 * the footer landscape is (see `--v3-foot-art`): a template is static HTML with
 * no way to write an uploads URL that is correct on both staging and
 * production, and every hard-coded `/staging/1452/` is one more thing to
 * remember at cutover. A CSS `url()` resolves against the stylesheet, which
 * travels inside the theme, so this is right on both sites and on any future
 * one.
 *
 * It is a background rather than an `<img>` because of the same constraint, and
 * the alternative text moves to `role="img"` + `aria-label` on the div — the
 * pattern `.mswc-v3-footwordmark` already uses here.
 *
 * Position 58% 50%: the two figures and the certificate sit centre-right, and
 * `.mswc-v3-hero--page`'s scrim is heaviest across the left 32%. Centring the
 * crop put the handshake under the darkest part of the wash.
 */
.mswc-v3-hero-art {
	background-image: url(../img/mswc-blog-hero.webp);
	background-size: cover;
	background-position: 58% 50%;
	background-repeat: no-repeat;
}

/* --------------------------------------------------------- the blog index */

/*
 * ⚠️ NOT CARDS. The index that was here was nine identical centred blocks —
 * a repeated all-caps category label, a centred blue 36px title, a centred
 * excerpt — which is the "identical cards in a uniform grid" tell wearing a
 * column instead of a grid, and it is also a claim the site should not make:
 * these nine are not nine equal articles. The most recent one is what a visitor
 * arriving from the homepage came to read.
 *
 * So it is set as an editorial index, in the idiom `.mswc-v3-steps` already
 * established on What We Do: rules that run ACROSS the row rather than boxing
 * each item, a lead entry at a different scale, and two columns so the title
 * and the standfirst are separate objects instead of a stack of centred text.
 * Nothing here is a new component; it is the band, the wrap and the display
 * face the rest of the site is built from.
 */
.mswc-v3-blogmain > .mswc-v3-hero,
.mswc-v3-blogmain > .mswc-v3-band,
.mswc-v3-single > .mswc-v3-band {
	/*
	 * The root 2.25rem blockGap spaces the children of a constrained group, and
	 * these bands butt against each other on purpose. (0,2,1) beats core's
	 * `.wp-container-x > * + *` at (0,1,0).
	 */
	margin-block: 0;
}

.mswc-v3-blogindex .wp-block-query {
	margin: 0;
}

.mswc-v3-postlist {
	list-style: none;
	margin: 0;
	padding: 0;
}

.mswc-v3-postlist > li {
	margin: 0;
}

.mswc-v3-postrow {
	display: grid;
	/*
	 * 1fr / 1.05fr rather than equal halves: the right column carries a 46ch
	 * paragraph and the left carries a title that wraps to two or three lines,
	 * so equal columns left the titles short and the excerpts tight.
	 */
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
	gap: 0 clamp(40px, 5vw, 88px);
	align-items: start;
	border-top: 1px solid rgba(20, 24, 26, 0.16);
	padding: 34px 0 42px;
}

/*
 * THE LEAD ARTICLE. One column, at the band's own heading scale, with no rule
 * above it — the same move a newspaper front page makes and the reason this
 * does not read as a list of equals.
 */
.mswc-v3-postlist > li:first-child .mswc-v3-postrow {
	border-top: 0;
	padding-top: 0;
	padding-bottom: 52px;
}

/*
 * ⚠️ IT KEEPS THE TWO COLUMNS. The first draft made the lead a single full-width
 * column, and because the title and the standfirst both carry a measure, what
 * that produced was a 340px stack of text against 840px of nothing. Scale is
 * enough to make it the lead; changing the layout as well only breaks the
 * alignment the rules below it establish.
 */
.mswc-v3-postlist > li:first-child h2.mswc-v3-posttitle {
	font-size: var(--v3-h2);
	max-width: 14ch;
}

.mswc-v3-postlist > li:first-child .mswc-v3-postexcerpt {
	font-size: 1.1875rem;
	max-width: 46ch;
}

h2.mswc-v3-posttitle {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.5rem, 2.2vw, 2rem);
	line-height: 1.15;
	letter-spacing: -0.01em;
	font-weight: 700;
	margin: 10px 0 0;
	max-width: 26ch;
	text-wrap: balance;
}

/*
 * Ink, not the site blue. Nine blue headlines in a column is the old index's
 * loudest habit and it fights the display face. The link is announced as a link
 * either way; hover and keyboard focus both add an underline, so colour is not
 * carrying the affordance alone.
 */
.mswc-v3-posttitle a {
	color: #1f1f1f;
	/*
	 * ⚠️ A PERSISTENT UNDERLINE, quiet, not none-until-hover. The first pass
	 * showed the underline on hover only, which on a phone is never: nothing on
	 * the index looked clickable, and ink headlines with no affordance are how
	 * a list of nine articles reads as a list of nine headings. At 0.3 alpha the
	 * rule reads as typography; on hover and keyboard focus it takes the accent
	 * with the letters. The em offset scales with the lead's 48px as a fixed
	 * pixel offset did not.
	 */
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
	text-decoration-color: rgba(20, 24, 26, 0.3);
}

.mswc-v3-posttitle a:hover,
.mswc-v3-posttitle a:focus-visible {
	color: var(--v3-accent);
	text-decoration-color: currentColor;
}

/*
 * The category, small and quiet, above the title rather than centred over it.
 * Guy asked for "Community-led Conservation" on the Blog tab and it is billed
 * work, so it stays; what changes is that seven identical centred chips become
 * seven quiet lines in a margin.
 *
 * ⚠️ #5b6063, not the 0.55-alpha ink the hanging numerals use: this is 13px
 * text AND a link, so it needs 4.5:1, and 0.55 alpha on white computes to about
 * 3.0. This measures 6.4:1. (`mswc_hide_default_category` in functions.php
 * means the two Uncategorized posts render nothing here at all.)
 */
.mswc-v3-postcat {
	margin: 0;
}

.mswc-v3-postcat a {
	color: #5b6063;
	font-size: 0.75rem;
}

/*
 * The 10px above the title is the gap UNDER the category line. Two places have
 * no category line — the archive (every post on it is in that category, so
 * printing it nine times says nothing) and the two uncategorised posts, where
 * `mswc_hide_default_category` means core renders no terms at all. Without this
 * the left column of those rows starts 10px below the excerpt beside it.
 */
.mswc-v3-postrow-head > h2.mswc-v3-posttitle:first-child {
	margin-top: 0;
}

.mswc-v3-postexcerpt {
	font-size: 1.0625rem;
	line-height: 1.7;
	color: var(--v3-body);
	max-width: 46ch;
	margin: 0;
}

.mswc-v3-postexcerpt p {
	margin: 0;
}

.mswc-v3-pagination {
	margin-top: 56px;
	font-size: 0.9375rem;
}

/* Core emits the container even with one page of results. */
.mswc-v3-pagination:empty {
	display: none;
}

@media (max-width: 860px) {
	.mswc-v3-postrow {
		grid-template-columns: minmax(0, 1fr);
		padding: 28px 0 34px;
	}

	.mswc-v3-postrow-body {
		margin-top: 14px;
	}

	.mswc-v3-postlist > li:first-child .mswc-v3-postrow {
		padding-bottom: 38px;
	}
}

/* ------------------------------- single posts and the category archive */

/*
 * A post used to open on white with a blue title, which is the one thing the
 * v4 pages were rebuilt to stop doing: an inner page that never changes ground
 * reads as a document. This is the cheapest beat that fixes it — the band, the
 * wrap and the ink the rest of the site already uses — and it costs the article
 * itself nothing, because the body below it is unchanged at its 42rem measure.
 *
 * Shorter than `--v3-band-pad`: this is a masthead, not a section.
 */
.mswc-v3-postheader,
.mswc-v3-archivehead {
	padding-block: clamp(3.25rem, 7vw, 5.5rem);
}

.mswc-v3-postheader .mswc-eyebrow a,
.mswc-v3-archivehead .mswc-eyebrow a {
	color: var(--v3-lime);
}

h1.mswc-v3-bighead {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(2rem, 3.8vw, 3.25rem);
	line-height: 1.1;
	letter-spacing: -0.015em;
	font-weight: 700;
	color: #ffffff;
	margin: 14px 0 0;
	max-width: 24ch;
	text-wrap: balance;
}

.mswc-v3-archivehead h1.mswc-v3-bighead {
	margin-top: 0;
}

.mswc-v3-termdeck {
	color: var(--v3-on-dark);
	max-width: 46ch;
	margin: 20px 0 0;
}

.mswc-v3-single .mswc-article {
	margin-top: clamp(2.5rem, 5vw, 4rem);
}

.mswc-v3-postnav {
	margin-top: clamp(3rem, 6vw, 4.5rem);
	padding-top: 28px;
	border-top: 1px solid rgba(20, 24, 26, 0.16);
}

/* Core emits an empty navigation container when there is no adjacent post. */
.mswc-v3-postnav .wp-block-post-navigation-link:empty {
	display: none;
}

/* ======================================================================
 * 0.21.0 — THE FOOTER JOINS EVERY PAGE, NOT JUST THE HOMEPAGE
 * ====================================================================== */

/*
 * The landscape's top ramp dissolves into `--v3-foot-join`, which defaulted to
 * #f7f5f1 because the homepage was the only page that mattered when the band
 * was built — that is the support band's ground, so the homepage join is
 * invisible. Every page that ends on WHITE then met a #fff→#f7f5f1 step: two
 * or three counts of warmth, and a dead-straight full-width line of it, which
 * is exactly the class of defect the band's own 72px gradient exists to
 * prevent (see the "THREE LAYERS" note above).
 *
 * So the pages that end on white say so. The first two selectors are the flow
 * and blog templates, which carry their class on <main> — a plain sibling
 * combinator, no :has() needed. The third is for the v4 pages whose LAST BAND
 * is light (What We Do, Contact): only :has() can see that from the body, and
 * on a browser without :has() they simply keep today's faint line — the
 * fallback is the status quo, never a new artifact. The homepage matches none
 * of these (its last child is `.mswc-v3-closing`, not a band) and keeps
 * #f7f5f1.
 */
main.mswc-v3-flowmain ~ footer .mswc-v3-sitefoot,
main.mswc-v3-blogmain ~ footer .mswc-v3-sitefoot,
body:has(.wp-block-post-content > .mswc-v3-band:not(.mswc-v3-dark):last-child) .mswc-v3-sitefoot {
	--v3-foot-join: #ffffff;
}

/*
 * ⚠️ NO DISSOLVE ON THE INK PAGES — ALEX'S CALL, 2026-09-08 EVENING, after
 * seeing it live. A page that ends on a dark band (About, Testimonials) keeps
 * the crisp cut into the landscape: "does not need the transition gradient
 * since it's black just above it." The dusk gradient that briefly lived here
 * (0.21.0/0.21.1) is deliberately gone — do not reintroduce it. The
 * `--v3-foot-join` machinery above is untouched: those pages keep the #f7f5f1
 * default, the white-ending pages keep their invisible join, which he does
 * want ("blog needs it though").
 */

/* ------------------------------------------- audit fixes, same round */

/*
 * Search results are ranked by relevance, not curated by date, so the blog
 * index's lead-article treatment (48px first entry, no rule above it) makes a
 * claim the page cannot back. The flat modifier sets every result at the same
 * scale, first included.
 */
.mswc-v3-postlist--flat > li:first-child .mswc-v3-postrow {
	border-top: 1px solid rgba(20, 24, 26, 0.16);
	padding-top: 34px;
	padding-bottom: 42px;
}

.mswc-v3-postlist--flat > li:first-child h2.mswc-v3-posttitle {
	font-size: clamp(1.5rem, 2.2vw, 2rem);
	max-width: 26ch;
}

.mswc-v3-postlist--flat > li:first-child .mswc-v3-postexcerpt {
	font-size: 1.0625rem;
	max-width: 46ch;
}

/*
 * theme.json's heading scale bottoms out at 13.28px for an h5, which is
 * SMALLER than the article's body text — the "Guy Pfeffermann, on Lewa
 * Conservancy, 2019." byline on Lioness of Lewa rendered as a caption-sized
 * blue whisper. Production sets the same element at 16px; this restores that
 * inside articles and changes nothing else about it (the face, the weight and
 * the accent colour are production's own).
 */
.mswc-article h5 {
	font-size: 1rem;
}

.mswc-article h6 {
	font-size: 0.9375rem;
}
