/* ============================================================================
   DESIGN TOKENS

   Three layers, one theming mechanism.

     1. Primitives   --c-*        raw ramps. Never used by a component.
     2. Semantics    --color-*    role-named. What components consume.
     3. Components   --btn-*      per-component recipes built from semantics.

   Every themed token is declared with light-dark(). That is deliberate: it
   means any container can flip its whole subtree by declaring
   `color-scheme: dark`, which is how the always-dark sections, the footer and
   the red hero get their styling without a single hand-written override. See
   the "scoped themes" note at the bottom of this file.
   ============================================================================ */

@layer tokens {

/* ── Layer 1 · Primitives ─────────────────────────────────────────────────── */

:root {
	color-scheme: light dark; /* required for light-dark() to resolve */

	/* Neutral ramp — authored in oklch so the lightness steps are perceptually
	   even and hue/chroma stay locked. The previous ramp drifted from hue 33 to
	   hue 60 across its range and had L* steps between 3.4 and 20.8, which is
	   why there was never a usable value for tertiary text.

	   450 exists because dark mode needs a tertiary text value that clears
	   4.5:1 against the 950 surface; 500 lands at 4.31 there. */
	--c-neutral-50:  oklch(0.972 0.004 70); /* #F7F5F3 */
	--c-neutral-100: oklch(0.938 0.006 70); /* #EDEAE6 */
	--c-neutral-200: oklch(0.878 0.008 70); /* #DAD6D1 */
	--c-neutral-300: oklch(0.795 0.009 70); /* #C0BBB6 */
	--c-neutral-400: oklch(0.660 0.009 70); /* #96918C */
	--c-neutral-450: oklch(0.610 0.009 70); /* #87827D */
	--c-neutral-500: oklch(0.560 0.008 70); /* #78746F */
	--c-neutral-600: oklch(0.470 0.007 70); /* #5D5A57 */
	--c-neutral-700: oklch(0.355 0.006 70); /* #3E3B38 */
	--c-neutral-800: oklch(0.255 0.005 70); /* #242220 */
	--c-neutral-900: oklch(0.185 0.004 70); /* #141211 */
	--c-neutral-950: oklch(0.135 0.004 70); /* #090807 */

	--c-white-alpha-10: hsla(0, 0%, 100%, 0.1);
	--c-white-alpha-20: hsla(0, 0%, 100%, 0.2);
	--c-white-alpha-30: hsla(0, 0%, 100%, 0.3);
	--c-white-alpha-40: hsla(0, 0%, 100%, 0.4);
	--c-white-alpha-50: hsla(0, 0%, 100%, 0.5);
	--c-white-alpha-60: hsla(0, 0%, 100%, 0.6);
	--c-white-alpha-70: hsla(0, 0%, 100%, 0.7);
	--c-white-alpha-80: hsla(0, 0%, 100%, 0.8);
	--c-white-alpha-90: hsla(0, 0%, 100%, 0.9);

	--c-black-alpha-10: hsla(0, 0%, 0%, 0.1);
	--c-black-alpha-20: hsla(0, 0%, 0%, 0.2);
	--c-black-alpha-30: hsla(0, 0%, 0%, 0.3);
	--c-black-alpha-40: hsla(0, 0%, 0%, 0.4);
	--c-black-alpha-50: hsla(0, 0%, 0%, 0.5);
	--c-black-alpha-60: hsla(0, 0%, 0%, 0.6);
	--c-black-alpha-70: hsla(0, 0%, 0%, 0.7);
	--c-black-alpha-80: hsla(0, 0%, 0%, 0.8);
	--c-black-alpha-90: hsla(0, 0%, 0%, 0.9);

	/* Red ramp. Kept in hsl so 500 stays exactly the brand red.

	   IMPORTANT: 500 is the *identity* red and nothing else. White on it is
	   3.96:1, and red-500 on white is also 3.96:1 — both below the 4.5 needed
	   for the sizes this site actually sets. Anything interactive or textual
	   starts at 600. */
	--c-red-400: hsl(348 100% 57%); /* #FF2450 — red text on dark surfaces */
	--c-red-500: hsl(348 100% 50%); /* #FF0033 — brand only */
	--c-red-600: hsl(348 100% 44%); /* #E0002D */
	--c-red-700: hsl(348 100% 40%); /* #CC0029 */
	--c-red-800: hsl(348 100% 34%); /* #AD0023 */

	/* Status ramp. Reserved for form validation and system messaging — no
	   consumers yet, kept so the palette is derived once rather than invented
	   at the point of need. */
	--c-amber-400: #FF8C30;
	--c-amber-600: #8A5A12;
	--c-green-400: #4FBF8B;
	--c-green-600: #1C6B45;
}

/* ── Layer 2 · Semantic colour ────────────────────────────────────────────── */

:root {
	/* Surfaces */
	--color-surface:   light-dark(#ffffff, var(--c-neutral-950));
	/* One step darker than it was. At neutral-50 the alternating band read as
	   white at a glance, so the page's value structure was red / white /
	   black with nothing in between. */
	--color-surface-2: light-dark(var(--c-neutral-100), var(--c-neutral-900));
	--color-surface-3: light-dark(var(--c-neutral-100), var(--c-neutral-800));

	/* Text, strongest to faintest. Measured against --color-surface:
	   text-1 18.68 / 16.69 · text-2 11.13 / 6.41 · text-3 4.64 / 5.26 */
	--color-text-1: light-dark(var(--c-neutral-900), var(--c-neutral-100));
	--color-text-2: light-dark(var(--c-neutral-700), var(--c-neutral-400));
	--color-text-3: light-dark(var(--c-neutral-500), var(--c-neutral-450));

	/* Lines. Two tokens, because they have different jobs and different legal
	   minimums: --color-rule is a decorative hairline and may be faint;
	   --color-border-control is the only thing indicating the bounds of an
	   input or an outline button, so it holds >= 3:1 (3.12 / 4.31). */
	--color-rule:           light-dark(var(--c-black-alpha-10), var(--c-white-alpha-10));
	--color-rule-strong:    light-dark(var(--c-neutral-300), var(--c-neutral-700));
	--color-border-control: light-dark(var(--c-neutral-400), var(--c-neutral-500));

	/* A second, higher-emphasis control border. --color-border-control only
	   has to clear 3:1 (that's what an input needs); the ghost button's
	   outline *is* the whole control, so it reads as a much weaker shape than
	   the filled variants at that floor — 3.12:1 in light mode, and a flat
	   mid-grey at 4.31:1 in dark mode that doesn't read as "outlined in white"
	   the way the on-brand ghost button already does. This is the same
	   neutral-700 already proven as text-2 (11.13:1) and a white-alpha wash in
	   dark mode (~9:1 on --color-surface) — deliberately heavier than a form
	   field needs, on purpose, for the one button whose border is its only
	   fill. */
	--color-border-control-strong: light-dark(var(--c-neutral-700), var(--c-white-alpha-70));

	/* Brand, action, focus */
	--color-brand:        var(--c-red-500);                                 /* identity, large use only */
	--color-action:       light-dark(var(--c-red-600), var(--c-red-700));   /* filled control */
	--color-action-hover: light-dark(var(--c-red-700), var(--c-red-600));   /* darkens in light, lightens in dark */
	--color-action-text:  light-dark(var(--c-red-600), var(--c-red-400));   /* red as small text: 4.99 / 5.36 */
	--color-on-action:    #ffffff;                                          /* 4.99 / 5.83 on the fills above */
	--color-focus:        light-dark(var(--c-red-600), var(--c-red-400));

	/* A full red field that carries text. One step down from the identity red
	   so white body copy on it clears 4.5:1 — at this size the difference from
	   --color-brand is not perceptible, but 3.96 vs 4.99 is. */
	--color-surface-brand: var(--c-red-600);
	--color-on-brand:      #ffffff;

	/* --- Page-scheme tokens -------------------------------------------------
	   These follow the *page* theme and deliberately do NOT use light-dark().
	   They are applied to containers that also set `color-scheme`, where
	   light-dark() would resolve against the container's own scheme rather than
	   the page's — which would make an always-dark band pick its dark-mode
	   value even on a light page. Keep this list short; everything else should
	   be a normal light-dark() token. */
	--page-surface-contrast: var(--c-neutral-900);

	/* Translucent wash for tinted panels that must sit on either surface */
	--color-brand-wash: light-dark(hsl(348 100% 50% / 0.06), hsl(348 100% 50% / 0.12));

	/* --- Physical objects ---------------------------------------------------
	   The picture frames on /field-notes are the one place the site draws an
	   object rather than a surface. A real moulding is black and a real mount
	   board is white in both schemes — a frame that inverted with the page
	   would stop reading as a frame — so these are fixed values and, like the
	   page-scheme tokens above, deliberately not light-dark(). They are
	   tokens rather than literals so the exception is declared here once and
	   findable, rather than being two hex values buried in a component. */
	--color-frame-moulding: var(--c-neutral-950);
	--color-frame-mount:    #ffffff;
	--color-frame-shadow:   hsl(0 0% 0% / 0.2);
	--color-frame-bevel:    hsl(0 0% 0% / 0.4);

	/* --- Nav grounds for a forced theme -------------------------------------
	   When an element tells the nav what it is with data-nav-theme (a
	   full-bleed image, typically), there is no background to measure, so
	   scripts.js takes the strip the bar paints behind itself from here. Fixed
	   values, not light-dark(), for the same reason as the frames: "light"
	   means a light ground on a dark page too, because the thing under the bar
	   is light whatever the page scheme. Each matches the surface its bucket
	   normally measures, so a forced band looks like a real one. */
	--nav-ground-light: #ffffff;
	--nav-ground-dark:  var(--c-neutral-950);
	--nav-ground-brand: var(--color-surface-brand);
}

@media (prefers-color-scheme: dark) {
	:root {
		/* On a dark page an always-dark band cannot get darker, so it lifts
		   instead — the standard elevated-panel step. */
		--page-surface-contrast: var(--c-neutral-800);
	}
}

/* ── Layer 3 · Component recipes ──────────────────────────────────────────── */

:root {
	/* Buttons. Three variants cover every case on the site. There is no
	   "static light" or "inverse" variant: a container that is always dark
	   declares `color-scheme: dark` and these resolve to their dark values. */

	--btn-primary-bg:       var(--color-action);
	--btn-primary-bg-hover: var(--color-action-hover);
	--btn-primary-fg:       var(--color-on-action);
	--btn-primary-border:   var(--color-action);

	/* On a near-black ground a filled neutral button cannot get much contrast
	   from its fill alone — on the always-dark bands the 800 fill landed within
	   1.2:1 of the band. So the fill only has to read as *lifted*, and the
	   border does the work of bounding the control: --color-border-control is
	   the token that guarantees >= 3:1 against whatever surface it sits on.

	   The fill itself is a black/white alpha wash rather than a fixed neutral
	   step, on purpose: a wash darkens or lightens *relative to whatever's
	   behind it*, so it can't land close to its surface the way two absolute
	   ramp steps can. That was a real gap — neutral-50 → neutral-100 (the
	   surface-2 alt band vs. the old secondary fill) is only 0.034 L apart,
	   the smallest gap anywhere on the ramp, so a secondary button on an alt
	   section nearly disappeared into it. 10%/20% black covers every light
	   surface with room to spare (dark neutral-900 text stays >10:1 regardless
	   of backdrop); 20% white lands almost exactly on the old neutral-700
	   (~9:1 white-text headroom on the darkest band) but keeps that same
	   margin on the lighter alt-3 band too, where neutral-700 vs. neutral-800
	   was a much thinner 0.10 L gap. */
	--btn-secondary-bg:       light-dark(var(--c-black-alpha-10), var(--c-white-alpha-20));
	--btn-secondary-bg-hover: light-dark(var(--c-black-alpha-20), var(--c-white-alpha-30));
	--btn-secondary-fg:       light-dark(var(--c-neutral-900), var(--c-neutral-100));

	/* Same alpha-wash logic as secondary, at half strength — a hint of fill on
	   hover, not a jump to a fixed surface step that (like the old secondary
	   fill) could read as invisible on some bands and heavy-handed on others. */
	--btn-ghost-bg-hover: light-dark(var(--c-black-alpha-10), var(--c-white-alpha-10));

	/* NOTE — why the button borders are NOT tokens here.
	   A var() reference inside a custom property is substituted where the
	   property is *declared*, not where it is used. So a component token
	   written as `--btn-secondary-border: var(--color-border-control)` freezes
	   to the :root value and ignores any element that re-points the semantic
	   token — which is exactly what .onBrand does. (light-dark() behaves
	   differently: it is a colour function, resolved at use, which is why the
	   fills above still follow a scoped color-scheme correctly.)

	   So the two properties that must track their surface — both button borders
	   — read var(--color-border-control) directly in 05-buttons.css. */

	/* Links — the highlighter stroke.

	   Every underline on the site is one thick translucent band lifted into the
	   lower half of the word, not a hairline under it. Its colour is mixed from
	   the ink it marks, so a link takes a wash of its own colour on any surface
	   with no per-theme override: neutral copy gets a neutral wash, a red link
	   gets a red one.

	   currentColor is what lets this be a token at all. The var() substitution
	   trap noted above does not apply to it — currentColor is a colour keyword
	   resolved where the token is *used*, the same way light-dark() is, so one
	   declaration covers every link on every surface.

	   Measured against the band itself, since that is the ground the lower half
	   of the glyph is read on: 14.3:1 at rest / 9.9:1 on hover in light,
	   11.9 / 7.6 in dark. */
	--link-highlight:       color-mix(in srgb, currentColor 20%, transparent);
	--link-highlight-hover: color-mix(in srgb, currentColor 25%, transparent);

	/* A negative offset lifts the band into the word; skip-ink is off in
	   05-buttons.css so it runs unbroken through descenders. */
	--link-underline-offset:    -0.15em;
	--link-underline-thickness:  0.5em;
}

/* ── Typography ───────────────────────────────────────────────────────────── */

:root {
	/* Gotham comes from the Adobe Fonts kit loaded in each page's <head>.
	   Weights available: 300 light, 400 book, 500 medium, 700 bold, 800 black, 900 ultra. */
	/* Two cuts carry the site. --font is display, headings and body;
	   --font-narrow is every small tracked voice — buttons, nav, captions,
	   eyebrows, the label family, form labels. gotham-xnarrow was a third cut
	   doing the same job as --font-narrow at label sizes and has been dropped;
	   don't reintroduce it. */
	--font:           "gotham", sans-serif;
	--font-narrow:    "gotham-narrow", sans-serif;
	--font-condensed: "gotham-condensed", sans-serif;
	--font-serif:     "EB Garamond", "Times New Roman", Times, serif;

	--letter-spacing-tight:  -0.025em;
	--letter-spacing-normal:  0em;
	--letter-spacing-loose:   0.07em;
	--letter-spacing-wide:    0.15em;
	--letter-spacing-wider:   0.25em;
	--letter-spacing-widest:  0.35em;

	/* --- Type scale ---------------------------------------------------------
	   @link https://utopia.fyi/type/calculator?c=360,16,1.25,1240,19,1.333,7,2,&s=0.75|0.5|0.25,1.5|2|3|4|6|8,s-l&g=s,l,xl,12

	   360px/16px/1.25 → 1240px/19px/1.333. The two ratios are the point: the
	   scale is gentler at the small end and steeper at the large one, so a
	   headline takes proportionally more of a desktop screen than of a phone.

	   THE STEP NAMES ARE OFFSET FROM UTOPIA'S BY ONE. Utopia's base step —
	   the 1rem/16px one — is --step-1 here, not --step-0, because --step-1 is
	   what `body` and the form controls are set in and renaming it would have
	   meant touching every font-size on the site. So when you regenerate this
	   from the link above, the generator's step -2…7 paste in as -1…8. Check
	   that --step-1's floor is still exactly 1rem before you ship it.

	   THE 1rem FLOOR ON --step-1 IS LOAD-BEARING, not a round number that
	   happened to land. iOS Safari zooms the viewport when a focused form
	   control computes under 16px, and .form's input/select/textarea are set
	   in --step-1 (09-pages.css). The previous base was 12px/14px, which put
	   --step-1 at 15.0–15.3px across every phone width and zoomed the contact
	   form on every tap. Don't lower it. */
	--step--1: clamp(0.64rem, 0.6284rem + 0.0515vw, 0.6683rem);
	--step-0: clamp(0.8rem, 0.7628rem + 0.1652vw, 0.8908rem);
	--step-1: clamp(1rem, 0.9233rem + 0.3409vw, 1.1875rem);
	--step-2: clamp(1.25rem, 1.1138rem + 0.6053vw, 1.5829rem);
	--step-3: clamp(1.5625rem, 1.3385rem + 0.9956vw, 2.1101rem);
	--step-4: clamp(1.9531rem, 1.6015rem + 1.5629vw, 2.8127rem);
	--step-5: clamp(2.4414rem, 1.9063rem + 2.3781vw, 3.7493rem);
	--step-6: clamp(3.0518rem, 2.2556rem + 3.5384vw, 4.9979rem);
	--step-7: clamp(3.8147rem, 2.6498rem + 5.1772vw, 6.6622rem);
	--step-8: clamp(4.7684rem, 3.0861rem + 7.4769vw, 8.8806rem);
}

/* ── Radius, spacing, chrome ──────────────────────────────────────────────── */

:root {
	--radius-xs:  4px;
	--radius-sm:  8px;
	--radius-md:  12px;
	--radius-lg:  16px;
	--radius-xl:  20px;
	--radius-2xl: 24px;

	/* --- Spacing scale ------------------------------------------------------
	   @link https://utopia.fyi/space/calculator?c=360,12,1.2,1240,20,1.25,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6|8,s-l&g=s,l,xl,12 */
	--space-3xs: clamp(0.1875rem, 0.1364rem + 0.2273vw, 0.3125rem);
	--space-2xs: clamp(0.375rem, 0.2727rem + 0.4545vw, 0.625rem);
	--space-xs:  clamp(0.5625rem, 0.4091rem + 0.6818vw, 0.9375rem);
	--space-s:   clamp(0.75rem, 0.5455rem + 0.9091vw, 1.25rem);
	--space-m:   clamp(1.125rem, 0.8182rem + 1.3636vw, 1.875rem);
	--space-l:   clamp(1.5rem, 1.0909rem + 1.8182vw, 2.5rem);
	--space-xl:  clamp(2.25rem, 1.6364rem + 2.7273vw, 3.75rem);
	--space-2xl: clamp(3rem, 2.1818rem + 3.6364vw, 5rem);
	--space-3xl: clamp(4.5rem, 3.2727rem + 5.4545vw, 7.5rem);
	--space-4xl: clamp(6rem, 4.3636rem + 7.2727vw, 10rem);

	/* One-up pairs */
	--space-3xs-2xs: clamp(0.1875rem, 0.0085rem + 0.7955vw, 0.625rem);
	--space-2xs-xs:  clamp(0.375rem, 0.1449rem + 1.0227vw, 0.9375rem);
	--space-xs-s:    clamp(0.5625rem, 0.2813rem + 1.25vw, 1.25rem);
	--space-s-m:     clamp(0.75rem, 0.2898rem + 2.0455vw, 1.875rem);
	--space-m-l:     clamp(1.125rem, 0.5625rem + 2.5vw, 2.5rem);
	--space-l-xl:    clamp(1.5rem, 0.5795rem + 4.0909vw, 3.75rem);
	--space-xl-2xl:  clamp(2.25rem, 1.125rem + 5vw, 5rem);
	--space-2xl-3xl: clamp(3rem, 1.1591rem + 8.1818vw, 7.5rem);
	--space-3xl-4xl: clamp(4.5rem, 2.25rem + 10vw, 10rem);

	--hero-border-width: 4px;

	/* --- The global nav ------------------------------------------------------
	   A row of text links fixed across the top of the viewport (see 06-nav).
	   Three numbers describe it.

	   --nav-inset is the air above the links, plus whatever the device puts
	   there. env(safe-area-inset-top) is 0px everywhere except a home-screen
	   web app, where it is the real status bar — so on the open web this reads
	   as --space-s and nothing moves, and installed to the home screen the
	   whole bar steps down clear of the clock without a second set of numbers
	   to keep in sync. The viewport meta in Layout.astro carries
	   viewport-fit=cover, which is what makes env() report anything at all.

	   (It used to be tuned against the home hero's white frame. That frame was
	   removed in the redesign — --hero-border-width above has no consumer any
	   more — so the constraint the old number was holding is gone.)

	   --nav-height is what the whole bar occupies — the inset, one line of body
	   type, and the same air underneath. Anything that has to clear the nav
	   (scroll-padding, the first band of a page, the sticky chapter rail)
	   measures itself against this rather than guessing. It assumes one line,
	   which is true above 700px; below that the row stacks and the bar is
	   taller. Nothing needs the real number: the ground's fade is written from
	   the bottom of the bar rather than from the top (see 06-nav), so it holds
	   at any height without measuring one.

	   --nav-links-measure is how far the row of links may spread before it
	   starts to feel scattered. Under it the row justifies across the site
	   measure; over it the row caps and sits right.*/
	   
	--nav-inset:  calc(var(--space-s) + env(safe-area-inset-top, 0px));
	--nav-height: calc(var(--nav-inset) + 1.6rem + var(--space-s));
	--nav-links-measure: 32rem;

	/* --- The nav ground ------------------------------------------------------
	   --nav-surface is the colour of the band currently behind the bar,
	   measured and written to <html> by scripts.js on scroll. Two things read
	   it: the ground the bar paints (06-nav) and the page's own background
	   (03-base), which is what iOS Safari tints its status bar from. One value
	   for both is the point — it is what stops the browser chrome and the page
	   from reading as two treatments.

	   It is deliberately measured and not a bucket. A surface-2 band and a
	   surface-1 band are both "light" and visibly different, and a ground in
	   the wrong one of them stops being invisible, which is the only property
	   that makes it worth having.

	   It is deliberately NOT declared here. Every use site names its own
	   fallback — the token that site would have used anyway — so the no-JS
	   state is the site exactly as it was, per place, with nothing to keep in
	   sync. Declare it here and you would be choosing one colour for every
	   band on the site.

	   --nav-solid is how far down the ground stays fully opaque. Small by
	   design: its job is to meet the opaque strip iOS Safari paints behind the
	   status bar with no seam between the two, and nothing more. env() is the
	   real height of that strip wherever the page is allowed to know it — a
	   home-screen web app — and --space-m is the stand-in in the browser,
	   where the top inset always reports 0. max() rather than a sum, so the
	   opaque band does not grow into the type.

	   The ground has no tail past the bar. #header is exactly .navBar's height
	   and the gradient is sized by that box, so it finishes where the bar
	   does. A tail below it was tried and read as a haze hanging off the nav
	   rather than as the page. */
	--nav-solid: max(var(--space-s), env(safe-area-inset-top, 0px));
}

/* ── Scoped themes ────────────────────────────────────────────────────────────
   Because every token above is light-dark(), a container can re-theme its whole
   subtree with one declaration. This replaces the old --color-*-inverse,
   --color-*-light and --color-*-dark families, all of which encoded appearance
   rather than role and none of which are needed now.

       .someAlwaysDarkThing { color-scheme: dark; background: var(--color-surface); }

   Text, rules, buttons, form controls and scrollbars inside all follow.
   .themeDark / .themeLight below are the reusable version.
   ---------------------------------------------------------------------------- */

/* A saturated brand field (the home hero, a red band, the red "turn").
   color-scheme:dark gets the controls, buttons and form elements right, but the
   neutral text ramp is tuned for near-black grounds and reads as dirty grey on
   red — --color-text-2 lands at 1.6:1 there. So the text tokens are re-pointed
   at white for this surface only.

   There is deliberately no opacity ramp: solid white on --color-surface-brand is
   4.99:1, so any transparency at all drops small text below 4.5. Hierarchy on
   this surface comes from size and weight, not from fading the ink. */
.onBrand,
.homeHero,
.section.accent,
.csThemeRestrained .csTurn {
	color-scheme: dark;

	--color-text-1: var(--color-on-brand);
	--color-text-2: var(--color-on-brand);
	--color-text-3: var(--color-on-brand);
	--color-action-text: var(--color-on-brand);
	--color-rule:        color-mix(in srgb, var(--color-on-brand) 32%, transparent);
	--color-rule-strong: color-mix(in srgb, var(--color-on-brand) 55%, transparent);
	/* On red, neither the neutral control border (a mid-grey, 1.07:1) nor the
	   dark button fill (2.22:1) can bound a control on its own. So the border
	   goes near-white and does the work: 80% white over --color-surface-brand
	   is 3.48:1, which is what makes the button identifiable on this field. */
	--color-border-control: color-mix(in srgb, var(--color-on-brand) 80%, transparent);
	/* The ghost button's outline gets the same near-white treatment as the
	   regular control border — on this field there's no lighter/darker split
	   to make, both want to read as "white line on red." */
	--color-border-control-strong: var(--color-border-control);

	/* Buttons need their own recipe here rather than inheriting the page
	   scheme's: --btn-primary-bg is --color-action (red), which on a red field
	   is functionally invisible, and --btn-secondary-bg's dark-mode wash
	   lightens red-600 toward pink — great for a near-black ground, wrong
	   direction for white text on this one. */

	/* Primary flips polarity: white fill, red text — the one surface on the
	   site where red reads as *text* rather than a field. Red-600 on white is
	   the same 4.99:1 already proven for --color-action-text; the hover fill
	   (neutral-50) keeps that margin while still giving tactile feedback. */
	--btn-primary-bg:       var(--color-on-brand);
	--btn-primary-bg-hover: var(--c-neutral-100);
	--btn-primary-fg:       var(--c-red-600);
	--btn-primary-border:   var(--color-on-brand);

	/* Secondary goes a shade darker rather than lighter — white text needs a
	   dark fill, and lightening red-600 (the dark-mode instinct) moves toward
	   pink and away from it. Red-800 on red-600 gives white text 7.5:1 (up
	   from 4.99 on the field itself); the shape is bounded by the same
	   near-white border as everything else here, not by fill-vs-field
	   contrast, matching how secondary already relies on its border
	   everywhere else. */
	--btn-secondary-bg:       var(--c-black-alpha-20);
	--btn-secondary-bg-hover: var(--c-black-alpha-30);
	--btn-secondary-fg:       var(--color-on-brand);

	/* Ghost's hover wash follows suit: white, not the dark-mode default. */
	--btn-ghost-bg-hover: var(--c-black-alpha-10);

	/* The highlighter has to go the other way here. A wash mixed from white ink
	   lightens the field behind the word, and white on red-600 has only 4.99:1
	   to spend — 14% white takes it to 4.51 and the hover wash to 3.77, i.e.
	   through the floor. A black wash darkens instead, so the identical band
	   *raises* white text to 7.1:1 at rest and 8.6 on hover. Same reason this
	   surface has no opacity ramp: nothing on red may move the ground toward
	   the ink. */
	--link-highlight:       var(--c-black-alpha-20);
	--link-highlight-hover: var(--c-black-alpha-30);

	background: var(--color-surface-brand);
	color: var(--color-text-1);
}

.themeDark  { color-scheme: dark; }
.themeLight { color-scheme: light; }

.themeDark,
.themeLight {
	background: var(--color-surface);
	color: var(--color-text-1);
}

} /* @layer tokens */
