/* ── PT Mono for all headings ── */
h1,
h2,
h3,
h4,
h5,
h6 {
	font-family: 'PT Mono', monospace;
}

/* ── Type scale ──
   The scale is a token, not a hard-coded size: every theme is expected to
   override these to express its own voice (Bold goes enormous and tight,
   Win95 small and system-sized, Vaporwave airy). Display steps are fluid so
   a 4.5rem headline never overflows a phone, and the steps are deliberately
   far apart so hierarchy survives any family swap. ── */
:root {
	--t-h1: clamp(2.25rem, 1.35rem + 4.2vw, 4rem);
	--t-h2: clamp(1.55rem, 1.2rem + 1.7vw, 2.25rem);
	--t-h3: clamp(1.1rem, 1rem + 0.5vw, 1.35rem);
	--t-body: 1rem;
	--t-sm: 0.875rem;
	--t-xs: 0.75rem;
	--t-2xs: 0.6875rem;

	--t-lh-display: 1.06;
	--t-lh-heading: 1.2;
	--t-lh-body: 1.6;
	--t-track-display: -0.02em;
	--t-track-heading: -0.01em;

	/* ── Radius scale ──
	   Four steps, one pill and one circle — the same "token, not constant"
	   rule as the type scale, so a theme changes its corner language by
	   redefining six values instead of hunting per-component overrides.
	   Brutalist and Win95 zero the steps; Bold and Vaporwave retune them. ── */
	--r-xs: 0.3rem;
	--r-sm: 0.5rem;
	--r-md: 0.75rem;
	--r-lg: 1rem;
	--r-pill: 999px;
	--r-round: 50%;

	/* Accent colours are picked as FILLS. Painted as small text they fail
	   contrast badly (measured 1.03:1–4.3:1 across the themes), so every
	   accent used as TEXT is first blended toward the theme's own text
	   colour — which is by definition readable on that theme's surfaces.
	   One formula, correct in light and dark, hue preserved. Themes may
	   retune the ratio; lower = closer to the text colour = safer. */
	--ink-mix: 34%;
	--ink-l: 0.38;
}

:root[data-theme='dark'],
html[data-theme='dark'] {
	--ink-l: 0.82;
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme]) {
		--ink-l: 0.82;
	}
}

/* ── Status & accent palette tokens ──
   Moved here from theme-colorful.css. Every theme redefines these under its
   own html[data-style='…'] selector (see theme-brutalist.css etc.), so this
   :root block was never colorful-specific — it is the shared shape plus a
   working default. Leaving it in theme-colorful.css made that file a
   mandatory dependency for every other theme; it belongs in base.css so any
   single theme-*.css can be dropped without losing status colours or accent
   slots for the ones that remain. ── */
:root {
	--p-info: #3b8ef0;
	--p-success: #84cc16;
	--p-warn: #f0c000;
	--p-danger: #ef4444;
	--p-on-accent: #0a0a0a;

	--p-accent-1: #06d6c8;
	--p-accent-2: #e8178a;
	--p-accent-3: #f0c000;
	--p-accent-4: #8b5cf6;
	--p-accent-5: #3b8ef0;
	--p-accent-6: #ef4444;
	--p-accent-7: #84cc16;
	--p-accent-8: #f97316;
}

/* ── Elevation (--e-*) ──
   Tokenized by ROLE, not by literal offset — brutalist wants a hard offset,
   bold a soft blur, vaporwave a neon stack, win95 a bevel stack, minimal
   none. A theme expresses its voice by redefining the role; these are the
   neutral defaults. --e-accent defaults to --e-surface so a theme that
   doesn't need a distinct accent-tinted elevation gets one value for free;
   a theme that wants e.g. a --c-text-coloured shadow on plain cards and a
   --c-accent-coloured one on accented cards can split the two. Usage
   convention: these are HOVER/FOCUS feedback, not permanent decoration. ── */
:root {
	--e-control: 0 1px 2px rgba(0, 0, 0, 0.08); /* checkbox, radio, switch */
	--e-input: 0 1px 3px rgba(0, 0, 0, 0.1); /* input, select focus */
	--e-raised: 0 4px 12px -4px rgba(0, 0, 0, 0.12); /* icon buttons hover */
	--e-surface: 0 8px 32px -8px rgba(0, 0, 0, 0.12); /* cards, buttons hover */
	--e-accent: var(--e-surface);
}
:root[data-theme='dark'],
html[data-theme='dark'] {
	--e-surface: 0 8px 32px -8px rgba(0, 0, 0, 0.5);
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme]) {
		--e-surface: 0 8px 32px -8px rgba(0, 0, 0, 0.5);
	}
}

/* ── Border width (--bw-*) ──
   A de-facto three-step scale (1px/2px/3px) existed only as repeated
   literals across the kit. --bw-edge is the accent-edge/left-marker weight
   consumed by the .card/.link-card accent edge below. ── */
:root {
	--bw-hair: 1px; /* default surfaces */
	--bw-base: 1px; /* component borders */
	--bw-thick: 2px; /* emphasis */
	--bw-edge: 3px; /* accent edge / left marker */
}

/* ── Motion (--dur-*, --ease-*) ──
   The difference between a snappy theme and a relaxed one is real design
   voice, not noise — brutalist runs faster than this neutral default.
   Every existing prefers-reduced-motion block is untouched by this: these
   tokens only name a duration, they don't change when transitions run. ── */
:root {
	--dur-fast: 0.15s;
	--dur-base: 0.25s;
	--dur-slow: 0.7s;
	--ease-out: cubic-bezier(0.25, 1, 0.5, 1);
	--ease-standard: ease;
}

/* ── Spacing (--sp-*) ──
   A modest geometric-ish ramp so themes can retune density (win95 dense,
   vaporwave airy) instead of overriding component padding wholesale.
   --sp-5 (1.5rem) intentionally lands on .card/.link-card's existing
   padding — the most-reused value in the file. Not every literal in this
   file maps cleanly onto a step (e.g. .row-mt's 1.25rem, .alert's
   0.875rem/1.1rem); those are left as literals rather than bent to fit. ── */
:root {
	--sp-1: 0.25rem;
	--sp-2: 0.5rem;
	--sp-3: 0.75rem;
	--sp-4: 1rem;
	--sp-5: 1.5rem;
	--sp-6: 2rem;
	--sp-7: 3rem;
	--sp-8: 4rem;
}

/* ── Faint text (--c-faint) ──
   One step fainter than --c-muted WITHOUT stacking opacity — opacity
   double-dims and drifts unpredictably across light/dark, defeating the
   tuned --c-muted value.

   The ordering here is deliberate and is the opposite of the obvious one.
   --c-faint is NOT "muted, minus a bit": mixing down from --c-muted has
   nowhere to go, because --c-muted already sits close to the AA 4.5:1
   floor in most themes. Derive it from the other end instead — --c-faint
   is pinned to a lightness that CLEARS the floor, and --c-muted is then
   free to sit above it. So faint is the quietest legible step the system
   has, not a step past legibility.

   Same machinery as the accent ink treatment: a fixed target lightness
   via relative colour, hue and chroma inherited from --c-text so a warm
   or cool theme stays warm or cool. --faint-mix is the fallback ratio.
   Themes whose --c-bg is not near-white/near-black (Bold's vermilion,
   Win95's teal) MUST retune --faint-l or set --c-faint outright — the
   contrast audit is what proves the value. ── */
:root {
	--faint-l: 0.52;
	--faint-mix: 62%;
	--c-faint: color-mix(in srgb, var(--c-text) var(--faint-mix), var(--c-bg));
}

:root[data-theme='dark'],
html[data-theme='dark'] {
	--faint-l: 0.62;
}
@media (prefers-color-scheme: dark) {
	:root:not([data-theme]) {
		--faint-l: 0.62;
	}
}

@supports (color: oklch(from red l c h)) {
	:root {
		--c-faint: oklch(from var(--c-text) var(--faint-l) c h);
	}
}

h1 {
	font-size: var(--t-h1);
	line-height: var(--t-lh-display);
	letter-spacing: var(--t-track-display);
	text-wrap: balance;
}
h2 {
	font-size: var(--t-h2);
	line-height: var(--t-lh-heading);
	letter-spacing: var(--t-track-heading);
	text-wrap: balance;
}
h3 {
	font-size: var(--t-h3);
	line-height: var(--t-lh-heading);
	text-wrap: balance;
}

html {
	scroll-behavior: smooth;
	color-scheme: light dark;
}

body {
	background-color: var(--c-bg);
	color: var(--c-text);
	font-family: 'IBM Plex Sans', system-ui, sans-serif;
	line-height: var(--t-lh-body);
	-webkit-font-smoothing: antialiased;
	/* Deliberately its own pace, not --dur-base: this is a full-page theme
	   crossfade, not an interactive hover/focus state, so it isn't part of
	   the --dur-* interaction scale. */
	transition:
		background-color 0.3s ease,
		color 0.3s ease;
}

/* ── Animations ── */
@keyframes fade-up {
	from {
		opacity: 0;
		transform: translateY(24px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

.animate-fade-up {
	animation: fade-up var(--dur-slow) ease forwards;
}

/* The delay-N names encode their own value (N * 0.1s) — tokenizing them would
   break that correspondence for no gain, so these stay literal. */
.delay-100 {
	animation-delay: 0.1s;
	opacity: 0;
}
.delay-200 {
	animation-delay: 0.2s;
	opacity: 0;
}
.delay-300 {
	animation-delay: 0.3s;
	opacity: 0;
}
.delay-400 {
	animation-delay: 0.4s;
	opacity: 0;
}
.delay-500 {
	animation-delay: 0.5s;
	opacity: 0;
}
.delay-600 {
	animation-delay: 0.6s;
	opacity: 0;
}

/* Reduced motion: skip the entrance entirely. The .delay-* classes hold
   content at opacity:0 until the animation paints it, so these MUST restore
   opacity — cancelling only the animation would leave the content invisible. */
@media (prefers-reduced-motion: reduce) {
	.animate-fade-up {
		animation: none;
		opacity: 1;
		transform: none;
	}

	.delay-100,
	.delay-200,
	.delay-300,
	.delay-400,
	.delay-500,
	.delay-600 {
		animation-delay: 0s;
		opacity: 1;
	}
}

.section-label {
	font-size: var(--t-2xs);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	font-weight: 600;
}

/* ── Gradient headline (background-clip not expressible in Tailwind) ── */
.gradient-text {
	background: linear-gradient(
		120deg,
		var(--c-grad-h1-from) 0%,
		var(--c-grad-h1-mid) 50%,
		var(--c-grad-h1-to) 100%
	);
	-webkit-background-clip: text;
	-webkit-text-fill-color: transparent;
	background-clip: text;
}

/* ── Dot grid (radial-gradient bg-image, no Tailwind equivalent) ── */
.dot-grid {
	background-image: radial-gradient(circle, var(--c-dot) 1px, transparent 1px);
	background-size: 28px 28px;
}

/* ── Tag pills ── */
.tag {
	font-size: var(--t-2xs);
	letter-spacing: 0.15em;
	text-transform: uppercase;
	padding: 0.2rem 0.65rem;
	border-radius: var(--r-pill);
	border-width: var(--bw-hair);
	border-style: solid;
	/* No blanket opacity here: the .tag-* ink below is computed to clear AA at
	   full strength, and fading the whole pill would blend that ink back toward
	   the page and undo it. Softness belongs in the colour, not in alpha. */
}

/* ── Cards ── */
.card {
	border: var(--bw-base) solid var(--c-border);
	background: var(--c-surface);
	transition:
		transform var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}

/* --e-surface already carries its own light/dark values (see the token
   section near the top), so hover no longer needs a separate dark override
   here. */
.card:hover {
	transform: translateY(-2px);
	box-shadow: var(--e-surface);
}

/* ── Link cards ── */
.link-card {
	border: var(--bw-base) solid var(--c-border);
	background: var(--c-surface);
	transition:
		border-color var(--dur-base) ease,
		transform var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}

.link-card:hover {
	transform: translateY(-2px);
	box-shadow: var(--e-surface);
}

/* ── Font size scale ── */
html[data-font-size='s'] {
	font-size: 14px;
}
html[data-font-size='m'],
html:not([data-font-size]) {
	font-size: 16px;
}
html[data-font-size='l'] {
	font-size: 18px;
}

/* ── On mobile, always use 'm' (16px) regardless of setting ── */
@media (max-width: 640px) {
	html[data-font-size='s'],
	html[data-font-size='l'] {
		font-size: 16px;
	}
}

/* ══ Button system ══════════════════════════════════════════ */

/* Form-associated elements do NOT inherit font from their ancestors — the UA
   sheet gives <button>/<input>/<select> their own `font: 400 13.333px Arial`.
   Without this, a `<button class="btn-primary">` renders in Arial at an
   off-scale size in every theme, while the same class on an `<a>` renders
   correctly. Reset the whole family once so the theme's voice actually reaches
   its controls, and so the `em`-based margins below measure against the
   theme's own size. */
.btn-primary,
.btn-outlined,
.btn-ghost,
.btn-icon,
.theme-toggle,
.checkbox,
.radio,
.switch {
	font-family: inherit;
}

/* The text buttons name their own step from the scale; these carry no text, so
   they take the inherited size — which is also what their `em`-based margins
   measure against (at the UA's 13.333px the gap next to a checkbox label came
   out ~17% tight). */
.btn-icon,
.theme-toggle,
.checkbox,
.radio,
.switch {
	font-size: inherit;
}

/* Primary — filled accent */
.btn-primary {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.375rem;
	padding: 0.625rem var(--sp-5);
	border-radius: var(--r-pill);
	border: var(--bw-thick) solid transparent;
	background: var(--c-accent);
	/* Never --c-bg: a bright accent (cyan, orange) needs a foreground picked
	   for contrast against the accent itself, not against the page. */
	color: var(--c-on-accent);
	font-size: var(--t-sm);
	font-weight: 500;
	letter-spacing: 0.025em;
	text-decoration: none;
	cursor: pointer;
	transition:
		opacity var(--dur-base) ease,
		transform var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}

.btn-primary:hover {
	opacity: 0.88;
}

/* Outlined — border, bg matches page */
.btn-outlined {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.375rem;
	padding: 0.625rem var(--sp-5);
	border-radius: var(--r-pill);
	border: var(--bw-base) solid var(--c-border);
	background: var(--c-bg);
	color: var(--c-text);
	font-size: var(--t-sm);
	font-weight: 500;
	letter-spacing: 0.025em;
	text-decoration: none;
	cursor: pointer;
	transition:
		border-color var(--dur-base) ease,
		color var(--dur-base) ease,
		transform var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}

.btn-outlined:hover {
	border-color: var(--c-accent);
	color: var(--c-accent);
}

/* Selected state — the ARIA state is styled directly so a settings UI can't
   drift from accessibility by inventing a class like .is-selected.
   border-color: var(--c-accent) is a FILL-shaped use (a 1px boundary reads
   as a shape, not text) and already clears the 3:1 SC 1.4.11 floor per
   theme, so it's left alone. color must NOT reuse --c-accent raw: accents
   in this kit are chosen for fills and fail 4.5:1 as small text (see the
   tag/card ink treatment below). Route it through the same ink treatment —
   pinning lightness while keeping the accent's own hue/chroma keeps the
   pressed state visibly distinct from the unpressed --c-text, unlike
   collapsing to --c-text would. The @supports block below upgrades this
   to the relative-colour form. */
.btn-outlined[aria-pressed='true'] {
	border-color: var(--c-accent);
	color: color-mix(in srgb, var(--c-accent) var(--ink-mix), var(--c-text));
}

/* Small size modifier */
.btn-sm {
	padding: 0.375rem var(--sp-4);
	font-size: var(--t-xs);
}

/* Ghost — no border, no bg */
.btn-ghost {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.375rem;
	padding: 0;
	background: transparent;
	border: none;
	color: var(--c-muted);
	font-size: var(--t-sm);
	font-weight: 500;
	text-decoration: none;
	cursor: pointer;
	transition:
		color var(--dur-base) ease,
		transform var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}

.btn-ghost:hover {
	color: var(--c-accent);
}

/* Same anti-pattern risk as .btn-outlined above: no border here to carry
   the fill-shaped accent, so the ink treatment is the only contrast-safe
   way to signal "selected" without collapsing to plain --c-text. */
.btn-ghost[aria-pressed='true'] {
	color: color-mix(in srgb, var(--c-accent) var(--ink-mix), var(--c-text));
}

/* Icon button (square aspect, no fixed padding) */
.btn-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: var(--bw-base) solid var(--c-border);
	background: var(--c-surface);
	color: var(--c-text-sub);
	text-decoration: none;
	cursor: pointer;
	transition:
		border-color var(--dur-base) ease,
		color var(--dur-base) ease,
		transform var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}

.btn-icon:hover {
	border-color: var(--c-accent);
	color: var(--c-accent);
}

/* Theme toggle button — 36px, not 32px: WCAG 2.2 SC 2.5.8 puts the floor
   at 24px, and matching .btn-icon keeps the nav's controls one size. */
.theme-toggle {
	width: 2.25rem;
	height: 2.25rem;
	border-radius: var(--r-round);
	border: var(--bw-base) solid var(--c-border);
	background: var(--c-surface);
	color: var(--c-text-sub);
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition:
		border-color var(--dur-base) ease,
		color var(--dur-base) ease;
}

.theme-toggle:hover {
	border-color: var(--c-accent);
	color: var(--c-accent);
}

/* ════════════════════════════════════════════════════════════
   STANDALONE HELPERS
   Layered on top of the styled classes above so every element
   can be built from classes alone — no inline `style` and no
   utility framework required. All additive: existing classes
   keep their behaviour, these just fill in structure + variants.
   ════════════════════════════════════════════════════════════ */

/* ── Text colour helpers ── */
.text-accent {
	color: color-mix(in srgb, var(--c-accent) var(--ink-mix), var(--c-text));
}
.text-accent-2 {
	color: var(--c-accent-2);
}
.text-accent-3 {
	color: var(--c-accent-3);
}
.text-sub {
	color: var(--c-text-sub);
}
.text-muted {
	color: var(--c-muted);
}
.text-faint {
	color: var(--c-faint);
}

/* ── Layout helpers ── */
.row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-3);
}
.row-mt {
	margin-top: 1.25rem; /* not on the --sp-* scale (nearest steps are 1rem/1.5rem); left literal rather than nudging the layout */
}

/* ── Divider ──
   No showcase-specific max-width: a consumer's own container decides the
   width, not this class. ── */
.divider {
	width: 100%;
	height: 0;
	margin: var(--sp-6) 0;
	border: none;
	border-top: var(--bw-base) solid var(--c-border);
}
.divider-soft {
	border-top-color: color-mix(in srgb, var(--c-border) 50%, transparent);
}

/* ── Media / image frame ──
   The one primitive the kit shipped without: every consumer with a photo
   invented its own. Works either wrapping an <img> in a <figure class="media">
   or applied straight to the <img>. object-fit + max-width keep it well
   behaved in a grid; themes layer their own border/shadow voice on top. ── */
.media,
img.media {
	display: block;
	width: 100%;
	max-width: 100%;
	margin: 0;
	overflow: hidden;
	border-radius: var(--r-md);
	background: var(--c-surface);
}
.media img,
img.media {
	height: 100%;
	object-fit: cover;
}
.media-round {
	border-radius: var(--r-round);
	aspect-ratio: 1 / 1;
}
.media-wide {
	aspect-ratio: 16 / 9;
}

/* ── Palette accent selector ──
   Sets --card-color, the hook read by .card's edge
   and .link-icon's fill. Add one to a card / link / icon. ── */
.accent-1 {
	--card-color: var(--p-accent-1);
}
.accent-2 {
	--card-color: var(--p-accent-2);
}
.accent-3 {
	--card-color: var(--p-accent-3);
}
.accent-4 {
	--card-color: var(--p-accent-4);
}
.accent-5 {
	--card-color: var(--p-accent-5);
}
.accent-6 {
	--card-color: var(--p-accent-6);
}
.accent-7 {
	--card-color: var(--p-accent-7);
}
.accent-8 {
	--card-color: var(--p-accent-8);
}

/* ── Tag colour variants ──
   Base .tag becomes inline-block (so it can animate) with a
   neutral border; add .tag-<color> to tint it. ── */
.tag {
	display: inline-block;
	border-color: var(--c-border);
}

/* ── Tag tint tiers (--tag-bg-tint / --tag-border-tint) ──
   Untiered .tag-accent-N (no modifier) is the "standard" tier: full-strength
   punch. Stack .tag-weak or .tag-weaker alongside it for a quieter chip —
   these only set the two mix-percentage variables the accent rule below
   reads, so they compose with any accent slot without a combinatorial
   per-colour class.

   Deliberately SOLID, not translucent: an earlier version mixed the accent
   toward `transparent`, which is alpha, not colour — the chip's apparent
   tone then depended on whatever sat behind it (page vs. card), and Chromium
   renders that mix as a real alpha channel, not a flattened opaque colour.
   Mixing toward --c-surface instead produces a fully opaque colour that
   reads the same wherever the tag sits — quieter because it carries less of
   the accent, never because it carries less coverage. */
.tag-weak {
	--tag-bg-tint: 8%;
	--tag-border-tint: 26%;
}
.tag-weaker {
	--tag-bg-tint: 4%;
	--tag-border-tint: 16%;
}
.tag-accent-1 {
	--slot: var(--p-accent-1);
}
.tag-accent-2 {
	--slot: var(--p-accent-2);
}
.tag-accent-3 {
	--slot: var(--p-accent-3);
}
.tag-accent-4 {
	--slot: var(--p-accent-4);
}
.tag-accent-5 {
	--slot: var(--p-accent-5);
}
.tag-accent-6 {
	--slot: var(--p-accent-6);
}
.tag-accent-7 {
	--slot: var(--p-accent-7);
}
.tag-accent-8 {
	--slot: var(--p-accent-8);
}

/* One ink treatment for every accent slot. Blending an accent toward the
   theme's neutral text colour is contrast-safe but strips chroma — the tags
   go grey. Where relative colour is supported we instead pin only the
   LIGHTNESS (--ink-l) and keep the accent's own chroma and hue, so the tag
   stays unmistakably its colour and still clears AA. The color-mix line is
   the fallback for browsers without relative colour. */
.tag[class*='tag-accent-'] {
	color: color-mix(in srgb, var(--slot) var(--ink-mix), var(--c-text));
	border-color: color-mix(in srgb, var(--slot) var(--tag-border-tint, 38%), var(--c-surface));
	background: color-mix(in srgb, var(--slot) var(--tag-bg-tint, 14%), var(--c-surface));
}
@supports (color: oklch(from white l c h)) {
	.tag[class*='tag-accent-'] {
		color: oklch(from var(--slot) var(--ink-l) c h);
	}
	.card .section-label,
	.card .card-subtitle,
	.link-icon,
	.quote-mark {
		color: oklch(from var(--card-color, var(--c-accent)) var(--ink-l) c h);
	}
	.text-accent {
		color: oklch(from var(--c-accent) var(--ink-l) c h);
	}
	.btn-outlined[aria-pressed='true'],
	.btn-ghost[aria-pressed='true'] {
		color: oklch(from var(--c-accent) var(--ink-l) c h);
	}
}


/* ── Card — standalone structure ──
   base.css already styles the surface + accent edge; these add
   the padding/radius and lay out the card's contents. No max-width here —
   that was sized for the kit's own demo grid and every real consumer lifted
   it; opt in with .card-narrow instead. ── */
.card {
	padding: var(--sp-5);
	border-radius: var(--r-lg);
}
.card-narrow {
	max-width: 22rem;
}
/* Denser variant for a wide, shallow row (a milestone/list entry) rather
   than a showcase tile. 1.25rem/1.75rem was the hand-rolled value one
   consumer landed on; these are the nearest clean steps on the scale. */
.card-compact {
	padding: var(--sp-4) var(--sp-6);
}
.card .section-label {
	margin: 0 0 0.5rem;
	color: color-mix(in srgb, var(--card-color, var(--c-accent)) var(--ink-mix), var(--c-text));
}
.card h3 {
	margin: 0;
	font-size: var(--t-body);
}
.card .card-subtitle {
	margin: 0.25rem 0 0.75rem;
	font-size: var(--t-sm);
	font-weight: 500;
	color: color-mix(in srgb, var(--card-color, var(--c-accent)) var(--ink-mix), var(--c-text));
}
.card .card-text {
	margin: 0;
	font-size: var(--t-sm);
	/* Leading is part of a theme's voice, not a constant — Win95 runs tight
	   at 1.45, Minimal and Vaporwave open up to 1.7/1.65. */
	line-height: var(--t-lh-body);
	color: var(--c-text-sub);
}

/* ── Link card — standalone structure ──
   No max-width — see .card above for why; opt in with .link-card-narrow. ── */
.link-card {
	display: flex;
	align-items: center;
	gap: 1.25rem; /* not on the --sp-* scale (between sp-4 and sp-5); left literal */
	padding: var(--sp-5);
	border-radius: var(--r-lg);
	text-decoration: none;
}
.link-card-narrow {
	max-width: 22rem;
}
.link-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 2.75rem;
	height: 2.75rem;
	border-radius: var(--r-md);
	font-weight: 700;
	background: color-mix(in srgb, var(--card-color, var(--c-accent)) 12%, transparent);
	color: color-mix(in srgb, var(--card-color, var(--c-accent)) var(--ink-mix), var(--c-text));
}
.link-body {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}
.link-card strong {
	color: var(--c-text);
	font-size: var(--t-sm);
}
.link-sub {
	color: var(--c-text-sub);
	font-size: var(--t-xs);
}

/* ── Pull quote ──
   Accent left border at --bw-thick, oversized mark, attribution line. ── */
.quote {
	margin: 0;
	padding-left: var(--sp-6);
	border-left: var(--bw-thick) solid var(--c-accent);
	font-size: var(--t-h3);
	line-height: var(--t-lh-heading);
	color: var(--c-text);
}
.quote-mark {
	display: block;
	margin-bottom: var(--sp-2);
	font-family: 'PT Mono', monospace;
	font-size: 2.5em;
	line-height: 1;
	color: color-mix(in srgb, var(--c-accent) var(--ink-mix), var(--c-text));
}
.quote-author {
	display: block;
	margin-top: var(--sp-4);
	font-size: var(--t-sm);
	font-weight: 500;
	color: var(--c-text-sub);
}
.quote-author::before {
	content: '— ';
}

/* ── Icon button — default square size ── */
.btn-icon {
	width: 2.25rem;
	height: 2.25rem;
	border-radius: var(--r-sm);
}

/* ── Ambient effect stage ──
   A sized, rounded backdrop for .dot-grid + .halo blobs. ── */
.effect-stage {
	position: relative;
	overflow: hidden;
	height: 11rem;
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-lg);
}
.effect-caption {
	position: relative;
	margin: 0;
	padding-top: 4.5rem;
	text-align: center;
	color: var(--c-text-sub);
	font-size: var(--t-sm);
}
.halo {
	position: absolute;
	border-radius: var(--r-round);
	filter: blur(48px);
	opacity: 0.32;
	pointer-events: none;
}
.halo-a {
	top: -2rem;
	left: 8%;
	width: 10rem;
	height: 10rem;
}
.halo-b {
	right: 10%;
	bottom: -3rem;
	width: 12rem;
	height: 12rem;
}
.halo-accent-1 {
	background: var(--p-accent-1);
}
.halo-accent-2 {
	background: var(--p-accent-2);
}
.halo-accent-3 {
	background: var(--p-accent-3);
}
.halo-accent-4 {
	background: var(--p-accent-4);
}
.halo-accent-5 {
	background: var(--p-accent-5);
}

/* ── Halo drift animations ──
   Moved here from theme-colorful.css: they are shared ambient motion used
   by every theme's .effect-stage, not colorful-specific, so a consumer that
   drops theme-colorful.css must not lose them (see the shared status/accent
   token section near the top for the same reasoning). ── */
@keyframes halo-drift-1 {
	0%,
	100% {
		transform: translate(0, 0) scale(1);
	}
	33% {
		transform: translate(60px, -45px) scale(1.1);
	}
	66% {
		transform: translate(-45px, 35px) scale(0.92);
	}
}
@keyframes halo-drift-2 {
	0%,
	100% {
		transform: translate(0, 0) scale(1);
	}
	40% {
		transform: translate(-55px, 48px) scale(1.09);
	}
	72% {
		transform: translate(40px, -36px) scale(0.91);
	}
}
@keyframes halo-drift-3 {
	0%,
	100% {
		transform: translate(0, 0) scale(1);
	}
	30% {
		transform: translate(50px, 52px) scale(1.08);
	}
	65% {
		transform: translate(-42px, -30px) scale(0.93);
	}
}
@keyframes halo-drift-4 {
	0%,
	100% {
		transform: translate(0, 0) scale(1);
	}
	45% {
		transform: translate(-48px, -50px) scale(1.1);
	}
	78% {
		transform: translate(44px, 32px) scale(0.92);
	}
}
.halo-drift-1 {
	animation: halo-drift-1 9s ease-in-out infinite;
}
.halo-drift-2 {
	animation: halo-drift-2 11s ease-in-out infinite;
}
.halo-drift-3 {
	animation: halo-drift-3 10s ease-in-out infinite;
}
.halo-drift-4 {
	animation: halo-drift-4 12s ease-in-out infinite;
}

/* Reduced motion: hold the halos still. They're purely ambient, and their
   untransformed position is the intended resting layout, so stopping the
   animation leaves the composition intact rather than blank. */
@media (prefers-reduced-motion: reduce) {
	.halo-drift-1,
	.halo-drift-2,
	.halo-drift-3,
	.halo-drift-4 {
		animation: none;
	}
}

/* ══ Form controls ═══════════════════════════════════════════ */

/* ── Field wrapper — no max-width; opt in with .field-narrow (see .card
   above for the same reasoning: a showcase-grid number every real
   consumer had to override). ── */
.field {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}
.field-narrow {
	max-width: 22rem;
}
.field-label {
	font-size: var(--t-sm);
	font-weight: 500;
	color: var(--c-text);
}
.field-hint {
	font-size: var(--t-xs);
	color: var(--c-muted);
}

/* ── Text input / textarea ── */
.input {
	display: block;
	width: 100%;
	padding: 0.625rem 0.875rem;
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-sm);
	background: var(--c-surface);
	color: var(--c-text);
	font-family: inherit;
	font-size: var(--t-sm);
	line-height: 1.4;
	transition:
		border-color var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}
textarea.input {
	min-height: 6rem;
	resize: vertical;
}
.input::placeholder {
	color: var(--c-muted);
}
.input:hover {
	border-color: var(--c-muted);
}
.input:focus-visible {
	outline: none;
	border-color: var(--c-accent);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}
.input:disabled {
	opacity: 0.6;
	cursor: not-allowed;
	background: color-mix(in srgb, var(--c-border) 35%, var(--c-surface));
}

/* ── Select — custom chevron drawn from two currentColor gradients ── */
.select {
	appearance: none;
	-webkit-appearance: none;
	-moz-appearance: none;
	display: block;
	width: 100%;
	padding: 0.625rem 2.25rem 0.625rem 0.875rem;
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-sm);
	background-color: var(--c-surface);
	background-image:
		linear-gradient(45deg, transparent 50%, currentColor 50%),
		linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position:
		calc(100% - 1.15rem) center,
		calc(100% - 0.85rem) center;
	background-size:
		0.4rem 0.4rem,
		0.4rem 0.4rem;
	background-repeat: no-repeat;
	color: var(--c-text);
	font-family: inherit;
	font-size: var(--t-sm);
	cursor: pointer;
	transition:
		border-color var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}
.select:hover {
	border-color: var(--c-muted);
}
.select:focus-visible {
	outline: none;
	border-color: var(--c-accent);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}
.select:disabled {
	opacity: 0.6;
	cursor: not-allowed;
	background-color: color-mix(in srgb, var(--c-border) 35%, var(--c-surface));
}

/* ── Checkbox — appearance:none, checkmark drawn with clip-path ── */
.checkbox {
	appearance: none;
	-webkit-appearance: none;
	display: inline-grid;
	place-content: center;
	flex-shrink: 0;
	width: 1.15rem;
	height: 1.15rem;
	margin: 0 0.5em 0 0;
	vertical-align: middle;
	border: 1.5px solid var(--c-border); /* half-step between --bw-hair/--bw-thick, tuned to this control's own size — not on the scale */
	border-radius: var(--r-xs);
	background: var(--c-surface);
	cursor: pointer;
	transition:
		background var(--dur-fast) ease,
		border-color var(--dur-fast) ease,
		box-shadow var(--dur-fast) ease;
}
.checkbox::before {
	content: '';
	width: 0.68rem;
	height: 0.68rem;
	clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
	background: var(--c-on-accent);
	transform: scale(0);
	/* Faster than --dur-fast on purpose — the tick needs to feel instant, not eased-in. */
	transition: transform 0.12s ease;
}
.checkbox:checked {
	background: var(--c-accent);
	border-color: var(--c-accent);
}
.checkbox:checked::before {
	transform: scale(1);
}
.checkbox:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}
.checkbox:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* ── Radio — appearance:none, dot fill ── */
.radio {
	appearance: none;
	-webkit-appearance: none;
	display: inline-grid;
	place-content: center;
	flex-shrink: 0;
	width: 1.15rem;
	height: 1.15rem;
	margin: 0 0.5em 0 0;
	vertical-align: middle;
	border: 1.5px solid var(--c-border); /* half-step, see .checkbox above */
	border-radius: var(--r-round);
	background: var(--c-surface);
	cursor: pointer;
	transition:
		border-color var(--dur-fast) ease,
		box-shadow var(--dur-fast) ease;
}
.radio::before {
	content: '';
	width: 0.55rem;
	height: 0.55rem;
	border-radius: var(--r-round);
	background: var(--c-accent);
	transform: scale(0);
	/* Faster than --dur-fast on purpose — see .checkbox::before above. */
	transition: transform 0.12s ease;
}
.radio:checked {
	border-color: var(--c-accent);
}
.radio:checked::before {
	transform: scale(1);
}
.radio:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}
.radio:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* ── 24×24 hit target (WCAG 2.2 AA, SC 2.5.8) ──
   The 18.4px box is load-bearing — every theme's tick, dot and border
   weights are tuned to it — so the VISUAL size stays exactly as-is and
   only the target grows. A transparent centred ::after does that without
   touching layout: ::before is already the tick/dot, and absolutely
   positioning the pseudo keeps it out of the inline-grid flow that
   centres that tick. Sizing it 100% with a 24px floor means a theme that
   enlarges the control gets a bigger target rather than a clipped one.
   Rejected: padding on the control (repaints the border box in every
   theme) and a bigger box scaled back down (blurs the clip-path tick). ── */
.checkbox,
.radio {
	position: relative;
}
.checkbox::after,
.radio::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 100%;
	height: 100%;
	min-width: 24px;
	min-height: 24px;
	transform: translate(-50%, -50%);
}

/* ── Switch — pill track, sliding thumb ── */
.switch {
	appearance: none;
	-webkit-appearance: none;
	position: relative;
	flex-shrink: 0;
	width: 2.75rem;
	height: 1.5rem;
	margin: 0 0.5em 0 0;
	vertical-align: middle;
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-pill);
	background: var(--c-border);
	cursor: pointer;
	transition:
		background var(--dur-base) ease,
		border-color var(--dur-base) ease,
		box-shadow var(--dur-base) ease;
}
.switch::before {
	content: '';
	position: absolute;
	top: 0.19rem;
	left: 0.2rem;
	width: 1.1rem;
	height: 1.1rem;
	border-radius: var(--r-round);
	background: var(--c-surface);
	/* Deeper than --e-control on purpose — this permanent thumb shadow needs
	   more contrast against the track than the interactive-hover role gives;
	   not part of the hover/focus elevation ladder. */
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
	transition: transform var(--dur-base) ease;
}
.switch:checked {
	background: var(--c-accent);
	border-color: var(--c-accent);
}
.switch:checked::before {
	transform: translateX(1.25rem);
}
.switch:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}
.switch:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* ══ Feedback ═════════════════════════════════════════════════ */

/* ── Alert — tinted via color-mix like .tag-* does. Body copy and the
   title stay on --c-text: the vivid --p-* palette is not reliable as a
   TEXT colour (e.g. cyan/yellow on a light surface fall well under 4.5:1),
   so the palette only tints the background/border and marks a left edge,
   never the readable text itself. ── */
.alert {
	padding: 0.875rem 1.1rem; /* neither value lands cleanly on the --sp-* scale; left literal */
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-md);
	background: var(--c-surface);
	color: var(--c-text);
	font-size: var(--t-sm);
	line-height: var(--t-lh-body);
}
.alert > *:first-child {
	margin-top: 0;
}
.alert > *:last-child {
	margin-bottom: 0;
}
.alert-title {
	display: block;
	margin: 0 0 0.2rem;
	font-weight: 600;
	color: var(--c-text);
}
.alert-info {
	background: color-mix(in srgb, var(--p-info) 10%, var(--c-surface));
	border-color: color-mix(in srgb, var(--p-info) 40%, var(--c-border));
}
.alert-success {
	background: color-mix(in srgb, var(--p-success) 10%, var(--c-surface));
	border-color: color-mix(in srgb, var(--p-success) 40%, var(--c-border));
}
.alert-warn {
	background: color-mix(in srgb, var(--p-warn) 12%, var(--c-surface));
	border-color: color-mix(in srgb, var(--p-warn) 45%, var(--c-border));
}
.alert-error {
	background: color-mix(in srgb, var(--p-danger) 10%, var(--c-surface));
	border-color: color-mix(in srgb, var(--p-danger) 40%, var(--c-border));
}

/* ── Badge — solid fill counter/status pill ── */
.badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.35rem;
	height: 1.35rem;
	padding: 0 0.45rem;
	border-radius: var(--r-pill);
	background: var(--c-accent);
	color: var(--c-on-accent);
	font-size: var(--t-2xs);
	font-weight: 700;
	line-height: 1;
	white-space: nowrap;
}
/* Palette variants: fg verified at #0a0a0a (not the #111 the spec floated —
   #111 measures 4.42:1 / 4.46:1 on --p-accent-2 / --p-accent-4, just under AA
   4.5:1; #0a0a0a clears 4.5:1 against all 8 palette colours). */
.badge-accent-1 {
	background: var(--p-accent-1);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-2 {
	background: var(--p-accent-2);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-3 {
	background: var(--p-accent-3);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-4 {
	background: var(--p-accent-4);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-5 {
	background: var(--p-accent-5);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-6 {
	background: var(--p-accent-6);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-7 {
	background: var(--p-accent-7);
	color: var(--p-on-accent, #0a0a0a);
}
.badge-accent-8 {
	background: var(--p-accent-8);
	color: var(--p-on-accent, #0a0a0a);
}

/* ── Progress ── */
.progress {
	width: 100%;
	height: 0.5rem;
	border-radius: var(--r-pill);
	background: var(--c-border);
	overflow: hidden;
}
/* The fill is always full width and scaled down to the current value: a
   transform animates on the compositor, where `width` would relayout the
   track on every frame. The track's overflow:hidden supplies the rounded
   cap, so the bar carries no radius of its own to get squashed. */
.progress-bar {
	height: 100%;
	width: 100%;
	background: var(--c-accent);
	transform-origin: left center;
	transform: scaleX(var(--progress, 0));
	/* Its own pace, not --dur-base: a value change is a deliberate, slightly
	   slower moment, not a hover/focus micro-interaction. */
	transition: transform 0.3s ease;
}
.progress-25 {
	--progress: 0.25;
}
.progress-50 {
	--progress: 0.5;
}
.progress-75 {
	--progress: 0.75;
}
.progress-100 {
	--progress: 1;
}
@media (prefers-reduced-motion: reduce) {
	.progress-bar {
		transition: none;
	}
}

/* ── Skeleton — shimmer placeholder; reduced-motion → static tint ── */
.skeleton {
	position: relative;
	overflow: hidden;
	background: var(--c-border);
	border-radius: var(--r-sm);
}
.skeleton::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(
		90deg,
		transparent,
		color-mix(in srgb, var(--c-surface) 65%, transparent),
		transparent
	);
	transform: translateX(-100%);
	animation: skeleton-shimmer 1.6s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
	100% {
		transform: translateX(100%);
	}
}
.skeleton-text {
	width: 100%;
	height: 1em;
	border-radius: var(--r-xs);
}
.skeleton-circle {
	width: 2.75rem;
	height: 2.75rem;
	border-radius: var(--r-round);
}
.skeleton-rect {
	width: 100%;
	height: 6rem;
}
@media (prefers-reduced-motion: reduce) {
	.skeleton::after {
		animation: none;
		display: none;
	}
}

/* ── Spinner — reduced-motion → static ¾ arc (still visible) ── */
.spinner {
	display: inline-block;
	width: 1.25rem;
	height: 1.25rem;
	border: var(--bw-thick) solid var(--c-border);
	border-top-color: var(--c-accent);
	border-radius: var(--r-round);
	animation: spinner-spin var(--dur-slow) linear infinite;
}
@keyframes spinner-spin {
	100% {
		transform: rotate(360deg);
	}
}
@media (prefers-reduced-motion: reduce) {
	.spinner {
		animation: none;
		border-color: var(--c-accent);
		border-right-color: var(--c-border);
	}
}

/* ══ Navigation ═══════════════════════════════════════════════ */

/* ── Tabs — switches which VIEW is shown. See .segmented below for the
   value-setting counterpart. ── */
.tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem;
	border-bottom: var(--bw-base) solid var(--c-border);
}
.tab {
	position: relative;
	padding: 0.625rem 0.125rem;
	background: none;
	border: none;
	color: var(--c-text-sub);
	font-family: inherit;
	font-size: var(--t-sm);
	font-weight: 500;
	text-decoration: none;
	cursor: pointer;
	transition: color var(--dur-base) ease;
}
.tab::after {
	content: '';
	position: absolute;
	right: 0;
	bottom: -1px;
	left: 0;
	height: var(--bw-thick);
	background: transparent;
	transition: background var(--dur-base) ease;
}
.tab:hover {
	color: var(--c-text);
}
.tab-active {
	color: var(--c-text);
	font-weight: 600;
}
.tab-active::after {
	background: var(--c-accent);
}
.tab:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}

/* ── Segmented control — sets a VALUE (like a size or view-density picker),
   not a view; distinct from .tabs above. The selected segment is driven by
   aria-pressed so it can't drift from the accessible state. ── */
.segmented {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-1);
	padding: var(--sp-1);
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-md);
	background: var(--c-surface);
}
.segment {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: var(--sp-2) var(--sp-4);
	border: none;
	border-radius: var(--r-sm);
	background: none;
	color: var(--c-text-sub);
	font-family: inherit;
	font-size: var(--t-sm);
	font-weight: 500;
	cursor: pointer;
	transition:
		background var(--dur-base) var(--ease-standard),
		color var(--dur-base) var(--ease-standard);
}
.segment:hover {
	color: var(--c-text);
}
/* Scoped to .segmented (not just .segment) so this beats theme overrides
   like `html[data-style='x'] .segment { color: … }` on specificity — that
   theme-scoped pattern carries a type selector plus a class, which outranks
   a bare `.segment[aria-pressed='true']` and was silently repainting the
   selected segment back to its unselected colour (Vaporwave). --c-on-accent
   is correct here in principle: it's text ON a --c-accent FILL, not accent
   text on the page surface. */
.segmented .segment[aria-pressed='true'] {
	background: var(--c-accent);
	color: var(--c-on-accent);
}
.segment:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}

/* ── Breadcrumbs — separator auto-inserted before every item but the first ── */
.breadcrumbs {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0;
	font-size: var(--t-xs);
}
.breadcrumbs a {
	color: var(--c-text-sub);
	text-decoration: none;
	transition: color var(--dur-base) ease;
}
.breadcrumbs a:hover {
	color: var(--c-accent);
}
.breadcrumbs [aria-current='page'] {
	color: var(--c-text);
	font-weight: 600;
}
.breadcrumbs > * + * {
	position: relative;
	margin-left: 0.8rem;
	padding-left: 0.8rem;
}
.breadcrumbs > * + *::before {
	content: '/';
	position: absolute;
	left: 0;
	color: var(--c-muted);
}

/* ── Pagination ── */
.pagination {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.35rem;
}
.page {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.1rem;
	height: 2.1rem;
	padding: 0 0.5rem;
	border: var(--bw-base) solid var(--c-border);
	border-radius: var(--r-sm);
	background: var(--c-surface);
	color: var(--c-text);
	font-family: inherit;
	font-size: var(--t-xs);
	text-decoration: none;
	cursor: pointer;
	transition:
		border-color var(--dur-base) ease,
		background var(--dur-base) ease,
		color var(--dur-base) ease;
}
.page:hover {
	border-color: var(--c-accent);
	color: var(--c-accent);
}
.page-active,
.page-active:hover {
	background: var(--c-accent);
	border-color: var(--c-accent);
	color: var(--c-on-accent);
}
.page:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent) 35%, transparent);
}

/* ══ Forced colours (Windows High Contrast Mode) ══════════════
   This mode discards author colours and repaints from the user's own
   system palette. Three decisions in this sheet break under it: the
   `appearance: none` controls have no UA widget left to be repainted
   for them, `box-shadow` is not rendered at all — which is every focus
   ring here — and checked and unchecked collapse onto the same forced
   background. The rules below opt the affected controls out with
   `forced-color-adjust` and repaint them by hand from system colours,
   so state stays DISTINGUISHABLE rather than merely visible.
   `!important` is load-bearing, not defensive: the theme files
   re-declare these same rings and fills at higher specificity, and a
   media query contributes no specificity of its own. ══ */
@media (forced-colors: active) {
	/* Focus rings first — every one of these traded the UA outline away
	   for a box-shadow glow, which this mode drops silently. */
	.input:focus-visible,
	.select:focus-visible,
	.checkbox:focus-visible,
	.radio:focus-visible,
	.switch:focus-visible,
	.tab:focus-visible,
	.page:focus-visible {
		outline: 2px solid CanvasText !important;
		outline-offset: 2px;
	}

	.input {
		forced-color-adjust: none;
		background-color: Canvas !important;
		color: CanvasText !important;
		border-color: ButtonBorder !important;
	}
	.input::placeholder {
		color: GrayText !important;
	}
	.input:disabled {
		color: GrayText !important;
		border-color: GrayText !important;
	}

	/* The chevron is two currentColor gradients, and background images are
	   left unforced — restated in CanvasText so it still reads as a
	   dropdown instead of a plain text field. Position and size are left
	   to whichever theme is active. */
	.select {
		forced-color-adjust: none;
		background-color: Canvas !important;
		background-image: linear-gradient(45deg, transparent 50%, CanvasText 50%),
			linear-gradient(135deg, CanvasText 50%, transparent 50%) !important;
		color: CanvasText !important;
		border-color: ButtonBorder !important;
	}
	.select:disabled {
		color: GrayText !important;
		border-color: GrayText !important;
		background-image: linear-gradient(45deg, transparent 50%, GrayText 50%),
			linear-gradient(135deg, GrayText 50%, transparent 50%) !important;
	}

	/* Unchecked is an empty Canvas well with a ButtonBorder edge; checked
	   fills with SelectedItem and flips its mark to SelectedItemText. Both
	   the fill and the mark change, so the states differ by two signals
	   even where a theme (Win95, Bold) had tuned its own. */
	.checkbox,
	.radio,
	.switch {
		forced-color-adjust: none;
		background: Canvas !important;
		border-color: ButtonBorder !important;
	}
	.checkbox:checked,
	.radio:checked,
	.switch:checked {
		background: SelectedItem !important;
		border-color: SelectedItem !important;
	}
	.checkbox:checked::before,
	.radio:checked::before {
		background: SelectedItemText !important;
	}
	/* The switch thumb is drawn unchecked too, so it needs the contrasting
	   ink for whichever track it is currently sitting on. */
	.switch::before {
		background: CanvasText !important;
		box-shadow: none !important;
	}
	.switch:checked::before {
		background: SelectedItemText !important;
	}
	.checkbox:disabled,
	.radio:disabled,
	.switch:disabled {
		border-color: GrayText !important;
	}

	/* Selection elsewhere is expressed as an --c-accent fill, which forces
	   flat to Canvas — the current page and current tab would read as
	   ordinary ones. Same system pair, same reasoning as the controls. */
	.page-active,
	.page-active:hover {
		forced-color-adjust: none;
		background: SelectedItem !important;
		border-color: SelectedItem !important;
		color: SelectedItemText !important;
	}
	.tab-active::after {
		forced-color-adjust: none;
		background: SelectedItem !important;
	}
}
