/*
Theme Name: EPAS Style
Template: twentytwentythree
Version: 1.0.11
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;
}

/* ---- Kill the empty band above the header and below the footer ----
   The parent theme puts ~43.6px of top and bottom padding on .wp-site-blocks
   (a spacing-preset clamp). It's white-on-white so it reads as nothing but a
   bar of dead space - the header floats ~44px down from the viewport top and
   there's a matching gap under the footer. Zeroing the block axis pulls the
   header flush to the top and the footer flush to the document end.
   Only the top/bottom padding: this element's left/right is untouched (it's
   0 here anyway - the horizontal root padding lives on the constrained blocks,
   not on .wp-site-blocks), so content stays on the 32px grid. Plain selector
   is enough; the parent sets this via a :where() zero-specificity rule. */
.wp-site-blocks {
	padding-top: 0;
	padding-bottom: 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;
}

/* ---- Homepage hero: align its text/button with the content column below ----
   The hero headline and the "Register Now" button sat ~16px left of, and ~89px
   short of, the content beneath them (the "What is" band, the cards, Latest
   News), so the whole hero read as off-grid. Two separate faults, measured live
   against the identical full-bleed "What is" band directly below it, which does
   render on-grid (left 32 / right 1233 at 1280):

   1. The cover breaks out to full width with a -32px margin (root-padding-aware
      alignfull) but core only pads its content back by ~15.8px, so the content
      started 16px too far left. Restoring the root padding on both sides lines
      the left edge up with every constrained block on the page, and tracks the
      same clamp on mobile (32px desktop, 24px at 375 - matching the cards, not
      the band's hardcoded 32px).
   2. With contentPosition "bottom left", core flex-sizes the inner container to
      its widest line (the h1) and left-pins it, instead of filling the column.
      Everything - inner container, group, h1, button row - collapsed to exactly
      1128px, so the right-justified button landed mid-page. width:100% makes it
      fill the content box; the constrained group inside then centres its
      children within the real 1240 column. Needs !important: core's width rule
      outranks this selector, and nothing else here does.

   Scoped to .home so it can't touch the page/post covers (page.html/single.html),
   which are bottom-centre and deliberately behave differently. */
.home .wp-block-cover.alignfull {
	padding-left: var(--wp--style--root--padding-left, 32px);
	padding-right: var(--wp--style--root--padding-right, 32px);
}
.home .wp-block-cover.alignfull > .wp-block-cover__inner-container {
	width: 100% !important;
}

/* ---- 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;
}

/* ---- Homepage schools-map: text link only, whole-cover click abandoned ----
   The "Ambassador Schools in the UK" block is a cover with a static map
   screenshot as its background (`.has-parallax`, background-attachment:fixed)
   and a text-overlay link to /participant-schools/.

   A prior attempt (0.3.12) made the WHOLE cover clickable via a stretched-link,
   which required forcing this cover's inner container from core's default
   position:relative to position:static. That, combined with `overflow:clip` -
   core's own default on every `.wp-block-cover`, `style.min.css`, nothing to
   do with our CSS - turned out to be a bad combination for a fixed-attachment
   background: the text went invisible, unpredictably, and NEITHER a darker
   scrim (0.3.26-0.3.28) NOR forcing `background-attachment:scroll` (0.3.31)
   reliably fixed it. Per the user (2026-07-20): drop the whole-cover-clickable
   feature rather than keep chasing the interaction. Only the text needs to be
   a link, which is what a plain, unmodified core cover already gives you -
   nothing to write here except making sure our earlier overrides are gone.
   `overflow:clip` stays (it's core's, not scoped to remove safely), and with
   the inner container back to its own default positioning, the fixed-
   attachment background is no longer sharing a stacking context it has to
   fight with an ancestor override - which was the actual root of the bug,
   not the parallax effect on its own. */

/* ---- 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 ul.wp-block-list > li::before,
footer ul.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;
}

/* Ordered lists get a number instead of a dot, same hand-rolled-marker approach
   (list-style:none above strips the native ::marker for both ul and ol alike, so
   ol needs its own counter-driven replacement rather than relying on `decimal`).
   Wider padding than the dot's 1.1em to fit two-digit numbers, and the marker
   sits flush with the top of the first line rather than vertically centred, since
   digit glyphs (unlike the small dot) already read correctly against the text
   baseline without that adjustment. */
.epas-cards ol.wp-block-list,
footer ol.wp-block-list {
	counter-reset: epas-list-counter;
}
.epas-cards ol.wp-block-list > li,
footer ol.wp-block-list > li {
	counter-increment: epas-list-counter;
	padding-left: 1.4em;
}
.epas-cards ol.wp-block-list > li::before,
footer ol.wp-block-list > li::before {
	content: counter(epas-list-counter) ".";
	position: absolute;
	left: 0;
	top: 0;
	font-weight: 700;
}

/* ---- 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);
}

/* ---- Old-palette slugs, remapped (Trap F, in content) ----
   The previous theme shipped its own `ep-*` colour palette. Deleting it took the
   slugs with it, but the slugs are still written into page content as
   `has-custom-ep-*-background-color` classes — and a class with no rule behind
   it paints nothing, so these highlight boxes render as plain text on white.
   Found by the page walk (2026-07-20) on /roadmap/, /epas-resources/, the
   eTwinning page and /register/.

   Remapping here rather than re-authoring the blocks: it fixes every page at
   once, needs no content edits (Trap E), and follows the precedent already set
   by `.has-primary-background-color` below. The old theme is no longer on disk,
   so the original hexes are unrecoverable — these are mapped by name to the
   nearest EP palette equivalent. `ep-purple` had no equivalent at all (the EP
   palette contains no purple); the user chose Pantone 1795.

   Text colour: every mapping except 1795 is a light tint that keeps the
   inherited black comfortably (7479 11.6:1, 7408 12.5:1, 0821 13.9:1). Pantone
   1795 is dark — black on it is only 4.04:1 and fails — so those two flip to
   white (5.20:1), links included, mirroring the Reflex Blue surface rule above. */
.has-custom-ep-lime-background-color,
.has-custom-ep-peppermint-background-color {
	background-color: var(--wp--preset--color--pantone-7479);
}
.has-custom-ep-yellow-background-color {
	background-color: var(--wp--preset--color--pantone-7408);
}
.has-custom-ep-light-blue-background-color {
	background-color: var(--wp--preset--color--pantone-0821);
}
.has-custom-ep-purple-background-color,
.has-custom-ep-red-background-color {
	background-color: var(--wp--preset--color--pantone-1795);
	color: var(--wp--preset--color--white);
}
.has-custom-ep-purple-background-color a:not(.wp-element-button),
.has-custom-ep-red-background-color a:not(.wp-element-button) {
	color: var(--wp--preset--color--white);
}
/* `contrast` is a TT3 slug this palette deleted; it only ever meant body text. */
.has-contrast-color {
	color: var(--wp--preset--color--black);
}

/* NB — the separators on /learning-resources/ and /support/ carry the dead
   `accent`/`secondary` slugs too, but they need NO rule here and deliberately
   don't have one. They are `is-style-dots` separators: core draws them as a
   `::before` containing "···" coloured by `color` (grey), and kills background
   and border with `background:initial !important`. They render correctly. A
   first pass at the page walk reported them as "8 invisible separators" — that
   was a false positive from a check that only looked at background-color and
   border-width and never considered the pseudo-element. Any future audit of
   "invisible" elements must account for `::before`/`::after` content before
   concluding anything is missing. */

/* ---- /roadmap/ step tables ----
   These carry `asher-table` classes from the old theme, whose styling lived in
   an inline <style> block in the page head — so it never travelled with the
   content and the tables arrived here completely unstyled (1px padding, no
   header, no period bars). Recovered from the live site and rebuilt to the new
   brand rather than copied: the original set `font-family:EuropeaNarrowVar`
   and `font-style:italic`, and this theme loads neither — five Europea faces,
   all upright — so a straight copy would have asked the browser to synthesise
   a fake oblique of the wrong family. Weight and case carry that hierarchy now.

   The header treatment deliberately matches the Formidable View tables above,
   so every table on the site now reads the same way. The one thing kept
   verbatim is the period-bar colour: the original `#FF9600` is Pantone 1495,
   already in the EP palette, so it was on-brand all along (black on it is
   9.61:1). `asher-table-span` rows are the full-width month/term dividers
   ("October", "Autumn Term"); `asher-table-th2` cells are the row labels. */
table.asher-table {
	border-collapse: collapse;
	width: 100%;
}
table.asher-table th,
table.asher-table td {
	padding: 0.5em 0.75em;
	vertical-align: top;
	text-align: left;
}
table.asher-table th {
	font-weight: 700;
	text-transform: uppercase;
	color: var(--wp--preset--color--reflex-blue);
	border-bottom: 2px solid var(--wp--preset--color--reflex-blue);
}
table.asher-table td {
	border-bottom: 1px solid rgba(0, 0, 0, 0.15);
}
table.asher-table td.asher-table-th2 {
	font-weight: 700;
	text-transform: uppercase;
	line-height: 1.15;
}
table.asher-table td.asher-table-span {
	background-color: var(--wp--preset--color--pantone-0821);
	font-weight: 700;
	text-transform: uppercase;
	text-align: center;
	border-bottom: none;
}
/* Gold call-out: applied to a <tr> for a whole-row highlight (Timeline table) or
   to a single <td> for a cell-only highlight (Criteria table) - same treatment,
   the markup decides the scope. */
table.asher-table .asher-table-highlight {
	background-color: var(--wp--preset--color--pantone-7408);
}

/* ---- Cookie consent: don't reserve space twice for a blocked video ----
   With consent withheld, CookieYes removes the YouTube iframe and drops its own
   placeholder (thumbnail + "Please accept cookies to access this content") in
   its place. But WordPress reserves the 16:9 space with a padding-top spacer on
   `.wp-block-embed__wrapper::before`, sized for an ABSOLUTELY positioned iframe.
   CookieYes's placeholder is `position:relative`, i.e. in normal flow, so the
   reserved space is never filled and the block renders at exactly double
   height: 675.6px of nothing + 676px of placeholder = 1352px. That empty half
   is what pushes the video down the page — the message was always there, just
   below a screenful of blank space.

   Collapsing the spacer only when a placeholder is present means the moment
   consent is given and the real iframe returns, the selector stops matching and
   the normal aspect-ratio behaviour is back untouched. Keyed to the
   `data-cky-tag` attribute rather than the provider-specific
   `.video-placeholder-youtube` class, so it covers Vimeo and the rest too.

   Specificity, not just matching, is what makes this win: core sets the spacer
   via `.wp-embed-responsive .wp-embed-aspect-16-9 .wp-block-embed__wrapper::before`
   (3 classes + 1 element = 0,3,1 — one of several near-identical rules, one per
   ratio, e.g. `.wp-embed-aspect-4-3`, `.wp-embed-aspect-1-1`). A first version of
   this rule matched the right element but only reached 0,2,1, so it lost
   outright — the selector matched, the padding never moved, and the bug looked
   unfixed even though the CSS had deployed correctly. `.wp-embed-responsive` is
   a body class WP adds whenever responsive embeds are supported (present on
   every page here); `.wp-has-aspect-ratio` is always paired on the figure
   alongside whichever specific `.wp-embed-aspect-N-N` class is in play. Adding
   both brings this to 0,4,1, which beats every one of core's per-ratio rules
   outright regardless of which ratio or source order — no !important needed. */
.wp-embed-responsive .wp-has-aspect-ratio .wp-block-embed__wrapper:has(> [data-cky-tag="video-placeholder"])::before {
	padding-top: 0;
}

/* ---- 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);
}
/* The name is now a plain link (wp:paragraph, not wp:site-title), so it's a bare
   <a> matching the theme's global link rule (style.css generated from theme.json
   elements.link) — that rule's shorthand `text-decoration: underline` resets
   text-decoration-color to currentColor on the anchor itself, and its :hover
   variant sets `text-decoration: none`, which removes that self-drawn line and
   reveals the ancestor's gold one underneath. Net effect without the two rules
   below: blue underline by default, gold on hover — backwards. Restating both
   states explicitly on the anchor (higher specificity than the :where()-based
   global rule) fixes it: gold by default, reflex blue on hover. Same story for
   font-weight: the global rule sets 700 directly on the anchor, masking the
   500 set on the ancestor .epas-site-name, so that's restated too (as `inherit`
   rather than a hardcoded 500, so it always tracks the ancestor's value). */
.epas-site-name a {
	color: inherit;
	font-weight: inherit;
	text-decoration-line: underline;
	text-decoration-color: var(--wp--preset--color--pantone-7408);
}
.epas-site-name a:hover,
.epas-site-name a:focus {
	color: inherit;
	font-weight: inherit;
	text-decoration-line: underline;
	text-decoration-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
   "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;
}

/* ---- Headings inside a coloured box ----
   ⚠ The class name is a misnomer and CANNOT be renamed: it is baked into the
   content of 95 of 100 posts (the "EPAS Team Comment" boxes) plus the nine
   School Dashboard headings. Renaming means editing every post. There is no
   white background here any more; the name is history.

   Per the user (2026-07-20): no background at all - just blue heading text -
   because the white "highlighter tab" broke up the coloured boxes it sat on.
   So this is now only a colour rule. The old `display:table`, `line-height:1`
   and padding all existed purely to shape that tab; with no background they
   have nothing to do, and dropping them returns these headings to the same
   leading and flow as every other h3.

   Blue is the default. The headings are 26.88px/700, so WCAG's large-text
   threshold (3:1) applies, but Reflex Blue clears even the stricter 4.5:1 on
   every surface it actually lands on:
     white page              8.08  ✓
     Pantone 0821  #65E2FF   5.34  ✓  (dashboard + Team Comment box in posts)
     Pantone 7408  #FCBE00   4.81  ✓  (dashboard)
     Pantone 7479  #28DC78   4.46  ✓  (dashboard)
   7479 is the only one under 4.5, by 0.9% - the same Reflex-Blue-on-Green-7479
   pairing §6 already records as known and accepted, and it clears the 3:1
   large-text bar these headings are actually judged against with room to spare.

   Check this again if a box colour ever changes. The dashboard previously used
   WP's `luminous-vivid-orange` #FF6900, where Reflex Blue is 2.80:1 and fails
   even the 3:1 floor; white was no better (2.89) and black (7.27) was the only
   workable option. Those boxes are Pantone 7408 now and the exception has been
   removed, but any new mid-tone warm background will need the same check. */
.ep-white-bg-heading {
	color: var(--wp--preset--color--reflex-blue) !important;
}

/* Exception to the blanket rule above, same precedent as the orange-box case
   in the comment above it: "Using EP Teaching Materials" (added 2026-07-22)
   is the first of these dashboard box headings to sit on a DARK background
   (reflex-blue) rather than the pastel/mid-tone ones the blanket rule assumes.
   Asher set the block's own textColor to white, but the blanket !important
   above was overriding it back to reflex-blue - text the same colour as its
   own background, i.e. functionally invisible (1:1 contrast), not just "the
   wrong blue". This selector is more specific (two classes vs one) so it
   wins without touching the general rule. White on Reflex Blue is 8.08:1 -
   already established elsewhere on the site (main handoff §6). */
.has-reflex-blue-background-color .ep-white-bg-heading {
	color: var(--wp--preset--color--white) !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;
}

/* ---- Formidable Forms ----
   Formidable is entirely CSS-custom-property driven: its own stylesheet reads
   `var(--field-height)`, `var(--submit-bg-color)` and ~100 others from a single
   block on `.with_frm_style`. So we re-declare the *variables* rather than
   fighting `.with_frm_style` selector specificity with overrides - the plugin's
   own rules then repaint themselves. Two consequences worth knowing:

   1. This lives in style.css, not the plugin's style settings, because the theme
      is shared with epasbe.eu and the France build (see the handoff §0) - form
      config is per-site, the theme is not.
   2. It survives plugin updates. The plugin's generated stylesheet carries
      "any changes made to this file will be lost when your settings are
      updated"; nothing here is in that file.

   Selector is the double class the plugin itself uses for the active style
   (`.frm_style_formidable-style.with_frm_style`, 0-2-0) so we match its
   specificity and win on source order - formidableforms.css is enqueued before
   the theme. A single-class `.with_frm_style` would LOSE to the plugin's own
   double-class block. */
.frm_style_formidable-style.with_frm_style {
	/* The plugin never defines --font, but its field rules say
	   `font-family:var(--font)`. A dangling var() invalidates the whole
	   declaration (same failure mode as Trap F), so every form control fell back
	   to the UA default - which is why submit buttons rendered in Arial while
	   text inputs only looked right by inheriting from body. */
	--font: var(--wp--preset--font-family--europea);

	/* Controls match the 44px header login/search height (and the minimum
	   comfortable touch target). Was 32px. --field-pad is re-derived to fill it:
	   44 = 2px borders + 2x11px padding + 20px line box. */
	--field-height: 44px;
	--line-height: 44px;
	--field-pad: 11px 14px;

	/* 14px -> 1rem. Below 16px, iOS Safari zooms the viewport on focus and never
	   zooms back out, which strands the user mid-form. */
	--field-font-size: 1rem;

	/* Was rgb(89,89,89) - grey text in a white field reads as disabled. */
	--text-color: #000000;

	/* Labels: bold so the field name survives being scanned, not shouted. Site
	   doctrine reserves uppercase for buttons and headings. */
	--weight: 700;

	/* Brand red, and 5.3:1 on white - the plugin's #B94A48 is off-palette. */
	--required-color: var(--wp--preset--color--pantone-1795);

	/* These two reach the secondary buttons only (.frm_button, save-draft,
	   start-over). The primary submit ignores them - see the block below. */
	--submit-font-size: var(--wp--preset--font-size--medium);
	--submit-weight: 700;

	/* The plugin shipped hover/active identical to the resting colour, so the
	   button gave no feedback at all. Blue 293 is the site's hover-only blue -
	   never a resting background (handoff §6). */
	--submit-hover-bg-color: var(--wp--preset--color--pantone-293);
	--submit-hover-border-color: var(--wp--preset--color--pantone-293);
	--submit-active-bg-color: var(--wp--preset--color--pantone-293);
	--submit-active-border-color: var(--wp--preset--color--pantone-293);
}

/* The primary submit button is the one place the variables can't reach: the
   plugin's rule for it hardcodes `font-size:20px; font-weight:500` as literals
   rather than var()s, so font size/weight/family have to be declared directly.
   That rule is `.frm_style_formidable-style.with_frm_style input[type=submit]`
   (0-2-1); adding `.frm_submit` takes us to 0-3-1 so we win without !important.

   Font-family has to be spelled out because the submit isn't in the plugin's
   `font-family:var(--font)` selector list at all - buttons don't inherit
   font-family from body, which is the actual reason these rendered in Arial.

   Sizing matches the site's own buttons: fluid `medium` preset, 700, uppercase,
   44px minimum, and the same +/-0.09em all-caps optical nudge - see the
   .wp-block-button__link block above for why that asymmetry exists. An <input>
   can't be a flex container, so height is held by min-height + padding rather
   than align-items. */
.frm_style_formidable-style.with_frm_style .frm_submit input[type=submit],
.frm_style_formidable-style.with_frm_style .frm_submit input[type=button],
.frm_style_formidable-style.with_frm_style .frm_submit button {
	box-sizing: border-box;
	font-family: var(--wp--preset--font-family--europea);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 700;
	text-transform: uppercase;
	min-height: 44px;
	line-height: 1;
	padding: calc(0.69em + 0.09em) 1.4em calc(0.69em - 0.09em);

	/* Drops a 6px 6px hard drop shadow that arrives from custom CSS in the
	   plugin's own style settings (a bare `.frm_button_submit{...!important}`).
	   Nothing else on this site carries a shadow - the design is flat, square
	   and 0-radius throughout - so a chunky offset shadow on form buttons only
	   reads as a stray. Needs !important solely to beat the !important it is
	   overriding. **Approved by the user 2026-07-20 — settled, don't re-open.** */
	box-shadow: none !important;
}

/* ---- Dashboard View entries: keep the status icon on the title's line ----
   Each entry in a dashboard View is a title/link/date block plus a 30px
   tick (Approved) or pause (Pending) icon. The nine Views are configured
   inconsistently in Formidable: six put the icon inside the same `frm9` grid
   cell as the text, three give it its own full-width `frm12` cell, which drops
   it onto a line of its own and costs ~137px of height per entry. With every
   box now in a 3-wide grid that was the difference between a compact card and
   a tall one.

   Fixed here rather than in the nine View configs because the config is
   per-site (it would not survive the France clone) and because this makes all
   nine agree regardless of how any individual View is set up. The entry
   becomes a flex row: text takes the space, icon keeps its intrinsic width and
   sits top-right. `:has()` targets only the stacked variant, so the six Views
   that already inline their icon are left completely alone.

   NB this is NOT the `frm_no_grid_750` responsive rule - that is a viewport
   media query (max-width:750px), inactive at desktop widths, and it was not
   the cause. The stacking is pure View configuration.

   Both containers hold a single `frm12` - a full-width 12-of-12 span - so
   each one's 12-track grid is doing nothing a block wouldn't do, and dropping
   to `display:block` is equivalent. That matters: the obvious version of this
   fix (flex the parent, leave the grids alone, shrink the icon's cell with
   `grid-column:auto`) does NOT work. The icon's container keeps all twelve
   tracks, so at `flex:0 0 auto` its max-content width becomes ~1920px, which
   starves the text container to 0px and wraps the title one character per
   line - 1520px tall per entry. The `:has(> .frm12:only-child)` guard keeps
   this to genuinely single-cell containers, so any View using a real split
   (e.g. frm9 + frm3) is untouched. */
.frm-grid-view > div:has(> .frm_grid_container + .frm_grid_container) {
	display: flex;
	align-items: flex-start;
	gap: 12px;
}
.frm-grid-view > div:has(> .frm_grid_container + .frm_grid_container) > .frm_grid_container:has(> .frm12:only-child) {
	display: block;
}
.frm-grid-view > div:has(> .frm_grid_container + .frm_grid_container) > .frm_grid_container:first-child {
	flex: 1 1 auto;
	min-width: 0; /* let the title wrap instead of forcing the row wider */
}
.frm-grid-view > div:has(> .frm_grid_container + .frm_grid_container) > .frm_grid_container + .frm_grid_container {
	flex: 0 0 auto;
}
.frm-grid-view .frm_has_image_options p {
	margin: 0;
}

/* Formidable sizes the image-option container at a fixed 150px, which is right
   for an image *choice* field (a row of selectable picture tiles) but wrong
   here, where the same markup carries one read-only 30px status icon. Left as
   150px it claims 160px of a 289px entry and squeezes the title into a 105px
   ribbon. Scoped to Views so real image-choice fields inside forms keep their
   tiles. */
.frm-grid-view .frm_show_images.frm_image_option_container {
	width: auto;
}

/* ---- Formidable View tables fill their block ----
   The Ambassadors table (dashboard) and the one on /add-ambassadors/ both sat
   at 445px inside a 1063px / 1201px block - ten columns crushed into a third
   of the available width while the block sat empty beside them.

   Nothing was constraining them. No rule in any loaded stylesheet sets a width
   on these tables at all, so they fall back to `width:auto` - and for a table
   that means shrink-to-fit its content, not fill its container. A table is not
   a block-level box in that sense; this is default CSS table behaviour, not a
   plugin bug and not something our layout caused.

   Red herring worth recording: the dashboard's table carries a class literally
   called `width100`, which looks like it should already do this. It is defined
   **nowhere** - zero occurrences in the loaded `formidableforms.css`, and no
   matching width rule from any other sheet. Formidable emits the class but
   ships no rule for it on the front end, so it does nothing. (The table on
   /add-ambassadors/ doesn't even carry it, yet renders identically - which is
   what confirms the class is inert rather than load-bearing.)

   Both selectors are needed: `.with_frm_style` sits on the table itself in the
   Views seen so far, but the plugin's own CSS also has an ancestor form
   (`#content .with_frm_style table.frm-grid`), so the class can land higher up.
   Checked at 100%: no cell overflows at either width, and the responsive
   stacking `.frm-responsive-table` applies below 750px regardless. */
table.frm-grid,
.with_frm_style table.frm-grid {
	width: 100%;
}

/* ---- Formidable View tables: appearance ----
   The plugin ships these as `padding:5px` with a 1px `rgb(89,89,89)` rule under
   every cell and no header treatment at all - the header row is just bold body
   text, so a wide table reads as an undifferentiated block. Only the bottom
   border is drawn (not a full grid), which is already the right instinct; it's
   just too dark against a white card, at an off-token grey used nowhere else.

   🚨 **Sort-safety.** `table-sorter` is active on the staff evidence tables
   (`/evidence-to-approve/`, `/approved-evidence/`, `/approved-evidence-table/`,
   `/all-evidence/`), and those are permission-gated - a Senior Ambassador like
   `claudetest` gets "you do not have permission", so this styling could NOT be
   eyeballed there. It is therefore written to be safe by construction:
     - `background-color`, never the `background` shorthand, so if the sorter
       paints its arrows as a `background-image` on the `th` they survive;
     - the header keeps DARK text on a LIGHT tint, so a dark sort arrow stays
       visible - a solid Reflex Blue header with white text would look sharper
       but could swallow one;
     - nothing here touches `content`, `display`, `position` or `cursor` on
       `th`, which is what a sorter binds to and decorates.
   **Settled 2026-07-20:** the user could not find a sortable table to check
   against, so the cautious light tint STAYS. Don't "upgrade" it to a solid
   Reflex Blue header on the assumption that it's safe — the whole point is
   that the surfaces where the sorter runs could not be inspected.

   `border-collapse` is set explicitly: the plugin asks for `collapse` but the
   computed value on the live table is `separate`, so something outranks it.
   Stating it here makes the header fill and the 1px rules predictable rather
   than depending on who wins that fight. */
table.frm-grid {
	border-collapse: collapse;
}
table.frm-grid th,
table.frm-grid td {
	padding: 0.6em 0.75em;
}
table.frm-grid th {
	background-color: rgba(12, 77, 162, 0.08); /* Reflex Blue at 8% */
	color: var(--wp--preset--color--reflex-blue);
	border-bottom: 2px solid var(--wp--preset--color--reflex-blue);
	vertical-align: bottom;
}
table.frm-grid td {
	border-bottom-color: rgba(0, 0, 0, 0.15);
}
/* Zebra. Formidable emits `.frm_even`/`.frm_odd` on some Views but sets BOTH to
   the same white, so its striping is inert; these tables don't carry the classes
   at all, hence nth-child. Kept very faint - the rules do the separating work,
   the tint just helps the eye track across a wide row. */
table.frm-grid tbody tr:nth-child(even) {
	background-color: rgba(12, 77, 162, 0.04);
}

/* The footer "Contact us" modal (formidable-modal) ships Bootstrap's 8px
   rounded dialog. The fields inside it already pick up everything above, but
   the dialog itself was the one rounded corner left on the site - everything
   else is square, including the fields it contains. This part is site-wide:
   the modal is in the footer on every page. */
.wp-block-frm-modal-content .modal-content {
	border-radius: 0;
}

/* Restore a visible focus indicator. The plugin sets `outline:none` on every
   field and replaces it with a border-colour change only - a 1px border shift
   is not a perceivable focus state, and for anyone navigating by keyboard it's
   the only way to tell where they are. :focus-visible so pointer users don't
   see a ring on click. */
.frm_style_formidable-style.with_frm_style input:focus-visible,
.frm_style_formidable-style.with_frm_style select:focus-visible,
.frm_style_formidable-style.with_frm_style textarea:focus-visible,
.frm_style_formidable-style.with_frm_style button:focus-visible {
	outline: 2px solid var(--wp--preset--color--pantone-2727);
	outline-offset: 2px;
}

/* ---- /participant-schools/ map: too short, so too zoomed out ----
   Formidable Geolocation (view 4172) sets `height:300px` as an INLINE style
   attribute on `#frmgeo-map-4172`, written by its own JS on load - not from a
   stylesheet, so it has to be beaten with !important; nothing else here does
   that, and this is the reason.

   The zoom is not a separate setting to find and change. There's no hardcoded
   zoom for this view - the plugin's loader builds a `LatLngBounds` from every
   marker (85 schools, confirmed no stray far-flung outlier skewing it) and
   calls `map.fitBounds(bounds)`, which is Google's own "compute the tightest
   zoom that fits this bounding box in the CURRENT container" - so with the
   box only 300px tall against ~1200px wide, fitBounds had to zoom out far
   enough to fit the UK's north-south extent into very few vertical pixels,
   wasting most of the horizontal space on empty sea either side. A taller
   box can only produce an equal-or-greater zoom for the same markers - that's
   how fitBounds is defined, not a guess - so this single height change is
   expected to satisfy both halves of the ask (bigger AND more zoomed in)
   without touching the plugin's zoom logic at all.

   Timing matters and was checked: the plugin's loader runs on `window.load`,
   by which point this stylesheet has long since been parsed and applied, so
   the map reads the CSS-forced height - not the inline 300px - when it
   measures the container and calls fitBounds. If Formidable Geolocation is
   ever reconfigured with its own fixed zoom, this rule stops being what's
   controlling it and should be revisited alongside that setting.

   900px per the user (2026-07-20, revised up from an initial 500px). */
#frmgeo-map-4172 {
	height: 900px !important;
}

/* ---- .report-images: photo grid for the year-end written report ----
   Carried over from live's global-styles custom CSS (wp_global_styles post
   1300, tied to the currently-active parent TT3) - that record disappears the
   moment epas-style activates, and this is the one rule in it with real
   content depending on it (checked: used on /all-evidence/, page 3834, only -
   confirmed by searching all 38 pages + 479 posts for the class). Ported
   verbatim rather than redesigned since it's a simple responsive tiling rule,
   not a themed component. */
.report-images {
	padding: 0 10px 10px 0;
	float: left;
	width: 24.99999%;
	height: auto;
}

@media only screen and (max-width: 700px) {
	.report-images {
		width: 49.99999%;
		height: auto;
		margin: 0 10px 10px 0;
	}
}

@media only screen and (max-width: 500px) {
	.report-images {
		width: 100%;
		height: auto;
	}
}

/* ---- .epas-progress-wrap: School Dashboard "path to accreditation" strip ----
   Generic/box-agnostic on purpose: this file only knows how to paint a box
   red (empty) or green (filled), group three of them under a gold "Essential"
   panel vs four under a plain "Optional" one, and draw a decorative arrow
   behind the row. Which Formidable View feeds which box, and how a count is
   derived from it, is wired in page 1400's own content (a per-site page, not
   this shared theme file) via data-epas-progress-box attributes - see that
   page's Custom HTML block. That split is deliberate: EPAS Belgium can offer
   a different set of boxes with different categories by editing their own
   page + Formidable filters, without ever touching this file.

   Layout is one CSS Grid with named areas rather than nested flex rows, so
   the gold background (spanning the essential heading + its 3 boxes) and the
   arrow (spanning behind all 7 boxes) can be separate grid items placed
   first in DOM order - painted first, so the opaque box squares and heading
   text that follow in the markup naturally paint over them with no z-index
   needed. The arrow is only ever visible in the gaps between boxes, exactly
   like the reference mockup once its wireframe (transparent) squares are
   replaced with the real opaque red/green ones. */
.epas-progress-wrap {
	position: relative;
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	grid-template-areas:
		"head-ess head-ess head-ess head-opt head-opt head-opt head-opt"
		"b1 b2 b3 b4 b5 b6 b7"
		". . . . . . conn"
		". . . . note note note";
	column-gap: 20px;
	row-gap: 10px;
	margin: 0 0 8px;
}

.epas-progress-bg-essential {
	grid-column: 1 / 4;
	grid-row: 1 / 3;
	background: var(--wp--preset--color--pantone-7408);
}

.epas-progress-arrow {
	grid-column: 1 / 8;
	grid-row: 2;
	position: relative;
	align-self: center;
	height: 22px;
}

.epas-progress-arrow-line {
	position: absolute;
	top: 50%;
	left: 0;
	right: 28px;
	height: 10px;
	transform: translateY(-50%);
	background: var(--wp--preset--color--pantone-3405);
	opacity: .4;
}

.epas-progress-arrow-head {
	position: absolute;
	top: 50%;
	right: 0;
	transform: translateY(-50%);
	width: 0;
	height: 0;
	border-top: 14px solid transparent;
	border-bottom: 14px solid transparent;
	border-left: 20px solid var(--wp--preset--color--pantone-3405);
	opacity: .4;
}

.epas-progress-head {
	padding: 20px 24px 4px;
}

.epas-progress-head h3 {
	margin: 0 0 6px;
	color: var(--wp--preset--color--reflex-blue);
	font-family: var(--wp--preset--font-family--europea);
	font-weight: 800;
	font-size: 1.7rem;
}

.epas-progress-head p {
	margin: 0;
	color: var(--wp--preset--color--reflex-blue);
	font-family: var(--wp--preset--font-family--europea);
	font-size: 1rem;
}

.epas-progress-head--essential {
	grid-area: head-ess;
}

.epas-progress-head--optional {
	grid-area: head-opt;
}

.epas-progress-box {
	position: relative;
	text-align: center;
}

.epas-progress-box-1 { grid-area: b1; }
.epas-progress-box-2 { grid-area: b2; }
.epas-progress-box-3 { grid-area: b3; }
.epas-progress-box-4 { grid-area: b4; }
.epas-progress-box-5 { grid-area: b5; }
.epas-progress-box-6 { grid-area: b6; }
/* Grey backdrop drawn as ::before rather than the box's own background+
   padding: padding pushes every child down by the same amount, which was
   quietly knocking this box's label 10px out of alignment with the other
   six (found 2026-07-22, same day this was added).

   Getting this to sit BEHIND the square/label needed two attempts. Source
   order alone doesn't decide paint order once anything is `position`ed: a
   plain in-flow (non-positioned) element always paints before ANY
   positioned element with z-index:auto/0, regardless of which comes first
   in the markup - so a naive "::before is generated first, so it must
   paint first" assumption is wrong the moment the square-slot/label aren't
   themselves positioned, and the grey ends up covering them completely
   (found immediately from Asher's screenshot after the first attempt went
   live). Fix: give `.epas-progress-square-slot` and `.epas-progress-label`
   `position:relative` too (no offset - purely to opt them into the same
   painting bucket as the ::before). With all three now positioned/z-index
   auto, source order finally does what's expected: ::before first = drawn
   first = behind. */
.epas-progress-box-7 {
	grid-area: b7;
	position: relative;
}

.epas-progress-box-7::before {
	content: "";
	position: absolute;
	top: -10px;
	left: -10px;
	right: -10px;
	bottom: -4px;
	background: #D6D9DA;
}

/* The empty (red) square renders smaller than the filled (green) one on
   purpose - Asher's call, 2026-07-22: size becomes a second signal alongside
   colour, so a row of mostly-small-red boxes visibly reads as "not much done
   yet" before you even register the colours. The slot below is fixed at the
   filled square's rendered size and bottom-aligns its square, so labels stay
   on one baseline across the row regardless of which boxes are still small.
   84px content-box + 4px border each side = 92px actual rendered height -
   the slot has to match the BORDER-box size (92px), not the CSS width/height
   value (84px), or the filled square overflows the slot by 8px and eats
   into whatever padding sits around it (found via box-7's grey background
   looking squeezed only in the filled state, 2026-07-22). */
.epas-progress-square-slot {
	position: relative;
	height: 92px;
	display: flex;
	align-items: flex-end;
	justify-content: center;
}

.epas-progress-box .epas-progress-square {
	width: 58px;
	height: 58px;
	border: 4px solid var(--wp--preset--color--pantone-1795);
	background: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--wp--preset--font-family--europea);
	font-weight: 800;
	font-size: 1.4rem;
	line-height: 1;
	color: var(--wp--preset--color--pantone-1795);
	transition: width .3s ease, height .3s ease, border-color .3s ease, background-color .3s ease, color .3s ease;
}

.epas-progress-box.is-filled .epas-progress-square {
	width: 84px;
	height: 84px;
	border-color: var(--wp--preset--color--pantone-3405);
	background: var(--wp--preset--color--pantone-3405);
	color: #fff;
	font-size: 2rem;
}

.epas-progress-box .epas-progress-label {
	position: relative;
	display: block;
	margin-top: 10px;
	color: var(--wp--preset--color--reflex-blue);
	font-family: var(--wp--preset--font-family--europea);
	font-weight: 700;
	font-size: 0.85rem;
	line-height: 1.15;
	text-decoration: none;
}

/* Labels are turned into links (to the matching evidence table further down
   the page) by page 1400's own script, not by this file - see that page's
   Custom HTML block. This is just the link's visual treatment: no underline
   at rest (reads as a plain heading, matching the pre-link design Asher
   already approved), underline + a visible focus ring on hover/keyboard
   focus so it's still discoverable as interactive and accessible. */
a.epas-progress-label:hover,
a.epas-progress-label:focus-visible {
	text-decoration: underline;
}

a.epas-progress-label:focus-visible {
	outline: 2px solid var(--wp--preset--color--pantone-2727);
	outline-offset: 2px;
}

.epas-progress-box .epas-progress-tick {
	font-size: 1.8rem;
}

/* Small grey tail pointing from Trip Write-up down to its explanation -
   Asher's call, 2026-07-22: that note is specifically about the write-up
   box, not the whole optional row, so it needed a direct visual link to it
   rather than just sitting underneath the general row. */
.epas-progress-connector {
	grid-area: conn;
	justify-self: center;
	width: 0;
	height: 0;
	border-left: 10px solid transparent;
	border-right: 10px solid transparent;
	border-top: 10px solid #D6D9DA;
}

.epas-progress-callout {
	grid-area: note;
	align-self: start;
	background: #D6D9DA;
	color: var(--wp--preset--color--reflex-blue);
	font-family: var(--wp--preset--font-family--europea);
	font-size: 0.95rem;
	padding: 14px 20px;
}

@media only screen and (max-width: 900px) {
	.epas-progress-wrap {
		grid-template-columns: repeat(3, 1fr);
		grid-template-areas:
			"head-ess head-ess head-ess"
			"b1 b2 b3"
			"head-opt head-opt head-opt"
			"b4 b5 b6"
			"b7 . ."
			"conn . ."
			"note note note";
	}

	.epas-progress-bg-essential {
		grid-column: 1 / 4;
		grid-row: 1 / 3;
	}

	.epas-progress-arrow {
		display: none;
	}
}

/* ---- Formidable tidy-ups found via the "Your Ambassadors" table, 2026-07-22 ----
   Both fixes are scoped to `.frm-grid` (Formidable's own class on every View
   table with inline-edit enabled), not just this one table, because the
   markup pattern causing each bug is the plugin's, not something authored
   per-page - so any other Formidable table with the same feature enabled
   would have the same bug. */

/* Rows with an "Edit" link were visibly taller than rows without one. The
   Edit cell wraps its link in a bare <p> (default browser margin) plus a
   trailing <br> that adds a second, empty line - neither serves a purpose
   here, they're just how the plugin emits this markup. */
.frm-grid td p {
	margin: 0;
}

.frm-grid .frm_edit_link_container br {
	display: none;
}

/* Formidable's CSV-export link ("Download list") sits flush under the table
   with no breathing room by default. */
a.export-view {
	display: inline-block;
	margin-top: 1em;
}

/* ---- "Your Ambassadors" table split into collapsed Senior/Junior groups ----
   Built client-side (page 1400's own script, not a new Formidable View) by
   regrouping the already-rendered table's own rows into two <details>
   elements - keeps every row's real Edit/Delete link intact (they're moved,
   not recreated), and needs no Formidable config change, so this survives a
   France/Belgium clone with a differently-shaped Ambassadors table exactly
   as-is. Collapsed by default is the native <details> behaviour - no JS
   toggle logic needed for that part. */
.epas-ambassadors-group {
	margin-bottom: 8px;
}

.epas-ambassadors-group summary {
	cursor: pointer;
	font-family: var(--wp--preset--font-family--europea);
	font-weight: 700;
	color: var(--wp--preset--color--reflex-blue);
	padding: 8px 0;
}

.epas-ambassadors-group table {
	margin-top: 4px;
}
