/**
 * Ariana 4 Fresno - campaign styles
 * ---------------------------------------------------------------------------
 * CONVENTIONS
 *
 * 1. Naming        Every campaign class is prefixed `a4f-`. Blocks use
 *                  `a4f-block`, children `a4f-block__element`, variants
 *                  `a4f-block--variant`. No bare element selectors outside
 *                  section 2, so nothing here can leak into admin or plugin UI.
 *
 * 2. Colour        Never hard-code a hex below section 1. Always go through a
 *                  `--a4f-*` token, which in turn points at a WordPress preset
 *                  (`--wp--preset--color--*`). That keeps the block editor's
 *                  colour pickers authoritative: change a palette colour in
 *                  theme.json and every rule here follows.
 *
 * 3. Spacing       Use `--wp--preset--spacing--*` presets so spacing stays on
 *                  the same scale the editor offers.
 *
 * 4. Specificity   Single class selectors wherever possible. Where a core block
 *                  style must be beaten, the override is scoped under an `a4f-`
 *                  ancestor rather than raised with `!important`.
 *
 * CONTENTS
 *   1. Tokens
 *   2. Base
 *   3. Header
 *   4. Hero
 *   5. Letter
 *   6. Priorities (yard signs)
 *   7. Experience timeline
 *   8. Endorsement logo wall
 *   9. Get involved
 *  10. Footer
 *  11. Motion
 *  12. Page-load curtain
 *  13. Interior pages
 *  14. Endorsements
 *  15. About letter
 *  16. Mobile navigation
 *  17. Forms
 * ---------------------------------------------------------------------------
 */

/* ==========================================================================
   1. Tokens
   ========================================================================== */

:root {
	/*
	 * This is a committed dark design: the page ground is the campaign purple
	 * itself, not a neutral. `page` is the base ground, `surface` the raised
	 * band, and `primary` the lighter purple that separates the Get Involved
	 * block from both.
	 */
	--a4f-page: var(--wp--preset--color--purple-deep, #170f24);
	--a4f-surface: var(--wp--preset--color--purple-tint, #221535);
	--a4f-primary: var(--wp--preset--color--primary, #3a2260);
	--a4f-accent: var(--wp--preset--color--accent, #b79bde);
	--a4f-accent-soft: var(--wp--preset--color--accent-soft, #d6c3f2);
	--a4f-secondary: var(--wp--preset--color--secondary, #ebb220);
	--a4f-tertiary: var(--wp--preset--color--tertiary, #bada54);

	/* Text and hairlines, light-on-dark. */
	--a4f-ink: var(--wp--preset--color--ink, #f6f2fb);
	--a4f-ink-soft: var(--wp--preset--color--ink-soft, #cbb9e6);
	--a4f-base: var(--wp--preset--color--base, #ffffff);
	--a4f-cream: var(--wp--preset--color--cream, #f7f3ea);
	--a4f-line: var(--wp--preset--color--line, #35274c);

	/* Typography. */
	--a4f-font-heading: var(--wp--preset--font-family--playfairdisplay, "PlayfairDisplay", serif);
	--a4f-font-body: var(--wp--preset--font-family--open-sans, "Open Sans", sans-serif);
	--a4f-font-accent: var(--wp--preset--font-family--prata, "Prata", serif);

	/* Elevation. On a dark ground these have to be near-black to read at all. */
	--a4f-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.35);
	--a4f-shadow-md: 0 18px 40px -20px rgba(0, 0, 0, 0.7);
	--a4f-shadow-lg: 0 24px 50px -20px rgba(0, 0, 0, 0.75);

	/* Motion. `--a4f-logo-scale-top` is the multiplier applied to the logo while
	   the page is at the top; change it here to retune the effect. */
	--a4f-logo-scale-top: 2.5;
	--a4f-logo-speed: 0.4s;
	--a4f-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
	--a4f-header-gap: 1rem;

	/* Shared geometry. */
	--a4f-radius: 4px;
	--a4f-measure: 62ch;
}

/* ==========================================================================
   2. Base
   ========================================================================== */

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

/*
 * Undo the parent theme's scroll-reveal, which strands legacy content invisible.
 *
 * hostinger-ai-theme prints `.hostinger-ai-fade-up { opacity: 0 }` inline and
 * relies on its own front-scripts.min.js to fade those blocks in. That script is
 * enqueued with get_stylesheet_directory_uri(), which under a child theme
 * resolves to THIS directory rather than the parent's, so the file 404s and the
 * reveal never runs. The rule still applies, so every block the Hostinger AI
 * builder generated sits at zero opacity permanently.
 *
 * Any page still on builder-generated content is blank because of this. The
 * campaign's own sections do not use the class and have their own reveal, so
 * neutralising it here is safe and keeps legacy pages readable until they are
 * rebuilt from patterns.
 */
.hostinger-ai-fade-up {
	opacity: 1;
}

/* Keyboard focus must stay visible on every interactive element. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
	outline: 3px solid var(--a4f-accent);
	outline-offset: 2px;
}

/* ==========================================================================
   3. Header
   ========================================================================== */

/*
 * Sticky belongs on the template-part wrapper, not on the header group inside
 * it. A sticky element can only travel within its parent's box, and the wrapper
 * is exactly as tall as the header, so sticking the inner group gives it zero
 * range and it behaves exactly like static. The wrapper's own parent is
 * .wp-site-blocks, which spans the document, so it has the whole page to stick
 * through.
 *
 * :has() ties this to the Position control in the editor: turn Sticky off on
 * the header group and WordPress drops .is-position-sticky, and this stops
 * applying too.
 */
.site-header:has(.is-position-sticky) {
	position: sticky;
	top: 0;
	z-index: 40;
}

.a4f-header {
	position: relative;
	/* Brand rule rather than a neutral hairline, so the purple starts at the top. */
	border-bottom: 2px solid var(--a4f-primary);
	box-shadow: 0 1px 0 rgba(183, 155, 222, 0.25);
}

/*
 * The tinted blur sits on a pseudo-element rather than on .a4f-header itself.
 * An element carrying backdrop-filter becomes the containing block for every
 * position:fixed descendant, and core's mobile menu overlay is exactly that:
 * with the filter on the header, the overlay was confined to the header's own
 * ~76px strip instead of covering the viewport, so opening the menu appeared to
 * do nothing at all. Moving the filter down one level keeps the frosted header
 * and leaves the overlay anchored to the viewport where it belongs.
 */
.a4f-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: color-mix(in srgb, var(--a4f-page) 92%, transparent);
	backdrop-filter: blur(8px);
	pointer-events: none;
}

/*
 * A 2.5x logo eats most of a phone's width and squeezes the site title into an
 * awkward wrap, so the effect is dialled back rather than dropped. Retune here
 * rather than in the rules above, which all read the custom property.
 */
@media (max-width: 700px) {
	:root {
		--a4f-logo-scale-top: 1.6;
	}
}

/*
 * Deliberately no width/height here: the logo is sized by the Image Width
 * control on the Site Logo block, so setting it in CSS would override the
 * editor. Only the scale and the transition belong to the theme.
 */
/*
 * Everything below hangs off classes WordPress itself generates
 * (.wp-block-site-logo, .wp-block-template-part) rather than the theme's own
 * a4f-* classes.
 *
 * The header is a template part saved in the database as soon as it is touched
 * in the Site Editor, and any later save there rewrites that record from the
 * editor's state. Custom classes added outside the editor do not survive it, so
 * a rule depending on them works until the next time the header is edited and
 * then silently stops. Core classes are always present.
 */
.site-header,
.site-header .wp-block-group,
.site-header .wp-block-site-logo {
	overflow: visible;
}

.site-header .wp-block-site-logo img {
	display: block;
	border-radius: 0;
	box-shadow: var(--a4f-shadow-sm);
	transform-origin: left top;
	transition: transform var(--a4f-logo-speed) var(--a4f-ease);
	/* Paints over the hero while it overhangs the header. */
	position: relative;
	z-index: 1;
}

/*
 * At the top of the page the logo is shown large, returning to its configured
 * size once the reader scrolls. `--a4f-logo-h` is measured from the rendered
 * logo by main.js so the header reserves the right height whatever size is
 * chosen in the editor; transform alone would not affect layout and the
 * enlarged mark would spill over the hero.
 */
/*
 * The header keeps a single height, set by the logo at its configured size. At
 * the top of the page the mark scales up and is allowed to overhang the bar
 * rather than pushing it open, so the navigation never shifts.
 *
 * The state lives on <body>, set by main.js, so it does not depend on markup
 * that the Site Editor can rewrite.
 */
body.a4f-at-top .site-header .wp-block-site-logo img {
	transform: scale(var(--a4f-logo-scale-top));
}


.a4f-header__title,
.a4f-header__title a {
	font-family: var(--a4f-font-heading);
	font-size: 1.28rem;
	line-height: 1.1;
	text-decoration: none;
	color: var(--a4f-ink);
}

/*
 * Fluid size so four links plus the Donate button stay on one row between the
 * 600px overlay breakpoint and full desktop, where a fixed 0.95rem wrapped them
 * onto a second line.
 */
.a4f-header__nav a {
	font-family: var(--a4f-font-body);
	font-weight: 600;
	font-size: clamp(0.78rem, 1.15vw, 0.95rem);
	text-decoration: none;
	color: var(--a4f-ink-soft);
}

.a4f-header__nav a:hover {
	color: var(--a4f-accent);
}

/* ==========================================================================
   4. Hero
   ========================================================================== */

.a4f-hero__eyebrow,
.a4f-eyebrow {
	font-family: var(--a4f-font-body);
	font-weight: 700;
	font-size: 0.78rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--a4f-secondary);
}

.a4f-hero__title {
	text-wrap: balance;
}

.a4f-hero__lede {
	max-width: 46ch;
	color: var(--a4f-ink-soft);
}

/*
 * Marker underline. Drawn with a background gradient rather than an SVG so the
 * phrase stays plain editable text in the block editor.
 */
.a4f-mark {
	position: relative;
	padding: 0 0.08em;
	background: none;
}

/*
 * The stroke is a masked pseudo-element rather than an inline <svg>, so the
 * highlighted phrase stays plain editable text in the block editor: nothing to
 * detach, and no markup for the editor to flag as invalid.
 *
 * The SVG supplies only the shape; the colour comes from the palette token, so
 * changing the accent in theme.json still repaints the stroke. The curve is the
 * same path as the original design, and preserveAspectRatio='none' lets it
 * stretch to whatever width the phrase happens to be.
 */
.a4f-mark::before {
	content: "";
	position: absolute;
	left: -2%;
	right: -2%;
	bottom: -0.12em;
	height: 0.42em;
	z-index: -1;
	pointer-events: none;
	background-color: var(--a4f-tertiary);
	-webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20200%2020'%20preserveAspectRatio='none'%3E%3Cpath%20d='M4,13C60,4,140,4,196,12'%20fill='none'%20stroke='%23000'%20stroke-width='8'%20stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
	mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20200%2020'%20preserveAspectRatio='none'%3E%3Cpath%20d='M4,13C60,4,140,4,196,12'%20fill='none'%20stroke='%23000'%20stroke-width='8'%20stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
}

.a4f-hero__facts {
	list-style: none;
	margin: 0;
	padding: 1.4rem 0 0;
	border-top: 1px solid var(--a4f-line);
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.6rem 1.6rem;
}

.a4f-hero__facts li {
	position: relative;
	padding-left: 1.4rem;
	font-size: 0.92rem;
	color: var(--a4f-ink-soft);
}

.a4f-hero__facts li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.55em;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--a4f-tertiary);
}

.a4f-hero__media img {
	border-radius: var(--a4f-radius);
	box-shadow: var(--a4f-shadow-lg);
	object-fit: cover;
	width: 100%;
}

/*
 * Positioning context for the badge. The image is the only thing establishing
 * height here, so the badge can hang off its lower-left corner.
 */
.a4f-hero__frame {
	position: relative;
}

.a4f-hero__frame .wp-block-image {
	margin-bottom: 0;
}

.a4f-hero__badge {
	position: absolute;
	left: 0;
	bottom: 32px;
	z-index: 2;
	margin: 0;
	transform: translateX(-14px);
	background: var(--a4f-primary);
	color: var(--a4f-base);
	font-family: var(--a4f-font-heading);
	font-size: 1.02rem;
	line-height: 1.2;
	padding: 0.7rem 1.25rem;
	box-shadow: var(--a4f-shadow-md);
}

/* Keep the overhang inside the viewport on narrow screens. */
@media (max-width: 600px) {
	.a4f-hero__badge {
		transform: none;
		bottom: 20px;
		font-size: 0.92rem;
		padding: 0.6rem 1rem;
	}
}

@media (max-width: 781px) {
	.a4f-hero__facts {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   5. Letter
   ========================================================================== */

.a4f-letter {
	background: var(--a4f-surface);
}

.a4f-letter__quote {
	font-family: var(--a4f-font-accent);
	font-size: clamp(1.35rem, 2.6vw, 1.7rem);
	line-height: 1.42;
	color: var(--a4f-accent-soft);
	border: 0;
	margin: 0;
	padding: 0;
}

.a4f-letter__body p {
	max-width: 58ch;
	color: var(--a4f-ink-soft);
}

.a4f-letter__signoff {
	font-family: var(--a4f-font-accent);
	color: var(--a4f-ink);
}

.a4f-letter__media img {
	border-radius: var(--a4f-radius);
	box-shadow: var(--a4f-shadow-md);
	width: 100%;
	object-fit: cover;
}

.a4f-letter__media figcaption {
	font-size: 0.85rem;
	color: var(--a4f-ink-soft);
	text-align: left;
}

/* ==========================================================================
   6. Priorities (yard signs)
   ========================================================================== */

.a4f-signs {
	--a4f-sign-gap: clamp(1.5rem, 3vw, 1.75rem);
}

/*
 * Each card is a yard sign: a printed board on a stake. The stake is the
 * ::after below, which is why the grid carries extra row spacing.
 */
.a4f-sign {
	position: relative;
	background: var(--a4f-surface);
	border: 2px solid var(--a4f-primary);
	border-radius: 3px;
	box-shadow: var(--a4f-shadow-sm);
	height: 100%;
	transition: transform 0.35s ease, box-shadow 0.35s ease;
}

/* The stake the sign stands on. */
.a4f-sign::after {
	content: "";
	position: absolute;
	left: 50%;
	bottom: -18px;
	width: 3px;
	height: 18px;
	background: var(--a4f-primary);
	opacity: 0.45;
	transform: translateX(-50%);
}

.a4f-sign:hover {
	transform: rotate(-0.6deg) translateY(-3px);
	box-shadow: var(--a4f-shadow-md);
}

.a4f-sign:nth-child(even):hover {
	transform: rotate(0.6deg) translateY(-3px);
}

.a4f-sign__stance {
	display: inline-block;
	font-family: var(--a4f-font-body);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--a4f-page);
	background: var(--a4f-secondary);
	padding: 0.25rem 0.6rem;
	border-radius: 2px;
}

.a4f-sign__title {
	font-size: 1.28rem;
}

.a4f-sign__list {
	color: var(--a4f-ink-soft);
	font-size: 0.94rem;
	padding-left: 1.1em;
}

.a4f-sign__list li {
	margin-bottom: 0.35rem;
}

/* ==========================================================================
   7. Experience timeline
   ========================================================================== */

.a4f-experience {
	background: var(--a4f-surface);
}

.a4f-timeline {
	list-style: none;
	margin: 0;
	padding: 0;
	border-left: 2px solid var(--a4f-line);
}

.a4f-timeline__item {
	position: relative;
	padding: 0 0 1.9rem 1.75rem;
}

.a4f-timeline__item:last-child {
	padding-bottom: 0;
}

.a4f-timeline__item::before {
	content: "";
	position: absolute;
	left: -7px;
	top: 0.4em;
	width: 12px;
	height: 12px;
	border-radius: 50%;
	background: var(--a4f-primary);
	border: 2px solid var(--a4f-surface);
}

.a4f-timeline__year {
	display: block;
	font-family: var(--a4f-font-body);
	font-weight: 700;
	font-size: 0.82rem;
	letter-spacing: 0.06em;
	color: var(--a4f-secondary);
	margin-bottom: 0.2rem;
}

/* Set on a class rather than left to the heading element default, because the
   timeline entries are body-font labels, not display headings. */
.a4f-timeline__title {
	font-family: var(--a4f-font-body);
	font-weight: 700;
	font-size: 1.05rem;
	color: var(--a4f-ink);
	margin: 0 0 0.2rem;
}

.a4f-timeline__text {
	margin: 0;
	max-width: 46ch;
	font-size: 0.95rem;
	color: var(--a4f-ink-soft);
}

.a4f-experience__media img {
	border-radius: var(--a4f-radius);
	box-shadow: var(--a4f-shadow-md);
	width: 100%;
	object-fit: cover;
}

.a4f-experience__media figcaption {
	font-size: 0.85rem;
	color: var(--a4f-ink-soft);
	text-align: left;
}

/* ==========================================================================
   8. Endorsement logo wall
   ========================================================================== */

.a4f-logowall {
	align-items: center;
	justify-content: center;
}

/*
 * Endorsement logos are supplied in every possible form: transparent PNGs, dark
 * artwork drawn for white paper, and some with a white background baked into the
 * file. Inverting them individually breaks whichever group it wasn't tuned for,
 * so instead every logo sits on its own light chip. That gives all of them the
 * white-paper ground they were designed for, and any new endorsement drops in
 * without needing a per-logo rule.
 */
.a4f-logowall .wp-block-image {
	margin: 0;
	background: var(--a4f-base);
	border-radius: 6px;
	padding: 0.75rem 1rem;
	transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.a4f-logowall .wp-block-image img {
	height: 44px;
	width: auto;
	max-width: 140px;
	object-fit: contain;
	/* Slight desaturation so a dozen brand palettes read as one wall. */
	filter: grayscale(0.55);
	transition: filter 0.25s ease;
}

.a4f-logowall .wp-block-image:hover {
	transform: translateY(-2px);
	box-shadow: var(--a4f-shadow-sm);
}

.a4f-logowall .wp-block-image:hover img {
	filter: none;
}

/* ==========================================================================
   9. Get involved
   ========================================================================== */

.a4f-involve {
	background: var(--a4f-primary);
	color: var(--a4f-base);
}

.a4f-involve :is(h1, h2, h3, p) {
	color: var(--a4f-base);
}

.a4f-involve__eyebrow {
	color: var(--a4f-secondary);
}

.a4f-involve__card {
	background: var(--a4f-base);
	border-radius: var(--a4f-radius);
}

.a4f-involve__card :is(p, span, strong) {
	color: var(--a4f-page);
}

.a4f-involve__row {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 1rem;
	font-size: 0.95rem;
	padding-bottom: 0.85rem;
	border-bottom: 1px solid #e3dbef;
}

.a4f-involve__row:last-child {
	padding-bottom: 0;
	border-bottom: 0;
}

/* ==========================================================================
   10. Footer
   ========================================================================== */

.a4f-footer {
	background: var(--a4f-page);
	color: var(--a4f-base);
	border-top: 1px solid var(--a4f-line);
}

/*
 * Body copy default. The :not() guards keep this from outranking the brand and
 * heading modifiers below, which are single-class selectors and would otherwise
 * lose to this two-class rule.
 */
.a4f-footer :is(p, address, li):not([class*="a4f-footer__"]) {
	color: rgba(255, 255, 255, 0.72);
	font-size: 0.92rem;
}

.a4f-footer a {
	color: rgba(255, 255, 255, 0.85);
	text-decoration: none;
}

.a4f-footer a:hover {
	color: var(--a4f-secondary);
}

.a4f-footer__heading {
	font-family: var(--a4f-font-body);
	font-size: 0.78rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--a4f-secondary);
}

.a4f-footer__brand {
	font-family: var(--a4f-font-heading);
	font-size: 1.3rem;
	color: var(--a4f-base);
}

.a4f-footer__logo img {
	width: 56px;
	height: 56px;
	border-radius: 0;
}

.a4f-footer__legal {
	border-top: 1px solid rgba(255, 255, 255, 0.16);
}

.a4f-footer__legal p {
	color: rgba(255, 255, 255, 0.55);
	font-size: 0.8rem;
}

/* Footer link lists carry their own bullets in the block markup, so strip the
   default list styling rather than fighting it inline. */
.a4f-footer__list {
	list-style: none;
	margin: 0;
	padding-left: 0;
	display: flex;
	flex-direction: column;
	gap: 0.55rem;
}

/* ==========================================================================
   12. Page-load curtain
   ========================================================================== */

/*
 * Shown over the front page on load, then dismissed. Two rules matter here:
 *
 * 1. It is an overlay on top of the page, never a wrapper that hides it. The
 *    content is present and readable to crawlers the whole time.
 * 2. The dismissal is a CSS animation, not a JS callback. If the script fails
 *    or is blocked the curtain still lifts on its own, so the page can never be
 *    left permanently covered. main.js only lifts it sooner and tidies up.
 *
 * The logo fades in, holds, and the whole curtain fades out.
 */
.a4f-curtain {
	position: fixed;
	inset: 0;
	z-index: 9999;
	/*
	 * Flex rather than grid: with `place-items: center` a grid still leaves
	 * `align-content` at stretch, so the two rows expand to fill the viewport
	 * and the mark and bar end up pushed apart rather than sitting together.
	 */
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1.5rem;
	background: var(--a4f-page);
	animation: a4f-curtain-lift 0.7s var(--a4f-ease) 1.15s forwards;
}

.a4f-curtain__mark {
	width: clamp(120px, 21vw, 176px);
	height: auto;
	display: block;
	animation: a4f-curtain-mark 0.65s var(--a4f-ease) both;
}

.a4f-curtain.is-lifted {
	animation: none;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.45s var(--a4f-ease), visibility 0.45s;
}

/* Scroll is held only while the curtain is up. */
body.a4f-curtain-active {
	overflow: hidden;
}

@keyframes a4f-curtain-mark {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@keyframes a4f-curtain-lift {
	to { opacity: 0; visibility: hidden; }
}

/*
 * Reduced motion: the curtain still appears so there is no flash of unstyled
 * content, but nothing animates and it clears almost immediately.
 */
@media (prefers-reduced-motion: reduce) {
	.a4f-curtain {
		animation: a4f-curtain-lift 0.01s linear 0.2s forwards;
	}

	.a4f-curtain__mark {
		animation: none;
	}

	.a4f-header__logo img,
	.a4f-header {
		transition: none;
	}
}

/* ==========================================================================
   11. Motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	.a4f-sign,
	.a4f-logowall .wp-block-image img {
		transition: none;
	}

	.a4f-sign:hover,
	.a4f-sign:nth-child(even):hover {
		transform: none;
	}
}


/* ==========================================================================
   13. Interior pages

   Shared furniture for the pages below the homepage: Priorities, About and
   Get Involved. The homepage states each plank in a sentence; these pages
   carry the full detail, so the layout here favours reading length over the
   scannable card grid used on the front page.
   ========================================================================== */

/* --- Page masthead ------------------------------------------------------ */

.a4f-pagehead {
	border-bottom: 1px solid var(--a4f-line);
}

.a4f-pagehead__title {
	max-width: 18ch;
}

.a4f-pagehead__lede {
	color: var(--a4f-ink-soft);
	font-size: clamp(1.05rem, 1.6vw, 1.22rem);
	max-width: 54ch;
}

/* --- Callout ------------------------------------------------------------ */

/*
 * A single commitment lifted out of the running text. Uses the accent rule on
 * the leading edge rather than a filled panel, so it reads as emphasis within
 * the document instead of a separate card.
 */
.a4f-callout {
	border-left: 3px solid var(--a4f-tertiary);
}

.a4f-callout__text {
	color: var(--a4f-ink);
	font-size: clamp(1.02rem, 1.5vw, 1.14rem);
	max-width: 58ch;
}

/* --- Figures ------------------------------------------------------------ */

/*
 * Documentary photographs, not decoration: each one shows the commitment it
 * sits beside. Squared corners to match the rest of the site.
 */
.a4f-figure img,
.a4f-figure__image img,
.a4f-plank__image img {
	border-radius: var(--a4f-radius);
	box-shadow: var(--a4f-shadow-md);
	width: 100%;
	object-fit: cover;
}

.a4f-figure figcaption {
	color: var(--a4f-ink-soft);
	font-size: 0.86rem;
	line-height: 1.45;
	margin-top: 0.75rem;
	max-width: 40ch;
}

/* --- Platform planks ---------------------------------------------------- */

/*
 * Each plank is a heading column beside its commitments. Hairline rules
 * between them make the set read as one platform document rather than a stack
 * of unrelated cards, which is what the yard signs on the homepage are for.
 */
.a4f-plank {
	border-top: 1px solid var(--a4f-line);
}

/*
 * Below the column breakpoint the grid collapses to one column, so the gap
 * would double up with the heading's own bottom spacing. Grid gap handles the
 * separation in both directions instead.
 */
@media (min-width: 782px) {
	.a4f-plank__aside {
		/* Sits with its heading while a long list scrolls past. Offset clears
		   the sticky site header. */
		position: sticky;
		top: 6.5rem;
		align-self: start;
	}
}

.a4f-plank__image {
	margin-bottom: 0;
}

.a4f-plank__title {
	font-size: clamp(1.45rem, 2.4vw, 1.85rem);
	max-width: 16ch;
}

.a4f-plank__list {
	color: var(--a4f-ink-soft);
	font-size: 1.02rem;
	line-height: 1.55;
	list-style: none;
	padding-left: 0;
	max-width: var(--a4f-measure);
}

.a4f-plank__list li {
	position: relative;
	padding-left: 1.6rem;
	margin-bottom: 0.85rem;
}

/*
 * Custom marker rather than a list bullet: at this text size the default disc
 * sits too high and too close to sibling lines to read as a checklist of
 * commitments.
 */
.a4f-plank__list li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.58em;
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--a4f-tertiary);
}

.a4f-plank__list li:last-child {
	margin-bottom: 0;
}


/* ==========================================================================
   14. Endorsements

   Three tiers, each with its own treatment because the source material
   differs, not for variety's sake: elected officials arrive as names only,
   community endorsers as photographs of wildly varying kind, and
   organisations as logos.
   ========================================================================== */

/* --- Elected officials -------------------------------------------------- */

/*
 * Set typographically rather than as an empty portrait frame. No approved
 * likeness has been supplied for these endorsers, and a placeholder avatar
 * would read as a missing image; a name given room reads as deliberate, and
 * an office holder's name is the substance of the endorsement anyway.
 */
.a4f-official {
	border-left: 3px solid var(--a4f-secondary);
	height: 100%;
}

.a4f-official__name {
	font-family: var(--a4f-font-heading);
	font-size: clamp(1.5rem, 2.6vw, 2rem);
	line-height: 1.15;
	color: var(--a4f-ink);
	margin: 0;
}

.a4f-official__office {
	color: var(--a4f-secondary);
	font-size: 0.82rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	margin: 0;
}

/* --- Community endorsers ------------------------------------------------ */

.a4f-endorser img {
	border-radius: var(--a4f-radius);
	box-shadow: var(--a4f-shadow-md);
	width: 100%;
	/*
	 * The supplied photographs are a mix of headshots, full-length portraits,
	 * a family group and a selfie. A centred crop decapitates the full-length
	 * ones, so the frame is biased towards the top of the image where faces
	 * fall in all of them.
	 */
	object-fit: cover;
	object-position: center 20%;
}

.a4f-endorser__name {
	font-family: var(--a4f-font-heading);
	font-size: 1.12rem;
	line-height: 1.25;
	color: var(--a4f-ink);
	margin: 0;
	text-wrap: balance;
}


/* --- Organisation logo wall --------------------------------------------- */

/*
 * The homepage wall is a single row of nine; this page carries all of them, so
 * it wraps into a grid with room to breathe. Logos arrive on assorted grounds,
 * hence the white plate behind each rather than dropping them on the purple.
 */
.a4f-orgwall {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	gap: clamp(0.75rem, 2vw, 1.25rem);
	align-items: stretch;
}

.a4f-orgwall .wp-block-image {
	margin: 0;
	background: var(--a4f-base);
	border-radius: var(--a4f-radius);
	padding: clamp(0.9rem, 2vw, 1.25rem);
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 92px;
}

.a4f-orgwall .wp-block-image img {
	width: auto;
	max-width: 100%;
	max-height: 64px;
	object-fit: contain;
}


/* ==========================================================================
   15. About letter

   The About page carries Ariana's letter to the district in her own voice, so
   it is set as an actual sheet of paper laid on the purple rather than as more
   dark-on-dark body copy. The material change is the point: it marks the one
   place on the site where she speaks directly.
   ========================================================================== */

.a4f-letterhead {
	/*
	 * Ink derived from the page purple rather than a new hard-coded grey, so a
	 * change to the brand purple carries through to the letter's text.
	 */
	--letter-ink: var(--a4f-page);
	--letter-ink-soft: color-mix(in srgb, var(--a4f-page) 78%, var(--a4f-cream));

	background: var(--a4f-cream);
	color: var(--letter-ink-soft);
	border-radius: 2px;
	box-shadow: var(--a4f-shadow-lg);
}

/*
 * Every text colour inside the sheet has to be restated. The site's defaults
 * are light-on-dark, so an unstyled heading or link inherits near-white and
 * disappears against the cream.
 */
.a4f-letterhead :is(h2, h3, strong) {
	color: var(--letter-ink);
}

/*
 * Deliberately no max-width here. The reading measure is set by the sheet's own
 * contentSize instead, because core's constrained layout centres each child
 * with `margin-left/right: auto !important`. A per-paragraph max-width in `ch`
 * resolves differently for Open Sans and Prata, so each line would be centred
 * at a different width and the letter would not sit flush down its left edge.
 */
.a4f-letterhead p {
	color: var(--letter-ink-soft);
}

.a4f-letterhead a {
	color: var(--a4f-primary);
}

.a4f-letterhead__salutation {
	font-family: var(--a4f-font-accent);
	font-size: clamp(1.35rem, 2.4vw, 1.7rem);
	color: var(--letter-ink);
	margin: 0;
}

/* The one line that carries the weight of the letter. */
.a4f-letterhead__lead {
	font-family: var(--a4f-font-heading);
	font-size: clamp(1.25rem, 2.2vw, 1.55rem);
	line-height: 1.35;
	color: var(--letter-ink);
}

.a4f-letterhead__signature {
	font-family: var(--a4f-font-accent);
	font-size: clamp(1.5rem, 2.8vw, 2rem);
	line-height: 1.2;
	color: var(--letter-ink);
	margin: 0;
}

.a4f-letterhead__signoff {
	color: var(--letter-ink-soft);
	font-size: 0.95rem;
	margin: 0;
}

/* --- Moments strip ------------------------------------------------------ */

.a4f-moment img {
	border-radius: var(--a4f-radius);
	box-shadow: var(--a4f-shadow-md);
	width: 100%;
	object-fit: cover;
}

.a4f-moment figcaption,
.a4f-moment__caption {
	color: var(--a4f-ink-soft);
	font-size: 0.88rem;
	line-height: 1.45;
	margin-top: 0.7rem;
}


/* ==========================================================================
   16. Mobile navigation

   Core ships the overlay's mechanics (fixed positioning, show/hide, focus
   handling) and the Interactivity API drives the toggle, so none of that is
   reimplemented here. What core cannot know is the brand: left alone it paints
   the open menu `#fff` on `#000`, via

     .wp-block-navigation:not(.has-background) …is-menu-open { background: #fff }

   which on this dark purple site reads as a broken white sheet. Everything
   below is scoped under .a4f-header so it outranks that rule without
   !important, and so it cannot leak into any other navigation block.
   ========================================================================== */

/* --- Hamburger ---------------------------------------------------------- */

/*
 * Core's default is a 24px glyph with no padding, which is both visually thin
 * against the header and below the 44px minimum comfortable tap target.
 *
 * Scoped to core's own breakpoint. Core hides this button with
 *   @media (min-width:600px) { …-open:not(.always-shown) { display:none } }
 * at the same specificity as ours, so an unscoped `display:flex` here simply
 * wins on source order and leaves a hamburger sitting on the desktop header
 * beside the full link list.
 */
@media (max-width: 599px) {
	.a4f-header .wp-block-navigation__responsive-container-open {
		display: flex;
		align-items: center;
		justify-content: center;
		min-width: 44px;
		min-height: 44px;
		padding: 0;
		color: var(--a4f-ink);
		background: transparent;
		border: 0;
		border-radius: 3px;
		cursor: pointer;
	}
}

.a4f-header .wp-block-navigation__responsive-container-open svg {
	width: 28px;
	height: 28px;
	fill: currentColor;
}

.a4f-header .wp-block-navigation__responsive-container-open:hover {
	color: var(--a4f-secondary);
}

/* --- Open overlay ------------------------------------------------------- */

/*
 * These selectors deliberately mirror core's own, one class deeper. Core paints
 * the default overlay with
 *   .wp-block-navigation:not(.has-background) …is-menu-open:not(.disable-default-overlay)
 * which is five classes; a shorter selector loses to it and the menu opens
 * white. Matching its shape and prefixing .a4f-header wins on specificity
 * without resorting to !important, and keeps the override tied to this header.
 */
.a4f-header .wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
	background-color: var(--a4f-page);
	padding-top: clamp(1.5rem, 6vw, 3rem);
	padding-bottom: clamp(1.5rem, 6vw, 3rem);
}

.a4f-header .wp-block-navigation:not(.has-text-color) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
	/*
	 * Core forces `color: inherit !important` onto the items inside the open
	 * overlay, so the link colour has to be set here on the container and
	 * inherited down rather than applied to the anchors directly.
	 */
	color: var(--a4f-ink);
}

.a4f-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-close {
	max-width: 100%;
}

/* Close control, matched to the hamburger's tap target. */
.a4f-header .wp-block-navigation__responsive-container-close {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding: 0;
	color: var(--a4f-secondary);
	background: transparent;
	border: 0;
	cursor: pointer;
}

.a4f-header .wp-block-navigation__responsive-container-close svg {
	width: 26px;
	height: 26px;
	fill: currentColor;
}

/* --- Overlay links ------------------------------------------------------ */

/*
 * The menu is the whole screen once open, so the links are set at display size
 * rather than the header's small caps. Generous vertical rhythm keeps each one
 * an easy target.
 */
.a4f-header .is-menu-open .wp-block-navigation-item__content {
	font-family: var(--a4f-font-heading);
	font-size: clamp(1.6rem, 7vw, 2.1rem);
	line-height: 1.2;
	color: var(--a4f-ink);
	padding: 0.35rem 0;
	text-decoration: none;
}

.a4f-header .is-menu-open .wp-block-navigation-item__content:hover,
.a4f-header .is-menu-open .wp-block-navigation-item__content:focus-visible {
	color: var(--a4f-secondary);
}

/* A hairline between entries, so the list reads as a menu rather than a stack
   of loose headings. */
.a4f-header .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item {
	width: 100%;
	border-bottom: 1px solid var(--a4f-line);
	padding-block: 0.55rem;
}

.a4f-header .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item:last-child {
	border-bottom: 0;
}

.a4f-header .is-menu-open .wp-block-navigation__container {
	width: 100%;
	gap: 0;
}


/* ==========================================================================
   17. Forms

   Colour is NOT set here. Gravity Forms 3.0 prints a per-form <style> block
   after this stylesheet, scoped to `#gform_wrapper_N[data-form-index]`. That is
   an ID selector, so any label or button colour written here loses to it
   silently. Those values come from the `gform_default_styles` filter in
   functions.php instead, which is the input Gravity Forms generates that block
   from.

   What remains below is the handful of properties that block does not emit, so
   they are still ours to set.
   ========================================================================== */

.gform-theme--framework {
	/* Typography: the plugin ships its own stack, the site does not want it. */
	--gf-ctrl-font-family: var(--a4f-font-body);
	--gf-ctrl-label-font-family: var(--a4f-font-body);
	--gf-ctrl-btn-font-family: var(--a4f-font-body);

	/*
	 * Inputs read as ruled lines rather than filled boxes. The filter hands
	 * Gravity Forms the page purple so its lighten and darken maths has a real
	 * colour to work from, and this makes the field itself transparent.
	 */
	--gf-ctrl-bg-color: transparent;
	--gf-ctrl-bg-color-hover: transparent;
	--gf-ctrl-bg-color-focus: transparent;
	--gf-ctrl-color: var(--a4f-ink);
	--gf-ctrl-color-focus: var(--a4f-ink);
	--gf-ctrl-placeholder-color: color-mix(in srgb, var(--a4f-ink-soft) 55%, transparent);

	/* Focus lands on the campaign gold, matching links and buttons elsewhere. */
	--gf-ctrl-border-color-focus: var(--a4f-secondary);
	--gf-ctrl-border-color-hover: var(--a4f-accent-soft);

	/*
	 * Error states. The plugin signals errors in red, which is close to
	 * unreadable on deep purple, so validation borrows the campaign gold.
	 */
	--gf-ctrl-border-color-error: var(--a4f-secondary);
	--gf-ctrl-color-error: var(--a4f-ink);
	--gf-ctrl-bg-color-error: transparent;
}

/*
 * The form sits on the tinted band beside its intro copy. A slightly deeper
 * ground and a hairline separate it from that copy without turning it into a
 * boxed-off widget.
 */
.a4f-formcard {
	background: color-mix(in srgb, var(--a4f-page) 55%, transparent);
	border: 1px solid var(--a4f-line);
	border-radius: var(--a4f-radius);
	padding: clamp(1.25rem, 3.5vw, 2.5rem);
}

/* Confirmation shown after a successful submission. */
.gform_confirmation_message {
	color: var(--a4f-ink);
	font-family: var(--a4f-font-heading);
	font-size: 1.3rem;
}

/* The TCPA consent block, an HTML field below the checkboxes. */
.a4f-form__consent {
	color: var(--a4f-ink-soft);
	font-size: 0.8rem;
	line-height: 1.5;
	max-width: 60ch;
}

.a4f-form__consent a {
	color: var(--a4f-accent);
}
