/*
Theme Name:   BatterySafety
Theme URI:    https://www.batterysafety.co.uk
Description:  Child theme of GeneratePress implementing the Marzan Security design system v2. Two-layer tokens: CORE is shared across every Marzan brand, BRAND is overridden per data-brand attribute. All behaviour lives in the batterysafety-core plugin so this theme can be replaced without losing the site.
Author:       Marzan Security Ltd
Author URI:   https://marzansecurity.com/en
Template:     generatepress
Version:      2.0.0
Requires PHP: 8.2
License:      GNU General Public License v2 or later
Text Domain:  batterysafety
*/

/* ===========================================================================
   FONTS
   Declared once, in theme.json, not here. WordPress emits the @font-face rules
   from theme.json for both the front end and the block editor, so the editor
   previews in the real typefaces. Duplicating them in this file registered every
   face twice.

   Both are self-hosted variable fonts in assets/fonts/: Archivo 400–800 for
   headings, Montserrat 500–700 for body. Two files cover every weight, and
   nothing is fetched from a third party on the critical path. They are preloaded
   in functions.php because they render the H1 and the first paragraph.
   ======================================================================== */

/* ===========================================================================
   LAYER 1 — CORE TOKENS
   Identical for every Marzan brand. Do not put brand colours in here.
   ======================================================================== */

:root {
	/* ── Typography ─────────────────────────────────────────────────── */
	--font-heading: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
	--font-body:    'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;

	/* Fluid throughout, so there is no jump at a breakpoint and the
	   intermediate sizes need no overrides. */
	--text-display:    clamp(1.875rem, 1.2rem + 2.8vw, 3rem);      /* 30 → 48px */
	--text-display-xl: clamp(2.25rem, 1.4rem + 3.6vw, 3.75rem);    /* 36 → 60px, full-width hero only */
	--text-h2:         clamp(1.625rem, 1.35rem + 1.2vw, 2rem);     /* 26 → 32px */
	--text-h3:         clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);    /* 20 → 24px */
	--text-h4:         1.125rem;                                   /* 18px */
	--text-body-lg:    clamp(1.0625rem, 1rem + 0.2vw, 1.125rem);   /* 17 → 18px */
	--text-body:       1rem;                                       /* 16px */
	--text-article:    1.125rem;                                   /* 18px — long-form */
	--text-small:      0.875rem;                                   /* 14px */
	--text-button:     0.9375rem;                                  /* 15px */

	--leading-display: 1.05;
	--leading-h2:      1.15;
	--leading-h3:      1.25;
	--leading-h4:      1.3;
	--leading-body:    1.5;
	--leading-body-lg: 1.6;
	--leading-article: 1.7;

	/* ── Reading measure ────────────────────────────────────────────── */
	/*
	 * A page may be 1280px wide. A paragraph may not.
	 *
	 * The design brief specifies 70ch and states the goal as 60–75 characters a
	 * line. Those two do not agree in Montserrat: 1ch is the width of the "0"
	 * glyph, which here is 12px against an average character width of 10.6px, so
	 * 70ch measured out at 840px and 79 characters — above the range it was meant
	 * to produce. Measured on the live page, 696px lands on ~68 characters, the
	 * middle of the target. The goal is honoured rather than the literal value;
	 * re-measure if the body typeface ever changes.
	 *
	 * Expressed in rem, not ch, for a second reason found while measuring: 1ch is
	 * relative to the element's own font-size, so a 14px caption and an 18px
	 * paragraph carrying the same token ended up in columns of 542px and 696px.
	 * That is not one column, it is several. rem keeps the column identical
	 * whatever size the text inside it is.
	 */
	--measure:         43.5rem;   /* 696px — ≈68 characters at 18px Montserrat */
	--measure-intro:   37.5rem;   /* 600px */
	--measure-heading: 30rem;     /* 480px — deliberately tighter; a heading over
	                                 three lines reads worse than one over two */

	/* ── Neutral and semantic ───────────────────────────────────────── */
	--surface:         #FFFFFF;
	--surface-muted:   #F5F5F5;
	--surface-inverse: var(--brand-primary);

	--text-heading:    var(--brand-primary);
	--text-body-color: #45565E;   /* 7.7:1 on white — full hex, never rgba */
	/*
	 * The design brief specifies #6B7A80 here. Measured, that is 4.45:1 on white
	 * and 4.08:1 on the muted surface — both below the 4.5:1 the brief itself sets
	 * as the standard, and this colour carries 14px text: source attributions,
	 * breadcrumbs, byline dates, CTA blurbs. Darkened to the nearest value that
	 * clears AA on both surfaces with margin (5.2:1 and 4.8:1). Same hue.
	 */
	--text-muted:      #626F75;
	--text-on-inverse: #F5F5F5;

	/*
	 * Two border roles, because they answer to different rules.
	 * --border-subtle is decoration (table rules, hairlines, dividers) and has no
	 * contrast requirement. --border-control is the visible boundary of an
	 * interactive control, which WCAG 1.4.11 requires to reach 3:1 — the measured
	 * #C7C7C7 manages 1.69:1, so inputs would have had no perceivable edge.
	 */
	--border-subtle:   #C7C7C7;   /* 1.69:1 — decorative only, never a control edge */
	--border-control:  #8A8A8A;   /* 3.45:1 — inputs, selects, radio and checkbox boxes */
	--border-strong:   #626F75;   /* hover state on a control */

	--color-success:   #1E7B4D;
	--color-warning:   #B45309;
	--color-error:     #C0392B;
	--color-info:      #005C94;

	--blue-100: #9DCAEC;
	--blue-400: #1BA2DD;
	--blue-700: #005C94;

	/* ── Shape ──────────────────────────────────────────────────────── */
	/* The contrast between soft 25px on media and tight 10px on buttons is the
	   strongest piece of handwriting in this design. Keep it consistent. */
	--radius-card:   25px;
	--radius-button: 10px;
	--radius-input:  10px;
	--radius-badge:  999px;

	/* Four-step elevation, navy-tinted rather than black. One level per role;
	   an element rises exactly one step on interaction, never two. */
	--shadow-1: 0 1px   2px        rgba(16, 57, 91, 0.08);
	--shadow-2: 0 6px  24px  -4px  rgba(16, 57, 91, 0.18);
	--shadow-3: 0 12px 32px  -6px  rgba(16, 57, 91, 0.24);
	--shadow-4: 0 24px 64px -12px  rgba(16, 57, 91, 0.32);
	--shadow-card:       var(--shadow-2);
	--shadow-card-hover: var(--shadow-3);

	/* ── Space — 4px base ───────────────────────────────────────────── */
	--space-1:  0.25rem;
	--space-2:  0.5rem;
	--space-3:  0.75rem;
	--space-4:  1rem;
	--space-5:  1.25rem;
	--space-6:  1.5rem;
	--space-8:  2rem;
	--space-12: 3rem;
	--space-16: 4rem;
	--space-20: 5rem;

	--container-max: 1280px;
	--wide:          70rem;     /* 1120px — the section-block width */
	--gutter:        1.25rem;   /* 20px — was 10px, text nearly touched the edge */
	--section-y:     clamp(3rem, 2rem + 4vw, 5rem);
	--card-gap:      2rem;      /* 32px — was 20px, cards stuck together */

	/* ── Motion ─────────────────────────────────────────────────────── */
	/* Under 150ms reads as a jolt, over 220ms reads as sluggish. */
	--ease:       cubic-bezier(0.4, 0, 0.2, 1);
	--duration:   180ms;
	--duration-slow: 220ms;
}

/* ===========================================================================
   LAYER 2 — BRAND TOKENS
   Set data-brand on <html>. One component library, several brands.
   ======================================================================== */

:root,
[data-brand='batterysafety'],
[data-brand='marzan'],
[data-brand='accukluis'] {
	--brand-primary:      #10395B;
	--brand-primary-deep: #0B2C5A;
	--brand-accent:       #FA8C30;
	--brand-accent-text:  #A84E00;   /* 5.6:1 on white — orange for text */
	--brand-accent-hover: #E07A1F;
	--brand-accent-active:#D06E15;
}

/*
 * BatterySafety currently shares the family accent so it reads as part of the
 * Marzan group. To differentiate it instead, uncomment this block: it swaps the
 * accent to the blue already present in the Marzan palette. Nothing else in the
 * system needs to change — that is the point of the two-layer split.
 *
 * [data-brand='batterysafety'] {
 *   --brand-accent:        #1BA2DD;
 *   --brand-accent-text:   #005C94;
 *   --brand-accent-hover:  #1789BC;
 *   --brand-accent-active: #14759F;
 * }
 */

/* ===========================================================================
   BASE
   ======================================================================== */

body {
	font-family: var(--font-body);
	font-size: var(--text-body);
	font-weight: 500;
	line-height: var(--leading-body);
	color: var(--text-body-color);
	background: var(--surface);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	/*
	 * Full-bleed bands are 100vw, and 100vw includes the scrollbar, so they overhang
	 * the content box by the scrollbar width and the page gains a horizontal scroll.
	 * `clip` rather than `hidden`: hidden makes this a scroll container and would break
	 * the sticky header, clip only clips.
	 */
	overflow-x: clip;
}

h1, h2, h3, h4, h5, h6,
.entry-title {
	font-family: var(--font-heading);
	color: var(--text-heading);
	text-wrap: balance;
}

/* The H1 gets the text measure, not the tighter heading measure: at 48px that
   works out to roughly 24 characters a line, which is the figure the design brief
   targets. The heading measure would cut it to about 19 and make a large heading
   read as cramped rather than large. */
h1, .entry-title {
	font-size: var(--text-display);
	font-weight: 800;
	line-height: var(--leading-display);
	letter-spacing: -0.01em;
	max-width: var(--measure);
	margin-bottom: var(--space-6);
}

h2 {
	font-size: var(--text-h2);
	font-weight: 800;
	line-height: var(--leading-h2);
	max-width: var(--measure-heading);
	margin-top: var(--space-16);
	margin-bottom: var(--space-4);
}

h3 {
	font-size: var(--text-h3);
	font-weight: 700;
	line-height: var(--leading-h3);
	max-width: var(--measure-heading);
	margin-top: var(--space-12);
	margin-bottom: var(--space-3);
}

h4 {
	font-size: var(--text-h4);
	font-weight: 700;
	line-height: var(--leading-h4);
	margin-top: var(--space-8);
	margin-bottom: var(--space-2);
}

/* Display-xl is reserved for a full-width hero with no image beside it.
   Never on the standard split hero — see the design brief. */
.bs-display-xl {
	font-size: var(--text-display-xl);
	line-height: var(--leading-display);
	max-width: none;
}

strong { font-weight: 700; }

/* ── Links: navy and underlined, never orange ───────────────────────────
   Orange is reserved for the primary CTA. When inline links are orange too,
   every link in a paragraph competes with the conversion button and the eye
   cannot find the destination. */
a {
	color: var(--brand-primary);
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-thickness: 1px;
	transition: color 150ms var(--ease), text-decoration-thickness 150ms var(--ease);
}

a:hover {
	color: var(--brand-accent-text);
	text-decoration-thickness: 2px;
}

:focus-visible {
	outline: 2px solid var(--brand-primary);
	outline-offset: 2px;
}

/* On navy, the focus ring and links have to invert or they disappear. */
.bs-inverse :focus-visible,
.bs-trust :focus-visible,
.site-header :focus-visible,
.bs-mobile-cta :focus-visible {
	outline-color: var(--text-on-inverse);
}

.bs-inverse a,
.bs-trust a {
	color: var(--text-on-inverse);
}

.bs-inverse a:hover,
.bs-trust a:hover {
	color: var(--brand-accent);
}

/* ===========================================================================
   SKIP LINK
   ======================================================================== */

.bs-skip-link {
	position: absolute;
	left: -9999px;
	z-index: 999;
	padding: var(--space-3) var(--space-4);
	background: var(--brand-primary);
	color: var(--text-on-inverse);
	border-radius: 0 0 var(--radius-button) 0;
	text-decoration: none;
	font-weight: 600;
}

.bs-skip-link:focus {
	left: 0;
	top: 0;
}

/* ===========================================================================
   HEADER — navy, negative logo
   ======================================================================== */

.site-header,
body .site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--brand-primary);
	border-bottom: none;
}

/* Sticky headers sit above content, so they need one elevation step. */
.site-header.bs-header--scrolled {
	box-shadow: var(--shadow-3);
	backdrop-filter: saturate(140%) blur(6px);
}

.site-header .inside-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: nowrap;
	/* 24px gutter, per the design brief. GeneratePress defaults to 40px, which cost
	   32px the header did not have to spare. */
	padding: var(--space-3) var(--space-6);
	gap: var(--space-6);
}

/* GeneratePress puts 20px either side of every nav link. Across six items that is
   240px of padding, which is what pushed the header past the viewport. 14px keeps a
   comfortable target while giving the row room to fit. */
.site-header .main-nav > ul > li > a {
	padding-left: var(--space-4);
	padding-right: var(--space-4);
}

.main-navigation .main-nav > ul > li > a::after {
	left: var(--space-4);
	right: var(--space-4);
}

/* The mark never shrinks to make room for the navigation. When the two no longer
   fit, the navigation collapses to a toggle — that is what the breakpoint filter in
   functions.php is for. Without this, flexbox squashed a 176px logo to 101px. */
.site-header .site-branding {
	flex: 0 0 auto;
	min-width: 0;
}

/*
 * The nav does not shrink either.
 *
 * min-width:0 here was a bug: it let flexbox compress the nav below its min-content
 * width, so every label containing a space broke onto two lines — "Battery fires" and
 * "Storage & charging" wrapped while "Cabinets" and "News" did not, which is what made
 * the row heights alternate between 60px and 120px. Below 1024px the nav becomes a
 * toggle, so on desktop it never needs to give way.
 */
.site-header .main-navigation {
	flex: 0 0 auto;
	min-width: auto;
}

.site-header .main-nav > ul {
	flex-wrap: nowrap;
}

/* Belt and braces: a nav label is never worth two lines. */
.site-header .main-nav > ul > li > a {
	white-space: nowrap;
}

/* Anchored links must clear the sticky header rather than landing underneath it.
   overflow-x: clip is the fallback for full-bleed bands if --scrollbar-width is
   never set; `clip` does not create a scroll container, so sticky still works. */
html {
	scroll-padding-top: 6rem;
	overflow-x: clip;
}

/* Wordmark fallback, used until the logo assets arrive. */
.bs-wordmark {
	display: inline-flex;
	align-items: baseline;
	gap: 0.1em;
	font-family: var(--font-heading);
	font-weight: 800;
	font-size: 1.375rem;
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--text-on-inverse);
	text-decoration: none;
}

.bs-wordmark:hover { color: var(--text-on-inverse); }

/*
 * Deliberately not orange. The wordmark sits inches from the orange header CTA,
 * and two orange things in the same bar is exactly the dilution the "orange is
 * the CTA only" rule exists to prevent. Weight carries the emphasis instead, and
 * the pale blue is from the Marzan palette.
 */
.bs-wordmark__accent { color: var(--text-on-inverse); }

.bs-wordmark__tld {
	font-size: 0.6em;
	font-weight: 600;
	color: var(--blue-100);
	letter-spacing: 0;
}

/*
 * Explicit height, not max-height.
 *
 * The supplied SVG carries a viewBox but no width/height attributes, so it has an
 * intrinsic ratio and no intrinsic size. With height:auto and only a max-height to
 * constrain it, the browser resolved the used size to 0×0 and the logo vanished.
 * A stated height plus width:auto gives the ratio something to work from.
 */
.bs-logo {
	display: flex;
	align-items: center;
	line-height: 0;   /* no descender gap under an inline-level image */
}

.bs-logo img,
.site-header .site-logo img {
	height: 44px;
	width: auto;
	max-width: 100%;
	display: block;
}

/* Below the point where the nav collapses there is more room, but the header bar
   is shorter, so the mark comes down slightly with it. */
@media (max-width: 639px) {
	.bs-logo img { height: 36px; }
}

/* ── Navigation ─────────────────────────────────────────────────────────
   The source site had no explicit font-family here and fell back to the
   system font. */
/* 15px rather than the brief's 16px: at 16px the six labels plus the CTA and a 176px
   logo left almost no headroom in the bar, and a slightly smaller nav reads as more
   composed against the 48px H1. Uses the existing button size token, so it stays
   inside the type scale. */
.main-navigation,
.main-navigation .main-nav > ul > li > a,
.main-navigation .menu-toggle {
	font-family: var(--font-body);
	font-size: var(--text-button);
	font-weight: 500;
	background: transparent;
}

.main-navigation .main-nav > ul > li > a,
.main-navigation .menu-toggle {
	color: var(--text-on-inverse);
	text-decoration: none;
	position: relative;
}

/* The underline is a pseudo-element rather than a border so it can animate
   without shifting the text. */
.main-navigation .main-nav > ul > li > a::after {
	content: '';
	position: absolute;
	left: var(--space-5);
	right: var(--space-5);
	bottom: 12px;
	height: 2px;
	background: var(--brand-accent);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--duration) var(--ease);
}

.main-navigation .main-nav > ul > li > a:hover,
.main-navigation .main-nav > ul > li[class*='current-menu'] > a {
	color: var(--brand-accent);
	background: transparent;
}

.main-navigation .main-nav > ul > li > a:hover::after,
.main-navigation .main-nav > ul > li[class*='current-menu'] > a::after {
	transform: scaleX(1);
}

/* Dropdowns must open on focus as well as hover, or they are unreachable by
   keyboard. GeneratePress handles hover; this adds the focus path. */
.main-navigation ul ul {
	background: var(--brand-primary-deep);
	box-shadow: var(--shadow-3);
	border-radius: 0 0 var(--radius-button) var(--radius-button);
	overflow: hidden;
}

.main-navigation li:focus-within > ul,
.main-navigation li.bs-submenu-open > ul {
	display: block;
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	left: auto;
	transform: none;
}

.main-navigation ul ul li a { color: var(--text-on-inverse); }
.main-navigation ul ul li a:hover { color: var(--brand-accent); }

/* Header CTA — the one orange element up here.
   The <li> loses GeneratePress's link padding so the button controls its own
   box; without this the nav padding and the button padding stack. */
.main-navigation .bs-menu-item-cta {
	display: flex;
	align-items: center;
	margin-left: var(--space-3);
}

.main-navigation .bs-menu-item-cta > a,
.main-navigation .main-nav > ul > li.bs-menu-item-cta > a {
	color: var(--brand-primary);
	background: var(--brand-accent);
	padding: 10px 18px;
	line-height: 1;
}

.main-navigation .bs-menu-item-cta > a:hover {
	color: var(--brand-primary);
	background: var(--brand-accent-hover);
}

/* No underline animation on the CTA — it is a button, not a nav link. */
.main-navigation .bs-menu-item-cta > a::after { content: none; }

/*
 * In the collapsed menu the CTA becomes a full-width block. At its desktop padding
 * it measured 38px tall, under the 44px minimum touch target, and a button squeezed
 * against the left edge of a dropdown does not read as the primary action.
 */
@media (max-width: 1024px) {
	.main-navigation .bs-menu-item-cta {
		margin: var(--space-3) var(--space-5) var(--space-4);
	}

	.main-navigation .bs-menu-item-cta > a,
	.main-navigation .main-nav > ul > li.bs-menu-item-cta > a {
		display: flex;
		align-items: center;
		justify-content: center;
		min-height: 48px;
		text-align: center;
	}
}

/* ===========================================================================
   BREADCRUMBS
   ======================================================================== */

/* Aligned with the text column, not with the container edge. GeneratePress emits the
   breadcrumb outside .entry-content, so it does not inherit the measure. */
.bs-breadcrumb {
	max-width: var(--measure);
	margin-inline: auto;
	margin-bottom: var(--space-6);
	font-size: var(--text-small);
	color: var(--text-muted);
}

.bs-breadcrumb ol {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin: 0;
	padding: 0;
}

.bs-breadcrumb a {
	color: var(--text-muted);
	text-decoration: none;
}

.bs-breadcrumb a:hover {
	color: var(--brand-accent-text);
	text-decoration: underline;
}

.bs-breadcrumb li + li::before {
	content: '›';
	margin-right: var(--space-2);
	color: var(--border-subtle);
}

/* ===========================================================================
   ARTICLE MEASURE
   GeneratePress nests content as .bs-article > .inside-article > .entry-content
   and does not apply theme.json's contentSize to that container, so the measure
   is set here on the children of .entry-content. Do not move it up to
   .bs-article or .inside-article: those also wrap the tables, which are wider.

   Long-form gets 18px/1.7. Montserrat is a display face — high x-height, wide
   letterforms, little rhythm between characters — so extended regulatory text
   needs the larger size and looser leading to stay readable.
   ======================================================================== */

.bs-article .entry-content {
	font-size: var(--text-article);
	line-height: var(--leading-article);
}

.bs-article .entry-content > *,
.bs-article .entry-title,
.bs-article .bs-byline {
	max-width: var(--measure);
	margin-inline: auto;
}

/*
 * Headings are capped shorter than the body, but their left edge must stay on the
 * body column. `margin-inline: auto 0` did the opposite — it put the free space on
 * the left and flushed every heading to the right-hand edge of the column.
 *
 * The body column is centred inside .entry-content, so its left offset is
 * (100% - measure) / 2. Reproducing that as an explicit left margin keeps the
 * heading aligned with the text while the shorter cap takes effect on the right.
 * max() guards the narrow case, where the column is already the full width.
 */
.bs-article .entry-content > h2,
.bs-article .entry-content > h3 {
	max-width: var(--measure-heading);
	margin-left: max(0px, calc((100% - var(--measure)) / 2));
	margin-right: auto;
}

/* ── Breaking out of the measure ─────────────────────────────────────────
   Long-form prose belongs in the 696px column. Section compositions — two-column
   text-and-image blocks, card grids, navy bands — do not: squeezed into the
   measure they stop being compositions. Three widths are available:

     (default)    696px   prose
     .alignwide  1120px   section blocks, tables, card grids
     .alignfull   100vw   full-bleed bands, which set their own inner container

   Tables and the trust bar get alignwide behaviour without needing the class,
   because a standards comparison cramped to the measure is unreadable and that
   table is meant to be citable. */
.bs-article .entry-content > .alignwide,
.bs-article .entry-content > .wp-block-table,
.bs-article .entry-content > .bs-table-wrap,
.bs-article .entry-content > .bs-trust,
.bs-article .entry-content > .bs-split,
.bs-article .entry-content > .bs-cards {
	width: min(var(--wide), calc(100vw - 2 * var(--gutter)));
	max-width: none;
	margin-left: 50%;
	transform: translateX(-50%);
}

/* Full-bleed: escape .inside-article and the grid container's padding entirely.
   100vw rather than 100% because every ancestor is narrower than the viewport.

   --scrollbar-width is measured in theme.js, because 100vw includes the scrollbar
   while the content box does not: without subtracting it the band overhangs by
   ~15px and the page gains a horizontal scroll. It falls back to 0px if JavaScript
   never runs, and the overflow-x: clip below catches that case. */
.bs-article .entry-content > .alignfull {
	width: calc(100vw - var(--scrollbar-width, 0px));
	max-width: none;
	margin-left: 50%;
	transform: translateX(-50%);
}

@media (max-width: 1023px) {
	/* Below the breakout threshold there is nothing to break out of. */
	.bs-article .entry-content > .alignwide,
	.bs-article .entry-content > .wp-block-table,
	.bs-article .entry-content > .bs-table-wrap,
	.bs-article .entry-content > .bs-trust,
	.bs-article .entry-content > .bs-split,
	.bs-article .entry-content > .bs-cards {
		width: 100%;
		margin-left: 0;
		transform: none;
	}
}

.bs-article .entry-content > p,
.bs-article .entry-content > ul,
.bs-article .entry-content > ol {
	margin-bottom: var(--space-6);
}

.bs-article .entry-content > ul,
.bs-article .entry-content > ol {
	padding-left: 1.4em;
}

.bs-article .entry-content li + li { margin-top: var(--space-2); }

/* ===========================================================================
   SECTION RHYTHM
   white → muted → white → navy → white. The background alternation is the
   layout mechanism; it gives rhythm without decoration.
   ======================================================================== */

.bs-section {
	padding-block: var(--section-y);
}

.bs-section--muted {
	background: var(--surface-muted);
}

.bs-section--inverse,
.bs-inverse {
	background: var(--brand-primary);
	color: var(--text-on-inverse);
}

.bs-section--inverse h1,
.bs-section--inverse h2,
.bs-section--inverse h3,
.bs-section--inverse h4,
.bs-inverse h1, .bs-inverse h2, .bs-inverse h3, .bs-inverse h4 {
	color: var(--text-on-inverse);
}

/* ===========================================================================
   DIRECT ANSWER BOX — the first thing on every page
   ======================================================================== */

.bs-answer {
	background: var(--surface-muted);
	border-left: 4px solid var(--brand-primary);
	padding: var(--space-6);
	border-radius: 0 var(--radius-card) var(--radius-card) 0;
	margin-bottom: var(--space-8);
}

.bs-answer__label {
	font-family: var(--font-heading);
	font-size: var(--text-small);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--brand-primary);
	margin-bottom: var(--space-2);
}

.bs-answer p:last-child {
	margin-bottom: 0;
	font-size: var(--text-body-lg);
	line-height: var(--leading-body-lg);
}

/* ===========================================================================
   SOURCED STATISTIC CALLOUT
   ======================================================================== */

.bs-stat {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: var(--space-2) var(--space-6);
	align-items: baseline;
	padding: var(--space-6);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	background: var(--surface);
	box-shadow: var(--shadow-2);
	margin-block: var(--space-8);
}

.bs-stat__figure {
	grid-row: span 2;
	font-family: var(--font-heading);
	font-size: clamp(2.25rem, 1.8rem + 2vw, 3.25rem);
	font-weight: 800;
	line-height: 1;
	color: var(--brand-primary);
	margin: 0;
	font-variant-numeric: tabular-nums;
}

.bs-stat__text {
	margin: 0;
	font-size: var(--text-body-lg);
	line-height: var(--leading-body-lg);
}

.bs-stat__source {
	margin: 0;
	font-size: var(--text-small);
	line-height: var(--leading-body);
	color: var(--text-muted);
}

.bs-stat__source a { color: var(--text-muted); }
.bs-stat__source a:hover { color: var(--brand-accent-text); }

@media (max-width: 639px) {
	.bs-stat { grid-template-columns: 1fr; }
	.bs-stat__figure { grid-row: auto; }
}

/* ===========================================================================
   TABLES
   ======================================================================== */

.bs-table-wrap,
.wp-block-table {
	overflow-x: auto;                 /* wide tables scroll inside themselves */
	margin-block: var(--space-12);
	border-radius: var(--radius-card);
}

.bs-spec-table,
.wp-block-table table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--text-small);
	line-height: var(--leading-body);
	background: var(--surface);
}

.bs-spec-table caption,
.wp-block-table caption {
	text-align: left;
	font-size: var(--text-small);
	color: var(--text-muted);
	padding-bottom: var(--space-2);
}

.wp-block-table figcaption,
.bs-table-wrap figcaption {
	font-size: var(--text-small);
	color: var(--text-muted);
	margin-top: var(--space-3);
}

.bs-spec-table th,
.bs-spec-table td,
.wp-block-table th,
.wp-block-table td {
	border: 1px solid var(--border-subtle);
	padding: var(--space-3) var(--space-4);
	text-align: left;
	vertical-align: top;
}

.bs-spec-table th[scope='row'],
.wp-block-table th[scope='row'] {
	background: var(--surface-muted);
	width: 30%;
	font-weight: 600;
	color: var(--text-heading);
}

.wp-block-table thead th {
	background: var(--brand-primary);
	color: var(--text-on-inverse);
	font-family: var(--font-heading);
	font-weight: 700;
	border-color: var(--brand-primary);
}

/* ===========================================================================
   FAQ ACCORDION — core Details blocks
   ======================================================================== */

.wp-block-details {
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-button);
	padding: var(--space-4) var(--space-6);
	margin-bottom: var(--space-3);
	background: var(--surface);
	transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

.wp-block-details:hover {
	border-color: var(--border-strong);
}

.wp-block-details[open] {
	border-color: var(--brand-primary);
	box-shadow: var(--shadow-1);
}

.wp-block-details summary {
	font-family: var(--font-heading);
	font-size: var(--text-h4);
	font-weight: 700;
	line-height: var(--leading-h4);
	color: var(--brand-primary);
	cursor: pointer;
}

.wp-block-details[open] summary { margin-bottom: var(--space-3); }
.wp-block-details p:last-child { margin-bottom: 0; }

/* ===========================================================================
   TRUST BAR
   ======================================================================== */

.bs-trust {
	background: var(--brand-primary);
	color: var(--text-on-inverse);
	padding: var(--space-8);
	border-radius: var(--radius-card);
	gap: var(--space-6);
	margin-block: var(--space-16);
}

.bs-trust__item {
	flex: 1 1 240px;
	margin: 0;
	font-size: var(--text-body);
	line-height: var(--leading-body);
	color: var(--text-on-inverse);
}

.bs-trust__item strong {
	display: block;
	font-family: var(--font-heading);
	font-weight: 700;
	margin-bottom: var(--space-1);
}

/*
 * Light variant. Navy is the strongest emphasis in the system and the page rhythm
 * uses it once; a navy trust bar directly below the navy band read as one
 * undifferentiated block with a white gap through it.
 */
.bs-trust--light {
	background: var(--surface);
	border: 1px solid var(--border-subtle);
	color: var(--text-body-color);
	box-shadow: var(--shadow-1);
}

.bs-trust--light .bs-trust__item { color: var(--text-body-color); }
.bs-trust--light .bs-trust__item strong { color: var(--brand-primary); }
.bs-trust--light a { color: var(--brand-primary); }
.bs-trust--light a:hover { color: var(--brand-accent-text); }
.bs-trust--light :focus-visible { outline-color: var(--brand-primary); }

/* ===========================================================================
   SECTION COMPOSITIONS
   The page rhythm from the design brief: two-column text-and-image blocks with
   the image alternating sides, card grids, and full-bleed navy bands. The
   background alternation (white → muted → white → navy → white) is the layout
   mechanism — it gives rhythm without decoration.
   ======================================================================== */

/* ── Split: text one side, media the other ───────────────────────────────
   .bs-split--flip puts the media on the left. On mobile both collapse to a
   single column with the text first, so the reading order never depends on
   which side the image happens to be on. */
.bs-split {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--space-16);
	align-items: center;
	margin-block: var(--space-20);
}

.bs-split__text > *:first-child { margin-top: 0; }
.bs-split__text > *:last-child { margin-bottom: 0; }

/* Inside a column the measure is the column, so the cap has to lift or the text
   would sit in a 696px box inside a 520px column and overflow it. */
.bs-split__text > *,
.bs-split__text h2,
.bs-split__text h3 {
	max-width: none;
	margin-inline: 0;
}

.bs-split__media img,
.bs-split__media video {
	width: 100%;
	height: auto;
	border-radius: var(--radius-card);
	display: block;
}

/* Fixed ratio so a row of these never looks ragged. */
.bs-split__media figure,
.bs-split__media .wp-block-image {
	margin: 0;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: var(--radius-card);
}

.bs-split__media figure img,
.bs-split__media .wp-block-image img {
	height: 100%;
	object-fit: cover;
}

@media (max-width: 1023px) {
	.bs-split {
		grid-template-columns: 1fr;
		gap: var(--space-8);
		margin-block: var(--space-12);
	}

	/* Text first regardless of source order. */
	.bs-split__text { order: 1; }
	.bs-split__media { order: 2; }
}

@media (min-width: 1024px) {
	.bs-split--flip .bs-split__text { order: 2; }
	.bs-split--flip .bs-split__media { order: 1; }
}

/* ── Heading left, body right ────────────────────────────────────────────
   The accukluis pattern where a large heading occupies its own column beside the
   body copy. Gives a long heading room to breathe without stretching the text. */
.bs-split--heading {
	grid-template-columns: 5fr 6fr;
	align-items: start;
}

.bs-split--heading .bs-split__text h1,
.bs-split--heading .bs-split__text h2 {
	margin-top: 0;
	max-width: 18ch;   /* headings in their own column want a tighter cap */
}

/* ── Full-bleed band ─────────────────────────────────────────────────────
   Sets its own inner container, because the block itself is 100vw wide. */
.bs-band {
	padding-block: var(--section-y);
	margin-block: var(--space-20);
}

.bs-band__inner {
	max-width: var(--wide);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.bs-band--muted { background: var(--surface-muted); }

.bs-band--navy {
	background: var(--brand-primary);
	color: var(--text-on-inverse);
}

.bs-band--navy h2,
.bs-band--navy h3,
.bs-band--navy h4 { color: var(--text-on-inverse); }
.bs-band--navy .bs-split__text > * { color: var(--text-on-inverse); }

.bs-band .bs-split { margin-block: 0; }

/* ── Card grid ───────────────────────────────────────────────────────────── */
.bs-cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: var(--card-gap);
	margin-block: var(--space-16);
}

.bs-cards > * { margin: 0; }

/* A card built from a Group block. */
.bs-cards .wp-block-group {
	background: var(--surface);
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	padding: var(--space-6);
	box-shadow: var(--shadow-card);
	transition: box-shadow var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.bs-cards .wp-block-group:hover {
	box-shadow: var(--shadow-card-hover);
	transform: translateY(-2px);
}

.bs-cards .wp-block-group > *:first-child { margin-top: 0; }
.bs-cards .wp-block-group > *:last-child { margin-bottom: 0; }

.bs-cards h3 {
	max-width: none;
	margin-top: 0;
	font-size: var(--text-h3);
}

.bs-cards img {
	border-radius: var(--radius-card);
	width: 100%;
	height: auto;
}

/* ── Editorial image placeholder ─────────────────────────────────────────
   Marks where photography is needed. Deliberately obvious: an empty grey box
   that looks intentional would ship to production unnoticed.
   Per the design brief, imagery must be product-in-context — the cabinet in a
   real setting — never a product shot on white. */
.bs-image-placeholder {
	display: grid;
	place-items: center;
	aspect-ratio: 4 / 3;
	border: 2px dashed var(--border-control);
	border-radius: var(--radius-card);
	background: var(--surface-muted);
	padding: var(--space-6);
	text-align: center;
	color: var(--text-muted);
	font-size: var(--text-small);
}

.bs-image-placeholder p { margin: 0; max-width: 32ch; }
.bs-image-placeholder strong { display: block; color: var(--brand-primary); }

/* ── Hero block ──────────────────────────────────────────────────────────
   The front page carries its H1 inside the hero, so GeneratePress's own page
   title is suppressed there — see functions.php. Everywhere else the entry
   title is the H1 and this block is not used. */
.bs-hero-block {
	margin-top: var(--space-8);
	margin-bottom: var(--space-20);
}

.bs-hero-block h1 {
	margin-top: 0;
	max-width: 20ch;
}

.bs-lead {
	font-size: var(--text-body-lg);
	line-height: var(--leading-body-lg);
	color: var(--text-heading);
	font-weight: 600;
}

/* ── Two statistics side by side inside a band ───────────────────────────── */
.bs-stat-row {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
	gap: var(--card-gap);
	margin-bottom: var(--space-8);
}

.bs-stat-row .bs-stat { margin-block: 0; }

.bs-band__note {
	max-width: var(--measure);
	margin-bottom: 0;
	color: var(--text-body-color);
}

.bs-band--muted h2 { margin-top: 0; }

/* ── Hero (pattern variant) ──────────────────────────────────────────────
   On mobile the image moves below the text so the CTA stays above the fold. */
.bs-hero { margin-block: var(--space-8) var(--space-16); }

.bs-hero .wp-block-column > *:first-child { margin-top: 0; }

.bs-hero__media img {
	border-radius: var(--radius-card);
	width: 100%;
	height: auto;
}

@media (max-width: 1023px) {
	.bs-hero { flex-direction: column; }
	.bs-hero .wp-block-column:last-child { order: 2; }
}

/* Certification badges: monochrome, beside the CTA rather than three
   paragraphs above it, where they do nothing at the moment of clicking. */
.bs-badges {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-5);
	margin-top: var(--space-6);
}

.bs-badges img,
.bs-badges svg {
	height: 36px;
	width: auto;
	filter: grayscale(1);
	opacity: 0.75;
}

/* ===========================================================================
   BUTTONS
   One scale. Buttons that sit next to each other are always the same size —
   the difference is fill versus outline, never height.
   ======================================================================== */

.bs-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	font-family: var(--font-body);
	font-size: var(--text-button);
	font-weight: 600;
	line-height: 1;
	padding: 14px 28px;
	border-radius: var(--radius-button);
	border: 1px solid transparent;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--duration) var(--ease),
	            color var(--duration) var(--ease),
	            border-color var(--duration) var(--ease),
	            transform var(--duration) var(--ease),
	            box-shadow var(--duration) var(--ease);
}

.bs-button--sm { padding: 10px 18px; font-size: var(--text-small); }
.bs-button--lg { padding: 17px 32px; font-size: var(--text-body); }

/* The most important button on the site should not carry a 15px label. */
.bs-button--hero { padding: 18px 36px; font-size: var(--text-body-lg); }

/* ── Primary — the CTA, and the only orange element on the page ────── */
.bs-button--primary {
	background: var(--brand-accent);
	color: var(--brand-primary);   /* navy on orange = 5.5:1 */
	border-color: transparent;
}

.bs-button--primary:hover {
	background: var(--brand-accent-hover);
	color: var(--brand-primary);
	transform: translateY(-1px);
	box-shadow: var(--shadow-2);
}

.bs-button--primary:active {
	background: var(--brand-accent-active);
	transform: none;
	box-shadow: none;
}

/* ── Secondary on light — navy outline, never orange ───────────────── */
.bs-button--secondary {
	background: transparent;
	color: var(--brand-primary);
	border-color: var(--brand-primary);
}

.bs-button--secondary:hover {
	background: rgba(16, 57, 91, 0.06);
	color: var(--brand-primary);
}

.bs-button--secondary:active { background: rgba(16, 57, 91, 0.12); }

/* ── Secondary on navy ────────────────────────────────────────────── */
.bs-button--ghost {
	background: transparent;
	color: var(--text-on-inverse);
	/* A button edge is a control boundary; on navy the light border already
	   clears 3:1 comfortably. */
	border-color: var(--border-subtle);
}

.bs-button--ghost:hover {
	background: rgba(245, 245, 245, 0.1);
	border-color: var(--text-on-inverse);
	color: var(--text-on-inverse);
}

/* ── Tertiary — a link with direction, not a button ────────────────── */
.bs-button--tertiary {
	background: transparent;
	border: none;
	padding: 0;
	color: var(--brand-primary);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.bs-button--tertiary:hover { color: var(--brand-accent-text); }
.bs-button--tertiary::after {
	content: '→';
	transition: transform var(--duration) var(--ease);
}
.bs-button--tertiary:hover::after { transform: translateX(4px); }

.bs-button[disabled],
.bs-button--disabled {
	opacity: 0.45;
	cursor: not-allowed;
	transform: none;
}

.bs-button:focus-visible {
	outline: 2px solid var(--brand-primary);
	outline-offset: 2px;
}

.bs-button--ghost:focus-visible { outline-color: var(--text-on-inverse); }

/* White space around a CTA raises the click rate: the button reads as its own
   object rather than as part of the paragraph. */
.bs-cta-block { margin-block: var(--space-8); }

/* ===========================================================================
   DUAL-DESTINATION CTA
   ======================================================================== */

.bs-cta {
	background: var(--surface-muted);
	border-radius: var(--radius-card);
	padding: var(--space-8);
	margin-block: var(--space-16);
}

.bs-cta__heading {
	font-size: var(--text-h3);
	margin-top: 0;
	margin-bottom: var(--space-3);
	max-width: var(--measure-heading);
}

.bs-cta__intro {
	max-width: var(--measure-intro);
	margin-bottom: var(--space-6);
}

.bs-cta__options {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: var(--space-4);
	margin-bottom: var(--space-6);
}

.bs-cta__button {
	display: block;
	padding: var(--space-6);
	border-radius: var(--radius-button);
	text-decoration: none;
	border: 1px solid var(--brand-primary);
	background: var(--surface);
	color: var(--brand-primary);
	transition: box-shadow var(--duration) var(--ease),
	            transform var(--duration) var(--ease),
	            background-color var(--duration) var(--ease);
}

/* The primary destination carries the orange fill. */
.bs-cta__button--primary {
	background: var(--brand-accent);
	border-color: transparent;
	color: var(--brand-primary);
}

.bs-cta__button--primary:hover {
	background: var(--brand-accent-hover);
	color: var(--brand-primary);
}

.bs-cta__button--secondary:hover {
	background: rgba(16, 57, 91, 0.06);
	color: var(--brand-primary);
}

.bs-cta__button:hover {
	transform: translateY(-2px);
	box-shadow: var(--shadow-2);
}

.bs-cta__button:active { transform: none; box-shadow: none; }

.bs-cta__label {
	display: block;
	font-family: var(--font-heading);
	font-weight: 700;
	font-size: var(--text-h4);
	line-height: var(--leading-h4);
	margin-bottom: var(--space-1);
}

.bs-cta__blurb {
	display: block;
	font-size: var(--text-small);
	line-height: var(--leading-body);
	color: var(--text-muted);
}

/* Full navy, not 80%: at 80% opacity this measured 3.21:1 on the orange fill,
   below AA for 14px text. Semi-transparent text also shifts colour with whatever
   sits behind it, which is exactly what the brief warns against. */
.bs-cta__button--primary .bs-cta__blurb { color: var(--brand-primary); }

.bs-cta__note {
	margin: 0;
	font-size: var(--text-small);
	line-height: var(--leading-body);
	color: var(--text-muted);
	max-width: var(--measure-intro);
}

.bs-cta__note a { color: var(--text-muted); }
.bs-cta__note a:hover { color: var(--brand-accent-text); }

/* ===========================================================================
   BYLINE — named author, credentials, both dates
   ======================================================================== */

.bs-byline {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	border-top: 1px solid var(--border-subtle);
	border-bottom: 1px solid var(--border-subtle);
	padding-block: var(--space-4);
	margin-block: var(--space-8);
	font-size: var(--text-small);
	line-height: var(--leading-body);
}

.bs-byline__avatar {
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	border-radius: var(--radius-badge);
	overflow: hidden;
	background: var(--brand-primary);
	color: var(--text-on-inverse);
	display: grid;
	place-items: center;
	font-family: var(--font-heading);
	font-weight: 700;
	font-size: var(--text-body);
	letter-spacing: 0.02em;
}

.bs-byline__avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.bs-byline__text { min-width: 0; }
.bs-byline p { margin: 0; }
.bs-byline__author { color: var(--text-heading); font-weight: 600; }
.bs-byline__dates { color: var(--text-muted); }

/* ===========================================================================
   RELATED LINKS
   ======================================================================== */

.bs-related {
	background: var(--surface-muted);
	border-radius: var(--radius-card);
	padding: var(--space-6);
	margin-block: var(--space-12);
}

.bs-related__heading {
	font-size: var(--text-h4);
	margin: 0 0 var(--space-3);
}

.bs-related ul { margin: 0; padding-left: 1.2em; }
.bs-related li { margin-bottom: var(--space-2); }
.bs-related__note { color: var(--text-muted); font-size: var(--text-small); }

.bs-news-quote {
	border-left: 4px solid var(--brand-accent);
	padding-left: var(--space-4);
	margin: 0 0 var(--space-4);
	font-size: var(--text-body-lg);
	font-style: italic;
	color: var(--text-heading);
}

/* ===========================================================================
   CARDS
   ======================================================================== */

.bs-news-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
	gap: var(--card-gap);
}

.bs-card,
.bs-news-card {
	display: flex;
	flex-direction: column;
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	padding: var(--space-6);
	background: var(--surface);
	box-shadow: var(--shadow-card);
	transition: box-shadow var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.bs-card:hover,
.bs-news-card:hover {
	box-shadow: var(--shadow-card-hover);
	transform: translateY(-2px);
}

.bs-card:focus-within,
.bs-news-card:focus-within {
	outline: 2px solid var(--brand-primary);
	outline-offset: 4px;
}

/* A ragged grid of differently proportioned images reads as unfinished. */
.bs-card__media {
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: var(--radius-card);
	margin-bottom: var(--space-4);
}

.bs-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--duration-slow) var(--ease);
}

.bs-card:hover .bs-card__media img { transform: scale(1.03); }

/* ── Glossary index ────────────────────────────────────────────────── */

.bs-glossary-list { margin: 0; }

.bs-glossary-list dt {
	font-family: var(--font-heading);
	font-size: var(--text-h4);
	font-weight: 700;
	margin-top: var(--space-6);
}

.bs-glossary-list dt a { text-decoration: none; }
.bs-glossary-list dt a:hover { text-decoration: underline; }

.bs-glossary-list dd {
	margin: var(--space-1) 0 0;
	color: var(--text-body-color);
}

.bs-news-card__date,
.bs-news-card__source {
	font-size: var(--text-small);
	color: var(--text-muted);
	margin: 0;
}

.bs-news-card__title {
	font-size: var(--text-h3);
	line-height: var(--leading-h3);
	margin: var(--space-2) 0;
	max-width: none;
}

.bs-news-card__title a { text-decoration: none; }
.bs-news-card__title a:hover { color: var(--brand-accent-text); text-decoration: underline; }
.bs-news-card:hover .bs-news-card__title a { color: var(--brand-accent-text); }
.bs-news-card__summary { margin: 0 0 var(--space-3); font-size: var(--text-body); }

/* ===========================================================================
   WIZARD
   ======================================================================== */

.bs-wizard {
	max-width: var(--measure);
	margin-inline: auto;
}

.bs-wizard__step {
	border: 1px solid var(--border-subtle);
	border-radius: var(--radius-card);
	padding: var(--space-8);
	margin-bottom: var(--space-6);
	background: var(--surface);
	box-shadow: var(--shadow-2);
}

.bs-wizard__legend {
	font-family: var(--font-heading);
	font-size: var(--text-h2);
	font-weight: 800;
	line-height: var(--leading-h2);
	color: var(--brand-primary);
	max-width: var(--measure-heading);
}

.bs-wizard__number {
	display: block;
	font-family: var(--font-body);
	font-size: var(--text-small);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--brand-accent-text);
	margin-bottom: var(--space-2);
}

.bs-wizard__help {
	color: var(--text-muted);
	font-size: var(--text-body);
	max-width: var(--measure-intro);
	margin-bottom: var(--space-6);
}

.bs-wizard__answers { display: grid; gap: var(--space-3); }

.bs-wizard__answer {
	display: flex;
	align-items: flex-start;
	gap: var(--space-3);
	min-height: 48px;              /* comfortable touch target */
	border: 1px solid var(--border-control);
	border-radius: var(--radius-input);
	padding: var(--space-4);
	cursor: pointer;
	transition: border-color var(--duration) var(--ease), background-color var(--duration) var(--ease);
}

.bs-wizard__answer:hover { border-color: var(--border-strong); }

.bs-wizard__answer:has(input:checked) {
	border-color: var(--brand-primary);
	background: var(--surface-muted);
	box-shadow: inset 0 0 0 1px var(--brand-primary);
}

.bs-wizard__answer:has(input:focus-visible) {
	outline: 2px solid var(--brand-primary);
	outline-offset: 2px;
}

.bs-wizard__nav {
	display: flex;
	gap: var(--space-3);
	flex-wrap: wrap;
}

.bs-wizard__outcome {
	border: 1px solid var(--brand-primary);
	border-radius: var(--radius-card);
	padding: var(--space-8);
	margin-bottom: var(--space-8);
	background: var(--surface);
	box-shadow: var(--shadow-3);
}

.bs-wizard__outcome h2 { margin-top: 0; }
.bs-wizard__because { font-size: var(--text-small); color: var(--text-muted); }
.bs-wizard__guidance { padding-left: 1.2em; }
.bs-wizard__guidance li { margin-bottom: var(--space-2); }
.bs-wizard__restart { font-size: var(--text-small); }

/* ===========================================================================
   FORMS
   One column, labels above the field, 48px targets, 16px text so iOS does not
   zoom on focus.
   ======================================================================== */

.bs-field,
.fluentform .ff-el-group {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-bottom: var(--space-5);
}

.bs-field label,
.fluentform .ff-el-input--label label {
	font-size: var(--text-small);
	font-weight: 600;
	color: var(--text-heading);
}

.bs-field input,
.bs-field select,
.bs-field textarea,
.fluentform input[type='text'],
.fluentform input[type='email'],
.fluentform input[type='tel'],
.fluentform select,
.fluentform textarea {
	min-height: 48px;
	width: 100%;
	background: var(--surface);
	border: 1px solid var(--border-control);
	border-radius: var(--radius-input);
	padding: 12px 16px;
	font-family: var(--font-body);
	font-size: 1rem;
	font-weight: 500;
	line-height: var(--leading-body);
	color: var(--text-body-color);
	transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

.bs-field textarea,
.fluentform textarea { min-height: 120px; }

.bs-field input:hover,
.fluentform input:hover,
.fluentform textarea:hover { border-color: var(--border-strong); }

.bs-field input:focus,
.bs-field select:focus,
.bs-field textarea:focus,
.fluentform input:focus,
.fluentform select:focus,
.fluentform textarea:focus {
	border-color: var(--brand-primary);
	box-shadow: 0 0 0 3px rgba(16, 57, 91, 0.15);
	outline: none;   /* replaced by the ring above, not removed */
}

.bs-field [aria-invalid='true'],
.fluentform .ff-el-is-error input {
	border-color: var(--color-error);
}

/* Colour alone is not a message. */
.bs-field__error,
.fluentform .error-text {
	font-size: var(--text-small);
	font-weight: 600;
	color: var(--color-error);
}

.bs-field input:disabled,
.fluentform input:disabled {
	background: var(--surface-muted);
	color: #8A8A8A;
}

.fluentform .ff-btn-submit {
	background: var(--brand-accent);
	color: var(--brand-primary);
	font-family: var(--font-body);
	font-size: var(--text-button);
	font-weight: 600;
	padding: 14px 28px;
	border: none;
	border-radius: var(--radius-button);
}

.fluentform .ff-btn-submit:hover {
	background: var(--brand-accent-hover);
	color: var(--brand-primary);
}

/* ===========================================================================
   MOBILE STICKY CTA
   On a 375px screen the hero pushes the CTA below the fold. Two actions only —
   a three-way choice in a 375px bar does not work.
   ======================================================================== */

.bs-mobile-cta {
	position: fixed;
	inset-inline: 0;
	bottom: 0;
	z-index: 50;
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 1fr;
	gap: var(--space-2);
	padding: 12px 16px;
	padding-bottom: max(12px, env(safe-area-inset-bottom));
	background: var(--brand-primary);
	box-shadow: 0 -4px 16px rgba(16, 57, 91, 0.18);
	transform: translateY(110%);
	transition: transform var(--duration-slow) var(--ease);
}

.bs-mobile-cta.is-visible { transform: translateY(0); }

.bs-mobile-cta .bs-button { width: 100%; }

@media (min-width: 1024px) {
	.bs-mobile-cta { display: none; }
}

/* ===========================================================================
   FOOTER
   ======================================================================== */

.site-footer,
.site-footer .inside-footer-widgets {
	background: var(--surface);
	color: var(--text-body-color);
}

.site-footer .inside-site-info,
.site-footer .copyright-bar {
	text-align: left;
}

.bs-footer-legal {
	font-size: var(--text-small);
	line-height: var(--leading-body);
	color: var(--text-muted);
	max-width: var(--measure);
	margin-inline: auto;
}

.bs-footer-legal p { margin-bottom: var(--space-3); }
.bs-footer-legal p:last-child { margin-bottom: 0; }

.bs-footer-menu {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2) var(--space-5);
	margin: 0 0 var(--space-4);
	padding: 0;
}

/* A list of links is not inline text, so WCAG 2.2's 24px minimum target applies.
   At 14px these measured 18px high; the padding brings them to 32px without
   changing how the row looks. */
.bs-footer-menu a {
	display: inline-flex;
	align-items: center;
	min-height: 32px;
	color: var(--brand-primary);
	font-weight: 600;
	text-decoration: none;
}

.bs-footer-menu a:hover {
	color: var(--brand-accent-text);
	text-decoration: underline;
}

.bs-footer-legal a { color: var(--text-muted); }
.bs-footer-legal a:hover { color: var(--brand-accent-text); }

.bs-company { font-size: var(--text-small); color: var(--text-muted); }
.bs-empty { color: var(--text-muted); font-style: italic; }

/* ===========================================================================
   MOTION
   ======================================================================== */

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

	/* Every transform-based hover is removed, not just shortened. */
	.bs-button:hover,
	.bs-card:hover,
	.bs-news-card:hover,
	.bs-cta__button:hover {
		transform: none;
	}

	.bs-card:hover .bs-card__media img { transform: none; }
	.bs-button--tertiary:hover::after { transform: none; }
}

/* ===========================================================================
   PRINT — regulations pages get printed and taken into meetings
   ======================================================================== */

@media print {
	.site-header,
	.site-footer,
	.bs-cta,
	.bs-wizard__nav,
	.bs-related,
	.bs-mobile-cta,
	.bs-skip-link { display: none; }

	.inside-article { max-width: none; padding: 0; }

	.bs-article .entry-content > *,
	.bs-article .entry-content > .wp-block-table,
	.bs-article .entry-content > .bs-table-wrap {
		max-width: none;
		width: 100%;
		margin-left: 0;
		transform: none;
	}

	.wp-block-details { break-inside: avoid; }
	.wp-block-details[open] summary { margin-bottom: var(--space-2); }

	/* Sources have to survive the printer. */
	a[href^='http']::after {
		content: ' (' attr(href) ')';
		font-size: 0.75em;
		color: #555;
	}
}
