/*
 * GeleVB — page layout CSS. CLEAN REBUILD — step 1 (hero only).
 * Author: BouwArchitectbaas · 2026-06-05
 *
 * SCOPE: LAYOUT ONLY, all inside `@layer components`. Typography sizes and colour
 * are owned by theme.json (unlayered → wins over this layer by construction). This
 * file must NEVER set a font-size on a hero-H1 selector — that rule is the H1 bug
 * and it does not exist here. Later steps append their section layout below the
 * hero block, same @layer.
 *
 * The @layer ORDER is declared once in style.css:
 *   @layer base, wp-overrides, components, utilities;
 * Everything here lives in `components`.
 */

/* Single named breakpoint where the 2-col layouts stop fitting cleanly. */
:root {
	--gelevb-bp: 880px;
}

@layer components {

	/* ========================================================================
	 * Block 0 — Header (on yellow). Build-Spec §2 Block 0.
	 * Step 1: a simple bar (not yet sticky) so it never obscures the hero H1.
	 * The wordmark size is its own clamp — it is NOT an H1 and does not compete
	 * with theme.json's hero-H1 size.
	 * ====================================================================== */
	.gelevb-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: var(--wp--preset--spacing--md);
		padding: var(--wp--preset--spacing--sm) var(--wp--preset--spacing--md);
		background: var(--wp--preset--color--surface-brand);
		/* Thin dark rule between header and body (per mockup, 2026-06-10). Uses the
		 * themeable footer-ink token (#2B2A24, warm dark — NOT hard #000) so it stays
		 * restyleable from theme.json. The header is a full-width block-level flex bar,
		 * so the 1px border-bottom spans edge-to-edge. Not sticky yet (sticky = later
		 * step), so no z-index/scroll interaction to clash with. */
		border-bottom: 1px solid var(--wp--preset--color--surface-footer);
	}
	.gelevb-header__wordmark {
		font-weight: 800;
		letter-spacing: 0.01em;
		text-transform: uppercase;
		text-decoration: none;
		color: var(--wp--preset--color--text-on-brand);
		font-size: clamp(13px, 2.6vw, 18px);
		white-space: nowrap;
	}
	.gelevb-header__nav {
		display: flex;
		align-items: center;
		gap: var(--wp--preset--spacing--md);
	}
	.gelevb-header__link {
		color: var(--wp--preset--color--text-on-brand);
		text-decoration: none;
		font-weight: 600;
	}
	.gelevb-header__burger {
		display: inline-flex;
		flex-direction: column;
		justify-content: center;
		gap: 5px;
		width: 44px;
		height: 44px;
		padding: 10px;
		background: transparent;
		border: 0;
		cursor: pointer;
	}
	.gelevb-header__burger span {
		display: block;
		height: 2px;
		width: 100%;
		background: var(--wp--preset--color--text-on-brand);
		border-radius: 2px;
	}
	.gelevb-header__menu[hidden] {
		display: none;
	}

	/* ========================================================================
	 * Block 1 — Hero (yellow). Desktop 2-col text-left / image-right;
	 *           mobile image above text. Build-Spec §2 / §7.
	 * NOTE: the floating-overlap onto the feature card (§1a) is a LATER step.
	 *       Step 1 is a self-contained hero so the H1-gate reads cleanly.
	 * ====================================================================== */
	.gelevb-hero {
		/* Width is inherited, NOT set here. The PARENT <section> (hero.php) carries
		 * `align:wide`, so WP's UNLAYERED constrained-layout rule gives that section
		 * max-width = wideSize = 1440px and centres it inside the root-padding
		 * gutters. The section is `default`(flow) layout so it does not re-cap this
		 * grid; `.gelevb-hero` simply fills the section's 1440px band at width:100%.
		 * We deliberately set NO width / max-width here: an @layer'd width would lose
		 * to WP's unlayered layout CSS anyway, and that mismatch was the old desktop
		 * root cause (hero pinned to contentSize=720px, starving the text column to
		 * ~432px so "vaccinatieboekje" could not fit on one line and broke mid-word). */
		display: grid;
		gap: var(--wp--preset--spacing--lg);
		/* COMPACT PASS: the LEFT column is now a TALL stack (copy + white card + cream
		 * card). Top-align the columns so the booklet's top lines up with the H1, like
		 * the mockup — `center` would float the booklet down to the middle of the tall
		 * stack and re-open a big gap above it. */
		align-items: start;
		/* Grid children must be allowed to shrink below their content's intrinsic
		 * size, otherwise the long H1 word forces the text column wider than the
		 * track and pushes the whole grid past the viewport at 390px. This is the
		 * mobile-overflow root cause fix (constraint B). */
		grid-template-columns: minmax(0, 1fr);
		/* Defensive belt-and-braces against horizontal scroll at 390px. The REAL
		 * fix for the overflow is the H1 clamp lower-bound in theme.json (sized so
		 * the unbreakable 16-char word "vaccinatieboekje" fits inside 390px minus
		 * root padding). `clip` (not `hidden`) does NOT create a scroll container,
		 * so it will not break `position: sticky` on the later header/bottom-bar,
		 * and it leaves vertical flow untouched — note the booklet's floating
		 * overlap onto the feature card (§1a) is VERTICAL and lands on a LATER
		 * block, so clipping horizontal-only here is safe for it. */
		overflow-x: clip;
	}

	/* ---- Mobile (390px floor → up to the breakpoint) ----
	 * DOM source order is text-first (copy + both cards), media-second (fixed in
	 * hero.php for SEO/a11y). The MOBILE VISUAL order Stef wants is different:
	 *   hero copy → BOOKLET → white USP card → cream social card
	 * i.e. the booklet must sit BETWEEN the copy and the cards, and hang slightly
	 * over the top of the white USP card (the "floating booklet" feature).
	 *
	 * HOW (no DOM change, desktop untouched): on mobile we set `display: contents`
	 * on .gelevb-hero__text, which dissolves that wrapper so its three children
	 * (copy, white card, cream card) become DIRECT grid items of .gelevb-hero,
	 * SIBLINGS of .gelevb-hero__media. All four are then re-sequenced with `order`
	 * in the single-column grid. The grid's own row-`gap` (lg) supplies the rhythm,
	 * so we no longer need the flex column + its gap on .gelevb-hero__text here.
	 * Desktop keeps the original 2-col grid (text-wrapper intact) — the
	 * `display:contents` + ordering live ONLY in this mobile block and are reset at
	 * the breakpoint. */
	.gelevb-hero__text {
		display: contents;          /* mobile: dissolve so children join the hero grid */
	}
	.gelevb-hero__copy {
		order: 1;
		min-width: 0;               /* allow it to shrink inside the grid track */
		max-width: 100%;
	}
	.gelevb-hero__media {
		order: 2;                   /* booklet BETWEEN copy and the cards */
	}
	.gelevb-hero .gelevb-features {   /* white USP card */
		order: 3;
		/* The booklet hangs a touch over THIS card's top. The card pulls up under the
		 * booklet's negative bottom-margin; a higher stacking context on the booklet
		 * keeps the image on top. */
		position: relative;
		z-index: 0;
	}
	.gelevb-hero .gelevb-social {     /* cream social card */
		order: 4;
	}
	/* The copy sub-group carries the H1/subhead/USP; its paragraphs own their own
	 * margins. Kill the trailing margin on its last child so the grid row-gap is the
	 * single source of the copy→booklet spacing (no doubled gap). */
	.gelevb-hero__copy > :last-child {
		margin-bottom: 0;
	}
	/* ---- The floating booklet (mobile) ----
	 * Width constraint (PUNT 2): cap the booklet to ~68vw so it reads comfortably
	 * inside a 390px screen with margin around it, not rand-tot-rand. 68vw @ 390 =
	 * ~265px. Right-anchored (justify-self:end) to match the desktop/mockup side and
	 * to line up with the overhang onto the card below it.
	 * Overlap (PUNT 1): the negative bottom-margin that pulls the next grid item (white
	 * card) up UNDER the booklet is NOT here — it CANNOT live in @layer components.
	 * WordPress emits an UNLAYERED rule `:root :where(.is-layout-flow) > *{
	 * margin-block-end:0}` and unlayered ALWAYS beats layered (proven: this rule was
	 * computing to 0). So the overlap margin moved to an UNLAYERED block at the very
	 * end of this file (search "UNLAYERED OVERLAP OVERRIDE"). Everything else (width,
	 * z-index, pointer-events) is layered and works. NO transform on the image (hard
	 * rule, Decisions vervolg 11) — overlap is pure positioning. */
	.gelevb-hero__media {
		justify-self: end;          /* right-anchored, matches mockup */
		width: min(68vw, 300px);
		position: relative;
		z-index: 1;                 /* booklet floats ABOVE the white card below it */
		pointer-events: none;       /* guard (a): overhang never blocks card taps */
	}
	/* Reserve the image ratio so there is no CLS before the webp paints. The webp
	   ships explicit width/height too; this matches it. Shadow is BAKED INTO the
	   asset → NO box-shadow / drop-shadow here (would double it). */
	.gelevb-hero__media .wp-block-image,
	.gelevb-hero__media img {
		display: block;
		width: 100%;
		height: auto;
		max-width: 100%;            /* constraint B belt-and-braces */
	}
	.gelevb-hero__media img {
		aspect-ratio: var(--wp--custom--hero--ratio);
	}

	/* The H1 gets NO font-size here — theme.json styles.elements.h1 owns it
	   (this is the H1-bug guard: a font-size on a hero-H1 selector must not exist).
	   We only set layout: bottom margin, explicit no-hyphenation, and a wrap that
	   keeps "vaccinatieboekje" intact as one whole word. The mockup wants exactly
	   two lines: "Het gele" / "vaccinatieboekje", no hyphen.

	   On the hyphens: the unlayered `hyphens: auto` that USED to force the
	   "vaccina-/tieboekje" hyphen has been removed from the style.css heading reset
	   (initial value is `manual` → no auto-hyphenation), so the bug is already gone
	   at source. These `hyphens: none` lines are kept as explicit, self-documenting
	   intent for this H1 specifically; they no longer have to out-rank an unlayered
	   competitor.

	   `overflow-wrap: normal` here keeps the long word from breaking mid-word on
	   desktop (where the wider text measure fits it on its own line). It is safe
	   because on the 390px floor the word now FITS (clamp lower-bound sized for it),
	   so `normal` does not cause an overflow; the base-layer `break-word` is the
	   ultimate fallback for any narrower-than-390px edge device. */
	.gelevb-hero__text h1 {
		margin: 0 0 var(--wp--preset--spacing--sm);
		hyphens: none;
		-webkit-hyphens: none;
		/* No `overflow-wrap` override here. The unlayered base reset
		 * `h1 { overflow-wrap: break-word }` (style.css) is the safety net for any
		 * device narrower than the 390px floor; on desktop the wide column makes
		 * "vaccinatieboekje" fit on one line, so it never actually breaks. Forcing
		 * `normal` here (the old line) re-introduced the mobile overflow because it
		 * forbade the word from wrapping even when it had to.
		 *
		 * `balance` gives the wanted two clean lines "Het gele" / "vaccinatieboekje"
		 * (it breaks between words, never mid-word) on both desktop and the 390px
		 * floor, where the long word fits the measure as its own line. */
		text-wrap: balance;
	}

	/* Subhead + USP: layout rhythm + weight only. Their SIZE comes from the `md`
	   font-size preset set on the block (theme.json), not from here. */
	.gelevb-hero__subhead {
		margin: 0 0 var(--wp--preset--spacing--md);
		font-weight: 600;
		line-height: 1.25;
	}
	.gelevb-hero__usp {
		margin: 0;
		font-weight: 700;
	}

	/* ----- Desktop: 2-col reflow above the named breakpoint. -----
	 * Mockup composition: text column LEFT and WIDER (so the whole word
	 * "vaccinatieboekje" fits on one line at the H1's max clamp size), booklet
	 * RIGHT, larger/dominant. Its tilt/shadow are baked into the source image
	 * (HGVB-2025.webp) — do NOT re-add a CSS rotate; the source renders 1:1.
	 * Columns are intentionally asymmetric (text wider than booklet). */
	@media (min-width: 880px) {
		.gelevb-hero {
			grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
			gap: var(--wp--preset--spacing--xxl);
			align-items: center;
		}
		/* RESET the mobile `display:contents` trick: on desktop the left column is a
		 * REAL block again (text + both cards stacked inside it as the LEFT grid
		 * track), with the booklet as the RIGHT track. This restores the approved
		 * desktop composition exactly — the mobile re-sequencing does not apply here. */
		.gelevb-hero__text {
			display: flex;
			flex-direction: column;
			gap: var(--wp--preset--spacing--md);
			/* widen the text measure so the long word never wraps to 3 lines */
			max-width: 40rem;
		}
		/* Drop the mobile `order` values so source order (text-left, media-right)
		 * governs the 2-col grid again. The cards are nested inside __text on desktop,
		 * so they are NOT grid items here and their mobile order is inert — resetting
		 * the wrappers' order is what matters. */
		.gelevb-hero__copy,
		.gelevb-hero__media {
			order: 0;
		}
		.gelevb-hero__media {
			justify-self: end;
			/* No CSS tilt: the booklet's tilt/perspective is baked into the source
			 * image (HGVB-2025.webp), so it must render 1:1 with no transform. The
			 * layout box is now axis-aligned, so the booklet can sit flush in its
			 * column without the rotated corner spilling toward the gutter. */
			width: min(100%, 500px);
			/* Reset the mobile floating-overlap: no negative margin, no overhang, taps
			 * restored. Desktop overlap (§1a) is a separate later concern, not here. */
			margin-bottom: 0;
			pointer-events: auto;
			z-index: auto;
		}
	}

	/* ========================================================================
	 * Block 2 — Feature card (WHITE USP card). Build-Spec §2 Block 2.
	 * A white rounded card with 5 rows (green check + text), thin dividers.
	 * It sits on the yellow surface in the LEFT column, directly under the hero
	 * text (mockup). LAYOUT ONLY — type size/colour stay owned by theme.json.
	 *
	 * Placement vs the hero (COMPACT PASS, 2026-06-08): the card is now NESTED in
	 * the hero's LEFT column (.gelevb-hero__text), directly under the copy. It no
	 * longer needs its own width cap / left-align — the parent column is already
	 * capped (40rem on desktop) and the flex-stack gap supplies the rhythm. The card
	 * simply fills the column width. The booklet→card floating overlap (§1a) is still
	 * NOT attempted (it would require positioning against the untouchable booklet).
	 * Mobile: full width, no horizontal overflow at 390px.
	 * ====================================================================== */
	.gelevb-card {
		background: var(--wp--preset--color--surface-base);
		border-radius: var(--wp--custom--radius--card);
		box-shadow: var(--wp--custom--shadow--card);
		/* Vertical padding only; the rows manage their own horizontal inset so the
		 * dividers can run the full card width if we ever want them edge-to-edge. */
		padding: var(--wp--preset--spacing--xs) var(--wp--preset--spacing--lg);
		margin: 0;                       /* it's a <ul>; kill the UA list margins */
		list-style: none;
		/* Mobile floor: full width of the constrained band, never wider. */
		width: 100%;
		max-width: 100%;
	}

	.gelevb-features__row {
		display: flex;
		align-items: center;             /* icon vertically centred to the text */
		gap: var(--wp--preset--spacing--sm);
		padding: var(--wp--preset--spacing--sm) 0;
		/* Thin low-contrast divider between rows; none above the first. */
		border-top: 1px solid var(--wp--preset--color--divider);
	}
	.gelevb-features__row:first-child {
		border-top: 0;
	}

	.gelevb-features__icon {
		flex: 0 0 auto;
		width: 24px;
		height: 24px;
		display: block;
		/* The source webp is 251×256 (near-square). Lock the box so the slightly
		 * non-square source never distorts the row rhythm. */
		object-fit: contain;
	}

	/* Row text: layout/weight only. Its SIZE/colour come from theme.json (base
	 * body size + text-on-base). No font-size here. */
	.gelevb-features__text {
		min-width: 0;                    /* allow wrapping inside the flex row */
		font-weight: 600;
		line-height: 1.3;
		color: var(--wp--preset--color--text-on-base);
	}

	/* ========================================================================
	 * Block 3 — Social-proof card (CREAM "50.000 reizigers"). Build-Spec §2 Block 3.
	 * Cream rounded card, nested under the WHITE USP card in the hero's left column.
	 * Layout = people icon LEFT + a two-part text (bold count line + continuation)
	 * to its right. Re-uses the .gelevb-card base (radius/shadow/padding system); the
	 * --cream modifier only swaps the surface colour so it reads distinct from the
	 * white card above it. LAYOUT ONLY — type size/colour owned by theme.json.
	 * ====================================================================== */
	.gelevb-card--cream {
		background: var(--wp--preset--color--surface-cream);
	}
	/* The social card is a horizontal icon|text row, not a list of rows. Override the
	 * vertical card padding to a balanced inset and lay out icon + text inline. */
	.gelevb-social {
		display: flex;
		align-items: center;
		gap: var(--wp--preset--spacing--md);
		padding: var(--wp--preset--spacing--md) var(--wp--preset--spacing--lg);
	}
	.gelevb-social__icon {
		flex: 0 0 auto;
		height: 40px;
		width: auto;                     /* ratio follows the 397×256 source */
		display: block;
		object-fit: contain;
	}
	/* Text block: layout/weight only; SIZE + colour come from theme.json (base body
	 * size + text-on-base). The count line is bold + sits on its own line; the
	 * continuation follows under it. No font-size here. */
	.gelevb-social__text {
		margin: 0;
		min-width: 0;                    /* allow wrapping inside the flex row */
		line-height: 1.3;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-social__count {
		display: block;
		font-weight: 800;
	}
	.gelevb-social__cont {
		display: block;
		font-weight: 500;
	}

	/* ========================================================================
	 * Block 5 — "Waarom dit boekje?" + "Veelgestelde vragen". Build-Spec §2 Block 5.
	 * Two WHITE cards on the yellow band. Desktop (≥ --gelevb-bp) = side-by-side,
	 * Waarom LEFT / FAQ RIGHT. Mobile = stacked (DOM order: Waarom then FAQ).
	 * Both cards re-use the EXISTING .gelevb-card / --white base (same white surface,
	 * radius, shadow, padding system as Block 2). LAYOUT ONLY — type size/colour stay
	 * owned by theme.json. No new hex; only existing palette roles + spacing tokens.
	 * ====================================================================== */

	/* Two-up on desktop, single column (stacked) on mobile. Same breakpoint token as
	 * the rest of the page so the reflow is consistent. align-items:start keeps the
	 * two cards top-aligned when their heights differ. */
	.gelevb-whyfaq {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		gap: var(--wp--preset--spacing--lg);
	}

	/* Shared card heading for both white cards. Layout/weight only; SIZE comes from
	 * theme.json's heading element (this is an <h2>) — no font-size set here. The card
	 * already supplies its white surface/radius/shadow via .gelevb-card. */
	.gelevb-card__title {
		margin: 0 0 var(--wp--preset--spacing--md);
		font-weight: 800;
		line-height: 1.2;
		color: var(--wp--preset--color--text-on-base);
	}

	/* The two cards override the bare-list .gelevb-card padding to a balanced block
	 * inset (the base was tuned for the vertical USP list). They are block containers,
	 * not <ul>, so no list reset is needed. */
	.gelevb-why,
	.gelevb-faq {
		padding: var(--wp--preset--spacing--lg);
	}

	/* ---- "Waarom" rows: icon + text, mirrors the Block-2 feature-row mechanic. ---- */
	.gelevb-why__list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
	}
	.gelevb-why__row {
		display: flex;
		align-items: center;
		gap: var(--wp--preset--spacing--sm);
		padding: var(--wp--preset--spacing--sm) 0;
		border-top: 1px solid var(--wp--preset--color--divider);
	}
	.gelevb-why__row:first-child {
		border-top: 0;
	}
	.gelevb-why__icon {
		flex: 0 0 auto;
		width: 28px;
		height: 28px;
		display: block;
		object-fit: contain;
	}
	.gelevb-why__text {
		min-width: 0;
		font-weight: 600;
		line-height: 1.3;
		color: var(--wp--preset--color--text-on-base);
	}

	/* ---- FAQ: native <details>/<summary> accordion, no JS. ---- */
	.gelevb-faq__item {
		border-top: 1px solid var(--wp--preset--color--divider);
	}
	.gelevb-faq__item:first-of-type {
		border-top: 0;
	}
	/* Whole summary row is the click/keyboard target; min-height clears 44px. The
	 * default UA disclosure triangle is removed so the styled chevron is the only
	 * affordance. */
	.gelevb-faq__q {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: var(--wp--preset--spacing--sm);
		min-height: 48px;
		padding: var(--wp--preset--spacing--sm) 0;
		cursor: pointer;
		list-style: none;                /* Firefox: drop default marker */
		font-weight: 700;
		line-height: 1.3;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-faq__q::-webkit-details-marker {
		display: none;                   /* WebKit/Blink: drop default marker */
	}
	.gelevb-faq__q:focus-visible {
		outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--focus-ring);
		outline-offset: var(--wp--custom--focus--offset);
		border-radius: var(--wp--custom--radius--input);
	}
	.gelevb-faq__q-text {
		min-width: 0;
	}
	/* Pure-CSS chevron from current text colour; rotates when the item is open. */
	.gelevb-faq__chevron {
		flex: 0 0 auto;
		width: 10px;
		height: 10px;
		border-right: 2px solid currentColor;
		border-bottom: 2px solid currentColor;
		transform: rotate(45deg);
		transition: transform 0.15s ease;
	}
	.gelevb-faq__item[open] .gelevb-faq__chevron {
		transform: rotate(-135deg);
	}
	.gelevb-faq__a {
		padding: 0 0 var(--wp--preset--spacing--sm);
		line-height: 1.5;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-faq__a p {
		margin: 0;
	}
	/* "lees meer"-teaser link (kwijt item 4). Own paragraph below the snippet so it sits
	 * on its own line. Colour = focus-ring blue (#0A3FB0) on the white card (#FFFFFF) =
	 * 8.59:1, well above AA 4.5:1, and reads as an obvious link next to the near-black
	 * body text. Underlined so it is not colour-only. Hover/focus darken + keep the
	 * underline; focus-visible reuses the same ring as the summary rows. */
	.gelevb-faq__more-wrap {
		margin-top: var(--wp--preset--spacing--sm);
	}
	.gelevb-faq__more {
		display: inline-flex;
		align-items: baseline;
		gap: 0.35em;
		padding: 0.5em 0;                /* vertical tap room without forcing a fixed box */
		font-weight: 700;
		color: var(--wp--preset--color--focus-ring);
		text-decoration: underline;
		text-underline-offset: 0.18em;
	}
	.gelevb-faq__more:hover,
	.gelevb-faq__more:focus-visible {
		color: #062a78;                  /* darker blue on #FFFFFF = 11.9:1, still AA+ */
		text-decoration: underline;
	}
	.gelevb-faq__more:focus-visible {
		outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--focus-ring);
		outline-offset: var(--wp--custom--focus--offset);
		border-radius: var(--wp--custom--radius--input);
	}
	.gelevb-faq__more-arrow {
		font-weight: 700;
	}

	/* ---- Desktop: two cards side-by-side (Waarom LEFT / FAQ RIGHT). ----
	 * Column gap = `lg` (24px). The mockup's sampled card gap is modest (~2% of the
	 * card width), so `lg` matches it; the original `2xl` (48px) overshot the mockup
	 * AND silently collapsed to 0 because `--wp--preset--spacing--2xl` was never
	 * emitted (leading-digit preset slug bug — see theme.json rename to `xxl`). Using
	 * `lg` here = a real visible token that reads like the mockup. Size is a
	 * main-session screenshot-loop call; bump to `xl`/`xxl` there if more air is wanted. */
	@media (min-width: 880px) {
		.gelevb-whyfaq {
			grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
			gap: var(--wp--preset--spacing--lg);
			align-items: start;
		}
	}

	/* ========================================================================
	 * Block 4 — "Bestel direct" order box (CONVERSION CORE). Build-Spec §3.
	 * ONE white rounded card on the yellow band. Desktop = 2 columns inside the
	 * card (price-list LEFT / Woo form RIGHT) with a vertical divider. Mobile
	 * (390px) = STACKED single column (Decisions vervolg-12 deliberate deviation
	 * from the mobile mockup). LAYOUT ONLY — type size/colour owned by theme.json.
	 *
	 * TOKEN MAPPING (the stale theme referenced border-input / trust-accent /
	 * action-primary; only the first two are absent in the new palette). Mapped to
	 * the new theme.json roles: card border/divider -> `divider`; muted helper text
	 * -> `text-on-base`; the chosen-row highlight + radio accent -> `action-primary`
	 * (still present). No font-size is set on any heading here.
	 * ====================================================================== */

	/* The section band re-uses the page surface-brand background (markup). The card
	 * is the white panel; cap it to a comfortable reading width and centre it. */
	.gelevb-orderbox {
		background: var(--wp--preset--color--surface-base);
		border-radius: var(--wp--custom--radius--card);
		box-shadow: var(--wp--custom--shadow--card);
		padding: var(--wp--preset--spacing--lg);
		width: 100%;
		max-width: 100%;
		margin: 0 auto;
	}

	.gelevb-orderbox__title {
		margin: 0 0 var(--wp--preset--spacing--lg);
		font-weight: 800;
		line-height: 1.2;
		color: var(--wp--preset--color--text-on-base);
		text-align: center;
	}

	/* MOBILE-FIRST = single stacked column. DOM order (price-list -> divider ->
	 * form) is already the wanted stack order, so no `order` juggling. */
	.gelevb-orderbox__grid {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		gap: var(--wp--preset--spacing--lg);
	}
	.gelevb-orderbox__col {
		min-width: 0;            /* allow columns to shrink inside the grid track (390px) */
	}

	/* The divider is a horizontal rule between the stacked price-list and form on
	 * mobile; it becomes a vertical rule on desktop (see breakpoint below). */
	.gelevb-orderbox__divider {
		height: 1px;
		width: 100%;
		background: var(--wp--preset--color--divider);
	}

	/* ---- Price radio-list (recovered mechanic, tokens remapped) ---- */
	.gelevb-pricelist__fieldset {
		border: 0;
		margin: 0;
		padding: 0;
		min-width: 0;            /* fieldset has an intrinsic min-width; kill it for 390px */
	}
	.gelevb-pricelist__legend {
		padding: 0;
		margin: 0 0 var(--wp--preset--spacing--sm);
		font-weight: 700;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-pricelist__list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: var(--wp--preset--spacing--xs);
	}
	.gelevb-pricelist__item {
		margin: 0;
	}
	/* The whole row is tappable; min-height clears the 44px target with margin.
	 * box-sizing:border-box keeps the 1px border + horizontal padding INSIDE the
	 * declared box width so the row never out-grows its track. SINGLE-LINE: the
	 * label is `flex-wrap: nowrap` so price + sep + count stay on ONE line inside
	 * the bordered box (fix 2026-06-10 v2, reverting the earlier flex-wrap:wrap
	 * which dropped the count chip onto a second line — NOT wanted). The room to
	 * fit the longest label ("€ 67,05 — 7 boekjes") on one line is created by
	 * widening the left grid track instead (see the 880px breakpoint), and the
	 * count chip is allowed to take remaining space via flex-grow so the row
	 * fills its track without overflowing it. */
	.gelevb-pricelist__label {
		display: flex;
		flex-wrap: nowrap;
		align-items: center;
		gap: var(--wp--preset--spacing--xs) var(--wp--preset--spacing--sm);
		min-height: 48px;
		padding: var(--wp--preset--spacing--sm) var(--wp--preset--spacing--md);
		border: 1px solid var(--wp--preset--color--divider);
		border-radius: var(--wp--custom--radius--input);
		box-sizing: border-box;
		cursor: pointer;
		background: var(--wp--preset--color--surface-base);
		color: var(--wp--preset--color--text-on-base);
		line-height: 1.3;
	}
	.gelevb-pricelist__radio {
		width: 22px;
		height: 22px;
		margin: 0;
		flex: 0 0 auto;
		accent-color: var(--wp--preset--color--action-primary);
	}
	.gelevb-pricelist__price {
		font-weight: 700;
		white-space: nowrap;
	}
	.gelevb-pricelist__sep {
		color: var(--wp--preset--color--divider);
	}
	.gelevb-pricelist__count {
		color: var(--wp--preset--color--text-on-base);
		/* nowrap keeps the count chip on ONE line ("7 boekjes" never splits between the
		 * number and the noun). flex:1 lets the count take the leftover track width so
		 * the row fills (not overflows) the bordered box; the price stays nowrap on the
		 * left and the box itself is sized wide enough by the left grid track. */
		flex: 1 1 auto;
		min-width: 0;
		white-space: nowrap;
	}
	/* Selected row highlight — feedback, no badge/discount frivolity. */
	.gelevb-pricelist__label:has(.gelevb-pricelist__radio:checked) {
		border-color: var(--wp--preset--color--action-primary);
		box-shadow: inset 0 0 0 1px var(--wp--preset--color--action-primary);
	}
	.gelevb-pricelist__radio:focus-visible {
		outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--focus-ring);
		outline-offset: var(--wp--custom--focus--offset);
	}
	.gelevb-pricelist__empty {
		text-align: center;
		color: var(--wp--preset--color--text-on-base);
	}

	/* ---- Live total (updated by pricelist.js on radio change, aria-live) ---- */
	.gelevb-orderbox__total {
		display: flex;
		align-items: baseline;
		justify-content: space-between;
		gap: var(--wp--preset--spacing--sm);
		margin: var(--wp--preset--spacing--md) 0 var(--wp--preset--spacing--xxs);
		padding-top: var(--wp--preset--spacing--sm);
		border-top: 1px solid var(--wp--preset--color--divider);
	}
	.gelevb-orderbox__total-label {
		font-weight: 700;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-orderbox__total-value {
		font-weight: 800;
		font-size: var(--wp--preset--font-size--lg);
		color: var(--wp--preset--color--text-on-base);
		white-space: nowrap;
	}
	.gelevb-orderbox__ship {
		margin: 0;
		font-size: var(--wp--preset--font-size--sm);
		color: var(--wp--preset--color--text-on-base);
	}

	/* ---- Pay lockup under the form ---- */
	.gelevb-orderbox__pay {
		margin-top: var(--wp--preset--spacing--md);
		text-align: center;
	}
	.gelevb-orderbox__pay .gelevb-pay-lockup {
		display: inline-block;
		width: 160px;
		max-width: 100%;
		height: auto;
	}

	/* ---- Desktop: 2-col reflow (price-list LEFT / form RIGHT) with a vertical
	 * divider drawn by the middle grid cell. The grid becomes 3 tracks:
	 * [choose] [1px divider] [form]. ---- */
	@media (min-width: 880px) {
		.gelevb-orderbox {
			padding: var(--wp--preset--spacing--xxl);
		}
		.gelevb-orderbox__title {
			text-align: left;
		}
		.gelevb-orderbox__grid {
			/* Left (choose) track WIDENED from 0.9fr to give the price-list room so the
			 * longest label "€ 67,05 — 7 boekjes" fits on ONE line inside its box (fix
			 * 2026-06-10 v2). minmax floor of 17rem guarantees the single-line label fits
			 * even when the constrained container is narrow; the form track (right) yields
			 * the space (1fr) but never collapses thanks to its own minmax(0,...). */
			grid-template-columns: minmax(17rem, 1fr) 1px minmax(0, 1fr);
			gap: var(--wp--preset--spacing--xxl);
			align-items: start;
		}
		/* The divider cell stretches full column height as a vertical rule. */
		.gelevb-orderbox__divider {
			height: 100%;
			width: 1px;
			align-self: stretch;
		}
	}

	/* ========================================================================
	 * Block 6 — FOOTER / COLOFON. Build-Spec §2 Block 6 (HERZIEN). NON-sticky,
	 * full-width band after </main>. The dark band colour + text colour come from
	 * theme.json (surface-footer / text-on-footer tokens, emitted as
	 * has-*-background-color / has-*-color on the part group) — NOT hardcoded here.
	 * LAYOUT ONLY below: inner max-width, link/copyright spacing, focus ring.
	 *   - Mobile: links stack (column), copyright below.
	 *   - >=720px: links in a centred row that wraps, copyright centred under them.
	 * ====================================================================== */
	.gelevb-footer__inner {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: var(--wp--preset--spacing--md);
		text-align: center;
	}

	.gelevb-footer__nav {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: var(--wp--preset--spacing--sm);
	}

	/* Footer-link LAYOUT only (underline, tap target, hover/focus shape). The link
	 * COLOUR is NOT set here on purpose: theme.json emits an UNLAYERED global rule
	 * `a:where(:not(.wp-element-button)){color:var(--…--action-primary)}` (= #1A1A1A,
	 * dark) that ALWAYS beats anything in @layer components. A layered `color:inherit`
	 * here (the previous attempt) therefore lost to that unlayered rule and the three
	 * links rendered dark #1A1A1A on the dark footer band #2B2A24 = 1.21:1, far under
	 * WCAG AA. The corrective colour lives in the UNLAYERED "FOOTER LINK COLOUR
	 * OVERRIDE" block at the end of this file — the only way to out-rank the unlayered
	 * global link rule without `!important` (same mechanic as the overlap override). */
	.gelevb-footer__link {
		text-decoration: underline;
		text-underline-offset: 2px;
		/* Min 44px tap target (theme.json custom.target.min) via vertical padding. */
		display: inline-flex;
		align-items: center;
		min-height: var(--wp--custom--target--min);
		padding: var(--wp--preset--spacing--xxs) var(--wp--preset--spacing--xs);
		line-height: 1.3;
	}
	.gelevb-footer__link:hover,
	.gelevb-footer__link:focus-visible {
		text-decoration: none;
	}
	/* Focus-ring SHAPE (offset/radius) is layered; the focus-ring COLOUR is overridden
	 * to text-on-footer in the unlayered block (the default focus-ring token #0A3FB0
	 * only reaches 1.61:1 against the dark footer band, too low to read as an
	 * indicator there — white reaches 14.39:1 and stays token-coupled to the band). */
	.gelevb-footer__link:focus-visible {
		outline-width: var(--wp--custom--focus--width);
		outline-style: solid;
		outline-offset: var(--wp--custom--focus--offset);
		border-radius: var(--wp--custom--radius--control);
	}

	.gelevb-footer__copy {
		margin: 0;
		font-size: var(--wp--preset--font-size--sm);
		opacity: 0.85;
	}

	@media (min-width: 720px) {
		.gelevb-footer__nav {
			flex-direction: row;
			flex-wrap: wrap;
			justify-content: center;
			gap: var(--wp--preset--spacing--lg);
		}
	}

	/* ========================================================================
	 * CONTENT-PAGINA — kopband + body + CTA-box. Content-pagina-spoor 2026-06-11.
	 * Hoort bij templates/page.html + patterns/cta-box.php. LAYOUT ONLY — type
	 * size/colour blijven van theme.json (kopband-h1 erft elements.h1; CTA-knop
	 * erft elements.button). Geen nieuwe hex; alleen bestaande tokens.
	 * ====================================================================== */

	/* Compacte kopband: GEEL (surface-brand) op een GELE body (Stef-besluit
	 * 2026-06-11, revert terug naar geel — de tussenstap-witte stand is hiermee
	 * teruggedraaid). Kopband en body delen nu hetzelfde gele vlak. GEEN onderrand
	 * meer: de vorige `divider`-onderrand (#E6E1CF, laag-contrast) was er om wit
	 * van wit te scheiden; op het naadloze gele vlak zou diezelfde lichte lijn als
	 * een vuil streepje lezen. De zonescheiding komt nu enkel van de section-padding
	 * (xl, template) — de kopband leest als header-zone door de ruime verticale
	 * ademing, niet door een rand. De site-nav-header heeft z'n eigen onderrand al
	 * (.gelevb-header border-bottom). */
	/* Compacte kopband: hier alleen het ritme TITEL -> LEAD + de no-overflow-
	 * garantie voor de lange NL-compound in de h1. */
	.gelevb-kopband__title {
		margin: 0 0 var(--wp--preset--spacing--sm);
		/* Geen font-size hier: de paginatitel erft theme.json elements.h1. Dat is
		 * hero-zwaar -- zie de RENDER-FLAG in page.html: als de content-h1 lichter
		 * moet, zet een lg-fontSize-override op DE H1 in de template (block-style),
		 * niet hier (zou de H1-bug-discipline doorbreken: type = enkel theme.json/
		 * block-attribuut, nooit een CSS-font-size op een titel-selector). */
		text-wrap: balance;
		/* MOBIELE-OVERFLOW-FIX (≤390px): de content-h1's bevatten lange NL-compounds
		 * ("vaccinatieboekje", "backpackers") die op een smalle viewport niet passen.
		 * De base-reset `h1 { overflow-wrap: break-word }` is hier ONVOLDOENDE: het
		 * verlaagt de MIN-CONTENT-breedte van het element niet, dus het lange woord
		 * blijft de pagina-min-content boven de viewport duwen -> globale horizontale
		 * scroll (alle tekst valt rechts weg, incl. "Contact" in de header).
		 * `overflow-wrap: anywhere` verlaagt WEL de min-content-breedte (spec-verschil
		 * met `break-word`), zodat niets de viewport overschrijdt. Het grijpt alleen
		 * in als een enkel woord anders niet past; `text-wrap: balance` houdt de
		 * normale per-woord-afbreking op bredere viewports. Geen koppelteken: dit is
		 * een harde wrap, geen hyphenation (de hyphens-bug blijft dus weg). */
		overflow-wrap: anywhere;
	}
	.gelevb-kopband__lead {
		margin: 0;
		font-weight: 600;
		line-height: 1.3;
		/* Zelfde min-content-garantie als de title: een excerpt is meerdelig en
		 * breekt normaal op witruimte, maar mocht een lead ooit een lang compound
		 * bevatten, dan mag dat de viewport nóóit verbreden (≤390px). */
		overflow-wrap: anywhere;
	}

	/* Pagina-body: leesritme tussen de blokken. De CTA-box krijgt meer lucht boven/
	 * onder zich dan een gewone alinea, zodat hij als onderbreking leest. */
	.gelevb-pagebody > * {
		margin-top: var(--wp--preset--spacing--md);
	}
	.gelevb-pagebody > .gelevb-cta {
		margin-top: var(--wp--preset--spacing--xl);
		margin-bottom: var(--wp--preset--spacing--xl);
	}

	/* CTA-box: erft .gelevb-card (surface-base/radius/shadow-systeem) uit Block 2.
	 * Hier alleen de interne stapeling kop -> subtekst -> knop. De knop zelf
	 * (core/button) erft kleur/radius van theme.json elements.button -- GEEN colour
	 * hier. width:100% zodat de kaart de leeskolom (contentSize 720px) vult, nooit
	 * breder (390px-overflow-garantie via de globale box-sizing/max-width-reset). */
	.gelevb-cta {
		width: 100%;
		max-width: 100%;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-cta__title {
		margin: 0 0 var(--wp--preset--spacing--sm);
		font-weight: 800;
		line-height: 1.2;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-cta__text {
		margin: 0 0 var(--wp--preset--spacing--md);
		line-height: 1.5;
		color: var(--wp--preset--color--text-on-base);
	}
	.gelevb-cta__actions {
		margin: 0;
	}
	/* Lange NL-knoplabels: het core/button-label wrapt netjes binnen de kaart op
	 * 390px (geen clip, geen horizontale scroll). */
	.gelevb-cta__actions .wp-block-button__link {
		max-width: 100%;
		overflow-wrap: break-word;
		text-align: center;
	}

	/* ========================================================================
	 * Block 7 — Contactformulier (Contact Form 7), scoped onder .gelevb-pagebody.
	 * Author: BouwArchitectbaas · 2026-06-12
	 *
	 * SCOPE: layout + a11y-affordances voor de CF7-velden op de contactpagina.
	 * Kleur/type blijft theme.json-gestuurd (text-on-base op surface-base = #1A1A1A
	 * op #FFFFFF = 17:1, ruim boven WCAG AA). Geen font-size op een label/heading hier
	 * (H1-bug-discipline). De form-velden erven de witte body-achtergrond; labels en
	 * ingevulde tekst zijn text-on-base. Velden krijgen de input-radius-token + een
	 * 44px touch-target-floor (theme.json custom.target.min).
	 *
	 * CF7 wrapt elke control in <span class="wpcf7-form-control-wrap">. De selectors
	 * zijn STRIKT onder .gelevb-pagebody .wpcf7 zodat ze geen enkel veld elders raken
	 * (de Woo-block-checkout-velden staan buiten .gelevb-pagebody en blijven onaangeroerd).
	 *
	 * FOCUS-RING (a11y, non-text >= 3:1): focus-ring-token #0A3FB0 op wit = ~7:1,
	 * ruim boven de 3:1-eis voor UI-componenten. width/offset uit theme.json custom.focus.
	 * ====================================================================== */
	.gelevb-pagebody .wpcf7 {
		color: var(--wp--preset--color--text-on-base);
		max-width: 100%;
	}
	.gelevb-pagebody .wpcf7 p {
		margin: 0 0 var(--wp--preset--spacing--md);
	}
	.gelevb-pagebody .wpcf7 label {
		display: block;
		font-weight: 600;
		line-height: 1.4;
		color: var(--wp--preset--color--text-on-base);
	}
	/* De tekstvelden, e-mail, textarea en select: één consistente input-stijl. */
	.gelevb-pagebody .wpcf7 input[type="text"],
	.gelevb-pagebody .wpcf7 input[type="email"],
	.gelevb-pagebody .wpcf7 textarea,
	.gelevb-pagebody .wpcf7 select {
		display: block;
		width: 100%;
		max-width: 100%;
		box-sizing: border-box;
		margin-top: var(--wp--preset--spacing--xxs);
		min-height: var(--wp--custom--target--min);   /* 44px touch-target-floor */
		padding: var(--wp--preset--spacing--sm) var(--wp--preset--spacing--md);
		font-family: inherit;
		font-size: var(--wp--preset--font-size--base);
		color: var(--wp--preset--color--text-on-base);
		background: var(--wp--preset--color--surface-base);
		/* WCAG 1.4.11 (non-text contrast >= 3:1): de veldrand is de ENIGE visuele
		 * indicator van de inputgrens (veld-bg == pagina-bg, beide wit), dus moet de
		 * rand zelf 3:1 halen. divider (#E6E1CF) = 1.31:1 op wit (gemeten, §3a) -> FAALT.
		 * Token-gekoppelde fix: text-on-base (#1A1A1A) op 55% over wit = 3.90:1 (gemeten,
		 * boven de 3:1-eis). color-mix houdt 'm gekoppeld aan het ink-token; de rgba-regel
		 * eronder is de fallback voor engines zonder color-mix. */
		border: 1px solid rgba(26, 26, 26, 0.55);
		border: 1px solid color-mix(in srgb, var(--wp--preset--color--text-on-base) 55%, transparent);
		border-radius: var(--wp--custom--radius--input);
	}
	.gelevb-pagebody .wpcf7 textarea {
		min-height: calc(var(--wp--custom--target--min) * 3);
		resize: vertical;
	}
	/* Zichtbare focus-affordance op elk veld — token-gekoppeld, >= 3:1 op wit. */
	.gelevb-pagebody .wpcf7 input:focus-visible,
	.gelevb-pagebody .wpcf7 textarea:focus-visible,
	.gelevb-pagebody .wpcf7 select:focus-visible {
		outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--focus-ring);
		outline-offset: var(--wp--custom--focus--offset);
		border-color: var(--wp--preset--color--focus-ring);
	}
	/* Consent-checkbox-regel: checkbox en tekst op één regel, target-floor op de box. */
	.gelevb-pagebody .wpcf7 .wpcf7-acceptance label {
		display: flex;
		align-items: flex-start;
		gap: var(--wp--preset--spacing--sm);
		font-weight: 400;
	}
	.gelevb-pagebody .wpcf7 .wpcf7-acceptance input[type="checkbox"] {
		width: 22px;
		height: 22px;
		min-height: 0;       /* override de input-floor: een checkbox is geen tekstveld */
		margin-top: 2px;
		flex: 0 0 auto;
		accent-color: var(--wp--preset--color--action-primary);
	}
	.gelevb-pagebody .wpcf7 .wpcf7-acceptance a:focus-visible {
		outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--focus-ring);
		outline-offset: var(--wp--custom--focus--offset);
	}
	/* Verzendknop: erft de core/button-rol uit theme.json niet automatisch (CF7 rendert
	 * een eigen <input type=submit>). We binden hem aan dezelfde action-primary-tokens
	 * zodat hij identiek is aan de homepage-knoppen — één styling-bron. */
	.gelevb-pagebody .wpcf7 input[type="submit"] {
		min-height: var(--wp--custom--target--min);
		padding: var(--wp--preset--spacing--sm) var(--wp--preset--spacing--xl);
		font-family: inherit;
		font-size: var(--wp--preset--font-size--base);
		font-weight: 700;
		color: var(--wp--preset--color--action-primary-text);
		background: var(--wp--preset--color--action-primary);
		border: 0;
		border-radius: var(--wp--custom--radius--control);
		cursor: pointer;
	}
	.gelevb-pagebody .wpcf7 input[type="submit"]:focus-visible {
		outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--focus-ring);
		outline-offset: var(--wp--custom--focus--offset);
	}
	/* CF7-feedback (validatie/response): leesbaar op wit; gebruikt de bestaande
	 * feedback-success-token voor de OK-melding. De rode fout-tekst laat ik aan CF7's
	 * eigen .wpcf7-not-valid-tip (CF7 levert daar een AA-rode); render-loop verifieert. */
	.gelevb-pagebody .wpcf7 .wpcf7-response-output {
		margin: var(--wp--preset--spacing--md) 0 0;
		padding: var(--wp--preset--spacing--sm) var(--wp--preset--spacing--md);
		border-radius: var(--wp--custom--radius--input);
		color: var(--wp--preset--color--text-on-base);
	}

}

/* ============================================================================
 * UNLAYERED ANKER-OFFSET — scroll-margin tegen de (latere) plak-header.
 * ----------------------------------------------------------------------------
 * Author: BouwArchitectbaas · 2026-06-11
 *
 * Na een klik op een CTA-knop springt de viewport naar #bestel (op de homepage).
 * Zodra de header sticky is (theme.json custom.sticky.headerHeight = 60px; sticky =
 * latere step) dekt die de bovenrand van de bestel-titel af. scroll-margin-top op
 * het anker-element duwt het landingspunt onder de header.
 *
 * VARIABELE-NAAM (let op, geverifieerd): theme.json-sleutel "headerHeight" (camelCase)
 * wordt door WP omgezet naar kebab-case in de CSS-variabele -> --wp--custom--sticky--
 * header-height (NIET --headerHeight). De camelCase-vorm resolvet naar niets en zou de
 * calc() ongeldig maken. Bron: developer.wordpress.org global-settings-and-styles
 * ("camelCased keys are transformed into its kebab-case form").
 *
 * WAAROM UNLAYERED: dit is anker-/scroll-gedrag, geen type/colour en geen layout-
 * compositie; het hoort niet in @layer components. Unlayered + nul-specificiteit
 * (:where([id]) draagt 0 bij) -> het zet een veilige default-offset op ELK id-anker
 * zonder iets zwaarders te overrulen.
 *
 * OFFSET = headerHeight + md (16px) lucht. Token-gekoppeld: wijzigt de header-hoogte
 * ooit, dan schuift de offset mee (geen magisch getal).
 *
 * VEILIG VOORUIT: zolang de header NIET sticky is, is de offset onschadelijk (het
 * anker landt dan iets ruimer). Raakt Woo/checkout/order-box NIET -- puur CSS, geen
 * markup, geen JS. RENDER-FLAG: meet in de render-loop de WERKELIJKE header-hoogte
 * tegen de 60px-token; wijkt ze af, corrigeer de TOKEN (theme.json), niet deze regel.
 *
 * GEEN scroll-behavior:smooth -- dat is optioneel/visueel (Stef's call); de sprong
 * werkt zonder, en we introduceren geen scroll-gedrag-afhankelijkheid (A3 boring-tech).
 * ========================================================================== */
:where([id]) {
	scroll-margin-top: calc(var(--wp--custom--sticky--header-height) + var(--wp--preset--spacing--md));
}

/* ============================================================================
 * UNLAYERED OVERLAP OVERRIDE — mobile floating booklet (PUNT 1, Decisions vervolg 12)
 * ----------------------------------------------------------------------------
 * This single rule sits OUTSIDE `@layer components` ON PURPOSE. WordPress's block
 * layout engine emits an UNLAYERED rule `:root :where(.is-layout-flow) > *{
 * margin-block-end:0}` that resets the block-end margin of every flow child —
 * including .gelevb-hero__media (a wp:group, .is-layout-flow). Unlayered always
 * beats layered (MDN @layer cascade), so the same margin written inside
 * @layer components computed to 0. Writing it unlayered here is the ONLY reliable
 * way to out-rank WP's reset without `!important`.
 *
 * It is mobile-only (<880px) and creates the booklet→white-card overlap by pulling
 * the next grid item up under the booklet: it first cancels the grid row-gap
 * (lg = 24px) and then adds ~48px of real overhang (booklet bottom hangs ~24px
 * over the white card's top, right-anchored). NO transform on the booklet
 * image (hard rule Decisions vervolg 11) — the overlap is pure positioning.
 * Reset to 0 on desktop so the approved 2-col composition is byte-for-byte unchanged.
 * ========================================================================== */
@media (max-width: 879.98px) {
	/* `:root` prefix raises specificity to (0,2,0). WP's competing reset
	 * `:root :where(.is-layout-flow) > *{margin-block-end:0}` is only (0,1,0)
	 * (`:where()`/`>`/`*` add nothing), and it is unlayered too — so without this
	 * extra `:root` they tie on specificity and WP wins on source order. With it,
	 * THIS rule wins on specificity, no `!important` required. */
	:root .gelevb-hero__media {
		margin-bottom: calc(-1 * var(--wp--preset--spacing--lg) - 48px);
	}
}

/* ============================================================================
 * UNLAYERED FOOTER LINK COLOUR OVERRIDE — WCAG AA fix (2026-06-09)
 * ----------------------------------------------------------------------------
 * Author: BouwArchitectbaas
 *
 * WHY UNLAYERED: theme.json emits (verified via wp_get_global_stylesheet)
 *   a:where(:not(.wp-element-button)){color:var(--wp--preset--color--action-primary)}
 * That rule is UNLAYERED and specificity (0,0,1) (`:where()` contributes 0). It set
 * the three footer nav-links to action-primary = #1A1A1A (dark) on the dark footer
 * band surface-footer = #2B2A24 → contrast 1.21:1, far under AA (>=4.5:1). Anything
 * inside `@layer components` loses to an unlayered rule by the cascade, so the fix
 * MUST be unlayered too (same reason as the overlap override above). NO `!important`.
 *
 * THE SELECTOR `.gelevb-footer a` is specificity (0,1,1) > the global (0,0,1) and is
 * STRICTLY scoped to the footer landmark — it touches NO link elsewhere (header /
 * order-box / why-faq links are outside .gelevb-footer and keep their theme.json
 * colour untouched). It targets `a` (not only .gelevb-footer__link) so the colour is
 * robust even if a link is ever dropped in without the BEM class.
 *
 * TOKEN-COUPLED: colour = text-on-footer (#FFFFFF, 14.39:1 against surface-footer,
 * WCAG AAA). This is the SAME token the copyright uses, so ONE theme.json change to
 * text-on-footer re-styles links + copyright together — and the AA re-check applies
 * to both at once.
 *
 * THEMEABLE-CAVEAT (matches the copyright caveat in theme.json / footer.php docblock):
 * if Stef later lightens surface-footer, text-on-footer must be RE-CHECKED to keep
 * >=4.5:1 for the link text AND focus ring against the new band. Because both the
 * link text and the focus ring are bound to text-on-footer, a single token retune
 * carries the whole footer; only the AA verification has to be repeated.
 *
 * STATES: default / hover / focus-visible / visited / active all forced to
 * text-on-footer so :visited can NEVER fall back to the dark UA/global default on
 * the dark band. The focus-ring colour is also bound here (the #0A3FB0 focus-ring
 * token reaches only 1.61:1 on this band; white reaches 14.39:1).
 * ========================================================================== */
.gelevb-footer a,
.gelevb-footer a:link,
.gelevb-footer a:visited,
.gelevb-footer a:hover,
.gelevb-footer a:active,
.gelevb-footer a:focus-visible {
	color: var(--wp--preset--color--text-on-footer);
}
.gelevb-footer a:focus-visible {
	outline-color: var(--wp--preset--color--text-on-footer);
}
