/*
Theme Name: Cobell Scholar
Description: Block theme for the Cobell Scholar site. Pages are composed entirely of ACF Blocks; native Gutenberg blocks are suppressed in the page and post editors.
Requires at least: 6.6
Tested up to: 7.0
Requires PHP: 8.3
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: cobell
Tags: full-site-editing, block-patterns, block-styles, translation-ready
*/

/*
 * Shared primitives every block render template composes with. Colours,
 * type sizes, and spacing come from theme.json as custom properties — the
 * only hex values below are inside the grain data URI, which has no token
 * equivalent. Block-specific rules belong in blocks/<name>/style.css.
 */

/*
 * The face every glyph Inter does not carry falls back to, and the reason the
 * arrows were wrong.
 *
 * Inter ships here as a Latin subset, and live's ships as the same one: both
 * carry U+2191 and U+2193 and neither carries U+2192, U+2197 or U+2726. So no
 * arrow on either site is drawn in Inter — each falls through its own stack,
 * and the two stacks disagreed. Live's next entry is Next's generated
 * `Inter Fallback`, which is Arial with Inter's metrics laid over it; ours was
 * `ui-sans-serif`, which is SF on macOS and Segoe UI on Windows. Arial's
 * arrow is long and flat, SF's short with an angled head — a different mark,
 * not a different size, and nothing in a computed style shows it because both
 * sides report the same `font-family`. `CSS.getPlatformFontsForNode` is what
 * names the face that actually rendered.
 *
 * Descriptors are live's own, copied from its stylesheet verbatim. They matter:
 * `size-adjust` scales the glyph, so Arial without them draws a smaller arrow
 * than live's.
 *
 * theme.json's sans stack names this second, exactly where live names it. One
 * declaration therefore covers every arrow on the site — the button glyph, the
 * card cue, the lineup quicklinks, the nav's "All of …" row, the need-help
 * wizard — and the eligibility list's ✦ marker with them.
 */
@font-face {
	font-family: "Inter Fallback";
	src: local( "Arial" );
	ascent-override: 90.44%;
	descent-override: 22.52%;
	line-gap-override: 0%;
	size-adjust: 107.12%;
}

html {
	/* Forbids a single-word last line; the browser reflows earlier lines to
	   pull a word down. Inherited, so every block gets it. `balance` is the
	   fallback where `pretty` is unsupported. */
	text-wrap: balance;
	text-wrap: pretty;
	scroll-behavior: smooth;

	/*
	 * Live's `antialiased` on <html> (layout.tsx), which is Tailwind's shorthand
	 * for these two. Grayscale rasterisation lays down less ink than the
	 * platform default, and without it every glyph on the site rendered a shade
	 * heavier than live's — light-on-dark measurably brighter, dark-on-light
	 * darker. It is the same amount of ink either way, so the direction flips
	 * with the surface; that flip is the tell, and it is why the footer read as
	 * a weight difference when its colours already matched to the byte.
	 *
	 * Rasterisation only. Metrics, advance widths and layout are untouched, and
	 * so are the declared colours every contrast ratio in this build is measured
	 * from.
	 */
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/*
 * Visually hidden but present for assistive technology. Used where a section
 * needs an accessible name and a correct place in the document outline but the
 * design carries no visible heading — clip-path rather than display:none, which
 * would remove it from the accessibility tree entirely.
 */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset( 50% );
	white-space: nowrap;
}

/*
 * Skip link. First focusable element in the document, parked off-screen
 * until focused. Cream on deep forest clears WCAG AA at this size.
 */
.cobell-skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
}

.cobell-skip-link:focus {
	left: 1rem;
	top: 1rem;
	padding: 0.75rem 1.25rem;
	border-radius: 0.375rem;
	background: var( --wp--preset--color--cream );
	color: var( --wp--preset--color--forest );
	outline: 2px solid var( --wp--preset--color--forest );
	text-decoration: none;
}

/*
 * Focus-visible fallback (WCAG 2.4.11). Teal clears 3:1 against cream, which
 * is the surface most of the site uses. Dark sections override it below
 * rather than relying on one ring colour to clear both surfaces.
 */
:focus-visible {
	outline: 2px solid var( --wp--preset--color--teal );
	outline-offset: 2px;
}

.cobell-section--dark :focus-visible {
	outline-color: var( --wp--preset--color--sunflower );
}

/*
 * Ambient grain. A 6%-opacity multiplied noise field used across the
 * editorial sections so consecutive cream panels read as one surface. Applied
 * to a block's section element; the pseudo-element is inert to pointers and
 * sits behind content.
 */
.cobell-grain {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}

.cobell-grain::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -10;
	pointer-events: none;
	opacity: var( --wp--custom--grain-opacity );
	mix-blend-mode: multiply;
	background-image: url( "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='g'><feTurbulence baseFrequency='0.75'/></filter><rect width='100%25' height='100%25' filter='url(%23g)'/></svg>" );
}

/* Multiplying noise onto a dark surface is invisible, so dark sections screen
   it back out and carry slightly more of it. */
.cobell-section--dark.cobell-grain::before {
	opacity: 0.08;
	mix-blend-mode: screen;
}

@media ( prefers-reduced-motion: reduce ) {
	html {
		scroll-behavior: auto;
	}
}

/*
 * The page gutter is a step, not a ramp.
 *
 * It was `clamp(1.5rem, 4vw, 3.5rem)` against the reference's `px-6 md:px-14`.
 * A clamp cannot reproduce a step: it agreed with live at 375 (24) and from
 * ~1400 up (56) — the two widths this build was fitted at — and was wrong at
 * every width in between, bottoming the whole 768–1400 band out on `4vw`. At
 * 768 that is 31px against live's 56 and at 1024 it is 41.
 *
 * It is the single largest remaining source of difference on a tablet, and the
 * signature is unmistakable once you look for it: every section's first child
 * starts 25px left of live's. It was showing up as *height* differences, not
 * width ones, because a wider column makes a card shorter — /about-iei's whole
 * +141 at 768 was this, its board cards measuring 214 wide and 321 tall against
 * live's 197 and 296.
 *
 * Declared on `:root` rather than left in theme.json because theme.json cannot
 * carry a media query. `:root` is (0,1,0) and global styles emit their custom
 * properties on `body` at (0,0,1), so this wins on specificity and does not
 * depend on stylesheet order. theme.json keeps the mobile value so the token
 * still has one honest source for its base.
 *
 * Below 48rem this is a no-op: the old clamp's floor was already 1.5rem and
 * `4vw` only passes it at 600px. From 1400 up both resolve to 3.5rem. So 390
 * and 1440 are the regression gates for any change here — they must not move.
 *
 * Six sections still want 48 rather than 56 at md — the contact, support and
 * news-press family is `md:px-12`. Not carried; they are 8px wide of live from
 * 768 up and were before this change too.
 */
:root {
	--wp--custom--gutter: 1.5rem;
}

@media ( min-width: 48rem ) {
	:root {
		--wp--custom--gutter: 3.5rem;
	}

	/*
	 * The second register: 48, not 56.
	 *
	 * Live authors this per page and uses `px-12` on the six /support pages, on
	 * /news-press, and on /contact's hero — `px-14` everywhere else. Read off the
	 * deployed site by scanning for elements with a computed 48 or 56 inline
	 * padding, not off the reference checkout, which is stale.
	 *
	 * Three of the four scopes are registers that render on one page each, so
	 * they need no page context: `--wide` is /news-press's hero, `press-releases`
	 * and `--measure-snug` are its two body sections. `--full-bleed` is the
	 * /contact, /support and audience-page hero and is 48 on all seven.
	 *
	 * Only the /support cluster's body sections need to know what page they are
	 * on, because card-grid, faq and cta-band all render at 56 elsewhere. That is
	 * what `cobell-cluster-support` is for; see the note on it in helpers.php.
	 *
	 * Setting the token rather than `padding-inline` so anything doing arithmetic
	 * on the gutter — the full-bleed hero's `calc(72rem + gutter * 2)` caps, the
	 * contact spread's five-track grid — follows it instead of drifting from it.
	 */
	.cobell-hero--full-bleed,
	.cobell-hero--wide,
	.cobell-press,
	.cobell-media--measure-snug,
	body.cobell-cluster-support .cobell-section {
		--wp--custom--gutter: 3rem;
	}
}

/*
 * Section shell. Every block's outermost element takes this so vertical
 * rhythm and gutters are decided in one place instead of per block.
 *
 * The reference steps its section padding rather than scaling it — `py-28`
 * below its md breakpoint and `py-36` above, so 112px then 144px. A single
 * clamp cannot reproduce a step, and the earlier clamp landed 29px short at
 * every viewport, compounding down a seven-section page. So the step is a
 * local property rather than the theme.json token read directly: blocks that
 * scale the section rhythm (hero, cta-band) multiply this and follow the
 * breakpoint without repeating the media query.
 */
/*
 * Body copy is one step, set once. The reference runs every section's reading
 * copy at `text-base md:text-lg` — 16px, stepping to 18px at the same
 * breakpoint the section padding steps at — and tints it forest at 75%, which
 * measures 5.22:1 on cream. Blocks that need to sit off this (the Process
 * intro, which the reference holds at 16px) set their own size.
 *
 * The two font-size tokens are fixed rather than fluid, so the step has to be
 * a media query here rather than a clamp on the token.
 */
.cobell-section {
	--cobell-section-padding: var( --wp--custom--section-padding );
	--cobell-body-size: var( --wp--preset--font-size--medium );
	--cobell-body-color: color-mix( in srgb, var( --wp--preset--color--forest ) 75%, transparent );

	padding-block: var( --cobell-section-padding );
	padding-inline: var( --wp--custom--gutter );
	background-color: var( --wp--preset--color--cream );
	color: var( --wp--preset--color--forest );
}

@media ( min-width: 48rem ) {
	.cobell-section {
		--cobell-section-padding: var( --wp--custom--section-padding-wide );
		--cobell-body-size: var( --wp--preset--font-size--large );
	}
}

/*
 * The homepage runs a looser rhythm than the interior, and the two were fought
 * over a single token before this rule existed.
 *
 * Measured on live: the interior pages sit at 128px on the large majority of
 * their sections, which is what --section-padding-wide is set to. The homepage
 * sits at 144px on every one of its editorial sections — the reference gives it
 * `md:py-36` where the interior templates use `py-32`. One global value cannot
 * be both, and splitting it by block does not work either: criteria-list and
 * media-text appear on the homepage and on interior pages, and want a different
 * value in each place.
 *
 * So the exception is scoped to the page rather than the block, which is where
 * the difference actually lives.
 *
 * The same split exists on a phone and only the desktop half of it had been
 * carried. Live's two registers are `py-24 md:py-32` on the interior — 96 then
 * 128 — and `py-28 md:py-36` on the homepage, 112 then 144. The shell's mobile
 * token was 7rem, which is the homepage's value, so every interior section that
 * did not override it locally ran 16px deep at both ends. Measured at 390:
 * /our-story's three media-text rows and its pull quote all read 112/112 against
 * live's 96/96, and /scholarships' ledger the same.
 *
 * The token is 6rem now and the homepage takes 7 here. Nothing else needs
 * scoping — /about-iei is live's other 112 page and all three of its sections
 * (a card-grid `--split` and two people-grids) already carry their own padding,
 * verified 112/112 against live on both sides at 390 before and after.
 */
body.home .cobell-section {
	--cobell-section-padding: 7rem;
}

@media ( min-width: 48rem ) {
	body.home .cobell-section {
		--cobell-section-padding: 9rem;
	}
}

/*
 * The hairline live draws between sections, on the three pages that have it.
 * `cobell-ruled-sections` is written by a body_class filter; the note on it in
 * helpers.php lists which pages carry rules and why this cannot be a rule on
 * `.cobell-section` generally.
 *
 * `:first-child` is the hero and `:last-child` the closing CTA band, and live
 * rules neither — the sections are the only element children of
 * `.wp-block-post-content`, so the two pseudo-classes name exactly those. That
 * also means the set follows the block list: reordering or adding a section in
 * the editor moves the rules with it rather than stranding them on a position.
 *
 * The colour is live's own `#26352a` at 15%, which is the forest token exactly.
 */
body.cobell-ruled-sections .cobell-section:not( :first-child ):not( :last-child ) {
	border-top: 1px solid color-mix( in srgb, var( --wp--preset--color--forest ) 15%, transparent );
}

/*
 * Dark surface — deep forest, the tone the reference uses to break the cream
 * rhythm at a page's decisive moment. Not the teal the footer uses; the footer
 * carries its own colours in chrome.css.
 */
.cobell-section--dark {
	--cobell-body-color: color-mix( in srgb, var( --wp--preset--color--cream ) 88%, transparent );

	background-color: var( --wp--preset--color--forest );
	color: var( --wp--preset--color--cream );
}

.cobell-section__inner {
	margin-inline: auto;
	max-width: var( --wp--style--global--wide-size );
}

.cobell-section__inner--narrow {
	max-width: var( --wp--style--global--content-size );
}

/*
 * Eyebrow. Letterspaced small caps above a heading, optionally flanked by
 * hairline rules. The rules are drawn by ::before/::after so no decorative
 * markup reaches the render templates.
 *
 * Terracotta #d45d00, which is live's, and it costs a WCAG AA failure that is
 * a decision rather than an oversight. At the eyebrow's 10px this is
 * normal-size text and 1.4.3 wants 4.5:1; terracotta on cream measures
 * 3.15:1. An earlier pass here substituted ember #8b3a00 (6.26:1, same hue
 * family, already in the reference palette) and that was reversed on
 * 2026-08-05 on request — live is the target, the same call already made and
 * reversed once on the "Need help?" pill. Ember is the substitute to restore
 * if this is reversed again; nothing else has to move with it.
 *
 * The flanking hairlines were terracotta throughout and are unaffected — they
 * are aria-hidden decoration and carry no information.
 *
 * The margin and line-height below are the reference's own: 1.5 leading on a
 * 10px kicker, and 2rem of air beneath it. Sections that sit the eyebrow
 * tighter to the headline take --tight.
 */
.cobell-eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 1rem;
	margin: 0 0 2rem;
	color: var( --wp--preset--color--terracotta );
	font-size: var( --wp--custom--eyebrow-size );
	font-weight: 600;
	letter-spacing: var( --wp--custom--eyebrow-tracking );
	line-height: 1.5;
	text-transform: uppercase;
}

.cobell-eyebrow--tight {
	margin-bottom: 1.5rem;
}

/* Where the element beneath the eyebrow owns the gap itself — the scholarship
   detail regions space their list off the label rather than the other way
   round, so the eyebrow's own 2rem would double it. */
.cobell-eyebrow--flush {
	margin-bottom: 0;
}

/*
 * Hairline rules flanking the eyebrow. The reference has three registers, and
 * which one a section uses is part of its identity rather than a free choice:
 * a rule on both sides where the eyebrow is centred, a single leading rule
 * where it is left-aligned in a column, and none at all where the eyebrow sits
 * inside a card.
 */
.cobell-eyebrow--ruled::before,
.cobell-eyebrow--ruled::after,
.cobell-eyebrow--ruled-leading::before {
	content: "";
	width: 2rem;
	height: 1px;
	background-color: color-mix( in srgb, var( --wp--preset--color--terracotta ) 60%, transparent );
}

/* The single-rule register sits its label a notch closer to the hairline than
   the flanked one does — gap-3 against gap-4 in the reference. */
.cobell-eyebrow--ruled-leading {
	gap: 0.75rem;
}

/* Flame on deep forest is 5.39:1; ember would disappear against it. */
.cobell-section--dark .cobell-eyebrow {
	color: var( --wp--preset--color--flame );
}

.cobell-section--dark .cobell-eyebrow--ruled::before,
.cobell-section--dark .cobell-eyebrow--ruled::after,
.cobell-section--dark .cobell-eyebrow--ruled-leading::before {
	background-color: color-mix( in srgb, var( --wp--preset--color--flame ) 60%, transparent );
}

/*
 * Heading accent. The trailing fragment of a headline, set in terracotta.
 * Colour only — the reference build used a plain span, so this must not
 * italicise or carry semantic emphasis.
 *
 * Terracotta stays here: the accent is part of a heading whose smallest
 * clamped size is 1.75rem, so it is large text under WCAG and 3.15:1 clears
 * the 3:1 threshold that applies.
 */
.cobell-accent {
	color: var( --wp--preset--color--terracotta );
	font-style: inherit;
}

/*
 * Terracotta on the dark surface too, which is what live does — the reference's
 * own note calls the accent "the visual through-line of the cluster" and keeps
 * it at `#d45d00` on both tones rather than lightening it.
 *
 * This was flame (#fa8a3b, 5.39:1). Terracotta on forest measures 3.30:1, and
 * the two sections that reach this rule are both dark `cta-band` closers —
 * /our-story and /how-to-apply — whose heading is `clamp(2rem, 4.6vw, 3.75rem)`.
 * It floors at 32px, so the fragment is large text at every width and 1.4.3's
 * threshold is 3:1, not 4.5. Flame is the substitute if that heading ever drops
 * below 24px, which is the only thing that would make this fail.
 *
 * Fifth live-colour decision on this build to be made and reversed; the others
 * are listed in CLAUDE.md. Do not change it back silently.
 */
.cobell-section--dark .cobell-accent {
	color: var( --wp--preset--color--terracotta );
}

/*
 * Caption plate. The site's canonical photograph caption: a feathered glass
 * strip pinned to the foot of the image, carrying cream small caps. Live has it
 * on the Elouise spotlight, both /about-iei rosters, the scholarship detail
 * heroes and bodies, the support heroes, and the alumni rail — the reference
 * consolidated its five hand-written copies into one primitive after they had
 * drifted on glass opacity, mask cutoff and padding, so it is one rule here too.
 *
 * Two things make it work and both are easy to lose:
 *
 * The mask feathers the top edge of the glass into the photograph rather than
 * cutting it, so the type always sits on solid coverage and there is never a
 * hard horizontal seam across the picture.
 *
 * #14201a is a literal, not a token. It is darker than forest-deep and exists
 * to hold cream at AA over a photograph nobody has seen — cream on this tint is
 * legible whatever is behind it.
 *
 * The plate is positioned against its figure, so the figure owns the aspect
 * ratio, the radius and the overflow clip; a plate on a bare <img> has nothing
 * to pin itself to.
 */
.cobell-caption-plate {
	position: absolute;
	inset: auto 0 0;
	padding: 0.75rem 1rem;
	background-color: color-mix( in srgb, #14201a 55%, transparent );
	color: var( --wp--preset--color--cream );
	font-family: var( --wp--preset--font-family--sans );
	font-size: var( --wp--custom--eyebrow-size );
	font-weight: 600;
	letter-spacing: 0.35em;
	line-height: 1.625;
	text-align: center;
	text-transform: uppercase;
	-webkit-backdrop-filter: blur( 40px );
	backdrop-filter: blur( 40px );
	-webkit-mask-image: linear-gradient( to top, #000 55%, transparent 100% );
	mask-image: linear-gradient( to top, #000 55%, transparent 100% );
}

/*
 * Tall register. A two-line caption reads as bottom-hugging on the standard
 * band, so the reference extends the glass and moves the headroom above the
 * type rather than below it. Live uses this on the support heroes; the
 * single-line captions everywhere else stay on the default.
 */
.cobell-caption-plate--tall {
	padding: 2.25rem 1rem 0.75rem;
	-webkit-mask-image: linear-gradient( to top, #000 66%, transparent 100% );
	mask-image: linear-gradient( to top, #000 66%, transparent 100% );
}

.cobell-caption-plate__line {
	display: block;
}

.cobell-caption-plate__line--meta {
	color: color-mix( in srgb, var( --wp--preset--color--cream ) 75%, transparent );
}

/*
 * Buttons. Rendered by cobell_render_buttons() from the shared buttons
 * repeater, so the three variants below are the whole button vocabulary.
 */
/*
 * `gap-4` and `items-center`, both literal. The gap was `spacing--30`, which
 * resolves to 0.67rem rather than the 1rem the scale reads as — the preset trap
 * again — and live writes 16px on every row of these it draws. Only two
 * instances on the site carry more than one button and so could show it: the
 * homepage hero and /support/parents. `align-items` was missing outright, which
 * lets an outlined pill and a text link sit on different baselines.
 */
.cobell-buttons {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1rem;
	margin-top: var( --wp--preset--spacing--50 );
}

/*
 * The reference has two call-to-action type treatments, not one. An earlier
 * note here claimed a single 11px uppercase treatment shared by all three
 * variants; that was wrong, and it is why every button on the site read a
 * step small and over-tracked.
 *
 * The pill CTAs — filled and outlined — are 14px semibold in sentence case
 * with no tracking, on 12px × 24px of padding and a 20px line box. The 11px
 * uppercase treatment belongs to the bare text link and to the blocks that set
 * their own register (cta-band, criteria-list), so the pill typography lives on
 * the base and --ghost overrides it below.
 *
 * Three of those numbers were wrong against live and every button on the site
 * carried all three:
 *
 *   line-height  1.25 gave a 17.5px line box where live's is 20px, so every
 *                filled pill stood 3px short of live's 44px.
 *   padding      1.75rem inline where live sets 1.5rem, so each pill ran 8px
 *                wide. The two blocks live pads differently override it.
 *   border       a 1px transparent border added 2px to every filled pill,
 *                which is why they measured 46 against live's 44. Only the
 *                outlined variant draws a border, so only it declares one.
 */
.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	padding: 0.75rem 1.5rem;
	border: 0;
	border-radius: 999px;
	/* A <button> does not inherit the document font — the UA hands it Arial at
	   13.3px — and three of these variants are buttons, not anchors: the download
	   card's "Email to Me", the Gravity submit, the need-help triggers. Anchors
	   inherited already, which is why the pair only looked wrong on the tile where
	   a filled anchor sits directly above an outlined button. */
	font-family: inherit;
	font-size: 0.875rem;
	font-weight: 600;
	line-height: 1.25rem;
	text-decoration: none;
	transition: background-color 150ms ease, color 150ms ease, border-color 150ms ease;
}

/*
 * `hidden` has to be able to hide a button, and on its own it cannot: the UA's
 * `[hidden] { display: none }` is (0,1,0) and `.btn`'s `display: inline-flex`
 * above ties with it, so the class wins on source order and the attribute reads
 * as having no effect at all.
 *
 * This is what the Email-to-me trigger's progressive enhancement rests on — it
 * ships hidden and email-resource.js unhides it — so without this rule a page
 * with that script blocked shows a button that does nothing. Same shape as
 * `.cobell-need-help-pill[hidden]`, which needed it for the same reason.
 */
.btn[hidden] {
	display: none;
}

/* Decorative arrow. Slides on hover for pointer users; held still for anyone
   who has asked for reduced motion. */
.btn__arrow {
	line-height: 1;
	transition: transform 150ms ease;
}

.btn:hover .btn__arrow {
	transform: translateX( 0.25rem );
}

@media ( prefers-reduced-motion: reduce ) {
	.btn__arrow {
		transition: none;
	}

	.btn:hover .btn__arrow {
		transform: none;
	}
}

/*
 * Solid fills are teal, matching live. An earlier pass here read the
 * reference's fill as terracotta or clay and substituted ember to clear
 * contrast — but neither is what live fills a button with. Terracotta is the
 * heading accent and clay the dropdown rule; the reference's own CTA and header
 * pill are both #005f61, the teal already in this palette.
 *
 * It clears AA on its own merits, so there is nothing to trade away: a button
 * label is 11px, which is normal-size text needing 4.5:1, and cream on teal
 * measures 6.02:1 with the deeper step at 9.46:1.
 *
 * Terracotta and clay stay off solid fills. Cream on them is 3.15:1 and 3.72:1,
 * so they are used only for large text or non-informational decoration.
 */
.btn--primary {
	background-color: var( --wp--preset--color--teal );
	color: var( --wp--preset--color--cream );
}

.btn--primary:hover,
.btn--primary:focus-visible {
	background-color: var( --wp--preset--color--teal-deep );
	color: var( --wp--preset--color--cream );
}

/*
 * Forest fill. The reference uses it in exactly one place — the Elouise
 * spotlight's CTA — where a teal pill would read as chrome against the
 * portrait rather than as part of the spread. Kept as its own variant rather
 * than normalised to teal because it is a deliberate one-off in the reference,
 * and it costs nothing on contrast: cream on forest is 10.63:1, better than
 * the teal fill's 6.02:1.
 */
.btn--forest {
	background-color: var( --wp--preset--color--forest );
	color: var( --wp--preset--color--cream );
}

.btn--forest:hover,
.btn--forest:focus-visible {
	background-color: var( --wp--preset--color--forest-deep );
	color: var( --wp--preset--color--cream );
}

/* Two-pixel rule, not one. At 14px on a cream field a hairline outline reads
   as a disabled control; the reference draws it at 2px. The whole border is
   declared here rather than only its width, because the base no longer carries
   a transparent one for this to widen. */
.btn--secondary {
	border: 2px solid var( --wp--preset--color--forest );
	background-color: transparent;
	color: var( --wp--preset--color--forest );
}

.btn--secondary:hover,
.btn--secondary:focus-visible {
	background-color: var( --wp--preset--color--forest );
	color: var( --wp--preset--color--cream );
}

/*
 * The 11px uppercase treatment on a pill. This is a third register, and it is
 * not the mistake an earlier note here took it for: live draws it on the
 * download and "email to me" pair, on the students video CTA, and on the
 * /contact submit button, which is where it was first met and scoped locally.
 * Four call sites is no longer a one-off, so it is a variant.
 *
 * The type is --ghost's; the shell is the pill's. Both --caps variants stretch
 * to their container by default because every current call site pairs them in a
 * column where matched widths are the point.
 */
.btn--caps,
.btn--caps-outline {
	/* The theme has no global reset, so a stretched --caps button was resolving
	   `width: 100%` against its content box and coming out 48px — its own inline
	   padding — wider than the column it sits in. */
	box-sizing: border-box;
	/* 28px, against the base's 24. Live pads this register a step wider, and the
	   difference is only visible on a button that is not stretched — it is what
	   left the video CTA 9px narrower than live's. */
	padding: 0.75rem 1.75rem;
	/* 12px, against the base's 8. The tracked-out label needs more air before the
	   glyph or the two run together at this letter-spacing. */
	gap: 0.75rem;
	font-size: 0.6875rem;
	letter-spacing: 0.35em;
	line-height: 1.5;
	text-transform: uppercase;
}

.btn--caps {
	background-color: var( --wp--preset--color--forest );
	color: var( --wp--preset--color--cream );
}

.btn--caps:hover,
.btn--caps:focus-visible {
	background-color: var( --wp--preset--color--forest-deep );
	color: var( --wp--preset--color--cream );
}

/* A hairline, not --secondary's 2px. The outlined pill sits directly under a
   filled one here, and at 2px it competed with the fill instead of reading as
   the quieter of the pair — live draws it at 1px in forest at 40%. */
/* The width and the style are declared here, not inherited: `.btn` is `border: 0`,
   so a variant that sets only a colour renders no rule at all — which is what
   left this pill looking like bare centred text beside the filled one. */
.btn--caps-outline {
	border-width: 1px;
	border-style: solid;
	border-color: color-mix( in srgb, var( --wp--preset--color--forest ) 40%, transparent );
	background-color: transparent;
	color: var( --wp--preset--color--forest );
}

.btn--caps-outline:hover,
.btn--caps-outline:focus-visible {
	border-color: var( --wp--preset--color--forest );
	background-color: color-mix( in srgb, var( --wp--preset--color--forest ) 5%, transparent );
	color: var( --wp--preset--color--forest );
}

/*
 * The bare text link. Shares the 11px uppercase type with the --caps pair above
 * and is the only one of the three that carries no pill.
 * No pill and no rule at rest, matching the reference — the affordance is the
 * tracked-out uppercase setting and the trailing arrow, neither of which is a
 * colour cue, so WCAG 1.4.1 is satisfied without an underline. One is added on
 * hover and focus anyway, since it costs nothing at rest.
 */
.btn--ghost {
	/* Live sets every underlined caps link `items-baseline`, and only the pills
	   `items-center`. Centred, the arrow rides 1.5px high of the label's
	   baseline — the whole of what a pixel diff of this button still showed once
	   the glyph itself was right. */
	align-items: baseline;
	padding: 0 0 0.25rem;
	border: 0;
	/* The rule under the label is the affordance — without it this reads as
	   uppercase text rather than something to press. Live draws it at 1px in
	   forest at 40%. */
	border-bottom: 1px solid color-mix( in srgb, var( --wp--preset--color--forest ) 40%, transparent );
	border-radius: 0;
	background-color: transparent;
	color: var( --wp--preset--color--forest );
	font-size: 0.6875rem;
	letter-spacing: 0.35em;
	line-height: 1.5;
	text-transform: uppercase;
}

/* Darkens rather than changing hue. Live's quiet CTA — the hero's "Meet Elouise
   Cobell" — goes from forest at 80% to full forest on hover and stays in the
   one family; an ember hover here read as a second accent colour beside the
   teal fill it sits next to. */
.btn--ghost:hover,
.btn--ghost:focus-visible {
	border-bottom-color: var( --wp--preset--color--forest-deep );
	color: var( --wp--preset--color--forest-deep );
}

/* A forest fill on a forest section is invisible, so it takes the same cream
   inversion the teal fill does. */
.cobell-section--dark .btn--primary,
.cobell-section--dark .btn--forest {
	background-color: var( --wp--preset--color--cream );
	color: var( --wp--preset--color--forest );
}

.cobell-section--dark .btn--primary:hover,
.cobell-section--dark .btn--primary:focus-visible,
.cobell-section--dark .btn--forest:hover,
.cobell-section--dark .btn--forest:focus-visible {
	background-color: var( --wp--preset--color--flame );
	color: var( --wp--preset--color--forest-deep );
}

.cobell-section--dark .btn--secondary,
.cobell-section--dark .btn--ghost {
	border-color: color-mix( in srgb, var( --wp--preset--color--cream ) 60%, transparent );
	color: var( --wp--preset--color--cream );
}

/*
 * The outline inverts to a cream fill on the dark band, not to the forest fill
 * the cream surface uses. Inheriting the cream-surface hover put a forest fill
 * on a forest section and left the label cream, so the only thing that moved
 * was the border going from 60% to 60% — it read as a button with no hover at
 * all rather than as a wrong colour, which is why it survived a visual pass.
 *
 * Deep ink on cream is 13.5:1, so this is also the better end of the trade.
 */
.cobell-section--dark .btn--secondary:hover,
.cobell-section--dark .btn--secondary:focus-visible {
	border-color: var( --wp--preset--color--cream );
	background-color: var( --wp--preset--color--cream );
	color: var( --wp--preset--color--forest-deep );
}

/*
 * The closing band runs its own CTA register, and it belongs to the band rather
 * than to the dark surface.
 *
 * On cream the shared pill is 14px sentence case — "Explore Scholarships",
 * "Read her story". Live drops every cta-band CTA to 11px uppercase at 0.35em,
 * filled and outlined alike, so the button reads as a quiet footer to the band
 * rather than competing with the headline above it.
 *
 * This was keyed on .cobell-section--dark, which is true of seven of the eight
 * bands and wrong about the eighth: /support/institutions' band is cream and
 * live sets 11px there all the same. Its four buttons were left on the 14px
 * pill, 5px too tall and 50 to 60px too narrow each. Only the metrics below vary
 * with the surface, so only they stay keyed on it.
 */
.cobell-cta-band__button.btn--primary,
.cobell-cta-band__button.btn--secondary,
.cobell-cta-band__button.btn--forest {
	gap: 0.75rem;
	padding: 0.75rem 1.75rem;
	border-width: 1px;
	font-size: 0.6875rem;
	letter-spacing: 0.35em;
	line-height: 1.5;
	text-transform: uppercase;
}

/* On the dark band the outline stands 2px taller and tightens its gap. */
.cobell-section--dark .cobell-cta-band__button.btn--secondary {
	gap: 0.5rem;
	padding: 0.875rem 1.75rem;
}

/* The filled one carries more weight than the outline beside it — more padding,
   no border to account for, the deeper ink, and its glyph a register above its
   label at 14px. Without that last pair "Apply on OASIS" ran 6px narrow on all
   six scholarship pages. */
.cobell-section--dark .cobell-cta-band__button.btn--primary,
.cobell-section--dark .cobell-cta-band__button.btn--forest {
	padding: 1rem 2rem;
	border-width: 0;
	color: var( --wp--preset--color--forest-deep );
}

.cobell-section--dark .cobell-cta-band__button.btn--primary .btn__arrow,
.cobell-section--dark .cobell-cta-band__button.btn--forest .btn__arrow {
	font-size: 0.875rem;
}

/*
 * Rich text. The wysiwyg field is the only place an editor produces nested
 * markup, so its internals are styled once here.
 */
.cobell-prose > * + * {
	margin-top: 1.25em;
}

.cobell-prose h2,
.cobell-prose h3,
.cobell-prose h4 {
	margin-top: 2em;
}

.cobell-prose ul,
.cobell-prose ol {
	padding-left: 1.25em;
}

.cobell-prose li + li {
	margin-top: 0.5em;
}

.cobell-prose a {
	color: var( --wp--preset--color--teal );
	text-underline-offset: 0.2em;
}

.cobell-section--dark .cobell-prose a {
	color: var( --wp--preset--color--sunflower );
}

/*
 * Editor-only affordance. Blocks render a placeholder when they have no
 * content yet so an empty block is visible in the canvas instead of
 * collapsing to nothing.
 */
.cobell-placeholder {
	margin: 0;
	padding: var( --wp--preset--spacing--40 );
	border: 1px dashed color-mix( in srgb, var( --wp--preset--color--forest ) 40%, transparent );
	border-radius: 0.375rem;
	color: color-mix( in srgb, var( --wp--preset--color--forest ) 70%, transparent );
	font-size: var( --wp--preset--font-size--small );
}

/*
 * Not-found page. There was no 404 template, so a missing URL fell through to
 * the blog index, which rendered an empty query loop — a blank main region with
 * no h1 on it. Found while sweeping the published pages.
 */
.cobell-404__heading {
	margin: 0;
	font-size: var( --wp--preset--font-size--xx-large );
	line-height: 1.02;
	letter-spacing: var( --wp--custom--heading-tracking );
}

.cobell-404__body {
	max-width: 34rem;
	margin-top: var( --wp--preset--spacing--40 );
	color: var( --cobell-body-color );
	font-size: var( --cobell-body-size );
}

.cobell-404__links {
	margin: var( --wp--preset--spacing--50 ) 0 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid color-mix( in srgb, var( --wp--preset--color--forest ) 15%, transparent );
}

.cobell-404__links li {
	border-bottom: 1px solid color-mix( in srgb, var( --wp--preset--color--forest ) 15%, transparent );
}

.cobell-404__links a {
	display: block;
	padding-block: var( --wp--preset--spacing--30 );
	color: inherit;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.3em;
	text-transform: uppercase;
	text-decoration: none;
}

.cobell-404__links a:hover,
.cobell-404__links a:focus-visible {
	color: var( --wp--preset--color--ember );
}

/*
 * Heading weight is per block, not global.
 *
 * Live sets 400 on 83 of the 86 headings across the interior pages and on
 * every h3 everywhere, including the homepage. The exceptions are a handful of
 * section headings that the reference builds from its own components, each of
 * which sets its own weight — so the bold is a property of those surfaces, not
 * of headings in general.
 *
 * Setting 700 on `elements.heading` in theme.json therefore corrected six
 * homepage h2s and broke roughly ninety other headings, h3s included. The
 * weight lives here instead, on the surfaces live actually sets bold.
 *
 * `steps` was on this list and is not any more: it is bold on seven of its nine
 * placements and regular on the other two, so its weight moved to the block's
 * own `heading_scale` field alongside the size and tracking that travel with it.
 *
 * Three instances still disagree with live and want a field rather than a
 * rule, because the same block is bold in one placement and not another: the
 * homepage's media-text ("Scholar to scholar."), the alumni people-grid
 * ("They started where you are"), and news-press's content-section
 * ("Press & Publications"). All three read 400 here.
 */
.cobell-spotlight__heading,
.cobell-manifesto__heading,
.cobell-lineup__heading,
.cobell-criteria__heading {
	font-weight: 700;
}

/* ─────────────────────────────  Marquee  ─────────────────────────────
 *
 * A continuously drifting strip of portraits, used below the `md` breakpoint by
 * the homepage hero and the audience lineup — both of which the reference swaps
 * for a marquee on a phone rather than stacking their desktop composition.
 *
 * The track holds two identical copies so the loop has no seam: when the first
 * has travelled exactly its own width out of view, the second is sitting where
 * the first started, and resetting to zero is invisible.
 *
 * Distance and duration are custom properties written by `initMarquees` in
 * motion.js, because the copy's width is a function of the viewport (each tile
 * is a vw) and CSS cannot divide it by the reference's 80px/s. Both carry a
 * fallback, so with no JS at all the strip still drifts at a sane speed — the
 * `50%` is very slightly wrong (the first copy carries an extra 12px of leading
 * pad) and is invisible in motion.
 *
 * Class names deliberately avoid `__item`, `__image` and `__figure`: motion.css
 * reveals anything matching those and holds `transform` in its end state, which
 * would outrank the animation and pin the strip. `__tile` and `__photo` are
 * clear of that list.
 *
 * ── WCAG 2.2.2, satisfied since 2026-08-10 ──
 *
 * This starts on load and runs indefinitely, which Level A asks to be pausable.
 * The reference gates it on `prefers-reduced-motion` and offers no control; the
 * gate helps the readers most affected but is not the mechanism the criterion
 * asks for, and this build carries a contractual AA commitment.
 *
 * `cobell_marquee_pause()` prints a checkbox ahead of the track and the rule
 * below pauses the animation from `:checked`. A checkbox rather than a button
 * because this animation is pure CSS with its duration defaulted here — it runs
 * whether or not motion.js loads, so a scripted control would be dead in the
 * one case the criterion still bites.
 *
 * It is a visible departure from live. Taken deliberately: Level A is the floor.
 */

.cobell-marquee {
	position: relative;
	overflow: hidden;
}

.cobell-marquee__track {
	display: flex;
	width: max-content;
	will-change: transform;
}

.cobell-marquee__copy {
	display: flex;
	flex: none;
	gap: 0.75rem;
	padding-right: 0.75rem;
}

.cobell-marquee__copy:first-child {
	padding-left: 0.75rem;
}

.cobell-marquee__tile {
	flex: none;
	overflow: hidden;
	border-radius: 0.25rem;
	box-shadow: 0 10px 15px -3px rgba( 0, 0, 0, 0.1 ), 0 4px 6px -4px rgba( 0, 0, 0, 0.1 );
}

.cobell-marquee__photo {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	/* Centred, a 3:4 crop of a standing portrait takes the crop out of the head. */
	object-position: top;
}

@media ( prefers-reduced-motion: no-preference ) {
	.cobell-marquee__track {
		animation: cobell-marquee-drift var( --cobell-marquee-duration, 24s ) linear infinite;
	}

	/* The whole of 2.2.2, in one declaration. The checkbox is a sibling that
	   precedes the track, which is the only reason `~` reaches it — do not
	   reorder the two in render.php. */
	.cobell-marquee__pause-input:checked ~ .cobell-marquee__track {
		animation-play-state: paused;
	}
}

/* ── The pause control ───────────────────────────────────────────────────── */

/* Visually hidden but focusable: the label is the visible control, and a
   `display: none` input takes the keyboard with it. */
.cobell-marquee__pause-input {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset( 50% );
	white-space: nowrap;
	border: 0;
}

.cobell-marquee__pause {
	position: absolute;
	z-index: 2;
	right: 0.75rem;
	bottom: 0.75rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* 2.5.5 asks 44px of any control that is not inline text. */
	width: 2.75rem;
	height: 2.75rem;
	box-sizing: border-box;
	color: var( --wp--preset--color--cream, #efe6d1 );
	background: rgba( 20, 32, 26, 0.72 );
	border-radius: 50%;
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.cobell-marquee__pause:hover {
	background: rgba( 20, 32, 26, 0.9 );
}

/* The ring goes on the label, since the input it belongs to is clipped. */
.cobell-marquee__pause-input:focus-visible + .cobell-marquee__pause {
	outline: 2px solid var( --wp--preset--color--sunflower, #f5e462 );
	outline-offset: 2px;
}

/* Screen-reader only. Whichever one is `display: none` drops out of the
   accessible name, so the name always describes the next action. */
.cobell-marquee__pause-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip-path: inset( 50% );
	white-space: nowrap;
}

.cobell-marquee__pause-text--play,
.cobell-marquee__pause-input:checked ~ .cobell-marquee__pause .cobell-marquee__pause-text--pause {
	display: none;
}

.cobell-marquee__pause-input:checked ~ .cobell-marquee__pause .cobell-marquee__pause-text--play {
	display: inline;
}

.cobell-marquee__pause-glyph {
	fill: currentColor;
	pointer-events: none;
}

.cobell-marquee__pause-play,
.cobell-marquee__pause-input:checked ~ .cobell-marquee__pause .cobell-marquee__pause-bar {
	display: none;
}

.cobell-marquee__pause-input:checked ~ .cobell-marquee__pause .cobell-marquee__pause-play {
	display: inline;
}

/* Nothing is moving, so there is nothing to pause — and an inert control is
   worse than none. Matches the gate the animation itself sits behind. */
@media ( prefers-reduced-motion: reduce ) {
	.cobell-marquee__pause-input,
	.cobell-marquee__pause {
		display: none;
	}
}

@keyframes cobell-marquee-drift {
	to {
		transform: translateX( calc( -1 * var( --cobell-marquee-distance, 50% ) ) );
	}
}
