/*
 * EU1144 Campaign — structural stylesheet.
 *
 * Campaign-neutral: it references palette and font tokens by theme.json PRESET
 * SLUG, never by value. The fallbacks below are deliberately neutral greys so
 * that a missing child theme is obvious rather than accidentally on-brand.
 *
 * House rules enforced here, not by convention:
 *   - border-radius: 0 everywhere
 *   - box-shadow: none everywhere
 *   - hairlines only, 1px, ink at 8-14%
 *   - every animated element renders its FINAL state under reduced motion
 */

/* ---------------------------------------------------------------- tokens -- */

:root {
	--eu-ink: var(--wp--preset--color--ink, #333);
	--eu-page: var(--wp--preset--color--page, #fdfdfd);
	--eu-stone: var(--wp--preset--color--stone, #e9e9e9);
	--eu-dark: var(--wp--preset--color--dark, #1c1c1c);
	--eu-accent: var(--wp--preset--color--accent, currentColor);
	--eu-paper: var(--wp--preset--color--paper, #fff);

	--eu-hair: color-mix(in srgb, var(--eu-ink) 10%, transparent);
	--eu-hair-strong: color-mix(in srgb, var(--eu-ink) 14%, transparent);

	--eu-container: 1280px;
	--eu-container-narrow: 760px;
	--eu-gutter: clamp(20px, 4vw, 40px);

	/* Section rhythm: 88 narrow, 112 medium, 140 wide. */
	--eu-rhythm: var(--wp--preset--spacing--88, 88px);

	/*
	 * Header region. Two static bar heights; never measured in JavaScript.
	 *
	 * --eu-region-h is the TOTAL height of the header region: brand bar plus
	 * hero, bar height included. It is bounded by the small viewport height, so
	 * the region can never be taller than what the reader sees on landing, and
	 * the mandatory signature is therefore always inside the first viewport
	 * (Charter p.20, "visible directly when user lands on the page").
	 *
	 * The signature's ARTWORK height is exactly one sixth of it. Because the
	 * region's declared height is also its rendered height — the bar is a grid
	 * track, not padding — the two can no longer disagree.
	 */
	--eu-header-h: 72px;
	/*
	 * The height of the element that actually STAYS FIXED, as distinct from the
	 * header region's own height. They are the same number today, because the
	 * whole bar is fixed. They stop being the same number the moment a two-tier
	 * bar exists, where the utility tier scrolls away and only the primary tier
	 * stays — at which point --eu-header-h remains 96/72 (it is load-bearing in
	 * the 1/6 signature arithmetic) while this one becomes the primary tier's
	 * height.
	 *
	 * Anchors offset against THIS value, not against the region height, so
	 * introducing the tier cannot silently break every in-page anchor on ten
	 * routes. Static values only, never measured in JavaScript.
	 */
	--eu-header-sticky-h: var(--eu-header-h);
	--eu-region-h: 100vh;
	--eu-signature-h: calc(var(--eu-region-h) / 6);

	--eu-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

	/*
	 * Paint order, declared once. Use these; do not invent a number.
	 *
	 * The lesson that produced this scale: the brand bar carried z-index 20 and
	 * was still painted over by a photograph. z-index only orders siblings
	 * WITHIN a stacking context, and .eu-header-region had isolation: isolate,
	 * which creates one — so the bar's 20 ordered it inside the header and never
	 * competed with page content at all. The header region itself sat at
	 * z-index auto, the same layer as any positioned element in <main>, and lost
	 * on document order. Two things had to be true, and only one looked wrong.
	 *
	 * The region now carries a real z-index, which both establishes the stacking
	 * context (a positioned element with a numeric z-index does) and lifts the
	 * whole region — bar, hero and mandatory signature — above page content.
	 * That is what makes the guarantee structural: a future positioned element
	 * in <main> cannot paint over the bar, the logo or the signature by
	 * appearing later in the document.
	 */
	--eu-z-media: 0;        /* photography inside a composed block   */
	--eu-z-scrim: 1;        /* the hero's directional scrim          */
	--eu-z-type: 2;         /* type set over photography             */
	--eu-z-signature: 3;    /* the mandatory signature, inside the region */
	--eu-z-region: 10;      /* the whole header region               */
	--eu-z-bar: 20;         /* the brand bar, inside the region      */
	--eu-z-skiplink: 100;   /* focused skip link, above everything   */
}

@media (min-width: 768px) {
	:root {
		/*
		 * The responsive specification asks for 112px here, but 112 is not on
		 * the project's own 4px spacing scale (…88, 120, 140, 180) and the scale
		 * rule is absolute: every vertical space comes from it. 120px is the
		 * nearest scale value and is used instead.
		 */
		--eu-rhythm: var(--wp--preset--spacing--120, 120px);
	}
}

/*
 * Small viewport height where supported: it is the height with browser chrome
 * expanded, which is the conservative reading of "visible on landing".
 */
@supports (height: 100svh) {
	:root {
		--eu-region-h: 100svh;
	}
}

@media (min-width: 1024px) {
	:root {
		--eu-header-h: 96px;
		/*
		 * The homepage header region is the brand bar plus the hero, treated as
		 * one region (see README, "the 1/6 rule"). Capped so it cannot grow
		 * absurd on very tall screens, and never larger than the viewport, so
		 * the signature cannot fall below the fold. At 1440x900 this resolves to
		 * exactly 900px, and the signature artwork to exactly 150px.
		 */
		--eu-region-h: min(100vh, 960px);
		--eu-rhythm: var(--wp--preset--spacing--140, 140px);
	}
}

@supports (height: 100svh) {
	@media (min-width: 1024px) {
		:root {
			--eu-region-h: min(100svh, 960px);
		}
	}
}

/* ------------------------------------------------------------- baselines -- */

html {
	scroll-behavior: auto;
	-webkit-text-size-adjust: 100%;
}

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

/*
 * Anchors never land underneath the fixed brand bar. CSS only.
 *
 * Keyed to the STICKY height rather than the region height: this now matters on
 * ten routes rather than one, because inner pages have in-page anchors too.
 */
[id] {
	scroll-margin-top: calc(var(--eu-header-sticky-h) + 24px);
}

body {
	background-color: var(--eu-page);
	color: var(--eu-ink);
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

/* Zero radius, zero shadow. No exceptions, including images and the emblem panel. */
*,
*::before,
*::after {
	border-radius: 0;
	box-shadow: none;
}

img,
svg,
video {
	max-width: 100%;
	height: auto;
}

figure {
	margin: 0;
}

:where(.eu-section, .eu-band) img {
	display: block;
}

/* ------------------------------------------------------------ typography -- */

.eu-eyebrow {
	font-family: var(--wp--preset--font-family--text, inherit);
	font-size: var(--wp--preset--font-size--eyebrow, 0.8125rem);
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	/*
	 * NOT the accent colour. Measured, --accent on --page is 2.66:1, well under
	 * the 4.5:1 that 13px text needs. The accent stays where it cannot fail a
	 * text-contrast requirement: hairline rules, fruit markers and the active
	 * navigation underline.
	 */
	color: var(--eu-ink);
	margin: 0 0 var(--wp--preset--spacing--16, 16px);
}

.eu-h2 {
	font-family: var(--wp--preset--font-family--display, inherit);
	margin: 0 0 var(--wp--preset--spacing--24, 24px);
	max-width: 22ch;
	text-wrap: balance;
}

.eu-lead {
	font-family: var(--wp--preset--font-family--display, inherit);
	font-size: var(--wp--preset--font-size--h3, 1.75rem);
	font-weight: 400;
	line-height: 1.25;
	margin: 0 0 var(--wp--preset--spacing--32, 32px);
	max-width: 34ch;
}

.eu-prose {
	max-width: 74ch;
}

.eu-prose__p {
	font-size: var(--wp--preset--font-size--body, 1.0625rem);
	line-height: 1.6;
	margin: 0 0 var(--wp--preset--spacing--24, 24px);
	max-width: 74ch;
}

.eu-prose__p:last-child {
	margin-bottom: 0;
}

/* Body links: ink with an accent underline. No colour change on hover. */
:where(.eu-prose, .eu-market, .eu-footer, .eu-funding) a:where(:not(.wp-element-button)) {
	color: inherit;
	text-decoration-line: underline;
	text-decoration-color: var(--eu-accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

:where(.eu-prose, .eu-market, .eu-footer, .eu-funding) a:where(:not(.wp-element-button)):hover {
	text-decoration-thickness: 2px;
}

/* --------------------------------------------------------------- layout --- */

.eu-section {
	padding-block: var(--eu-rhythm);
	padding-inline: var(--eu-gutter);
}

.eu-section--light {
	background-color: var(--eu-page);
	color: var(--eu-ink);
}

.eu-section--stone {
	background-color: var(--eu-stone);
	color: var(--eu-ink);
}

/* Dark register: warm off-white on warm near-black, never pure white. */
.eu-section--dark {
	background-color: var(--eu-dark);
	color: var(--eu-page);
}

.eu-section--dark .eu-eyebrow {
	color: var(--eu-page);
	opacity: 0.7;
}

.eu-section--dark .eu-rule--accent {
	border-top-color: color-mix(in srgb, var(--eu-page) 45%, transparent);
}

/* Bands that sit register-to-register get no padding at the seam. */
.eu-section--dark + .eu-section--dark {
	padding-top: 0;
}

.eu-section > * {
	max-width: var(--eu-container);
	margin-inline: auto;
}

.eu-main {
	padding-block-start: var(--eu-header-h);
}

/* On the homepage the header region already reserves the bar's height. */
.eu-header-region + .eu-main {
	padding-block-start: 0;
}

.eu-split {
	display: grid;
	gap: var(--wp--preset--spacing--32, 32px);
}

@media (min-width: 768px) {
	.eu-split {
		grid-template-columns: 4fr 7fr;
		gap: var(--wp--preset--spacing--64, 64px);
	}
}

.eu-split__aside {
	align-self: start;
}

/* ---------------------------------------------------------------- rules --- */

.eu-rule {
	border-top: 1px solid var(--eu-hair);
	block-size: 0;
	inline-size: 100%;
	margin-block-end: var(--wp--preset--spacing--16, 16px);
}

.eu-rule--accent {
	border-top-color: var(--eu-accent);
}

.eu-rule--hair {
	border-top-color: var(--eu-hair-strong);
}

/* 4px categorical marker. Decoration: the fruit name is always present as text. */
.eu-rule--marker {
	border-top-width: 4px;
	border-top-color: var(--eu-marker, var(--eu-accent));
	inline-size: 64px;
	margin-block-end: var(--wp--preset--spacing--24, 24px);
}

/* -------------------------------------------------------------- pillars --- */

.eu-pillars {
	gap: var(--wp--preset--spacing--32, 32px);
	margin-block-start: var(--wp--preset--spacing--64, 64px);
}

/*
 * 4-up wide, 2-up tablet, 1-up narrow. Core stacks its columns below 782px and
 * refuses to wrap above it, so both ends need an explicit rule for the 2-up
 * band. The 600px lower bound matches the navigation's overlay threshold.
 */
@media (min-width: 600px) and (max-width: 1023.98px) {
	.eu-pillars {
		flex-wrap: wrap;
	}

	.eu-pillars > .wp-block-column {
		flex-basis: calc(50% - var(--wp--preset--spacing--32, 32px) / 2) !important;
		flex-grow: 0;
	}
}

.eu-pillar__name {
	font-family: var(--wp--preset--font-family--text, inherit);
	font-size: var(--wp--preset--font-size--eyebrow, 0.8125rem);
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	margin: 0 0 var(--wp--preset--spacing--12, 12px);
	max-width: none;
}

.eu-pillar__text {
	font-size: var(--wp--preset--font-size--body, 1.0625rem);
	line-height: 1.6;
	margin: 0;
	max-width: 42ch;
}

/* ----------------------------------------------------------- photography -- */

.eu-photo {
	margin: 0;
	background-color: var(--eu-stone);
}

.eu-photo__img,
.eu-photo img {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/* A role with no media yet: a deliberate plate at the final proportions. */
.eu-photo--pending {
	background-color: var(--eu-stone);
	inline-size: 100%;
}

.eu-section--dark .eu-photo,
.eu-section--dark .eu-photo--pending {
	background-color: color-mix(in srgb, var(--eu-page) 8%, var(--eu-dark));
}

.eu-band {
	padding: 0;
	margin: 0;
}

.eu-band .eu-photo,
.eu-band .eu-photo--pending {
	inline-size: 100%;
}

.eu-band__caption {
	margin: var(--wp--preset--spacing--12, 12px) auto 0;
	max-width: var(--eu-container);
	padding-inline: var(--eu-gutter);
	font-size: var(--wp--preset--font-size--small, 0.9375rem);
	text-align: end;
	opacity: 0.8;
}

/* --------------------------------------------------------------- fruits --- */

/*
 * The full-bleed key visual. A direct child of the section, so it escapes both
 * the container cap and the page gutter and runs edge to edge — the negative
 * inline margin is exactly the section's own padding, so no viewport units are
 * involved and no scrollbar can be provoked.
 *
 * Hard edges only: no inset, no radius, no shadow, no card.
 */
.eu-fruit__key--bleed {
	max-inline-size: none;
	margin-inline: calc(var(--eu-gutter) * -1);
	margin-block-end: var(--wp--preset--spacing--48, 48px);
}

@media (min-width: 768px) {
	.eu-fruit__key--bleed {
		margin-block-end: var(--wp--preset--spacing--64, 64px);
	}
}

.eu-fruit__grid {
	display: grid;
	gap: var(--wp--preset--spacing--32, 32px);
	align-items: center;
}

.eu-fruit__detail {
	margin-block-start: var(--wp--preset--spacing--48, 48px);
}

/*
 * Where the key visual swaps to a native portrait source below 1024px, the
 * supporting detail is that same portrait frame, so showing it twice would
 * break the one-key-plus-one-detail parity rule. It is therefore carried on
 * wide viewports only.
 */
@media (max-width: 1023px) {
	.eu-fruit__detail--wide-only {
		display: none;
	}
}

@media (min-width: 768px) {
	.eu-fruit__grid {
		grid-template-columns: 1fr 1fr;
		gap: var(--wp--preset--spacing--64, 64px);
	}

	.eu-fruit--left .eu-fruit__text {
		order: 2;
	}

	.eu-fruit--left .eu-fruit__key {
		order: 1;
	}

	/*
	 * Full-bleed composition: one edge-to-edge photographic band with all type
	 * beneath it, on the register's own ground. Type is never set over this
	 * image — see the note in inc/pattern-parts.php for the measurement that
	 * settled it.
	 */
	.eu-fruit--full .eu-fruit__grid {
		grid-template-columns: 1fr;
	}

	.eu-fruit--full .eu-fruit__key--bleed .eu-photo {
		aspect-ratio: 21 / 9;
	}

	.eu-fruit__detail {
		margin-block-start: var(--wp--preset--spacing--88, 88px);
		max-inline-size: 72%;
	}

	.eu-fruit--left .eu-fruit__detail {
		margin-inline-start: auto;
	}
}

/*
 * Art-directed slots (a <picture> with a genuinely different source per art
 * direction) must switch their rendered aspect at the SAME 1024px breakpoint as
 * the block's <source media>, or a portrait original lands in a landscape box
 * and is hard-cropped. This bit the pears key visual in the 768-1023px band,
 * where the narrow portrait source was being served into a 21:9 frame.
 *
 * .eu-adi carries block-size:100%, so these slots also need a declared aspect
 * to have any height at all.
 */
.eu-fruit__key .eu-adi,
.eu-fruit__key--bleed .eu-adi,
.eu-fruit__detail .eu-adi {
	aspect-ratio: 4 / 5;
}

@media (min-width: 1024px) {
	.eu-fruit--full .eu-fruit__key .eu-adi,
	.eu-fruit__key--bleed .eu-adi,
	.eu-fruit__detail .eu-adi {
		aspect-ratio: 21 / 9;
	}

	.eu-fruit:not(.eu-fruit--full) .eu-fruit__key .eu-adi {
		aspect-ratio: 4 / 5;
	}
}

.eu-fruit__tagline {
	font-family: var(--wp--preset--font-family--display, inherit);
	font-weight: 400;
	font-size: var(--wp--preset--font-size--h3, 1.75rem);
	line-height: 1.25;
	margin: 0 0 var(--wp--preset--spacing--24, 24px);
	max-width: 28ch;
}

/* -------------------------------------------------------------- markets --- */

.eu-markets {
	display: grid;
	gap: var(--wp--preset--spacing--48, 48px);
	margin-block-start: var(--wp--preset--spacing--64, 64px);
}

/*
 * TWO COLUMNS ONLY FROM 1180px, and the threshold is MEASURED rather than
 * assumed.
 *
 * Phase 1 switched at 768px. Measured in a real browser at final font metrics,
 * on the route that carries the attributed market copy, the two-column measure
 * yields:
 *
 *     768px   ->  36 characters per line
 *     900px   ->  47
 *    1023px   ->  54
 *    1024px   ->  54
 *    1180px   ->  63
 *
 * The specified body measure is 60-74 characters. So 768px was a live defect —
 * 36 characters is a column of broken phrases, not prose — and 1024px, the
 * default ruling, still measures 54 and would have been wrong too. Only 1180px
 * lands inside the target.
 *
 * This is the one place in this build where a specified default was overridden
 * by measurement, which is precisely what the specification asked for: "it must
 * not stand on the assumption that it is fine."
 *
 * It also happens to coincide with the navigation's overlay breakpoint, so the
 * page has one behavioural threshold rather than two.
 */
@media (min-width: 1180px) {
	.eu-markets {
		grid-template-columns: 1fr 1fr;
		gap: var(--wp--preset--spacing--64, 64px);
	}
}

.eu-market__label {
	font-family: var(--wp--preset--font-family--text, inherit);
	font-size: var(--wp--preset--font-size--eyebrow, 0.8125rem);
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	line-height: 1.3;
	margin: 0 0 var(--wp--preset--spacing--24, 24px);
	max-width: 28ch;
}

/*
 * Attributions and dietary-guideline references are content obligations, not
 * clutter: they are styled as distinct structural elements so that they read as
 * part of the record rather than as small print.
 */
.eu-attribution,
.eu-reference {
	font-size: var(--wp--preset--font-size--small, 0.9375rem);
	line-height: 1.55;
	margin: var(--wp--preset--spacing--24, 24px) 0 0;
	max-width: 60ch;
}

.eu-reference {
	border-top: 1px solid var(--eu-hair-strong);
	padding-block-start: var(--wp--preset--spacing--12, 12px);
}

/* ------------------------------------------------------------- channels --- */

.eu-channels {
	list-style: none;
	margin: 0;
	padding: 0;
}

.eu-channels li {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--8, 8px) var(--wp--preset--spacing--24, 24px);
	padding-block: var(--wp--preset--spacing--12, 12px);
	border-top: 1px solid var(--eu-hair-strong);
}

.eu-channel__label {
	flex: 0 0 8rem;
	font-size: var(--wp--preset--font-size--eyebrow, 0.8125rem);
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	opacity: 0.7;
}

.eu-channel__name {
	font-size: var(--wp--preset--font-size--body, 1.0625rem);
}

/* --------------------------------------------------------- header region -- */

/*
 * The header region is the brand bar plus the hero, composed and treated as one
 * region: one contiguous topmost block above the body content. The mandatory
 * signature is sized as 1/6 of its height at every breakpoint.
 *
 * The bar is fixed rather than sticky BECAUSE of that composition: a sticky
 * element cannot escape its containing block, so a sticky bar inside the header
 * region would unstick as soon as the hero scrolled past. A static bar height
 * plus a matching region padding keeps cumulative layout shift at zero.
 */
.eu-header-region {
	position: relative;
	display: grid;
	/*
	 * Three tracks: a spacer the exact height of the fixed brand bar, the hero,
	 * and — on narrow viewports, where it sits in the flow — the signature.
	 *
	 * The bar's height is a TRACK, not padding on the region. Padding would be
	 * added outside a content-box height and the region would render one bar
	 * taller than declared, which would push the signature below the fold and
	 * make it smaller than one sixth of the rendered region. Both were real
	 * defects; a track cannot reintroduce them, and box-sizing is pinned below
	 * so that a future padding cannot either.
	 *
	 * The hero track is minmax(0, 1fr): if hero content ever exceeds the space,
	 * it overflows within its own track instead of displacing the signature.
	 * Compliance geometry wins over type.
	 */
	grid-template-rows: var(--eu-header-h) minmax(0, 1fr) auto;
	block-size: var(--eu-region-h);
	background-color: var(--eu-page);
	/*
	 * Replaces isolation: isolate. Both establish a stacking context, but a
	 * numeric z-index also places the region ABOVE page content, which
	 * isolation alone did not. See the scale above.
	 */
	z-index: var(--eu-z-region);
}

.eu-header-region,
.eu-header-region > * {
	box-sizing: border-box;
}

/* Explicit placement: the fixed bar is out of flow and claims no track. */
.eu-header-region > .eu-hero {
	grid-row: 2;
}

.eu-header-region > .eu-signature {
	grid-row: 3;
}

.eu-bar {
	position: fixed;
	inset-block-start: 0;
	inset-inline: 0;
	z-index: var(--eu-z-bar);
	block-size: var(--eu-header-h);
	padding: 0 var(--eu-gutter);
	background-color: var(--eu-page);
	border-bottom: 1px solid transparent;
	transition: border-color 180ms ease-out;
}

.eu-bar.is-scrolled {
	border-bottom-color: var(--eu-hair);
}

/*
 * Optional condense (motion behaviour 4). Free of layout cost here because the
 * bar is fixed and the header region's padding is static: nothing below it
 * moves, so cumulative layout shift stays at zero.
 */
@media (min-width: 1024px) {
	.eu-bar.is-condensed {
		block-size: 72px;
	}

	.eu-bar.is-condensed .wp-block-site-logo img,
	.eu-bar.is-condensed .eu-logo img {
		inline-size: 120px;
	}
}

@media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
	.eu-bar {
		transition: border-color 180ms ease-out, block-size 200ms ease-out;
	}

	.eu-bar .wp-block-site-logo img,
	.eu-bar .eu-logo img {
		transition: inline-size 200ms ease-out;
	}
}

.eu-bar__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--24, 24px);
	block-size: 100%;
	max-inline-size: var(--eu-container);
	margin-inline: auto;
}

/* Clear space around the lockup: at least the cap-height of the wordmark. */
.eu-bar .wp-block-site-logo,
.eu-bar .eu-logo {
	display: flex;
	align-items: center;
	padding-block: 12px;
	flex: 0 0 auto;
}

.eu-bar .wp-block-site-logo img,
.eu-bar .eu-logo img {
	display: block;
	/*
	 * Minimum reproduction width for a three-line lockup is 110px.
	 * The upper bound is 150px, not 160px: at 150px the lockup is 68.9px tall,
	 * which keeps the EU emblem lockup (76px at wide viewports) at least as
	 * prominent as the campaign logo anywhere on the page — R-08, measured.
	 */
	inline-size: clamp(118px, 11vw, 150px);
	block-size: auto;
}

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

/*
 * The hero has three parts:
 *
 *   .eu-hero__media    the photograph
 *   .eu-hero__display  eyebrow + h1
 *   .eu-hero__plinth   standfirst, and — at its bottom-right — the mandatory
 *                      "Enjoy, it's from Europe" signature
 *
 * The plinth exists for a measured compliance reason. The specified hero frame
 * carries mid-green out-of-focus foliage and a warm out-of-focus fruit exactly
 * where the Charter puts the stamp: the orange signature measures 1.12:1
 * against that ground, where a graphical object needs 3:1. The Charter's own
 * remedy is to change the crop or the image, never the stamp; no crop of this
 * frame yields a clean corner, and the imagery selection is approved, so the
 * signature is instead seated on solid --page at the foot of the header region
 * — the same structure the specification already adopts for narrow viewports,
 * where it measures 3.32:1. The 1/6 size is still computed on the FULL header
 * region, never on the plinth alone.
 */

.eu-hero {
	position: relative;
	display: grid;
	grid-template-rows: minmax(88px, 1fr) auto auto;
	min-block-size: 0;
	padding: 0;
	max-inline-size: none;
	background-color: var(--eu-page);
}

.eu-hero__media {
	position: relative;
	overflow: hidden;
	background-color: var(--eu-stone);
	min-block-size: 0;
}

.eu-hero__media .eu-adi,
.eu-hero__media .eu-adi__img {
	block-size: 100%;
	inline-size: 100%;
}

.eu-hero__display,
.eu-hero__plinth {
	position: relative;
	z-index: var(--eu-z-type);
	max-inline-size: none;
	padding-inline: var(--eu-gutter);
	background-color: var(--eu-page);
	color: var(--eu-ink);
}

.eu-hero__display {
	padding-block-start: var(--wp--preset--spacing--24, 24px);
}

.eu-hero__plinth {
	padding-block: var(--wp--preset--spacing--12, 12px) var(--wp--preset--spacing--16, 16px);
}

.eu-hero__eyebrow {
	margin-block-end: var(--wp--preset--spacing--12, 12px);
}

/*
 * Selector deliberately two classes deep: theme.json emits element styles as
 * ":root :where(h1)", which carries the same specificity as a single class, so
 * a one-class selector would depend on stylesheet order to win. This does not.
 */
.eu-hero .eu-hero__title {
	font-family: var(--wp--preset--font-family--display, inherit);
	/*
	 * The hero headline is sized to its FIELD, not to the display token.
	 *
	 * The approved headline is 70 characters and the type field is the left 40%
	 * of the viewport. At the token's 7vw / 6.5rem the sentence set six lines
	 * ~101px tall, overflowed the hero upwards and pushed the eyebrow under the
	 * fixed brand bar, where it was clipped. At 4.2vw / 4.5rem it sets four
	 * lines and the whole display block clears the bar at every breakpoint.
	 * Below 640px the 2rem floor is what keeps the header block — signature
	 * included — inside the first viewport with real browser chrome present.
	 * Compliance geometry and legibility both outrank the type ceiling.
	 */
	font-size: clamp(2rem, 4.2vw, 4.5rem);
	line-height: 1.05;
	letter-spacing: -0.02em;
	margin: 0;
	max-inline-size: 22ch;
	text-wrap: balance;
}

.eu-hero__standfirst {
	font-size: var(--wp--preset--font-size--body, 1.0625rem);
	line-height: 1.5;
	margin: 0;
	max-inline-size: 62ch;
}

@media (min-width: 640px) {
	.eu-hero__standfirst {
		font-size: var(--wp--preset--font-size--lead, 1.1875rem);
	}
}

@media (min-width: 1024px) {
	/*
	 * Wide viewports: full-bleed photograph with the display type in the left
	 * 40%, over a single left-anchored directional scrim, and the solid plinth
	 * beneath.
	 */
	.eu-hero {
		--eu-plinth-h: calc(var(--eu-signature-h) + var(--wp--preset--spacing--48, 48px));

		/*
		 * The type field and the scrim are derived from ONE set of values, so
		 * they cannot drift apart. Both are container-aligned, not
		 * viewport-aligned, because everything else on the page is.
		 *
		 * The field's right edge is held at or before 46% of the viewport width.
		 * Without that cap the field is anchored to the centred container, so
		 * above ~1600px it slides rightwards into the sunlit fruit — which is
		 * what made the headline unreadable at 1600, 1920 and 2560 while 1440
		 * passed. The cap changes nothing at or below 1440px, where 40% is
		 * already the smaller value.
		 */
		--eu-hero-field-start: max(var(--eu-gutter), calc((100% - var(--eu-container)) / 2));
		--eu-hero-field-w: max(320px, min(40%, calc(46% - var(--eu-hero-field-start))));
		--eu-hero-scrim-w: calc(var(--eu-hero-field-start) + var(--eu-hero-field-w) * 1.55);

		grid-template-rows: minmax(0, 1fr) minmax(var(--eu-plinth-h), auto);
	}

	/* The photograph fills the hero above the plinth. */
	.eu-hero__media {
		position: absolute;
		inset: 0 0 var(--eu-plinth-h) 0;
		z-index: var(--eu-z-media);
	}

	/*
	 * The directional scrim. One left-anchored gradient, monotonic left to
	 * right, and nothing else: no full-frame darkening, no shape or panel
	 * behind the text, no shadow.
	 *
	 * Its box is keyed to the type field (--eu-hero-scrim-w = field start plus
	 * 1.55 field widths), so the ramp tracks the type at every width instead of
	 * being keyed to the viewport. It reaches zero at 58-68% of the width
	 * depending on breakpoint, so the right third of the frame — the fruit — and
	 * the whole bottom-right stamp reserve carry no scrim gradient at all. The
	 * plinth is excluded by the bottom inset, so the signature always sits on
	 * unmodified solid --page.
	 *
	 * The stop values are measured, not chosen. Every pixel of both text
	 * bounding boxes was composited against the real photograph and tested for
	 * WCAG contrast against --page at 1024, 1280, 1366, 1440, 1512, 1600, 1920
	 * and 2560 wide. The specification's single 0.45 ramp left 2.0% of the
	 * headline field and up to 6.5% of the eyebrow field below threshold, worst
	 * case 1.91:1 where 3:1 is required. These stops clear both at every width
	 * with the worst pixel at 3.67:1. Do not shallow them without re-measuring.
	 */
	.eu-hero::before {
		content: "";
		position: absolute;
		inset-block: 0 var(--eu-plinth-h);
		inset-inline-start: 0;
		inline-size: var(--eu-hero-scrim-w);
		z-index: var(--eu-z-scrim);
		background-image: linear-gradient(
			to right,
			rgba(20, 24, 18, 0.64) 0%,
			rgba(20, 24, 18, 0.5) 26%,
			rgba(20, 24, 18, 0.46) 66%,
			rgba(20, 24, 18, 0.16) 84%,
			rgba(20, 24, 18, 0) 100%
		);
		pointer-events: none;
	}

	/*
	 * In the flow, not absolutely positioned. Bottom-aligned by flex rather than
	 * by an inset, so the block can never grow upwards into the fixed brand bar:
	 * its top edge is the top of its own track, which begins where the bar ends.
	 */
	.eu-hero__display {
		grid-row: 1;
		align-self: stretch;
		display: flex;
		flex-direction: column;
		justify-content: flex-end;
		min-block-size: 0;
		inline-size: var(--eu-hero-field-w);
		margin-inline-start: var(--eu-hero-field-start);
		padding: var(--wp--preset--spacing--24, 24px) 0 var(--wp--preset--spacing--48, 48px);
		background-color: transparent;
		color: var(--eu-page);
		z-index: var(--eu-z-type);
	}

	.eu-hero__plinth {
		grid-row: 2;
	}

	.eu-hero__eyebrow {
		color: var(--eu-page);
		/*
		 * The box hugs the tracked caps instead of stretching across the field.
		 * The label is ~210px of ink in a 576px field, so a full-width box put
		 * 300px of bright bokeh inside a text bounding box that contains no
		 * text — which is measured as a contrast failure and is not one. This
		 * makes the measured box the real one.
		 */
		align-self: flex-start;
		inline-size: fit-content;
	}

	/*
	 * No display-token override here. The token's ceiling (7vw / 6.5rem) is for
	 * a short headline in a full-width field; this headline is 70 approved
	 * characters in a 40% field, and the token made it overflow the hero and
	 * clip the eyebrow under the fixed bar. The field-sized clamp in the base
	 * rule governs at every breakpoint.
	 */

	.eu-hero__plinth {
		display: flex;
		align-items: flex-end;
		padding-block: var(--wp--preset--spacing--32, 32px);
	}

	.eu-hero__standfirst {
		max-inline-size: 62ch;
		margin-inline-start: max(0px, calc((100% - var(--eu-container)) / 2));
		/* Keep the standfirst clear of the signature's clear space. */
		padding-inline-end: calc(var(--eu-signature-h) * 0.6203 + var(--eu-signature-h) * 0.42);
	}
}

/* ------------------------------------------------------------ skip link --- */

/*
 * WordPress 7.x renders the skip link server-side as the first element of the
 * document and points it at <main>, using .skip-link.screen-reader-text. It is
 * therefore already first in tab order with JavaScript disabled; all it needs
 * from us is a visible, high-contrast appearance when focused (see
 * .screen-reader-text:focus below) and a focusable target, which the render
 * filter in inc/nav-anchors.php guarantees with tabindex="-1" on <main>.
 */

/* --------------------------------------------------------------- focus ---- */

/*
 * FUNCTIONAL COLOUR MEETS CONTRAST. --accent measures 2.60:1 on --page, which
 * fails SC 1.4.11's 3:1 for a non-text indicator, so the focus ring is INK —
 * 11.3:1 on --page and 9.8:1 on --stone. The earlier specification prescribed
 * an accent ring AND required >=3:1, and those two instructions cannot both
 * hold; accessibility wins and the accent moves to decoration.
 *
 * The brand cue is kept as a 1px accent ring INSIDE the ink ring via box-shadow,
 * never replacing it. box-shadow is globally reset to none in this stylesheet,
 * so it is re-declared here deliberately and only for the focus state: it is an
 * outline companion, not a shadow, and it carries no offset or blur.
 */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--eu-ink);
	outline-offset: 3px;
	box-shadow: 0 0 0 1px var(--eu-accent);
}

.eu-section--dark :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
.eu-plate--dark :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline-color: var(--eu-page);
	box-shadow: none;
}

/* The compliance band is stone: ink at 9.8:1 is correct there too. */
.eu-funding :where(a, button, [tabindex]):focus-visible {
	outline-color: var(--eu-ink);
}

/* ------------------------------------------------- assistive text helper -- */

.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	clip-path: none;
	height: auto;
	width: auto;
	margin: 0;
	padding: 12px 16px;
	inset-block-start: 8px;
	inset-inline-start: 8px;
	background-color: var(--eu-page);
	color: var(--eu-ink);
	font-size: var(--wp--preset--font-size--nav, 0.8125rem);
	letter-spacing: 0.1em;
	text-transform: uppercase;
	/* Ink, not accent: see the focus note above. */
	outline: 2px solid var(--eu-ink);
	outline-offset: 2px;
	z-index: var(--eu-z-skiplink);
}

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

.eu-footer {
	background-color: var(--eu-page);
	color: var(--eu-ink);
	padding-block: var(--wp--preset--spacing--64, 64px);
	padding-inline: var(--eu-gutter);
}

/*
 * The footer is the portal's SECOND NAVIGATION SURFACE: identity, then three
 * columns of routes and channels. Four columns at wide widths, two at tablet,
 * one stacked below.
 */
.eu-footer__inner {
	max-inline-size: var(--eu-container);
	margin-inline: auto;
	display: grid;
	gap: var(--wp--preset--spacing--48, 48px);
}

@media (min-width: 600px) {
	.eu-footer__inner {
		grid-template-columns: 1fr 1fr;
	}
}

@media (min-width: 1024px) {
	.eu-footer__inner {
		grid-template-columns: 1.2fr 1fr 1fr 1.2fr;
		gap: var(--wp--preset--spacing--32, 32px);
	}
}

/*
 * Column labels are eyebrow PARAGRAPHS, never headings: footer furniture must
 * not enter the document's heading tree.
 */
.eu-footer__column .eu-eyebrow {
	margin-block-end: var(--wp--preset--spacing--16, 16px);
}

.eu-footer__links {
	list-style: none;
	margin: 0;
	padding: 0;
}

.eu-footer__links li {
	margin: 0;
}

.eu-footer__links a {
	display: inline-block;
	min-block-size: 44px;
	padding-block: 11px;
	font-family: var(--wp--preset--font-family--text, inherit);
	font-size: var(--wp--preset--font-size--eyebrow, 0.8125rem);
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--eu-ink) 74%, var(--eu-page));
	text-decoration-line: underline;
	text-decoration-color: transparent;
	text-underline-offset: 6px;
}

.eu-footer__links a:hover,
.eu-footer__links a:focus-visible {
	color: var(--eu-ink);
	text-decoration-color: var(--eu-accent);
}

.eu-footer__identity img {
	display: block;
	/* Bounded so the EU emblem stays at least as prominent. R-08. */
	inline-size: clamp(120px, 14vw, 150px);
	block-size: auto;
}

.eu-footer__meta {
	max-inline-size: var(--eu-container);
	margin: var(--wp--preset--spacing--48, 48px) auto 0;
	padding-block-start: var(--wp--preset--spacing--24, 24px);
	border-top: 1px solid var(--eu-hair);
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--16, 16px) var(--wp--preset--spacing--32, 32px);
	font-size: var(--wp--preset--font-size--small, 0.9375rem);
}

/* An empty region until partner logos are supplied and re-measured. */
.eu-footer__partners:empty {
	display: none;
}

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

/*
 * Two behaviours live here: the hero scale-settle and the section
 * fade-and-rise. Both are gated on the .eu-js class, which is set by a single
 * inline statement in the document head, so that without JavaScript — and
 * under reduced motion — content renders in its FINAL state and is never
 * left invisible.
 */

@media (prefers-reduced-motion: no-preference) {
	.eu-js .eu-reveal > * {
		opacity: 0;
		transform: translateY(16px);
		transition: opacity 420ms var(--eu-ease), transform 420ms var(--eu-ease);
	}

	.eu-js .eu-reveal > *:nth-child(2) {
		transition-delay: 60ms;
	}

	.eu-js .eu-reveal > *:nth-child(3) {
		transition-delay: 120ms;
	}

	.eu-js .eu-reveal > *:nth-child(n + 4) {
		transition-delay: 180ms;
	}

	.eu-js .eu-reveal.is-revealed > * {
		opacity: 1;
		transform: none;
	}

	.eu-js .eu-hero__media .eu-adi__img {
		animation: eu-hero-settle 900ms var(--eu-ease) both;
	}
}

@keyframes eu-hero-settle {
	from {
		transform: scale(1.03);
	}

	to {
		transform: scale(1);
	}
}

/*
 * Mandatory EU elements never animate, under any circumstances.
 */
.eu-signature,
.eu-signature__img,
.eu-funding,
.eu-funding * {
	animation: none !important;
	transition: none !important;
	transform: none !important;
	opacity: 1 !important;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	.eu-reveal > * {
		opacity: 1 !important;
		transform: none !important;
	}
}

/* ---------------------------------------------------------------- print --- */

@media print {
	.eu-bar,
	.wp-block-navigation {
		display: none;
	}

	.eu-header-region {
		block-size: auto;
		padding-block-start: 0;
	}

	.eu-section {
		padding-block: 12mm;
	}

	.eu-section--dark {
		background: #fff !important;
		color: #000 !important;
	}
}

/*
 * An anchor alias: a second permanent address for a section that already has
 * one. Zero height, no content, aria-hidden — it exists so that a link written
 * against the approved heading's own slug resolves instead of failing silently.
 * See eu1144_anchor_alias() for why fragments can never be retired.
 *
 * It needs no scroll-margin of its own: the [id] rule above already gives it
 * the same offset as every other anchor target.
 */
.eu-anchor-alias {
	block-size: 0;
	overflow: hidden;
}
