/**
 * PropLaunch theme stylesheet.
 *
 * One hand-written file with no build step: this is the file the site loads.
 *
 *   1. Fonts                  7. Header
 *   2. Tokens                 8. Mobile menu
 *   3. Base                   9. Footer
 *   4. Layout                10. Call to action band
 *   5. Components            11. Floating booking button
 *   6. Motion                12. Pages (listing, entry, 404)
 *  13. Homepage sections, in page order
 *  14. Inner pages: blog, posts, About, Contact, legal
 *
 * Colours and fonts always come from the tokens in section 2, as do the shared
 * radii, section spacing, shadows and motion. Measurements that belong to one
 * section (a card's padding, a gap) are written in place, taken from the old
 * site. Class names follow BEM
 * (.block, .block__element, .block--modifier) and states use is- classes
 * (is-open, is-visible, is-scrolled).
 *
 * @package proplaunch
 * @author  James@ARO
 */

/* ==========================================================================
   1. Fonts
   Self-hosted variable fonts (SIL Open Font License, see assets/fonts/OFL.txt).
   The fallback faces resize Arial to each font's metrics, so text does not
   jump when the web font arrives.
   ========================================================================== */

@font-face {
	font-family: "Space Grotesk Fallback";
	src: local("Arial");
	ascent-override: 89.71%;
	descent-override: 26.62%;
	line-gap-override: 0%;
	size-adjust: 109.69%;
}

@font-face {
	font-family: "Inter Fallback";
	src: local("Arial");
	ascent-override: 90.44%;
	descent-override: 22.52%;
	line-gap-override: 0%;
	size-adjust: 107.12%;
}

@font-face {
	font-family: "JetBrains Mono Fallback";
	src: local("Arial");
	ascent-override: 75.79%;
	descent-override: 22.29%;
	line-gap-override: 0%;
	size-adjust: 134.59%;
}

@font-face {
	font-family: "Inter";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/inter-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: "Inter";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/inter-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: "JetBrains Mono";
	font-style: normal;
	font-weight: 100 800;
	font-display: swap;
	src: url("../fonts/jetbrains-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;
}

@font-face {
	font-family: "JetBrains Mono";
	font-style: normal;
	font-weight: 100 800;
	font-display: swap;
	src: url("../fonts/jetbrains-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: "Space Grotesk";
	font-style: normal;
	font-weight: 300 700;
	font-display: swap;
	src: url("../fonts/space-grotesk-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: "Space Grotesk";
	font-style: normal;
	font-weight: 300 700;
	font-display: swap;
	src: url("../fonts/space-grotesk-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;
}


/* ==========================================================================
   2. Tokens
   Text contrast is noted beside each text colour (WCAG AA needs 4.5:1 for
   body text). Borders are decorative edges, not control outlines.
   ========================================================================== */

:root {
	/* Families: a font swap is a one-line change here plus its @font-face. */
	--font-display: "Space Grotesk", "Space Grotesk Fallback", -apple-system, BlinkMacSystemFont, sans-serif;
	--font-body: "Inter", "Inter Fallback", -apple-system, BlinkMacSystemFont, sans-serif;
	--font-mono: "JetBrains Mono", "JetBrains Mono Fallback", ui-monospace, monospace;

	/* Type scale, fluid between phone and desktop widths. */
	--text-display: clamp(40px, 6.2vw, 63px);
	--text-h1: clamp(33px, 4.6vw, 46px);
	--text-h2: clamp(27px, 3.5vw, 38px);
	--text-h3: clamp(19px, 2.1vw, 23px);
	--text-lead: clamp(16px, 1.5vw, 19px);
	--text-base: 16px;
	--text-sm: 14px;
	--text-xs: 12px;

	/* Colour: the dark palette is the default. Ratios are against --color-bg. */
	--color-bg: #08090c;
	--color-bg-alt: #0b0d11;
	--color-surface: #111318;
	--color-surface-2: #171a20;
	--color-surface-3: #1f232b;
	--color-border: #22262e;
	--color-border-strong: #333b47;
	--color-hairline: #131519;
	--color-text: #edf1f6;        /* 17.6:1, safe on every dark surface */
	--color-text-muted: #98a2b0;  /* 7.7:1, safe on every dark surface */
	--color-text-dim: #7e8a98;    /* 5.7:1 on bg, 5:1 on surface-2; not on surface-3 or tints (under 4.5:1) */
	--color-accent: #3ee9a6;      /* 12.7:1 as text on dark; only a fill on light */
	--color-accent-text: #7cf5c4; /* 14.9:1, labels and highlights on dark */
	--color-accent-deep: #15c088; /* fills and gradients only */
	--color-on-accent: #04241b;   /* text on an accent fill, 10.5:1 */
	--color-glow: #3ee9a680;
	--color-glow-soft: #3ee9a624;
	--color-warn: #ffb05a;
	--color-danger: #ff6b6b;

	/* Radii. */
	--radius-xs: 6px;
	--radius-sm: 10px;
	--radius-md: 14px;
	--radius-lg: 20px;
	--radius-xl: 28px;
	--radius-pill: 999px;

	/* Layout. */
	--container: 1180px;
	--gutter: 32px;
	--header-height: 64px;
	--section-space: clamp(64px, 9vw, 116px);
	--section-space-tight: clamp(44px, 6vw, 76px);

	/* Shadows. */
	--shadow-card: inset 0 1px #ffffff0b, 0 2px 6px -2px #0006;
	--shadow-card-hover: inset 0 1px 0 #ffffff0f, 0 26px 60px -34px var(--color-glow);
	--shadow-button: 0 8px 30px -8px var(--color-glow);
	--shadow-button-hover: 0 14px 46px -8px var(--color-glow);

	/* Motion. */
	--ease: cubic-bezier(.22, 1, .36, 1);
	--ease-out: cubic-bezier(.16, 1, .3, 1);
	--ease-spring: linear(0, .006, .025 2.8%, .101 6.1%, .539 18.9%, .721 25.3%, .849, .937 34.6%, .968, .991 43.5%, 1.006, 1.017 53.4%, 1.019, 1.01 70.5%, 1.004 79.8%, 1);
	--dur-fast: .18s;
	--dur: .5s;
	--dur-slow: .8s;
}

@media (max-width: 640px) {
	:root {
		--gutter: 20px;
	}
}

/* Light sections swap the palette, and every component re-colours through
   the tokens. Accent fills stay the same; accent text darkens to stay legible. */
.section--light {
	--color-bg: #fff;
	--color-bg-alt: #f4f6fa;
	--color-surface: #fff;
	--color-surface-2: #f4f6fa;
	--color-surface-3: #edf1f6;
	--color-border: #e6eaf0;
	--color-border-strong: #d3dae4;
	--color-hairline: #edf1f6;
	--color-text: #0b0d11;        /* 19.5:1 */
	--color-text-muted: #56606c;  /* 6.4:1 on white, 5.9:1 on bg-alt */
	--color-text-dim: #6b7480;    /* 4.7:1 on white only: use muted on bg-alt */
	--color-accent-text: #0a8158; /* 4.9:1 on white, 4.5:1 on bg-alt. The old site's #0b8a5e measured 4.4:1 */
	--color-glow: #0b0d1100;
	--color-glow-soft: #15c0881a;
	--shadow-card-hover: inset 0 1px 0 #ffffff0f, 0 18px 44px -30px #0b0d1147;
}

/* ==========================================================================
   3. Base
   ========================================================================== */

*,
*::before,
*::after {
	box-sizing: border-box;
}

[hidden] {
	display: none !important;
}

html {
	scroll-padding-top: calc(var(--header-height) + 18px);
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

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

body {
	margin: 0;
	background: var(--color-bg);
	color: var(--color-text);
	font-family: var(--font-body);
	font-size: var(--text-base);
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

/* Soft accent glow at the top and bottom corner of the viewport. */
body::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -2;
	pointer-events: none;
	background:
		radial-gradient(58% 42% at 50% -8%, var(--color-glow-soft), transparent 68%),
		radial-gradient(42% 40% at 100% 102%, var(--color-glow-soft), transparent 70%);
}

/* Faint 66px grid that fades out from the top centre. */
body::after {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	opacity: .26;
	background-image:
		linear-gradient(var(--color-hairline) 1px, transparent 1px),
		linear-gradient(90deg, var(--color-hairline) 1px, transparent 1px);
	background-size: 66px 66px;
	-webkit-mask-image: radial-gradient(circle at 50% -2%, #000, #0000 70%);
	mask-image: radial-gradient(circle at 50% -2%, #000, #0000 70%);
}

/* Film grain over the whole page. */
.grain {
	position: fixed;
	inset: 0;
	z-index: 3;
	pointer-events: none;
	opacity: .05;
	mix-blend-mode: soft-light;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

h1,
h2,
h3,
h4,
h5,
h6 {
	margin: 0;
	font-family: var(--font-display);
	font-weight: 600;
	line-height: 1.06;
	letter-spacing: -.02em;
	color: var(--color-text);
}

p,
ul,
ol,
figure,
blockquote {
	margin: 0;
}

a {
	color: inherit;
}

img,
svg,
video {
	display: block;
	max-width: 100%;
}

img {
	height: auto;
}

button {
	font: inherit;
}

::selection {
	background: var(--color-accent);
	color: var(--color-on-accent);
}

:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

.section--light :focus-visible {
	outline-color: var(--color-accent-text);
}

/* The main element takes focus from the skip link but needs no ring. */
.site-main:focus {
	outline: none;
}

.skip-link {
	position: fixed;
	top: -60px;
	left: 12px;
	z-index: 200;
	padding: 10px 16px;
	border-radius: var(--radius-sm);
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-size: var(--text-sm);
	font-weight: 600;
	text-decoration: none;
	transition: top var(--dur-fast) var(--ease);
}

.skip-link:focus {
	top: 12px;
}

/* Core prints this class on pagination, post navigation and search labels. */
.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	border: 0;
	white-space: nowrap;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	top: 5px;
	left: 5px;
	z-index: 100000;
	width: auto;
	height: auto;
	padding: 15px 23px 14px;
	clip-path: none;
	background: var(--color-surface);
	color: var(--color-text);
	font-size: var(--text-sm);
	text-decoration: none;
}

.alignleft {
	float: left;
	margin: .3em 1.5em 1em 0;
}

.alignright {
	float: right;
	margin: .3em 0 1em 1.5em;
}

.aligncenter {
	display: block;
	margin-inline: auto;
}

.wp-caption {
	max-width: 100%;
}

.wp-caption-text {
	margin-top: 8px;
	color: var(--color-text-dim);
	font-size: 13px;
}

/* ==========================================================================
   4. Layout and type utilities
   ========================================================================== */

.container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/* overflow-x: clip (unlike hidden) creates no scroll container, so it keeps
   sideways entrance offsets and glows from widening the page on phones
   without affecting sticky positioning or vertical glows. */
.section {
	position: relative;
	padding: var(--section-space) 0;
	overflow-x: clip;
}

.section--tight {
	padding: var(--section-space-tight) 0;
}

.section--light {
	background: var(--color-bg);
	color: var(--color-text);
}

/* A faint accent hairline along the top and bottom of each light band. */
.section--light::before,
.section--light::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	z-index: 1;
	height: 1px;
	pointer-events: none;
	opacity: .55;
	background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--color-accent) 28%, transparent), transparent);
}

.section--light::before {
	top: 0;
}

.section--light::after {
	bottom: 0;
}

/* Dot grid behind a section, fading out towards the bottom. */
.section--dots::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: .5;
	background-image: radial-gradient(var(--color-border) 1px, transparent 1px);
	background-size: 24px 24px;
	-webkit-mask-image: radial-gradient(120% 90% at 50% 0, #000, #0000 72%);
	mask-image: radial-gradient(120% 90% at 50% 0, #000, #0000 72%);
}

.section--dots > .container {
	position: relative;
	z-index: 1;
}

.grid {
	display: grid;
	gap: 20px;
}

.grid--2 {
	grid-template-columns: repeat(2, 1fr);
}

.grid--3 {
	grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 900px) {
	.grid--2,
	.grid--3 {
		grid-template-columns: 1fr;
	}
}

/* A wrapping row of buttons or chips. */
.cluster {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
}

.h-display {
	font-size: var(--text-display);
	line-height: 1.02;
}

.h1 {
	font-size: var(--text-h1);
}

.h2 {
	font-size: var(--text-h2);
}

.h3 {
	font-size: var(--text-h3);
	line-height: 1.22;
}

.lead {
	color: var(--color-text-muted);
	font-size: var(--text-lead);
	line-height: 1.62;
}

.muted {
	color: var(--color-text-muted);
}

.balance {
	text-wrap: balance;
}

.measure {
	max-width: 62ch;
}

.mono {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   5. Components
   ========================================================================== */

/* Small mono label above a section heading, with a glowing dot. */
.eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
	letter-spacing: .18em;
	text-transform: uppercase;
}

.eyebrow::before {
	content: "";
	flex: none;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--color-accent);
	box-shadow: 0 0 12px 2px var(--color-glow);
}

/* Small mono title for a card, column or strip (not above a section heading). */
.kicker {
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
	letter-spacing: .15em;
	text-transform: uppercase;
}

.tag {
	display: inline-flex;
	padding: 3px 9px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 11px;
}

/* The "Back to home" link at the top of inner pages. Inline-level, as on the
   old site: it sits in a line of body text, and its bottom margin adds to the
   next element's top margin instead of collapsing into it. Inline content that
   follows it must start on its own line (About wraps its label in a block). */
.back-link {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 30px;
	color: var(--color-text-muted);
	font-family: var(--font-mono);
	font-size: 13px;
	text-decoration: none;
	transition: color var(--dur-fast);
}

.back-link:hover,
.back-link:focus-visible {
	color: var(--color-text);
}

/* A post's category: on blog cards (placed over the cover by the card) and
   above a post's title. */
.post-tag {
	display: inline-block;
	padding: 5px 10px;
	border: 1px solid color-mix(in srgb, var(--color-accent) 26%, var(--color-border));
	border-radius: var(--radius-pill);
	background: var(--color-glow-soft);
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

/* A highlighted note with an accent rule: the Contact page's demo prompt, and
   a quote in page content (About's closing line). */
.callout {
	padding: 14px 18px;
	border-left: 2px solid var(--color-accent);
	border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
	background: linear-gradient(90deg, var(--color-glow-soft), transparent);
	color: var(--color-text-muted);
}

.pill {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 6px 13px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background: var(--color-glow-soft);
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
}

.chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px 10px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.chip {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 8px 14px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background: var(--color-surface);
	color: var(--color-text-muted);
	font-size: 13.5px;
	transition: transform var(--dur-fast) var(--ease), border-color var(--dur-fast), background var(--dur-fast), color var(--dur-fast);
}

@media (hover: hover) {
	.chip:hover {
		border-color: var(--color-border-strong);
		color: var(--color-text);
		transform: translateY(-2px);
	}
}

.chip__icon {
	flex: none;
	width: 15px;
	height: 15px;
	color: var(--color-accent);
}

.chip--lg {
	gap: 9px;
	padding: 9px 16px;
	font-size: var(--text-sm);
}

.section-head {
	position: relative;
	max-width: 720px;
}

.section-head--center {
	margin-inline: auto;
	text-align: center;
}

.section-head__eyebrow {
	margin-bottom: 18px;
}

/* Short line after the label, drawn in when the heading scrolls into view. */
.section-head__eyebrow::after {
	content: "";
	display: inline-block;
	width: 26px;
	height: 1px;
	margin-left: 12px;
	vertical-align: middle;
	background: linear-gradient(90deg, var(--color-accent), transparent);
	transform-origin: 0;
}

.section-head__lead {
	max-width: 62ch;
	margin-top: 16px;
}

/* The old site left this box at the left of centred heads, so its leads sat
   off centre at tablet widths. Centring the box keeps its line breaks. */
.section-head--center .section-head__lead {
	margin-inline: auto;
}

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 9px;
	padding: 13px 22px;
	border: 1px solid transparent;
	border-radius: var(--radius-pill);
	font-family: var(--font-body);
	font-size: 15px;
	font-weight: 600;
	line-height: 1;
	white-space: nowrap;
	text-decoration: none;
	cursor: pointer;
	transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast);
}

.btn__arrow {
	flex: none;
	transition: transform var(--dur-fast) var(--ease);
}

.btn:hover .btn__arrow {
	transform: translateX(3px);
}

/* position and overflow go together so the sheen stays inside the button. */
.btn--primary {
	position: relative;
	overflow: hidden;
	background: var(--color-accent);
	color: var(--color-on-accent);
	box-shadow: var(--shadow-button);
}

.btn--primary::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: linear-gradient(105deg, #0000 30%, #ffffff59 50%, #0000 70%);
	transform: translateX(-120%);
	transition: transform .7s var(--ease-out);
}

.btn--primary:hover {
	box-shadow: var(--shadow-button-hover);
	transform: translateY(-2px);
}

.btn--primary:hover::after {
	transform: translateX(120%);
}

.btn--ghost {
	border-color: var(--color-border);
	background: var(--color-surface);
	color: var(--color-text);
}

.btn--ghost:hover {
	border-color: var(--color-border-strong);
	background: var(--color-surface-2);
	transform: translateY(-2px);
}

.btn--lg {
	padding: 15px 27px;
	font-size: var(--text-base);
}

.btn--sm {
	padding: 9px 16px;
	font-size: 13.5px;
}

.card {
	position: relative;
	padding: 26px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background: var(--color-surface);
	box-shadow: var(--shadow-card);
	transition: transform var(--dur) var(--ease-spring), border-color var(--dur-fast), box-shadow var(--dur), background var(--dur-fast);
}

@media (hover: hover) {
	.card--hover:hover {
		border-color: var(--color-border-strong);
		box-shadow: var(--shadow-card-hover);
		transform: translateY(-4px);
	}
}

.card--pad-lg {
	padding: 32px;
}

.icon-box {
	display: inline-flex;
	flex: none;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background: var(--color-glow-soft);
	color: var(--color-accent);
}

.icon-box .icon {
	width: 22px;
	height: 22px;
}

.icon-box--brand {
	background: var(--color-surface-2);
}

.section--light .icon-box {
	border-color: color-mix(in srgb, var(--color-accent) 22%, var(--color-border));
	color: var(--color-accent-text);
}

.checklist {
	display: grid;
	gap: 12px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.checklist__item {
	display: flex;
	align-items: flex-start;
	gap: 11px;
	color: var(--color-text-muted);
}

.checklist__icon {
	flex: none;
	width: 19px;
	height: 19px;
	margin-top: 1px;
	color: var(--color-accent);
}

.divider {
	height: 1px;
	margin: 0;
	border: 0;
	background: linear-gradient(90deg, transparent, var(--color-border), transparent);
}

/* Drifting blurred glows, used behind the hero and the call to action band. */
.mesh {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
	-webkit-mask-image: linear-gradient(#0000 0%, #000 9% 72%, #0000 97%);
	mask-image: linear-gradient(#0000 0%, #000 9% 72%, #0000 97%);
}

.mesh__blob {
	position: absolute;
	border-radius: 50%;
	filter: blur(74px);
}

.mesh__blob--1 {
	top: 2%;
	left: -10%;
	width: 46%;
	height: 60%;
	opacity: .34;
	background: radial-gradient(circle, var(--color-glow), transparent 66%);
}

.mesh__blob--2 {
	top: 34%;
	right: -8%;
	width: 40%;
	height: 54%;
	opacity: .5;
	background: radial-gradient(circle, var(--color-glow-soft), transparent 68%);
}

.mesh__blob--3 {
	bottom: -16%;
	left: 32%;
	width: 36%;
	height: 44%;
	opacity: .2;
	background: radial-gradient(circle, var(--color-accent-deep), transparent 72%);
}

/* A bright arc that travels round the border (hero console, call to action
   band, "coming soon" pill). Needs the element to have a border radius. */
@property --orbit-angle {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0deg;
}

.orbit {
	position: relative;
}

.orbit::before {
	content: "";
	position: absolute;
	inset: 0;
	padding: 1px;
	border-radius: inherit;
	pointer-events: none;
	background: conic-gradient(from var(--orbit-angle), transparent 0deg, var(--color-accent) 42deg, transparent 120deg, transparent 360deg);
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask-composite: exclude;
}

/* Cards that lean towards the pointer, with a soft highlight under it. The
   script sets the custom properties; see initTilt() in main.js. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
	.tilt {
		transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(var(--lift, 0px));
		transition: transform .2s var(--ease-out), border-color var(--dur-fast), box-shadow var(--dur), background var(--dur-fast);
		will-change: transform;
	}

	.tilt:hover {
		--lift: -4px;
	}

	/* .card--hover:hover sets its own transform; restate the lean so both apply. */
	.tilt.card--hover:hover {
		transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(var(--lift, 0px));
	}

	.tilt::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 2;
		border-radius: inherit;
		pointer-events: none;
		opacity: var(--tilt, 0);
		background: radial-gradient(220px circle at var(--gx, 50%) var(--gy, 0%), #ffffff0f, transparent 60%);
		transition: opacity .25s var(--ease);
	}
}

/* ==========================================================================
   6. Motion
   The finished state is the default. Entrance animations only run when the
   visitor has not asked for reduced motion and the script is running (html.js),
   so without either every element simply shows.
   ========================================================================== */

/* The entrance delay lives in a non-inheriting property, so a delayed parent
   never delays a child, and it applies only to the entrance: hover lifts and
   tilts, which use transform, start at once. */
@property --reveal-delay {
	syntax: "<time>";
	inherits: false;
	initial-value: 0s;
}

.reveal--d1 {
	--reveal-delay: 60ms;
}

.reveal--d2 {
	--reveal-delay: .12s;
}

.reveal--d3 {
	--reveal-delay: .18s;
}

/* Entrances animate translate and opacity rather than transform, so a
   revealed card can still lift and tilt on hover. */
@media (prefers-reduced-motion: no-preference) {
	.js .reveal:not(.is-visible) {
		opacity: 0;
		translate: 0 16px;
	}

	.js .reveal--left:not(.is-visible) {
		translate: -22px 0;
	}

	.js .reveal--right:not(.is-visible) {
		translate: 22px 0;
	}

	.js .reveal.is-visible {
		animation: reveal-in .7s var(--ease-out) var(--reveal-delay) both;
	}

	.js .reveal--left.is-visible {
		animation-name: reveal-in-left;
	}

	.js .reveal--right.is-visible {
		animation-name: reveal-in-right;
	}

	.js .section-head__eyebrow::after {
		transform: scaleX(0);
		transition: transform .6s var(--ease-out) .15s;
	}

	.js .section-head.is-visible .section-head__eyebrow::after {
		transform: scaleX(1);
	}

	.mesh__blob {
		will-change: transform;
	}

	.mesh__blob--1 {
		animation: mesh-drift-1 19s ease-in-out infinite alternate;
	}

	.mesh__blob--2 {
		animation: mesh-drift-2 23s ease-in-out infinite alternate;
	}

	.mesh__blob--3 {
		animation: mesh-drift-3 27s ease-in-out infinite alternate;
	}

	.orbit::before {
		animation: orbit-spin 7s linear infinite;
	}
}

@keyframes reveal-in {
	from {
		opacity: 0;
		translate: 0 16px;
	}
}

@keyframes reveal-in-left {
	from {
		opacity: 0;
		translate: -22px 0;
	}
}

@keyframes reveal-in-right {
	from {
		opacity: 0;
		translate: 22px 0;
	}
}

@keyframes mesh-drift-1 {
	to {
		transform: translate(9%, 7%);
	}
}

@keyframes mesh-drift-2 {
	to {
		transform: translate(-7%, -6%);
	}
}

@keyframes mesh-drift-3 {
	to {
		transform: translate(6%, -9%);
	}
}

@keyframes orbit-spin {
	to {
		--orbit-angle: 360deg;
	}
}

/* Reading progress along the top edge, scaled by the script. */
.scroll-progress {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 70;
	width: 100%;
	height: 2px;
	background: linear-gradient(90deg, var(--color-accent-deep), var(--color-accent), var(--color-accent-text));
	transform: scaleX(0);
	transform-origin: 0;
}

/* ==========================================================================
   7. Header
   ========================================================================== */

.site-header {
	position: sticky;
	top: var(--wp-admin--admin-bar--height, 0px);
	z-index: 60;
	border-bottom: 1px solid transparent;
	background: color-mix(in srgb, var(--color-bg) 60%, transparent);
	-webkit-backdrop-filter: blur(14px) saturate(140%);
	backdrop-filter: blur(14px) saturate(140%);
	transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* The admin bar stops being fixed on narrow screens, so the header sticks to the top. */
@media (max-width: 600px) {
	.site-header {
		top: 0;
	}
}

.site-header.is-scrolled {
	border-bottom-color: var(--color-hairline);
	background: color-mix(in srgb, var(--color-bg) 86%, transparent);
	box-shadow: 0 10px 30px -24px #000c;
	-webkit-backdrop-filter: blur(20px) saturate(160%);
	backdrop-filter: blur(20px) saturate(160%);
}

/* The mobile panel sits inside the header. A header with its own
   backdrop-filter becomes the panel's backdrop root, leaving the panel's blur
   nothing to blur, so the page showed through it. Drop it while open. */
body.is-menu-open .site-header {
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
}

.site-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	/* Less the header's 1px bottom border, so the whole header is --header-height. */
	height: calc(var(--header-height) - 1px);
}

.logo {
	display: inline-flex;
	flex: none;
	align-items: center;
	gap: 11px;
	color: var(--color-text);
	text-decoration: none;
}

.logo__image {
	width: auto;
	height: 30px;
}

.logo__mark {
	width: 30px;
	height: 30px;
	color: var(--color-accent);
}

.logo__word {
	font-family: var(--font-display);
	font-size: 19px;
	font-weight: 500;
	letter-spacing: -.01em;
}

.site-nav {
	margin-left: auto;
	margin-right: 8px;
}

.site-nav__list {
	display: flex;
	align-items: center;
	gap: 26px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-nav__list a {
	color: var(--color-text-muted);
	font-size: var(--text-sm);
	text-decoration: none;
	transition: color .2s;
}

.site-nav__list a:hover,
.site-nav__list a:focus-visible {
	color: var(--color-text);
}

.site-header__actions {
	display: flex;
	align-items: center;
	gap: 12px;
}

.menu-toggle {
	display: none;
	align-items: center;
	justify-content: center;
	width: 42px;
	height: 42px;
	padding: 0;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	background: var(--color-surface);
	color: var(--color-text);
	cursor: pointer;
}

.menu-toggle__close,
.menu-toggle[aria-expanded="true"] .menu-toggle__open {
	display: none;
}

.menu-toggle[aria-expanded="true"] .menu-toggle__close {
	display: block;
}

/* ==========================================================================
   8. Mobile menu
   Below 900px the header links move into a panel under the header. Without
   JavaScript the panel is a plain list inside the header, and the header
   stops sticking so the list scrolls away with the page.
   ========================================================================== */

.mobile-menu {
	display: none;
}

@media (max-width: 900px) {
	.site-nav,
	.site-header__cta {
		display: none;
	}

	html:not(.js) .site-header {
		position: relative;
	}

	.menu-toggle {
		display: inline-flex;
	}

	.mobile-menu {
		display: block;
		width: 100%;
		padding: 18px var(--gutter) 26px;
		border-bottom: 1px solid var(--color-border);
		background: color-mix(in srgb, var(--color-bg) 96%, transparent);
		-webkit-backdrop-filter: blur(18px);
		backdrop-filter: blur(18px);
	}

	/* With the script running the panel hangs under the sticky header and is
	   hidden (and out of the tab order) until opened. */
	.js .mobile-menu {
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		visibility: hidden;
		opacity: 0;
		pointer-events: none;
		transform: translateY(-8px);
		transition: opacity .25s var(--ease), transform .25s var(--ease), visibility 0s linear .25s;
	}

	.js .mobile-menu.is-open {
		visibility: visible;
		opacity: 1;
		pointer-events: auto;
		transform: none;
		transition: opacity .25s var(--ease), transform .25s var(--ease), visibility 0s;
	}

	.mobile-menu__list {
		margin: 0;
		padding: 0;
		list-style: none;
	}

	.mobile-menu__list a {
		display: block;
		padding: 13px 4px;
		border-bottom: 1px solid var(--color-hairline);
		color: var(--color-text);
		font-size: var(--text-base);
		text-decoration: none;
	}

	.mobile-menu__cta {
		display: flex;
		width: 100%;
		margin-top: 16px;
		padding: 14px 22px;
		font-size: var(--text-base);
	}
}

/* Stops the page scrolling behind the open menu. */
body.is-menu-open {
	overflow: hidden;
}

/* ==========================================================================
   9. Footer
   ========================================================================== */

.site-footer {
	position: relative;
	padding: 60px 0 44px;
	border-top: 1px solid var(--color-hairline);
	background: var(--color-bg-alt);
}

.site-footer a {
	color: var(--color-text-muted);
	font-size: var(--text-sm);
	text-decoration: none;
	transition: color .2s;
}

.site-footer a:hover,
.site-footer a:focus-visible {
	color: var(--color-text);
}

.site-footer .logo {
	color: var(--color-text);
}

.site-footer__grid {
	display: grid;
	grid-template-columns: 1.4fr 2fr;
	gap: clamp(32px, 5vw, 60px);
}

.site-footer__about {
	max-width: 46ch;
	margin-top: 18px;
	color: var(--color-text-muted);
	font-size: var(--text-sm);
}

.site-footer__disclaimer {
	max-width: 46ch;
	margin-top: 12px;
	color: var(--color-text-dim);
	font-size: 12.5px;
	line-height: 1.6;
}

.site-footer__address {
	margin-top: 18px;
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 12.5px;
	line-height: 1.7;
}

.site-footer__contact {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-top: 18px;
}

.site-footer__cols {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
}

.site-footer__title {
	margin-bottom: 16px;
}

.site-footer__links {
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-footer__divider {
	margin: 40px 0 24px;
}

.site-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}

.site-footer__copyright {
	color: var(--color-text-dim);
	font-size: 13px;
}

@media (max-width: 820px) {
	.site-footer__grid {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 520px) {
	.site-footer__cols {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* ==========================================================================
   10. Call to action band
   ========================================================================== */

.section.cta {
	padding: clamp(52px, 8vw, 96px) 0;
}

.cta__band {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	overflow: hidden;
	padding: clamp(44px, 6vw, 72px) clamp(22px, 5vw, 56px);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-xl);
	background: linear-gradient(180deg, var(--color-surface), var(--color-bg-alt));
	text-align: center;
}

/* Content sits above the glow and mesh, which are absolutely positioned. */
.cta__mark,
.cta__title,
.cta__text,
.cta__actions {
	position: relative;
}

.cta__glow {
	position: absolute;
	top: -42%;
	left: 50%;
	width: 460px;
	max-width: 120%;
	height: 460px;
	border-radius: 50%;
	pointer-events: none;
	opacity: .5;
	background: radial-gradient(circle, var(--color-glow) 0%, transparent 60%);
	filter: blur(30px);
	transform: translateX(-50%);
}

.cta__mark {
	width: 54px;
	height: 54px;
	color: var(--color-accent);
	filter: drop-shadow(0 6px 22px var(--color-glow));
}

.cta__title {
	max-width: 18ch;
	margin-top: 16px;
}

.cta__text {
	max-width: 46ch;
	margin: 18px auto 0;
}

.cta__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 12px;
	margin-top: 30px;
}

/* ==========================================================================
   11. Floating booking button
   ========================================================================== */

.book-call {
	position: fixed;
	right: 40px;
	bottom: 24px;
	z-index: 50;
	display: inline-flex;
	align-items: center;
	gap: 12px;
	min-height: 64px;
	padding: 16px 24px;
	border-radius: var(--radius-pill);
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-family: var(--font-body);
	font-size: var(--text-base);
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
	transition: transform var(--dur-fast) var(--ease);
}

.book-call:hover {
	transform: translateY(-2px);
}

.book-call__icon {
	flex: none;
	width: 28px;
	height: 28px;
}

@media (max-width: 640px) {
	.book-call {
		right: 16px;
		bottom: 16px;
	}
}

/* ==========================================================================
   12. Pages: listing, single entry and 404
   ========================================================================== */

.listing__title,
.entry__title {
	margin-bottom: 32px;
}

.listing__items {
	display: grid;
	gap: 16px;
}

.listing__item a {
	text-decoration: none;
}

.listing__excerpt {
	margin-top: 10px;
}

.pagination {
	margin-top: 32px;
}

.pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.pagination .page-numbers {
	padding: 8px 14px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	color: var(--color-text-muted);
	text-decoration: none;
}

.pagination .page-numbers.current {
	border-color: var(--color-accent);
	color: var(--color-text);
}

.entry__inner {
	max-width: 760px;
}

/* Spacing for anything typed into the editor. */
.entry-content > * + * {
	margin-top: 1.1em;
}

.entry-content h2,
.entry-content h3,
.entry-content h4 {
	margin-top: 1.8em;
}

.entry-content h2 {
	font-size: var(--text-h2);
}

.entry-content h3 {
	font-size: var(--text-h3);
}

.entry-content ul,
.entry-content ol {
	padding-left: 1.3em;
}

.entry-content li + li {
	margin-top: .4em;
}

.entry-content a {
	color: var(--color-accent-text);
	text-underline-offset: 3px;
}

.entry-content blockquote {
	padding-left: 18px;
	border-left: 2px solid var(--color-accent);
	color: var(--color-text-muted);
}

.search-form {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-top: 22px;
}

.search-form__field {
	flex: 1 1 240px;
	min-height: 48px;
	padding: 0 18px;
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background: var(--color-surface);
	color: var(--color-text);
	font: inherit;
}

.search-form__field::placeholder {
	color: var(--color-text-dim);
}

/* The 404 page, with the old site's spacing: extra room above and below the
   column inside the section padding. */
.error-page__inner {
	max-width: 640px;
	padding-block: clamp(40px, 10vh, 96px);
	text-align: center;
}

.error-page__eyebrow + .error-page__title {
	margin-top: 16px;
}

.error-page__text {
	margin-top: 18px;
	margin-inline: auto;
}

.error-page__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	justify-content: center;
	margin-top: 30px;
}

/* ==========================================================================
   13. Homepage sections
   In page order, one block per section.
   ========================================================================== */

/* --------------------------------------------------------------------------
   13.1 hero
   -------------------------------------------------------------------------- */

/**
 * 01 Hero: the page's h1 with its label, text and buttons, the launch console
 * beside them and the short points below.
 *
 * - The section opens without the helper's container, because the mesh must
 *   cover the whole section. .hero__inner is the container and sits above it.
 * - The console is printed in its finished state. main.js replays the launch
 *   by toggling is-lit on each row and bar, is-live on the console, is-booting
 *   or is-live on the dot and is-drawing on the mark (see initHeroConsole()).
 *   Each bar is an outline path and a fill path: the outline shows while the
 *   bar is unlit, the fill once it lights.
 * - --hero-ease is the curve the old site gives the console's state changes.
 *   Nothing outside the console uses it, so it is local rather than a token.
 * - Breakpoints are the old site's: 940px stacks the console under the copy,
 *   420px drops the provider names from the console rows.
 */

/* position and overflow go together so the mesh and glows stay inside. */
.section.hero {
	--hero-ease: cubic-bezier(.4, 0, .2, 1);
	position: relative;
	overflow: hidden;
	padding: clamp(46px, 7vw, 92px) 0 clamp(36px, 5vw, 60px);
}

.hero__inner {
	position: relative;
	z-index: 1;
}

.hero__grid {
	display: grid;
	grid-template-columns: 1.05fr .95fr;
	align-items: center;
	gap: clamp(30px, 5vw, 60px);
}

/* Grid items default to min-width: auto, so the unwrapped console caption set
   the column's minimum width and a long caption pushed the heading off small
   phones. With 0, the caption's ellipsis does its job. */
.hero__grid > * {
	min-width: 0;
}

.hero__copy {
	max-width: 620px;
}

/* Every part is optional, so whichever comes first sits flush. */
.hero__inner > :first-child,
.hero__copy > :first-child {
	margin-top: 0;
}

.hero__title {
	margin-top: 18px;
}

.hero__highlight {
	color: var(--color-accent-text);
}

/* Gradient text, only where the browser can clip a background to the text. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
	.hero__highlight {
		background: linear-gradient(100deg, var(--color-accent) 24%, var(--color-accent-text) 46%, var(--color-accent) 66%);
		background-size: 220%;
		-webkit-background-clip: text;
		background-clip: text;
		color: transparent;
		-webkit-text-fill-color: transparent;
	}
}

.hero__lead {
	margin-top: 22px;
}

.hero__actions {
	margin-top: 30px;
}

/* --------------------------------------------------------------------------
   Launch console
   -------------------------------------------------------------------------- */

/* .orbit supplies position: relative and the travelling border arc. */
.hero__console {
	padding: 22px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-xl);
	background: linear-gradient(180deg, var(--color-surface) 0%, var(--color-bg-alt) 100%);
	box-shadow: 0 44px 130px -70px var(--color-glow);
}

.hero__caption {
	position: relative;
	display: flex;
	align-items: center;
	gap: 9px;
	height: 22px;
	overflow: hidden;
	font-size: var(--text-sm);
	letter-spacing: .01em;
}

.hero__dot {
	flex: none;
	width: 8px;
	height: 8px;
	border: 1.5px solid var(--color-text-dim);
	border-radius: 50%;
	background: transparent;
	transition: background .5s var(--ease-out), border-color .5s var(--ease-out), box-shadow .5s var(--ease-out);
}

.hero__dot.is-booting {
	border-color: var(--color-accent);
	background: var(--color-accent);
}

.hero__dot.is-live {
	border-color: var(--color-accent-text);
	background: var(--color-accent-text);
	box-shadow: 0 0 6px 1px var(--color-glow);
}

.hero__caption-text {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	color: var(--color-text);
	white-space: nowrap;
	text-overflow: ellipsis;
}

.hero__stage {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	height: 176px;
	margin-top: 14px;
	background: radial-gradient(60% 60% at 50% 46%, var(--color-glow-soft), transparent 70%);
}

.hero__stage-glow {
	position: absolute;
	width: 240px;
	height: 240px;
	border-radius: 50%;
	opacity: .45;
	background: radial-gradient(circle, var(--color-glow) 0%, transparent 62%);
	filter: blur(26px);
}

.hero__mark {
	position: relative;
	width: 128px;
	height: 128px;
}

.hero__bar-outline {
	fill: none;
	stroke: var(--color-accent);
	stroke-width: 2px;
	opacity: .55;
	transition: opacity .9s var(--hero-ease);
}

.hero__bar-fill {
	fill: var(--color-accent);
	opacity: 0;
	transition: opacity .9s var(--hero-ease);
}

.hero__bar.is-lit .hero__bar-outline {
	opacity: 0;
}

.hero__bar.is-lit .hero__bar-fill {
	opacity: 1;
}

.hero__engines {
	display: grid;
	gap: 8px;
	margin: 14px 0 0;
	padding: 0;
	list-style: none;
}

/* position: relative contains the provider name when it is visually hidden. */
.hero__engine {
	position: relative;
	display: grid;
	grid-template-columns: auto 1fr auto auto;
	align-items: center;
	gap: 12px;
	padding: 10px 13px;
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-md);
	background: var(--color-surface-2);
	color: var(--color-text);
	transition: background .5s var(--hero-ease);
}

.hero__engine.is-lit {
	background: linear-gradient(90deg, var(--color-glow-soft), transparent), var(--color-surface-2);
}

.hero__engine-no {
	color: var(--color-text-muted);
	font-size: var(--text-xs);
}

.hero__engine-name {
	min-width: 0;
	font-family: var(--font-display);
	font-size: 15px;
	font-weight: 600;
}

.hero__engine-by {
	color: var(--color-text-dim);
	font-size: 11.5px;
}

/* Always the last column, whether or not the row has a provider name. */
.hero__engine-logo {
	display: inline-flex;
	grid-column: -2;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	background: var(--color-bg-alt);
	opacity: .62;
	transition: opacity .6s var(--ease-out), border-color .6s var(--ease-out), box-shadow .6s var(--ease-out);
}

.hero__engine.is-lit .hero__engine-logo {
	border-color: color-mix(in srgb, var(--color-accent) 45%, var(--color-border));
	opacity: 1;
	box-shadow: 0 0 12px -2px var(--color-glow);
}

.hero__engine-img {
	width: 18px;
	height: 18px;
	object-fit: contain;
}

.hero__engine-mark {
	width: 16px;
	height: 16px;
	color: var(--color-accent);
}

.hero__foot {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 14px;
}

.hero__deploy {
	color: var(--color-text-dim);
	text-transform: uppercase;
}

/* position and overflow go together so the fill stays inside the track. */
.hero__progress {
	position: relative;
	flex: 1;
	height: 6px;
	overflow: hidden;
	border-radius: var(--radius-pill);
	background: var(--color-surface-3);
}

.hero__progress-bar {
	display: block;
	height: 100%;
	border-radius: var(--radius-pill);
	background: linear-gradient(90deg, var(--color-accent-deep), var(--color-accent));
	box-shadow: 0 0 12px var(--color-glow);
	transition: width .9s var(--hero-ease);
}

.hero__status {
	color: var(--color-text-dim);
	font-size: 11px;
	letter-spacing: .06em;
	text-transform: uppercase;
}

.hero__console.is-live .hero__status {
	color: var(--color-accent-text);
}

/* --------------------------------------------------------------------------
   Short points
   -------------------------------------------------------------------------- */

.hero__chips {
	gap: 12px 14px;
	margin-top: clamp(40px, 6vw, 60px);
}

/* The hero chips use a heavier tick than the lists and feature chips, as on
   the old site. */
.hero__chips .chip__icon {
	stroke-width: 2.4;
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 940px) {
	.hero__grid {
		grid-template-columns: 1fr;
	}
}

/* The old site drops the provider names here. They stay available to screen
   readers, because the logo beside them has an empty alt. */
@media (max-width: 420px) {
	.hero__engine {
		grid-template-columns: auto 1fr auto;
	}

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

/* --------------------------------------------------------------------------
   Motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
	.hero__highlight {
		animation: hero-sheen 7s linear infinite;
	}

	.hero__dot.is-booting {
		animation: hero-pulse 1.6s var(--ease) infinite;
	}

	.hero__mark.is-drawing {
		animation: hero-mark-draw 1s var(--hero-ease);
	}
}

@keyframes hero-sheen {
	to {
		background-position: 220%;
	}
}

@keyframes hero-pulse {
	50% {
		opacity: .5;
	}
}

@keyframes hero-mark-draw {
	from {
		opacity: .12;
		transform: scale(.94);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* --------------------------------------------------------------------------
   13.2 platforms
   -------------------------------------------------------------------------- */

/**
 * 02 Supported platforms: a small centred title over a row of platform logos
 * that scrolls in a continuous loop, fading out at both edges.
 *
 * The component prints the logo list twice. Each list ends with the same space
 * that sits between its logos, so moving the track by exactly half its width
 * (one whole list) lands the second list where the first began and the loop
 * has no seam. The loop takes 5s per logo, which is live's 40s for the eight
 * at launch, so adding logos does not speed it up. It only runs for visitors
 * who have not asked for reduced motion, and pauses under the pointer. Logos
 * are recoloured white with a filter, so any transparent logo matches.
 */

.platforms__head {
	max-width: 720px;
	margin-inline: auto;
	text-align: center;
}

.platforms__marquee {
	--platforms-gap: 80px;
	position: relative;
	overflow: hidden;
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 7% 93%, transparent);
	mask-image: linear-gradient(90deg, transparent, #000 7% 93%, transparent);
}

.platforms__head + .platforms__marquee {
	margin-top: 44px;
}

.platforms__track {
	display: flex;
	width: max-content;
}

/* The trailing padding equals the gap, so both lists measure the same. */
.platforms__list {
	display: flex;
	flex: none;
	align-items: center;
	gap: var(--platforms-gap);
	margin: 0;
	padding: 0 var(--platforms-gap) 0 0;
	list-style: none;
}

.platforms__item {
	display: flex;
	flex: none;
	align-items: center;
	height: 52px;
}

.platforms__logo {
	width: auto;
	max-width: none;
	height: 46px;
	opacity: .82;
	filter: brightness(0) invert(1);
	transition: opacity .25s;
}

.platforms__item:hover .platforms__logo {
	opacity: 1;
}

/* White logos would vanish if the strip is ever given a light background. */
.section--light .platforms__logo {
	filter: brightness(0);
}

@media (max-width: 640px) {
	.platforms__marquee {
		--platforms-gap: 52px;
	}

	.platforms__item {
		height: 40px;
	}

	.platforms__logo {
		height: 34px;
	}
}

@media (prefers-reduced-motion: no-preference) {
	.platforms__track {
		animation: platforms-scroll calc(var(--platforms-count, 8) * 5s) linear infinite;
	}

	.platforms__marquee:hover .platforms__track {
		animation-play-state: paused;
	}
}

@keyframes platforms-scroll {
	to {
		transform: translateX(-50%);
	}
}

/* --------------------------------------------------------------------------
   13.3 problem
   -------------------------------------------------------------------------- */

/**
 * 03 Problem: the heading block, then two cards side by side (stacked below
 * 900px by the shared .grid--2): what founders expect, and the highlighted
 * list of what must also work, with a green-tinted top and an accent edge.
 *
 * The card titles are h3 elements displayed inline, as live's labels were
 * inline, so each sits in a line as tall as the card's body text and the
 * list starts exactly where live's does.
 */

.problem__grid {
	margin-top: 44px;
}

.problem__card-title {
	display: inline;
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 11.5px;
	font-weight: 400;
	line-height: 1.6;
	letter-spacing: .05em;
	text-transform: uppercase;
}

.problem__card-title + .problem__list {
	margin-top: 18px;
}

.problem__card--highlight {
	border-color: color-mix(in srgb, var(--color-accent) 32%, var(--color-border));
	background: linear-gradient(180deg, var(--color-glow-soft), transparent 42%), var(--color-surface);
}

.problem__card--highlight .problem__card-title {
	color: var(--color-accent-text);
}

/* --------------------------------------------------------------------------
   13.4 operating-model
   -------------------------------------------------------------------------- */

/**
 * 04 Operating model: what the founder owns beside what PropLaunch operates,
 * two cards joined by a hand-off badge on a vertical line.
 *
 * - The line, the badge and the pulse only exist when both cards print
 *   (.operating-model__grid--split). They hide at 900px and below, where the
 *   cards stack, as on the old site.
 * - The pulse travels down the line once, after the right-hand card has
 *   revealed. It is invisible at rest, so the unanimated state loses nothing.
 */

.operating-model__grid {
	position: relative;
	margin-top: 44px;
}

.operating-model__card {
	position: relative;
	overflow: hidden;
}

/* With one card left empty, the other takes the full width. */
.operating-model__card:only-child {
	grid-column: 1 / -1;
}

/* Coloured edge down the left of each card. */
.operating-model__card::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	z-index: 1;
	width: 3px;
	background: linear-gradient(var(--color-text-dim), transparent);
}

/* The highlighted card: accent edge, border and a tint fading down from the top. */
.operating-model__card--operate {
	border-color: color-mix(in srgb, var(--color-accent) 32%, var(--color-border));
	background: linear-gradient(180deg, var(--color-glow-soft), transparent 42%), var(--color-surface);
}

.operating-model__card--operate::before {
	background: linear-gradient(var(--color-accent-deep), transparent);
}

.operating-model__card--operate .operating-model__tag {
	border-color: color-mix(in srgb, var(--color-accent) 30%, var(--color-border));
	background: var(--color-glow-soft);
	color: var(--color-accent-text);
}

.operating-model__title {
	margin-top: 16px;
}

.operating-model__list {
	margin-top: 22px;
}

.operating-model__title:first-child,
.operating-model__list:first-child {
	margin-top: 0;
}

/* The line between the cards, fading out at both ends. */
.operating-model__grid--split::before {
	content: "";
	position: absolute;
	top: 8%;
	bottom: 8%;
	left: 50%;
	z-index: 0;
	width: 1px;
	background: linear-gradient(180deg, transparent, var(--color-border-strong), transparent);
	transform: translateX(-50%);
}

.operating-model__handoff {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 2;
	padding: 5px 11px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background: var(--color-bg);
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 10.5px;
	letter-spacing: .14em;
	text-transform: uppercase;
	white-space: nowrap;
	transform: translate(-50%, -50%);
}

/* The dot that runs down the line. Hidden until the animation plays. */
.operating-model__pulse {
	position: absolute;
	top: 8%;
	left: 50%;
	z-index: 3;
	width: 7px;
	height: 7px;
	margin-left: -3.5px;
	border-radius: 50%;
	opacity: 0;
	background: var(--color-accent-deep);
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 16%, transparent);
}

@media (max-width: 900px) {
	.operating-model__grid--split::before,
	.operating-model__handoff,
	.operating-model__pulse {
		display: none;
	}

	.operating-model__grid--split .operating-model__card--operate {
		margin-top: 4px;
	}
}

@media (prefers-reduced-motion: no-preference) {
	.js .operating-model__card--operate.is-visible ~ .operating-model__pulse {
		animation: operating-model-pulse 1.7s var(--ease) .35s 1;
	}
}

@keyframes operating-model-pulse {
	0% {
		top: 8%;
		opacity: 0;
	}

	16%,
	84% {
		opacity: 1;
	}

	100% {
		top: 92%;
		opacity: 0;
	}
}

/* --------------------------------------------------------------------------
   13.5 why
   -------------------------------------------------------------------------- */

/**
 * 05 Why PropLaunch: a centred heading over six cards in a 3 x 2 grid (one
 * column at 900px and below, from the shared .grid--3).
 *
 * - Each card sits in a list item that carries the reveal. The cards lift on
 *   hover; on the old site a bug in its reveal cancelled the lift, so its
 *   cards only changed border and shadow.
 */

.why__grid {
	margin-top: 48px;
	padding: 0;
	list-style: none;
}

/* Three to a row as a wrapping flex row rather than the shared grid, so one,
   two, four or five cards centre under the heading instead of hugging the
   left. Three or six look exactly as the grid did. */
@media (min-width: 901px) {
	.why__grid {
		display: flex;
		flex-wrap: wrap;
		justify-content: center;
	}

	.why__item {
		flex: 0 0 calc((100% - 40px) / 3);
	}
}

.why__card {
	height: 100%;
}

/* Card sizes are fixed on the old site rather than following the h3 scale. */
.why__title {
	margin-top: 18px;
	font-size: 19px;
}

.why__title:first-child {
	margin-top: 0;
}

.why__text {
	margin-top: 10px;
	font-size: 14.5px;
}

/* --------------------------------------------------------------------------
   13.6 engines
   -------------------------------------------------------------------------- */

/* ==========================================================================
   Engines (06)
   Cards that turn over to show the track record behind each engine, then
   lines converging on a pill for the visitor's own firm.

   - Both faces sit in one grid cell (grid-area 1 / 1), so a card is as tall as
     its longer face and the row as tall as its tallest card. Turning over is a
     crossfade, never a height change.
   - .is-flipped comes from the toggle button (initFlipCards() in main.js).
     Hover turns a card too, in CSS, only where hover exists and motion is
     allowed, as on the old site. Only cards with a back ([data-flip]) turn.
   - The cards carry the shared tilt hook, so they lean towards the pointer and
     light up under it. On the old site a bug in its reveal stopped the lean.
   - The connector's curves are a fixed 560px funnel into the pill, not lines
     to each card's centre, exactly as on the old site. Below 900px it becomes
     one short vertical line.
   ========================================================================== */

.engines__status {
	margin-top: 20px;
}

.engines__dot {
	flex: none;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--color-accent);
	box-shadow: 0 0 8px 1px var(--color-glow);
}

.engines__grid {
	display: grid;
	grid-auto-columns: minmax(0, 1fr);
	grid-auto-flow: column;
	gap: 20px;
	margin: 28px 0 0;
	padding: 0;
	list-style: none;
}

.engines__card {
	position: relative;
	display: grid;
	border-radius: var(--radius-lg);
	-webkit-tap-highlight-color: transparent;
}

/* Accent ring and soft glow round each card. */
.engines__card::after {
	content: "";
	position: absolute;
	inset: -1px;
	border-radius: inherit;
	pointer-events: none;
	box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 38%, transparent), 0 0 30px -12px var(--color-glow);
}

.engines__face {
	display: flex;
	flex-direction: column;
	grid-area: 1 / 1;
	padding: 32px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background: var(--color-surface);
	box-shadow: var(--shadow-card);
}

.engines__face--back {
	opacity: 0;
	pointer-events: none;
	transform: scale(1.01);
}

.engines__card.is-flipped .engines__face--front {
	opacity: 0;
	pointer-events: none;
	transform: scale(.99);
}

.engines__card.is-flipped .engines__face--back {
	opacity: 1;
	pointer-events: auto;
	transform: none;
}

.engines__top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 46px;
}

.engines__logo {
	display: block;
	width: 28px;
	height: 28px;
	object-fit: contain;
}

.engines__mark {
	width: 22px;
	height: 22px;
}

/* A large, deliberately faint number: decoration, hidden from assistive technology. */
.engines__number {
	margin-left: auto;
	color: var(--color-surface-3);
	font-size: 30px;
	font-weight: 600;
	letter-spacing: -.02em;
}

.engines__label {
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: 12.5px;
}

.engines__title {
	margin-top: 20px;
	font-size: 20px;
}

.engines__text {
	margin-top: 12px;
}

/* A real button over the whole card, so the card is one tab stop. */
.engines__toggle {
	position: absolute;
	inset: 0;
	z-index: 3;
	width: 100%;
	padding: 0;
	border: 0;
	border-radius: inherit;
	background: transparent;
	cursor: pointer;
}

.engines__converge {
	display: flex;
	flex-direction: column;
	align-items: center;
	margin-top: 20px;
}

.engines__connector {
	position: relative;
	width: min(560px, 100%);
	height: 46px;
	margin-top: 4px;
}

.engines__lines {
	display: block;
	width: 100%;
	height: 100%;
	overflow: visible;
}

.engines__line {
	fill: none;
	stroke: var(--color-accent);
	stroke-width: 1.25px;
	opacity: .32;
	vector-effect: non-scaling-stroke;
}

.engines__line--mid {
	opacity: .4;
}

/* The light running down each line. Shown only while it animates. */
.engines__flow {
	fill: none;
	stroke: var(--color-accent-text);
	stroke-width: 2px;
	stroke-linecap: round;
	stroke-dasharray: .12 .88;
	opacity: 0;
	vector-effect: non-scaling-stroke;
	filter: drop-shadow(0 0 3px var(--color-glow));
}

.engines__node {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 11px;
	max-width: 100%;
	margin-top: 2px;
	padding: 12px 18px;
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background: linear-gradient(90deg, var(--color-glow-soft), transparent), var(--color-surface);
}

.engines__node-mark {
	flex: none;
	width: 24px;
	height: 24px;
	color: var(--color-accent);
	filter: drop-shadow(0 4px 14px var(--color-glow));
}

.engines__node-label {
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: 15px;
	font-weight: 600;
}

.engines__node-sub {
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 11.5px;
}

@media (max-width: 900px) {
	.engines__grid {
		grid-auto-flow: row;
	}

	.engines__connector {
		width: 2px;
		height: 34px;
	}

	.engines__lines {
		display: none;
	}

	.engines__connector::before {
		content: "";
		position: absolute;
		top: 0;
		bottom: 0;
		left: 50%;
		width: 2px;
		background: linear-gradient(180deg, color-mix(in srgb, var(--color-accent) 40%, transparent), transparent);
		transform: translateX(-50%);
	}
}

@media (max-width: 560px) {
	.engines__face {
		padding: 24px;
	}
}

/* Motion. Without it, or without the script, everything above is the
   finished state: rings on, lines drawn, no light running. */
@media (prefers-reduced-motion: no-preference) {
	.engines__dot {
		animation: engines-pulse 2.4s var(--ease) infinite;
	}

	.engines__face {
		transition: opacity .55s var(--ease), transform .55s var(--ease);
	}

	.js .engines__card::after {
		transition: opacity 1s var(--ease-out) 50ms;
	}

	.js .engines__card:nth-child(2)::after {
		transition-delay: .3s;
	}

	.js .engines__card:nth-child(3)::after {
		transition-delay: .55s;
	}

	.js .engines__card:not(.is-visible)::after {
		opacity: 0;
	}

	.js .engines__line {
		stroke-dasharray: 1;
		transition: stroke-dashoffset 1.1s var(--ease-out);
	}

	.js .engines__converge:not(.is-visible) .engines__line {
		stroke-dashoffset: 1px;
	}

	/* All three lights run in step and reach the pill together, as on the
	   old site. (Its stylesheet declared a stagger, but its own animation
	   shorthand reset those delays, so the lights never ran staggered.) */
	.js .engines__converge.is-visible .engines__flow {
		opacity: 1;
		animation: engines-flow 2.6s linear infinite;
	}

	.js .engines__converge.is-visible .engines__node {
		animation: engines-node-pulse 2.6s var(--ease) infinite;
	}
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
	.engines__card[data-flip]:hover .engines__face--front {
		opacity: 0;
		pointer-events: none;
		transform: scale(.99);
	}

	.engines__card[data-flip]:hover .engines__face--back {
		opacity: 1;
		pointer-events: auto;
		transform: none;
	}
}

@keyframes engines-pulse {
	50% {
		opacity: .5;
	}
}

@keyframes engines-flow {
	from {
		stroke-dashoffset: 1px;
	}

	to {
		stroke-dashoffset: 0;
	}
}

@keyframes engines-node-pulse {
	0%,
	100% {
		box-shadow: 0 0 0 1px transparent;
	}

	50% {
		box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 34%, transparent), 0 0 24px -8px var(--color-glow);
	}
}

/* --------------------------------------------------------------------------
   13.7 how-it-works
   -------------------------------------------------------------------------- */

/* ==========================================================================
   How it works (07)
   Numbered steps side by side, joined by a line under the numbers.

   - The line's ends sit half a column in from each side, which depends on
     the step count, so the component passes --how-it-works-count and the
     inset is worked out here. Three steps give the old site's 16.66% + 4px.
   - The static line, its fill (.how-it-works__progress) and the spark are
     placed over the list, below the numbers, which have a ring of the section
     background round them to cut the line cleanly.
   - Settled state (no script, or reduced motion): numbers lit, line filled,
     no spark. With motion, the numbers light one after another as the fill
     reaches them, as on the old site. The fill is triggered with :has(), so
     browsers without it simply keep the settled state.
   - The numbers use --color-accent-text. The old site used the lighter
     --accent-deep, which measures 2.2:1 on the tinted circle; this passes AA.
   ========================================================================== */

.how-it-works__flow {
	--how-it-works-inset: calc(50% / var(--how-it-works-count, 3) + 4px);
	position: relative;
	margin-top: 48px;
}

/* The faint line under the numbers. */
.how-it-works__flow::before {
	content: "";
	position: absolute;
	top: 23px;
	left: var(--how-it-works-inset);
	right: var(--how-it-works-inset);
	z-index: 0;
	height: 2px;
	border-radius: 2px;
	background: linear-gradient(90deg, color-mix(in srgb, var(--color-accent) 28%, transparent), color-mix(in srgb, var(--color-accent) 12%, transparent));
}

.how-it-works__steps {
	position: relative;
	z-index: 1;
	display: grid;
	grid-auto-columns: minmax(0, 1fr);
	grid-auto-flow: column;
	gap: 20px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.how-it-works__step {
	padding: 6px 2px;
	text-align: center;
}

.how-it-works__number {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	border: 1.5px solid var(--color-accent);
	border-radius: 50%;
	background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface));
	box-shadow: 0 0 0 5px var(--color-bg), 0 0 0 6px color-mix(in srgb, var(--color-accent) 26%, transparent);
	color: var(--color-accent-text);
	font-size: 15px;
	font-weight: 600;
}

/* The ripple that leaves each number as it lights. Only ever animated. */
.how-it-works__number::after {
	content: "";
	position: absolute;
	inset: 0;
	border: 1.5px solid color-mix(in srgb, var(--color-accent) 55%, transparent);
	border-radius: 50%;
	pointer-events: none;
	opacity: 0;
}

.how-it-works__title {
	margin-top: 18px;
}

.how-it-works__text {
	margin-top: 10px;
}

/* The fill along the line, and the spark that runs ahead of it. */
.how-it-works__progress {
	position: absolute;
	top: 23px;
	left: var(--how-it-works-inset);
	right: var(--how-it-works-inset);
	z-index: 0;
	height: 2px;
	border-radius: 2px;
	background: linear-gradient(90deg, var(--color-accent-deep), var(--color-accent));
	transform-origin: 0;
}

.how-it-works__spark {
	position: absolute;
	top: 23px;
	left: var(--how-it-works-inset);
	z-index: 2;
	width: 11px;
	height: 11px;
	margin: -5px 0 0 -6px;
	border-radius: 50%;
	background: var(--color-accent);
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 16%, transparent);
	pointer-events: none;
	opacity: 0;
}

@media (max-width: 900px) {
	.how-it-works__steps {
		grid-auto-flow: row;
	}

	.how-it-works__flow::before,
	.how-it-works__progress,
	.how-it-works__spark {
		display: none;
	}
}

@media (prefers-reduced-motion: no-preference) {
	/* Each step, its number and its ripple start as the fill reaches it:
	   .1s, then evenly across the .9s the fill takes. */
	.how-it-works__flow {
		--how-it-works-stagger: calc(.9s / max(1, var(--how-it-works-count, 3) - 1));
	}

	.how-it-works__step.reveal {
		--reveal-delay: calc(.1s + var(--i, 0) * var(--how-it-works-stagger));
	}

	.js .how-it-works__number {
		transition: transform .6s var(--ease-spring), border-color .5s var(--ease), background .5s var(--ease), box-shadow .5s var(--ease);
		transition-delay: calc(.1s + var(--i, 0) * var(--how-it-works-stagger));
	}

	.js .how-it-works__step:not(.is-visible) .how-it-works__number {
		border-color: var(--color-border-strong);
		background: var(--color-surface);
		box-shadow: 0 0 0 5px var(--color-bg);
		transform: scale(.82);
	}

	.js .how-it-works__step.is-visible .how-it-works__number::after {
		animation: how-it-works-ripple 1s var(--ease-out) forwards;
		animation-delay: calc(.1s + var(--i, 0) * var(--how-it-works-stagger));
	}

	@supports selector(:has(*)) {
		.js .how-it-works__progress {
			transform: scaleX(0);
			transition: transform .9s linear .1s;
		}

		.js .how-it-works__steps:has(> .is-visible) ~ .how-it-works__progress {
			transform: none;
		}

		.js .how-it-works__steps:has(> .is-visible) ~ .how-it-works__spark {
			animation: how-it-works-spark .9s linear .1s both;
		}
	}
}

@keyframes how-it-works-ripple {
	from {
		opacity: .7;
		transform: scale(1);
	}

	to {
		opacity: 0;
		transform: scale(2);
	}
}

@keyframes how-it-works-spark {
	0% {
		left: var(--how-it-works-inset);
		opacity: 0;
		transform: scale(.5);
	}

	12%,
	88% {
		opacity: 1;
		transform: scale(1);
	}

	100% {
		left: calc(100% - var(--how-it-works-inset));
		opacity: 0;
		transform: scale(.5);
	}
}

/* --------------------------------------------------------------------------
   13.8 features
   -------------------------------------------------------------------------- */

/**
 * 08 What's included (features): the operating layer stack.
 *
 * Numbered layer rows joined on the left by a vertical spine, with a node and
 * a short connector per row. The spine is the list's own ::before, so the
 * list holds only list items. --features-rail is the space left of the rows
 * and --features-spine is the spine's distance from the list's left edge; the
 * nodes are placed from both, so change them together.
 *
 * The finished state (spine drawn, nodes lit, rows and chips shown) is the
 * default. The entrance runs only under html.js with motion allowed, keyed off
 * .is-visible on the list: the spine draws down, each row docks in from the
 * right, its node lights and its chips fade in. --i (row, set in the markup)
 * and --j (chip, from proplaunch_chips()) stagger it.
 */

.features__stack {
	--features-rail: 46px;
	--features-spine: 22px;
	position: relative;
	display: grid;
	gap: 14px;
	margin: 46px 0 0;
	padding: 0 0 0 var(--features-rail);
	list-style: none;
}

.features__stack::before {
	content: "";
	position: absolute;
	top: 38px;
	bottom: 38px;
	left: calc(var(--features-spine) - 1px);
	width: 2px;
	border-radius: 2px;
	background: linear-gradient(180deg, color-mix(in srgb, var(--color-accent) 75%, transparent), color-mix(in srgb, var(--color-accent) 12%, transparent));
	transform-origin: top;
}

.features__layer {
	position: relative;
	padding: 20px 24px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background: var(--color-surface-2);
	box-shadow: inset 0 1px #ffffff0a, 0 2px 8px -4px #00000080;
	transition: border-color .3s var(--ease), box-shadow .3s var(--ease), background .3s var(--ease);
}

.features__layer:hover {
	border-color: color-mix(in srgb, var(--color-accent) 42%, var(--color-border));
	background: color-mix(in srgb, var(--color-accent) 5%, var(--color-surface-2));
	box-shadow: inset 0 1px 0 #ffffff0d, 0 0 32px -14px var(--color-glow);
}

/* The node sits on the spine; the 5px ring in the page colour breaks the
   spine around it. Its ::after is the connector across to the row. */
.features__node {
	position: absolute;
	top: 50%;
	left: calc(var(--features-spine) - var(--features-rail) - 6px);
	width: 12px;
	height: 12px;
	margin-top: -6px;
	border: 2px solid var(--color-accent);
	border-radius: 50%;
	background: color-mix(in srgb, var(--color-accent) 35%, var(--color-bg));
	box-shadow: 0 0 0 5px var(--color-bg), 0 0 14px -2px var(--color-glow);
}

.features__node::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 12px;
	width: calc(var(--features-rail) - var(--features-spine) - 3px);
	height: 2px;
	background: var(--color-accent);
	transform: translateY(-50%);
}

.features__layer-main {
	display: grid;
	grid-template-columns: 190px 1fr;
	align-items: center;
	gap: 22px;
}

.features__layer-head {
	display: flex;
	align-items: baseline;
	gap: 10px;
}

.features__layer-no {
	color: var(--color-accent-text);
	font-size: 13px;
}

/* Live sets this as body text (line height 1.6), not as a heading. */
.features__layer-title {
	font-size: 16.5px;
	line-height: 1.6;
	letter-spacing: -.01em;
}

@media (max-width: 760px) {
	.features__stack {
		--features-rail: 34px;
		--features-spine: 18px;
	}

	.features__layer-main {
		grid-template-columns: 1fr;
		gap: 13px;
	}
}

@media (prefers-reduced-motion: no-preference) {
	/* The list itself stays put; its parts animate instead. */
	.js .features__stack.reveal {
		opacity: 1;
		translate: none;
		animation: none;
	}

	.js .features__stack::before {
		transform: scaleY(0);
		transition: transform 1s var(--ease-out);
	}

	.js .features__stack.is-visible::before {
		transform: scaleY(1);
	}

	.js .features__stack:not(.is-visible) .features__layer {
		opacity: 0;
	}

	.js .features__stack.is-visible .features__layer {
		animation: features-dock .55s var(--ease-spring) both;
		animation-delay: calc(var(--i) * .16s + .15s);
	}

	.js .features__stack:not(.is-visible) .features__chips .chip {
		opacity: 0;
	}

	.js .features__stack.is-visible .features__chips .chip {
		animation: features-chip-in .4s var(--ease-out) both;
		animation-delay: calc(var(--i) * .16s + var(--j) * 45ms + .45s);
	}

	/* Nodes and connectors start unlit and light in turn as the rows dock. */
	.js .features__node {
		border-color: var(--color-border-strong);
		background: var(--color-bg);
		box-shadow: 0 0 0 5px var(--color-bg);
		transition: border-color .45s var(--ease), background .45s var(--ease), box-shadow .45s var(--ease);
		transition-delay: calc(var(--i) * .16s + .35s);
	}

	.js .features__node::after {
		background: var(--color-border);
		transition: background .45s var(--ease);
		transition-delay: calc(var(--i) * .16s + .35s);
	}

	.js .features__stack.is-visible .features__node {
		border-color: var(--color-accent);
		background: color-mix(in srgb, var(--color-accent) 35%, var(--color-bg));
		box-shadow: 0 0 0 5px var(--color-bg), 0 0 14px -2px var(--color-glow);
	}

	.js .features__stack.is-visible .features__node::after {
		background: var(--color-accent);
	}
}

@keyframes features-dock {
	from {
		opacity: 0;
		transform: translateX(26px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes features-chip-in {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

/* --------------------------------------------------------------------------
   13.9 markets
   -------------------------------------------------------------------------- */

/**
 * 09 Markets: a centred heading and the markets as a centred row of pills.
 *
 * Each pill shows the market's name and its status beside a pulsing dot. The
 * coming soon pill is tinted and carries the shared travelling border
 * (.orbit, in main.css). On the narrowest phones a long pill shrinks to fit
 * and its words wrap inside it, as on the old site, rather than pushing the
 * page wider.
 */

.markets__list {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 14px;
	margin: 40px 0 0;
	padding: 0;
	list-style: none;
}

.markets__pill {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	padding: 12px 18px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background: var(--color-surface);
	transition: transform var(--dur-fast) var(--ease), border-color var(--dur-fast);
}

.markets__pill:hover {
	border-color: var(--color-border-strong);
	transform: translateY(-2px);
}

.markets__name {
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: 15px;
	font-weight: 600;
}

.markets__status {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: 11px;
	letter-spacing: .06em;
	text-transform: uppercase;
}

.markets__dot {
	flex: none;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--color-accent);
	box-shadow: 0 0 8px 1px var(--color-glow);
}

.markets__pill--soon {
	border-color: color-mix(in srgb, var(--color-accent) 42%, var(--color-border));
	background: linear-gradient(180deg, var(--color-glow-soft), transparent 60%), var(--color-surface);
}

.markets__pill--soon .markets__dot {
	width: 7px;
	height: 7px;
}

.markets__note {
	max-width: 560px;
	margin: 18px auto 0;
	color: var(--color-text-dim);
	font-size: 12.5px;
	text-align: center;
}

@media (prefers-reduced-motion: no-preference) {
	.markets__dot {
		animation: markets-pulse 2.4s var(--ease) infinite;
	}
}

@keyframes markets-pulse {
	50% {
		opacity: .5;
	}
}

/* --------------------------------------------------------------------------
   13.10 calculator
   -------------------------------------------------------------------------- */

/**
 * 10. Revenue calculator (#calculator, dark).
 *
 * The section head, then the sliders on a card beside the figures on a
 * glowing panel. The pair sits in the shared .grid--2, so it stacks below
 * 900px like the old site. Both halves stretch to the taller one and centre
 * their contents.
 *
 * The range inputs stay inline-block, as on the old site: each sits in a line
 * box as tall as the body line height, which is what places the thumb 12px
 * lower than a block input would. They render hidden until main.js reveals
 * them; without it the controls read as a list of the starting values (the
 * :has() rules at the end).
 */

.calculator__grid {
	margin-top: 48px;
}

/* Sliders */

.calculator__controls {
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 26px;
}

.calculator__control-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-bottom: 12px;
}

.calculator__label {
	color: var(--color-text-muted);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
	letter-spacing: .04em;
	text-transform: uppercase;
}

.calculator__value {
	flex: none;
	color: var(--color-accent-text);
	font-size: 15px;
}

.calculator__range {
	width: 100%;
	height: 6px;
	margin: 0;
	border-radius: var(--radius-pill);
	background: var(--color-surface-3);
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
}

/* The thumb's dark rim is the page background, with a thin accent ring
   outside it. WebKit and Firefox need separate rules: one unknown
   pseudo-element would void a shared selector list. */
.calculator__range::-webkit-slider-thumb {
	width: 20px;
	height: 20px;
	border: 3px solid var(--color-bg);
	border-radius: 50%;
	background: var(--color-accent);
	box-shadow: 0 0 0 1px var(--color-accent), 0 4px 14px var(--color-glow);
	cursor: pointer;
	transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
	-webkit-appearance: none;
	appearance: none;
}

.calculator__range::-moz-range-thumb {
	width: 18px;
	height: 18px;
	border: 3px solid var(--color-bg);
	border-radius: 50%;
	background: var(--color-accent);
	box-shadow: 0 0 0 1px var(--color-accent), 0 4px 14px var(--color-glow);
	cursor: pointer;
}

.calculator__range::-webkit-slider-thumb:hover {
	transform: scale(1.14);
}

/* The old site removed the focus outline and showed nothing instead. The ring
   here goes round the thumb, where the eye already is; the transparent
   outline still shows in Windows high contrast mode, which drops shadows. */
.calculator__range:focus-visible {
	outline: 2px solid transparent;
}

.calculator__range:focus-visible::-webkit-slider-thumb {
	box-shadow: 0 0 0 1px var(--color-accent), 0 0 0 4px var(--color-surface), 0 0 0 6px var(--color-accent-text), 0 4px 14px var(--color-glow);
}

.calculator__range:focus-visible::-moz-range-thumb {
	box-shadow: 0 0 0 1px var(--color-accent), 0 0 0 4px var(--color-surface), 0 0 0 6px var(--color-accent-text), 0 4px 14px var(--color-glow);
}

/* Figures */

.calculator__results {
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: clamp(26px, 4vw, 34px);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-xl);
	background: linear-gradient(180deg, var(--color-surface), var(--color-bg-alt));
	box-shadow: 0 44px 130px -80px var(--color-glow);
}

.calculator__breakdown,
.calculator__totals,
.calculator__results dd {
	margin: 0;
}

.calculator__row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	padding: 9px 0;
}

.calculator__row + .calculator__row {
	border-top: 1px solid var(--color-hairline);
}

.calculator__row-label {
	color: var(--color-text-muted);
}

.calculator__row-value {
	color: var(--color-text);
	font-size: 17px;
}

.calculator__divider {
	margin: 20px 0;
}

.calculator__total {
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.calculator__total-label {
	margin-top: 8px;
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
	letter-spacing: .05em;
	text-transform: uppercase;
}

.calculator__total-value {
	color: var(--color-text);
	font-size: clamp(30px, 4.6vw, 42px);
	font-weight: 600;
	letter-spacing: -.02em;
	line-height: 1.02;
}

.calculator__year {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
}

/* The rule only belongs between the two, so it goes when the net figure is hidden. */
.calculator__total + .calculator__year {
	margin-top: 14px;
	padding-top: 14px;
	border-top: 1px solid var(--color-border);
}

.calculator__year-label {
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: var(--text-xs);
	letter-spacing: .04em;
	text-transform: uppercase;
}

.calculator__year-value {
	color: var(--color-text-muted);
	font-size: var(--text-base);
}

.calculator__disclaimer {
	margin-top: 18px;
	color: var(--color-text-dim);
	font-size: 12.5px;
	line-height: 1.55;
}

/* Without the script the sliders stay hidden (the script reveals all three or
   none), so each label and value becomes a ruled row, like the figures. */
.calculator__controls:has(.calculator__range[hidden]) {
	gap: 0;
}

.calculator__controls:has(.calculator__range[hidden]) .calculator__control-head {
	margin-bottom: 0;
}

.calculator__controls:has(.calculator__range[hidden]) .calculator__control + .calculator__control {
	margin-top: 14px;
	padding-top: 14px;
	border-top: 1px solid var(--color-border);
}

/* --------------------------------------------------------------------------
   13.11 comparison
   -------------------------------------------------------------------------- */

/**
 * 11. Build vs launch comparison (light).
 *
 * A centred section head, then a card holding a real <table>. Each row is a
 * CSS grid (1.1fr 1fr 1fr, as on the old site), which is why the table and
 * its row groups are display: block; the markup restates the table roles for
 * browsers that drop them once the display changes. Below 640px the rows
 * stack, the header row is hidden visually (screen readers keep it) and the
 * column titles repeated in each cell show instead.
 *
 * The highlighted column's text uses --color-accent-text: the old site used
 * its brighter accent (#15c088), which is about 2.2:1 on the tint and fails
 * WCAG AA. The tint itself is a fill, so it keeps the accent.
 */

.comparison__card {
	max-width: 800px;
	margin: 44px auto 0;
}

.comparison__table {
	display: block;
	width: 100%;
}

.comparison__head,
.comparison__body {
	display: block;
}

/* Zero specificity, so it only resets the browser's table cell styles. */
:where(.comparison__table) :where(th, td) {
	padding: 0;
	font-weight: inherit;
	text-align: left;
}

.comparison__head-row,
.comparison__row {
	display: grid;
	grid-template-columns: 1.1fr 1fr 1fr;
	align-items: center;
	gap: 14px;
}

.comparison__head-row {
	padding-bottom: 12px;
	border-bottom: 1px solid var(--color-border);
}

.comparison__col {
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 11.5px;
	letter-spacing: .05em;
	text-transform: uppercase;
}

.comparison__col--launch {
	justify-self: start;
	color: var(--color-accent-text);
}

/* The old site's 8px corner has no token; --radius-xs is the nearest. */
.comparison__col--launch,
.comparison__launch {
	padding: 6px 12px;
	border-radius: var(--radius-xs);
	background: color-mix(in srgb, var(--color-accent) 9%, transparent);
}

.comparison__row {
	padding: 14px 0;
	border-bottom: 1px solid var(--color-hairline);
}

.comparison__label {
	color: var(--color-text);
	font-size: var(--text-sm);
	font-weight: 600;
}

.comparison__build {
	color: var(--color-text-dim);
	font-size: 13px;
}

.comparison__launch {
	color: var(--color-accent-text);
	font-size: 13px;
	font-weight: 600;
}

/* The column titles repeated in each cell, for the stacked phone layout. */
.comparison__cell-label {
	display: none;
}

.comparison__ref {
	margin-left: 1px;
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: .62em;
	font-weight: 700;
	vertical-align: super;
}

.comparison__footnote {
	display: flex;
	align-items: flex-start;
	gap: 9px;
	margin-top: 18px;
	color: var(--color-text-dim);
	font-size: var(--text-xs);
	line-height: 1.5;
}

.comparison__note-number {
	display: inline-flex;
	flex: none;
	align-items: center;
	justify-content: center;
	width: 18px;
	height: 18px;
	margin-top: .5px;
	border-radius: var(--radius-pill);
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-family: var(--font-mono);
	font-size: 10.5px;
	font-weight: 700;
	line-height: 1;
}

@media (max-width: 640px) {
	/* Hidden visually rather than with display: none, so screen readers still
	   hear each entry's column title from the real header. */
	.comparison__head {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.comparison__row {
		grid-template-columns: 1fr;
		gap: 4px;
		padding: 16px 0;
	}

	/* The weight is inherited, so the highlighted column's title is bold, as on the old site. */
	.comparison__cell-label {
		display: block;
		margin-bottom: 2px;
		color: var(--color-text-dim);
		font-family: var(--font-mono);
		font-size: 10.5px;
		letter-spacing: .05em;
		text-transform: uppercase;
	}

	.comparison__launch {
		padding: 0;
		background: none;
	}
}

/* The rows follow the card in, one after another (--i is each row's index). */
@media (prefers-reduced-motion: no-preference) {
	.js .comparison__row {
		opacity: 0;
		transform: translateY(8px);
		transition: opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
	}

	.js .comparison__card.is-visible .comparison__row {
		opacity: 1;
		transform: none;
		transition-delay: calc(var(--i, 0) * 60ms);
	}
}

/* --------------------------------------------------------------------------
   13.12 audience
   -------------------------------------------------------------------------- */

/**
 * 12 Who it's for: the heading block over three persona cards in a row (one
 * column at 900px and below, from the shared .grid--3).
 *
 * - The cards lean towards the pointer and lift on hover (the shared .tilt and
 *   .card--hover rules). On the old site a bug in its reveal cancelled both,
 *   so its cards only changed border, shadow and the glow under the pointer.
 */

/* The gap belongs to the pair, so cards without a heading block start at the top. */
.audience .section-head + .audience__grid {
	margin-top: 48px;
}

.audience__grid {
	padding: 0;
	list-style: none;
}

.audience__card {
	height: 100%;
}

/* Card sizes are fixed on the old site rather than following the h3 scale. */
.audience__title {
	margin-top: 18px;
	font-size: 19px;
}

.audience__title:first-child {
	margin-top: 0;
}

.audience__text {
	margin-top: 10px;
	font-size: 14.5px;
}

/* --------------------------------------------------------------------------
   13.13 faq
   -------------------------------------------------------------------------- */

/**
 * 13 FAQ: a centred heading over the questions, each a native details element
 * whose plus sign turns into a cross (a 135 degree turn) as it opens.
 *
 * - The list is capped at 810px and centred, as on the old site.
 * - Each item clips to its rounded corners, and overflow goes with position
 *   by the house rule. The clip would hide the global focus ring, which sits
 *   outside the element, so the question's ring is drawn inside it instead,
 *   in the accent text colour, which keeps 3:1 or better on either palette.
 * - Answers are paragraphs: a blank line in the answer field starts a new one.
 */

/* The gap belongs to the pair, so a list without a heading starts at the top. */
.faq .section-head + .faq__list {
	margin-top: 40px;
}

.faq__list {
	max-width: 810px;
	margin-inline: auto;
}

.faq__item {
	position: relative;
	overflow: hidden;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background: var(--color-surface);
	overflow-wrap: anywhere;
}

.faq__item + .faq__item {
	margin-top: 12px;
}

.faq__summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 18px;
	padding: 20px 22px;
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: 17px;
	font-weight: 600;
	list-style: none;
	cursor: pointer;
}

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

.faq__summary:hover {
	color: var(--color-accent-text);
}

.faq__summary:focus-visible {
	border-radius: calc(var(--radius-md) - 1px);
	outline-color: var(--color-accent-text);
	outline-offset: -4px;
}

.faq__icon {
	position: relative;
	flex: none;
	width: 18px;
	height: 18px;
}

.faq__icon::before,
.faq__icon::after {
	content: "";
	position: absolute;
	border-radius: var(--radius-pill);
	background: var(--color-accent);
}

/* The accent is 1.6:1 on white; the sign shows the open state, so it needs 3:1. */
.section--light .faq__icon::before,
.section--light .faq__icon::after {
	background: var(--color-accent-text);
}

/* Windows high contrast replaces backgrounds, so the sign and the slider
   track would vanish. */
@media (forced-colors: active) {
	.faq__icon::before,
	.faq__icon::after {
		background: CanvasText;
	}

	.calculator__range {
		border: 1px solid CanvasText;
	}
}

/* The bar across, then the bar down, each 2px thick. */
.faq__icon::before {
	inset: 8px 0;
}

.faq__icon::after {
	inset: 0 8px;
}

.faq__item[open] .faq__icon {
	transform: rotate(135deg);
}

.faq__answer {
	max-width: 74ch;
	padding: 0 22px 22px;
	color: var(--color-text-muted);
	line-height: 1.62;
}

.faq__answer p + p {
	margin-top: .8em;
}

@media (prefers-reduced-motion: no-preference) {
	.faq__icon {
		transition: transform var(--dur) var(--ease);
	}
}

/* ==========================================================================
   14. Inner pages
   One block per template.
   ========================================================================== */

/* --------------------------------------------------------------------------
   14.1 blog
   -------------------------------------------------------------------------- */

/**
 * 21 Blog: the posts page (the heading block, the category filter, the post
 * cards and the empty category message) and the category, tag, date and
 * author archives, which reuse the heading block and cards without the filter.
 *
 * - WordPress puts the class "blog" on the body of the posts page, so no rule
 *   here targets .blog on its own: every selector starts from an element class.
 * - The filter renders hidden and the script reveals it (initBlogFilter() in
 *   main.js), so without JavaScript every post shows and there is no filter.
 * - The grid's smallest column is capped at the container width. The old site
 *   used a flat 320px, which pushed the cards past the edge of a 320px screen.
 */

/* Heading block. The old site set these gaps inline on the heading and lead. */
.blog__head {
	max-width: 680px;
	margin-top: 26px;
}

.blog__eyebrow + .blog__title {
	margin-top: 14px;
}

.blog__title + .blog__lead {
	margin-top: 16px;
}

/* An archive's description can hold more than one paragraph. */
.blog__lead > p + p {
	margin-top: .8em;
}

/* Category filter: a wrapping row of pills, the selected one filled. */
.blog-filter {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-top: 30px;
}

.blog-filter__pill {
	padding: 8px 15px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background: var(--color-surface);
	color: var(--color-text-muted);
	font-family: var(--font-mono);
	font-size: 12.5px;
	letter-spacing: .02em;
	cursor: pointer;
	transition: transform var(--dur-fast) var(--ease), color var(--dur-fast), border-color var(--dur-fast), background var(--dur-fast);
}

@media (hover: hover) {
	.blog-filter__pill:hover {
		border-color: var(--color-border-strong);
		color: var(--color-text);
		transform: translateY(-1px);
	}
}

/* After the hover rule, so the selected pill keeps its colours under the pointer. */
.blog-filter__pill.is-active {
	border-color: var(--color-accent);
	background: var(--color-accent);
	color: var(--color-on-accent);
}

/* Cards: as many 320px columns as fit, the featured card across the row. */
.blog__grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
	gap: 22px;
	margin-top: 34px;
}

.blog__empty {
	margin-top: 40px;
	color: var(--color-text-dim);
}

/* position and overflow go together so the cover stays inside the corners. */
.blog-card {
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background: var(--color-surface);
	color: inherit;
	text-decoration: none;
	transition: transform var(--dur) var(--ease), border-color var(--dur-fast), box-shadow var(--dur);
}

/* The old site's blog card glows on hover without the inset top highlight
   that --shadow-card-hover adds for the homepage cards, so the glow is
   written out here. */
@media (hover: hover) {
	.blog-card:hover {
		border-color: var(--color-border-strong);
		box-shadow: 0 26px 60px -34px var(--color-glow);
		transform: translateY(-4px);
	}

	.blog-card:hover .blog-card__arrow {
		transform: translateX(3px);
	}
}

/* Keyboard focus gets the global ring plus the hover edge and arrow nudge. */
.blog-card:focus-visible {
	border-color: var(--color-border-strong);
}

.blog-card:focus-visible .blog-card__arrow {
	transform: translateX(3px);
}

.blog-card__cover {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	height: 168px;
	border-bottom: 1px solid var(--color-border);
	background:
		radial-gradient(70% 90% at 50% 40%, var(--color-glow-soft), transparent 70%),
		linear-gradient(180deg, var(--color-surface-2), var(--color-bg-alt));
}

.blog-card__mark {
	color: var(--color-accent);
	opacity: .9;
	filter: drop-shadow(0 6px 22px var(--color-glow));
}

.blog-card__tag {
	position: absolute;
	top: 14px;
	left: 14px;
}

.blog-card__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	padding: 22px;
}

.blog-card__meta {
	color: var(--color-text-dim);
	font-size: var(--text-xs);
}

.blog-card__title {
	margin-top: 10px;
	font-size: 19px;
	line-height: 1.25;
	letter-spacing: -.01em;
}

/* Three lines at most; position goes with overflow by the house rule. */
.blog-card__excerpt {
	position: relative;
	display: -webkit-box;
	overflow: hidden;
	margin-top: 10px;
	font-size: 14.5px;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
}

/* Pushed to the foot of the card, so the links line up across a row. */
.blog-card__more {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	margin-top: auto;
	padding-top: 16px;
	color: var(--color-accent-text);
	font-size: var(--text-sm);
	font-weight: 500;
}

.blog-card__arrow {
	flex: none;
	transition: transform var(--dur-fast) var(--ease);
}

.blog-card--featured {
	grid-column: 1 / -1;
}

/* From 760px the featured card lays its cover beside the text. */
@media (min-width: 760px) {
	.blog-card--featured {
		flex-direction: row;
	}

	.blog-card--featured .blog-card__cover {
		width: 42%;
		height: auto;
		min-height: 240px;
		border-right: 1px solid var(--color-border);
		border-bottom: 0;
	}

	.blog-card--featured .blog-card__body {
		justify-content: center;
		padding: 34px;
	}

	.blog-card--featured .blog-card__title {
		font-size: clamp(22px, 2.4vw, 30px);
	}

	.blog-card--featured .blog-card__excerpt {
		font-size: 15.5px;
		-webkit-line-clamp: 4;
	}
}

/* --------------------------------------------------------------------------
   14.2 single
   -------------------------------------------------------------------------- */

/**
 * 22 Single post: the back link, the head (category, title and meta line),
 * the lead, then the body with the "On this page" contents beside it.
 *
 * - Measurements are the old site's .article rules, in a 760px column.
 * - The contents list shows from 1240px only, in the space left of the column,
 *   and sticks under the header while the post scrolls; narrower screens have
 *   no room for it, and the old site hides it there too.
 * - The gap between the lead and the body is the body's first margin (48px
 *   before a heading, 16px before a paragraph) collapsing through the layout
 *   wrappers, so nothing here may start a new formatting context.
 * - Only a body that opens with a paragraph gets the drop cap (the short
 *   announcement); one that opens with a heading has none, as on the old site.
 * - Body headings are offset for the admin bar and a pending entrance only:
 *   the header's own offset is the page's scroll-padding-top (main.css,
 *   3. Base), so a contents link always lands 18px below the header, where
 *   the old site aims it.
 * - Links, bold text, numbered lists, h4, images and rules follow the theme:
 *   the old site's posts use none of them.
 */

.article__inner {
	max-width: 760px;
	margin-inline: auto;
	padding: clamp(70px, 9vw, 116px) 0 clamp(50px, 7vw, 88px);
	overflow-wrap: break-word;
}

/* Head */

.article__head {
	padding-bottom: 26px;
	border-bottom: 1px solid var(--color-border);
}

.article__title {
	margin-top: 16px;
	font-size: clamp(30px, 4.6vw, 44px);
	line-height: 1.1;
}

.article__title:first-child {
	margin-top: 0;
}

.article__meta {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	margin-top: 22px;
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 12.5px;
}

.article__lead {
	margin-top: 18px;
	color: var(--color-text-muted);
	font-size: 18px;
	line-height: 1.6;
}

.article__layout {
	position: relative;
	margin-top: 8px;
}

/* Contents */

.article__toc {
	display: none;
}

.article__toc-title {
	display: block;
	margin-bottom: 14px;
	color: var(--color-text-dim);
	font-size: 11px;
	letter-spacing: .14em;
	text-transform: uppercase;
}

.article__toc-list {
	display: grid;
	gap: 9px;
	margin: 0;
	padding: 0;
	border-left: 1px solid var(--color-border);
	list-style: none;
}

.article__toc-link {
	display: block;
	margin-left: -1px;
	padding-left: 14px;
	border-left: 1px solid transparent;
	color: var(--color-text-dim);
	font-size: 12.5px;
	line-height: 1.35;
	text-decoration: none;
	transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.article__toc-link:hover {
	color: var(--color-text-muted);
}

.article__toc-link.is-active {
	border-left-color: var(--color-accent);
	color: var(--color-accent-text);
}

@media (min-width: 1240px) {
	.article__toc {
		position: absolute;
		top: 0;
		right: 100%;
		display: block;
		width: 190px;
		height: 100%;
		margin-right: 34px;
	}

	/* The list scrolls inside itself when it is taller than the window. The
	   4px padding, cancelled by the negative margin, top and max-height,
	   leaves room for the focus ring inside that scroll box: the list sits
	   exactly where the old site's did (118px from the top, 150px shorter
	   than the window). */
	.article__toc-inner {
		position: sticky;
		top: 114px;
		max-height: calc(100vh - 142px);
		margin: -4px;
		padding: 4px;
		overflow-y: auto;
		scroll-padding-block: 4px;
	}
}

/* Body */

.article__body {
	margin-top: 8px;
}

/* Page links for a post split with a page break (none on the old site). */
.article__pages {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	margin-top: 40px;
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 13px;
}

.article__pages a {
	color: var(--color-accent-text);
}

.article__pages .current {
	color: var(--color-text);
}

.article__body h2 {
	margin-top: 48px;
	font-size: clamp(22px, 2.6vw, 28px);
	letter-spacing: -.01em;
}

.article__body h3 {
	margin-top: 30px;
	font-size: clamp(17px, 2vw, 20px);
}

.article__body h4 {
	margin-top: 26px;
	font-size: 17px;
}

.article__body h2,
.article__body h3,
.article__body h4 {
	scroll-margin-top: var(--wp-admin--admin-bar--height, 0px);
}

/* A heading that has not faded in yet still sits 16px low (the entrance
   offset in main.css, 6. Motion), and a contents link aims at that spot, so
   the heading would settle almost against the header. The extra margin
   cancels the offset; keep the two numbers in step. */
@media (prefers-reduced-motion: no-preference) {
	.js .article__body h2.reveal:not(.is-visible),
	.js .article__body h3.reveal:not(.is-visible),
	.js .article__body h4.reveal:not(.is-visible) {
		scroll-margin-top: calc(var(--wp-admin--admin-bar--height, 0px) + 16px);
	}
}

.article__body p {
	margin-top: 16px;
	color: var(--color-text-muted);
	font-size: 16px;
	line-height: 1.75;
}

.article__body > p:first-child::first-letter {
	float: left;
	margin: 6px 12px 0 0;
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: 3.1em;
	font-weight: 600;
	line-height: .82;
}

.article__body ul,
.article__body ol {
	display: grid;
	gap: 10px;
	margin-top: 16px;
	padding: 0;
	list-style: none;
}

.article__body li {
	position: relative;
	padding-left: 24px;
	color: var(--color-text-muted);
	line-height: 1.6;
}

.article__body ul > li::before {
	content: "";
	position: absolute;
	top: 10px;
	left: 6px;
	width: 6px;
	height: 6px;
	border-radius: 2px;
	background: var(--color-accent);
}

.article__body ol {
	counter-reset: article-list;
}

.article__body ol > li {
	counter-increment: article-list;
}

.article__body ol > li::before {
	content: counter(article-list) ".";
	position: absolute;
	top: 0;
	left: 0;
	color: var(--color-accent-text);
	font-family: var(--font-mono);
	font-size: 13px;
	line-height: 1.6rem;
}

.article__body blockquote {
	margin: 40px 0 8px;
	padding: 6px 0 6px 26px;
	border-left: 2px solid var(--color-accent);
}

.article__body blockquote p {
	margin: 0;
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: clamp(19px, 2.4vw, 23px);
	font-weight: 500;
	letter-spacing: -.01em;
	line-height: 1.4;
}

.article__body blockquote p + p {
	margin-top: 12px;
}

.article__body a {
	color: var(--color-accent-text);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	transition: color var(--dur-fast);
}

.article__body a:hover {
	color: var(--color-text);
}

.article__body strong,
.article__body b {
	color: var(--color-text);
	font-weight: 600;
}

.article__body figure {
	margin-top: 24px;
}

.article__body img {
	border-radius: var(--radius-sm);
}

.article__body hr {
	margin: 40px 0 0;
	border: 0;
	border-top: 1px solid var(--color-border);
}

/* --------------------------------------------------------------------------
   14.3 doc
   -------------------------------------------------------------------------- */

/**
 * Document pages: About, Privacy Policy and Terms & Conditions.
 *
 * One narrow column with the old site's .doc spacing and type scale. The
 * article sets its own padding (there is no .section wrapper, as on the old
 * site). The body is editor content with no wrappers of its own, so the h2 top
 * margin does the work of the old site's section elements, and About's closing
 * line is the content's blockquote, drawn with the .callout tokens.
 *
 * The old site set some spacing inline; it is reproduced here: 16px above
 * About's heading, the 18px introduction in the full text colour, 34px above
 * the quote and 30px above the line after it.
 */

.doc {
	max-width: 760px;
	margin-inline: auto;
	padding: clamp(80px, 10vw, 128px) 0 clamp(60px, 8vw, 100px);
}

.doc__title {
	font-size: clamp(32px, 5vw, 46px);
}

/* The label sits in its own paragraph, so it starts a new line below the back
   link at every width. Inside it the label keeps .eyebrow's inline-flex, in a
   line of body text height, as the old site's label did when it wrapped below
   the back link at narrow widths. (Wider, the old site ran the two together.) */
.doc__eyebrow + .doc__title {
	margin-top: 16px;
}

.doc__updated {
	margin-top: 10px;
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 12.5px;
	line-height: 1.7;
}

.doc__intro {
	margin-top: 14px;
	color: var(--color-text);
	font-size: 18px;
	line-height: 1.7;
}

/* Editor content. The first element's top margin passes through the wrapper,
   so the body starts 14px below the line above it, as on the old site. */
.doc__body h2 {
	margin-top: 40px;
	font-size: clamp(20px, 2.4vw, 26px);
}

.doc__body h3,
.doc__body h4 {
	margin-top: 28px;
}

.doc__body p,
.doc__body li {
	margin-top: 14px;
	color: var(--color-text-muted);
	line-height: 1.7;
}

.doc__body ul,
.doc__body ol {
	margin-top: 14px;
	padding-left: 20px;
}

/* The old site's lists have no markers, only the indent. Numbered lists keep
   their numbers. */
.doc__body ul {
	list-style: none;
}

.doc__body li {
	margin-top: 8px;
}

/* Links keep an underline, as in other editor content: the link colour alone
   is only 1.9:1 against the paragraph text. */
.doc__body a {
	color: var(--color-accent-text);
	text-underline-offset: 3px;
}

.doc__body blockquote {
	margin-top: 34px;
	padding: 14px 18px;
	border-left: 2px solid var(--color-accent);
	border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
	background: linear-gradient(90deg, var(--color-glow-soft), transparent);
	color: var(--color-text-muted);
}

.doc__body blockquote > :first-child {
	margin-top: 0;
}

.doc__body blockquote + p {
	margin-top: 30px;
}

/* --------------------------------------------------------------------------
   14.4 contact
   -------------------------------------------------------------------------- */

/**
 * 24 Contact: the Contact page's introduction (the contact details and the
 * demo prompt) beside the Contact Form 7 form card, and the thank-you panel
 * that replaces the form once a message is sent.
 *
 * - Blocks: contact (the page), contact-form (the fields and everything
 *   Contact Form 7 prints), contact-success (the thank-you panel).
 * - Measurements are the old site's .apply-*, .field, .input, .textarea and
 *   .form-error rules. Its inline spacing (18px above the heading and the
 *   introduction, 20px above the button) is written here on element classes.
 * - Contact Form 7's stylesheet never loads (inc/forms.php), so this file also
 *   covers what it would have: the hidden-fields fieldset, the summary for
 *   screen readers, the invalid state and its tips, the response line and the
 *   spinner. Controls are styled by the plugin's own classes, so a text field
 *   added in the form editor picks up the look without extra classes.
 * - The columns and the name row stack at 900px, as on the old site.
 */

/* Page layout */

.contact__grid {
	align-items: start;
	gap: clamp(30px, 5vw, 54px);
}

/* Without a form card, the introduction takes the full width. */
.contact__intro:only-child {
	grid-column: 1 / -1;
}

/* Every part is optional, so whichever comes first sits flush. */
.contact__intro > :first-child {
	margin-top: 0;
}

.contact__title,
.contact__lead {
	margin-top: 18px;
}

.contact__microlabel {
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 11.5px;
	letter-spacing: .05em;
	text-transform: uppercase;
}

.contact__email {
	display: flex;
	align-items: center;
	gap: 14px;
	margin-top: 30px;
	padding: 14px 16px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background: var(--color-surface);
	color: var(--color-text);
	line-height: 1.4;
	text-decoration: none;
	transition: border-color var(--dur-fast), background var(--dur-fast);
}

.contact__email:hover {
	border-color: var(--color-border-strong);
	background: var(--color-surface-2);
}

/* A long address wraps inside the card rather than widening the page. */
.contact__email-text {
	min-width: 0;
	overflow-wrap: anywhere;
}

.contact__hq {
	margin-top: 24px;
}

.contact__address {
	display: grid;
	gap: 2px;
	margin-top: 8px;
	color: var(--color-text-muted);
	font-size: 14.5px;
	font-style: normal;
	line-height: 1.5;
}

.contact__callout {
	margin-top: 26px;
}

.contact__callout-link {
	color: var(--color-accent-text);
	text-decoration: underline;
}

/* Form: Contact Form 7's markup */

/* The plugin's hidden inputs sit in a fieldset that would otherwise draw a
   border. Hidden inputs are still sent. */
.contact-form .hidden-fields-container {
	display: none;
}

/* The plugin's summary for screen readers: announced, not shown. Its error
   list holds links to the fields, so it comes into view while a keyboard user
   is on one of them, rather than taking focus unseen. */
.contact-form .screen-reader-response {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	border: 0;
	white-space: nowrap;
}

.contact-form .screen-reader-response:focus-within {
	position: static;
	width: auto;
	height: auto;
	margin: 0 0 16px;
	overflow: visible;
	clip-path: none;
	white-space: normal;
}

.contact-form .screen-reader-response ul {
	margin: 0;
	padding-left: 18px;
	font-size: 13px;
	line-height: 1.6;
}

.contact-form .screen-reader-response a {
	color: var(--color-danger);
}

.contact-form__row {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 16px;
}

.contact-form__field {
	display: flex;
	flex-direction: column;
	gap: 7px;
	min-width: 0;
}

.contact-form form > .contact-form__field {
	margin-top: 16px;
}

.contact-form label {
	color: var(--color-text-dim);
	font-family: var(--font-mono);
	font-size: 11.5px;
	letter-spacing: .05em;
	text-transform: uppercase;
}

.contact-form .wpcf7-form-control-wrap {
	display: block;
}

.contact-form .wpcf7-text,
.contact-form .wpcf7-textarea {
	display: block;
	width: 100%;
	margin: 0;
	padding: 12px 14px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	background: var(--color-surface);
	color: var(--color-text);
	font-family: var(--font-body);
	font-size: 15px;
	line-height: 1.6;
	transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}

.contact-form .wpcf7-textarea {
	min-height: 130px;
	resize: vertical;
}

.contact-form ::placeholder {
	color: color-mix(in oklab, var(--color-text) 50%, transparent);
	opacity: 1;
}

/* The accent border and soft ring replace the outline, as on the old site.
   The transparent outline shows in forced colours, where shadows are dropped. */
.contact-form .wpcf7-text:focus,
.contact-form .wpcf7-textarea:focus {
	border-color: var(--color-accent);
	outline: 2px solid transparent;
	box-shadow: 0 0 0 3px var(--color-glow-soft);
}

/* Invalid: the plugin marks the control and adds a tip under it. The tip is
   hidden from screen readers, which hear the plugin's summary instead. */
.contact-form .wpcf7-not-valid {
	border-color: var(--color-danger);
}

.contact-form .wpcf7-not-valid:focus {
	border-color: var(--color-danger);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-danger) 20%, transparent);
	outline: 2px solid var(--color-danger);
	outline-offset: 2px;
}

.contact-form .wpcf7-not-valid-tip {
	display: block;
	margin-top: 6px;
	color: var(--color-danger);
	font-size: 12.5px;
	line-height: 1.5;
}

/* The honeypot: moved off screen rather than hidden with display: none,
   which bots skip. */
.contact-form__trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
	opacity: 0;
}

/* The response line above the button, where the old site showed its error.
   It stays out of the layout while empty. */
.contact-form .wpcf7-response-output {
	margin-top: 14px;
	color: var(--color-danger);
	font-size: 13px;
	line-height: 1.5;
}

.contact-form .wpcf7-response-output:empty {
	display: none;
}

/* Sent, on a page without a thank-you panel to take over. */
.contact-form .sent .wpcf7-response-output {
	color: var(--color-accent-text);
}

/* The wrapper positions the plugin's spinner, which follows the button. */
.contact-form__actions {
	position: relative;
	margin-top: 20px;
}

.contact-form__submit {
	display: flex;
	width: 100%;
}

/* One message at a time: the button ignores clicks while one sends. */
.contact-form .submitting .contact-form__submit {
	pointer-events: none;
}

/* A small ring inside the right end of the button while a message sends. */
.contact-form .wpcf7-spinner {
	position: absolute;
	top: 50%;
	right: 18px;
	width: 18px;
	height: 18px;
	margin-top: -9px;
	border: 2px solid color-mix(in srgb, var(--color-on-accent) 25%, transparent);
	border-top-color: var(--color-on-accent);
	border-radius: 50%;
	visibility: hidden;
	pointer-events: none;
}

.contact-form .submitting .wpcf7-spinner {
	visibility: visible;
}

.contact-form__note {
	margin-top: 12px;
	color: var(--color-text-dim);
	font-size: 12.5px;
	text-align: center;
}

/* Thank-you panel */

.contact-success {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 26px 8px;
	text-align: center;
}

.contact-success__icon {
	width: 54px;
	height: 54px;
}

.contact-success__icon .icon {
	width: 26px;
	height: 26px;
}

.contact-success__title {
	margin-top: 18px;
}

/* The heading takes focus when the panel opens. It is not a control, so it
   shows no ring. */
.contact-success__title:focus {
	outline: none;
}

.contact-success__text {
	margin-top: 8px;
}

.contact-success__reset {
	margin-top: 20px;
}

@media (max-width: 900px) {
	.contact-form__row {
		grid-template-columns: 1fr;
	}
}

@media (prefers-reduced-motion: no-preference) {
	.contact-form .wpcf7-spinner {
		animation: contact-form-spin .8s linear infinite;
	}

	.js .contact-success {
		animation: contact-success-in .45s var(--ease-out) both;
	}
}

@keyframes contact-form-spin {
	to {
		transform: rotate(360deg);
	}
}

@keyframes contact-success-in {
	from {
		opacity: 0;
		transform: translateY(8px) scale(.98);
	}
}

/* High contrast (forced colours): the selected pill and the section being
   read keep a marker of their own once the theme's colours are replaced. */
@media (forced-colors: active) {
	.blog-filter__pill.is-active {
		forced-color-adjust: none;
		border-color: SelectedItem;
		background: SelectedItem;
		color: SelectedItemText;
	}

	.article__toc-link.is-active {
		text-decoration: underline;
	}
}
