/* The site's ground and chrome, the same on every page: the base (font, black ground, the spectrum line, the one
   column), the header (siteHeader), the footer (siteFooter), the get row (getRow) of
   web/scripts/seo.mjs, and the shared primitives every page builds on: the quiet button (.btn), the page title,
   the totals line and the unbreakable fact (.fact) and sentence (.sent). Linked as /site.css, fingerprinted as
   site.<hash>.css by web/scripts/landing-page.mjs; the landing page carries it verbatim in its <style> instead
   (no render-blocking stylesheet before its first paint). Brand tokens only (web/brand/tokens.css). A page's own
   <style> comes after this sheet, so it adds to these rules and never repeats them.

   The look (owner, 2026-10-04: "lean into simplicity", nothing that reads as vibecoded): plain and calm on true
   black. White text, one grey for secondary text, accent blue for links and focus. Normal weights but for headings,
   left-aligned, a few sizes, 4-6 px radii, a border only where something is a control. No uppercase tracked labels,
   no gradients but the 2 px spectrum line at the top, no glow, blur or shadow, mono only for code and seed numbers.
   The current page is marked by a plain white rule (owner, 2026-10-03). Motion is short fades, none under
   prefers-reduced-motion.

   Page switches (owner, 2026-10-03): every page opts in to cross-document view transitions, so a same-origin
   navigation crossfades the page in 160 ms while the header stands still and the current page's rule slides from
   the old link to the new one (with no current link on one side, it fades). No script and no SPA: a browser
   without view transitions, or a visitor who asks for reduced motion, navigates as before. The links are fetched
   ahead by the speculation rules (/speculation-rules.json, sent in a Speculation-Rules header by web/Caddyfile).

   Header: sticky and centred (brand, the menu as one row, Add to <the visitor's browser>), the theme button at the
   right edge of the column. Clear at the top, solid black with a hairline once the page has scrolled
   (html.scrolled, install.js). Narrow (under 55rem): brand and a "Menu" that opens a native <details> panel of
   48 px rows split by a hairline, no script. Touch screens: no Add to Chrome (the extension is desktop
   only); the panel's last row sends the link to the visitor's computer. */

@font-face {
  font-family: 'Inter Var';
  src: url('/fonts/inter-opsz.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root { --gutter: 1.5rem; scroll-padding-top: calc(var(--tf-header-h) + 1rem); }
@media (max-width: 560px) {
  :root { --gutter: 1rem; }
}
/* The scrollbar's room is kept on every page, a short one too, so the centred header never moves between pages. */
html { scrollbar-gutter: stable; }
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--tf-ink);
  color: var(--tf-text);
  font-family: 'Inter Var', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif, 'Segoe UI Symbol', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji';
  font-optical-sizing: auto;
  font-size: 0.9375rem;
  line-height: 1.6;
  letter-spacing: -0.003em;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
/* The spectrum line, in flow above the header (owner, 2026-10-04: the line only, no light under it). */
body::before { content: ""; display: block; height: 2px; background: var(--tf-spectrum); }
::selection { background: var(--tf-select); color: var(--tf-fg); }
:focus-visible { outline: 2px solid var(--tf-accent); outline-offset: 2px; border-radius: 2px; }
a { color: inherit; }
h1, h2, h3, h4 { color: var(--tf-fg); text-wrap: balance; }
code, kbd, samp { font-family: var(--tf-font-mono); }
code { font-size: 0.86em; letter-spacing: 0; }
button, select, input { font: inherit; color: inherit; }

/* One column for every page: the same edges under the header, the content and the footer. */
.wrap { width: min(100%, calc(var(--tf-col) + 2 * var(--gutter))); margin-inline: auto; padding-inline: var(--gutter); }
main.wrap { padding-top: 3rem; }
/* A fact (a number, its label and the dot after them) and one sentence of a two-sentence heading each break as
   one: a line breaks between facts and between sentences, never inside one. */
.fact, .sent { display: inline-block; }

/* The page title, and the totals under it: a plain line, the numbers in white. */
main > h1, main > article > h1 { margin: 0 0 0.75rem; font-size: 2.25rem; font-weight: 650; line-height: 1.15; letter-spacing: -0.025em; }
main > .totals { display: block; margin: 0 0 2.5rem; color: var(--tf-muted); font-size: 1rem; line-height: 1.6; font-variant-numeric: tabular-nums; }
main > .totals b { margin-right: 0.25em; color: var(--tf-fg); font-weight: 600; }
main > .totals code { color: var(--tf-muted); font-size: 0.875rem; letter-spacing: 0; }

/* The quiet button: square-cornered, one hairline, raised on hover. */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem; min-height: 2.5rem; padding: 0 1rem; border: 0; border-radius: var(--tf-radius-sm); background: none; box-shadow: inset 0 0 0 1px var(--tf-line-strong); color: var(--tf-fg); font-size: 0.875rem; font-weight: 500; line-height: 1.2; text-decoration: none; white-space: nowrap; cursor: pointer; transition: background-color var(--tf-t) var(--tf-ease), box-shadow var(--tf-t) var(--tf-ease); }
.btn:hover { background: var(--tf-ink-raised); box-shadow: inset 0 0 0 1px var(--tf-line-heavy); }

/* The header. */
header.top {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  justify-content: center;
  align-items: stretch;
  gap: 0;
  width: 100%;
  max-width: none;
  height: var(--tf-header-h);
  margin: 0;
  padding-block: 0;
  padding-inline: max(var(--gutter), calc((100% - var(--tf-col)) / 2));
  background: var(--tf-bar-clear);
  box-shadow: inset 0 -1px 0 transparent;
  view-transition-name: top;
}
.scrolled header.top { background: var(--tf-ink); box-shadow: inset 0 -1px 0 var(--tf-line-strong); }
/* The sentinel install.js watches to tell the header the page has left the top. */
.top-sentinel { position: absolute; top: 0; left: 0; width: 1px; height: 8px; pointer-events: none; visibility: hidden; }
.brand { display: inline-flex; flex: none; align-self: center; align-items: center; gap: 0.55rem; color: var(--tf-fg); font-size: 0.9375rem; font-weight: 650; letter-spacing: -0.015em; text-decoration: none; }
.brand img { display: block; width: 22px; height: 22px; }
.top__nav { display: flex; align-items: stretch; gap: 1.75rem; margin-inline: 2.5rem 1.5rem; font-size: 0.84375rem; }
.top__nav a { position: relative; display: flex; align-items: center; color: var(--tf-muted); text-decoration: none; white-space: nowrap; }
.top__nav a:hover, .top__nav a[aria-current] { color: var(--tf-fg); }
/* The current page: a 1 px white rule at the header's foot, an element of its own (span.top__cur, seo.mjs) so a page
   switch can slide it to the next page's link. Only the colour changes on the link itself, never its weight, so
   the centred header keeps one width on every page. */
.top__cur { position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--tf-fg); pointer-events: none; view-transition-name: top-cur; }
.top__nav a:focus-visible { outline: none; }
.top__nav a:focus-visible::before { content: ""; position: absolute; inset: 0.875rem -0.4rem; border-radius: var(--tf-radius-sm); box-shadow: 0 0 0 2px var(--tf-accent); }
/* Add to <browser>: small and solid; while the store has no URL the build makes it "Coming soon to Chrome",
   disabled. The header holds one button per browser and shows the visitor's own: lead.js, in the <head>, sets
   data-lead on <html> before the first paint (Chrome without it), so nothing moves on load. The get row's big
   button (.get__add) is shown the same way. */
.top__add { display: inline-flex; flex: none; align-self: center; align-items: center; gap: 0.45rem; height: 2rem; margin-left: 1rem; padding: 0 0.8rem 0 0.65rem; border-radius: var(--tf-radius-sm); background: var(--tf-fg); color: var(--tf-ink); font-size: 0.8125rem; font-weight: 600; line-height: 1; text-decoration: none; white-space: nowrap; }
.top__add img { width: 15px; height: 15px; }
.top__add:hover { background: var(--tf-solid-hover); }
.top__add[aria-disabled="true"] { background: transparent; box-shadow: inset 0 0 0 1px var(--tf-line-strong); color: var(--tf-muted); cursor: not-allowed; }
.top__add[aria-disabled="true"]:hover { background: transparent; }
:root:not([data-lead]) :is(.top__add, .get__add):not([data-br="chrome"]), :root[data-lead="chrome"] :is(.top__add, .get__add):not([data-br="chrome"]),
:root[data-lead="firefox"] :is(.top__add, .get__add):not([data-br="firefox"]), :root[data-lead="edge"] :is(.top__add, .get__add):not([data-br="edge"]),
:root[data-lead="brave"] :is(.top__add, .get__add):not([data-br="brave"]), :root[data-lead="opera"] :is(.top__add, .get__add):not([data-br="opera"]) { display: none; }

/* The theme button, last in the header (siteHeader, behaviour in lead.js): the sun in the dark theme, the moon in the
   light one. A round button with one hairline, as quiet as the menu button beside it. The curtain
   is what it drops over the page: the next theme's ground, falling from the top and lifting again (550 ms each way);
   lead.js adds it to <body> for the length of one switch. */
.theme-toggle { display: grid; flex: none; align-self: center; place-items: center; width: 2.25rem; height: 2.25rem; margin-left: 0.75rem; padding: 0; appearance: none; border: 1px solid var(--tf-line-strong); border-radius: 999px; background: none; color: var(--tf-fg); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.theme-toggle:hover { border-color: var(--tf-line-heavy); }
.theme-toggle svg { width: 1rem; height: 1rem; }
:root:not([data-theme="light"]) .theme-toggle__moon, :root[data-theme="light"] .theme-toggle__sun { display: none; }
/* From 62rem the group of brand, menu and Add stays centred, and the button sits at the right edge of the
   column on its own (below that it follows Add, as there is no room beside the centred group). */
@media (min-width: 62rem) {
  .theme-toggle { position: absolute; top: 50%; right: max(var(--gutter), calc((100% - var(--tf-col)) / 2)); margin: -1.125rem 0 0; }
}
/* The mark is white (a prism and its rays): on white it is flipped to black, the rays turn to their deeper shades. */
:root[data-theme="light"] :is(.brand img, .foot__brand img, img.mark) { filter: invert(1) hue-rotate(180deg); }
/* Max White is a white gem: on white it gets a hairline outline (a drop shadow either side), the art untouched. */
:root[data-theme="light"] img[src$="/gems/max-white.svg"] { filter: drop-shadow(0 0 0.5px rgba(0, 0, 0, 0.7)) drop-shadow(0 0 1px rgba(0, 0, 0, 0.3)); }
.theme-curtain { position: fixed; inset: 0; z-index: 9997; background: #000000; transform: scaleY(0); transform-origin: top; pointer-events: none; }
.theme-curtain[data-to="light"] { background: #ffffff; }
.theme-curtain[data-phase="falling"] { transform: scaleY(1); transition: transform 550ms cubic-bezier(0.76, 0, 0.24, 1); }
.theme-curtain[data-phase="rising"] { transform: scaleY(0); transition: transform 550ms cubic-bezier(0.76, 0, 0.24, 1); }

/* Narrow: a "Menu" button that opens a full-width panel of 48 px rows; the current page's words on a 1 px white
   rule. */
.menu { display: none; align-self: center; }
.menu > summary { display: flex; align-items: center; gap: 0.6rem; min-height: 2.5rem; padding: 0 0.85rem; border-radius: var(--tf-radius-sm); box-shadow: inset 0 0 0 1px var(--tf-line-strong); color: var(--tf-fg); font-size: 0.875rem; font-weight: 500; list-style: none; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; }
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::after { content: ""; width: 12px; height: 7px; border-top: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transition: transform 180ms var(--tf-ease), height 180ms var(--tf-ease); }
.menu[open] > summary { background: var(--tf-ink-raised); box-shadow: inset 0 0 0 1px var(--tf-line-heavy); }
.menu[open] > summary::after { height: 1.5px; border-bottom: 0; transform: translateY(0.5px); }
.menu > nav { position: absolute; z-index: 20; top: 100%; left: 0; right: 0; display: flex; flex-direction: column; padding: 0.25rem var(--gutter) 0.75rem; border-bottom: 1px solid var(--tf-line-strong); background: var(--tf-ink); }
.menu[open] > nav { animation: top-drop 160ms var(--tf-ease); }
.menu > nav > a, .menu__send { display: flex; align-items: center; min-height: 3rem; border-top: 1px solid var(--tf-line); color: var(--tf-text); font-size: 1rem; font-weight: 500; text-decoration: none; }
.menu > nav > a:first-child { border-top: 0; }
.menu > nav > a[aria-current] { color: var(--tf-fg); font-weight: 600; }
.menu > nav > a[aria-current] > span { padding-bottom: 0.3em; background: linear-gradient(var(--tf-fg), var(--tf-fg)) left bottom / 100% 1px no-repeat; }
.menu__send { display: none; width: 100%; padding: 0; border-right: 0; border-bottom: 0; border-left: 0; background: none; font: inherit; font-weight: 500; text-align: left; cursor: pointer; }
@keyframes top-drop { from { opacity: 0; transform: translateY(-4px); } }

@media (max-width: 55rem) {
  header.top { justify-content: flex-start; gap: 0.5rem; }
  .brand { min-height: 2.75rem; margin-right: auto; }
  .top__nav { display: none; }
  .menu { display: block; }
  .top__add { height: 2.5rem; margin-left: 0; }
  .theme-toggle { width: 2.5rem; height: 2.5rem; margin-left: 0; }
}
/* 30rem, not 25: the theme toggle beside the menu needs the room. */
@media (max-width: 30rem) {
  .top__add { display: none; }
}
@media (hover: none) and (pointer: coarse) {
  .top__add { display: none; }
  .js .menu__send { display: flex; }
}

/* The footer: the links in a row, the fine print beside them. */
footer.foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.25rem 2rem; margin-top: 6rem; padding-top: 0; padding-bottom: 2.5rem; color: var(--tf-muted); font-size: 0.875rem; }
.foot nav { display: flex; flex-wrap: wrap; justify-content: flex-start; column-gap: 1.5rem; }
.foot nav a { display: inline-flex; align-items: center; min-height: 2.5rem; color: var(--tf-muted); text-decoration: none; }
.foot nav a:hover, .foot nav a[aria-current] { color: var(--tf-fg); }
.foot p { margin: 0; }
.foot a { text-underline-offset: 3px; }

/* The get row: Add to <the visitor's browser> as the one big button, the other four browsers as small logos after
   "Also for" (their names are the tooltips), the landing page. Each browser is there twice, as a button and as a
   logo: lead.js sets data-lead on <html> before the first paint (Chrome without it), the button of the visitor's own
   browser shows and its logo is left out of the logos. Hidden on touch screens but for its link, as the extension
   is desktop only. */
.get { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 1rem; margin: 4rem 0 0; }
.get__add { display: inline-flex; flex: none; align-items: center; justify-content: center; gap: 0.5rem; height: 2.5rem; padding: 0 1rem 0 0.85rem; border-radius: var(--tf-radius); background: var(--tf-fg); color: var(--tf-ink); font-size: 0.9375rem; font-weight: 600; text-decoration: none; }
.get__add:hover { background: var(--tf-solid-hover); }
.get__add img { width: 18px; height: 18px; }
.get__also { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 0.1rem; color: var(--tf-muted); font-size: 0.875rem; }
.get__also > :first-child { margin-right: 0.4rem; }
.get__br { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; border-radius: var(--tf-radius-sm); text-decoration: none; }
.get__br:hover { background: var(--tf-ink-raised); }
.get__br img { width: 20px; height: 20px; }
.get__add[aria-disabled="true"], .get__br[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
.get__how { display: inline-flex; align-items: center; min-height: 2.5rem; color: var(--tf-accent-text); font-size: 0.875rem; text-decoration: none; text-underline-offset: 0.3em; }
.get__how:hover { text-decoration: underline; }
:root:not([data-lead]) .get__br[data-br="chrome"], :root[data-lead="chrome"] .get__br[data-br="chrome"],
:root[data-lead="firefox"] .get__br[data-br="firefox"], :root[data-lead="edge"] .get__br[data-br="edge"],
:root[data-lead="brave"] .get__br[data-br="brave"], :root[data-lead="opera"] .get__br[data-br="opera"] { display: none; }
@media (hover: none) and (pointer: coarse) {
  .get__add, .get__also { display: none; }
}

/* Page switches: the page crossfades, the header stands still (identical on both sides), the current page's rule
   slides to the new link in 250 ms (its pair of images stretched, never scaled, so it stays 1 px). */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 160ms; animation-timing-function: var(--tf-ease); }
::view-transition-group(top) { animation-duration: 160ms; }
::view-transition-group(top-cur) { animation-duration: 250ms; animation-timing-function: var(--tf-ease); }
::view-transition-old(top-cur), ::view-transition-new(top-cur) { height: 100%; }

/* Phones. */
@media (max-width: 560px) {
  main.wrap { padding-top: 1.75rem; }
  main > h1, main > article > h1 { font-size: 1.875rem; }
  footer.foot { flex-direction: column; align-items: flex-start; margin-top: 4rem; }
  .get { margin-top: 3rem; }
}

/* Motion off: nothing slides or fades; states still change at once. */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  *, *::before, *::after { transition-duration: 0s !important; }
  .menu[open] > nav { animation: none; }
}
