/*
 * base.css — design tokens, resets, typography, dark mode.
 * Every other CSS file in this theme reads these custom properties;
 * nothing below should hard-code a color, space or radius value.
 */

:root {
	/* Brand.

	   --brand is the identity blue and stays exactly as it is, but it is
	   a FILL colour only — icon tiles, rails, dots, glows. As text on
	   white it measures 4.30:1 and on --surface-alt 4.07:1, both under
	   the 4.5 AA needs for normal text, and white on it is likewise
	   4.30. So text and button fills use --brand-text instead, which is
	   the same hue darkened to clear AA in both directions:
	   6.12 on white, 5.79 on --surface-alt, 6.12 for white on it. */
	--brand: #1B7FC4;
	--brand-text: #15669F;
	--brand-deep: #0E5C93;
	--brand-light: #EAF4FC;
	/* The brand is unreadable on navy (2.2:1), so dark bands use this
	   lightened tint instead — 9.49:1 on --navy. It was already in the
	   CSS as a bare #8FC6EF in four places; this makes it a token. */
	--brand-on-dark: #8FC6EF;
	--brand-rgb: 27, 127, 196;
	--brand-text-rgb: 21, 102, 159;

	/* Neutrals — light mode */
	--ink: #0B1220;
	--ink-soft: #1E2A3C;
	--navy: #0B1B2E;
	--navy-soft: #13253D;
	--navy-line: rgba(255, 255, 255, 0.12);
	--surface: #FFFFFF;
	--surface-alt: #F6F9FC;
	--surface-raised: #FFFFFF;
	--muted: #5A6B80;
	/* Every --muted-soft use is real informational text at 13px — post
	   dates, breadcrumbs, field hints, testimonial roles, comment meta —
	   so it has to clear AA at small size. The old #8395A9 measured 3.07
	   on white and 2.91 on --surface-alt; this clears both (4.80 / 4.54)
	   with the least darkening that gets there, so it still reads a step
	   lighter than --muted. */
	--muted-soft: #627488;
	--border: #E4E9F0;
	--border-soft: #EEF2F6;
	/* Foreground for anything sitting ON a brand fill. Declared here and
	   flipped in the dark blocks below, because the dark-mode brand is
	   light enough that white on it drops to 3.03:1. */
	--on-brand: #FFFFFF;

	/* Type — Fraunces carries the display voice, Inter Tight the reading
	   and UI voice, IBM Plex Mono every technical label.

	   Fraunces replaced Bricolage Grotesque because Bricolage was not
	   actually contrasting with the body face: measured at 100px/700 its
	   x-height was 53 against Inter Tight's 55 and its width 513 against
	   549, so headings read as larger body text rather than as a second
	   voice. Worse, its cap-height (66) was SHORTER than Inter Tight's
	   (73), which is why headings had to be set so large to feel like
	   headings. Fraunces runs an 18% smaller x-height and a taller cap
	   (70), so it reads as a genuinely different face and carries more
	   presence per pixel.

	   Inter Tight is the first fallback deliberately: if the webfont
	   fails, headings drop to the body sans rather than to Times. */
	--font-display: 'Fraunces', 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
	--font-body: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
	--font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Consolas, Menlo, monospace;

	/* Fluid spacing scale */
	--space-3xs: clamp(0.25rem, 0.22rem + 0.15vw, 0.375rem);
	--space-2xs: clamp(0.5rem, 0.45rem + 0.2vw, 0.625rem);
	--space-xs: clamp(0.75rem, 0.68rem + 0.3vw, 0.875rem);
	--space-s: clamp(1rem, 0.9rem + 0.4vw, 1.25rem);
	--space-m: clamp(1.5rem, 1.3rem + 0.8vw, 2rem);
	--space-l: clamp(2.25rem, 1.9rem + 1.4vw, 3rem);
	--space-xl: clamp(3.5rem, 2.8rem + 2.8vw, 5.5rem);
	--space-2xl: clamp(5rem, 4rem + 4vw, 8rem);

	/* Fluid type scale.

	   The previous scale topped out at 6rem for --text-3xl, but both H1
	   rules overrode it with their own smaller clamps while H2 kept the
	   full --text-2xl. The result was H2 (62px) > hero H1 (52px) > page
	   H1 (48px) on every page and every breakpoint — the page title was
	   the smallest heading on the page.

	   Fixed by bringing H2/H3 down rather than pushing H1 up, so the
	   hero keeps the height it was tuned to, and by letting both H1s
	   use --text-3xl instead of carrying bespoke clamps. Ratios now run
	   56/42 = 1.33 and 42/30 = 1.40. */
	--text-xs: 0.8125rem;
	--text-s: 0.9375rem;
	--text-m: 1.0625rem;
	/* --text-l does real work now: card titles and lead paragraphs, the
	   step that used to be missing between 30px headings and 17px body. */
	--text-l: clamp(1.25rem, 1.13rem + 0.5vw, 1.4rem);
	--text-xl: clamp(1.5rem, 1.32rem + 0.7vw, 1.875rem);
	--text-2xl: clamp(1.95rem, 1.5rem + 1.7vw, 2.625rem);
	--text-3xl: clamp(2.4rem, 1.7rem + 2.6vw, 3.5rem);

	/* Tracking pairs with the sizes above — display type needs to pull
	   in hard at large sizes or it reads loose and cheap. */
	--track-3xl: -0.045em;
	--track-2xl: -0.035em;
	--track-xl: -0.025em;

	--radius-s: 10px;
	--radius-m: 16px;
	--radius-l: 24px;
	--radius-full: 999px;

	--shadow-s: 0 1px 2px rgba(11,18,32,.07), 0 1px 1px rgba(11,18,32,.04);
	--shadow-m: 0 10px 28px rgba(11,18,32,.09), 0 2px 6px rgba(11,18,32,.05);
	--shadow-l: 0 28px 70px rgba(11,18,32,.16), 0 10px 22px rgba(11,18,32,.08);
	--shadow-brand: 0 14px 30px rgba(var(--brand-text-rgb), .28);

	--ease: cubic-bezier(.22,1,.36,1);
	--ease-out: cubic-bezier(.16,1,.3,1);
	/* Overshoot curve — the spring feel on segmented controls, chips
	   and anything that "lands" rather than merely arriving. */
	--ease-spring: cubic-bezier(.34,1.56,.64,1);
	/* Heavy in-out used for full-band colour inversion wipes. */
	--ease-wipe: cubic-bezier(.76,0,.24,1);
	--dur-fast: 180ms;
	--dur-base: 340ms;
	--dur-slow: 620ms;
	--dur-xslow: 950ms;

	--container: 1200px;
	--container-narrow: 820px;
	--header-h: 82px;

	color-scheme: light;
}

/*
 * Dark mode has three states, matched to assets/js/app.js's toggle:
 * explicit light (data-theme="light"), explicit dark (data-theme="dark"),
 * and "system" (no attribute at all — prefers-color-scheme decides).
 * Tokens are redefined, never given a single source of truth inside a
 * media/attribute block, so both paths always agree.
 */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		color-scheme: dark;
		--ink: #E8EEF6;
		--ink-soft: #C9D4E2;
		--navy: #060D18;
		--navy-soft: #0B1B2E;
		--navy-line: rgba(255, 255, 255, 0.1);
		--surface: #0E1626;
		--surface-alt: #101C30;
		--surface-raised: #142238;
		--muted: #93A4BA;
		/* Lightened from #6C7F96, which measured 4.40 on --surface and
		   4.15 on --surface-alt — the same AA miss the light-mode value
		   had. Now 4.88 / 4.61, still clearly dimmer than --muted. */
		--muted-soft: #748799;
		--border: #223349;
		--border-soft: #1A2942;
		--brand: #3D9BDD;
		/* On a dark surface the brand is already light enough to read as
		   text (5.97:1 on --surface), so it doubles as --brand-text. */
		--brand-text: #3D9BDD;
		--brand-text-rgb: 61, 155, 221;
		--brand-deep: #1B7FC4;
		--brand-light: rgba(61, 155, 221, 0.14);
		--brand-on-dark: #8FC6EF;
		/* White on #3D9BDD is only 3.03:1. Navy on it is 6.22:1, so
		   filled brand controls invert their label in dark mode. */
		--on-brand: #06121F;
		--shadow-s: 0 1px 2px rgba(0,0,0,.35), 0 1px 1px rgba(0,0,0,.25);
		--shadow-m: 0 10px 28px rgba(0,0,0,.4), 0 2px 6px rgba(0,0,0,.3);
		--shadow-l: 0 28px 70px rgba(0,0,0,.5), 0 10px 22px rgba(0,0,0,.35);
	}
}

[data-theme="dark"] {
	color-scheme: dark;
	--ink: #E8EEF6;
	--ink-soft: #C9D4E2;
	--navy: #060D18;
	--navy-soft: #0B1B2E;
	--navy-line: rgba(255, 255, 255, 0.1);
	--surface: #0E1626;
	--surface-alt: #101C30;
	--surface-raised: #142238;
	--muted: #93A4BA;
	/* Lightened from #6C7F96, which measured 4.40 on --surface and
	   4.15 on --surface-alt — the same AA miss the light-mode value
	   had. Now 4.88 / 4.61, still clearly dimmer than --muted. */
	--muted-soft: #748799;
	--border: #223349;
	--border-soft: #1A2942;
	--brand: #3D9BDD;
	/* On a dark surface the brand is already light enough to read as
	   text (5.97:1 on --surface), so it doubles as --brand-text. */
	--brand-text: #3D9BDD;
	--brand-text-rgb: 61, 155, 221;
	--brand-deep: #1B7FC4;
	--brand-light: rgba(61, 155, 221, 0.14);
	--brand-on-dark: #8FC6EF;
	/* White on #3D9BDD is only 3.03:1. Navy on it is 6.22:1, so
	   filled brand controls invert their label in dark mode. */
	--on-brand: #06121F;
	--shadow-s: 0 1px 2px rgba(0,0,0,.35), 0 1px 1px rgba(0,0,0,.25);
	--shadow-m: 0 10px 28px rgba(0,0,0,.4), 0 2px 6px rgba(0,0,0,.3);
	--shadow-l: 0 28px 70px rgba(0,0,0,.5), 0 10px 22px rgba(0,0,0,.35);
}

/* ---------------------------------------------------------------
 * Reset
 * ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
	background: var(--surface);
	color: var(--ink);
	font-family: var(--font-body);
	font-size: var(--text-m);
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
	transition: background-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
img, picture, svg, video, canvas { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }
a { color: inherit; text-decoration: none; }
ul[class], ol[class] { list-style: none; padding: 0; }
table { border-collapse: collapse; width: 100%; }

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}
html.motion-off *, html.motion-off *::before, html.motion-off *::after {
	animation-duration: 0.01ms !important;
	transition-duration: 0.01ms !important;
}

/* ---------------------------------------------------------------
 * Typography
 * ------------------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
	font-family: var(--font-display);
	color: var(--ink);
	line-height: 1.15;
	font-weight: 700;
	text-wrap: balance;
}
h1 { font-size: var(--text-3xl); letter-spacing: var(--track-3xl); font-weight: 800; line-height: 1.02; }
h2 { font-size: var(--text-2xl); letter-spacing: var(--track-2xl); font-weight: 800; line-height: 1.06; }
h3 { font-size: var(--text-xl); letter-spacing: var(--track-xl); font-weight: 700; }
h4 { font-size: var(--text-l); font-weight: 700; letter-spacing: -0.015em; }
p { color: var(--muted); }
p + p { margin-top: var(--space-s); }
strong, b { color: var(--ink); font-weight: 600; }
small { font-size: var(--text-xs); }
code, pre, kbd { font-family: var(--font-mono); }
pre {
	background: var(--surface-alt);
	border: 1px solid var(--border);
	border-radius: var(--radius-m);
	padding: var(--space-s) var(--space-m);
	overflow-x: auto;
	font-size: 0.875em;
	line-height: 1.6;
	color: var(--ink-soft);
}
code:not(pre code) {
	background: var(--surface-alt);
	border: 1px solid var(--border);
	border-radius: 5px;
	padding: 0.1em 0.4em;
	font-size: 0.875em;
	color: var(--brand-deep);
}
blockquote {
	border-left: 3px solid var(--brand);
	padding-left: var(--space-m);
	font-style: italic;
	color: var(--ink-soft);
}
hr { border: 0; border-top: 1px solid var(--border); }

/* ---------------------------------------------------------------
 * Utilities
 * ------------------------------------------------------------- */
.wrap {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}
.wrap--narrow { max-width: var(--container-narrow); }

.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0,0,0,0);
	white-space: nowrap;
	border: 0;
}

.skip-link {
	position: absolute;
	top: -100px;
	left: var(--space-s);
	z-index: 999;
	background: var(--brand-text);
	color: var(--on-brand);
	padding: 0.75em 1.25em;
	border-radius: var(--radius-s);
	transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus { top: var(--space-s); }

:focus-visible {
	outline: 2.5px solid var(--brand);
	outline-offset: 3px;
	border-radius: 4px;
}

/* Eyebrows are set in mono, not the display face — they read as
   instrument labels rather than small headings, which is what gives
   the technical sections their voice. */
.eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 0.75em;
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--brand-text);
	margin-bottom: var(--space-s);
}
.eyebrow::before {
	content: "";
	width: 28px;
	height: 1px;
	background: currentColor;
	opacity: .55;
}

.section { padding-block: var(--space-2xl); position: relative; }
.section--tight { padding-block: var(--space-xl); }
.section--dark {
	background: var(--navy);
	color: #fff;
}
.section--dark h1, .section--dark h2, .section--dark h3, .section--dark h4 { color: #fff; }
.section--dark p { color: rgba(255,255,255,.68); }
.section--alt { background: var(--surface-alt); }

.section__head { max-width: 720px; margin-bottom: var(--space-xl); }
.section__head--center { margin-inline: auto; text-align: center; }
.section__title { margin-bottom: var(--space-xs); }
.section__desc { font-size: var(--text-l); color: var(--muted); }
.section--dark .section__desc { color: rgba(255,255,255,.68); }

.visually-hidden-focusable:not(:focus):not(:focus-within) {
	position: absolute !important;
	width: 1px; height: 1px;
	overflow: hidden;
	clip: rect(0,0,0,0);
}

@media (max-width: 1080px) {
	:root { --header-h: 72px; }
}
