/*
 * Labour Against the Assisted Dying Bill — theme stylesheet.
 *
 * Loaded on the front end AND in the block editor (see add_editor_style in
 * functions.php), so a pattern previews exactly as it will publish. A block
 * that looks right on the front end but broken in the editor is half-built,
 * and the client only ever sees the editor.
 *
 * NOTHING here may hardcode a colour, a font or a size that theme.json already
 * carries. Every value below is either a var(--wp--…) token or a layout number
 * that is genuinely structural (breakpoints, grid tracks, hairline widths).
 *
 * The discipline, restated because it is easy to lose:
 *   · red is the ONE accent and is capped at roughly 7% of any viewport
 *   · red type never below 18px — use --brand-text below that
 *   · black type on white does the heavy lifting
 *   · warm off-white bands give rhythm, hairline rules do the structure
 *   · no second hue, no gradients, NO SHADOWS, radius capped at 4px
 *
 * @package labour-adb
 * @author  James Willcocks <https://willcocks.uk>
 */

/* ══════════════════════════════════════════════════════════════════════════
   1. Local aliases
   The full var(--wp--preset--color--brand) is unreadable at the density this
   file needs. These are aliases for the SAME tokens, declared once, so there
   is still exactly one source of truth (theme.json) and one place to change it.
   ══════════════════════════════════════════════════════════════════════════ */

:root,
.editor-styles-wrapper {
	--paper: var(--wp--preset--color--paper);
	--surface: var(--wp--preset--color--surface);
	--ink: var(--wp--preset--color--ink);
	--mute: var(--wp--preset--color--mute);
	--rule: var(--wp--preset--color--rule);
	--brand: var(--wp--preset--color--brand);
	--brand-text: var(--wp--preset--color--brand-text);
	--brand-deep: var(--wp--preset--color--brand-deep);
	--brand-veil: var(--wp--preset--color--brand-veil);
	--wash: var(--wp--preset--color--wash);

	/* Muted type on INK — the event banner. --mute is a light-background token
	   and fails contrast badly on a dark ground; this is 10.6:1 on --ink. It is
	   in settings.custom rather than the palette on purpose: it must not appear
	   as a swatch the client can paint text with, because it fails on paper. */
	--mute-inverse: var(--wp--custom--mute-inverse);

	--font-display: var(--wp--preset--font-family--display);
	--font-serif: var(--wp--preset--font-family--serif);
	--font-mono: var(--wp--preset--font-family--mono);

	--radius-sm: var(--wp--custom--radius--sm);
	--radius-md: var(--wp--custom--radius--md);

	--t: var(--wp--custom--transition);
}

/* ══════════════════════════════════════════════════════════════════════════
   2. Base
   ══════════════════════════════════════════════════════════════════════════ */

/*
 * Border-box everywhere.
 *
 * WordPress applies box-sizing per block rather than globally, so any element
 * the theme adds itself — every .ladb-container, for one — sizes its padding
 * OUTSIDE its width by default and pushes the page wider than the viewport.
 * That is what put a horizontal scrollbar under the header bar.
 */
*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-padding-top: 6rem; /* anchors clear the sticky header */
	scrollbar-gutter: stable;
}

@media (prefers-reduced-motion: no-preference) {
	html {
		scroll-behavior: smooth;
	}
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

/*
 * The 4px solidarity-red rule across the very top of every viewport — the
 * brand's one piece of texture. On the front end it hangs off <body>; in the
 * editor the equivalent lives on the canvas wrapper so the client sees it too.
 */
body::before {
	content: '';
	display: block;
	height: var(--wp--custom--rail--top);
	background: var(--brand);
}

p {
	text-wrap: pretty;
}

h1, h2, h3, h4, h5, h6,
.wp-block-heading {
	text-wrap: balance;
}

::selection {
	background-color: var(--brand);
	color: #fff;
}

img,
svg,
video,
iframe {
	max-width: 100%;
	height: auto;
}

/* Visible 2px ink focus ring — a P0 accessibility commitment, not a default
   to be overridden. Deep-red bands flip it to white further down. */
:focus-visible {
	outline: 2px solid var(--ink);
	outline-offset: 3px;
	border-radius: var(--radius-sm);
}

/*
 * Directional arrows and external-link marks sit OUTSIDE the underline — an
 * underlined "→" reads as a typo. text-decoration propagates to inline
 * descendants and cannot be cancelled on the child with text-decoration:none;
 * display:inline-block is what actually excludes it.
 */
.arrow-glyph,
.ladb-ext {
	display: inline-block;
	text-decoration: none;
}

.ladb-ext {
	font-size: 0.75em;
	margin-left: 0.35em;
	color: var(--mute);
}

.screen-reader-text,
.ladb-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.skip-link,
.ladb-skip-link {
	position: absolute;
	left: -9999px;
	top: 0.5rem;
	z-index: 100;
	padding: 0.5rem 1rem;
	background: var(--ink);
	color: #fff;
	font-family: var(--font-display);
	font-weight: 600;
	text-decoration: none;
	border-radius: var(--radius-sm);
}

.skip-link:focus,
.ladb-skip-link:focus {
	left: 0.5rem;
}

/* ══════════════════════════════════════════════════════════════════════════
   3. Container widths — block styles on core/group

   theme.json owns prose (45rem, the default measure) and wide (82.5rem). These
   two add the other measures the design uses. WordPress's own constrained-layout
   rule is written entirely inside :where(), so it has zero specificity and a
   single class beats it cleanly.

   Every page must mix at least TWO widths. A page where every section starts
   and ends at the same x-coordinate on a 1440px viewport is the failure mode
   this system exists to prevent.
   ══════════════════════════════════════════════════════════════════════════ */

.is-style-container-content.is-layout-constrained > :not(.alignfull):not(.alignwide),
.is-style-container-content > .wp-block-group__inner-container > :not(.alignfull):not(.alignwide) {
	max-width: var(--wp--custom--container--content);
	margin-inline: auto;
}

.is-style-container-xwide.is-layout-constrained > :not(.alignfull):not(.alignwide),
.is-style-container-xwide > .wp-block-group__inner-container > :not(.alignfull):not(.alignwide) {
	max-width: var(--wp--custom--container--xwide);
	margin-inline: auto;
}

/* Utility versions, for markup the theme itself emits (header, footer, blocks). */
.ladb-container {
	width: 100%;
	margin-inline: auto;
	padding-inline: var(--wp--custom--container--gutter);
}

.ladb-container--prose   { max-width: var(--wp--custom--container--prose); }
.ladb-container--content { max-width: var(--wp--custom--container--content); }
.ladb-container--wide    { max-width: var(--wp--custom--container--wide); }
.ladb-container--xwide   { max-width: var(--wp--custom--container--xwide); }

/* ══════════════════════════════════════════════════════════════════════════
   4. Bands — the single thing the client picked up at review

   Sections alternate paper → warm → paper down every page. No two neighbours
   share a background: that is what stops a long page reading as one
   undifferentiated rail. The page then descends light → veil (CTA) → deep red
   (footer), so the CTA reads as a soft transition rather than a flare.

   ADDING, REMOVING OR REORDERING A SECTION FLIPS THE PARITY OF EVERYTHING
   BELOW IT. Verify with a rendered-background sweep, never by reading source.
   ══════════════════════════════════════════════════════════════════════════ */

.is-style-band-paper { background-color: var(--paper); color: var(--ink); }
.is-style-band-warm  { background-color: var(--surface); color: var(--ink); }

/* The CTA band. Pale on purpose. Carries INK type and a solid red button —
   NEVER white type. Full brand red at full-bleed scale was tried and rejected:
   it out-shouted the footer. */
.is-style-band-veil {
	background-color: var(--brand-veil);
	color: var(--ink);
}

.is-style-band-deep {
	background-color: var(--brand-deep);
	color: #fff;
}

.is-style-band-deep :focus-visible {
	outline-color: #fff;
}

.is-style-band-deep a {
	color: rgba(255, 255, 255, 0.88);
}

.is-style-band-deep a:hover,
.is-style-band-deep a:focus-visible {
	color: #fff;
}

/* Section vertical rhythm. Rotate deliberately — two adjacent sections on the
   same scale read as one block. */
.is-style-pad-tight { padding-block: var(--wp--custom--section--tight); }
.is-style-pad-base  { padding-block: var(--wp--custom--section--base); }
.is-style-pad-loose { padding-block: var(--wp--custom--section--loose); }

/* ══════════════════════════════════════════════════════════════════════════
   5. Editorial devices
   ══════════════════════════════════════════════════════════════════════════ */

/* Kicker — uppercase tracked Archivo label preceded by a 40px red rule.
   Precedes every major section heading and does most of the "modern editorial"
   work on the page. */
.is-style-kicker {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	line-height: 1.5;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--brand-text);
	margin-block-end: 1rem;
}

.is-style-kicker::before {
	content: '';
	width: 2.5rem;
	height: 2px;
	flex-shrink: 0;
	background: var(--brand);
}

/* Bare kicker without the rule — cards, list items, tight spots. */
.is-style-kicker-bare {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	line-height: 1.5;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--brand-text);
	margin-block-end: 0.5rem;
}

.is-style-band-deep .is-style-kicker,
.is-style-band-deep .is-style-kicker-bare {
	color: rgba(255, 255, 255, 0.72);
}

.is-style-band-deep .is-style-kicker::before {
	background: #fff;
}

/* Standfirst — the large serif intro under an H1. */
.is-style-standfirst {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--xl);
	line-height: 1.5;
	max-width: var(--wp--custom--measure--standfirst);
}

/* Meta line — bylines, dates, source attributions. */
.is-style-meta-line {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--mute);
}

/* Small note — "Correct as of…", figure caveats. */
.is-style-note {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--mute);
}

/* Rule-topped item — the beliefs / principles treatment. */
.is-style-rule-top {
	border-top: 2px solid var(--brand);
	padding-top: 1.25rem;
}

.is-style-hairline-top {
	border-top: 1px solid var(--rule);
	padding-top: 1.25rem;
}

/* ── The evidence block ────────────────────────────────────────────────────
   The house device. Wash ground, 3px red left border, serif quote, then a
   clearly separated attribution line set in the UI face at meta scale so it
   reads as a citation rather than as speech. */

.wp-block-quote.is-style-evidence,
.is-style-evidence.wp-block-group {
	background: var(--wash);
	border-left: 3px solid var(--brand);
	border-inline-end: 0;
	padding: 1.5rem 1.75rem;
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--xl);
	line-height: 1.5;
	font-style: normal;
	margin-inline: 0;
}

.wp-block-quote.is-style-evidence > p:first-child,
.is-style-evidence.wp-block-group > p:first-child {
	margin-top: 0;
}

.wp-block-quote.is-style-evidence > p + p,
.is-style-evidence.wp-block-group > p + p,
.wp-block-quote.is-style-evidence cite {
	display: block;
	margin-top: 1.5rem;
	padding-top: 1rem;
	border-top: 1px solid rgba(224, 27, 34, 0.22);
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.5;
	font-style: normal;
	color: var(--mute);
}

.wp-block-quote.is-style-evidence > p + p strong,
.is-style-evidence.wp-block-group > p + p strong,
.wp-block-quote.is-style-evidence cite strong {
	color: var(--ink);
	font-weight: 700;
}

/* A source link inside a citation must be unmistakably clickable. */
.wp-block-quote.is-style-evidence > p + p a,
.is-style-evidence.wp-block-group > p + p a,
.wp-block-quote.is-style-evidence cite a {
	color: var(--brand-deep);
	font-weight: 600;
	text-decoration: underline;
	text-decoration-color: currentColor;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.25em;
}

.wp-block-quote.is-style-evidence > p + p a::after,
.is-style-evidence.wp-block-group > p + p a::after,
.wp-block-quote.is-style-evidence cite a::after {
	content: '↗';
	display: inline-block; /* keeps the glyph out of the underline */
	margin-left: 0.3em;
	text-decoration: none;
	font-size: 0.85em;
}

.wp-block-quote.is-style-evidence > p + p a:hover,
.wp-block-quote.is-style-evidence > p + p a:focus-visible {
	color: var(--brand-text);
	text-decoration-thickness: 2px;
}

/* ── Cards ─────────────────────────────────────────────────────────────────
   Exactly two treatments across the whole site, and a card always takes the
   OPPOSITE tone to its band. A card the same colour as its band needs a shadow
   or a heavy border to read, and this design has neither. */

.is-style-card-paper,
.is-style-card-warm {
	border: 1px solid var(--rule);
	border-radius: var(--radius-md);
	padding: 1.5rem;
	transition: border-color var(--t);
}

.is-style-card-paper { background: var(--paper); }
.is-style-card-warm  { background: var(--surface); }

.is-style-card-paper:hover,
.is-style-card-paper:focus-within,
.is-style-card-warm:hover,
.is-style-card-warm:focus-within {
	border-color: var(--ink);
}

/* ══════════════════════════════════════════════════════════════════════════
   6. Buttons
   ══════════════════════════════════════════════════════════════════════════ */

.wp-block-button__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	min-height: 48px;
	white-space: nowrap;
	transition: background-color var(--t), color var(--t), border-color var(--t);
}

/* Secondary action — ink outline on paper. */
.wp-block-button.is-style-outline .wp-block-button__link {
	background: transparent;
	color: var(--ink);
	border: 1px solid var(--ink);
	font-weight: 600;
	padding: 0.8125rem 1.625rem;
}

.wp-block-button.is-style-outline .wp-block-button__link:hover,
.wp-block-button.is-style-outline .wp-block-button__link:focus-visible {
	background: var(--ink);
	color: #fff;
}

/* Inverse — white fill on deep-red bands. */
.wp-block-button.is-style-inverse .wp-block-button__link {
	background: #fff;
	color: var(--brand-deep);
}

.wp-block-button.is-style-inverse .wp-block-button__link:hover,
.wp-block-button.is-style-inverse .wp-block-button__link:focus-visible {
	background: var(--wash);
	color: var(--brand-deep);
}

/* Small "more" link button — section-level secondary. */
.wp-block-button.is-style-more .wp-block-button__link,
.ladb-btn-more {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	min-height: 44px;
	background: transparent;
	border: 1px solid var(--ink);
	border-radius: var(--radius-sm);
	padding: 0.55rem 1.1rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--ink);
	text-decoration: none;
	transition: background-color var(--t), color var(--t);
}

.wp-block-button.is-style-more .wp-block-button__link:hover,
.wp-block-button.is-style-more .wp-block-button__link:focus-visible,
.ladb-btn-more:hover,
.ladb-btn-more:focus-visible {
	background: var(--ink);
	color: var(--paper);
}

/* ══════════════════════════════════════════════════════════════════════════
   7. Long-form article body

   ⚠ SCOPED TO `.ladb-prose`, NEVER TO `.entry-content`. This is not a
   stylistic preference — it is a bug fix, and the bug was expensive.

   `.entry-content` is the class core puts on EVERY `core/post-content`,
   including the one on a page whose children are full-bleed band sections
   rather than prose. So `.entry-content ol` (specificity 0,2,0) reached past
   `.ladb-timeline` (0,1,0) and won: the Bill timeline came out numbered, with
   a 24px indent, and — worst of it — with a 10px row gap instead of the 120px
   the S-bend connector's geometry is drawn against, so the rail cut straight
   through the text. The briefings grid got bullets for the same reason. And
   `.entry-content > * + *` was putting a 22.5px margin between every band,
   which showed as white strips above the CTA and the footer.

   The rule that prevents a repeat: prose styling is opted INTO by a container
   that is actually prose, and list styling is scoped to `.wp-block-list`,
   which core puts on list blocks and nothing else.

   68ch serif measure, Archivo sub-headings, hairline rules on tables.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-prose {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--base);
	line-height: 1.65;
}

.ladb-prose > * + * {
	margin-top: 1.25em;
}

.ladb-prose > h2 {
	font-size: var(--wp--preset--font-size--2xl);
	margin-top: 2em;
}

.ladb-prose > h3 {
	font-size: var(--wp--preset--font-size--xl);
	margin-top: 1.75em;
}

.ladb-prose ul.wp-block-list,
.ladb-prose ol.wp-block-list {
	padding-left: 1.5rem;
	display: grid;
	gap: 0.625rem;
}

.ladb-prose ul.wp-block-list { list-style: disc; }
.ladb-prose ol.wp-block-list { list-style: decimal; }

.ladb-prose .wp-block-list li::marker {
	color: var(--brand);
}

.ladb-prose a:not(.wp-block-button__link) {
	text-decoration-color: var(--brand);
	text-decoration-thickness: 1.5px;
	text-underline-offset: 0.2em;
}

.ladb-prose a:not(.wp-block-button__link):hover {
	color: var(--brand-deep);
}

/* ── Band sections butt against each other ────────────────────────────────
   WordPress gives every child of a flow or constrained layout a block-gap
   margin. On a page built from full-bleed bands that margin is a visible
   strip of the parent's background between them — which is why there was
   white above the hero, above the rose CTA band and above the deep-red
   footer. Bands own their vertical padding; they never carry margin. */

.wp-site-blocks > *,
.wp-block-post-content > .alignfull {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* ── Nothing on this site is centred ──────────────────────────────────────
   WordPress's constrained layout puts `margin-left: auto !important;
   margin-right: auto !important` on every direct child. That one declaration
   does two jobs at once: it positions the content COLUMN inside a full-bleed
   band, and it centres any child narrower than the column. The first is
   wanted, the second is not — it is how the standfirst on News and Events
   ended up ~58px right of its own heading, which is exactly what the client
   flagged on the Astro build ("a sudden switch to centre aligned").

   The two cannot be separated on the same element, so DO NOT try to override
   the margin: forcing it to zero pushes the element to the edge of the
   full-bleed band instead, which is worse and was tried first. The fix is
   structural — put the content in a flow wrapper, so the wrapper takes the
   auto margins and its children flow left-aligned inside it.

   The rule below is the safety net for content the client adds straight into
   a band without that wrapper: drop the measure cap, so it fills the column
   rather than drifting into the middle of it. A slightly long line is a much
   smaller problem than a block that looks misaligned. */

.ladb-page-header__inner > * {
	margin-block-start: 0;
}

.is-layout-constrained > .is-style-standfirst,
.is-layout-constrained > .ladb-issues__intro {
	max-width: none;
}

.ladb-issues__intro {
	font-family: var(--font-serif);
	max-width: 58ch;
}

/* ── Tables ──────────────────────────────────────────────────────────────── */

.wp-block-table table {
	width: 100%;
	border-collapse: collapse;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
}

.wp-block-table th {
	font-weight: 700;
	text-align: left;
	padding: 0.75rem 1rem;
	border-bottom: 2px solid var(--ink);
}

.wp-block-table td {
	padding: 0.75rem 1rem;
	border-bottom: 1px solid var(--rule);
	vertical-align: top;
}

.wp-block-table.is-style-comparison tbody tr:nth-child(even) td {
	background: var(--surface);
}

/* A table is the one thing on the site allowed to scroll sideways rather than
   force the page to. */
.wp-block-table {
	overflow-x: auto;
}

/* ══════════════════════════════════════════════════════════════════════════
   8. Site header — sticky bar, split-trigger dropdowns, mobile panel

   Collapse breakpoint is 1280px, NOT the stock 1024: the full lockup, five
   Archivo labels and the CTA genuinely need the room, and the horizontal nav
   must never wrap. Raise it again if a sixth nav item is added.
   ══════════════════════════════════════════════════════════════════════════ */

/*
 * THE STICKY LIVES ON THE TEMPLATE PART, NOT ON .ladb-header.
 *
 * The block renders a <div> inside the part's <header> (so there is exactly one
 * banner landmark — see the block's render template). A sticky element can only
 * travel within its own containing block, and .ladb-header's parent is exactly
 * as tall as the header itself, so putting `position: sticky` there would look
 * correct and never actually stick. The part wrapper spans the page, so that is
 * where it belongs.
 */
.ladb-header-part {
	position: sticky;
	/*
	 * NOT `top: 0`. A logged-in editor gets WordPress's own admin bar fixed over
	 * the top of the viewport, so a header pinned at 0 scrolls underneath it.
	 * `--ladb-sticky-top` is 0 for visitors and the admin bar's height for
	 * editors. Below 601px WordPress switches the admin bar to position:absolute
	 * so it scrolls away with the page — the offset goes back to 0 there.
	 */
	top: var(--ladb-sticky-top, 0px);
	z-index: 50;
}

body.admin-bar {
	--ladb-sticky-top: 32px;
}

@media screen and (max-width: 782px) {
	body.admin-bar {
		--ladb-sticky-top: 46px;
	}
}

@media screen and (max-width: 600px) {
	body.admin-bar {
		--ladb-sticky-top: 0px;
	}
}

.ladb-header {
	border-bottom: 1px solid var(--rule);
}

/*
 * Background + blur live on this INNER wrapper, never on the sticky <header>.
 * backdrop-filter creates a containing block, which would trap the fixed
 * full-screen mobile panel inside the header's own height.
 */
.ladb-header__bar-wrap {
	position: relative;
	/*
	 * Higher than .ladb-panel's 40 — deliberately. The bar stays visible above
	 * the open panel and carries the only two controls up there (the logo and
	 * the ✕), so it must never be the thing that gets painted over. This used to
	 * be 10, and any mismatch between the panel's top edge and the bar's real
	 * height let the panel eat the bottom half of the ✕.
	 */
	z-index: 45;
	background: color-mix(in srgb, var(--paper) 88%, transparent);
	backdrop-filter: blur(8px);
}

.ladb-header__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	min-height: var(--wp--custom--header--height);
}

.ladb-header__brand {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
	flex-shrink: 0;
}

.ladb-logo {
	height: 2.75rem;
	width: auto;
	display: block;
}

@media (min-width: 640px) {
	.ladb-logo { height: 3.25rem; }
}

.ladb-header__nav {
	display: none;
}

.ladb-header__cta {
	display: none;
	align-items: center;
	min-height: 44px;
	padding: 0.55rem 1.1rem;
	border-radius: var(--radius-sm);
	background: var(--brand);
	color: #fff;
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--sm);
	text-decoration: none;
	white-space: nowrap;
	transition: background-color var(--t);
}

.ladb-header__cta:hover,
.ladb-header__cta:focus-visible {
	background: var(--brand-deep);
	color: #fff;
}

.ladb-header__burger {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	background: none;
	border: 1px solid var(--rule);
	border-radius: var(--radius-sm);
	color: var(--ink);
	cursor: pointer;
	flex-shrink: 0;
}

.ladb-header__burger .ladb-icon {
	display: inline-flex;
}

.ladb-header__burger .ladb-icon[hidden] {
	display: none;
}

/* ── Mobile panel ──────────────────────────────────────────────────────────
   Stays in the DOM (no `hidden`) so it can slide — you cannot transition
   `display`. The closed state is CSS (off-screen + faded) plus `inert` for the
   a11y tree. Deliberately NOT visibility:hidden — that on the start state
   blocks the transform transition from ever running. */

.ladb-panel {
	position: fixed;
	/*
	 * `top` is the header's MEASURED bottom edge — site.js writes
	 * --ladb-panel-top on open. Do NOT put the raw header-height token back:
	 * that token is the bar's min-height ALONE, while the real edge also carries
	 * the 4px red rail (body::before), the header's own 1px bottom border and,
	 * for a logged-in editor, the 32/46px WordPress admin bar. Hardcoding it put
	 * the panel 5px inside the header for a visitor and 37px inside it for an
	 * editor — far enough to cover the lower half of the ✕ and the bottom of the
	 * logo. The token survives only as the no-JS fallback, where the panel never
	 * opens anyway.
	 */
	inset: var(--ladb-panel-top, var(--wp--custom--header--height)) 0 0 0;
	z-index: 40;
	overflow-y: auto;
	background: var(--paper);
	padding: 1.5rem;
	transform: translateX(100%);
	opacity: 0;
	pointer-events: none;
	transition:
		transform 320ms cubic-bezier(0.22, 1, 0.36, 1),
		opacity 320ms cubic-bezier(0.22, 1, 0.36, 1);
}

.ladb-panel.is-open {
	transform: translateX(0);
	opacity: 1;
	pointer-events: auto;
}

.ladb-panel ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}

/* Scoped to `nav` so it styles nav links ONLY — never the panel footer CTA.
   The generic row rule is higher-specificity than the CTA class, so a CTA
   nested inside the nav list silently loses its background (the
   transparent-pill bug). Keeping it in a sibling footer is the fix. */
.ladb-panel nav li > a {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	min-height: 44px;
	padding: 0.9rem 0.25rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 600;
	color: var(--ink);
	text-decoration: none;
	border-bottom: 1px solid var(--rule);
}

.ladb-panel nav li > a[aria-current='page'] {
	color: var(--brand-text);
}

.ladb-panel__footer {
	margin-top: 1.5rem;
}

/* Self-contained, so no generic rule can override it. */
.ladb-panel__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: 48px;
	padding: 0.8rem 1.1rem;
	border-radius: var(--radius-md);
	background: var(--brand);
	color: var(--paper);
	font-family: var(--font-display);
	font-weight: 700;
	text-decoration: none;
}

.ladb-panel__cta:hover,
.ladb-panel__cta:focus-visible {
	background: var(--brand-deep);
	color: var(--paper);
}

@media (prefers-reduced-motion: reduce) {
	.ladb-panel,
	.ladb-panel.is-open {
		transition: none;
	}
}

@media (min-width: 1280px) {
	.ladb-header__burger,
	.ladb-panel {
		display: none;
	}

	.ladb-header__nav {
		display: block;
	}

	.ladb-header__cta {
		display: inline-flex;
	}

	.ladb-header__nav > ul {
		display: flex;
		align-items: center;
		gap: 0.25rem;
		list-style: none;
		margin: 0;
		padding: 0;
	}

	.ladb-header__nav li {
		position: relative;
	}

	.ladb-header__nav a {
		display: inline-flex;
		align-items: center;
		/* 44px even though this bar only exists on pointer devices — the house
		   minimum, and the header is 68px tall so it costs nothing. */
		min-height: 44px;
		padding: 0.5rem 0.75rem;
		text-decoration: none;
		color: var(--ink);
		border-radius: var(--radius-sm);
		font-family: var(--font-display);
		font-size: var(--wp--preset--font-size--sm);
		font-weight: 600;
		white-space: nowrap;
		transition: color var(--t);
	}

	.ladb-header__nav a:hover {
		color: var(--brand);
	}

	.ladb-header__nav a[aria-current='page'] {
		text-decoration: underline;
		text-decoration-color: var(--brand);
		text-underline-offset: 0.4em;
		text-decoration-thickness: 2px;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   9. Site footer — full-bleed deep red, four columns

   NO designer credit. The client explicitly instructed that no "Website by
   Willcocks Web" text appears (the site was built on behalf of another
   agency). This overrides the agency default; do not re-add it.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-footer {
	background: var(--brand-deep);
	color: #fff;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
}

.ladb-footer__inner {
	padding-block: 4rem 2rem;
}

.ladb-footer__cols {
	display: grid;
	gap: 2.5rem;
	grid-template-columns: 1fr;
}

@media (min-width: 640px) {
	.ladb-footer__cols { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1024px) {
	.ladb-footer__cols {
		grid-template-columns: 2.2fr 1fr 1fr 1fr;
		gap: 3rem;
	}
}

.ladb-footer__logo {
	display: inline-block;
	text-decoration: none;
}

.ladb-footer__strap {
	margin-top: 1.25rem;
	max-width: 34ch;
	line-height: 1.55;
	color: rgba(255, 255, 255, 0.82);
}

.ladb-footer__heading {
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.65);
	margin: 0 0 0.9rem;
}

.ladb-footer ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
}

.ladb-footer li a {
	display: inline-block;
	min-height: 32px;
	padding-block: 0.25rem;
	color: rgba(255, 255, 255, 0.88);
	text-decoration: none;
}

.ladb-footer li a:hover,
.ladb-footer li a:focus-visible {
	color: #fff;
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.ladb-footer__baseline {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 0.75rem;
	margin-top: 3rem;
	padding-top: 1.5rem;
	border-top: 1px solid rgba(255, 255, 255, 0.22);
	font-size: var(--wp--preset--font-size--xs);
	color: rgba(255, 255, 255, 0.72);
}

.ladb-footer__baseline p {
	margin: 0;
	font-family: var(--font-display);
}

.ladb-footer :focus-visible {
	outline-color: #fff;
}

/* ══════════════════════════════════════════════════════════════════════════
   10. Hero
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-hero {
	overflow-x: clip;
	padding-block: clamp(3rem, 6vw, 6rem);
}

.ladb-hero__grid {
	display: grid;
	gap: 2.5rem;
	align-items: center;
}

.ladb-hero h1,
.ladb-hero .wp-block-heading.ladb-hero__title {
	font-size: var(--wp--custom--heading--hero);
	margin-block: 1.25rem 1.5rem;
	max-width: 18ch;
}

/* The one place red is allowed inside a headline. */
.ladb-hero h1 em,
.ladb-hero__title em {
	font-style: normal;
	color: var(--brand);
}

.ladb-hero__standfirst {
	font-family: var(--font-serif);
	font-size: clamp(1.1875rem, 1vw + 0.75rem, 1.375rem);
	line-height: 1.5;
	max-width: 46ch;
	margin-bottom: 2rem;
}

.ladb-hero__support {
	margin-top: 2rem;
	padding-top: 1.25rem;
	border-top: 1px solid var(--rule);
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--mute);
	max-width: 52ch;
}

.ladb-hero__media {
	background: var(--surface);
	padding: clamp(1.5rem, 3vw, 2.75rem);
	border-radius: var(--radius-md);
}

/*
 * Between 640px and the 1024px two-column breakpoint the hero is a single
 * column, but the copy kept the caps that were drawn for the NARROW column
 * of the two-column layout — an 18ch headline on an 850px page, with roughly
 * 40% of the row empty to the right once the quote card had dropped below.
 * It read as unfinished rather than as deliberate white space.
 *
 * These are relaxed, not removed. Measure still matters: 26ch of display
 * type and ~55ch of serif are comfortable, and the caps snap back to the
 * tighter values the moment the two-column layout returns at 1024px.
 */
@media (min-width: 640px) and (max-width: 1023.98px) {
	.ladb-hero h1,
	.ladb-hero .wp-block-heading.ladb-hero__title {
		max-width: 26ch;
	}

	.ladb-hero__standfirst {
		max-width: 55ch;
	}

	.ladb-hero__support {
		max-width: 62ch;
	}
}

@media (min-width: 1024px) {
	.ladb-hero__grid {
		grid-template-columns: 58fr 42fr;
		gap: 4rem;
	}

	/*
	 * The warm panel bleeds to the right viewport edge, but the bleed is CAPPED
	 * at 8.75rem — exactly the gap between this container (wide, 82.5rem) and
	 * the header's (xwide, 100rem). Below ~1552px it runs to the viewport edge;
	 * above that it lines up with the right edge of the header bar instead of
	 * sprawling. Uncapped it grew forever: at 3840px the panel was 1811px wide
	 * against a 1600px header, with the document marooned in the middle of it.
	 *
	 * NB the usual calc(50% - 50vw) shorthand is WRONG on a grid item — the 50%
	 * resolves against the CELL, not the container, and over-bleeds badly.
	 */
	.ladb-hero__media {
		margin-right: calc(-1 * min(max(0px, 100vw - 82.5rem) / 2 + 1.5rem + 20px, 8.75rem));
		height: clamp(22rem, 30vw, 32rem);
		border-radius: var(--radius-md) 0 0 var(--radius-md);
	}

	.ladb-hero__media img,
	.ladb-hero__media svg {
		border-radius: var(--radius-md) 0 0 var(--radius-md);
	}
}

/* The Bill graphic — an information graphic, deliberately not a photograph and
   never AI-generated. */
.ladb-bill-graphic {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.ladb-bill-graphic .bg-title {
	font-family: var(--font-display);
	font-weight: 800;
	font-size: 19px;
	letter-spacing: 0.04em;
	fill: var(--ink);
}

/* ══════════════════════════════════════════════════════════════════════════
   11. Page header (inner pages)
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-page-header {
	padding-block: var(--wp--custom--section--header);
}

.ladb-page-header h1,
.ladb-page-header .wp-block-post-title {
	font-size: var(--wp--custom--heading--page);
	margin-block: 1rem 1.25rem;
}

/* Breadcrumb trail */
.ladb-crumbs ol {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	list-style: none;
	margin: 0 0 1.75rem;
	padding: 0;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--mute);
}

.ladb-crumbs li + li::before {
	content: '/';
	margin-right: 0.5rem;
	color: var(--rule);
}

.ladb-crumbs a {
	color: var(--mute);
	text-decoration: underline;
	text-decoration-color: var(--rule);
	text-underline-offset: 0.25em;
	padding-block: 0.35rem;
}

.ladb-crumbs a:hover,
.ladb-crumbs a:focus-visible {
	color: var(--brand-text);
	text-decoration-color: currentColor;
}

.ladb-crumbs [aria-current='page'] {
	color: var(--ink);
	font-weight: 600;
}

/* ══════════════════════════════════════════════════════════════════════════
   12. Issues grid + hub listing
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-issues__header {
	display: grid;
	gap: 1.5rem;
	margin-bottom: 2.5rem;
}

@media (min-width: 1024px) {
	.ladb-issues__header {
		grid-template-columns: 1fr 1fr;
		align-items: end;
		gap: 3rem;
	}
}

.ladb-issues-grid {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 1.25rem;
}

@media (min-width: 768px) {
	.ladb-issues-grid { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1200px) {
	.ladb-issues-grid { grid-template-columns: 1fr 1fr 1fr; }
}

.ladb-issue-card {
	position: relative;
	background: var(--surface); /* warm card on the paper band */
	border: 1px solid var(--rule);
	border-radius: var(--radius-md);
	padding: 1.5rem;
	display: flex;
	flex-direction: column;
	transition: border-color var(--t);
}

.is-style-band-warm .ladb-issue-card {
	background: var(--paper); /* flips if the section ever lands on warm */
}

.ladb-issue-card:hover,
.ladb-issue-card:focus-within {
	border-color: var(--ink);
}

.ladb-issue-card__title {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: 1.25;
	margin: 0.75rem 0 0.6rem;
}

.ladb-issue-card__title a {
	text-decoration: none;
	color: inherit;
	transition: color var(--t);
}

/* The whole card is the target. */
.ladb-issue-card__title a::after {
	content: '';
	position: absolute;
	inset: 0;
}

.ladb-issue-card:hover .ladb-issue-card__title a,
.ladb-issue-card__title a:focus-visible {
	color: var(--brand);
}

.ladb-issue-card__summary {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--base);
	margin: 0 0 1.25rem;
	flex: 1;
}

.ladb-issue-card__more {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--brand-text);
	margin: 0;
}

/* ── Hub listing (numbered rows) ───────────────────────────────────────────
   Deliberately NOT alternating — these are tabular list rows, and a zigzag
   makes a long list harder to scan (client's call). */

.ladb-briefings {
	list-style: none;
	margin: 0;
	padding: 0;
}

.ladb-briefing {
	display: grid;
	gap: 1rem;
	padding-block: 2.25rem;
	border-top: 1px solid var(--rule);
}

.ladb-briefing:last-child {
	border-bottom: 1px solid var(--rule);
}

.ladb-briefing__meta {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
}

.ladb-briefing__number {
	font-family: var(--font-display);
	font-variant-numeric: tabular-nums;
	font-weight: 800;
	font-size: clamp(2rem, 3vw, 2.75rem);
	line-height: 1;
	/* Muted watermark grey, but ≥3:1 on white (large-text AA). */
	color: #878c95;
}

.ladb-briefing__title {
	font-family: var(--font-display);
	font-size: clamp(1.5rem, 2vw, 1.875rem);
	font-weight: 700;
	line-height: 1.15;
	margin: 0 0 0.75rem;
}

.ladb-briefing__title a {
	text-decoration: none;
	transition: color var(--t);
}

.ladb-briefing__title a:hover,
.ladb-briefing__title a:focus-visible {
	color: var(--brand);
}

.ladb-briefing__summary {
	font-family: var(--font-serif);
	max-width: 58ch;
	margin: 0 0 1.5rem;
}

@media (min-width: 1024px) {
	.ladb-briefing {
		grid-template-columns: 1fr 3fr;
		gap: 3rem;
		align-items: start;
	}

	.ladb-briefing__meta {
		flex-direction: column;
		align-items: flex-start;
		gap: 0.75rem;
	}

	.ladb-briefing__number { font-size: 3.5rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   13. Beliefs / principles grid
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-beliefs {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 2rem;
}

@media (min-width: 768px) {
	.ladb-beliefs {
		grid-template-columns: 1fr 1fr;
		gap: 2.5rem 3rem;
	}
}

.ladb-beliefs > li {
	border-top: 2px solid var(--brand);
	padding-top: 1.25rem;
}

.ladb-beliefs h3 {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xl);
	line-height: 1.25;
	margin: 0 0 0.5rem;
}

.ladb-beliefs p {
	font-family: var(--font-serif);
	margin: 0;
}

.ladb-beliefs__number {
	display: block;
	font-family: var(--font-display);
	font-variant-numeric: tabular-nums;
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	letter-spacing: 0.09em;
	color: var(--brand-text);
	margin-bottom: 0.5rem;
}

/*
 * Closing coda to the section — a summing-up under a hairline, not a stray
 * fifth grid cell. The measure cap lives on the PARAGRAPHS, so the hairline
 * runs the full section width and the text starts on the same left edge as
 * everything above it. It was centred once; the client flagged it at review
 * ("a sudden switch to centre aligned") and they were right — nothing else on
 * the site is centred, so one centred block reads as a mistake. Do not put the
 * auto margin back.
 */
.ladb-coda {
	margin-top: 3.5rem;
	padding-top: 2.5rem;
	border-top: 1px solid var(--rule);
	display: grid;
	gap: 1em;
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--lg);
	line-height: 1.6;
	text-wrap: pretty;
}

.ladb-coda p {
	max-width: 64ch;
	margin: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   14. Poll statistics
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-stats {
	display: grid;
	gap: 2rem;
	margin: 0;
}

/*
 * Three across only from 1024px, NOT 768.
 *
 * The Astro build gated this at 768, which puts three columns of 18px serif
 * into a 753px viewport — about 22 characters a line, so every figure's
 * explanation reads as a ragged strip. The house tablet rule exists for exactly
 * this case: gate columns on lg, not md. A deliberate divergence from the
 * ported CSS, and the only one.
 */
@media (min-width: 1024px) {
	.ladb-stats {
		grid-template-columns: 1fr 1fr 1fr;
		gap: 3rem;
	}
}

.ladb-stat {
	border-top: 1px solid var(--rule);
	padding-top: 1.25rem;
}

.ladb-stat__figure {
	font-family: var(--font-display);
	font-variant-numeric: tabular-nums;
	font-size: clamp(2.5rem, 4vw, 3.25rem);
	font-weight: 800;
	line-height: 1.06;
	letter-spacing: -0.02em;
	color: var(--brand);
	margin: 0 0 0.5rem;
}

.ladb-stat__body {
	font-family: var(--font-serif);
	margin: 0;
}

/* Citation line — the house evidence device at stat scale. */
.ladb-stat__source {
	display: block;
	margin-top: 0.75rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--mute);
}

/*
 * The outlet link must be UNDERLINED, and the underline has to be declared
 * here rather than inherited — otherwise this link comes out visually identical
 * to the text beside it, which is a 1.4.1 failure and not merely colour-only.
 *
 * Colour stays mute grey and is deliberately NOT brand red: this line is well
 * under 18px, and red type below 18px is the one thing the brand brief rules
 * out. Hover and focus darken to ink rather than shifting hue.
 */
.ladb-stat__source a {
	color: inherit;
	text-decoration-line: underline;
	text-decoration-color: var(--mute);
	text-underline-offset: 0.25em;
	transition: color var(--t);
}

.ladb-stat__source a:hover,
.ladb-stat__source a:focus-visible {
	color: var(--ink);
	text-decoration-color: var(--ink);
}

/* ══════════════════════════════════════════════════════════════════════════
   15. Bill timeline
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-timeline {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0;
}

.ladb-timeline__step {
	position: relative;
	padding: 1.5rem 0 1.5rem 2rem;
	border-left: 2px solid var(--rule);
}

/* Node marker on the rail. Above the connector: ::after paints after ::before
   by default, so the S-bend's drop would otherwise cross over this node. */
.ladb-timeline__step::before {
	content: '';
	position: absolute;
	left: -6px;
	top: 2.15rem;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: var(--mute);
	z-index: 2;
}

.ladb-timeline__step.is-next {
	border-left-color: var(--brand);
}

.ladb-timeline__step.is-next::before {
	background: var(--brand);
	width: 12px;
	height: 12px;
	left: -7px;
}

.ladb-timeline__date {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--mute);
	margin: 0;
}

.ladb-timeline__step.is-next .ladb-timeline__date {
	color: var(--brand-text);
}

.ladb-timeline__title {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: 1.25;
	margin: 0.35rem 0 0.5rem;
}

.ladb-timeline__body {
	font-family: var(--font-serif);
	max-width: 62ch;
	margin: 0;
}

@media (min-width: 1024px) {
	/*
	 * ── The S-bend ─────────────────────────────────────────────────────────
	 * The rail is one continuous path that snakes down the grid: left → right
	 * across a row, down the right-hand side, back to the left, and on again.
	 * Each row-to-row turn is drawn in four moves:
	 *   1. across the row, left → right  (every item's border-top)
	 *   2. down the right-hand side      (the row's LAST item's border-right)
	 *   3. all the way back to the left  (that item's ::after bottom border,
	 *                                     stretched to the full grid width)
	 *   4. a short drop at the left      (the NEXT row's FIRST item's ::after)
	 * …then the new row's own border-tops carry it left → right again. Every
	 * turn is rounded so the eye follows the path instead of reading box edges.
	 *
	 * The connector lives ENTIRELY inside the row gap, so the gap has to be
	 * deep enough to hold the return leg plus the final drop.
	 *
	 * The turns are keyed to POSITION IN THE ROW, not to absolute child index,
	 * so the path repeats for as many rows as there are stages — the client can
	 * add stages indefinitely and the rail follows. It was keyed to
	 * :nth-child(3) / :nth-child(4) until 21 Aug 2026, which drew exactly ONE
	 * turn: a 7th stage left the rail dead-ending at the end of row 2 with row 3
	 * floating unconnected, and 3 stages or fewer left an 80px hook hanging off
	 * the last item into empty space. The two :not() guards below are what fix
	 * each of those — do not remove them.
	 *
	 * ⚠ THE COLUMN COUNT IS WRITTEN IN THREE PLACES and they must agree:
	 * `grid-template-columns` below, the `3n` / `3n + 1` selectors, and the
	 * `300%` on the return leg (= 100% × columns, since column-gap is 0).
	 *
	 * ⚠ -of-type, NOT -child, throughout. In the block editor Gutenberg
	 * renders its "add a stage" appender as a <div> INSIDE the <ol>, so it —
	 * not the last stage — is the <ol>'s :last-child, and the final stage would
	 * draw a descent into empty space on the canvas. Every stage is an <li> in
	 * both the editor and the front end, so counting by type ignores the
	 * appender and the two render identically. That is the whole point of this
	 * block: the canvas shows the published result.
	 * `nth-child` cannot read a custom property, so this cannot be reduced to
	 * one variable. Change one, change all three.
	 */
	.ladb-timeline {
		--tl-gap: 7.5rem;
		--tl-drop: 2.75rem;
		grid-template-columns: 1fr 1fr 1fr;
		column-gap: 0;
		row-gap: var(--tl-gap);
	}

	.ladb-timeline__step {
		border-left: none;
		border-top: 2px solid var(--rule);
		padding: 1.75rem 2.5rem 0 0;
	}

	.ladb-timeline__step::before {
		left: 0;
		top: -6px;
	}

	.ladb-timeline__step.is-next {
		border-left: none;
		border-top-color: var(--brand);
	}

	.ladb-timeline__step.is-next::before {
		top: -7px;
		left: 0;
	}

	/* 2. At the end of every row, turn down and descend the row's full height.
	   :not(:last-child) is what stops the FINAL stage from descending — whether
	   it happens to end a full row or not, there is nothing below it to reach. */
	.ladb-timeline__step:nth-of-type(3n):not(:last-of-type) {
		border-right: 2px solid var(--rule);
		border-top-right-radius: 14px;
		padding-right: 2rem;
	}

	/*
	 * 3. A short stub carrying the descent through the top of the row gap and
	 * curving it left. `right: -2px` cancels the item's own 2px border-right (an
	 * absolutely-positioned child resolves against the PADDING box, which
	 * excludes that border), so the stub sits exactly under the descent. The
	 * +4px height is what makes its bottom border land precisely ON the return
	 * leg's top border below.
	 */
	.ladb-timeline__step:nth-of-type(3n):not(:last-of-type)::after {
		content: '';
		position: absolute;
		right: -2px;
		top: 100%;
		width: 3.5rem;
		height: calc(var(--tl-gap) - var(--tl-drop) + 4px);
		border-right: 2px solid var(--rule);
		border-bottom: 2px solid var(--rule);
		border-bottom-right-radius: 14px;
	}

	/*
	 * 4. The return leg AND the drop into the next row, drawn as ONE element
	 * spanning the whole grid width: border-top is the leg running back to the
	 * left, border-left is the drop, and the radius is the corner between them.
	 * Keeping them in a single box means that corner can never misalign — two
	 * boxes joined here previously left a visible hairline double-line.
	 * Geometry: this box's bottom sits 2px below its own row's rail top, so with
	 * height H_b and the stub above of height H_a, their borders coincide when
	 * H_a + H_b = row-gap + 4px — hence the +4px there. Both are measured from
	 * the row gap, not from row heights, so unequal rows are fine.
	 * It goes on the first item of every row EXCEPT the very first, which has no
	 * row above it to return from.
	 */
	.ladb-timeline__step:nth-of-type(3n + 1):not(:first-of-type)::after {
		content: '';
		position: absolute;
		left: 0;
		bottom: 100%;
		/* Stops 14px (the corner radius) short of the grid's right edge, which
		   is exactly where the descent's rounded corner takes over. Running the
		   full 300% left a square nub sticking out past the curve. */
		width: calc(300% - 14px);
		height: var(--tl-drop);
		border-left: 2px solid var(--rule);
		border-top: 2px solid var(--rule);
		border-top-left-radius: 14px;
		z-index: 1;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   16. Video band
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-video__grid {
	display: grid;
	gap: 2.5rem;
	align-items: center;
}

.ladb-video__context h2 {
	font-size: var(--wp--custom--heading--section);
	margin-block: 1rem 1.25rem;
}

.ladb-video__copy {
	display: grid;
	gap: 1em;
	font-family: var(--font-serif);
}

.ladb-video__copy p { margin: 0; }

.ladb-video__wrap {
	position: relative;
	width: 100%;
	max-width: 34rem;
	margin-inline: auto;
	border-radius: var(--radius-md);
	overflow: hidden;
}

.ladb-video__wrap video {
	width: 100%;
	display: block;
	background: #000;
}

/* Overlay play affordance — covers the poster, disappears on first play.
   Native controls alone put only a small glyph in the corner, which does not
   read as "this is a film". */
.ladb-video__play {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1rem;
	border: 0;
	cursor: pointer;
	background: rgba(17, 19, 23, 0.28);
	color: #fff;
	transition: background-color var(--t);
}

.ladb-video__wrap[data-playing] .ladb-video__play {
	display: none;
}

.ladb-video__play:hover,
.ladb-video__play:focus-visible {
	background: rgba(17, 19, 23, 0.4);
}

.ladb-video__badge {
	display: block;
	transition: transform var(--t);
}

.ladb-video__play:hover .ladb-video__badge {
	transform: scale(1.06);
}

.ladb-video__label {
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--base);
	letter-spacing: 0.01em;
	text-shadow: 0 1px 12px rgba(0, 0, 0, 0.55);
}

.ladb-video__dur {
	font-weight: 400;
	opacity: 0.85;
}

.ladb-video__download {
	max-width: 34rem;
	margin: 0.75rem auto 0;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--mute);
}

@media (prefers-reduced-motion: reduce) {
	.ladb-video__play,
	.ladb-video__badge { transition: none; }
	.ladb-video__play:hover .ladb-video__badge { transform: none; }
}

/* Mobile/tablet: video first — it is the hook. */
.ladb-video__player { order: -1; }

@media (min-width: 1024px) {
	.ladb-video__grid {
		grid-template-columns: 45fr 55fr;
		gap: 3.5rem;
	}
	.ladb-video__player { order: 0; }
	.ladb-video__wrap { margin-left: auto; margin-right: 0; }
	.ladb-video__download { margin-inline: auto 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   17. Press — carousel strip and full list
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-strip__header {
	display: flex;
	flex-wrap: wrap;
	align-items: end;
	justify-content: space-between;
	gap: 1rem 2rem;
	margin-bottom: 2rem;
}

.ladb-strip__header h2 {
	font-size: var(--wp--custom--heading--strip);
	margin-block: 1rem 0;
}

/*
 * The carousel is CSS scroll-snap, not a JS slider library. It needs no
 * third-party dependency, works with JS disabled, and the browser handles
 * momentum, keyboard scrolling and reduced motion natively. The arrows and
 * dots are progressive enhancement on top.
 *
 * Slide width is set on the SLIDE, never inline — a `style` attribute cannot
 * be hashed under a CSP and was silently dropped in production on the previous
 * build, collapsing every carousel to one slide per view at all widths.
 */
.ladb-carousel {
	position: relative;
}

.ladb-carousel__track {
	/*
	 * `position: relative` is load-bearing, not tidiness.
	 *
	 * The visually-hidden "(opens in a new tab)" spans inside each card are
	 * absolutely positioned. Without a positioned ancestor INSIDE the scroll
	 * container, their containing block resolves to `.ladb-carousel` — which
	 * sits outside it — so they escape the track's clipping, sit at their
	 * static position several hundred pixels off-screen, and drag the whole
	 * document's scrollWidth out with them. The page got a horizontal
	 * scrollbar from text nobody can see.
	 */
	position: relative;
	display: flex;
	gap: 1.25rem;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	scrollbar-width: none;
	padding-bottom: 0.25rem;
}

.ladb-carousel__track::-webkit-scrollbar { display: none; }

@media (prefers-reduced-motion: reduce) {
	.ladb-carousel__track { scroll-behavior: auto; }
}

.ladb-carousel__slide {
	position: relative;
	flex: 0 0 var(--slide-basis, 100%);
	scroll-snap-align: start;
	display: flex;
	min-width: 0;
}

@media (min-width: 640px) {
	.ladb-carousel__slide { --slide-basis: calc(50% - 0.625rem); }
}

@media (min-width: 1024px) {
	.ladb-carousel__slide { --slide-basis: calc(33.3333% - 0.834rem); }
}

.ladb-carousel__controls {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: 1.25rem;
}

.ladb-carousel__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	background: transparent;
	border: 1px solid var(--ink);
	border-radius: var(--radius-sm);
	color: var(--ink);
	cursor: pointer;
	transition: background-color var(--t), color var(--t);
}

.ladb-carousel__btn:hover:not([disabled]),
.ladb-carousel__btn:focus-visible {
	background: var(--ink);
	color: var(--paper);
}

.ladb-carousel__btn[disabled] {
	opacity: 0.35;
	cursor: default;
}

/* Press card — paper on the warm band, per the card/band rule. */
.ladb-press-card {
	display: flex;
	flex-direction: column;
	width: 100%;
	background: var(--paper);
	border: 1px solid var(--rule);
	border-radius: var(--radius-md);
	padding: 1.5rem;
	transition: border-color var(--t);
}

.is-style-band-paper .ladb-press-card,
.ladb-carousel--on-paper .ladb-press-card {
	background: var(--surface);
}

.ladb-press-card:hover,
.ladb-press-card:focus-within {
	border-color: var(--ink);
}

.ladb-press-card__title {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 700;
	line-height: 1.25;
	margin: 0.75rem 0 1.25rem;
	flex: 1;
}

.ladb-press-card__title a {
	text-decoration: none;
	color: inherit;
	transition: color var(--t);
}

.ladb-press-card:hover .ladb-press-card__title a,
.ladb-press-card__title a:focus-visible {
	color: var(--brand);
}

.ladb-press-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem;
	margin: 0;
}

.ladb-press-meta__byline {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	color: var(--mute);
}

/* `:not(:first-child)` matters: this dot separated the outlet name from the
   byline, and now that the masthead sits out on the right the byline is the
   FIRST thing on that line. Without the guard every one of those rows opened
   with a stray "· ". */
.ladb-press-meta__byline:not(:first-child)::before {
	content: '·';
	margin-right: 0.5rem;
	color: var(--rule);
}

/*
 * The card's bottom line: "Read at The Times" left, masthead right.
 *
 * Client, 26 Aug 2026. It replaces a top-left masthead that started the
 * byline at a different x-position on every card, because mastheads vary
 * enormously in width. Down here the type has a straight left edge and the
 * logo has its own right edge, and the two never fight.
 *
 * `align-items: end` rather than center: wordmarks are optically heavy at
 * the baseline, and centring them left the logo floating above the text.
 */
.ladb-press-card__read {
	display: flex;
	align-items: end;
	justify-content: space-between;
	gap: 1rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--brand-text);
	margin: 0;
}

/* Smaller than the list's, deliberately — a card is a denser object than a
   full-width row, and the masthead is a credit here, not a heading. */
/* Bumped from 18px on 26 Aug 2026 — the client could not read them at a
   glance, which defeats the point of a masthead. Still smaller than the
   list's 28px: a card is a denser object than a full-width row. */
.ladb-press-card__read .ladb-outlet-logo {
	flex: none;
	height: 24px;
	max-width: 132px;
}

/* ── Press list (News and Events) — LabourList-style rules-separated rows ── */

.ladb-press-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.ladb-press-item {
	padding-block: 1.5rem;
	border-top: 1px solid var(--rule);
}

/*
 * Masthead out to the right; byline, headline and summary all on one left edge.
 *
 * Client's suggestion, 26 Aug 2026, and the screenshot showed exactly why:
 * mastheads vary enormously in width — The Times' is nearly three times
 * LabourList's — so inline they started the byline at a different x-position on
 * every row and the column had no left edge at all.
 *
 * Below 640px it stacks: a right-hand logo column on a phone leaves the
 * headline about forty characters wide.
 */
@media (min-width: 640px) {
	.ladb-press-item {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: start;
		column-gap: 2rem;
	}

	.ladb-press-item__main {
		min-width: 0;
	}

	.ladb-press-item .ladb-outlet-logo {
		grid-column: 2;
		/* Nudged down onto the byline's baseline rather than the very top of the
		   row, which read as though it were floating. */
		margin-top: 0.15rem;
		justify-self: end;
	}
}

/*
 * Below 640px the grid above does not apply, and the masthead is LAST in the
 * DOM — so it fell to the bottom of the row, under the summary, where it read
 * as though it belonged to the row beneath. Client picked this up on
 * 26 Aug 2026.
 *
 * `order: -1` lifts it to the top of the stack without touching the DOM,
 * which keeps the wide layout's source order intact. The masthead carries the
 * publication name as its alt text, so leading with it is also the right
 * reading order.
 */
@media (max-width: 639px) {
	.ladb-press-item {
		display: flex;
		flex-direction: column;
	}

	/*
	 * ⚠ `align-self: start` IS NOT OPTIONAL HERE.
	 *
	 * A flex column stretches its items across the cross axis, and an <img>
	 * with `width: auto` has no definite width to stop it — so the element
	 * became the full width of the row, and `object-fit: contain` then
	 * centred the artwork inside it. Wide mastheads nearly filled the box and
	 * looked fine; narrow ones (The Guardian, the Mirror, LabourList) sat
	 * adrift in the middle of the row. Client spotted it on 26 Aug 2026.
	 *
	 * It only appeared when this rule turned the row into a flex column. As a
	 * block-level default the image sized to its content and sat left, which
	 * is why it was never a problem before.
	 */
	.ladb-press-item .ladb-outlet-logo {
		order: -1;
		align-self: start;
		margin-bottom: 1rem;
	}
}

.ladb-press-item__main > :first-child {
	margin-top: 0;
}

.ladb-press-item:last-child {
	border-bottom: 1px solid var(--rule);
}

.ladb-press-item__title {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: 1.25;
	margin: 0.5rem 0 0;
	max-width: 34ch;
}

.ladb-press-item__title a {
	text-decoration: none;
	transition: color var(--t);
}

.ladb-press-item__title a:hover,
.ladb-press-item__title a:focus-visible {
	color: var(--brand);
}

.ladb-press-item__summary {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--base);
	color: var(--mute);
	margin: 0.6rem 0 0;
	max-width: 62ch;
}

/* ══════════════════════════════════════════════════════════════════════════
   18. Asides (article sidebar, news-and-events sidebar, contact sidebar)
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-aside {
	display: flex;
	flex-direction: column;
	gap: 2rem;
}

.ladb-aside__block {
	border-top: 2px solid var(--brand);
	padding-top: 1rem;
}

.ladb-aside__block p {
	font-family: var(--font-serif);
	margin: 0.6rem 0 1.25rem;
}

.ladb-aside__block p:last-child { margin-bottom: 0; }

/* Sticky sidebar at desktop only. */
@media (min-width: 1200px) {
	.ladb-aside--sticky {
		position: sticky;
		top: 6.5rem;
		align-self: start;
	}
}

/* Read unmistakably as links: underlined label + a red arrow affordance. */
.ladb-aside__links {
	list-style: none;
	margin: 0.75rem 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}

.ladb-aside__links a {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.75rem;
	min-height: 44px;
	padding-block: 0.6rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--ink);
	/* No underline on the flex container — flex blockifies children, so an
	   inline-block arrow would still be painted through. The underline lives on
	   the text span instead. */
	text-decoration: none;
	border-bottom: 1px solid var(--rule);
	transition: color var(--t);
}

.ladb-aside__links li:last-child a { border-bottom: none; }

.ladb-aside__links a > span:first-child {
	text-decoration: underline;
	text-decoration-color: var(--rule);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.25em;
}

.ladb-aside__links a .ladb-chev {
	color: var(--brand-text);
	flex-shrink: 0;
	transition: transform var(--t);
}

.ladb-aside__links a:hover,
.ladb-aside__links a:focus-visible { color: var(--brand-text); }

.ladb-aside__links a:hover > span:first-child,
.ladb-aside__links a:focus-visible > span:first-child { text-decoration-color: currentColor; }

.ladb-aside__links a:hover .ladb-chev { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
	.ladb-aside__links a .ladb-chev { transition: none; }
	.ladb-aside__links a:hover .ladb-chev { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   19. Single-briefing layout + foot navigation
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-article-layout {
	display: grid;
	gap: 3rem;
	padding-block: clamp(3rem, 5vw, 4.5rem);
}

.ladb-article-main {
	max-width: var(--wp--custom--container--prose);
	min-width: 0;
}

@media (min-width: 1200px) {
	.ladb-article-layout {
		grid-template-columns: minmax(0, 45rem) 20rem;
		gap: 4.5rem;
	}
}

.ladb-article-foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	margin-top: 3.5rem;
	padding-top: 1.5rem;
	border-top: 2px solid var(--ink);
}

.ladb-article-foot__back {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	min-height: 44px;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 600;
	color: var(--ink);
	text-decoration: none;
}

.ladb-article-foot__back span:not(.arrow-glyph) {
	text-decoration: underline;
	text-decoration-color: var(--brand);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.3em;
}

.ladb-article-foot__back:hover,
.ladb-article-foot__back:focus-visible { color: var(--brand-text); }

.ladb-article-foot__next {
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
	text-align: right;
	text-decoration: none;
	max-width: 22rem;
}

.ladb-article-foot__label {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--mute);
}

.ladb-article-foot__title {
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--lg);
	color: var(--ink);
}

.ladb-article-foot__title span:not(.arrow-glyph) {
	text-decoration: underline;
	text-decoration-color: var(--rule);
	text-underline-offset: 0.25em;
}

.ladb-article-foot__next:hover .ladb-article-foot__title,
.ladb-article-foot__next:focus-visible .ladb-article-foot__title { color: var(--brand-text); }

.ladb-article-foot__next:hover .ladb-article-foot__title span:not(.arrow-glyph) {
	text-decoration-color: currentColor;
}

/* ══════════════════════════════════════════════════════════════════════════
   20. Legal pages — grid + sticky table of contents

   A legal page must never be a lone 42rem strip.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-legal-layout {
	display: grid;
	gap: 3rem;
	padding-block: var(--wp--custom--section--legal);
}

.ladb-toc ul {
	list-style: none;
	margin: 0.75rem 0 0;
	padding: 0;
}

.ladb-toc a {
	display: block;
	padding-block: 0.4rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 500;
	color: var(--ink);
	text-decoration: none;
	border-bottom: 1px solid var(--rule);
}

.ladb-toc li:last-child a { border-bottom: none; }

.ladb-toc a:hover,
.ladb-toc a:focus-visible { color: var(--brand); }

.ladb-legal-body { max-width: var(--wp--custom--container--prose); }

@media (min-width: 768px) {
	.ladb-legal-layout {
		grid-template-columns: 15rem minmax(0, 45rem);
		gap: 4rem;
	}

	.ladb-toc {
		position: sticky;
		top: 6.5rem;
		align-self: start;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   21. CTA band

   Exactly ONE per page, immediately before the footer. One button, never two.
   Deliberately identical page to page: predictability is trust.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-cta__inner {
	display: flex;
	flex-direction: column;
	gap: 2rem;
}

@media (min-width: 1024px) {
	.ladb-cta__inner {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: 3rem;
	}
}

.ladb-cta h2 {
	font-size: clamp(1.75rem, 3vw, 2.25rem);
	margin: 0 0 0.75rem;
	color: var(--ink);
}

.ladb-cta__copy p {
	margin: 0;
	max-width: 56ch;
	font-family: var(--font-serif);
	color: var(--ink);
}

.ladb-cta__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1.25rem;
	flex-shrink: 0;
}

.ladb-cta__secondary {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	min-height: 44px;
	font-family: var(--font-display);
	font-weight: 600;
	color: var(--brand-deep);
	text-decoration: none;
}

/* Underline on the label only — the flex container would paint it through the
   arrow too. */
.ladb-cta__secondary > span:first-child {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.ladb-cta__secondary:hover,
.ladb-cta__secondary:focus-visible { color: var(--ink); }

/* ══════════════════════════════════════════════════════════════════════════
   22. Forms
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-form,
.frm-fluent-form {
	max-width: 35rem;
}

.ladb-form label,
.frm-fluent-form label,
.frm-fluent-form .ff-el-input--label label {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--sm);
	color: var(--ink);
}

.ladb-form input,
.ladb-form textarea,
.ladb-form select,
.frm-fluent-form input[type='text'],
.frm-fluent-form input[type='email'],
.frm-fluent-form input[type='tel'],
.frm-fluent-form input[type='url'],
.frm-fluent-form textarea,
.frm-fluent-form select {
	width: 100%;
	padding: 0.65rem 0.8rem;
	min-height: 44px;
	border: 1px solid var(--mute);
	border-radius: var(--radius-sm);
	background: var(--paper);
	color: var(--ink);
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--base);
	line-height: 1.5;
	box-shadow: none;
}

.ladb-form input:focus-visible,
.ladb-form textarea:focus-visible,
.frm-fluent-form input:focus-visible,
.frm-fluent-form textarea:focus-visible,
.frm-fluent-form select:focus-visible {
	outline: 2px solid var(--ink);
	outline-offset: 1px;
	border-color: var(--ink);
}

.ladb-form textarea,
.frm-fluent-form textarea { resize: vertical; }

.ladb-form button[type='submit'],
.frm-fluent-form .ff-btn-submit,
.frm-fluent-form button[type='submit'] {
	align-self: flex-start;
	min-height: 48px;
	padding: 0.8rem 1.6rem;
	border: none;
	border-radius: var(--radius-sm);
	background: var(--brand);
	color: #fff;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 700;
	cursor: pointer;
	box-shadow: none;
	transition: background-color var(--t);
}

.ladb-form button[type='submit']:hover,
.frm-fluent-form .ff-btn-submit:hover,
.frm-fluent-form button[type='submit']:hover {
	background: var(--brand-deep);
}

.frm-fluent-form .ff-el-is-error input,
.frm-fluent-form .ff-el-is-error textarea {
	border-color: var(--brand-deep);
}

.frm-fluent-form .error,
.frm-fluent-form .text-danger,
.frm-fluent-form .ff-el-is-error .error-text {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--brand-deep);
}

/* ══════════════════════════════════════════════════════════════════════════
   23. Cookie consent banner

   Non-blocking region, never a modal — it must not trap the user or hide
   content. Governs the consent cookie today; the Consent Mode v2 machinery is
   already wired so a tag can be added later without rework.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-consent {
	position: fixed;
	inset-inline: 0;
	bottom: 0;
	z-index: 90;
	background: var(--surface);
	border-top: 1px solid var(--rule);
	padding-block: 1rem;
	padding-bottom: calc(1rem + env(safe-area-inset-bottom));
}

.ladb-consent[hidden] { display: none; }

.ladb-consent__inner {
	display: flex;
	flex-direction: column;
	gap: 0.875rem;
	align-items: flex-start;
}

.ladb-consent__message {
	margin: 0;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--mute);
	max-width: 60ch;
}

.ladb-consent__message a {
	color: var(--ink);
	text-underline-offset: 0.2em;
}

.ladb-consent__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.625rem;
}

.ladb-consent__btn {
	min-height: 44px;
	padding: 0.5rem 1.25rem;
	border-radius: var(--radius-md);
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	cursor: pointer;
	border: 1.5px solid transparent;
	transition: background-color var(--t), color var(--t), border-color var(--t);
}

.ladb-consent__btn--solid {
	background: var(--brand);
	color: var(--paper);
}

.ladb-consent__btn--solid:hover,
.ladb-consent__btn--solid:focus-visible { background: var(--brand-deep); }

.ladb-consent__btn--ghost {
	background: transparent;
	color: var(--ink);
	border-color: color-mix(in srgb, var(--ink) 30%, transparent);
}

.ladb-consent__btn--ghost:hover,
.ladb-consent__btn--ghost:focus-visible {
	background: var(--ink);
	color: var(--paper);
	border-color: var(--ink);
}

@media (min-width: 768px) {
	.ladb-consent__inner {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: 1.5rem;
	}
	.ladb-consent__actions { flex-shrink: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   24. Articles index (the news stream)
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-articles {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 1.25rem;
}

@media (min-width: 768px) {
	.ladb-articles { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1200px) {
	.ladb-articles { grid-template-columns: 1fr 1fr 1fr; }
}

.ladb-article-card {
	position: relative;
	display: flex;
	flex-direction: column;
	background: var(--surface);
	border: 1px solid var(--rule);
	border-radius: var(--radius-md);
	overflow: hidden;
	transition: border-color var(--t);
}

.is-style-band-warm .ladb-article-card { background: var(--paper); }

.ladb-article-card:hover,
.ladb-article-card:focus-within { border-color: var(--ink); }

.ladb-article-card__media img {
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	display: block;
}

.ladb-article-card__body {
	padding: 1.5rem;
	display: flex;
	flex-direction: column;
	flex: 1;
}

.ladb-article-card__title {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: 1.25;
	margin: 0.5rem 0 0.6rem;
}

.ladb-article-card__title a {
	color: inherit;
	text-decoration: none;
	transition: color var(--t);
}

.ladb-article-card__title a::after {
	content: '';
	position: absolute;
	inset: 0;
}

.ladb-article-card:hover .ladb-article-card__title a,
.ladb-article-card__title a:focus-visible { color: var(--brand); }

.ladb-article-card__excerpt {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--base);
	margin: 0 0 1.25rem;
	flex: 1;
}

/* ══════════════════════════════════════════════════════════════════════════
   25. Two-column framing block (what we are / are not arguing)
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-framing {
	display: grid;
	gap: 2.5rem;
}

@media (min-width: 900px) {
	.ladb-framing {
		grid-template-columns: 1fr 1fr;
		gap: 4rem;
	}
}

.ladb-framing__body {
	display: grid;
	gap: 1em;
	margin-top: 1.25rem;
	font-family: var(--font-serif);
}

.ladb-framing__body p { margin: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   26. Reveal on scroll

   Functional-only motion: below-fold garnish, NEVER above-the-fold critical
   content — the H1, kicker, standfirst and primary CTA must render with JS
   disabled. Reduced-motion users see everything immediately.
   ══════════════════════════════════════════════════════════════════════════ */

[data-reveal] {
	opacity: 0;
	transform: translateY(22px);
	transition:
		opacity 800ms cubic-bezier(0.22, 1, 0.36, 1),
		transform 800ms cubic-bezier(0.22, 1, 0.36, 1);
	will-change: opacity, transform;
}

[data-reveal][data-revealed] {
	opacity: 1;
	transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
	[data-reveal] {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   27. Utility
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-flow > * + * { margin-top: 1.25rem; }
.ladb-flow-tight > * + * { margin-top: 0.5rem; }

.ladb-measure { max-width: var(--wp--custom--measure--body); }

/* Grid helpers used by the theme's own markup only. */
.ladb-two-col {
	display: grid;
	gap: 3rem;
}

@media (min-width: 1024px) {
	.ladb-two-col--sidebar {
		grid-template-columns: minmax(0, 1fr) minmax(0, 20rem);
		gap: 4.5rem;
	}
	.ladb-two-col--form {
		grid-template-columns: minmax(0, 35rem) minmax(0, 20rem);
		justify-content: space-between;
		gap: 4rem;
	}
}

/* Footnote under the timeline. A class, never an inline style attribute — see
   the note in the block's render template. */
.ladb-timeline__note {
	margin-top: 2rem;
}

/* Core's block-template skip link, restyled to the house focus treatment.
   Core injects the markup and a minimal inline style; this takes over the
   appearance so it matches everything else that receives focus. */
.skip-link.screen-reader-text:focus {
	position: fixed !important;
	top: 0.5rem;
	left: 0.5rem;
	z-index: 100000;
	width: auto !important;
	height: auto !important;
	clip: auto !important;
	clip-path: none !important;
	padding: 0.5rem 1rem;
	background: var(--ink);
	color: #fff;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	text-decoration: none;
	border-radius: var(--radius-sm);
}

/* ══════════════════════════════════════════════════════════════════════════
   28. Grid containers built from core Groups

   A core Group renders with `is-layout-flow`, and WordPress gives flow layouts
   a block-gap margin on every child. Inside a CSS grid that margin fights the
   grid's own gap and produces uneven rows. WordPress writes its rule entirely
   inside :where(), so it has zero specificity — a single class beats it
   cleanly and there is no !important anywhere.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-hero__grid.is-layout-flow > *,
.ladb-beliefs.is-layout-flow > *,
.ladb-stats.is-layout-flow > *,
.ladb-article-layout.is-layout-flow > *,
.ladb-legal-layout.is-layout-flow > *,
.ladb-framing.is-layout-flow > *,
.ladb-two-col.is-layout-flow > *,
.ladb-issues-grid.is-layout-flow > *,
.ladb-articles.is-layout-flow > * {
	margin-block-start: 0;
}

/* The beliefs / principles treatment works whether the items are list items or
   Groups the client added in the editor. */
.ladb-beliefs > * {
	border-top: 2px solid var(--brand);
	padding-top: 1.25rem;
}

.ladb-beliefs > * > * + * {
	margin-top: 0.5rem;
}

/* Bindings that resolve to nothing must collapse, not leave a red rule or a
   gap behind. A page with no kicker should look like a page with no kicker. */
.is-style-kicker:empty,
.is-style-kicker-bare:empty,
.is-style-standfirst:empty,
.is-style-meta-line:empty {
	display: none;
}

/* NOTE ON THE ROOT PADDING — verified in the browser, not assumed.
   `.wp-site-blocks` receives only the root TOP and BOTTOM padding; the left and
   right are applied by `.has-global-padding`, whose first occurrence down the
   tree is the <main> group. So the header and footer template parts are already
   edge to edge and must NOT be given negative margins — that would drag them a
   gutter's width outside the viewport and add a horizontal scrollbar.

   The consequence for templates: `core/post-content` has to carry
   `"align":"full"`, or every band section inside it is trapped at the 45rem
   prose measure and nothing bleeds. */

/* The hero's two columns. Declared here rather than as a core Columns block so
   the asymmetric 58/42 split and the capped right-edge bleed stay together. */
.ladb-hero__copy {
	min-width: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   29. Compact briefing links

   The minimised form of the briefings list — kicker over title, one hairline
   rule per row, a red arrow on the right. Used where the briefings are a
   pointer rather than the point: the "Who we are" page lists them so a reader
   can go on to the argument, whereas the Issues hub IS the argument and uses
   the full numbered rows.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-briefing-links {
	list-style: none;
	margin: 0;
	padding: 0;
}

.ladb-briefing-links a {
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: baseline;
	gap: 0.5rem 1.5rem;
	padding-block: 1.1rem;
	border-top: 1px solid var(--rule);
	text-decoration: none;
	transition: color var(--t);
}

.ladb-briefing-links li:last-child a {
	border-bottom: 1px solid var(--rule);
}

.ladb-briefing-links .bl-kicker {
	grid-column: 1;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--brand-text);
}

.ladb-briefing-links .bl-title {
	grid-column: 1;
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--xl);
	line-height: 1.25;
	text-decoration: underline;
	text-decoration-color: var(--rule);
	text-underline-offset: 0.25em;
}

.ladb-briefing-links .bl-arrow {
	grid-column: 2;
	grid-row: 1 / span 2;
	align-self: center;
	font-size: 1.25rem;
	color: var(--brand-text);
	transition: transform var(--t);
}

.ladb-briefing-links a:hover .bl-title,
.ladb-briefing-links a:focus-visible .bl-title {
	color: var(--brand-text);
	text-decoration-color: currentColor;
}

.ladb-briefing-links a:hover .bl-arrow {
	transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
	.ladb-briefing-links .bl-arrow { transition: none; }
	.ladb-briefing-links a:hover .bl-arrow { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   30. A two-column split that is NOT a sidebar

   `--sidebar` caps its second column at 20rem, which is right when the second
   column is a set of small aside blocks and wrong when it is running copy —
   it squeezed the "Press and spokespeople" text into a narrow stack. This is
   the Astro build's own 1fr / 1.4fr split, at its own 900px breakpoint:
   a short heading on the left, the paragraphs on the right.
   ══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 900px) {
	.ladb-two-col--split {
		grid-template-columns: 1fr 1.4fr;
		gap: 4rem;
	}
}

.ladb-two-col--split .ladb-framing__body {
	justify-items: start;
	margin-top: 0;
}

/* "See all briefings" — the way out of the sidebar list. */
.ladb-aside__all {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	margin-top: 0.75rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--brand-deep);
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.ladb-aside__all:hover,
.ladb-aside__all:focus-visible {
	color: var(--brand-text);
}

/* ══════════════════════════════════════════════════════════════════════════
   30. Quotes from MPs — the hero carousel and its full-width variant

   Client request, 25 Aug 2026: the hero's right-hand column becomes "a carousel
   of quotes from three MPs, each with their photo, sitting alongside the 'not
   safe' section". The same block, wider, closes the Who we are page.

   The portrait is a 3:4 crop at the 4px radius cap, NOT a circular avatar. The
   cap applies to everything on this site and one round photograph breaks it.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-quotes {
	display: flex;
	flex-direction: column;
	width: 100%;
	/*
	 * min-width: 0 is load-bearing, not tidiness.
	 *
	 * The Bill graphic this replaced in the hero was an SVG, which shrinks to
	 * fit whatever box it is given. A carousel does not: its track is a flex
	 * row of slides, so its max-content width is roughly three slides. Grid and
	 * flex items default to min-width:auto — "never shrink below your content"
	 * — so without this the warm hero panel grows several hundred pixels wider
	 * than its column and runs off the side of the phone.
	 */
	min-width: 0;
}

.ladb-quotes .ladb-carousel__slide {
	/* One quote at a time at every width. A quote is the unit; half of one is
	   nothing. This overrides the press strip's responsive slide widths. */
	--slide-basis: 100%;
}

.ladb-quote {
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
	justify-content: space-between;
	width: 100%;
	margin: 0;
}

/* The house evidence device — a 3px red rule down the left of quoted words. */
.ladb-quote__body {
	margin: 0;
	padding-left: 1.25rem;
	border-left: 3px solid var(--brand);
}

.ladb-quote__body p {
	font-family: var(--font-serif);
	font-size: clamp(1.125rem, 0.6vw + 0.95rem, 1.375rem);
	line-height: 1.5;
	margin: 0;
	text-wrap: pretty;
}

.ladb-quote__who {
	display: flex;
	align-items: center;
	gap: 1rem;
}

/* Sized by WIDTH with a fixed 3:4 ratio rather than a width/height pair, so
   one rule covers both carousels and the portrait cannot be squashed when
   the source image is not exactly 3:4. Client asked for these bigger on
   26 Aug 2026 — the face is the point of the card. */
.ladb-quote__photo {
	flex: none;
	width: clamp(96px, 6vw + 60px, 132px);
	aspect-ratio: 3 / 4;
	height: auto;
	object-fit: cover;
	border-radius: var(--radius-md);
}

.ladb-quote__photo--empty {
	display: block;
}

.ladb-quote__attrib {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
}

.ladb-quote__name {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--base);
	line-height: 1.3;
}

.ladb-quote__role {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.35;
	color: var(--mute);
	text-wrap: pretty;
}

/* Parliamentary portraits are licensed for reuse WITH attribution, so this line
   is a licence condition. Small, but never hidden. */
.ladb-quote__credit {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	color: var(--mute);
	margin-top: 0.35rem;
}

.ladb-quote__source {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	color: var(--mute);
	margin-top: 0.25rem;
}

a.ladb-quote__source {
	color: var(--brand-text);
}

.ladb-quotes .ladb-carousel__controls {
	margin-top: 1.25rem;
}

.ladb-quotes--wide .ladb-quote__body p {
	font-size: clamp(1.25rem, 1vw + 1rem, 1.625rem);
	max-width: 46ch;
}

.ladb-quotes--wide .ladb-quote__photo {
	width: clamp(104px, 7vw + 60px, 132px);
	height: auto;
}

/* ══════════════════════════════════════════════════════════════════════════
   31. People — the co-chairs carousel
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-people {
	min-width: 0;
}

.ladb-people__heading {
	font-size: var(--wp--preset--font-size--2xl);
	margin: 0.75rem 0 1.5rem;
}

.ladb-people .ladb-carousel__slide {
	--slide-basis: 100%;
}

.ladb-person {
	display: grid;
	grid-template-columns: minmax(0, 140px) minmax(0, 1fr);
	align-items: end;
	gap: 1.25rem;
	width: 100%;
	margin: 0;
}

.ladb-person__photo {
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	border-radius: var(--radius-md);
	/* The design carries no shadows anywhere, so a portrait needs a hairline to
	   hold its edge against the warm band. */
	border: 1px solid var(--rule);
}

.ladb-person__who {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	padding-bottom: 0.25rem;
}

.ladb-person__name {
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--lg);
	line-height: 1.25;
}

.ladb-person__role {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.5;
	color: var(--mute);
	text-wrap: pretty;
}

.ladb-person__credit {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	color: var(--mute);
	margin-top: 0.35rem;
}

@media (min-width: 480px) {
	.ladb-person {
		grid-template-columns: minmax(0, 170px) minmax(0, 1fr);
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   32. The event banner

   ⚠ CHROME, NOT A BAND. It lives in the header template part, between the
   header and <main>, because every section inside <main> hardcodes its own
   paper/warm value — a section that appears when an event is published and
   vanishes the day after it happens would flip the parity of the whole page
   beneath it.

   Ink rather than red, for two reasons that are both in the brief: red is
   capped at roughly 7% of any viewport and the footer already spends most of
   that, and a full-bleed red bar directly under the red-ruled header out-shouts
   the hero it sits above.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-event-banner {
	background: var(--ink);
	color: var(--paper);
}

/* Slim on purpose. This sits ABOVE the hero, so every pixel it takes is a pixel
   of the campaign's own argument pushed below the fold. Two lines of copy and a
   date block is the whole budget — an earlier draft carried an explanatory
   paragraph and ran to 259px. */
.ladb-event-banner__inner {
	display: grid;
	gap: 1rem;
	padding-block: 1.125rem;
}

.ladb-event-banner__main {
	min-width: 0;
}

/* The kicker's red rule reads fine on ink; the LABEL stays paper-white, because
   red type at 13px on ink does not clear 4.5:1. */
.ladb-event-banner__kicker {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--paper);
	margin: 0;
}

.ladb-event-banner__kicker::before {
	content: '';
	width: 40px;
	height: 3px;
	background: var(--brand);
	flex: none;
}

.ladb-event-banner__title {
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--base);
	line-height: 1.25;
	margin: 0.45rem 0 0;
	max-width: 40ch;
}

.ladb-event-banner__speakers {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	line-height: 1.5;
	margin: 0.35rem 0 0;
	max-width: 96ch;
	/* --mute is a LIGHT-background token and fails badly on ink; this is the
	   dark-ground equivalent, 10.6:1 against --ink. */
	color: var(--mute-inverse);
}

.ladb-event-banner__side {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 1rem;
}

.ladb-event-banner__when {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	margin: 0;
}

.ladb-event-banner__when-line {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.ladb-event-banner__when time {
	font-weight: 700;
}

.ladb-event-banner__detail {
	color: var(--mute-inverse);
}

.ladb-event-banner__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	padding: 0.6rem 1.4rem;
	background: var(--brand);
	color: var(--paper);
	font-family: var(--font-display);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--sm);
	border-radius: var(--radius-md);
	text-decoration: none;
	transition: background-color var(--t);
}

@media (hover: hover) and (pointer: fine) {
	.ladb-event-banner__cta:hover {
		background: var(--brand-deep);
	}
}

.ladb-event-banner__cta:focus-visible {
	outline: 2px solid var(--paper);
	outline-offset: 2px;
}

@media (min-width: 640px) {
	.ladb-event-banner__title {
		font-size: var(--wp--preset--font-size--lg);
	}
}

@media (min-width: 900px) {
	.ladb-event-banner__inner {
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: center;
		gap: 2.5rem;
	}

	.ladb-event-banner__side {
		flex-direction: row;
		align-items: center;
		gap: 1.5rem;
		text-align: right;
	}

	.ladb-event-banner__when {
		align-items: flex-end;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   32b. The event section — News and Events

   The full treatment the client asked for on 26 Aug 2026 ("replace the banner
   for the 3rd September event with a proper section instead").

   ⚠ IT IS INK, AND THAT IS THE WHOLE REASON IT IS SAFE TO PUT ON A PAGE.

   It appears when an event is published and vanishes the day after it happens.
   Every band on this site hardcodes its own paper/warm value, so a section that
   comes and goes would flip the parity of everything below it — silently, with
   no build error. Ink is not in the alternation, so it takes no slot: the
   sections either side keep their own values and still alternate correctly with
   each other the day this disappears.

   PAINT IT PAPER, WARM OR VEIL AND IT BECOMES A BAND, and then it does flip the
   parity of the page beneath it. Keep it ink.
   ══════════════════════════════════════════════════════════════════════════ */

/*
 * ⚠ NO GAP ABOVE THE FIRST BAND.
 *
 * WordPress puts a block-gap margin between the page-header template part and
 * the post content. Every page here opens on a full-bleed band, so that gap is
 * never wanted — and for months it was invisible, because the first band was
 * always paper and the body behind it is white too.
 *
 * The moment News and Events gained an INK first band it showed up as a 20px
 * white stripe between the warm page header and the black section. Client
 * spotted it on 26 Aug 2026.
 */
.entry-content {
	margin-block-start: 0;
}

.ladb-event-section {
	background: var(--ink);
	color: var(--paper);
	padding-block: clamp(2.5rem, 5vw, 4rem);
}

.ladb-event-section__inner {
	display: grid;
	gap: 1.25rem;
}

.ladb-event-section__kicker {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--paper);
	margin: 0;
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

/* The house kicker rule, in red — the one place red is allowed on ink, and it
   is a 2px line rather than type, so the 18px red-on-white floor does not
   apply. */
.ladb-event-section__kicker::before {
	content: '';
	flex: none;
	width: 1.75rem;
	height: 2px;
	background: var(--brand);
}

/* The client's own kicker rides after our standing "Upcoming event" label,
   divided by a rule rather than stacked on its own line. */
.ladb-event-section__kicker-context {
	position: relative;
	padding-left: 0.85rem;
	margin-left: 0.35rem;
	color: var(--rule);
}

.ladb-event-section__kicker-context::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.1em;
	bottom: 0.1em;
	width: 1px;
	background: rgb(255 255 255 / 0.35);
}

/*
 * Several events stack as a list with a rule between them. One event — the
 * common case — renders identically to the single-event treatment that was
 * signed off, because a one-item list has no separators and no top padding.
 */
.ladb-event-section__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.ladb-event-section__list > li + li {
	margin-top: 2.5rem;
	padding-top: 2.5rem;
	border-top: 1px solid rgb(255 255 255 / 0.18);
}

/* The client's own label ("In Parliament") sits on the event rather than on the
   section once there is more than one — see the note in render.php. */
.ladb-event__context {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--rule);
	margin: 0 0 0.5rem;
}

/*
 * The empty state. It exists because someone on News and Events may have gone
 * there looking for events, and a page that silently omits the section cannot
 * tell them "nothing is on" — only "something is broken".
 */
.ladb-event-section__empty {
	font-size: var(--wp--preset--font-size--base);
	max-width: 60ch;
	margin: 0;
}

.ladb-event-section__empty a {
	color: var(--paper);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
}

@media (hover: hover) and (pointer: fine) {
	.ladb-event-section__empty a:hover {
		color: var(--brand);
	}
}

.ladb-event-section__empty a:focus-visible {
	outline: 2px solid var(--paper);
	outline-offset: 2px;
}

.ladb-event-section__title {
	margin-top: 0;
	font-family: var(--font-display);
	font-size: clamp(1.75rem, 2.4vw + 1rem, 2.75rem);
	font-weight: 700;
	line-height: 1.15;
	margin: 0;
	max-width: 22ch;
	text-wrap: balance;
}

.ladb-event-section__facts {
	display: grid;
	gap: 1rem;
	margin: 0.5rem 0 0;
}

.ladb-event-section__fact dt {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--rule);
	margin: 0 0 0.15rem;
}

.ladb-event-section__fact dd {
	font-size: var(--wp--preset--font-size--base);
	margin: 0;
}

.ladb-event-section__speakers {
	margin-top: 0.5rem;
	padding-top: 1.25rem;
	border-top: 1px solid rgb(255 255 255 / 0.18);
}

.ladb-event-section__speakers-label {
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--rule);
	margin: 0 0 0.6rem;
}

/* A real list, not the banner's run-on sentence. Five organisations reading as
   one comma-spliced line was the thing that made the banner feel like a scroll
   of small print. */
.ladb-event-section__speaker-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0.4rem;
}

.ladb-event-section__speaker-list li {
	font-size: var(--wp--preset--font-size--base);
	padding-left: 1.1rem;
	position: relative;
}

.ladb-event-section__speaker-list li::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.62em;
	width: 0.4rem;
	height: 2px;
	background: var(--brand);
}

.ladb-event-section__actions {
	margin: 0.75rem 0 0;
}

.ladb-event-section__cta {
	display: inline-block;
	background: var(--brand);
	color: var(--paper);
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 700;
	text-decoration: none;
	padding: 0.75rem 1.5rem;
	border-radius: var(--radius-md);
	transition: background var(--t);
}

@media (hover: hover) and (pointer: fine) {
	.ladb-event-section__cta:hover {
		background: var(--brand-deep);
	}
}

.ladb-event-section__cta:focus-visible {
	outline: 2px solid var(--paper);
	outline-offset: 2px;
}

@media (min-width: 720px) {
	.ladb-event-section__facts {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 2rem;
	}

	.ladb-event-section__speaker-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 2rem;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   33. Briefing download

   The one deliberate exception to the card/band rule: wash ground with the 3px
   red left border, which is the house EVIDENCE device. It was signed off on the
   grounds that this is the single "take this away" action on the page. Do not
   spread the treatment to other panels.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-briefing-panel {
	display: grid;
	gap: 1.75rem;
	padding: clamp(1.5rem, 3vw, 2.5rem);
	background: var(--wash);
	border-left: 3px solid var(--brand);
	border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

.ladb-briefing-panel h2 {
	margin: 0.75rem 0 0;
}

.ladb-briefing-panel__desc {
	margin: 0.75rem 0 0;
	max-width: 62ch;
}

.ladb-briefing-panel__action {
	margin: 0;
	align-self: end;
}

@media (min-width: 900px) {
	.ladb-briefing-panel {
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: end;
		gap: 3rem;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   34. Section introductions, mastheads and the example-content flag
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-section__intro {
	max-width: 62ch;
	margin: 1rem 0 0;
}

/* Mastheads vary wildly in aspect ratio, so they are sized by HEIGHT and take
   whatever width that implies — capped, so a long wordmark cannot push the
   byline off the row. */
.ladb-outlet-logo {
	display: block;
	height: 28px;
	width: auto;
	max-width: 180px;
	object-fit: contain;
}

/*
 * The example-content flag.
 *
 * ⚠ NEVER DIM PLACEHOLDERS WITH `opacity` INSTEAD OF THIS. The previous build
 * tried .72 and put sixteen contrast failures on the home page — opacity
 * composites text against its backdrop and drops every muted and red-on-white
 * label below 4.5:1. This notice is what marks the content.
 */
.ladb-demo-flag {
	margin: 1.25rem 0 0;
	padding: 0.6rem 0.85rem;
	border: 1px dashed var(--mute);
	border-radius: var(--radius-md);
	background: var(--paper);
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	line-height: 1.5;
	color: var(--mute);
	max-width: 72ch;
}

.is-style-band-paper .ladb-demo-flag {
	background: var(--surface);
}

/* Full width on its own row: the footer baseline is a space-between flex and a
   thirty-word sentence inside it wraps into a mess between about 700 and
   1100px. */
.ladb-footer__colophon {
	flex-basis: 100%;
	max-width: 78ch;
	line-height: 1.6;
}

/* ══════════════════════════════════════════════════════════════════════════
   35. The hero panel when it holds quotes rather than a graphic

   The lg+ rule in section 10 gives .ladb-hero__media a fixed `height`, which is
   right for an image and wrong for text: a quote reflows, and at the narrowest
   width inside that column the longest one is clipped. This variant swaps the
   fixed height for a floor.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-hero__media--quotes {
	display: flex;
	min-width: 0;
}

@media (min-width: 1024px) {
	.ladb-hero__media--quotes {
		height: auto;
		min-height: clamp(22rem, 30vw, 32rem);
		align-items: center;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   36. Page header split in two — Who we are

   Client request, 25 Aug 2026: "could we split the section next to 'Who Are We'
   into two, with one half featuring a carousel of our co-chairs". Two columns
   only where there is room for two readable measures; below 1024px the
   co-chairs fall under the introduction, which is the right order — who we are,
   then who leads us.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-page-header__grid {
	display: grid;
	gap: 2.5rem;
}

.ladb-page-header__copy {
	min-width: 0;
}

.ladb-page-header__aside {
	min-width: 0;
	padding-top: 1.75rem;
	border-top: 1px solid var(--rule);
}

@media (min-width: 1024px) {
	.ladb-page-header__grid {
		grid-template-columns: 58fr 42fr;
		gap: 4rem;
		align-items: start;
	}

	.ladb-page-header__aside {
		padding-top: 0;
		padding-left: 3rem;
		border-top: 0;
		border-left: 1px solid var(--rule);
	}
}

/* ══════════════════════════════════════════════════════════════════════════
   37. The MPs' full statements

   "Why I'm against this Assisted Dying Bill" — three ~200-word first-person
   accounts, client copy of 26 Aug 2026.

   ⚠ NOT A CAROUSEL. A carousel would hide two of the three behind a control
   nobody clicks, and these are the most human material on the site. All three
   are on the page at once, portrait alternating left and right down the run,
   which is the house rule for repeating same-type sections.
   ══════════════════════════════════════════════════════════════════════════ */

.ladb-statement-list {
	display: flex;
	flex-direction: column;
	gap: clamp(3rem, 5vw, 4.5rem);
	margin-top: clamp(2.5rem, 4vw, 3.5rem);
}

.ladb-statement {
	display: grid;
	gap: 1.75rem;
	padding-top: clamp(2rem, 3vw, 2.75rem);
	border-top: 1px solid var(--rule);
	/* Anchored from the hero card, so the sticky header must not cover the name
	   when someone lands on it. */
	scroll-margin-top: 7rem;
}

.ladb-statement__person {
	display: grid;
	grid-template-columns: minmax(0, 160px) minmax(0, 1fr);
	align-items: end;
	column-gap: 1.25rem;
	align-content: start;
}

.ladb-statement__photo {
	grid-row: 1 / -1;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	border-radius: var(--radius-md);
	/* No shadows anywhere in this design, so a portrait needs a hairline to hold
	   its edge against the band. */
	border: 1px solid var(--rule);
}

.ladb-statement__name {
	grid-column: 2;
	align-self: end;
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--xl);
	line-height: 1.2;
	margin: 0;
}

.ladb-statement__role {
	grid-column: 2;
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.45;
	color: var(--mute);
	margin: 0.35rem 0 0;
	text-wrap: pretty;
}

.ladb-statement__credit {
	grid-column: 2;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--xs);
	color: var(--mute);
	margin: 0.5rem 0 0;
}

.ladb-statement__body > * + * {
	margin-top: 1.1rem;
}

/*
 * These are the MPs' own words, so the block is marked as a quotation: the
 * house red rail down the left, and true typographic quote marks opening the
 * first paragraph and closing the last. Client, 26 Aug 2026 — "something to
 * suggest that this is word for word".
 *
 * The marks are `content`, so they are decoration rather than text: the
 * statement reads identically with styles off, which matters because
 * inserting real quote characters into client copy would be editing it.
 */
.ladb-statement__body {
	border-left: 3px solid var(--brand);
	padding-left: clamp(1rem, 2vw, 1.5rem);
}

.ladb-statement__body p {
	font-family: var(--font-serif);
	font-size: var(--wp--preset--font-size--base);
	line-height: 1.65;
	margin: 0;
	max-width: 68ch;
	text-wrap: pretty;
}

/*
 * ⚠ SPECIFICITY, AND IT BIT US. `.ladb-statement__body > * + *` above is
 * (0,1,0); `.ladb-statement__body p` is (0,1,1) and its `margin: 0` therefore
 * WON. Every statement rendered as one unbroken wall of text — the paragraphs
 * were there in the markup, with zero space between them. It shipped like
 * that and the client found it, not us.
 *
 * `p + p` is (0,1,2), so this beats the reset. Do not "tidy" it back to a
 * universal sibling selector.
 */
.ladb-statement__body p + p {
	margin-top: 1.1rem;
}

.ladb-statement__body p:first-child::before {
	content: '\201C';
}

.ladb-statement__body p:last-child::after {
	content: '\201D';
}

@media (min-width: 900px) {
	.ladb-statement {
		grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
		gap: 3.5rem;
		align-items: start;
	}

	.ladb-statement__person {
		grid-template-columns: minmax(0, 1fr);
		position: sticky;
		top: 7rem;
	}

	.ladb-statement__photo {
		grid-row: auto;
		max-width: 260px;
	}

	.ladb-statement__name,
	.ladb-statement__role,
	.ladb-statement__credit {
		grid-column: 1;
	}

	.ladb-statement__name {
		margin-top: 1.1rem;
	}

	/* The house zigzag: portrait right on every other one. `order` moves only
	   the painted position, so the DOM order — and therefore the reading and tab
	   order — stays name-then-words throughout. */
	.ladb-statement:nth-child(even) .ladb-statement__person {
		order: 2;
	}

	.ladb-statement:nth-child(even) {
		grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
	}
}

/* ── The hero card's "read the full statement" link ──────────────────────── */

.ladb-quote__foot {
	display: flex;
	flex-direction: column;
	gap: 0.85rem;
}

.ladb-quote__more {
	align-self: flex-start;
	font-family: var(--font-display);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--brand-text);
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.ladb-quote__more:hover,
.ladb-quote__more:focus-visible {
	color: var(--brand-deep);
}

/*
 * The hero card is smaller than it was. These are opening PARAGRAPHS of ~55
 * words rather than one-line quotes, and the old clamp topped out at 22px,
 * which ran the longest of them past the bottom of the hero panel.
 */
.ladb-quotes--hero .ladb-quote__body p {
	font-size: clamp(1rem, 0.35vw + 0.9rem, 1.125rem);
	line-height: 1.55;
}
