@charset "UTF-8";

/* =========================================================================
   Sapient Store
   Flat, square, hairline-ruled. No radii outside the availability dot, no
   shadows, one tinted surface per band.

   Contents
     1.  Fonts
     2.  Design tokens
     3.  Reset
     4.  Utilities
     5.  Site header
     6.  Site footer
     7.  Product — breadcrumb
     8.  Product — hero grid
     9.  Product — purchase rail
     10. Product — specification and overview
     10a. Product — trust strip
     11. Product — what you get
     11a. Product — sticky action bar
     12. Product — testimonials (WC Testimonials with Proof)
     13. Product — FAQ accordion
     14. Product — ratings and reviews
     15. Product — extra tabs, upsells and related
     16. Certification listing
     16a. Search results
     17. Prose fallback templates
     18. Not found
     19. Home
     20. Live search
     21. Standing pages (About, Contact, FAQ, legal)
     22. Blog
   ========================================================================= */


/* 1. Fonts ---------------------------------------------------------------
   Geist and Geist Mono, self-hosted as the Latin and Latin-Extended slices
   Google Fonts serves. Both files are variable, so one face per family and
   subset covers every weight the page asks for.

   The weight descriptor has to be the axis range, not a single value. Four
   faces at 400/500/600/700 all pointing at the same variable file look
   equivalent and are not: the browser stops instancing the axis and 500 and 600
   come back identical. One face declared 100-900 renders the true weight at
   every step.
   ------------------------------------------------------------------------ */

@font-face {
	font-family: "Geist";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/geist-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Geist";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/geist-latin-ext.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: "Geist Mono";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/geist-mono-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Geist Mono";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/geist-mono-latin-ext.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* 2. Design tokens -------------------------------------------------------
   Geist scales. Step semantics follow the Geist colour docs: 100-300 component
   backgrounds, 400-600 borders, 700-800 high-contrast backgrounds, 900
   secondary text / solid fills, 1000 primary text. Every step is inside the
   sRGB gamut.
   ------------------------------------------------------------------------ */

:root {
	--ds-background-100: oklch(1 0 0);
	--ds-background-200: oklch(0.985 0.002 265);

	--ds-gray-100: oklch(0.98 0.003 265);
	--ds-gray-200: oklch(0.967 0.004 265);
	--ds-gray-300: oklch(0.95 0.005 265);
	--ds-gray-400: oklch(0.8806 0.0081 253.9);
	--ds-gray-500: oklch(0.845 0.009 258);
	--ds-gray-600: oklch(0.795 0.011 260);
	--ds-gray-700: oklch(0.7 0.015 263);
	--ds-gray-800: oklch(0.585 0.019 265);
	--ds-gray-900: oklch(0.4495 0.0206 267.6);
	--ds-gray-1000: oklch(0.1596 0.0203 265.6);

	--ds-blue-100: oklch(0.975 0.012 250);
	--ds-blue-200: oklch(0.9504 0.02 250.4);
	--ds-blue-300: oklch(0.915 0.036 253);
	--ds-blue-400: oklch(0.865 0.06 256);
	--ds-blue-500: oklch(0.79 0.105 260);
	--ds-blue-600: oklch(0.7 0.145 263);
	--ds-blue-700: oklch(0.57 0.215 265);
	--ds-blue-800: oklch(0.44 0.235 266.5);
	--ds-blue-900: oklch(0.3386 0.2276 267.2);
	--ds-blue-1000: oklch(0.27 0.175 268);

	--ds-amber-100: oklch(0.975 0.021 80);
	--ds-amber-200: oklch(0.955 0.037 78);
	--ds-amber-900: oklch(0.7201 0.1678 60.7);
	--ds-amber-1000: oklch(0.56 0.14 52);

	--ds-amber-300: oklch(0.92 0.075 80);
	--ds-amber-700: oklch(0.8 0.155 72);
	--ds-amber-ink: oklch(0.47 0.115 55);

	/* Three more hues, on the same step semantics as the scales above. They are
	   identity, not decoration: each certification is drawn in one, and the
	   homepage's lit cells and plan phases use the same five. */
	--ds-purple-200: oklch(0.945 0.03 305);
	--ds-purple-300: oklch(0.9 0.06 305);
	--ds-purple-700: oklch(0.6 0.19 300);
	--ds-purple-900: oklch(0.44 0.16 300);

	--ds-teal-200: oklch(0.95 0.04 185);
	--ds-teal-300: oklch(0.9 0.075 185);
	--ds-teal-700: oklch(0.68 0.12 185);
	--ds-teal-900: oklch(0.44 0.08 190);

	--ds-pink-200: oklch(0.945 0.03 355);
	--ds-pink-300: oklch(0.9 0.065 355);
	--ds-pink-700: oklch(0.65 0.2 355);
	--ds-pink-900: oklch(0.47 0.16 355);

	--ds-green-100: oklch(0.97 0.03 155);
	--ds-green-900: oklch(0.5024 0.1273 153.8);
	--ds-green-1000: oklch(0.4 0.095 154);

	/* Semantic tokens resolved against the scale above. */
	--background: var(--ds-background-100);
	--foreground: var(--ds-gray-1000);
	--muted-foreground: var(--ds-gray-900);
	--brand: var(--ds-blue-900);
	--brand-foreground: oklch(1 0 0);
	/* WhatsApp's own green, not the theme's — the point of the button is that
	   it is recognised before it is read, and an approximation is not the mark.
	   The label on it is dark rather than white: white on #25d366 measures
	   1.98:1, which is unreadable, and the same green under near-black measures
	   10.6:1. The green is exact either way; only the text moved. */
	--whatsapp: #25d366;
	--whatsapp-hover: #1ebe5b;
	--whatsapp-foreground: var(--ds-gray-1000);
	--success: var(--ds-green-900);
	--warning: var(--ds-amber-900);
	--border: var(--ds-gray-400);
	--ring: var(--ds-blue-900);

	/* The footer is the one dark surface in the theme, so it carries its own
	   small palette rather than inverting the semantic tokens page-wide. */
	/* The homepage hero's night surface and the one warm note it carries. */
	/* The brand hue taken darker and calmer than any button: deep enough that
	   the lit cells and the warm accent sit on it at full strength. */
	--night-surface: oklch(0.235 0.095 267);
	--night-foreground: oklch(1 0 0);
	--night-muted: oklch(0.85 0.04 268);
	--night-rule: oklch(1 0 0 / 0.08);
	--highlight: oklch(0.88 0.15 90);

	--footer-surface: var(--ds-gray-1000);
	--footer-foreground: oklch(1 0 0);
	--footer-muted: oklch(0.74 0.015 265);
	--footer-rule: oklch(0.3 0.02 265);

	--font-sans: "Geist", ui-sans-serif, system-ui, sans-serif;
	--font-mono: "Geist Mono", ui-monospace, SFMono-Regular, monospace;

	/* Native checkboxes and radios in the review form. */
	accent-color: var(--brand);

	/* Page shell. */
	--shell-max: 1600px;
	--shell-pad: 1.5rem;

	/* Lets the FAQ panel transition to its natural height. */
	interpolate-size: allow-keywords;
}

@media (min-width: 1024px) {
	:root {
		--shell-pad: 2.5rem;
	}
}


/* 3. Reset ---------------------------------------------------------------- */

*,
*::before,
*::after {
	box-sizing: border-box;
	border: 0 solid var(--border);
	margin: 0;
	padding: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	tab-size: 4;
	line-height: 1.5;
}

body {
	min-height: 100vh;
	background-color: var(--background);
	color: var(--foreground);
	font-family: var(--font-sans);
	font-size: 1rem;
	-webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
h5,
h6 {
	font-size: inherit;
	font-weight: inherit;
}

a {
	color: inherit;
	text-decoration: inherit;
}

b,
strong {
	font-weight: bolder;
}

code,
kbd,
samp,
pre {
	font-family: var(--font-mono);
	font-size: 1em;
}

table {
	text-indent: 0;
	border-color: inherit;
	border-collapse: collapse;
}

ol,
ul,
menu {
	list-style: none;
}

img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
	vertical-align: middle;
	display: block;
}

img,
video {
	max-width: 100%;
	height: auto;
}

button,
input,
select,
optgroup,
textarea {
	font: inherit;
	letter-spacing: inherit;
	color: inherit;
	opacity: 1;
	background-color: transparent;
	border-radius: 0;
}

button,
input:where([type="button"], [type="reset"], [type="submit"]) {
	appearance: button;
}

summary {
	display: list-item;
}

[hidden]:where(:not([hidden="until-found"])) {
	display: none !important;
}

/* WooCommerce marks the fixed quantity field with this class. */
.hidden {
	display: none;
}

/*
 * WooCommerce wraps the quantity input in a div even when the input is hidden,
 * and an empty block still claims a slot in the gapped CTA column. The rail
 * fixes quantity at one, so the wrapper never has anything to show.
 */
.rail form.cart .quantity {
	display: none;
}


/* 4. Utilities ------------------------------------------------------------ */

.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* The one focus treatment used across the theme. */
:where(a, button, summary, input, select, textarea):focus-visible {
	outline: 2px solid var(--ring);
	outline-offset: 2px;
}

.shell {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
}

.section-label {
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--muted-foreground);
}


/* 5. Site header ---------------------------------------------------------- */

/* A skip link, because the header is sticky and every page begins behind it. */
.skip-link:focus {
	position: fixed;
	top: 0.5rem;
	left: 0.5rem;
	z-index: 100;
	width: auto;
	height: auto;
	clip-path: none;
	background-color: var(--brand);
	color: var(--brand-foreground);
	padding-inline: 1rem;
	padding-block: 0.75rem;
	font-size: 0.875rem;
	font-weight: 600;
}

/* Tinted, not white. Against a white hero a white bar is only its hairline, and
   a sticky element that reads as part of the page it is floating over is the
   wrong way round. Still translucent, so content passing under it is visible as
   texture rather than hidden. */
.site-header {
	position: sticky;
	top: 0;
	z-index: 20;
	border-bottom-width: 1px;
	background-color: color-mix(in oklab, var(--ds-gray-200) 92%, transparent);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
}

/* The search sits on the header's own tint, so it needs to be lighter than its
   surroundings rather than darker — the field is the thing you can type into. */
.site-header .site-search__field {
	background-color: var(--background);
}

/* Two rows on a phone — wordmark and action, then the search across the full
   width — and one row from 48em. The search is the flexible item either way, so
   it takes whatever the wordmark, the menu and the button leave. */
.site-header__inner {
	display: grid;
	grid-template-columns: 1fr auto auto;
	align-items: center;
	column-gap: 0.75rem;
	row-gap: 0.625rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 0.75rem;
}

/* Placed, not auto-flowed. The search spans both columns, so left to place
   itself the button dropped past it onto a third row and stretched across the
   1fr track — a three-row header with a full-width button in it. */
.site-header__inner > .site-wordmark {
	grid-row: 1;
	grid-column: 1;
}

.site-header__inner > .site-cta,
.site-header__inner > .site-ctas {
	grid-row: 1;
	grid-column: 3;
	justify-self: end;
}

/* WhatsApp and text, as one pair in the action slot. */
.site-ctas {
	display: flex;
	gap: 0.5rem;
}

.site-wordmark {
	display: flex;
	align-items: center;
	gap: 0.5em;
	font-size: 1.0625rem;
	line-height: 1.2;
	letter-spacing: -0.02em;
	white-space: nowrap;
}

/* Sized so the name's capitals are the height of the grid inside the square,
   as in assets/brand/logo.svg. */
.site-wordmark__mark {
	flex: none;
	width: 1.5em;
	height: 1.5em;
}

.site-wordmark__name {
	display: flex;
	align-items: baseline;
	gap: 0.3125rem;
}

/* The first word carries the weight, the rest sits back from it. For a name of
   three words that is the difference between a mark and a sentence. */
.site-wordmark__lead {
	font-weight: 700;
	color: var(--foreground);
}

.site-wordmark__rest {
	font-weight: 500;
	color: var(--muted-foreground);
}

/* One joined word ("SystemExam"): no gap, same weight, and the second half in
   the brand colour — the weight step would read as two words. */
.site-wordmark--joined .site-wordmark__name {
	gap: 0;
}

.site-wordmark--joined .site-wordmark__rest {
	font-weight: 700;
	color: var(--brand);
}

/* The brand mark: the E-tick. Flat, square ends, no radius. */
.brand-mark__square {
	fill: var(--brand);
}

.brand-mark__letter {
	fill: oklch(1 0 0);
}

.brand-mark__tick {
	fill: none;
	stroke: var(--highlight);
	stroke-width: 5.75;
	stroke-linecap: square;
	stroke-linejoin: miter;
}

.site-wordmark--logo img {
	display: block;
	height: 2rem;
	width: auto;
}

/* The search. A field, an icon inside it, and no button: the form submits on
   Enter, and a magnifying glass that is a button as well as a label is two
   controls in the space of one. */
.site-search {
	grid-row: 2;
	grid-column: 1 / -1;
	position: relative;
	display: flex;
	align-items: center;
	min-width: 0;
}

.site-search__icon {
	position: absolute;
	left: 0.75rem;
	width: 1rem;
	height: 1rem;
	color: var(--muted-foreground);
	pointer-events: none;
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-search__field {
	width: 100%;
	min-width: 0;
	height: 2.5rem;
	padding-left: 2.375rem;
	padding-right: 0.875rem;
	font-size: 1rem; /* the floor that stops iOS zooming the page on focus */
	line-height: 1.4;
	background-color: var(--ds-gray-100);
	border-width: 1px;
	border-color: var(--border);
	color: var(--foreground);
	transition: border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-search__field::placeholder {
	color: var(--muted-foreground);
}

.site-search__field:hover {
	border-color: var(--ds-gray-500);
}

.site-search__field:focus {
	background-color: var(--background);
	border-color: var(--brand);
}

.site-search:focus-within .site-search__icon {
	color: var(--brand);
}

/* The search field clears itself in WebKit with a control that is not this
   theme's; the field is cleared by selecting it, as everywhere else. */
.site-search__field::-webkit-search-decoration,
.site-search__field::-webkit-search-cancel-button {
	-webkit-appearance: none;
}

.site-nav {
	display: none;
	grid-row: 3;
	grid-column: 1 / -1;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	font-weight: 500;
	color: var(--muted-foreground);
}

.site-nav.is-open {
	display: block;
}

.site-nav__list {
	display: flex;
	flex-direction: column;
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-nav li {
	list-style: none;
}

.site-nav a {
	display: block;
	padding-block: 0.75rem;
	border-top-width: 1px;
	border-color: var(--border);
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-nav a:hover,
.site-nav .current-menu-item > a {
	color: var(--foreground);
}

.site-nav-toggle {
	grid-row: 1;
	grid-column: 2;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	height: 2.5rem;
	padding-inline: 0.75rem;
	border-width: 1px;
	border-color: var(--border);
	background-color: var(--background);
	font-size: 0.8125rem;
	font-weight: 600;
	cursor: pointer;
}

.site-nav-toggle:hover {
	border-color: var(--ds-gray-500);
}

.site-nav-toggle__icon {
	display: flex;
	flex-direction: column;
	gap: 0.1875rem;
	width: 1rem;
}

.site-nav-toggle__icon span {
	display: block;
	height: 1px;
	background-color: currentColor;
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-nav-toggle[aria-expanded="true"] .site-nav-toggle__icon span:first-child {
	transform: translateY(4px) rotate(45deg);
}

.site-nav-toggle[aria-expanded="true"] .site-nav-toggle__icon span:nth-child(2) {
	opacity: 0;
}

.site-nav-toggle[aria-expanded="true"] .site-nav-toggle__icon span:last-child {
	transform: translateY(-4px) rotate(-45deg);
}

/* .btn is width:100% and is declared further down this file, so a bare
   .site-cta would tie on specificity and lose on order — which stretched the
   button across the whole header bar. Both classes settles it. */
.btn.site-cta {
	width: auto;
	height: 2.5rem;
	padding-inline: 0.625rem;
	font-size: 0.8125rem;
}

/* The narrowest phones: wordmark, menu and two message buttons are one row too
   many, so the menu keeps its icon and its name moves to assistive tech only. */
@media (max-width: 23.99em) {
	.site-nav-toggle {
		padding-inline: 0.75rem;
	}

	.site-nav-toggle__label {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}
}

/* The label goes before the button does: the mark alone still says WhatsApp,
   and on a phone the row has a wordmark to fit beside it. */
.site-cta__label {
	display: none;
}

@media (min-width: 36em) {
	.site-cta__label {
		display: inline;
	}

	.btn.site-cta {
		padding-inline: 1rem;
	}
}

@media (min-width: 64em) {
	.site-header__inner {
		display: flex;
		gap: 1.5rem;
		height: 4.5rem;
		padding-block: 0;
	}

	.site-search {
		flex: 1 1 auto;
		max-width: 26rem;
	}

	.site-nav {
		display: flex;
		align-items: center;
		gap: 1.5rem;
	}

	.site-nav__list {
		display: contents;
	}

	.site-nav a {
		display: inline;
		padding-block: 0;
		border-top-width: 0;
	}

	.site-nav-toggle {
		display: none;
	}

	.site-header__inner > .site-cta,
	.site-header__inner > .site-ctas {
		margin-left: auto;
	}
}


/* 6. Site footer ---------------------------------------------------------- */

/* The one dark surface in the theme, and the reason is separation: a light grey
   footer under a light grey band under a white page is three shades of the same
   thing and the page never lands. Dark ends it, and it puts the trademark line —
   which every page of a site named after somebody else's mark has to carry — on
   a footing that reads as the site's own rather than as an afterthought. */
.site-footer {
	background-color: var(--footer-surface);
	color: var(--footer-muted);
}

.site-footer__inner {
	display: grid;
	gap: 2.5rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 3rem;
}

.site-footer__brand .site-wordmark {
	font-size: 1.125rem;
}

.site-footer .site-wordmark__lead {
	color: var(--footer-foreground);
}

.site-footer .site-wordmark__rest {
	color: var(--footer-muted);
}

/* Brand indigo is too dark to read on the footer; the tick's yellow carries
   the second half there instead, as in logo-reverse.svg. */
.site-footer .site-wordmark--joined .site-wordmark__rest {
	color: var(--highlight);
}

.site-footer__blurb {
	margin-top: 0.75rem;
	max-width: 24rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--footer-muted);
}

.site-footer__heading {
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--footer-muted);
}

.site-footer__list {
	display: grid;
	gap: 0.625rem;
	margin: 0.875rem 0 0;
	padding: 0;
	list-style: none;
}

.site-footer__list li {
	list-style: none;
}

.site-footer__list a {
	font-size: 0.875rem;
	line-height: 1.4;
	color: color-mix(in oklab, var(--footer-foreground) 88%, transparent);
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-footer__list a:hover {
	color: var(--footer-foreground);
}

/* Exam codes are set in mono everywhere else on the site. */
.site-footer__list li:not(:last-child) a {
	font-family: var(--font-mono);
	font-size: 0.8125rem;
}

/* Navy is unreadable here; on the dark surface the emphasis is weight and full
   white, which is the same distinction the accent makes on a light one. */
.site-footer__all {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	font-weight: 600;
	color: var(--footer-foreground);
}

.site-footer__arrow {
	width: 0.875rem;
	height: 0.875rem;
	flex: none;
}

.site-footer__note {
	margin-top: 0.875rem;
	max-width: 24rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--footer-muted);
}

/* The outlined button, restated for the dark surface it now sits on. */
.site-footer .btn--secondary {
	border-color: color-mix(in oklab, var(--footer-foreground) 40%, transparent);
	color: var(--footer-foreground);
}

.site-footer .btn--secondary:hover {
	background-color: color-mix(in oklab, var(--footer-foreground) 12%, transparent);
	border-color: var(--footer-foreground);
}

.site-footer__channels {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 1.25rem;
}

.btn.site-footer__wa {
	width: auto;
	height: 2.75rem;
	padding-inline: 1.25rem;
}

.site-footer__number {
	margin-top: 0.75rem;
	font-size: 0.875rem;
	color: var(--footer-muted);
}

.site-footer__number a {
	color: var(--footer-foreground);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/* The legal line, on its own rule. It is the last thing on every page of a site
   whose name leans on a mark it does not own, so it is not a footnote inside a
   column — it spans the page. */
.site-footer__legal {
	border-top-width: 1px;
	border-color: var(--footer-rule);
}

.site-footer__legal-inner {
	display: flex;
	flex-wrap: wrap;
	gap: 0.375rem 1.5rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 1.5rem;
	font-size: 0.75rem;
	line-height: 1.6;
	color: var(--footer-muted);
}

.site-footer__copy {
	font-weight: 500;
	color: var(--footer-foreground);
}

.site-footer__trademark {
	max-width: 56rem;
}

@media (min-width: 48em) {
	.site-footer__inner {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 3rem;
		padding-block: 4rem;
	}
}

@media (min-width: 64em) {
	.site-footer__inner {
		grid-template-columns: 1.5fr 1fr 1fr;
	}

	.site-footer__brand {
		grid-column: 1;
	}
}


/* 7. Product — breadcrumb ------------------------------------------------- */

.woocommerce-breadcrumb {
	border-bottom-width: 1px;
}

.breadcrumb {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 0.875rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	color: var(--muted-foreground);
}

.breadcrumb a {
	text-decoration: underline;
	text-underline-offset: 4px;
}

.breadcrumb a:hover {
	text-decoration: none;
}

.breadcrumb__current {
	color: var(--foreground);
}


/* 8. Product — hero grid --------------------------------------------------- */

/* One explicit track on a phone. Left implicit, the column sized itself to its
   widest content — about 404px — and every narrower screen scrolled sideways. */
.product-hero__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	max-width: var(--shell-max);
	margin-inline: auto;
}

.product-identity {
	padding-inline: var(--shell-pad);
	padding-top: 2.5rem;
}

.product-code {
	font-family: var(--font-mono);
	font-size: 0.75rem;
	line-height: calc(1 / 0.75);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--brand);
}

.product-code span {
	background-color: var(--ds-blue-200);
	padding-inline: 0.75rem;
	padding-block: 0.375rem;
}

.product_title {
	margin-top: 1.25rem;
	max-width: 48rem;
	font-size: 2rem;
	font-weight: 700;
	line-height: 1.06;
	letter-spacing: -0.03em;
}

/* Prints only once the product has been rated; the link is WooCommerce's own
   and already points at the reviews band further down the page. */
.woocommerce-product-rating {
	margin-top: 1rem;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.625rem;
}

.woocommerce-review-link {
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	color: var(--muted-foreground);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.woocommerce-review-link:hover {
	color: var(--foreground);
}

/* The strapline is the short description when the product has one, and
   WooCommerce wraps that in its own element. Both read as the same line. */
.product-strapline,
.woocommerce-product-details__short-description {
	margin-top: 1rem;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

/* The strapline, drawn. Each point wears the card's own icon in the card's own
   tinted square, a size down, so the link to "What you get" is visible before
   it is clicked. Plain text beside it and no border: it sits under the title
   and above the proof link, and must stay quieter than both. */
.product-promises {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	margin-top: 1.25rem;
}

.product-promise {
	display: inline-flex;
	align-items: center;
	gap: 0.625rem;
	font-size: 0.9375rem;
	line-height: 1.4;
	font-weight: 500;
	color: var(--foreground);
	text-decoration: none;
}

.product-promise__icon {
	width: 1.75rem;
	height: 1.75rem;
	padding: 0.3125rem;
	flex: none;
	background-color: var(--ds-blue-200);
	color: var(--brand);
}

.product-promise__short {
	display: none;
}

/* One quiet line on a phone. The full labels need ~370px even without icons and
   a small phone has ~310, so the phone gets short wording instead of wrapping,
   and the icons lose their squares: at this size three tinted tiles read as
   noise. The full label stays readable to screen readers. */
@media (max-width: 47.99em) {
	.product-promises {
		flex-wrap: nowrap;
		gap: 1.125rem;
		margin-top: 1rem;
	}

	.product-promise {
		gap: 0.375rem;
		font-size: 0.875rem;
		white-space: nowrap;
	}

	.product-promise__icon {
		width: 1rem;
		height: 1rem;
		padding: 0;
		background-color: transparent;
	}

	.product-promise__label {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.product-promise__short {
		display: inline;
	}

	a.product-promise:hover .product-promise__short {
		text-decoration: underline;
		text-underline-offset: 0.2em;
	}
}

a.product-promise:hover .product-promise__label {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

a.product-promise:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}

.woocommerce-product-details__short-description p + p {
	margin-top: 0.75rem;
}

.woocommerce-product-details__short-description a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.product-rail {
	margin-top: 2rem;
	border-top-width: 1px;
	background-color: var(--ds-blue-200);
	padding-inline: var(--shell-pad);
	padding-block: 2rem;
}

.product-evidence {
	padding-inline: var(--shell-pad);
	padding-top: 2rem;
	padding-bottom: 2.5rem;
}

@media (min-width: 640px) {
	.product_title {
		font-size: 2.25rem;
	}
}

@media (min-width: 1024px) {
	/*
	 * grid-rows auto/1fr: the rail spans both rows and is usually the tallest
	 * child. Without this, its surplus height is shared between the rows and
	 * opens a gap under the title, pushing the specification table off short
	 * viewports.
	 */
	.product-hero__grid {
		grid-template-columns: minmax(0, 1fr) clamp(22rem, 30vw, 30rem);
		grid-template-rows: auto 1fr;
	}

	.product-identity {
		grid-column-start: 1;
		grid-row-start: 1;
		padding-right: 4rem;
		padding-top: 3rem;
	}

	.product-rail {
		grid-column-start: 2;
		grid-row: 1 / span 2;
		margin-top: 0;
		border-top-width: 0;
		border-left-width: 1px;
		padding-block: 3rem;
	}

	.product-rail__sticky {
		position: sticky;
		top: 6rem;
	}

	.product-evidence {
		grid-column-start: 1;
		grid-row-start: 2;
		padding-right: 4rem;
		padding-top: 1.75rem;
		padding-bottom: 3rem;
	}
}

@media (min-width: 1280px) {
	.product_title {
		font-size: 3rem;
	}

	.product-strapline,
	.woocommerce-product-details__short-description {
		font-size: 1.125rem;
		line-height: calc(1.75 / 1.125);
	}
}

@media (min-width: 1536px) {
	.product_title {
		font-size: 3.25rem;
	}
}


/* 9. Product — purchase rail ---------------------------------------------- */

.rail {
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
}

.rail__badge {
	display: inline-flex;
	align-items: center;
	background-color: var(--brand);
	padding-inline: 0.75rem;
	padding-block: 0.375rem;
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--brand-foreground);
}

.rail .price {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.75rem;
}

.rail .woocommerce-Price-amount {
	font-size: 3rem;
	line-height: 1;
	font-weight: 700;
	letter-spacing: -0.03em;
	color: var(--foreground);
}

.rail del {
	font-size: 1.125rem;
	line-height: calc(1.75 / 1.125);
	color: var(--muted-foreground);
	text-decoration: line-through;
}

.rail del .woocommerce-Price-amount {
	font-size: inherit;
	line-height: inherit;
	font-weight: inherit;
	letter-spacing: inherit;
	color: inherit;
}

.rail__terms {
	margin-top: 0.75rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	color: var(--muted-foreground);
}

.rail__stock {
	margin-top: 0.75rem;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	font-weight: 500;
	color: var(--ds-green-1000);
}

.rail__stock--out {
	color: var(--muted-foreground);
}

.rail__dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 9999px;
	background-color: var(--success);
	flex: none;
}

.rail__stock--out .rail__dot {
	background-color: var(--ds-gray-700);
}

.rail form.cart {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}

/* #submit is the review form's button. It joins the button rules rather than
   restating them, so there is one set of button dimensions in the theme. */
.btn,
#review_form #submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 3.25rem;
	width: 100%;
	padding-inline: 1.5rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	font-weight: 600;
	cursor: pointer;
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.btn--primary,
#review_form #submit {
	background-color: var(--brand);
	color: var(--brand-foreground);
}

.btn--primary:hover,
#review_form #submit:hover {
	background-color: var(--ds-blue-1000);
}

.btn--secondary {
	border-width: 1px;
	border-color: var(--brand);
	background-color: transparent;
	color: var(--brand);
}

.btn--secondary:hover {
	background-color: var(--ds-blue-300);
}

/* The one green control on the page. It hands the visitor to someone else's
   product, and that is recognised by colour before the label is read — so it
   gets its own, and nothing else does, or the colour would stop meaning it. */
.btn--whatsapp {
	background-color: var(--whatsapp);
	color: var(--whatsapp-foreground);
}

.btn--whatsapp:hover {
	background-color: var(--whatsapp-hover);
}

.rail__sample {
	margin-top: 0.25rem;
	text-align: center;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	font-weight: 500;
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.rail__sample:hover {
	text-decoration: none;
}

/* Enquiry mode. The rail asks for a conversation instead of a purchase, so the
   price block is gone and this stands where the cart form stood. It stays in
   the theme's one accent rather than borrowing WhatsApp's green: the rail is
   already the only place on the page asking to be acted on, and a second brand
   colour would be competing with itself. */
.enquiry__title {
	font-size: 1.125rem;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.enquiry__lede {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.enquiry__error {
	margin-top: 0.875rem;
	border-left-width: 2px;
	border-color: var(--warning);
	padding-left: 0.75rem;
	font-size: 0.875rem;
	line-height: 1.5;
}

.enquiry__unset {
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.enquiry__form {
	margin-top: 1.25rem;
	/* Restated against the rail's tint; grey borders disappear into blue. */
	--field-border: var(--ds-blue-400);
	--field-border-hover: var(--ds-blue-600);
}

.field + .field {
	margin-top: 0.875rem;
}

/* The exam is stated, not asked for. Mono because that is how every exam code
   on this page is set, and tinted so it does not look like an empty field
   someone forgot to fill. The attribute is repeated in the selector to outweigh
   the shared field rule, which sits later in this file. */
.enquiry__form input[type="text"][readonly] {
	background-color: var(--ds-blue-100);
	font-family: var(--font-mono);
	color: var(--muted-foreground);
}

.enquiry__form .btn,
.enquiry--sent .btn {
	margin-top: 1.25rem;
}

.enquiry__or {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	margin-top: 1rem;
	font-size: 0.6875rem; /* 11px, the field-label size */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
}

.enquiry__or::before,
.enquiry__or::after {
	content: "";
	flex: 1;
	border-top-width: 1px;
	border-color: var(--ds-blue-400);
}

/* WhatsApp and text, side by side in equal halves. Closer to the rule they
   belong under than to the button above it. */
.enquiry__channels {
	display: grid;
	grid-auto-columns: minmax(0, 1fr);
	grid-auto-flow: column;
	gap: 0.5rem;
	margin-top: 0.75rem;
}

.btn--icon {
	gap: 0.5rem;
}

.btn__icon {
	width: 1.125rem;
	height: 1.125rem;
	flex: none;
}

.enquiry__note {
	margin-top: 0.625rem;
	text-align: center;
	font-size: 0.75rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

/* Bait. Hidden from sighted visitors by the clip, from assistive technology by
   aria-hidden on the wrapper, and from the tab order by tabindex. */
.enquiry__trap {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* WooCommerce writes the add-to-cart confirmation here on the redirect back. */
.rail .woocommerce-notices-wrapper:empty {
	display: none;
}

.rail .woocommerce-message,
.rail .woocommerce-info,
.rail .woocommerce-error {
	border-width: 1px;
	border-color: color-mix(in oklab, var(--brand) 25%, transparent);
	background-color: var(--background);
	padding-inline: 1rem;
	padding-block: 0.75rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
	color: var(--foreground);
}

.rail .woocommerce-error {
	border-color: color-mix(in oklab, var(--ds-amber-1000) 35%, transparent);
}

.rail .woocommerce-message li + li,
.rail .woocommerce-info li + li,
.rail .woocommerce-error li + li {
	margin-top: 0.5rem;
}

.rail .woocommerce-message .button {
	float: right;
	margin-left: 1rem;
	font-weight: 500;
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.rail .woocommerce-message .button:hover {
	text-decoration: none;
}

.rail__meta {
	border-top-width: 1px;
	border-color: var(--ds-blue-300);
	padding-top: 1.25rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
}

.rail__meta-row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	padding-block: 0.375rem;
}

.rail__meta dt {
	color: var(--muted-foreground);
}

.rail__meta dd {
	text-align: right;
	font-weight: 500;
	color: var(--foreground);
}

.affiliation {
	border-left-width: 4px;
	border-color: var(--warning);
	background-color: var(--background);
	padding-inline: 1.25rem;
	padding-block: 1rem;
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
}

.affiliation__title {
	font-weight: 600;
	color: var(--foreground);
}

.affiliation__body {
	margin-top: 0.375rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}


/* 10. Product — specification and overview -------------------------------- */

.product-section {
	scroll-margin-top: 5rem;
}

.product-section--attributes,
.product-section--overview {
	margin-top: 2.5rem;
}

/* The specification is the purchase decision on this page — how many questions,
   how long, what the pass mark is — so it is weighted as data, not as fine
   print. The emphasis is deliberately colourless: one heavy top rule to anchor
   the block, larger values, and more air. Colour stays with the rail, which is
   the only thing on the page asking to be clicked. */
.shop_attributes {
	margin-top: 1rem;
	width: 100%;
	border-left-width: 1px;
	border-top-width: 2px;
	border-top-color: var(--foreground);
	font-size: 0.875rem;
	line-height: calc(1.25 / 0.875);
}

.shop_attributes tbody {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.woocommerce-product-attributes-item {
	display: flex;
	flex-direction: column;
	border-bottom-width: 1px;
	border-right-width: 1px;
	padding-inline: 1rem;
	padding-block: 1.25rem;
}

.woocommerce-product-attributes-item__label {
	text-align: left;
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	line-height: 1.25;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
}

.woocommerce-product-attributes-item__value {
	margin-top: 0.5rem;
	font-size: 1rem;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: -0.01em;
	/* Figures on a grid: the column reads as a set of numbers to compare. */
	font-variant-numeric: tabular-nums;
	color: var(--foreground);
}

/* The overview is the product description when one is written, so it holds
   whatever the block editor produced and not only a paragraph. */
.product-overview {
	margin-top: 1rem;
	max-width: 42rem;
	font-size: 1.125rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.product-overview > * + * {
	margin-top: 1rem;
}

.product-overview h2,
.product-overview h3,
.product-overview h4 {
	margin-top: 2rem;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

.product-overview h2 {
	font-size: 1.375rem;
	line-height: 1.3;
}

.product-overview h3,
.product-overview h4 {
	font-size: 1.125rem;
	line-height: 1.4;
}

.product-overview ul,
.product-overview ol {
	padding-left: 1.25rem;
}

.product-overview ul {
	list-style: disc;
}

.product-overview ol {
	list-style: decimal;
}

.product-overview li + li {
	margin-top: 0.375rem;
}

.product-overview a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.product-overview strong {
	font-weight: 600;
	color: var(--foreground);
}

.product-overview blockquote {
	border-left-width: 2px;
	border-color: var(--ds-gray-500);
	padding-left: 1.25rem;
}

.product-overview code {
	background-color: var(--ds-gray-200);
	padding-inline: 0.375em;
	padding-block: 0.125em;
	font-size: 0.9375em;
}

.product-overview pre {
	overflow-x: auto;
	background-color: var(--ds-gray-200);
	padding: 1rem;
	font-size: 0.875rem;
	line-height: 1.5;
}

.product-overview pre code {
	background-color: transparent;
	padding: 0;
}

.product-overview table {
	width: 100%;
	border-top-width: 1px;
	border-left-width: 1px;
	font-size: 0.875rem;
}

.product-overview th,
.product-overview td {
	border-bottom-width: 1px;
	border-right-width: 1px;
	padding-inline: 0.75rem;
	padding-block: 0.5rem;
	text-align: left;
}

.product-overview hr {
	border-top-width: 1px;
}

/* Four across on desktop, two on a phone: four specification rows tile evenly
   both ways, and one band of four reads as a spec strip rather than as a second
   grid competing with the cards below. A four-up cell still holds the longest
   label and the longest value — "Assessment type" and the dated exam code —
   each on one line. Keep sapient_exam_specs() at four rows, or a multiple of
   four, or this grid comes out ragged. */
@media (min-width: 1280px) {
	.shop_attributes tbody {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	.woocommerce-product-attributes-item {
		padding-inline: 1.25rem;
	}

	.woocommerce-product-attributes-item__value {
		font-size: 1.125rem;
	}
}


/* 10a. Product — trust strip ------------------------------------------------
   The reference site's badge band, in this theme's terms. Theirs is seven dark
   tiles with orange icons under a headline, and it is one of four trust devices
   stacked on that page — a star rating, two service rows inside the spec table,
   four tinted chips, then the band. Volume is doing the work there.

   One device here, and a ribbon rather than tiles: the "What you get" cards
   directly below are this page's card device, and a second grid at this point
   would be two of them arguing. A hairline above marks it off from the hero;
   nothing below, because the tint change into the next band is the boundary and
   a rule there would be saying it twice.
   ------------------------------------------------------------------------ */

.trust-strip {
	border-top-width: 1px;
}

/* Items at their own width, packed to the left margin the rest of the page
   uses — not equal tracks. Under equal tracks three short labels each sat at the
   left of a 422px column with 240px of nothing after them, and the strip read
   as three stranded phrases rather than one line of assurances. Packed, the
   whitespace ends up outside the group instead of inside every item, and the
   row starts on the same left edge as the H1 above and the band title below. */
.trust-strip__inner {
	display: flex;
	flex-direction: column;
	gap: 0.625rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 1.125rem;
}

.trust-point {
	display: flex;
	align-items: center;
	gap: 0.625rem;
	font-size: 0.875rem;
	line-height: 1.4;
	color: var(--foreground);
}

/* The accent, at the size of the word beside it. This is the quietest place the
   brand colour appears on the page, which is the point: the strip is meant to
   be read and believed, not looked at. */
.trust-point__icon {
	width: 1.125rem;
	height: 1.125rem;
	flex: none;
	color: var(--brand);
}

/* Inside the listing hero, where the block already holds the measure and the
   side padding. It sits under the lede and fills the half of that block the lede
   does not reach, so it takes no rule and no shell padding of its own — it is
   part of the hero, not a band beneath it. */
.trust-strip__inner--inline {
	max-width: none;
	margin-inline: 0;
	padding-inline: 0;
	padding-block: 0;
	margin-top: 1.75rem;
}

/* One per line on a phone — short assurances read as a checklist there, and
   forcing columns would wrap every one of them onto three lines. One line from
   48em, wrapping when it has to, with no flex-grow on the items: that is what
   turned a wrapped last one into a full-width bar and stretched every item into
   a track it could not fill. */
@media (min-width: 48em) {
	.trust-strip__inner {
		flex-direction: row;
		flex-wrap: wrap;
		gap: 0.75rem 2.5rem;
	}
}


/* 11. Product — what you get ----------------------------------------------
   Tinted band. The tone change is the section boundary, so no rule sits here,
   and the cards can drop their borders and read as white objects on a field
   instead of as another grid.
   ------------------------------------------------------------------------ */

.product-included {
	background-color: var(--ds-gray-200);
}

.band {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 4rem;
}

.band__title {
	font-size: 1.875rem;
	line-height: 1.2;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.highlight-grid {
	margin-top: 2rem;
	display: grid;
	gap: 1rem;
}

.highlight {
	background-color: var(--background);
	padding: 1.5rem;
	scroll-margin-top: 6rem;
}

/* Arrived at from a point under the title: the card says it is the one. */
.highlight:target {
	box-shadow: inset 0 0 0 2px var(--brand);
}

.highlight__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	background-color: var(--ds-blue-200);
	color: var(--brand);
}

.highlight__icon svg {
	width: 18px;
	height: 18px;
}

.highlight__title {
	margin-top: 1rem;
	font-size: 1rem;
	line-height: 1.5;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.highlight__body {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

@media (min-width: 640px) {
	.highlight-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.highlight-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}


/* 11a. Product — sticky action bar ------------------------------------------
   The rail is sticky inside the hero grid and unpins with it, about a screen
   and a half down. Measured, that left 66% of a desktop scroll and 81% of a
   phone scroll with nothing to act on — every argument the page makes below the
   fold was made to a reader with nowhere to go.

   No script. .product-body wraps everything under the hero and this is its last
   child, so `bottom: 0` pins the bar to the foot of the viewport for exactly as
   long as that wrapper is on screen: it appears where the rail lets go and
   settles into place at the end of the page. The one full-width element in the
   theme that floats over content, so it is a hairline and a surface, nothing
   more — no shadow, no radius, no translucency to read text through.
   ------------------------------------------------------------------------ */

.cta-bar {
	position: sticky;
	bottom: 0;
	z-index: 20;
	background-color: var(--background);
	border-top-width: 1px;
	border-top-color: var(--foreground);
}

.cta-bar__inner {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 0.75rem;
}

/* Below 48em the subject line is the first thing to go: two buttons and a
   thumb-sized target matter more than restating the exam code. */
.cta-bar__subject {
	display: none;
}

.cta-bar__actions {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex: 1;
}

/* .btn is width:100% by default — right for the rail, wrong here. */
.cta-bar .btn {
	width: auto;
	height: 3rem;
	flex: none;
}

.cta-bar__go {
	flex: 1;
	min-width: 0;
	justify-content: space-between;
	padding-inline: 1.25rem;
}

/* On the narrowest phones the label wraps to two lines rather than pushing the
   WhatsApp and text buttons off the edge: the button may shrink (never grow),
   and `.cta-bar .btn` would otherwise pin it at its content width. */
.cta-bar .cta-bar__go {
	flex: 0 1 auto;
}

.cta-bar__go span {
	min-width: 0;
	white-space: normal;
	line-height: 1.15;
	text-align: left;
}

.cta-bar__wa {
	padding-inline: 1rem;
}

/* The label is redundant beside the logo when space is short; the mark carries
   it, and the button keeps a 48px target either way. */
.cta-bar__wa-label {
	display: none;
}

@media (min-width: 30em) {
	.cta-bar__wa-label {
		display: inline;
	}
}

@media (min-width: 48em) {
	.cta-bar__inner {
		padding-block: 0.875rem;
	}

	.cta-bar__subject {
		display: flex;
		flex-direction: column;
		gap: 0.125rem;
		min-width: 0;
		flex: 1;
	}

	.cta-bar__code {
		font-family: var(--font-mono);
		font-size: 0.875rem;
		font-weight: 500;
		letter-spacing: -0.01em;
		color: var(--foreground);
	}

	.cta-bar__note {
		font-size: 0.75rem;
		line-height: 1.4;
		color: var(--muted-foreground);
	}

	.cta-bar__actions {
		flex: none;
	}

	.cta-bar__go {
		flex: none;
		gap: 0.75rem;
	}
}

/* The bar overlays the foot of the page while it is pinned, so the last band
   ends above it rather than under it. */
.product-body > :last-of-type {
	scroll-margin-bottom: 5rem;
}

/* Both anchor targets clear the fixed header. */
#purchase,
.enquiry {
	scroll-margin-top: 5rem;
}

/* The hero's link to the proof band. Set as a control rather than as prose: it
   is the one thing in the identity column asking to be clicked. */
.proof-link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: 1rem;
	padding-block: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.4;
	font-weight: 500;
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
	text-decoration-thickness: 1px;
}

.proof-link:hover {
	text-decoration: none;
}

.proof-link__icon {
	width: 1.125rem;
	height: 1.125rem;
	flex: none;
}


/* 12. Product — testimonials (WC Testimonials with Proof) -------------------
   The plugin's own stylesheet is dequeued in inc/testimonials.php — it is 12px
   radii, drop shadows and a red-to-orange gradient, none of which exists here.
   This is the whole of the block's appearance, its lightbox included, written
   in the theme's own terms against the plugin's markup contract.

   It sits on the plain surface between two others: "What you get" is tinted, so
   a second tint immediately below it would read as one long band. Cards take a
   hairline instead, which is how a white object separates from a white field.
   ------------------------------------------------------------------------ */

.product-testimonials {
	scroll-margin-top: 5rem;
	border-top-width: 1px;
}

.wct-testimonials-wrap {
	max-width: none; /* the .band wrapper already holds the measure */
	margin: 0;
}

/* Set as a band title, whatever heading level the plugin gave it. */
.wct-section-title {
	font-size: 1.875rem;
	line-height: 1.2;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.wct-grid {
	margin-top: 2rem;
	display: grid;
	gap: 1rem;
	/* Resilient to the count: three cards make three columns, two make two, and
	   min() stops the track floor from overflowing a narrow phone. */
	grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}

.wct-card {
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
	background-color: var(--background);
	border-width: 1px;
	padding: 1.5rem;
}

/* Card header ------------------------------------------------------------ */

.wct-card-header {
	display: flex;
	align-items: center;
	gap: 0.875rem;
}

.wct-avatar {
	flex: none;
}

.wct-photo,
.wct-avatar-placeholder {
	display: block;
	width: 3rem;
	height: 3rem;
	object-fit: cover;
}

/* Square, and the same tinted tile as the "What you get" icons, so a card with
   a photo and a card without read as the same object. */
.wct-avatar-placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: var(--ds-blue-200);
	color: var(--brand);
	font-size: 1.125rem;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.wct-name-wrap {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	min-width: 0;
}

.wct-name {
	font-size: 1rem;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

/* Deliberately not green. Green on this page means WhatsApp and nothing else;
   a verified mark is a system statement, so it is set like every other label
   here and the tick carries the accent. */
.wct-verified {
	display: flex;
	align-items: center;
	gap: 0.3125rem;
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
}

.wct-verified svg {
	flex: none;
	color: var(--brand);
}

/* Quote ------------------------------------------------------------------ */

.wct-quote {
	flex: 1;
	font-size: 0.9375rem;
	line-height: 1.625;
	color: var(--foreground);
}

/* The plugin brackets the quote in straight typewriter marks. They are the one
   piece of decoration in the card and they set badly at any size, so the rule
   the rest of the page follows applies: the text is the quote. */
.wct-quote-mark {
	display: none;
}

/* Proof ------------------------------------------------------------------ */

.wct-marksheets {
	border-top-width: 1px;
	padding-top: 1.25rem;
}

.wct-marksheet-label {
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--muted-foreground);
}

.wct-marksheet-grid {
	margin-top: 0.75rem;
	display: grid;
	gap: 0.5rem;
	grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
}

/* A fixed height, not a fixed ratio. Under a ratio, two thumbnails sharing a
   row come out half as tall as one thumbnail spanning it, so the proof block —
   and with it the label above it — sat at a different height in every card. A
   height is the same whatever the count, which is what lets the quote flex and
   pin every RESULT label to the same line across the row. The lightbox shows
   each image uncropped. */
.wct-marksheet-item {
	position: relative;
	height: 11rem;
}

/* Contained, not cropped. These are documents: a cover crop cuts the heading
   off one and the score off another, and a proof thumbnail that has had the
   proof cropped out of it is worse than no thumbnail. Letterboxing against the
   page's own tint reads as a document preview, which is what it is. */
.wct-marksheet-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
	border-width: 1px;
	background-color: var(--ds-gray-100);
}

/* The plugin ships this as an empty element for a hover treatment. It carries
   the affordance that the thumbnail opens — a ruled edge in the accent, the
   same treatment every field on the page takes on focus. */
.wct-img-overlay {
	position: absolute;
	inset: 0;
	border-width: 0;
	border-color: var(--brand);
	pointer-events: none;
	transition: border-width 0.12s cubic-bezier(0.4, 0, 0.2, 1);
}

.wct-marksheet-item:hover .wct-img-overlay,
.wct-marksheet-img:focus-visible + .wct-img-overlay {
	border-width: 2px;
}

@media (min-width: 1024px) {
	.wct-card {
		padding: 1.75rem;
	}
}

/* Lightbox --------------------------------------------------------------- */
/* assets/lightbox.js builds this DOM itself and is kept; only its dress is
   ours. Square buttons, one ink, no radii. The overlay is the only full-bleed
   dark surface in the theme, so it states the palette rather than borrowing. */

body.wct-lb-open {
	overflow: hidden;
}

.wct-lb-overlay {
	position: fixed;
	inset: 0;
	z-index: 999;
	display: none;
	align-items: center;
	justify-content: center;
	padding: 1.5rem;
	background-color: color-mix(in oklab, var(--ds-gray-1000) 92%, transparent);
}

.wct-lb-overlay.wct-lb-active {
	display: flex;
}

.wct-lb-inner {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
	max-width: min(64rem, 100%);
	max-height: 100%;
}

.wct-lb-img-wrap {
	min-height: 0;
}

.wct-lb-img {
	display: block;
	max-width: 100%;
	max-height: 70vh;
	opacity: 0;
	background-color: var(--background);
}

.wct-lb-img.wct-lb-loaded {
	opacity: 1;
}

@media (prefers-reduced-motion: no-preference) {
	.wct-lb-img {
		transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
	}
}

.wct-lb-caption {
	font-size: 0.9375rem;
	font-weight: 500;
	color: var(--brand-foreground);
}

.wct-lb-counter {
	font-size: 0.75rem;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.1em;
	color: color-mix(in oklab, var(--brand-foreground) 65%, transparent);
}

.wct-lb-close,
.wct-lb-prev,
.wct-lb-next {
	position: absolute;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	background-color: transparent;
	border-width: 1px;
	border-color: color-mix(in oklab, var(--brand-foreground) 35%, transparent);
	color: var(--brand-foreground);
	font-size: 1.25rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.wct-lb-close:hover,
.wct-lb-prev:hover,
.wct-lb-next:hover,
.wct-lb-close:focus-visible,
.wct-lb-prev:focus-visible,
.wct-lb-next:focus-visible {
	background-color: color-mix(in oklab, var(--brand-foreground) 15%, transparent);
	border-color: var(--brand-foreground);
}

/* Fixed to the viewport, not offset from the image.
   Hung off .wct-lb-inner these clip: the inner is centred, so on a short
   viewport its top edge rises far enough that a control sitting 3.5rem above it
   lands off-screen, and the only way out of the lightbox goes with it. Fixed,
   they are reachable at every height. */
.wct-lb-close {
	position: fixed;
	top: 1rem;
	right: 1rem;
}

.wct-lb-prev,
.wct-lb-next {
	position: fixed;
	top: 50%;
	transform: translateY(-50%);
}

.wct-lb-prev {
	left: 1rem;
}

.wct-lb-next {
	right: 1rem;
}

/* On a phone the arrows would sit on top of the image at half height, so they
   drop to the bottom edge — within a thumb's reach, and clear of the caption,
   which the shorter image makes room for. */
@media (max-width: 47.99em) {
	.wct-lb-img {
		max-height: 60vh;
	}

	.wct-lb-prev,
	.wct-lb-next {
		top: auto;
		bottom: 1rem;
		transform: none;
	}
}


/* 13. Product — FAQ accordion ---------------------------------------------
   A list, so the dividers stay — but a step lighter than the structural
   borders, and each row reacts to the pointer so it reads as something you can
   act on rather than a ruled table.
   ------------------------------------------------------------------------ */

.product-faq {
	scroll-margin-top: 5rem;
}

.faq-grid {
	display: grid;
	gap: 2rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 4rem;
}

.faq-lede {
	margin-top: 0.75rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.accordion {
	max-width: 48rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-300);
}

.accordion__item {
	border-bottom-width: 1px;
	border-color: var(--ds-gray-300);
}

.accordion__trigger {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	padding-inline: 0.75rem;
	padding-block: 1.25rem;
	font-size: 1rem;
	line-height: 1.5;
	font-weight: 500;
	text-align: left;
	cursor: pointer;
	list-style: none;
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.accordion__trigger::-webkit-details-marker {
	display: none;
}

.accordion__trigger:hover {
	background-color: var(--ds-gray-100);
}

.accordion__item[open] > .accordion__trigger {
	color: var(--brand);
}

.accordion__question {
	font-size: inherit;
	font-weight: inherit;
	line-height: inherit;
}

.accordion__chevron {
	width: 1rem;
	height: 1rem;
	flex: none;
	color: currentColor;
	transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.accordion__item[open] > .accordion__trigger .accordion__chevron {
	transform: rotate(180deg);
}

.accordion__answer {
	max-width: 42rem;
	padding-inline: 0.75rem;
	padding-top: 0;
	padding-bottom: 1.25rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

/* Height animation on the disclosure. Browsers without ::details-content just
   open and close instantly, which is the same interaction without the easing. */
.accordion__item::details-content {
	block-size: 0;
	overflow: hidden;
	transition: block-size 0.2s ease-out, content-visibility 0.2s ease-out allow-discrete;
}

.accordion__item[open]::details-content {
	block-size: auto;
}

@media (min-width: 1024px) {
	.faq-grid {
		grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
		gap: 4rem;
	}
}

@media (prefers-reduced-motion: reduce) {
	.accordion__item::details-content,
	.accordion__chevron,
	.btn,
	.site-nav a,
	.accordion__trigger {
		transition: none;
	}
}


/* 14. Product — ratings and reviews ----------------------------------------
   WooCommerce ships the star rating as an icon font inside the stylesheet the
   theme dequeues, so the glyph is redrawn here from a text star. The markup is
   untouched: an outer element sized by five empty stars, and an inner span
   whose inline width WooCommerce sets to the score, clipping a filled row to
   the same fraction. The span also carries the readable "Rated 4 out of 5",
   which the padding pushes out of the clipped box and leaves for assistive
   technology.
   ------------------------------------------------------------------------ */

.star-rating {
	position: relative;
	display: inline-block;
	overflow: hidden;
	font-size: 0.875rem;
	line-height: 1.2;
	letter-spacing: 0.1em;
	white-space: nowrap;
	color: var(--ds-gray-600);
}

.star-rating::before {
	content: "★★★★★";
	display: block;
}

.star-rating span {
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	overflow: hidden;
	padding-top: 2em;
	white-space: nowrap;
	color: var(--warning);
}

.star-rating span::before {
	content: "★★★★★";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
}

.star-rating span strong {
	font-weight: inherit;
}

/* Reviews sit on the same tinted field as "What you get", so each review and
   the form read as white objects on it rather than as another ruled list. */
.product-reviews {
	background-color: var(--ds-gray-200);
	scroll-margin-top: 5rem;
}

.woocommerce-Reviews {
	display: grid;
	gap: 3rem;
	align-items: start;
}

.woocommerce-Reviews-title {
	font-size: 1.875rem;
	line-height: 1.2;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.woocommerce-Reviews-title span {
	color: var(--muted-foreground);
}

.commentlist {
	margin-top: 2rem;
}

.commentlist > li {
	background-color: var(--background);
	padding: 1.5rem;
}

.commentlist > li + li {
	margin-top: 1rem;
}

.comment_container {
	display: flex;
	align-items: flex-start;
	gap: 1rem;
}

/* Square, like everything else. The avatar is the one image on the page and it
   earns its place by making a list of reviews scannable. */
.comment_container .avatar {
	width: 2.5rem;
	height: 2.5rem;
	flex: none;
	border-radius: 0;
	background-color: var(--ds-gray-300);
}

.comment-text {
	min-width: 0;
	flex: 1;
}

.comment-text .star-rating {
	margin-bottom: 0.5rem;
}

.comment-text .meta {
	font-size: 0.8125rem;
	line-height: 1.4;
	color: var(--muted-foreground);
}

.woocommerce-review__author {
	font-weight: 600;
	color: var(--foreground);
}

.woocommerce-review__verified {
	font-style: normal;
	color: var(--ds-green-1000);
}

.comment-text .description {
	margin-top: 0.75rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.comment-text .description > * + * {
	margin-top: 0.75rem;
}

.woocommerce-review__awaiting-approval {
	font-style: normal;
	color: var(--warning);
}

.woocommerce-noreviews,
.woocommerce-verification-required,
.must-log-in {
	margin-top: 1rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.must-log-in a,
.woocommerce-noreviews a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

#comments .woocommerce-pagination {
	margin-top: 1.5rem;
	font-size: 0.875rem;
}

#comments .woocommerce-pagination ul {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

#comments .woocommerce-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.25rem;
	height: 2.25rem;
	padding-inline: 0.5rem;
	border-width: 1px;
	background-color: var(--background);
}

#comments .woocommerce-pagination .current {
	background-color: var(--brand);
	border-color: var(--brand);
	color: var(--brand-foreground);
}

/* The review form. */
#review_form_wrapper {
	background-color: var(--background);
	padding: 1.5rem;
}

.comment-reply-title {
	display: block;
	font-size: 1.125rem;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: -0.01em;
}

#review_form .comment-form {
	margin-top: 1.25rem;
	display: grid;
	gap: 1.25rem;
}

#review_form .comment-notes,
#review_form .required-field-message {
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

.comment-reply-title small {
	font-size: 0.8125rem;
	font-weight: 400;
	color: var(--muted-foreground);
}

/* Field treatment shared by the review form and the enquiry rail. The border
   colour is a variable so the rail, which sits on a tinted field, can restate
   it without restating the rest — which is also why each form sets its own
   value rather than sharing a default here: a shared declaration would sit
   later in the file than the rail's and quietly win. */
#review_form {
	--field-border: var(--ds-gray-500);
	--field-border-hover: var(--ds-gray-700);
}

#review_form .comment-form label,
.field__label {
	display: block;
	margin-bottom: 0.375rem;
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
}

#review_form .required,
.field__label .required {
	color: var(--warning);
	text-decoration: none;
	border-bottom: 0;
	cursor: help;
}

/* 1rem is the floor that stops iOS zooming the page when a field takes focus,
   and the height is a comfortable touch target on the same 4px scale. */
#review_form input[type="text"],
#review_form input[type="email"],
#review_form input[type="url"],
#review_form textarea,
.enquiry__form input[type="text"],
.enquiry__form input[type="email"],
.enquiry__form input[type="tel"],
.enquiry__form select {
	display: block;
	width: 100%;
	min-height: 3rem;
	padding-inline: 0.875rem;
	padding-block: 0.75rem;
	font-size: 1rem;
	line-height: 1.5;
	background-color: var(--background);
	border-width: 1px;
	border-color: var(--field-border);
	color: var(--foreground);
}

#review_form textarea {
	min-height: 9rem;
	resize: vertical;
}

/* A select is sized from the font's own metrics rather than from the line box,
   so at the shared 1.5 line-height it lands 0.1rem shorter than the inputs it is
   stacked with. That leading goes back on as padding — split evenly, so the box
   lines up with its neighbours and the label inside it stays centred. */
.enquiry__form select {
	padding-block: 0.8rem;
}

/* Country code and number on one line. The code is the minor half, so the
   select stays narrow and the number takes the rest. Options lead with the
   dialling code, so what truncates is the country name, never the code. */
.field__phone {
	display: flex;
	gap: 0.5rem;
}

.enquiry__form .field__phone select {
	flex: 0 0 auto;
	width: 6rem;
	max-width: 35%;
	padding-inline-end: 1.75rem;
	text-overflow: ellipsis;
}

.enquiry__form .field__phone input {
	flex: 1 1 0;
	width: auto;
	min-width: 0;
}

#review_form input:hover,
#review_form textarea:hover,
.enquiry__form input:hover,
.enquiry__form select:hover {
	border-color: var(--field-border-hover);
}

#review_form input:focus,
#review_form textarea:focus,
.enquiry__form input:focus,
.enquiry__form select:focus {
	border-color: var(--brand);
}

/* :user-invalid waits until the field has actually been used, so the form does
   not scold anyone mid-sentence. The browser's own message carries the reason;
   the border only points at the field. */
#review_form input:user-invalid,
#review_form textarea:user-invalid,
.enquiry__form input:user-invalid,
.enquiry__form select:user-invalid {
	border-color: var(--warning);
}

.comment-form-cookies-consent {
	display: flex;
	align-items: center;
	gap: 0.5rem;
}

#review_form .comment-form-cookies-consent label {
	margin-bottom: 0;
	font-size: 0.8125rem;
	font-weight: 400;
	text-transform: none;
	letter-spacing: normal;
	color: var(--muted-foreground);
}

.comment-form-cookies-consent input {
	width: 1rem;
	height: 1rem;
	flex: none;
}

/* The rating widget. WooCommerce's script hides the select and inserts these
   links, so the select is what works without JavaScript and this is what
   replaces it with one. */
.comment-form-rating .stars {
	display: flex;
	gap: 0.25rem;
	margin-top: 0.25rem;
}

.comment-form-rating .stars span {
	display: flex;
	gap: 0.25rem;
}

.comment-form-rating .stars a {
	position: relative;
	display: block;
	width: 1.75rem;
	height: 1.75rem;
	overflow: hidden;
	text-indent: -999em;
	text-decoration: none;
}

.comment-form-rating .stars a::before {
	content: "★";
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	text-indent: 0;
	font-size: 1.5rem;
	line-height: 1;
	color: var(--ds-gray-600);
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* A chosen rating fills up to the active star; a pointer preview overrides it,
   which is why the selected rules stand down while the row is hovered. */
.comment-form-rating .stars.selected a::before {
	color: var(--warning);
}

.comment-form-rating .stars.selected:not(:hover) a.active ~ a::before {
	color: var(--ds-gray-600);
}

.comment-form-rating .stars:hover a::before {
	color: var(--warning);
}

.comment-form-rating .stars a:hover ~ a::before {
	color: var(--ds-gray-600);
}

/* WooCommerce closes the reviews block with a float clearer it no longer
   needs, and in a grid it would claim a row. */
.woocommerce-Reviews .clear {
	display: none;
}

@media (min-width: 1024px) {
	.woocommerce-Reviews {
		grid-template-columns: minmax(0, 1fr) minmax(0, 24rem);
		gap: 4rem;
	}

	/* Until the first review exists there is nothing in the left column, and a
	   form stranded beside half a page of nothing reads as a mistake. */
	.woocommerce-Reviews:has(.woocommerce-noreviews) {
		grid-template-columns: minmax(0, 34rem);
		gap: 2rem;
	}
}


/* 15. Product — extra tabs, upsells and related -----------------------------
   Everything WooCommerce puts below the summary that the layout has not already
   placed by hand. A plugin's tab becomes a section here; upsells and related
   keep their own priorities, so the running order is WooCommerce's.
   ------------------------------------------------------------------------ */

.product-extra-tabs {
	border-top-width: 1px;
}

.product-extra-tab + .product-extra-tab {
	margin-top: 3rem;
}

.product-extra-tab > * + * {
	margin-top: 1rem;
}

.product-extra-tab {
	font-size: 1rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.product-extra-tab .band__title,
.product-extra-tab h3,
.product-extra-tab h4,
.product-extra-tab strong {
	color: var(--foreground);
}

.product-extra-tab a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.related,
.up-sells {
	border-top-width: 1px;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 4rem;
}

.related > h2,
.up-sells > h2 {
	font-size: 1.875rem;
	line-height: 1.2;
	font-weight: 700;
	letter-spacing: -0.02em;
}

ul.products {
	margin-top: 2rem;
	display: grid;
	gap: 1rem;
}

ul.products li.product {
	display: flex;
	flex-direction: column;
	border-width: 1px;
	padding: 1.5rem;
}

ul.products .woocommerce-LoopProduct-link {
	display: flex;
	flex: 1;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.5rem;
}

.loop-card__code {
	font-family: var(--font-mono);
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	line-height: 1.25;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--brand);
}

.woocommerce-loop-product__title {
	font-size: 1rem;
	line-height: 1.5;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

ul.products li.product .price {
	margin-top: auto;
	padding-top: 0.5rem;
	font-size: 1.25rem;
	line-height: 1.2;
	font-weight: 700;
	letter-spacing: -0.02em;
	color: var(--foreground);
}

ul.products li.product .price del {
	margin-left: 0.5rem;
	font-size: 0.875rem;
	font-weight: 400;
	color: var(--muted-foreground);
	text-decoration: line-through;
}

ul.products li.product .button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	margin-top: 1.25rem;
	height: 2.75rem;
	padding-inline: 1rem;
	border-width: 1px;
	border-color: var(--brand);
	font-size: 0.8125rem;
	font-weight: 600;
	color: var(--brand);
	cursor: pointer;
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

ul.products li.product .button:hover {
	background-color: var(--ds-blue-300);
}

ul.products li.product .added_to_cart {
	margin-top: 0.5rem;
	font-size: 0.8125rem;
	font-weight: 500;
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

@media (min-width: 640px) {
	ul.products {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	ul.products {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (min-width: 1280px) {
	ul.products {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}


/* 16. Certification listing -------------------------------------------------
   No imagery and no price, so the card is carried by type alone: the dated code
   in mono where a thumbnail would sit, the certification name as the heading,
   and the three facts a candidate chooses on underneath.

   The whole card is one link. Nothing inside it is a button — a button inside a
   link is neither — so the closing line is set as one and the border does the
   reacting. Same grammar as the specification table on the single page: a flat
   field, hairline ruled, one accent, and the accent only where you can act.
   ------------------------------------------------------------------------ */

.listing-hero__inner,
.listing-controls__inner,
.listing-grid {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
}

/* Tighter on a phone, where every 16px is the difference between a
   certification being visible on the first screen and none being. */
.listing-hero__inner {
	padding-block: 2rem;
}

/* Two columns from 64em: the title and the lede on the left, what happens next
   on the right. The right column is the width of the product page's rail, so the
   two heroes sit on the same underlying measure. */
.listing-hero__grid {
	display: grid;
	gap: 1.75rem;
}

@media (min-width: 48em) {
	.listing-hero__grid {
		gap: 2.5rem;
	}
}

.listing-hero__title {
	font-size: 2.25rem;
	line-height: 1.1;
	font-weight: 700;
	letter-spacing: -0.03em;
	text-wrap: balance;
}

.listing-hero__lede {
	margin-top: 1rem;
	max-width: 46rem;
	font-size: 1.0625rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

@media (min-width: 64em) {
	.listing-hero__inner {
		padding-block: 3.5rem 2.5rem;
	}

	.listing-hero__title {
		font-size: 3rem;
	}

	.listing-hero__grid {
		grid-template-columns: minmax(0, 1fr) 23.75rem;
		gap: 4rem;
		align-items: start;
	}
}

/* How it works. Numerals in the same tinted tile as the "What you get" icons and
   the loop card's code chip, so the three blocks on this site that carry a small
   mark all carry the same one. */
.listing-steps {
	display: grid;
	gap: 0.625rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 48em) {
	.listing-steps {
		gap: 1.125rem;
	}
}

.listing-step {
	display: flex;
	align-items: flex-start;
	gap: 0.875rem;
}

.listing-step__n {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 1.75rem;
	height: 1.75rem;
	background-color: var(--ds-blue-200);
	font-family: var(--font-mono);
	font-size: 0.8125rem;
	font-weight: 500;
	color: var(--brand);
}

.listing-step__text {
	display: block;
}

.listing-step__title {
	display: block;
	font-size: 0.9375rem;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

/* The titles carry the sequence on their own — "find your certification, send
   your details, a consultant replies" — and the bodies elaborate it. On a phone
   the elaboration costs 150px of the first screen, which is the difference
   between seeing a certification without scrolling and seeing none at all, so
   it waits until there is room for it. */
.listing-step__body {
	display: none;
	margin-top: 0.1875rem;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

@media (min-width: 48em) {
	.listing-step__body {
		display: block;
	}
}

/* Count and sort share one line. No rule under it: the results band below is a
   tone change, and this theme lets tone be the boundary rather than saying it
   twice. */
.listing-controls {
	border-bottom-width: 0;
}

.listing-controls__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.625rem 1.5rem;
	padding-block: 0.875rem;
}

@media (min-width: 48em) {
	.listing-controls__inner {
		gap: 0.75rem 1.5rem;
		padding-block: 1rem;
	}
}

.listing-count {
	margin: 0;
	font-size: 0.8125rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
}

.woocommerce-ordering {
	margin: 0;
}

.woocommerce-ordering select {
	min-height: 2.5rem;
	padding-inline: 0.75rem;
	padding-block: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.4;
	background-color: var(--background);
	border-width: 1px;
	border-color: var(--border);
	color: var(--foreground);
}

.woocommerce-ordering select:hover {
	border-color: var(--foreground);
}

.woocommerce-ordering select:focus {
	border-color: var(--brand);
}

/* The results sit on a field.
   Everything on this page used to be white — hero, controls, and a grid of white
   cards hairlined onto white — so nothing was figure and nothing was ground, and
   the cards read as floating rather than as objects on a surface. This is the
   device the product page already uses for "What you get": tint the band, and
   the cards drop their borders and become white objects on it.

   Three surfaces, in the order the eye should take them: white for the hero,
   grey for the catalogue, and the rail's own blue for the one block asking to be
   acted on. */
.listing-results {
	background-color: var(--ds-gray-200);
}

.listing-grid {
	padding-block: 1.5rem;
}

@media (min-width: 48em) {
	.listing-grid {
		padding-block: 2rem;
	}
}

/* ul.products is WooCommerce's own element and carries its column classes; the
   grid is declared here so those classes decide nothing. */
.listing-grid ul.products {
	display: grid;
	gap: 1rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* The border comes off here too. The generic product-card rule above puts a
   hairline on the <li>; under the listing it survived beneath the white card,
   so every card carried a grey edge the design says it does not have, and on
   hover a second, blue one inside it. */
.listing-grid ul.products li.product {
	margin: 0;
	padding: 0;
	width: auto;
	float: none;
	border-width: 0;
}

/* The card. A grid rather than flow so the specification line and the closing
   line pin to the bottom edge whatever length the certification name runs to —
   two cards side by side stay level, which is the whole reason the name is
   allowed to be as long as SAP writes it.

   No border: on the tinted field the white edge is the edge. Hover draws one as
   an outline rather than a border, which costs no layout — a border appearing on
   hover would shift every line inside the card by a pixel. */
.listing-grid ul.products li.product .woocommerce-LoopProduct-link {
	display: grid;
	grid-template-rows: auto 1fr auto auto;
	gap: 0.875rem;
	height: 100%;
	padding: 1.5rem;
	background-color: var(--background);
	outline: 1px solid transparent;
	outline-offset: -1px;
	text-decoration: none;
	transition: outline-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.listing-grid ul.products li.product .woocommerce-LoopProduct-link:hover,
.listing-grid ul.products li.product .woocommerce-LoopProduct-link:focus-visible {
	outline-color: var(--brand);
	background-color: var(--ds-blue-100);
}

/* Where the thumbnail would have been. */
.listing-grid .loop-card__code {
	justify-self: start;
	padding-inline: 0.5rem;
	padding-block: 0.3125rem;
	background-color: var(--ds-blue-200);
	font-family: var(--font-mono);
	font-size: 0.75rem;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--brand);
}

.listing-grid .woocommerce-loop-product__title {
	margin: 0;
	font-size: 1.125rem;
	line-height: 1.35;
	font-weight: 600;
	letter-spacing: -0.015em;
	color: var(--foreground);
	text-wrap: balance;
}

.listing-grid .loop-card__specs {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem;
	margin: 0;
	padding-top: 0.875rem;
	border-top-width: 1px;
	font-size: 0.8125rem;
	line-height: 1.4;
	font-variant-numeric: tabular-nums;
	color: var(--muted-foreground);
}

.listing-grid .loop-card__sep {
	color: var(--ds-gray-500);
}

.listing-grid .loop-card__go {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.4;
	font-weight: 600;
	color: var(--brand);
}

.listing-grid .loop-card__arrow {
	width: 1rem;
	height: 1rem;
	flex: none;
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.listing-grid ul.products li.product .woocommerce-LoopProduct-link:hover .loop-card__arrow {
	transform: translateX(0.25rem);
}

/* Woo's own star rating, when an exam has been reviewed. Kept small — it is a
   footnote on a card, not the reason to open it. */
.listing-grid .star-rating {
	margin: 0;
	font-size: 0.75rem;
}

@media (min-width: 40em) {
	.listing-grid ul.products {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 64em) {
	.listing-grid ul.products {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.listing-grid ul.products li.product .woocommerce-LoopProduct-link {
		padding: 1.75rem;
	}
}

/* Three across is the ceiling, not four. The shell caps at 1600px, so a fourth
   track buys 373px cards — narrow enough that a certification name as long as
   "SAP Certified - SAP SuccessFactors Employee Central Core and Position
   Management" runs to five lines. Three gives it three, and a catalogue reads
   better as fewer, fuller cards than as a wall of thin ones. */

/* Nothing matched. */
.woocommerce-info,
.woocommerce-no-products-found .woocommerce-info {
	margin: 0;
	border-left-width: 4px;
	border-color: var(--brand);
	background-color: var(--ds-blue-100);
	padding-inline: 1.25rem;
	padding-block: 1rem;
	font-size: 0.9375rem;
	line-height: 1.625;
}

/* Pagination — WooCommerce's own markup, set as square hairline targets. */
.woocommerce-pagination {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 0 3rem;
}

.woocommerce-pagination ul.page-numbers {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
	border: 0;
}

.woocommerce-pagination ul.page-numbers li {
	border: 0;
	margin: 0;
}

/* WooCommerce puts .page-numbers on the <ul> as well as on every link in it,
   so the item rules have to say they mean the items. */
.woocommerce-pagination li .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.75rem;
	height: 2.75rem;
	padding-inline: 0.75rem;
	background-color: var(--background);
	border-width: 1px;
	font-size: 0.875rem;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	color: var(--foreground);
	text-decoration: none;
}

.woocommerce-pagination li .page-numbers:hover {
	border-color: var(--brand);
	color: var(--brand);
}

.woocommerce-pagination li .page-numbers.current {
	background-color: var(--brand);
	border-color: var(--brand);
	color: var(--brand-foreground);
}

/* The one thing on the page asking to be acted on, in the same blue the purchase
   rail uses, so that blue means the same thing on both pages. No rule: grey
   turning to blue is already the boundary. */
.listing-cta {
	background-color: var(--ds-blue-200);
}

.listing-cta__inner {
	display: grid;
	gap: 1.5rem;
	align-items: center;
}

.listing-cta__body {
	margin-top: 0.75rem;
	max-width: 40rem;
	font-size: 0.9375rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.listing-cta__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.listing-cta__actions .btn {
	width: auto;
	padding-inline: 1.5rem;
}

@media (min-width: 48em) {
	.listing-cta__inner {
		grid-template-columns: 1fr auto;
		gap: 2.5rem;
	}
}


/* 16a. Search results -------------------------------------------------------
   The catalogue's own hero, controls and grid, with the query in the title and
   the field repeated under it so a miss can be corrected without going back.
   ------------------------------------------------------------------------ */

.listing-hero__intro .site-search {
	max-width: 26rem;
	margin-top: 1.5rem;
}

.search-empty {
	max-width: 34rem;
	padding-block: 1rem 2rem;
}

.search-empty__title {
	font-size: 1.5rem;
	line-height: 1.25;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.search-empty__body {
	margin-top: 0.875rem;
	font-size: 0.9375rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.search-empty__browse {
	width: auto;
	margin-top: 1.75rem;
	gap: 0.75rem;
	padding-inline: 1.5rem;
}

.search-results-list {
	display: grid;
	gap: 1rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.search-result a {
	display: block;
	background-color: var(--background);
	padding: 1.5rem;
	outline: 1px solid transparent;
	outline-offset: -1px;
	text-decoration: none;
	transition: outline-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.search-result a:hover {
	outline-color: var(--brand);
}

.search-result__title {
	font-size: 1.125rem;
	line-height: 1.35;
	font-weight: 600;
	letter-spacing: -0.015em;
}

.search-result__excerpt {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}


/* 17. Prose fallback templates ---------------------------------------------
   Every non-product route until the rest of the theme is built.
   ------------------------------------------------------------------------ */

.prose-shell {
	max-width: 48rem;
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 4rem;
}

.prose-title {
	font-size: 1.875rem;
	line-height: 1.2;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.prose-lede {
	margin-top: 0.75rem;
	color: var(--muted-foreground);
}

.prose-entry + .prose-entry {
	margin-top: 2.5rem;
	border-top-width: 1px;
	padding-top: 2.5rem;
}

.prose-entry__title {
	font-size: 1.25rem;
	line-height: calc(1.75 / 1.25);
	font-weight: 600;
	letter-spacing: -0.01em;
}

.prose-entry__content {
	margin-top: 1rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.prose-entry__content > * + * {
	margin-top: 1rem;
}

.prose-link,
.prose-entry__content a,
.prose-pagination a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.prose-pagination {
	margin-top: 2.5rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	font-size: 0.875rem;
}


/* 18. Not found --------------------------------------------------------------
   The listing's three surfaces in the listing's order — white to say what
   happened, grey for the certifications, blue for the one thing to act on — so
   a dead link lands on a page that is recognisably the site rather than on a
   notice. The cards and the closing band are the listing's own.
   ------------------------------------------------------------------------ */

.notfound-hero__inner {
	display: grid;
	gap: 2.5rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 2.5rem 3rem;
}

.notfound-hero__intro {
	min-width: 0;
	max-width: 44rem;
}

/* The loop card's code chip, carrying the status code: the same small mono
   mark the site uses for every other code it prints. */
.notfound-code {
	display: inline-block;
	padding-inline: 0.5rem;
	padding-block: 0.3125rem;
	background-color: var(--ds-blue-200);
	font-family: var(--font-mono);
	font-size: 0.75rem;
	line-height: 1.4;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--brand);
}

.notfound-title {
	margin-top: 1.25rem;
	font-size: 2.25rem;
	line-height: 1.1;
	font-weight: 700;
	letter-spacing: -0.03em;
	text-wrap: balance;
}

.notfound-lede {
	margin-top: 1rem;
	max-width: 40rem;
	font-size: 1.0625rem;
	line-height: 1.625;
	color: var(--muted-foreground);
	text-wrap: pretty;
}

/* A search is the most likely way out, so it comes before the buttons and is
   given the button's height rather than the header's.

   Not on a phone. Below 48em the header's own field already spans the screen a
   few lines above this one, and two identical fields in one view reads as a
   mistake. From 48em the header's field is a narrow slot in the bar and this
   is the one the eye lands on. */
.notfound-hero__intro .site-search {
	display: none;
	max-width: 32rem;
	margin-top: 1.75rem;
}

@media (min-width: 48em) {
	.notfound-hero__intro .site-search {
		display: flex;
	}
}

.notfound-hero__intro .site-search__field {
	height: 3.25rem;
	padding-left: 2.75rem;
	background-color: var(--background);
}

.notfound-hero__intro .site-search__icon {
	left: 1rem;
	width: 1.125rem;
	height: 1.125rem;
}

.notfound-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1rem 1.75rem;
	margin-top: 1.75rem;
}

@media (min-width: 48em) {
	.notfound-actions {
		margin-top: 1.25rem;
	}
}

.btn.notfound-browse {
	width: auto;
	gap: 0.75rem;
}

.notfound-home {
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--brand);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 4px;
}

.notfound-home:hover {
	color: var(--ds-blue-1000);
}

/* Decoration only, and only where there is a second column for it: on a phone
   it would push the search a screen down to say what the chip already says. */
.notfound-numeral {
	display: none;
}

/* The intro keeps its measure and the numeral is centred in whatever is left.
   Pushed to the far edge instead, it left a 350px gap in the middle of the band
   at 1536px — two things floating apart rather than one composition. */
@media (min-width: 64em) {
	.notfound-hero__inner {
		grid-template-columns: minmax(0, 44rem) minmax(0, 1fr);
		align-items: center;
		gap: 3rem;
		padding-block: 3.5rem;
	}

	.notfound-title {
		font-size: 3rem;
	}

	/* Outlined in the brand's hairline rather than filled, so a numeral the
	   height of the whole intro still reads as the lightest thing in the band.
	   Where text-stroke is not supported it falls back to a pale fill. */
	/* Geist, not Geist Mono: the mono face slashes its zero, which is right in
	   an exam code and reads as "4Ø4" at this size. */
	.notfound-numeral {
		display: block;
		justify-self: center;
		margin: 0;
		font-family: var(--font-sans);
		font-size: clamp(9rem, 15vw, 14rem);
		line-height: 0.8;
		font-weight: 300;
		letter-spacing: -0.05em;
		color: var(--ds-blue-300);
		user-select: none;
	}

	@supports (-webkit-text-stroke: 1px black) {
		.notfound-numeral {
			color: transparent;
			-webkit-text-stroke: 1.5px var(--ds-blue-500);
		}
	}
}

/* The band's heading and its way out share a line, as the count and the sort do
   on the listing. */
.notfound-suggest__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.5rem 1.5rem;
	margin-bottom: 1.25rem;
}

.notfound-suggest__title {
	font-size: 1.25rem;
	line-height: 1.3;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.notfound-suggest__all {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--brand);
}

.notfound-suggest__arrow {
	width: 0.875rem;
	height: 0.875rem;
	flex: none;
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.notfound-suggest__all:hover .notfound-suggest__arrow {
	transform: translateX(0.25rem);
}

@media (min-width: 48em) {
	.notfound-suggest__title {
		font-size: 1.5rem;
	}

	.notfound-suggest__head {
		margin-bottom: 1.5rem;
	}
}


/* 19. Home -------------------------------------------------------------------
   The catalogue's grammar at the scale of a front door. Surfaces alternate so
   every boundary is a tone change: white hero on a ruled field, grey catalogue,
   white steps, grey results, white questions, blue for the last place to ask.

   The hero is the one place in the theme that draws something. There is no
   product to photograph, so it draws the offer instead — a preparation plan set
   in the same hairlines, tints and mono codes as the rest of the site — on graph
   paper that fades out under the headline. No shadows, no radii, no gradients
   that are not ruling lines.
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: no-preference) {
	html:has(.home) {
		scroll-behavior: smooth;
	}
}

/* Utilities: a hue is four steps — tint, soft, strong, ink — that components
   read without knowing which colour they are in. */
.hue--blue {
	--hue-tint: var(--ds-blue-200);
	--hue-soft: var(--ds-blue-300);
	--hue-strong: var(--ds-blue-700);
	--hue-ink: var(--ds-blue-900);
}

.hue--violet {
	--hue-tint: var(--ds-purple-200);
	--hue-soft: var(--ds-purple-300);
	--hue-strong: var(--ds-purple-700);
	--hue-ink: var(--ds-purple-900);
}

.hue--teal {
	--hue-tint: var(--ds-teal-200);
	--hue-soft: var(--ds-teal-300);
	--hue-strong: var(--ds-teal-700);
	--hue-ink: var(--ds-teal-900);
}

.hue--amber {
	--hue-tint: var(--ds-amber-200);
	--hue-soft: var(--ds-amber-300);
	--hue-strong: var(--ds-amber-700);
	--hue-ink: var(--ds-amber-ink);
}

.hue--pink {
	--hue-tint: var(--ds-pink-200);
	--hue-soft: var(--ds-pink-300);
	--hue-strong: var(--ds-pink-700);
	--hue-ink: var(--ds-pink-900);
}

/* The hero is the homepage's own surface: night blue, where every other page on
   the site opens on white. It is the brand colour at its deepest, so it is the
   site's identity rather than a new one, and it is what tells a returning
   visitor they are on the front door and not on an exam page. */
.home-hero {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background-color: var(--night-surface);
	color: var(--night-foreground);
}

/* Graph paper. Two one-pixel ruling gradients, masked so the grid is strongest
   behind the headline and gone by the foot of the band — texture where the eye
   starts, clean ground where the form and the plan need to be read. */
.home-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image:
		linear-gradient(to right, var(--night-rule) 1px, transparent 1px),
		linear-gradient(to bottom, var(--night-rule) 1px, transparent 1px);
	background-size: 2.5rem 2.5rem;
	background-position: -1px -1px;
	-webkit-mask-image: linear-gradient(to bottom, #000 0%, rgb(0 0 0 / 0.55) 45%, transparent 90%);
	mask-image: linear-gradient(to bottom, #000 0%, rgb(0 0 0 / 0.55) 45%, transparent 90%);
}

/* One column on a phone, in the order a phone reader needs it: what this is,
   the form, then the picture and the assurances. From 64em the form takes a
   column of its own and the other three stack beside it. */
.home-hero__inner {
	display: grid;
	grid-template-areas:
		"intro"
		"form"
		"art"
		"trust";
	gap: 2rem;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 2rem 2.5rem;
}

.home-hero__intro {
	grid-area: intro;
	min-width: 0;
}

.home-hero__form {
	grid-area: form;
	min-width: 0;
}

.home-hero__art {
	grid-area: art;
	min-width: 0;
}

.home-hero__trust {
	grid-area: trust;
	min-width: 0;
}

.home-hero__trust .trust-strip__inner--inline {
	margin-top: 0;
}

/* The proof, before the promise. A chip rather than a line of prose, because
   it is the one thing above the headline asking to be clicked. */
.home-hero__proof {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding-inline: 0.625rem 0.875rem;
	padding-block: 0.4375rem;
	background-color: oklch(1 0 0 / 0.06);
	border-width: 1px;
	border-color: oklch(1 0 0 / 0.2);
	font-size: 0.8125rem;
	line-height: 1.3;
	font-weight: 500;
	color: var(--night-foreground);
	transition: border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-hero__proof:hover {
	border-color: var(--highlight);
}

.home-hero__proof-icon {
	width: 1rem;
	height: 1rem;
	flex: none;
	color: var(--highlight);
}

.home-hero__eyebrow {
	color: var(--night-muted);
}

.home-hero__title {
	margin-top: 1.25rem;
	font-size: clamp(2.625rem, 1.4rem + 4.2vw, 4.75rem);
	line-height: 1;
	font-weight: 700;
	letter-spacing: -0.045em;
	text-wrap: balance;
}

/* The word the page is about, in the one warm colour on the site, over a marker
   stroke of the same. It draws itself in once, on load. */
.home-hero__accent {
	color: var(--highlight);
	background-image: linear-gradient(var(--highlight), var(--highlight));
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 100% 0.075em;
}

.home-hero__lede {
	margin-top: 1.25rem;
	max-width: 36rem;
	font-size: 1.0625rem;
	line-height: 1.6;
	color: var(--night-muted);
	text-wrap: pretty;
}

/* The form, as a white sheet on the night surface — the brightest object in the
   band, which is the point — with the warm rule across its top that ties it to
   the headline. Full bleed on a phone, as the rail is. */
.home-hero__form {
	margin-inline: calc(var(--shell-pad) * -1);
	padding-inline: var(--shell-pad);
	padding-block: 1.75rem 1.5rem;
	background-color: var(--background);
	border-top-width: 4px;
	border-color: var(--highlight);
	color: var(--foreground);
}

.home-hero__form .enquiry__form {
	--field-border: var(--ds-gray-500);
	--field-border-hover: var(--ds-gray-700);
}

.home-hero__form .enquiry__or::before,
.home-hero__form .enquiry__or::after {
	border-color: var(--ds-gray-300);
}

/* The rest of the band's furniture, restated for the dark ground. */
.home-hero .plan__board {
	border-color: transparent;
	color: var(--foreground);
}

.home-hero .plan__caption {
	color: var(--night-muted);
}

.home-hero .trust-point {
	color: var(--night-foreground);
}

.home-hero .trust-point__icon {
	color: var(--highlight);
}

/* Lit cells --------------------------------------------------------------- */

.cells {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}

/* Exactly one square of the graph paper: offset past the ruling line it sits
   on, and a pixel short of the next. */
.cell {
	position: absolute;
	left: calc(var(--x) * 2.5rem + 1px);
	top: calc(var(--y) * 2.5rem + 1px);
	width: calc(2.5rem - 1px);
	height: calc(2.5rem - 1px);
	background-color: var(--hue-strong);
	opacity: var(--o, 0.6);
}

.cell--sm {
	display: none;
}

@media (max-width: 39.99em) {
	.cells--hero .cell:not(.cell--sm) {
		display: none;
	}

	.cells--hero .cell--sm {
		display: block;
	}
}

@media (prefers-reduced-motion: no-preference) {
	.cell--pulse {
		animation: cell-pulse 6s ease-in-out infinite;
		animation-delay: calc(var(--delay, 0) * 1s);
	}

	@keyframes cell-pulse {
		0%,
		100% {
			opacity: var(--o, 0.6);
		}

		50% {
			opacity: 0.25;
		}
	}
}

.home-enquiry__title {
	font-size: 1.375rem;
	line-height: 1.25;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.field__hint {
	display: block;
	margin-top: 0.375rem;
	font-size: 0.75rem;
	line-height: 1.4;
	color: var(--muted-foreground);
}

/* The certification is the field that matters most, so it is set in the mono
   every exam code on the site is set in — the visitor types a code into the
   same letterforms they will see it printed in. */
.enquiry__form .home-enquiry__certification {
	font-family: var(--font-mono);
	letter-spacing: -0.01em;
}

.enquiry__form .home-enquiry__certification::placeholder {
	font-family: var(--font-sans);
	letter-spacing: normal;
}

.home-enquiry__submit {
	justify-content: space-between;
	padding-inline: 1.25rem;
}

/* Name and email share a row wherever the form is wide enough for two email
   addresses' worth of field. It is the difference between the submit button
   landing on a laptop's first screen and landing below it. */
@media (min-width: 40em) {
	.home-enquiry .enquiry__form {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 0.75rem;
	}

	.home-enquiry .enquiry__form > * {
		grid-column: 1 / -1;
	}

	.home-enquiry .enquiry__form > .field:has(#enquiry-name),
	.home-enquiry .enquiry__form > .field:has(#enquiry-email) {
		grid-column: auto;
	}
}

@media (min-width: 40em) and (max-width: 63.99em) {
	.home-hero__form {
		max-width: 40rem;
		margin-inline: 0;
		padding-inline: 2rem;
	}
}

/* The plan board ------------------------------------------------------------
   Self-paced: four phases end to end from today to ready, with no weeks and no
   exam date on the line. Positions are plain percentages set in the template.
   ------------------------------------------------------------------------ */

.plan {
	margin: 0;
	max-width: 40rem;
	/* The board lays itself out by its own width, not the viewport's: it is
	   narrow on a phone and narrow again beside the form at 1024px. */
	container-type: inline-size;
}

.plan__board {
	background-color: var(--background);
	border-width: 1px;
	border-color: var(--border);
}

.plan__head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem 1rem;
	padding-inline: 1rem;
	padding-block: 0.75rem;
	border-bottom-width: 1px;
	border-color: var(--ds-gray-300);
}

.plan__label {
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--muted-foreground);
	white-space: nowrap;
}

.plan__code {
	padding-inline: 0.5rem;
	padding-block: 0.25rem;
	background-color: var(--ds-blue-200);
	font-family: var(--font-mono);
	font-size: 0.75rem;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--brand);
}

/* A label column, the line from today to the finish, and the finish itself. */
.plan__chart {
	display: grid;
	grid-template-columns: minmax(5.75rem, 8.5rem) minmax(0, 1fr) 3.25rem;
	grid-template-rows: 2rem;
	grid-auto-rows: 2.125rem;
	align-items: center;
	padding-inline: 1rem;
	padding-block: 0.25rem 0.875rem;
}

.plan__rules {
	grid-column: 2;
	align-self: stretch;
	position: relative;
}

.plan__rules > i {
	position: absolute;
	top: 0;
	bottom: 0;
	border-left-width: 1px;
	border-color: var(--ds-gray-300);
}

.plan__rule-end {
	grid-column: 3;
	align-self: stretch;
	border-left-width: 1px;
	border-left-style: dashed;
	border-color: var(--brand);
}

.plan__ticks {
	grid-column: 2;
	grid-row: 1;
	position: relative;
	align-self: stretch;
}

.plan__tick {
	position: absolute;
	top: 50%;
	translate: 0 -50%;
	padding-left: 0.375rem;
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	line-height: 1;
	color: var(--muted-foreground);
	white-space: nowrap;
}

.plan__end {
	grid-column: 3;
	grid-row: 1;
	justify-self: end;
	font-size: 0.625rem;
	line-height: 1;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--brand);
}

.plan__task {
	grid-column: 1;
	min-width: 0;
	padding-right: 0.625rem;
	overflow: hidden;
	font-size: 0.75rem;
	line-height: 1.2;
	font-weight: 500;
	color: var(--foreground);
	white-space: nowrap;
	text-overflow: ellipsis;
}

.plan__track {
	grid-column: 2;
	position: relative;
	align-self: stretch;
}

/* Flat bars in the chip tint with the accent as the leading edge; the last is
   solid, because it is the one that ends at the finish. */
.plan__bar {
	position: absolute;
	top: calc(50% - 0.4375rem);
	left: var(--s);
	/* 3px short of its share, so phases laid end to end still read as separate
	   bars rather than one long one. */
	width: max(0.5rem, calc(var(--w) - 3px));
	height: 0.875rem;
	background-color: var(--hue-soft, var(--ds-blue-300));
	border-left-width: 2px;
	border-color: var(--hue-strong, var(--brand));
	transform-origin: left center;
}

/* Each phase in its own hue; the last is solid, because it ends at ready. */
.plan__bar--final {
	background-color: var(--hue-strong, var(--brand));
}

.plan__exam {
	grid-column: 3;
	justify-self: end;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 1.75rem;
	height: 1.75rem;
	background-color: var(--brand);
	border-width: 1px;
	border-color: var(--brand);
	color: var(--brand-foreground);
}

.plan__exam-icon {
	width: 1rem;
	height: 1rem;
}

.plan__caption {
	margin-top: 0.625rem;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--muted-foreground);
	text-wrap: pretty;
}

@media (min-width: 40em) {
	.plan__head {
		padding-inline: 1.25rem;
	}

	.plan__chart {
		grid-template-rows: 2.25rem;
		grid-auto-rows: 2.375rem;
		padding-inline: 1.25rem;
		padding-block: 0.25rem 1rem;
	}

	.plan__task {
		font-size: 0.8125rem;
	}

	.plan__bar {
		top: calc(50% - 0.5rem);
		height: 1rem;
	}

	.plan__tick {
		font-size: 0.75rem;
	}
}

/* A narrow board. Side-by-side, the phase names kept their 136px column and
   left the timeline about 110px — "Today", "Week 2" and "Week 4" ran into each
   other. Here each name sits above its own bar and the line gets the full
   width. */
@container (max-width: 30rem) {
	.plan__chart {
		grid-template-columns: 0 minmax(0, 1fr) 2.5rem;
		grid-template-rows: 2rem;
		grid-auto-rows: 2.75rem;
	}

	.plan__task {
		grid-column: 2;
		align-self: start;
		padding-top: 0.3125rem;
		padding-left: 0.375rem;
		padding-right: 0;
		font-size: 0.6875rem;
		color: var(--muted-foreground);
	}

	.plan__bar {
		top: auto;
		bottom: 0.4375rem;
		height: 0.75rem;
	}
}

/* Once, on load: the marker under the headline draws, the phases grow in one
   after another, and the finish lands last — none of it for anyone who has
   asked for less motion. */
@media (prefers-reduced-motion: no-preference) {
	.home-hero__accent {
		animation: home-mark 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) 0.3s backwards;
	}

	.plan__bar {
		animation: plan-grow 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
		animation-delay: calc(0.55s + var(--i, 0) * 0.16s);
	}

	.plan__exam {
		animation: plan-land 0.4s cubic-bezier(0.2, 0.8, 0.2, 1) 1.45s backwards;
	}

	@keyframes home-mark {
		from {
			background-size: 0% 0.075em;
		}
	}

	@keyframes plan-grow {
		from {
			transform: scaleX(0);
		}
	}

	@keyframes plan-land {
		from {
			transform: scale(0.4);
			opacity: 0;
		}
	}
}

@media (min-width: 64em) {
	.home-hero__inner {
		grid-template-columns: minmax(0, 1fr) 26rem;
		grid-template-rows: auto auto 1fr;
		grid-template-areas:
			"intro form"
			"art form"
			"trust form";
		column-gap: 4rem;
		row-gap: 2.5rem;
		align-items: start;
		padding-block: 3rem 4rem;
	}

	/* The picture fills its column. Held to 40rem it stopped two thirds of the
	   way across and left a 370px hole between it and the form. */
	.home-hero .plan {
		max-width: none;
	}

	.home-hero__lede {
		font-size: 1.1875rem;
	}

	.home-hero__form {
		margin-inline: 0;
		padding: 2rem;
	}
}

/* A wider form once the picture beside it has room to spare. At 1024px a 29rem
   column left the plan 401px wide with its week tracks 27px apart. */
@media (min-width: 80em) {
	.home-hero__inner {
		grid-template-columns: minmax(0, 1fr) 29rem;
	}
}

/* Section heads ------------------------------------------------------------ */

.home-section-head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: 1.25rem 2.5rem;
	margin-bottom: 1.75rem;
}

.home-section-head__lede {
	margin-top: 0.75rem;
	max-width: 40rem;
	font-size: 1rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.home-section-head .site-search {
	flex: 1 1 18rem;
	max-width: 26rem;
}

.home-section-head .site-search__field {
	height: 3rem;
	background-color: var(--background);
}

@media (min-width: 48em) {
	.home-section-head {
		margin-bottom: 2.25rem;
	}
}

#results,
#faq,
.home-catalogue {
	scroll-margin-top: 5rem;
}

/* Catalogue ---------------------------------------------------------------- */

.home-catalogue .listing-grid {
	padding-block: 3rem;
}

@media (min-width: 48em) {
	.home-catalogue .listing-grid {
		padding-block: 4.5rem;
	}
}

/* Tiles. The code, large, on the exam's own tint with its mark beside it; the
   name on white below. The whole tile is one link, and hover raises the tint a
   step and rules the edge in the exam's strong colour. */
.home-tiles {
	display: grid;
	gap: 1rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.home-tile {
	display: flex;
}

.home-tile__link {
	flex: 1;
	display: grid;
	grid-template-rows: auto 1fr;
	background-color: var(--background);
	outline: 1px solid transparent;
	outline-offset: -1px;
	text-decoration: none;
	transition: outline-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-tile__top {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: start;
	gap: 0.375rem 1rem;
	padding: 1.5rem;
	background-color: var(--hue-tint);
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-tile__code {
	grid-column: 1;
	font-family: var(--font-mono);
	font-size: 1.5rem;
	line-height: 1.15;
	font-weight: 600;
	letter-spacing: -0.03em;
	color: var(--hue-ink);
	overflow-wrap: anywhere;
}

.home-tile__facts {
	grid-column: 1;
	font-size: 0.8125rem;
	line-height: 1.4;
	font-variant-numeric: tabular-nums;
	color: var(--hue-ink);
}

/* Nine cells of graph paper, some lit — the exam's mark. */
.home-tile__glyph {
	grid-column: 2;
	grid-row: 1 / span 2;
	display: grid;
	grid-template-columns: repeat(3, 0.625rem);
	gap: 3px;
}

.home-tile__glyph > span {
	width: 0.625rem;
	height: 0.625rem;
	background-color: color-mix(in oklab, var(--hue-strong) 20%, transparent);
}

.home-tile__glyph > .is-on {
	background-color: var(--hue-strong);
}

.home-tile__body {
	display: grid;
	grid-template-rows: 1fr auto;
	gap: 1.25rem;
	padding: 1.25rem 1.5rem 1.5rem;
}

.home-tile__name {
	font-size: 1.0625rem;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: -0.015em;
	color: var(--foreground);
	text-wrap: balance;
}

.home-tile__go,
.home-unlisted__go {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.4;
	font-weight: 600;
	color: var(--hue-ink, var(--brand));
}

.home-tile__arrow {
	width: 1rem;
	height: 1rem;
	flex: none;
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-tile__link:hover,
.home-tile__link:focus-visible {
	outline-color: var(--hue-strong);
}

.home-tile__link:hover .home-tile__top,
.home-tile__link:focus-visible .home-tile__top {
	background-color: var(--hue-soft);
}

.home-tile__link:hover .home-tile__arrow,
.home-unlisted__link:hover .home-tile__arrow {
	transform: translateX(0.25rem);
}

@media (min-width: 40em) {
	.home-tiles {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 64em) {
	.home-tiles {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.home-tile__top {
		padding: 1.75rem;
	}

	.home-tile__body {
		padding: 1.25rem 1.75rem 1.75rem;
	}
}

/* The empty slot at the end of the grid: a dashed edge where a tile would be. */
.home-unlisted {
	display: flex;
}

.home-unlisted__link {
	flex: 1;
	display: grid;
	grid-template-rows: auto auto 1fr auto;
	gap: 0.75rem;
	width: 100%;
	padding: 1.5rem;
	border-width: 1px;
	border-style: dashed;
	border-color: var(--ds-blue-500);
	text-decoration: none;
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-unlisted__link:hover,
.home-unlisted__link:focus-visible {
	border-style: solid;
	border-color: var(--brand);
	background-color: var(--ds-blue-100);
}

.home-unlisted__mark {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	background-color: var(--ds-blue-200);
	font-size: 1.25rem;
	line-height: 1;
	font-weight: 400;
	color: var(--brand);
}

.home-unlisted__title {
	font-size: 1.125rem;
	line-height: 1.35;
	font-weight: 600;
	letter-spacing: -0.015em;
	color: var(--foreground);
}

.home-unlisted__body {
	align-self: start;
	font-size: 0.875rem;
	line-height: 1.6;
	color: var(--muted-foreground);
}

.home-unlisted__link:hover .loop-card__arrow {
	transform: translateX(0.25rem);
}

@media (min-width: 64em) {
	.home-unlisted__link {
		padding: 1.75rem;
	}
}

.home-catalogue__all {
	margin-top: 1.75rem;
}

.home-catalogue__all a {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	font-size: 0.9375rem;
	font-weight: 600;
	color: var(--brand);
}

.home-catalogue__arrow {
	width: 1rem;
	height: 1rem;
	flex: none;
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-catalogue__all a:hover .home-catalogue__arrow {
	transform: translateX(0.25rem);
}

/* How it works ------------------------------------------------------------- */

.home-steps__list {
	display: grid;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* One ruled line, broken into three, with the accent marking where each step
   starts. On a desktop the rules meet across the columns and read as a single
   timeline; on a phone each step keeps its own. */
.home-step {
	position: relative;
	padding-block: 1.5rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-400);
}

.home-step::before {
	content: "";
	position: absolute;
	top: -2px;
	left: 0;
	width: 2.5rem;
	height: 3px;
	background-color: var(--hue-strong, var(--brand));
}

/* Geist, not Geist Mono: the mono face slashes its zero. Each step in the hue
   of the plan phase it matches, so the sequence reads in colour as well. */
.home-step__n {
	display: block;
	font-size: 2.5rem;
	line-height: 1;
	font-weight: 300;
	letter-spacing: -0.04em;
	font-variant-numeric: tabular-nums;
	color: var(--hue-strong, var(--ds-blue-600));
}

.home-step__title {
	margin-top: 1rem;
	font-size: 1.125rem;
	line-height: 1.35;
	font-weight: 600;
	letter-spacing: -0.015em;
}

.home-step__body {
	margin-top: 0.5rem;
	max-width: 22rem;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--muted-foreground);
}

.btn.home-steps__go {
	width: auto;
	margin-top: 1.5rem;
	gap: 0.75rem;
	padding-inline: 1.5rem;
}

@media (min-width: 48em) {
	.home-steps__list {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.home-step {
		padding-right: 2.5rem;
	}

	.home-step__n {
		font-size: 3.25rem;
	}

	.btn.home-steps__go {
		margin-top: 2rem;
	}
}

/* Results ------------------------------------------------------------------ */

.home-results {
	background-color: var(--ds-gray-200);
}

/* On the grey field the white edge is the edge, as with the catalogue cards. */
.home-results .wct-card {
	border-width: 0;
}

.home-results .wct-grid {
	margin-top: 0;
}

.home-results__exam {
	align-self: flex-start;
	padding-inline: 0.5rem;
	padding-block: 0.25rem;
	background-color: var(--hue-tint, var(--ds-blue-200));
	font-family: var(--font-mono);
	font-size: 0.75rem;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--hue-ink, var(--brand));
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-results__exam:hover {
	background-color: var(--hue-soft, var(--ds-blue-300));
}

.home-results__tick {
	width: 0.875rem;
	height: 0.875rem;
	flex: none;
	color: var(--brand);
}

/* Closing band and bar ----------------------------------------------------- */

.cta-bar__title {
	font-size: 0.875rem;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

/* Closing band ------------------------------------------------------------- */

/* The last ask, in the brand's brightest usable blue, with the staircase of lit
   cells climbing to a ready tick on the right. Text and button stack on the left
   so the picture has the right half to itself. */
.home-close {
	background-color: var(--ds-blue-800);
	color: var(--night-foreground);
}

.home-close .listing-cta__inner {
	position: relative;
	isolation: isolate;
	grid-template-columns: minmax(0, 1fr);
	justify-items: start;
}

.home-close .band__title {
	max-width: 36rem;
	color: var(--night-foreground);
}

.home-close .listing-cta__body {
	color: var(--night-muted);
}

.home-close .btn--primary {
	background-color: var(--background);
	color: var(--brand);
}

.home-close .btn--primary:hover {
	background-color: var(--highlight);
	color: var(--ds-blue-1000);
}

.cells--close {
	display: none;
}

.cell--right {
	left: auto;
	right: calc(var(--x) * 2.5rem + var(--shell-pad));
	top: calc(var(--y) * 2.5rem + 1rem);
}

/* The top of the staircase: not a colour but an outline, with the tick in it. */
.cell--ready {
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: transparent;
	border-width: 1px;
	border-color: var(--highlight);
	color: var(--highlight);
}

.cell__icon {
	width: 1.25rem;
	height: 1.25rem;
}

@media (min-width: 48em) {
	.cells--close {
		display: block;
	}
}

/* 20. Live search ------------------------------------------------------------
   The list that opens under every search field as you type. It floats over the
   page, so it takes the one edge treatment the theme uses for floating things —
   a hairline and a surface, no shadow — plus a rule of the accent along the top
   so it reads as attached to the field above it. Each result carries its exam's
   colour, the same hue as its tile on the homepage.
   ------------------------------------------------------------------------ */

.search-pop {
	position: absolute;
	top: calc(100% + 0.375rem);
	left: 0;
	right: 0;
	z-index: 40;
	max-height: min(70vh, 30rem);
	overflow-y: auto;
	overscroll-behavior: contain;
	background-color: var(--background);
	border-width: 1px;
	border-top-width: 2px;
	border-color: var(--ds-gray-500);
	border-top-color: var(--brand);
	color: var(--foreground);
	text-align: left;
}

/* Wide enough in the header for a full certification name on one or two lines,
   never wider than the screen. */
.site-header .search-pop {
	min-width: min(34rem, calc(100vw - 2 * var(--shell-pad)));
}

.search-pop__item {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: start;
	gap: 0.875rem;
	padding-inline: 1rem;
	padding-block: 0.75rem;
	text-decoration: none;
	transition: background-color 0.1s cubic-bezier(0.4, 0, 0.2, 1);
}

.search-pop__item + .search-pop__item {
	border-top-width: 1px;
	border-color: var(--ds-gray-300);
}

.search-pop__item[aria-selected="true"] {
	background-color: var(--hue-tint);
}

.search-pop__code {
	margin-top: 0.0625rem;
	padding-inline: 0.5rem;
	padding-block: 0.25rem;
	background-color: var(--hue-tint);
	font-family: var(--font-mono);
	font-size: 0.75rem;
	line-height: 1.3;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--hue-ink);
	white-space: nowrap;
}

.search-pop__item[aria-selected="true"] .search-pop__code {
	background-color: var(--hue-soft);
}

.search-pop__text {
	display: grid;
	gap: 0.1875rem;
	min-width: 0;
}

.search-pop__name {
	font-size: 0.875rem;
	line-height: 1.4;
	font-weight: 500;
	color: var(--foreground);
}

.search-pop__facts {
	font-size: 0.75rem;
	line-height: 1.4;
	font-variant-numeric: tabular-nums;
	color: var(--muted-foreground);
}

/* The matched letters, in the homepage's warm highlight. */
.search-pop mark {
	background-color: color-mix(in oklab, var(--highlight) 55%, transparent);
	color: inherit;
}

.search-pop__footer:empty {
	display: none;
}

.search-pop__all {
	display: block;
	padding-inline: 1rem;
	padding-block: 0.75rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-300);
	font-size: 0.8125rem;
	font-weight: 600;
	color: var(--brand);
}

.search-pop__all:hover,
.search-pop__all:focus-visible {
	background-color: var(--ds-blue-100);
}

.search-pop__empty {
	padding: 1rem;
}

.search-pop__empty-title {
	font-size: 0.875rem;
	line-height: 1.4;
	font-weight: 600;
	overflow-wrap: anywhere;
}

.search-pop__empty-hint {
	margin-top: 0.25rem;
	padding: 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

.search-pop__footer > .search-pop__empty-hint {
	padding: 1rem;
	margin: 0;
}

.search-pop__ask {
	display: inline-block;
	margin-top: 0.625rem;
	font-size: 0.8125rem;
	font-weight: 600;
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 4px;
}

/* Waiting: a hairline of the accent running along the foot of the field, only
   shown when the answer takes long enough to notice. */
.site-search.is-loading::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 2px;
	background-color: var(--brand);
	transform-origin: left center;
}

@media (prefers-reduced-motion: no-preference) {
	.site-search.is-loading::after {
		animation: search-load 0.9s cubic-bezier(0.4, 0, 0.2, 1) infinite;
	}

	@keyframes search-load {
		from {
			transform: scaleX(0);
		}

		to {
			transform: scaleX(1);
			opacity: 0.2;
		}
	}
}

/* 21. Standing pages (About, Contact, FAQ, legal) ---------------------------
   A designed hero over one legible column of prose. The hero is the site's
   quiet grey band — not the homepage's night surface, which is the front door's
   alone — and the body is the reading measure the theme uses everywhere text is
   meant to be read rather than scanned.
   ------------------------------------------------------------------------ */

.page-hero {
	background-color: var(--ds-gray-200);
	border-bottom-width: 1px;
}

.page-hero__inner {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 3rem 2.5rem;
}

.page-hero__eyebrow {
	color: var(--brand);
}

.page-hero__title {
	margin-top: 0.75rem;
	max-width: 20ch;
	font-size: clamp(2rem, 1.3rem + 2.4vw, 3rem);
	line-height: 1.05;
	font-weight: 700;
	letter-spacing: -0.03em;
	text-wrap: balance;
}

.page-hero__lede {
	margin-top: 1rem;
	max-width: 44rem;
	font-size: 1.0625rem;
	line-height: 1.625;
	color: var(--muted-foreground);
	text-wrap: pretty;
}

.page-hero__meta {
	margin-top: 1.25rem;
	font-size: 0.8125rem;
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--muted-foreground);
}

@media (min-width: 48em) {
	.page-hero__inner {
		padding-block: 4rem 3rem;
	}
}

.page-body__inner {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 3rem;
}

@media (min-width: 48em) {
	.page-body__inner {
		padding-block: 4rem;
	}
}

/* With a contents list, two columns from 64em: the list sits alongside the
   prose and sticks while it scrolls. Below that it stacks above the text. */
@media (min-width: 64em) {
	.page-body__inner--toc {
		display: grid;
		grid-template-columns: 15rem minmax(0, 1fr);
		gap: 4rem;
		align-items: start;
	}
}

.page-toc {
	margin-bottom: 2.5rem;
}

@media (min-width: 64em) {
	.page-toc {
		position: sticky;
		top: 6rem;
		margin-bottom: 0;
	}
}

.page-toc__label {
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--muted-foreground);
}

.page-toc__list {
	margin: 0.875rem 0 0;
	padding: 0;
	list-style: none;
	border-left-width: 1px;
	border-color: var(--ds-gray-300);
}

.page-toc__list li {
	list-style: none;
}

.page-toc__list a {
	display: block;
	padding-block: 0.375rem;
	padding-left: 1rem;
	margin-left: -1px;
	border-left-width: 1px;
	border-color: transparent;
	font-size: 0.875rem;
	line-height: 1.4;
	color: var(--muted-foreground);
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.page-toc__list a:hover {
	color: var(--brand);
	border-color: var(--brand);
}

/* The reading column. One measure, and the vertical rhythm the rest of the
   theme uses — this is where whole paragraphs are read, so it is set for that
   and nothing else. */
.prose {
	max-width: 44rem;
	font-size: 1rem;
	line-height: 1.7;
	color: var(--foreground);
}

.prose > * + * {
	margin-top: 1.25rem;
}

.prose h2 {
	margin-top: 3rem;
	padding-top: 2rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-300);
	font-size: 1.375rem;
	line-height: 1.25;
	font-weight: 700;
	letter-spacing: -0.02em;
	scroll-margin-top: 6rem;
}

.prose > h2:first-child {
	margin-top: 0;
	padding-top: 0;
	border-top-width: 0;
}

.prose h3 {
	margin-top: 2rem;
	font-size: 1.0625rem;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.prose h2 + *,
.prose h3 + * {
	margin-top: 1rem;
}

.prose a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-thickness: 1px;
}

.prose a:hover {
	text-decoration-thickness: 2px;
}

.prose strong {
	font-weight: 600;
	color: var(--foreground);
}

.prose ul,
.prose ol {
	padding-left: 1.5rem;
}

/* The reset strips list markers everywhere; prose wants them back. Only on
   lists an editor writes — unclassed (classic editor) or core's list block —
   so block markup that uses a list for layout keeps core's own styling. */
.prose ul:where(:not([class]), .wp-block-list) {
	list-style: disc;
}

.prose ol:where(:not([class]), .wp-block-list) {
	list-style: decimal;
}

.prose :where(ul, ol) ul:where(:not([class]), .wp-block-list) {
	list-style: circle;
}

.prose li + li {
	margin-top: 0.5rem;
}

.prose li::marker {
	color: var(--muted-foreground);
}

.prose blockquote {
	border-left-width: 3px;
	border-color: var(--brand);
	padding-left: 1.25rem;
	color: var(--muted-foreground);
}

/* FAQ page. The accordion is the product page's, reused as-is; only the measure
   and the space above it are set here. */
.page-faq__intro {
	margin-bottom: 2.5rem;
}

.page-faq__list {
	max-width: 48rem;
}

/* Contact page. The channels as coloured cards, in the homepage's hues; the code
   tile grammar, applied to a way of reaching someone. */
.contact__intro {
	margin-bottom: 2.5rem;
}

.contact-methods {
	display: grid;
	gap: 1rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.contact-method {
	display: flex;
}

.contact-method__link {
	flex: 1;
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	grid-template-rows: auto auto;
	column-gap: 1rem;
	row-gap: 0.25rem;
	padding: 1.5rem;
	background-color: var(--hue-tint);
	outline: 1px solid transparent;
	outline-offset: -1px;
	text-decoration: none;
	transition: outline-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.contact-method__link:hover,
.contact-method__link:focus-visible {
	outline-color: var(--hue-strong);
}

.contact-method__icon {
	grid-row: 1 / 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	background-color: var(--hue-strong);
	color: oklch(1 0 0);
}

.contact-method__icon svg {
	width: 1.25rem;
	height: 1.25rem;
}

.contact-method__label {
	align-self: end;
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--hue-ink);
}

.contact-method__value {
	font-size: 1.0625rem;
	line-height: 1.3;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
	overflow-wrap: anywhere;
}

.contact-method__note {
	grid-column: 2;
	margin-top: 0.375rem;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

@media (min-width: 40em) {
	.contact-methods {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	/* An odd card out spans the row rather than leaving half of it empty. */
	.contact-method:last-child:nth-child(odd) {
		grid-column: 1 / -1;
	}
}

/* Email, WhatsApp and text: one row of three once there is room for it. */
@media (min-width: 64em) {
	.contact-methods:has(> :nth-child(3):last-child) {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.contact-methods:has(> :nth-child(3):last-child) > .contact-method:last-child {
		grid-column: auto;
	}
}

/* The certification form, on the grey band that closes the contact page. */
.contact-enquiry {
	background-color: var(--ds-gray-200);
	border-top-width: 1px;
}

/* One column on phones, sized to the screen. Left implicit, the column grows
   to the form's minimum content width and pushes the page sideways. */
.contact-enquiry__inner {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 2rem;
	align-items: start;
}

.contact-enquiry__lede {
	margin-top: 0.75rem;
	max-width: 34rem;
	font-size: 1rem;
	line-height: 1.625;
	color: var(--muted-foreground);
}

.contact-enquiry__form {
	background-color: var(--background);
	border-top-width: 4px;
	border-color: var(--highlight);
	padding: 1.75rem;
}

.contact-enquiry__form .home-enquiry {
	max-width: none;
}

/* The band's own heading already names the form, so the form's heading and
   lede stand down here. The sent state has neither class and keeps its own. */
.contact-enquiry__form .home-enquiry__title,
.contact-enquiry__form .home-enquiry__title + .enquiry__lede {
	display: none;
}

.contact-enquiry__form .home-enquiry__title ~ .enquiry__form {
	margin-top: 0;
}

/* What happens after the form is sent: three hairline rows, each keyed by a
   square number tile in its own hue, so the column beside the form carries
   the reassurance rather than empty grey. */
.contact-next {
	margin: 2rem 0 0;
	padding: 0;
	list-style: none;
	border-bottom-width: 1px;
	border-color: var(--ds-gray-400);
}

.contact-next__step {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	column-gap: 1.25rem;
	row-gap: 0.25rem;
	padding-block: 1.25rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-400);
}

.contact-next__n {
	grid-row: 1 / 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	background-color: var(--hue-strong);
	color: oklch(1 0 0);
	font-size: 1.125rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

.contact-next__title {
	align-self: end;
	font-size: 1.0625rem;
	line-height: 1.3;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

.contact-next__body {
	grid-column: 2;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--muted-foreground);
}

@media (min-width: 56em) {
	.contact-enquiry__inner {
		grid-template-columns: minmax(0, 1fr) minmax(0, 36rem);
		gap: 4rem;
		align-items: center;
	}

	.contact-enquiry__form {
		padding: 2.25rem;
	}
}

@media (min-width: 80em) {
	.contact-enquiry__inner {
		gap: 6rem;
	}

	.band__title.contact-enquiry__title {
		font-size: 2.25rem;
	}
}


/* 22. Blog ------------------------------------------------------------------
   Posts and their archives. The standing pages' grey hero and hairlines, with
   the colour carried by topic: each category has a hue, and a post wears it in
   its header, its card and its topic chip, so the blog reads as a set of
   subjects rather than one grey feed. Core block markup is restyled into the
   same flat, square language — no pills, no gradients, no shadows.
   ------------------------------------------------------------------------ */

.post-hero__sep {
	margin-inline: 0.375rem;
	opacity: 0.6;
}

/* The blog link in the header stays marked while reading a post or an archive,
   using the class core gives the posts page in that case. */
.site-nav .current_page_parent > a {
	color: var(--foreground);
}

/* Homepage: the three newest posts, on grey between the white questions and
   the blue closing band, so the surfaces keep alternating. */
.home-blog {
	background-color: var(--ds-gray-200);
}

.home-blog__all {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--brand);
}

.home-blog__all:hover {
	text-decoration: underline;
	text-underline-offset: 4px;
}

.home-blog__arrow {
	width: 1rem;
	height: 1rem;
}

/* Three across, however wide the band — the shared grid's auto-fill would
   leave an empty fourth track at desktop widths. */
@media (min-width: 64em) {
	.post-grid.home-blog__grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.page-hero__eyebrow a:hover,
.post-hero__eyebrow a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* Topics: a row of chips under the hero, each in its category's hue. */
.blog-topics {
	border-bottom-width: 1px;
}

.blog-topics__list {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 1rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.blog-topic {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	min-height: 2.25rem;
	padding-inline: 0.875rem;
	border-width: 1px;
	border-color: var(--ds-gray-400);
	font-size: 0.875rem;
	font-weight: 500;
	color: var(--foreground);
	transition: border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
		background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.blog-topic:hover {
	border-color: var(--brand);
}

.blog-topic[aria-current="page"] {
	background-color: var(--brand);
	border-color: var(--brand);
	color: var(--brand-foreground);
}

.blog-topic--hued {
	background-color: var(--hue-tint);
	border-color: transparent;
	color: var(--hue-ink);
}

.blog-topic--hued:hover {
	border-color: var(--hue-strong);
}

/* The selected topic deepens rather than inverts: ink on the soft step stays
   AA in every hue, where white on amber would not. */
.blog-topic--hued[aria-current="page"] {
	background-color: var(--hue-soft);
	border-color: var(--hue-strong);
	color: var(--hue-ink);
}

.blog-topic__count {
	font-size: 0.75rem;
	font-variant-numeric: tabular-nums;
	opacity: 0.7;
}

/* Cards. */
.post-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
	gap: 3rem 1.5rem;
}

.post-card {
	position: relative;
	display: flex;
	flex-direction: column;
}

.post-card__media {
	position: relative;
	aspect-ratio: 16 / 9;
	overflow: clip;
	background-color: var(--hue-tint);
}

.post-card__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* No featured image: a square of graph paper in the topic's hue, ruled the way
   the homepage hero is, with a few lit cells. */
.post-card__paper {
	position: absolute;
	inset: 0;
	background-image:
		linear-gradient(to right, var(--hue-soft) 1px, transparent 1px),
		linear-gradient(to bottom, var(--hue-soft) 1px, transparent 1px);
	background-size: 2.5rem 2.5rem;
	background-position: -1px -1px;
}

.post-card__cell {
	position: absolute;
	left: calc(var(--x) * 2.5rem);
	top: calc(var(--y) * 2.5rem);
	width: calc(2.5rem - 1px);
	height: calc(2.5rem - 1px);
	background-color: var(--hue-strong);
	opacity: var(--o, 0.6);
}

/* The accent that marks where each card's text starts, as the homepage steps do. */
.post-card__body {
	position: relative;
	flex: 1;
	display: flex;
	flex-direction: column;
	padding-top: 1.25rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-400);
}

.post-card__body::before {
	content: "";
	position: absolute;
	top: -2px;
	left: 0;
	width: 2.5rem;
	height: 3px;
	background-color: var(--hue-strong);
}

.post-card__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.25rem 0.75rem;
	font-size: 0.8125rem;
	line-height: 1.4;
	color: var(--muted-foreground);
}

/* Above the stretched title link, so it stays its own target. */
.post-card__term {
	position: relative;
	z-index: 1;
	font-size: 0.6875rem; /* 11px */
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--hue-ink);
}

.post-card__term:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.post-card__flag {
	padding: 0.125rem 0.5rem;
	background-color: var(--highlight);
	font-size: 0.6875rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--foreground);
}

.post-card__title {
	margin-top: 0.625rem;
	font-size: 1.25rem;
	line-height: 1.3;
	font-weight: 600;
	letter-spacing: -0.015em;
	text-wrap: balance;
}

.post-card__link::after {
	content: "";
	position: absolute;
	inset: 0;
}

.post-card:hover .post-card__link {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 4px;
}

.post-card__excerpt {
	margin-top: 0.625rem;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--muted-foreground);
	text-wrap: pretty;
}

.post-card__foot {
	margin-top: auto;
	padding-top: 1rem;
	font-size: 0.8125rem;
	color: var(--muted-foreground);
}

/* The lead card on the first page of the blog spans the grid. */
.post-card--featured {
	grid-column: 1 / -1;
}

@media (min-width: 56em) {
	.post-card--featured {
		display: grid;
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		gap: 2.5rem;
		align-items: center;
		padding-bottom: 3rem;
		border-bottom-width: 1px;
		border-color: var(--ds-gray-400);
	}

	.post-card--featured .post-card__body {
		padding-top: 0;
		border-top-width: 0;
	}

	.post-card--featured .post-card__body::before {
		top: -1.5rem;
	}

	.post-card--featured .post-card__title {
		font-size: clamp(1.625rem, 1rem + 1.4vw, 2.25rem);
		line-height: 1.15;
		letter-spacing: -0.025em;
	}

	.post-card--featured .post-card__excerpt {
		font-size: 1.0625rem;
	}
}

.blog-pagination {
	margin-top: 3.5rem;
}

.blog-pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.blog-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.5rem;
	height: 2.5rem;
	padding-inline: 0.75rem;
	border-width: 1px;
	border-color: var(--ds-gray-400);
	font-size: 0.875rem;
	font-variant-numeric: tabular-nums;
}

.blog-pagination a.page-numbers:hover {
	border-color: var(--brand);
	color: var(--brand);
}

.blog-pagination .current {
	background-color: var(--brand);
	border-color: var(--brand);
	color: var(--brand-foreground);
}

.blog-pagination .dots {
	border-color: transparent;
}

.blog-empty__title {
	font-size: 1.375rem;
	line-height: 1.25;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.blog-empty__body {
	margin-top: 0.75rem;
}

/* A post: the header in its topic's tint, on the reading column's measure. */
.post-hero {
	background-color: var(--hue-tint);
	border-bottom-width: 1px;
	border-color: var(--hue-soft);
}

.post-hero__inner {
	max-width: calc(44rem + 2 * var(--shell-pad));
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 3rem 2.5rem;
}

.post-hero--has-cover .post-hero__inner {
	padding-bottom: 6rem;
}

@media (min-width: 48em) {
	.post-hero__inner {
		padding-block: 4.5rem 3rem;
	}

	.post-hero--has-cover .post-hero__inner {
		padding-bottom: 8rem;
	}
}

.post-hero__eyebrow {
	color: var(--hue-ink);
}

.post-hero__title {
	margin-top: 0.875rem;
	font-size: clamp(2rem, 1.4rem + 2.2vw, 3rem);
	line-height: 1.08;
	font-weight: 700;
	letter-spacing: -0.03em;
	text-wrap: balance;
}

.post-hero__lede {
	margin-top: 1rem;
	font-size: 1.125rem;
	line-height: 1.6;
	color: var(--muted-foreground);
	text-wrap: pretty;
}

.post-byline {
	margin-top: 1.75rem;
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

.post-byline__avatar {
	width: 2.5rem;
	height: 2.5rem;
	flex: none;
	background-color: var(--hue-soft);
}

.post-byline__text {
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
	font-size: 0.875rem;
	line-height: 1.4;
}

.post-byline__author {
	font-weight: 600;
	overflow-wrap: anywhere;
}

.post-byline__author a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.post-byline__meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0 0.5rem;
	color: var(--muted-foreground);
}

/* The cover rides up over the bottom of the header. */
.post-cover {
	max-width: calc(72rem + 2 * var(--shell-pad));
	margin-inline: auto;
	margin-top: -4rem;
	padding-inline: var(--shell-pad);
}

@media (min-width: 48em) {
	.post-cover {
		margin-top: -5.5rem;
	}
}

.post-cover__img {
	width: 100%;
	background-color: var(--ds-gray-200);
}

.post-cover__caption {
	max-width: 44rem;
	margin-inline: auto;
	margin-top: 0.625rem;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

/* The body is a size container, so wide and full blocks measure against the
   space actually available — never 100vw, which counts the scrollbar and would
   scroll the page sideways. */
.post-body {
	container-type: inline-size;
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 3rem 4rem;
}

.post-body__content {
	margin-inline: auto;
}

.post-body__content::after {
	content: "";
	display: table;
	clear: both;
}

.post-body__content > .alignwide,
.post-body__content > .alignfull {
	margin-block: 2.5rem;
	max-width: none;
}

.post-body__content > .alignwide {
	width: min(64rem, 100cqi);
	margin-inline: calc((100% - min(64rem, 100cqi)) / 2);
}

.post-body__content > .alignfull {
	width: 100cqi;
	margin-inline: calc((100% - 100cqi) / 2);
}

.prose .alignwide img,
.prose .alignfull img {
	width: 100%;
}

.prose .aligncenter {
	margin-inline: auto;
}

.prose .alignleft {
	float: left;
	max-width: 50%;
	margin: 0.375rem 1.5rem 1rem 0;
}

.prose .alignright {
	float: right;
	max-width: 50%;
	margin: 0.375rem 0 1rem 1.5rem;
}

@media (max-width: 39.99em) {
	.prose .alignleft,
	.prose .alignright {
		float: none;
		max-width: 100%;
		margin-inline: 0;
	}
}

.prose h2,
.prose h3,
.prose h4,
.prose .wp-block-quote,
.prose .wp-block-pullquote,
.prose .wp-block-table {
	clear: both;
}

.prose h4 {
	margin-top: 1.75rem;
	font-size: 1rem;
	line-height: 1.4;
	font-weight: 600;
}

.prose figcaption {
	margin-top: 0.625rem;
	font-size: 0.8125rem;
	line-height: 1.5;
	text-align: left;
	color: var(--muted-foreground);
}

/* Core draws gallery captions as white text on a dark gradient over the image.
   Here they sit under it, like every other caption — which means undoing the
   flex-grow core gives an overlaid caption, or it takes the whole figure and a
   cropped image collapses to nothing. Cropped images get their height from a
   ratio instead, so a row stays even. The :not(#individual-image) matches
   core's own selector weight. */
.prose .wp-block-gallery.has-nested-images figure.wp-block-image figcaption {
	position: static;
	flex: none;
	max-height: none;
	padding: 0;
	margin-top: 0.5rem;
	background: none;
	font-size: 0.8125rem;
	text-align: left;
	color: var(--muted-foreground);
	text-shadow: none;
}

.prose .wp-block-gallery.has-nested-images figure.wp-block-image:has(figcaption)::before {
	content: none;
}

.prose .wp-block-gallery.has-nested-images.is-cropped figure.wp-block-image:not(#individual-image) img {
	flex: none;
	height: auto;
	aspect-ratio: 4 / 3;
}

.prose .wp-block-quote p {
	font-size: 1.125rem;
	line-height: 1.55;
}

.prose cite {
	display: block;
	margin-top: 0.5rem;
	font-size: 0.8125rem;
	font-style: normal;
	color: var(--muted-foreground);
}

.prose .wp-block-pullquote {
	margin-block: 2.5rem;
	padding: 2rem 0;
	border-top: 3px solid var(--highlight);
	border-bottom: 1px solid var(--ds-gray-400);
	text-align: left;
	font-size: 1.5rem;
	line-height: 1.35;
}

.prose .wp-block-pullquote blockquote {
	padding: 0;
	border: 0;
	color: var(--foreground);
}

.prose .wp-block-pullquote p {
	font-size: inherit;
	line-height: inherit;
	font-weight: 600;
	letter-spacing: -0.02em;
}

.prose .wp-block-table {
	overflow-x: auto;
}

.prose .wp-block-table table {
	width: 100%;
	font-size: 0.9375rem;
	line-height: 1.5;
}

.prose .wp-block-table thead {
	border-bottom: 0;
}

.prose .wp-block-table th,
.prose .wp-block-table td {
	padding: 0.625rem 0.75rem 0.625rem 0;
	border: 0;
	border-bottom: 1px solid var(--ds-gray-400);
	text-align: left;
	vertical-align: top;
}

.prose .wp-block-table th {
	font-size: 0.6875rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
	border-bottom-color: var(--foreground);
}

.prose pre {
	padding: 1rem 1.25rem;
	overflow-x: auto;
	background-color: var(--night-surface);
	color: var(--night-foreground);
	font-size: 0.875rem;
	line-height: 1.6;
}

.prose pre code {
	white-space: pre;
}

.prose :not(pre) > code {
	padding: 0.0625rem 0.375rem;
	background-color: var(--ds-gray-200);
	font-size: 0.875em;
}

.prose hr,
.prose .wp-block-separator {
	margin-block: 2.5rem;
	border: 0;
	border-top: 1px solid var(--ds-gray-400);
}

.prose .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	min-height: 3.25rem;
	padding: 0 1.5rem;
	border-radius: 0;
	background-color: var(--brand);
	color: var(--brand-foreground);
	font-size: 0.875rem;
	font-weight: 600;
	text-decoration: none;
}

.prose .wp-block-button__link:hover {
	background-color: var(--ds-blue-1000);
}

/* Split pages (<!--nextpage-->). */
.page-links {
	clear: both;
	margin-top: 2.5rem;
	padding-top: 1.5rem;
	border-top-width: 1px;
	border-color: var(--ds-gray-300);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
}

.page-links__label {
	margin-right: 0.5rem;
	font-size: 0.6875rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--muted-foreground);
}

.page-links .post-page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.25rem;
	height: 2.25rem;
	border-width: 1px;
	border-color: var(--ds-gray-400);
	font-size: 0.875rem;
	color: var(--foreground);
	text-decoration: none;
}

.page-links a.post-page-numbers:hover {
	border-color: var(--brand);
	color: var(--brand);
}

.page-links .post-page-numbers.current {
	background-color: var(--brand);
	border-color: var(--brand);
	color: var(--brand-foreground);
}

.post-footer {
	max-width: 44rem;
	margin-inline: auto;
	margin-top: 3rem;
	display: grid;
	gap: 2rem;
}

.post-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.post-tag {
	display: inline-flex;
	align-items: center;
	min-height: 2rem;
	padding-inline: 0.75rem;
	background-color: var(--ds-gray-200);
	font-size: 0.8125rem;
	color: var(--foreground);
}

.post-tag::before {
	content: "#";
	margin-right: 0.125rem;
	color: var(--muted-foreground);
}

.post-tag:hover {
	background-color: var(--ds-gray-300);
}

.post-author {
	display: flex;
	gap: 1rem;
	padding: 1.5rem;
	background-color: var(--ds-gray-200);
}

.post-author__avatar {
	width: 3.5rem;
	height: 3.5rem;
	flex: none;
}

.post-author__name {
	margin-top: 0.25rem;
	font-weight: 600;
}

.post-author__bio {
	margin-top: 0.375rem;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--muted-foreground);
}

.post-edit a {
	font-size: 0.8125rem;
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* Previous / next article. */
.post-nav {
	border-top-width: 1px;
}

.post-nav .nav-links {
	max-width: var(--shell-max);
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	display: grid;
}

.post-nav a {
	display: flex;
	flex-direction: column;
	gap: 0.375rem;
	padding-block: 2rem;
}

.post-nav .nav-previous + .nav-next {
	border-top-width: 1px;
}

.post-nav__label {
	font-size: 0.6875rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var(--muted-foreground);
}

.post-nav__title {
	font-size: 1.125rem;
	line-height: 1.35;
	font-weight: 600;
	letter-spacing: -0.01em;
	text-wrap: balance;
}

.post-nav a:hover .post-nav__title {
	color: var(--brand);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 4px;
}

@media (min-width: 40em) {
	.post-nav .nav-links {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.post-nav .nav-next {
		grid-column: 2;
		text-align: right;
	}

	.post-nav .nav-previous + .nav-next {
		border-top-width: 0;
		border-left-width: 1px;
	}

	.post-nav .nav-previous a {
		padding-right: 2rem;
	}

	.post-nav .nav-next a {
		align-items: flex-end;
		padding-left: 2rem;
	}
}

/* Comments: core's markup on the grey band, cards like the product reviews. */
.post-comments {
	background-color: var(--ds-gray-200);
	border-top-width: 1px;
}

.post-comments__inner {
	max-width: calc(44rem + 2 * var(--shell-pad));
	margin-inline: auto;
	padding-inline: var(--shell-pad);
	padding-block: 3.5rem 4rem;
}

.comments-title {
	font-size: 1.375rem;
	line-height: 1.25;
	font-weight: 700;
	letter-spacing: -0.02em;
}

.comment-list {
	margin-top: 1.5rem;
	display: grid;
	gap: 1rem;
}

.comment-list .children {
	margin-top: 1rem;
	padding-left: 1rem;
	border-left-width: 1px;
	border-color: var(--ds-gray-400);
	display: grid;
	gap: 1rem;
}

@media (min-width: 40em) {
	.comment-list .children {
		padding-left: 2rem;
	}
}

.comment-body {
	padding: 1.25rem 1.5rem;
	background-color: var(--background);
}

.bypostauthor > .comment-body {
	border-left: 3px solid var(--brand);
}

.comment-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem 1rem;
	font-size: 0.8125rem;
	line-height: 1.4;
	color: var(--muted-foreground);
}

.comment-author {
	min-width: 0;
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

.comment-author .avatar {
	width: 2.5rem;
	height: 2.5rem;
	flex: none;
	background-color: var(--ds-gray-300);
}

.comment-author .fn {
	font-size: 0.9375rem;
	font-weight: 600;
	font-style: normal;
	color: var(--foreground);
	overflow-wrap: anywhere;
}

.comment-author .says {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.comment-metadata a:hover {
	color: var(--brand);
}

.comment-metadata .edit-link {
	margin-left: 0.5rem;
}

.comment-awaiting-moderation {
	display: block;
	margin-top: 0.5rem;
	font-size: 0.8125rem;
	font-style: normal;
	color: var(--warning);
}

.comment-content {
	margin-top: 0.875rem;
	font-size: 0.9375rem;
	line-height: 1.65;
}

.comment-content > * + * {
	margin-top: 0.75rem;
}

.comment-content a,
.logged-in-as a,
.comments-pagination a,
#cancel-comment-reply-link {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.reply {
	margin-top: 0.75rem;
	font-size: 0.8125rem;
	font-weight: 600;
}

.comment-reply-link {
	color: var(--brand);
}

.comment-reply-link:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.comments-pagination .nav-links {
	margin-top: 1.5rem;
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	font-size: 0.875rem;
}

.no-comments {
	margin-top: 1.5rem;
	font-size: 0.875rem;
	color: var(--muted-foreground);
}

.comment-respond {
	margin-top: 2.5rem;
	padding: 1.5rem;
	background-color: var(--background);
	--field-border: var(--ds-gray-500);
	--field-border-hover: var(--ds-gray-700);
}

.comment-list .comment-respond {
	margin-top: 1rem;
	border-width: 1px;
	border-color: var(--ds-gray-400);
}

#cancel-comment-reply-link {
	margin-left: 0.5rem;
}

.comment-respond .comment-form {
	margin-top: 1.25rem;
	display: grid;
	gap: 1.25rem;
}

.comment-respond .comment-notes,
.comment-respond .logged-in-as,
.comment-respond .required-field-message {
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--muted-foreground);
}

.comment-respond .comment-form label {
	display: block;
	margin-bottom: 0.375rem;
	font-size: 0.6875rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--muted-foreground);
}

.comment-respond .required {
	color: var(--warning);
}

.comment-respond input[type="text"],
.comment-respond input[type="email"],
.comment-respond input[type="url"],
.comment-respond textarea {
	display: block;
	width: 100%;
	min-height: 3rem;
	padding-inline: 0.875rem;
	padding-block: 0.75rem;
	font-size: 1rem;
	line-height: 1.5;
	background-color: var(--background);
	border-width: 1px;
	border-color: var(--field-border);
	color: var(--foreground);
}

.comment-respond textarea {
	min-height: 9rem;
	resize: vertical;
}

.comment-respond input:hover,
.comment-respond textarea:hover {
	border-color: var(--field-border-hover);
}

.comment-respond input:focus,
.comment-respond textarea:focus {
	border-color: var(--brand);
}

.comment-respond input:user-invalid,
.comment-respond textarea:user-invalid {
	border-color: var(--warning);
}

.comment-respond .comment-form-cookies-consent label {
	margin-bottom: 0;
	font-size: 0.8125rem;
	font-weight: 400;
	text-transform: none;
	letter-spacing: normal;
}

.btn.comment-form__submit {
	width: auto;
}


/* 23. Product — exam topics --------------------------------------------------
   Under the specification in the evidence column (examsgrade-exam-data/
   overview.php): the exam's topics as a ruled index, each marked with the
   exam's own square in its hue (.hue--*), the mark its homepage tile carries.
   Type and hairlines do the work; no panel, no figures. */

.exam-topics {
	margin-top: 2.5rem;
}

.exam-topics .section-label {
	margin: 0 0 0.875rem;
}

.exam-topics__list {
	display: grid;
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: 1px solid var(--foreground);
}

.exam-topics__list li {
	display: grid;
	grid-template-columns: 0.5rem minmax(0, 1fr);
	align-items: baseline;
	gap: 0.875rem;
	margin: 0;
	padding: 0.875rem 0;
	border-bottom: 1px solid var(--border);
	font-size: 1rem;
	line-height: 1.4;
	font-weight: 500;
	letter-spacing: -0.01em;
	color: var(--foreground);
}

/* The exam's square, set on the first line of the name. */
.exam-topics__list li::before {
	content: "";
	width: 0.5rem;
	height: 0.5rem;
	transform: translateY(-0.0625rem);
	background-color: var(--hue-strong);
}

@media (min-width: 40em) {
	.exam-topics__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 2.5rem;
	}
}

/* A long list sits tighter, so it reads as one index rather than a page of rows. */
.exam-topics__list--long li {
	padding: 0.625rem 0;
	font-size: 0.9375rem;
}

.exam-topics__ask {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: 1.25rem;
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--brand);
	text-decoration: none;
}

.exam-topics__ask:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.exam-topics__ask-icon {
	width: 1rem;
	height: 1rem;
	transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.exam-topics__ask:hover .exam-topics__ask-icon {
	transform: translateX(0.1875rem);
}

@media (prefers-reduced-motion: reduce) {
	.exam-topics__ask-icon {
		transition: none;
	}
}
