@charset "utf-8";

/* The layer is declared here, in the file — see the note in reset.css for why.

   This file no longer overrides anything in `base`. It declares tokens; base and
   components apply them. That was the point of the step: `theme` sat later in the
   order and beat `base` on font-weight and letter-spacing, so the two files were
   arguing about the same properties from different layers. Now only one of them
   sets those properties at all.

   Nothing here is !important any more either. The last one covered a missing
   `body.dark` prefix in a duplicated block, and the block is gone. */
@layer theme {

	/*
	////////////////////////////////////////////////////////////
	//
	//  WHERE "THE THEME IS DARK" IS DECIDED — three places, and nowhere else
	//
	////////////////////////////////////////////////////////////
	*/

	/* Three places, because the target behaviour has three cases and they cannot be
	   folded into one selector: two of them live in media queries, the third in a
	   class, and below 741 the class must be ignored entirely.

	     >= 741   the system setting by default, a stored choice overrides it
	     <= 740   always the system setting; a stored choice is ignored, because
	              there is no switch at that width and a choice that cannot be
	              undone from the device is worse than no choice

	   `color-scheme` is on :root and not on body on purpose: on body it feeds
	   light-dark() correctly but leaves the UA's own painting — scrollbars, form
	   controls — on the light scheme. Measured: `body { color-scheme: dark }` gives
	   getComputedStyle(:root).colorScheme === "normal" and a byte-identical PNG to
	   declaring nothing.

	   Everything below this block is a value. Nothing below it asks which theme is
	   on, and that is the property worth keeping. */
	:root { color-scheme: light; }

	@media (min-width: 741px) {

		:root.dark { color-scheme: dark; }

		@media (prefers-color-scheme: dark) {
			:root:not(.light):not(.dark) { color-scheme: dark; }
		}
	}

	@media (prefers-color-scheme: dark) and (width <= 740px) {
		:root { color-scheme: dark; }
	}

	/*
	////////////////////////////////////////////////////////////
	//
	//  VALUES
	//
	////////////////////////////////////////////////////////////
	*/

	/* Colours ride light-dark(), so each one is written once and the condition above
	   picks the side. Note that this is not a saving in declarations — eight before,
	   eight now. What it buys is that the pair sits on one line, where a change to
	   one half cannot silently miss the other. */
	:root {
		--color-bg: light-dark(white, #222);
		--color-bg-muted: light-dark(#F4F4F4, #333);
		--color-fg: light-dark(black, #ddd);
		--color-fg-muted: light-dark(#999, #888);
		--color-accent: #00F;
		--color-fg-hover: light-dark(#00F, white);
		--color-menu-bg: light-dark(rgba(255, 255, 255, 0.75), rgba(34, 34, 34, 0.75));
		--color-icon-hover: light-dark(orange, white);
	}

	/* Weight, tracking and the icon file are not colours, so light-dark() does not
	   reach them and the dark values are repeated once per place. Three copies of
	   five declarations is the honest price of this behaviour; it is not a cost of
	   putting the condition in CSS, it is a cost of the behaviour having three cases.

	   The dark theme takes a lighter weight and a wider track on purpose: light text
	   on a dark ground reads heavier than the same size dark-on-light. Optical
	   compensation, tuned by eye — do not "straighten" these numbers. */
	:root {
		--weight-body: 380;
		--weight-display: 500;
		--weight-sub: 400;
		--weight-year: 570;
		--tracking-body: normal;
		--icon-theme: url('/icons/sun.svg');
	}

	@media (min-width: 741px) {

		:root.dark {
			--weight-body: 330;
			--weight-display: 450;
			--weight-sub: 350;
			--weight-year: 530;
			--tracking-body: 0.02em;
			--icon-theme: url('/icons/moon.svg');
		}

		@media (prefers-color-scheme: dark) {

			:root:not(.light):not(.dark) {
				--weight-body: 330;
				--weight-display: 450;
				--weight-sub: 350;
				--weight-year: 530;
				--tracking-body: 0.02em;
				--icon-theme: url('/icons/moon.svg');
			}
		}
	}

	@media (prefers-color-scheme: dark) and (width <= 740px) {

		:root {
			--weight-body: 330;
			--weight-display: 450;
			--weight-sub: 350;
			--weight-year: 530;
			--tracking-body: 0.02em;
			--icon-theme: url('/icons/moon.svg');
		}
	}

	/*
	////////////////////////////////////////////////////////////
	//
	//  WHAT WEARS THEM
	//
	////////////////////////////////////////////////////////////
	*/

	body {
		background-color: var(--color-bg);
		color: var(--color-fg);
	}

	a {
		color: var(--color-fg);
	}

	.block figcaption a {
		color: var(--color-fg-muted);
		text-decoration: underline;
	}

	/* Hover only. :focus-visible used to be listed here too, and that made keyboard
	   focus look exactly like a pointer resting on the button — the same colour
	   change and nothing else, because the button's own mask was eating its focus
	   ring. With the ring painting again (see #theme-icon in main.css) focus has its
	   own signal, and sharing this one would only blur the two states back together.
	   The ring is the browser's, on every focusable element on the site without
	   exception — .skip-link used to be the one that drew its own, and measurement
	   is what ended that; see its rule below. */
	#theme-icon:hover {
		color: var(--color-icon-hover);
	}

	.muted, .muted a, .job-year, .block figcaption, .block figcaption a {
		color: var(--color-fg-muted);
	}

	/* .job-desc is here because the work history is prose that is not in a .col.
	   It lost its hover twice, by two different mechanisms, and neither showed up
	   in a frame: the markup dropped the class this list matched on (a9df5cb,
	   <div class="col job"> became <li class="job">), and then the dark block's
	   broader bare `a:hover`, which had been covering it alone ever since, went
	   away with that block when the two themes merged onto light-dark() (c934df8).
	   Measured before adding it back: rest and hover were the same colour in both
	   themes, rgb(0,0,0) and rgb(221,221,221). */
	h1 a:hover, .footer a:hover, .next-project a:hover, a:hover .heading-flourish, .menu a:hover, .col a:hover, .job-desc a:hover, .block figcaption a:hover, .navigation a:hover,
	h1 a:focus-visible, .footer a:focus-visible, .next-project a:focus-visible, a:focus-visible .heading-flourish, .menu a:focus-visible, .col a:focus-visible, .job-desc a:focus-visible, .block figcaption a:focus-visible, .navigation a:focus-visible {
		color: var(--color-fg-hover);
	}

	.menu .selected {
		color: var(--color-fg);
	}

	.menu .selected:hover {
		color: var(--color-fg-muted);
		text-decoration: line-through;
	}

	.navigation {
		background-color: var(--color-bg-muted);
	}

	/* The skip link is only ever seen while focused, so this is its whole palette.
	   Geometry is in main.css, in `components`.

	   It used to draw its own ring, `2px solid var(--color-accent)`, and the comment
	   above this file's #theme-icon rule justified that by saying it needed one
	   against its own panel. Measured 2026-09-17, that was true in one theme and
	   measurably false in the other. Counted in pixels — the crop with the ring
	   against the same crop with `outline: none`, in the same run:

	     light panel rgb(255,255,255): own #00F 1164px at 8.59:1, browser's
	                                   rgb(0,95,204) 1148px at 5.98:1
	     dark  panel rgb(34,34,34):    own #00F 1180px at 1.85:1, browser's
	                                   rgb(153,200,255) 1742px at 9.14:1

	   1.85:1 is a ring that is in the frame and not on the screen. So the
	   declaration is gone and this element joins every other one: the browser's
	   ring follows color-scheme on :root and cannot drift away from the background,
	   which is the reason group A gave for not drawing our own anywhere. */
	.skip-link:focus-visible {
		background-color: var(--color-bg);
		color: var(--color-fg);
	}
}
