/*
Theme Name: EPAS Style
Template: twentytwentythree
Version: 0.3.9
Author: EPAS / EPLO UK
Description: Child theme carrying the new EPAS brand (EU/European Parliament colours and Europea typeface) on top of Twenty Twenty-Three. All design tokens live in theme.json — avoid adding per-block custom CSS here so the design stays centralised.
*/

/* ---- Typography per EP Youth VI Playbook v3 ----
   Headline (h1): Europea Ultra, uppercase, leading = font size - 3pt
   Subheading (h2-h6): Europea Bold, sentence case, leading = font size + 0.5pt
   Body copy: Europea Regular, sentence case, leading = font size + 2pt
   Weight/case live in theme.json; leading is set here since theme.json
   line-height doesn't support the playbook's "font size ± Npt" formula. */
h1 {
	font-family: "Europea", sans-serif;
	font-weight: 900;
	text-transform: uppercase;
	line-height: calc(1em - 3pt);
}
h2, h3, h4, h5, h6 {
	font-family: "Europea", sans-serif;
	font-weight: 700;
	text-transform: none;
	line-height: calc(1em + 0.5pt);
}
body, p, li, blockquote {
	line-height: calc(1em + 2pt);
}

/* The post-title block is pinned to font-weight:400 by the parent theme via
   `:root :where(.wp-block-post-title)`, which outranks the bare `h1` and the
   theme.json heading rules above. The pin applies at every heading level, so the
   treatment has to be restated at block level for each level actually used. */
h1.wp-block-post-title {
	font-weight: 900;
	text-transform: uppercase;
}

/* Card titles (news/archive h3) and search-result titles (h2): playbook
   subheading rule — Europea Bold, sentence case. */
h2.wp-block-post-title,
h3.wp-block-post-title {
	font-weight: 700;
}

/* ---- Hero / page-title image sits flush against the header ----
   The parent theme puts --wp--style--block-gap (24px) between every direct child
   of .wp-site-blocks, which opens a white stripe between the header and the hero
   (homepage) or the title cover (pages/posts). Every one of those sections carries
   its own padding, so the extra gap just reads as a bug. `header + *` rather than
   `:first-child` because the header itself is the first child. */
.wp-site-blocks > header + * {
	margin-block-start: 0;
}

/* Same gap, other end of the hero: the constrained-layout rule margins the block
   after the cover, leaving a white band between the hero and the coloured section
   below it. Only matters where the next section has a background of its own. */
.wp-block-post-content > .wp-block-cover:first-child + * {
	margin-block-start: 0;
}

/* ---- Photo scrim: text over imagery (EP Youth VI Playbook v3, pp.25-28) ----
   The playbook's ladder is: 1) fix with colour, 2) fix with a vignette/gradient
   that "should look natural", 3) drop shadow, 4) highlight behind the text. White
   text on unpredictable photography can't be fixed by colour alone, so this is
   step 2. We stop there deliberately: the gradient alone clears 4.5:1, and the
   playbook only escalates when a step fails to reach the ratio.

   Why a gradient rather than a flat dim: a flat overlay has to be dark enough for
   the image's brightest pixel, so it drains colour from the entire photo and still
   fails on blown highlights. Measured across 30 live featured images, the previous
   50% reflex-blue wash missed 4.5:1 on all 30 (worst 2.51:1) - blue's own
   luminance is too high to darken anything much.

   Why it's anchored to the text and not to the cover: titles wrap to anywhere
   between one and four lines (the longest on the site is 101 characters). A
   fixed-height gradient either fails the tall ones or needlessly muddies the short
   ones. Starting the fade 72px above the inner container - whatever height that
   turns out to be - keeps the text on >=0.62 alpha, which is >=5.9:1 against white
   on any image however bright, while everything above the fade keeps full colour.

   Geometry: full-bleed via 100vw, safe because the cover is overflow:clip; z-index
   -1 places it inside the inner container's stacking context, above the image
   (z-index 0) and below the text.

   NB: any cover using this class needs padding-top >= 72px, so the fade always has
   room above the text. With less, a title tall enough to fill the cover would push
   the fade past the top edge, where overflow:clip truncates it and the first line
   ends up on weak alpha. The templates set 72px; it costs nothing visually because
   the content is bottom-aligned. */
.wp-block-cover.epas-photo-scrim .wp-block-cover__inner-container::before {
	content: "";
	position: absolute;
	left: 50%;
	margin-left: -50vw;
	width: 100vw;
	top: -72px;
	bottom: -100vh; /* over-extends; clipped to the cover's bottom edge */
	z-index: -1;
	pointer-events: none;
	background: linear-gradient(
		to bottom,
		rgba(0, 0, 0, 0) 0,
		rgba(0, 0, 0, 0.62) 72px,
		rgba(0, 0, 0, 0.8) 420px
	);
}

/* ---- Covers with no featured image: fall back to the flat banner ----
   page.html's cover is useFeaturedImage, and 16 of 38 published pages have no
   featured image. Those render an empty 480px cover - no <img> at all, and a
   dim span at opacity 0 - with the scrim above painting a grey-to-black
   gradient straight onto the white page. The title stays legible (the gradient
   darkens white to ~5.9:1) but it reads as a bug.

   Most of those 16 are utility and logged-in dashboard pages - evidence tables,
   password reset, policies - which don't want hero photography at all. So the
   no-image case degrades to the same flat Reflex Blue band archive.html and
   404.html already use, rather than being given an image it has no use for.
   One rule covers all 16 and any future page without one.

   Keyed on the absence of the background image: WP emits no
   img.wp-block-cover__image-background whatsoever when there is no featured
   image, and where there is one it is a direct child of the cover - both
   verified against the served HTML, not assumed.

   min-height and padding need !important because they are inline styles on the
   block. The band is auto-height like .epas-banner (30px top and bottom), not
   the cover's 480px; with min-height 0 the bottom-center content position
   becomes a no-op, so the title just sits in its padding.

   Kept as its own rule rather than folded into the .epas-banner selector list
   below: an unsupported :has() would invalidate the whole list and silently
   take the working banners down with it. */
.wp-block-cover.epas-photo-scrim:not(:has(> img.wp-block-cover__image-background)) {
	min-height: 0 !important;
	padding-top: 30px !important;
	padding-bottom: 30px !important;
	background-color: var(--wp--preset--color--reflex-blue);
}

/* The scrim exists to lift text off a photograph. With no photo it would only
   dirty the flat blue, so it goes. */
.wp-block-cover.epas-photo-scrim:not(:has(> img.wp-block-cover__image-background))
	.wp-block-cover__inner-container::before {
	display: none;
}

/* Same all-caps optical centring the real banners get - see .epas-banner below
   for the reasoning. This band is now the same design, so it needs the same
   nudge or its title sits visibly high next to /news/. */
.wp-block-cover.epas-photo-scrim:not(:has(> img.wp-block-cover__image-background)) h1 {
	line-height: 1;
	position: relative;
	top: 0.09em;
}

/* ---- Bullet lists: bullet aligns with the text above it ----
   Core indents lists 40px, so the bullet sits well right of the paragraph or
   heading above and the column reads as two ragged left edges. The marker is
   redrawn as a pseudo-element rather than reducing `padding-left`, because the
   browser places its own `::marker` relative to the li's content edge with a gap
   we cannot address — there is no padding value that lands the bullet exactly on
   the content edge. Text keeps a hanging indent so wrapped lines align under the
   first line, not under the bullet. Scoped to the homepage cards and the footer;
   lists inside post content keep the normal indent. */
.epas-cards .wp-block-list,
footer .wp-block-list {
	padding-left: 0;
	list-style: none;
}
.epas-cards .wp-block-list > li,
footer .wp-block-list > li {
	position: relative;
	padding-left: 1.1em;
}
.epas-cards .wp-block-list > li::before,
footer .wp-block-list > li::before {
	content: "";
	position: absolute;
	left: 0;
	/* 0.5em down the first line box, then pulled back by half the dot: centres the
	   dot on the first line regardless of the inherited line-height. */
	top: 0.5em;
	width: 0.35em;
	height: 0.35em;
	margin-top: -0.175em;
	border-radius: 50%;
	background: currentColor;
}

/* ---- Quote / testimonial boxes ----
   The 1px green border and padding are theme.json (styles.blocks.core/quote).
   Two things have to be undone here:
   1. Browsers apply `margin: 1em 40px` to blockquote by default. WordPress's
      layout rules reset the block margins but not the inline 40px, so every quote
      box sat 40px narrower than the grids above and below it.
   2. `overflow-wrap` etc. is fine; only the inline margin is the problem. */
.wp-block-quote {
	margin-left: 0;
	margin-right: 0;
}

/* Testimonial columns: same gutter as the news grid below them (see the
   post-template rule above — both are 2rem, keep them in step). */
.epas-testimonials {
	gap: 2rem;
}

/* The mockup's green quotation mark, above the quote text. Geometry lifted from
   EPAS_Home.pdf: 40 x 34.681 units at the box's top-left, inset by the box
   padding. Scoped to the homepage testimonials — the site's other quote blocks
   are a pull-quote, a personal testimony and a block of explanatory text, none of
   which want a decorative flourish. */
.epas-testimonials .wp-block-quote::before {
	content: "";
	display: block;
	width: 40px;
	height: 34.681px;
	margin-bottom: 20px;
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 34.681'%3E%3Cpath fill='%2328DC78' d='M40 0C27.432 2.622 23.323 9.057 23.323 22.525L23.323 34.681L40 34.681L40 18.592L30.695 18.592C30.816 11.084 33.837 7.508 40 5.959Z M16.677 0C4.109 2.622 0 9.057 0 22.525L0 34.681L16.677 34.681L16.677 18.592L7.372 18.592C7.492 11.084 10.514 7.508 16.677 5.959Z'/%3E%3C/svg%3E") no-repeat left top / contain;
}

/* ---- Section/title banners: optical centring for the all-caps heading ----
   Same root cause as the buttons: the heading is uppercase, so it has no
   descender ink, the line box reserves space nothing uses, and the caps sit
   ~0.09em above the optical centre of the coloured band. Measured on the live
   "Latest News" band: 3.1px of line box above the caps against 12.2px below.

   The buttons fix this by shifting padding from bottom to top, but that only
   works where there is padding to redistribute. Doing the same to a heading grows
   its box, which pushes the band's bottom edge down by the same amount the text
   moved — a net correction of only half the nudge. (The obvious patch, a negative
   margin-bottom to give the height back, silently loses to core's
   `:root :where(.is-layout-flow) > :last-child{margin-block-end:0}` at specificity
   0,2,0.)

   A relative offset moves the rendered text without touching layout, so the band
   keeps its height and the caps land on the optical centre. `em` so it tracks the
   heading's own font size across the different banner sizes. */
.epas-banner :is(h1, h2) {
	line-height: 1;
	position: relative;
	top: 0.09em;
}

/* ---- Links on Reflex Blue surfaces ----
   theme.json colours links Reflex Blue with a Pantone 293 hover. Both are dark
   blues chosen against a white page, and both disappear on the site's own Reflex
   Blue surfaces — the homepage bands and the footer:

     link  Reflex Blue #0C4DA2 on #0C4DA2 = 1.00:1  (the exact same colour)
     hover Pantone 293 #003CB4 on #0C4DA2 = 1.13:1

   The homepage "What is EPAS" band was the visible symptom: its inline link was
   literally invisible. The hover half is the same bug and still bites every
   footer link.

   The footer only *looked* right because every link there carries a hand-added
   inline `style="color:#fff"` — a per-link workaround of the same species as the
   old pantone-293 `Read More` override (see Trap F in the handoff). Inline styles
   have no :hover, which is why the hover stayed broken. This rule makes those
   inline colours redundant; they can be stripped from the footer part whenever
   it's next touched.

   White matches the surrounding body copy on these bands (8.08:1) and the links
   are already bold + underlined, so they stay identifiable as links without
   relying on colour alone. Hover goes to Light Blue 0821 (5.34:1) — a light tint
   mirrors the light-background relationship, where hover shifts away from the
   base link colour. Pantone 306 was the other candidate but only reaches 3.71:1.

   Buttons are excluded: they sit on their own background and set their own
   colour. Social icons are untouched — core styles them at specificity 0,23,1,
   well above this rule. Verified no light-background element nests inside a blue
   surface anywhere on the site, which would otherwise turn white-on-white. */
.has-reflex-blue-background-color a:not(.wp-element-button) {
	color: var(--wp--preset--color--white);
}
.has-reflex-blue-background-color a:not(.wp-element-button):hover,
.has-reflex-blue-background-color a:not(.wp-element-button):focus {
	color: var(--wp--preset--color--pantone-0821);
}

/* ---- Navigation: normal weight, not bold (theme.json sets links to 700 globally) ---- */
.wp-block-navigation a,
.wp-block-navigation .wp-block-navigation-item__label {
	font-weight: 400;
}

/* ---- Current top-level page: green box, per the mockup ----
   Padding goes on every top-level item, not just the current one, so nothing
   shifts as you move between pages. The `current-menu-item` class is added by
   epas_style_mark_current_nav_item() in functions.php: WordPress only sets it
   automatically for links that point at a post ID, and this menu is built from
   custom links. */
.wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
	padding: 0.4em 0.8em;
}
.wp-block-navigation__container > .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content {
	background-color: var(--wp--preset--color--pantone-7479);
	color: var(--wp--preset--color--reflex-blue);
}

/* ---- Site name lockup (header, next to logo) ---- */
.epas-site-name {
	text-transform: uppercase;
	font-family: "Europea", sans-serif;
	font-weight: 500;
	font-size: 1.1rem;
	line-height: 1.3;
	color: var(--wp--preset--color--reflex-blue);
	max-width: 260px;
	/* Underline per line (per playbook: "Programme/initiative name in
	   Europea medium, uppercase, underlined" - each wrapped line gets
	   its own underline, not one line under the whole block). */
	text-decoration-line: underline;
	text-decoration-color: var(--wp--preset--color--pantone-7408);
	text-underline-offset: 4px;
}
.epas-site-name:hover {
	color: var(--wp--preset--color--reflex-blue);
}
/* Variant for use on a dark/blue background: swap to white text, blue underline */
.epas-site-name.is-on-dark {
	color: #ffffff;
	text-decoration-color: var(--wp--preset--color--pantone-306);
}

/* ---- Header on phones: two rows, smaller logo ----
   The header is a single nowrap flex row of logo + site name + nav + login +
   search. At 375px that needs ~596px against 375 available, so it burst its
   container and the browser widened the layout viewport to 564px — the whole page
   then scrolled sideways. The logo is the main culprit: its width attribute is
   also its min-content width, so nowrap could not shrink it.

   On phones the site name drops to its own row underneath everything else:
   `display:contents` dissolves the logo+name group so both become flex items of
   the header itself (nothing else can put the name on a full-width row while it
   is nested inside that group), then order+flex-basis send it to row two.

   Deliberately no markup change: the header template part is currently served
   from a *database* override, so edits to parts/header.html would not take
   effect — see the template-part note in the handoff. CSS applies either way.

   Breakpoint is 600px to match core's own navigation overlay, so the row is
   always logo + burger + login + search.

   The logo is sized with a clamp rather than a fixed width because the header's
   32px side padding is an *inline* style on the block and cannot be overridden
   from here without !important, so the row has a fixed 64px overhead. Worst case
   at 320px: 64 padding + 74 logo + 16 + 24 burger + 16 + 104 tools = 298. At
   375px it comes to 312.

   These values track the logo's *visible* size, not its box. The old SVG padded
   its artwork inside the viewBox (8.1% left/right, 22.8% top/bottom), so a 132px
   box drew only 110px of logo. The viewBox is now cropped to the ink, making box
   == ink, and the clamp was scaled by the same 0.836 to keep the rendered size
   identical: 88->74, 28vw->23.4vw, 132->110. If the SVG is ever re-exported,
   re-check that ratio before trusting these numbers. */
@media (max-width: 600px) {
	header.wp-block-group {
		flex-wrap: wrap;
		row-gap: 10px;
		column-gap: 16px;
	}
	/* dissolve the logo + site-name group into the header's own flex row */
	header.wp-block-group > .wp-block-group:first-child {
		display: contents;
	}
	header.wp-block-group > .wp-block-group:first-child img {
		width: clamp(74px, 23.4vw, 110px);
		height: auto;
	}
	/* order pushes it past nav/login/search (all order 0); the 100% basis forces
	   the line break, so it lands on its own row under everything else. */
	.epas-site-name {
		order: 1;
		flex-basis: 100%;
		max-width: none;
	}
}

/* ---- Buttons: optical vertical centring for all-caps labels ----
   Every button label is uppercase, so the line box always reserves descender
   space that no glyph ever uses, leaving the caps sitting ~0.09em above the
   optical centre. `line-height:1` drops the inherited body leading, and the
   asymmetric padding (+0.09em top / -0.09em bottom) shifts the caps back to the
   middle without changing the button's overall height. Icon-only buttons are
   excluded: an icon has no baseline to compensate for. */
.wp-block-button__link,
.wp-element-button:not(.has-icon) {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	line-height: 1;
	padding-top: calc(0.667em + 2px + 0.09em);
	padding-bottom: calc(0.667em + 2px - 0.09em);
}

/* ---- Header: log in/out and search share one height ----
   44px is also the minimum comfortable touch target. */
.epas-loginout a,
.wp-block-search__button {
	box-sizing: border-box;
	min-height: 44px;
}

/* ---- Log in / Log out: WordPress core loginout block, styled as a pill button ---- */
.epas-loginout a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--wp--preset--color--reflex-blue);
	color: #ffffff;
	text-decoration: none;
	text-transform: uppercase;
	font-weight: 700;
	line-height: 1;
	/* same +/-0.09em all-caps nudge as the buttons above */
	padding: 0.69em 1.4em 0.51em;
	white-space: nowrap;
}

/* ---- Search: icon button, lighter blue than the login button ---- */
.wp-block-search__button {
	margin-left: 0;
	padding-top: 0;
	padding-bottom: 0;
	padding-left: 1em;
	padding-right: 1em;
	align-items: center;
	background-color: var(--wp--preset--color--pantone-2727);
	color: #ffffff;
}
.wp-block-search__button:hover {
	background-color: var(--wp--preset--color--reflex-blue);
	color: #ffffff;
}
.epas-loginout a:hover {
	background: var(--wp--preset--color--pantone-293);
	color: #ffffff;
}
/* Below tablet width, collapse the button to an icon so it doesn't stack vertically */
@media (max-width: 782px) {
	.epas-loginout a {
		width: 44px;
		height: 44px;
		padding: 0;
		text-indent: -9999px;
		overflow: hidden;
		position: relative;
	}
	.epas-loginout a::after {
		content: "";
		position: absolute;
		inset: 0;
		margin: auto;
		width: 20px;
		height: 20px;
		text-indent: 0;
		background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4'/%3E%3Cpolyline points='10 17 15 12 10 7'/%3E%3Cline x1='15' y1='12' x2='3' y2='12'/%3E%3C/svg%3E") center / contain no-repeat;
	}
}

/* ---- News grids: gutter only ----
   The post-template block already lays itself out as a 3-column grid (its own
   `layout: {type:grid, columnCount:3}`), so no display/column override is needed
   here — the previous `display:grid !important` version fought the block's own
   layout and broke /news/. This only sets the gutter, and collapses to a single
   column earlier than core's 600px breakpoint, where 3 columns get too cramped. */
.wp-block-post-template.is-layout-grid {
	gap: 2rem;
}
@media (max-width: 781px) {
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: 1fr;
	}
}

/* ---- Homepage cards: buttons align along the bottom ----
   The four cards carry different amounts of text, so their buttons would
   otherwise sit at ragged heights. Each column becomes a flex column and the
   buttons group is pushed down with an auto top margin. Scoped by the
   `epas-cards` class on the columns block so the page's other column groups
   (which have no buttons to align) are left alone. */
.epas-cards .wp-block-column {
	display: flex;
	flex-direction: column;
}
.epas-cards .wp-block-column > .wp-block-buttons {
	margin-top: auto;
}

/* ---- "EPAS Team Comment" boxes inside post content ----
   Posts carry `has-primary-background-color` from the old theme, whose `primary`
   colour does not exist in this palette — so WordPress emits no rule at all and
   the box renders with no background. Map it to the playbook's light blue here
   rather than editing every post. `.ep-white-bg-heading` is the old theme's
   white "highlighter tab" treatment for the heading inside the box. */
.has-primary-background-color {
	background-color: var(--wp--preset--color--pantone-0821) !important;
}
.ep-white-bg {
	background-color: #ffffff;
}
.ep-white-bg-heading {
	display: table;
	line-height: 1 !important;
	padding: 0.2em 0.2em 0;
	background-color: #ffffff;
	color: var(--wp--preset--color--reflex-blue) !important;
}

/* ---- Homepage headings: mockup treatment, not the playbook default ----
   EPAS_Home.pdf sets homepage section headings in uppercase; the playbook
   reserves that for h1 only. Per the user (2026-07-16) the mockup wins on the
   homepage and the playbook holds everywhere else, so this is scoped to
   .home AND the post content — an unscoped .home h2/h3 would also catch the
   footer's headings, which must stay identical on every page.
   Fonts match the mockup: h2 = Europea Extrabold (800), h3 = Bold (700). */
.home .wp-block-post-content h2 {
	font-weight: 800;
	text-transform: uppercase;
}
.home .wp-block-post-content h3 {
	text-transform: uppercase;
}
