/* Copied from ix packages/web/src/styles/fonts.css (the two faces the docs use).
   Inter 4.1 (SIL OFL 1.1, static/fonts/Inter-LICENSE.txt), InterVariable.ttf subset to Latin-1 plus general
   punctuation, arrows and geometric shapes, both variable axes (wght 100-900, opsz 14-32). */
@font-face {
	font-family: 'Inter';
	src: url('/asset?u=https%3A%2F%2Fix.dev%2Fblaze%2Ffonts%2FInterVariable-latin.woff2') format('woff2');
	font-weight: 100 900;
	font-style: normal;
	font-display: swap;
}

/* Monospace is for code, commands and identifiers only. */
@font-face {
	font-family: 'Berkeley Mono';
	src: url('/asset?u=https%3A%2F%2Fix.dev%2Fblaze%2Ffonts%2FBerkeleyMono-Variable.woff2') format('woff2');
	font-weight: 100 700;
	font-style: normal;
	font-display: swap;
}

/* The ix docs palette, dark and light, following the reader's system. Copied from ix packages/web/src/styles/site.css
   (.site grayscale ladder and aliases, the light .site values), styles/theme.css (font stacks) and
   lib/docs/Blocks.svelte (the red inline-code ink). */
:root {
	color-scheme: dark light;

	--g-0: #0c0c0d;
	--g-1: #101011;
	--g-2: #141415;
	--g-3: #19191a;
	--g-4: #1f1f20;
	--g-5: #28282a;
	--g-6: #333335;
	--g-7: #414143;
	--g-8: #57575a;
	--g-9: #727274;
	--g-10: #929190;
	--g-11: #b3b2af;
	--g-12: #d4d3cf;
	--g-13: #ebeae6;

	--bg: var(--g-1);
	--bg-2: var(--g-2);
	--bg-3: var(--g-3);
	--bg-4: var(--g-4);
	--line: var(--g-5);
	--line-2: var(--g-6);
	--ink-1: var(--g-13);
	--ink-2: var(--g-11);
	--ink-3: #878684;
	--ink-4: var(--g-8);

	--code-bg: color-mix(in srgb, var(--g-2) 70%, var(--g-1));
	--s-tint: color-mix(in srgb, var(--ink-1) 6%, transparent);

	/* Colour carries meaning only: an error or a live status (site.css). */
	--danger: #ff7168;
	--ok: #4cc27a;

	/* Chart series (renderer core chart.rs): a Subject's slot N is --series-N in every chart. 1 to 3 are orange, blue
	   and aqua, checked with the dataviz palette validator against --bg in each scheme, all pairs (lightness band,
	   chroma, colour-blind and normal-vision separation, 3:1 contrast). 4 is a neutral grey for an "everything else"
	   reference; it is never drawn beside 3 (it fails against aqua) and passes against 1 and 2. */
	--series-1: #d95926;
	--series-2: #3987e5;
	--series-3: #199e70;
	--series-4: #7f7e82;

	/* Inline code in the docs (Blocks.svelte, dark). Also the diagrams' "changed / rebuilt" ink. */
	--doc-code-ink: #ff7369;
	/* Code blocks' plain text. */
	--code-ink: var(--g-12);

	--font-sans:
		'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', 'Segoe UI', system-ui, sans-serif;
	--font-mono: 'Berkeley Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

/* ix site.css's light .site: warm paper. */
@media (prefers-color-scheme: light) {
	:root {
		--g-12: #2a2a2c;
		--bg: #f2f1ee;
		--bg-2: #eae9e4;
		--bg-3: #f6f5f2;
		--bg-4: #e2e1dc;
		--line: #dcdbd5;
		--line-2: #cdccc6;
		--ink-1: #161617;
		--ink-2: #46464a;
		--ink-3: #6b6a6e;
		--ink-4: #a2a19d;
		--code-bg: #ebeae5;
		--code-ink: #4d4d51;
		--danger: #c4332a;
		--ok: #2b8a4f;
		--doc-code-ink: #eb5757;
		--series-1: #d4561f;
		--series-2: #2a78d6;
		--series-3: #138f63;
		--series-4: #82817d;
	}
}

/* Syntax colours for code blocks, copied from ix packages/web/src/styles/doc-code.css (dark, and light below).
   Roles: keyword red, string green, call purple, type and name blue, number orange, comment grey. */
.code-roles {
	--syn-keyword: #ff7b72;
	--syn-string: #7ee2a8;
	--syn-title: #d2a8ff;
	--syn-attr: #79c0ff;
	--syn-number: #ffb86b;
	--syn-comment: #7d8590;
}

@media (prefers-color-scheme: light) {
	.code-roles {
		--syn-keyword: #cf222e;
		--syn-string: #0a7d4f;
		--syn-title: #6639ba;
		--syn-attr: #0b5fc4;
		--syn-number: #b35900;
		--syn-comment: #8a8a85;
	}
}

.hljs { color: var(--code-ink); background: transparent; }
.code-roles .hljs-keyword,
.code-roles .hljs-literal,
.code-roles .hljs-selector-tag { color: var(--syn-keyword); font-weight: 600; }
.code-roles .hljs-string,
.code-roles .hljs-regexp { color: var(--syn-string); }
.code-roles .hljs-title,
.code-roles .hljs-title.function_,
.code-roles .hljs-section,
.code-roles .hljs-name { color: var(--syn-title); font-weight: 500; }
.code-roles .hljs-attr,
.code-roles .hljs-attribute,
.code-roles .hljs-property,
.code-roles .hljs-variable,
.code-roles .hljs-built_in,
.code-roles .hljs-title.class_,
.code-roles .hljs-type { color: var(--syn-attr); font-weight: 400; font-style: normal; }
.code-roles .hljs-number,
.code-roles .hljs-symbol,
.code-roles .hljs-meta { color: var(--syn-number); font-style: normal; }
.code-roles .hljs-comment { color: var(--syn-comment); }
.code-roles .hljs-punctuation,
.code-roles .hljs-operator { color: var(--ink-3); }

/* Page base and docs prose, after ix site.css (.site, .s-prose) and lib/docs/Blocks.svelte (.doc, .ref). */
* { box-sizing: border-box; }
html {
	background: var(--bg);
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	font-synthesis: none;
}
/* No rubber band on a desk: the chat, the rail and the bar are fixed while the page bounced under them, and nothing on
   the page is worth pulling past its ends. Phones keep it (and pull to refresh). Only y: x is the swipe back. */
@media (pointer: fine) { html { overscroll-behavior-y: none; } }
body {
	margin: 0;
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.6;
	letter-spacing: -0.011em;
	color: var(--ink-2);
	background: var(--bg);
	overflow-wrap: break-word;
	text-rendering: optimizeLegibility;
}
::selection { background: color-mix(in srgb, var(--ink-1) 22%, transparent); color: var(--ink-1); }
:focus-visible { outline: 1.5px solid var(--ink-1); outline-offset: 2px; border-radius: 4px; }
code, pre, .mono { font-family: var(--font-mono); letter-spacing: 0; }

.doc { font-size: 16px; line-height: 1.7; color: var(--ink-2); }
.doc h2, .doc h3 { color: var(--ink-1); line-height: 1.25; font-weight: 600; letter-spacing: -0.02em; scroll-margin-top: 24px; }
.doc h2 { margin: 2.4em 0 0.6em; font-size: 24px; }
.doc h3 { margin: 1.7em 0 0.45em; font-size: 18px; }
.doc p, .doc ul, .doc ol { margin: 0 0 1.1em; }
.doc strong { color: var(--ink-1); font-weight: 600; }
.doc ul, .doc ol { padding-left: 1.4em; }
.doc li { margin: 0 0 0.45em; }
.doc li::marker { color: var(--ink-4); }
.doc :not(pre) > code {
	padding: 0.12em 0.4em;
	border-radius: 6px;
	background: var(--s-tint);
	color: var(--doc-code-ink);
	font-size: 0.88em;
	overflow-wrap: break-word;
}
.doc a { color: var(--ink-1); text-decoration: underline; text-decoration-color: var(--line-2); text-decoration-thickness: 1px; text-underline-offset: 3px; transition: text-decoration-color 0.15s; }
.doc a:hover { text-decoration-color: currentColor; }
.doc .dim { color: var(--ink-3); }

/* A reference table: the wrapper scrolls on a narrow screen instead of squeezing it. */
.ref { margin: 0 0 1.3em; border-radius: 12px; box-shadow: inset 0 0 0 1px var(--line); overflow-x: auto; }
.ref table { font-variant-numeric: tabular-nums; width: 100%; margin: 0; border-collapse: collapse; font-size: 14px; line-height: 1.5; }
.ref th { padding: 9px 14px; border-bottom: 1px solid var(--line); background: var(--s-tint); text-align: left; font-size: 12px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
.ref td { padding: 9px 14px; border-bottom: 1px solid var(--line); vertical-align: top; color: var(--ink-2); }
.ref tr:last-child td { border-bottom: 0; }
.ref td:first-child { color: var(--ink-1); }

/* A diagram: its own tone and a hairline, like the docs' code blocks. */
.figure { margin: 0 0 1.5em; padding: 18px 18px 14px; border-radius: 12px; background: var(--code-bg); box-shadow: inset 0 0 0 1px var(--line); }
.figure svg { display: block; width: 100%; height: auto; }
.figure figcaption { margin-top: 10px; font-size: 13px; line-height: 1.5; color: var(--ink-3); }
.figure .scroll { overflow-x: auto; }
.doc em { font-style: italic; }
[hidden] { display: none !important; }

/* The blocks renderer/core render.rs writes. The page shell (sidebar, header, outline, pager) is in shell.css. */
.doc .lede { max-width: 62ch; font-size: 17px; line-height: 1.55; color: var(--ink-3); }
.doc img { display: block; width: 100%; height: auto; margin: 0 0 1.5em; border-radius: 12px; box-shadow: inset 0 0 0 1px var(--line); background: var(--code-bg); }
.meta { margin: 14px 0 0; font-size: 14px; color: var(--ink-3); }
.meta span { color: var(--ink-4); }
.doc h2 a.hash { color: inherit; text-decoration: none; }

.status { display: inline-block; padding: 0.05em 0.55em; border-radius: 999px; background: var(--s-tint); color: var(--ink-2); font-size: 12px; font-weight: 500; letter-spacing: 0.02em; vertical-align: 0.12em; }
.status-accepted, .status-resolved { color: var(--ok); }
.status-rejected { color: var(--danger); }

.issue { margin: 0 0 1.4em; padding: 2px 18px 4px; border-radius: 12px; box-shadow: inset 0 0 0 1px var(--line); }
.issue h3 { margin-top: 0.9em; }

.rfc-index { list-style: none; padding: 0; }
.rfc-index li { margin: 0 0 1em; }
.rfc-index .num { color: var(--ink-3); margin-right: 0.3em; }
.references { font-size: 14px; }
.references li { margin: 0 0 0.5em; }
sup.cite { font-size: 0.7em; margin-left: 0.15em; }
.doc sup.cite a { text-decoration: none; color: var(--ink-3); }

/* Code (was lib/Code.svelte and lib/Copy.svelte). */
.codeblock { position: relative; min-width: 0; margin: 0 0 1.3em; border-radius: 12px; background: var(--code-bg); box-shadow: inset 0 0 0 1px var(--line); overflow: hidden; }
.codeblock pre { margin: 0; padding: 14px 16px; overflow-x: auto; font-size: 13.5px; line-height: 1.6; tab-size: 4; }
.codeblock code, .cmd code { font-family: var(--font-mono); font-size: inherit; background: none; padding: 0; }
.cmd { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 1.3em; padding: 4px 8px 4px 16px; border-radius: 12px; background: var(--code-bg); box-shadow: inset 0 0 0 1px var(--line); }
.cmd pre { margin: 0; padding: 10px 0; overflow-x: auto; font-size: 14px; }
.cmd button, .c-btn, .c-form button, .c-del { flex: none; padding: 6px 12px; border: 0; border-radius: 8px; background: var(--s-tint); color: var(--ink-1); font: inherit; font-size: 13px; cursor: pointer; }
.cmd button:hover, .c-form button:hover { background: var(--bg-4); }
@media (max-width: 480px) { .codeblock pre { font-size: 12px; padding: 12px; } }

/* Text fields (the comment forms, the chat). */
input, textarea { width: 100%; padding: 10px 14px; border: 0; border-radius: 10px; background: var(--code-bg); box-shadow: inset 0 0 0 1px var(--line); color: var(--ink-1); font: inherit; font-size: 15px; }
/* No corner grip anywhere: a text field grows with what is typed (the chat's caps itself in shell.css). */
textarea { resize: none; field-sizing: content; min-height: 4.5lh; max-height: 60vh; }
input:focus, textarea:focus { outline: none; box-shadow: inset 0 0 0 1px var(--ink-3); }
.error { margin: 0; color: var(--danger); font-size: 14px; }

/* Inline comments, rendered by the worker (render/comments.ts) and enhanced by client/comments.ts. A block with
   comments, or under the pointer, shows its button in the left margin (code blocks and tables: their top-right
   corner; images: below, right-aligned); without a margin, see main:not(.gutter) below.
   Without JS a thread shows when it (or a comment in it) is the URL's target: the button links to it. Once the
   script runs (main.c-live) it shows and hides threads with `hidden` instead. */
main[data-doc]:not(.c-live) .c-thread:not(.c-page):not(:target):not(:has(:target)) { display: none; }
.doc a.c-btn { display: inline-block; text-align: center; text-decoration: none; color: var(--ink-3); }
.doc a.c-btn.has, .doc a.c-btn[aria-expanded=true] { color: var(--ink-1); }
.c-delform { display: inline; }
[data-block] { position: relative; }
.c-btn { position: absolute; left: -46px; top: 0.15em; min-width: 30px; padding: 2px 8px; font-size: 12px; line-height: 1.5; color: var(--ink-3); opacity: 0; transition: opacity 0.12s; }
h2 > .c-btn, h3 > .c-btn { font-weight: 400; letter-spacing: 0; }
li > .c-btn { left: -66px; }
.codeblock > .c-btn, .ref > .c-btn { left: auto; right: 8px; top: 8px; }
img + .c-btn { position: static; display: block; margin: -1.2em 0 1.2em auto; }
[data-block]:hover > .c-btn, img[data-block]:hover + .c-btn, .c-btn:hover, .c-btn.has, .c-btn:focus-visible, .c-btn[aria-expanded=true] { opacity: 1; }
.c-btn.has, .c-btn[aria-expanded=true] { color: var(--ink-1); }
.c-btn:hover { background: var(--bg-4); }
/* A block's thread opens as a card under it; the page's own (`.c-page`, the Discussion section) sits on the page.
   Both are a column of faces joined by a thread line, then the composer: the chat's (shell.css .chat-form), the
   reader's face beside it once client/comments.ts has set it up (.c-ready). */
.c-thread { --av: 24px; margin: -0.4em 0 1.3em; padding: 12px 16px 14px; border-radius: 14px; background: var(--code-bg); box-shadow: inset 0 0 0 1px var(--line); font-size: 14.5px; line-height: 1.55; color: var(--ink-2); font-weight: 400; letter-spacing: 0; }
li > .c-thread { margin: 0.5em 0 0.8em; }
.c-thread[hidden] { display: none; }
.c-thread.c-page { --av: 32px; margin: 0; padding: 0; border-radius: 0; background: none; box-shadow: none; font-size: 15px; }
@media (max-width: 560px) { .c-thread.c-page { --av: 28px; } .c-item, .c-form.c-ready { column-gap: 10px; } }
.doc .discussion > h2 { display: flex; align-items: center; gap: 10px; margin-bottom: 0.25em; font-size: 20px; }
.discussion > h2 .c-count { padding: 1px 8px; border-radius: 999px; background: var(--s-tint); color: var(--ink-3); font-size: 13px; font-weight: 500; letter-spacing: 0; font-variant-numeric: tabular-nums; }
.doc .discussion > p.dim { margin-bottom: 1.4em; font-size: 14px; }

.c-item { position: relative; display: grid; grid-template-columns: var(--av) minmax(0, 1fr); gap: 0 12px; padding: 6px 0 14px; scroll-margin: 80px; }
.c-item:not(:last-child)::before { content: ""; position: absolute; left: calc(var(--av) / 2 - 1px); top: calc(var(--av) + 12px); bottom: 0; width: 2px; border-radius: 1px; background: var(--line); }
.c-item.c-target, .c-item.c-new { border-radius: 6px; }
.c-item.c-target { background: var(--s-tint); box-shadow: 0 0 0 8px var(--s-tint); }
.c-item > img, .doc .c-item > img { width: var(--av); height: var(--av); margin: 0; border-radius: 50%; box-shadow: none; background: var(--bg-4); }
.c-main { min-width: 0; }
.c-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; min-height: calc(var(--av) - 2px); padding-top: calc((var(--av) - 22px) / 2); font-size: 13px; line-height: 1.6; color: var(--ink-4); }
.doc .c-head a { color: var(--ink-1); font-weight: 600; text-decoration: none; }
.doc .c-head a.c-when { color: var(--ink-3); font-weight: 400; }
.c-head a:hover, .doc .c-head a.c-when:hover { text-decoration: underline; text-decoration-color: currentColor; }
.c-quote { margin: 2px 0 6px; padding-left: 10px; border-left: 2px solid var(--line-2); color: var(--ink-3); font-size: 13px; white-space: pre-line; }
.c-body { margin-top: 1px; color: var(--ink-1); overflow-wrap: anywhere; }
.c-body p { margin: 0 0 0.6em; }
.c-body p:last-child { margin: 0; }
.c-body code { font-family: var(--font-mono); font-size: 0.9em; }
.c-delform { margin-left: auto; }
.c-thread .c-del { padding: 0 6px; border-radius: 6px; background: none; color: var(--ink-4); font-size: 12px; line-height: 1.6; opacity: 0; transition: opacity 0.12s; }
.c-item:hover .c-del, .c-del:focus-visible { opacity: 1; }
.c-thread .c-del:hover, .c-del:focus-visible { background: var(--s-tint); color: var(--danger); }
@media (hover: none) { .c-thread .c-del { opacity: 1; } }

.c-list:not(:empty) + .c-form { margin-top: 2px; }
.c-form.c-ready { display: grid; grid-template-columns: var(--av) minmax(0, 1fr); gap: 0 12px; align-items: start; }
.c-me { display: block; width: var(--av); height: var(--av); margin-top: calc((38px - var(--av)) / 2); border-radius: 50%; background: var(--bg-4); overflow: hidden; }
.c-anon { display: block; width: 60%; height: 60%; margin: 20%; fill: none; stroke: var(--ink-4); stroke-width: 1.4; stroke-linecap: round; }
.c-me img, .doc .c-me img { display: block; width: 100%; height: 100%; margin: 0; border-radius: 0; box-shadow: none; }
.c-form form.c-compose { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0 6px; padding: 5px 5px 5px 14px; border-radius: 19px; background: var(--bg-4); box-shadow: inset 0 0 0 1px transparent; transition: box-shadow 0.15s, background-color 0.15s; }
.c-thread:not(.c-page) .c-form form.c-compose { background: var(--bg-3); box-shadow: inset 0 0 0 1px var(--line); }
.c-form form.c-compose:focus-within { background: var(--bg-3); box-shadow: inset 0 0 0 1px var(--line-2), 0 0 0 3px var(--s-tint); }
.c-compose textarea, .c-compose textarea:focus { flex: 1; width: auto; min-width: 0; min-height: 28px; max-height: 50vh; padding: 4px 0; border: 0; border-radius: 0; box-shadow: none; background: none; color: var(--ink-1); font: inherit; font-size: 14.5px; line-height: 1.4; resize: none; outline: none; }
.c-compose:focus-within textarea, .c-compose.c-has textarea { min-height: calc(3 * 1.4em + 8px); }
.c-compose textarea::placeholder { color: var(--ink-4); }
/* Not the sidebar's .row (shell.css). */
.c-compose .row { position: static; z-index: auto; display: flex; align-items: center; gap: 8px; height: auto; padding: 0; border-radius: 0; font-size: 13px; color: var(--ink-3); }
.c-compose .error { order: 3; flex-basis: 100%; padding: 2px 0 4px; font-size: 13px; }
/* Without JS: the signed-in line and a Post button under the field. With it the top bar says who is signed in. */
main:not(.c-live) .c-compose .row { flex-basis: 100%; justify-content: space-between; padding: 4px 0 0; }
main.c-live .c-compose .row > span { display: none; }
.c-form button.c-signout { padding: 0; background: none; color: var(--ink-3); font-size: 13px; text-decoration: underline; }
.c-form button.c-signout:hover { background: none; color: var(--ink-1); }
.c-form button:disabled { opacity: 0.6; cursor: default; }
.c-kbd { display: none; font: inherit; font-size: 11.5px; color: var(--ink-4); letter-spacing: 0.02em; }
.c-compose.c-has .c-kbd { display: inline; }
@media (hover: none) { .c-compose.c-has .c-kbd { display: none; } }
.c-form button.c-send { display: grid; place-items: center; width: 28px; height: 28px; padding: 0; border-radius: 50%; background: var(--ink-1); color: var(--bg); transition: opacity 0.12s, background-color 0.12s; }
.c-form button.c-send:hover { background: var(--g-12); }
.c-form button.c-send:disabled { opacity: 1; background: transparent; color: var(--ink-4); }
.c-compose.c-busy button.c-send { background: var(--ink-3); color: var(--bg); animation: c-busy 1s ease-in-out infinite alternate; }
@keyframes c-busy { to { opacity: 0.45; } }
.c-arrow { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.c-form p.c-signin { margin: 0; }
.doc .c-signin a { display: flex; align-items: center; gap: 10px; min-height: 38px; padding: 0 16px; border-radius: 19px; background: var(--bg-4); color: var(--ink-2); font-size: 14px; font-weight: 500; text-decoration: none; transition: background-color 0.15s, color 0.15s, box-shadow 0.15s; }
.c-thread:not(.c-page) .c-signin a { background: var(--bg-3); box-shadow: inset 0 0 0 1px var(--line); }
.doc .c-signin a:hover, .doc .c-signin a:focus-visible { background: var(--bg-3); color: var(--ink-1); box-shadow: inset 0 0 0 1px var(--line-2); outline: none; }
.c-gh { flex: none; width: 16px; height: 16px; fill: currentColor; }
.c-form .error { font-size: 13.5px; }
.c-empty { margin: 0; color: var(--ink-3); font-size: 13.5px; }

/* Charts (renderer core chart.rs, schema.flecs), drawn at build time. Text keeps the page's size at any width: SVG x
   is in percent, heights in pixels. Marks wear --series-N (tokens.css), text the ink tokens; a line chart's tip is
   client/chart.ts. A row chart is HTML rows over a shared axis: label | track | values | ratio on a card wide enough,
   label and ratio over track and values on a narrow one (a container query, so two cards side by side narrow too). */
.charts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 0 0 16px; }
.chart { margin: 0 0 16px; padding: 16px 16px 10px; border-radius: 12px; background: var(--bg); box-shadow: inset 0 0 0 1px var(--line); min-width: 0; container-type: inline-size; }
.charts > .chart { margin: 0; }
.chart figcaption { display: flex; flex-direction: column; gap: 4px; margin: 0 0 12px; }
.chart .title { color: var(--ink-1); font-size: 14.5px; font-weight: 600; line-height: 1.35; }
.chart .note { margin: 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.45; }
.chart .legend { display: flex; flex-wrap: wrap; gap: 2px 14px; margin: 2px 0 0; padding: 0; list-style: none; color: var(--ink-2); font-size: 12.5px; line-height: 1.5; }
.chart .legend li { margin: 0; padding: 0; white-space: nowrap; }
.chart .legend li::before { content: none; }
.chart .key { display: inline-block; margin-right: 6px; vertical-align: -1px; overflow: visible; }
.chart svg text { font-family: var(--font-sans); font-variant-numeric: tabular-nums; }
.chart .tick { fill: var(--ink-3); font-size: 11px; }
/* A line chart's y labels sit on the plot: a halo in the card's colour keeps them clear of the lines. */
.chart svg.plot .tick { paint-order: stroke; stroke: var(--bg); stroke-width: 3px; stroke-linejoin: round; }
.chart .grid { stroke: var(--line); stroke-width: 1; }
.chart .grid.zero { stroke: var(--line-2); }
.chart .fill.s1, .chart .dot.s1 { fill: var(--series-1); }
.chart .fill.s2, .chart .dot.s2 { fill: var(--series-2); }
.chart .fill.s3, .chart .dot.s3 { fill: var(--series-3); }
.chart .fill.s4, .chart .dot.s4 { fill: var(--series-4); }
.chart .stroke { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart .stroke.s1, .chart .whisker.s1 { stroke: var(--series-1); }
.chart .stroke.s2, .chart .whisker.s2 { stroke: var(--series-2); }
.chart .stroke.s3, .chart .whisker.s3 { stroke: var(--series-3); }
.chart .stroke.s4, .chart .whisker.s4 { stroke: var(--series-4); }
.chart .stroke.dashed { stroke-dasharray: 5 4; }
.chart .band { stroke: none; }
.chart .band.s1 { fill: color-mix(in srgb, var(--series-1) 16%, transparent); }
.chart .band.s2 { fill: color-mix(in srgb, var(--series-2) 16%, transparent); }
.chart .band.s3 { fill: color-mix(in srgb, var(--series-3) 16%, transparent); }
.chart .band.s4 { fill: color-mix(in srgb, var(--series-4) 16%, transparent); }
.chart .whisker { stroke-width: 1.5; opacity: 0.6; }
.chart .dot { stroke: var(--bg); stroke-width: 2; }
.chart .rc-span { stroke: var(--line-2); stroke-width: 2; stroke-linecap: round; }
/* Row charts. A row is as tall as its values, one 17px line each (chart.rs LINE); the track's grid runs on through
   the rows. */
.chart.rows .plot { display: grid; grid-template-columns: minmax(7rem, 13rem) minmax(0, 1fr) max-content; column-gap: 14px; font-size: 13px; font-variant-numeric: tabular-nums; }
.chart.rows.ratios .plot { grid-template-columns: minmax(7rem, 13rem) minmax(0, 1fr) max-content 6.5rem; }
.chart.rows .rc-row { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; align-items: center; margin: 0 -8px; padding: 0 8px; border-radius: 6px; }
.chart.rows .rc-row:not(.rc-axis):hover { background: var(--s-tint); }
.chart.rows .rc-label { grid-column: 1; color: var(--ink-1); line-height: 1.35; }
.chart.rows .rc-track { grid-column: 2; display: block; overflow: visible; }
.chart.rows .rc-vals { grid-column: 3; display: flex; flex-direction: column; color: var(--ink-2); line-height: 17px; white-space: nowrap; }
.chart.rows .rc-vals .key { margin-right: 5px; vertical-align: 0; }
.chart.rows .rc-ratio { grid-column: 4; color: var(--ink-3); font-size: 12.5px; text-align: right; white-space: nowrap; }
.chart.rows .rc-axis .rc-track { margin-top: 2px; }
@container (max-width: 560px) {
	.chart.rows .plot, .chart.rows.ratios .plot { grid-template-columns: minmax(0, 1fr) max-content; column-gap: 12px; }
	.chart.rows .rc-row { padding-top: 6px; }
	.chart.rows .rc-label { grid-column: 1; grid-row: 1; font-size: 12.5px; }
	.chart.rows .rc-ratio { grid-column: 2; grid-row: 1; }
	.chart.rows .rc-track { grid-column: 1; grid-row: 2; }
	.chart.rows .rc-vals { grid-column: 2; grid-row: 2; font-size: 12.5px; }
	.chart.rows .rc-axis { padding-top: 0; }
}
/* A line chart with one run: its values, until a line can be drawn. */
.chart .stats { display: flex; flex-wrap: wrap; gap: 10px 28px; margin: 0 0 10px; }
.chart .stats div { margin: 0; }
.chart .stats dt { color: var(--ink-2); font-size: 12.5px; }
.chart .stats dd { margin: 2px 0 0; color: var(--ink-1); font-size: 22px; font-weight: 500; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.chart .plot.on .guide { visibility: visible; }
.chart .guide { stroke: var(--line-2); stroke-width: 1; visibility: hidden; }
.chart svg.plot { display: block; overflow: visible; }
.chart .numbers { margin: 8px 0 0; }
.chart .numbers summary { display: inline-block; padding: 2px 0; color: var(--ink-3); font-size: 12.5px; cursor: pointer; list-style: none; }
.chart .numbers summary::-webkit-details-marker { display: none; }
.chart .numbers summary::before { content: '\25B8'; display: inline-block; width: 1em; transition: transform 0.15s; }
.chart .numbers[open] summary::before { transform: rotate(90deg); }
.chart .numbers summary:hover { color: var(--ink-1); }
.chart > .note { margin: 8px 0 0; }
.chart .ref { overflow-x: auto; }
.chart .ref table { margin: 6px 0 0; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.chart .ref th, .chart .ref td { white-space: nowrap; }
.chart .ref .num { text-align: right; }
.chart .ref .dim { color: var(--ink-3); }
/* The line chart tooltip (client/chart.ts): the run under the pointer, in ink, each value beside its subject's key. */
.chart-tip { position: fixed; z-index: 60; max-width: 260px; padding: 6px 9px; border-radius: 8px; background: var(--pop-bg); box-shadow: var(--pop-ring), 0 6px 18px rgb(0 0 0 / 0.22); color: var(--ink-1); font-size: 12px; line-height: 1.45; font-variant-numeric: tabular-nums; pointer-events: none; }
.chart-tip[hidden] { display: none; }
.chart-tip b { display: block; font-weight: 600; }
.chart-tip span { display: block; color: var(--ink-2); white-space: nowrap; }
.chart-tip .key { margin-right: 6px; vertical-align: -1px; }

/* Picker (schema.flecs, render.rs): radio buttons over panels, one panel shown, with no JS. Its label leads the row;
   a picker inside another's panel is a step smaller. */
.picks { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 14px; padding: 0; border: 0; min-width: 0; }
.picks .what { min-width: 4.6rem; margin-right: 4px; color: var(--ink-3); font-size: 12.5px; }
.picks label { position: relative; display: inline-flex; }
.picks input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.picks label span { padding: 5px 12px; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--line); color: var(--ink-2); font-size: 14px; line-height: 1.4; transition: background 0.15s, color 0.15s, box-shadow 0.15s; }
.panel .picks label span { padding: 3px 10px; font-size: 13px; }
.picks label:hover span { box-shadow: inset 0 0 0 1px var(--line-2); color: var(--ink-1); }
.picks input:checked + span { background: var(--ink-1); box-shadow: none; color: var(--bg); font-weight: 500; }
.picks input:focus-visible + span { outline: 2px solid var(--ink-2); outline-offset: 2px; }
.picker > .panel { display: none; }
.picker:has(> .picks > label:nth-of-type(1) > input:checked) > .panel:nth-of-type(1) { display: block; }
.picker:has(> .picks > label:nth-of-type(2) > input:checked) > .panel:nth-of-type(2) { display: block; }
.picker:has(> .picks > label:nth-of-type(3) > input:checked) > .panel:nth-of-type(3) { display: block; }
.picker:has(> .picks > label:nth-of-type(4) > input:checked) > .panel:nth-of-type(4) { display: block; }
.picker:has(> .picks > label:nth-of-type(5) > input:checked) > .panel:nth-of-type(5) { display: block; }
.picker:has(> .picks > label:nth-of-type(6) > input:checked) > .panel:nth-of-type(6) { display: block; }
.picker:has(> .picks > label:nth-of-type(7) > input:checked) > .panel:nth-of-type(7) { display: block; }
.picker:has(> .picks > label:nth-of-type(8) > input:checked) > .panel:nth-of-type(8) { display: block; }
.picker:has(> .picks > label:nth-of-type(9) > input:checked) > .panel:nth-of-type(9) { display: block; }
.picker:has(> .picks > label:nth-of-type(10) > input:checked) > .panel:nth-of-type(10) { display: block; }
.picker:has(> .picks > label:nth-of-type(11) > input:checked) > .panel:nth-of-type(11) { display: block; }
.picker:has(> .picks > label:nth-of-type(12) > input:checked) > .panel:nth-of-type(12) { display: block; }
.picker:has(> .picks > label:nth-of-type(13) > input:checked) > .panel:nth-of-type(13) { display: block; }
.picker:has(> .picks > label:nth-of-type(14) > input:checked) > .panel:nth-of-type(14) { display: block; }
.picker:has(> .picks > label:nth-of-type(15) > input:checked) > .panel:nth-of-type(15) { display: block; }
.picker:has(> .picks > label:nth-of-type(16) > input:checked) > .panel:nth-of-type(16) { display: block; }
.bench .dim, .bench p { font-variant-numeric: tabular-nums; }
@media (max-width: 620px) {
	.charts { grid-template-columns: minmax(0, 1fr); }
	.picks .what { flex-basis: 100%; }
	.chart { padding: 12px 12px 6px; }
}

/* Where the page has no left margin for them (client/lib/blockctl.ts sets main.gutter when it has), a block's
   controls float at its top-right corner over the text, still only for the block under the pointer; a block with
   comments keeps its count in the text instead. On a touch screen the controls show for the block last tapped
   (.ctl-open) and nowhere else. */
main:not(.gutter) [data-block] > .c-btn { left: auto; right: 0; top: -0.15em; border-radius: 8px; background: var(--pop-bg); box-shadow: var(--pop-ring), 0 4px 14px rgb(0 0 0 / 0.08); }
main:not(.gutter) [data-block] > .c-btn.has { position: static; margin-left: 0.5em; vertical-align: 0.1em; background: none; box-shadow: none; }
main:not(.gutter) :is(.codeblock, .cmd, .ref) > .c-btn { top: 8px; }
main:not(.gutter) :is(.codeblock, .ref) > .c-btn { right: 8px; }
@media (hover: none) {
	.c-btn:not(.has, [aria-expanded=true]) { visibility: hidden; }
	.ctl-open > .c-btn, img.ctl-open + .c-btn { visibility: visible; opacity: 1; }
}

/* A comment that arrived while the page was open (client/comments.ts refresh). */
.c-item.c-new { animation: c-new 2.4s ease-out; }
@keyframes c-new { from { background: color-mix(in srgb, var(--ok) 14%, transparent); box-shadow: 0 0 0 8px color-mix(in srgb, var(--ok) 14%, transparent); } to { background: transparent; box-shadow: 0 0 0 8px transparent; } }
@media (prefers-reduced-motion: reduce) { .c-item.c-new { animation: none; } }

/* The page shell, after the ix docs (packages/web src/lib/site/side/{SideShell,SideSection,SideRow,PageColumn,
   PageHead}.svelte and routes/docs): a sidebar on the left with its own scroll, the page in a rounded pane beside it,
   "On this page" at the right on a wide screen. Unlike the ix docs the document itself scrolls (the sidebar is
   sticky), so anchors, comment threads, find-in-page and scroll restore behave as on any page. On a phone the sidebar
   is a drawer behind Menu: `#menu` opens it with no JS (`:target`), client/side.ts does the same with a class. */

.icon { width: 16px; height: 16px; flex: none; }
.sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

:root { --side-w: 268px; }
/* What floats over the page (tooltips, the who-is-here list, speech bubbles, the feed): one raised surface. */
:root { --pop-bg: var(--bg-4); --pop-ring: inset 0 0 0 1px var(--line-2); }
.frame { display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); gap: 4px; min-height: 100svh; padding: 6px clamp(8px, 1vw, 14px) 10px 0; }

/* The sidebar. */
.side { position: sticky; top: 0; display: flex; flex-direction: column; height: 100svh; margin-top: -6px; padding: 14px 0 0 clamp(8px, 1vw, 14px); }
.sidetop { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 8px 12px 0; }
.brand { display: block; padding: 2px 6px; border-radius: 8px; line-height: 0; }
.brand:hover { background: var(--s-tint); }
.logo, .logo img { display: block; }
.brand .logo img { width: 92px; height: auto; }
/* The small logo burns only while the pointer is on it (or it has focus): the still first frame until then. */
.logo.anim { display: none; }
@media (prefers-reduced-motion: no-preference) {
	.brand:hover .logo.still, .brand:focus-visible .logo.still, .mbrand:hover .logo.still, .mbrand:focus-visible .logo.still { display: none; }
	.brand:hover .logo.anim, .brand:focus-visible .logo.anim, .mbrand:hover .logo.anim, .mbrand:focus-visible .logo.anim { display: block; }
}
.closebtn { display: none; }
.searchbtn { display: flex; align-items: center; gap: 8px; flex: none; height: 34px; margin: 0 8px 10px 0; padding: 0 8px 0 10px; border: 0; border-radius: 999px; background: var(--s-tint); color: var(--ink-3); font: inherit; font-size: 13.5px; cursor: pointer; transition: background-color 0.15s, color 0.15s; }
.searchbtn[hidden] { display: none; }
.searchbtn:hover { background: color-mix(in srgb, var(--ink-1) 9%, transparent); color: var(--ink-1); }
.searchbtn span { flex: 1; text-align: left; }
.searchbtn kbd { padding: 1px 6px; border-radius: 6px; box-shadow: inset 0 0 0 1px var(--line-2); font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); }

/* Its own scroll, with a fade where the list runs under the footer. */
.scrollbox { position: relative; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-right: 8px; scrollbar-width: none; mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); }
.navlist { position: relative; padding-bottom: 28px; }
.sec + .sec { margin-top: 10px; }
.sec > summary { list-style: none; }
.sec > summary::-webkit-details-marker, .fold > summary::-webkit-details-marker { display: none; }
.sechead { display: flex; align-items: center; gap: 8px; width: 100%; height: 30px; padding: 0 8px; border-radius: 8px; font-size: 12px; font-weight: 500; color: var(--ink-3); cursor: pointer; user-select: none; transition: color 0.12s; }
.sechead:hover { color: var(--ink-1); }
.sechead span { flex: 1; }
.sechead .chev { width: 12px; height: 12px; transition: transform 0.18s; }
/* `.closing`: client/side.ts is still sliding the section shut, so the caret turns at the click, as in ix. */
.sec:not([open]) > .sechead .chev, .sec.closing > .sechead .chev { transform: rotate(-90deg); }

/* ix's glide.ts hover pill (client/side.ts places it): it appears on the first row the pointer touches, slides
   between rows with a small overshoot and fades when the pointer leaves the list. */
.navlist .glide-hov { position: absolute; top: 0; left: 0; z-index: 0; pointer-events: none; background: color-mix(in srgb, var(--ink-1) 3.5%, transparent); transition: transform 0.14s cubic-bezier(0.34, 1.3, 0.5, 1), width 0.14s cubic-bezier(0.34, 1.3, 0.5, 1), height 0.1s, opacity 0.1s; }

.rowwrap { position: relative; }
.row { position: relative; z-index: 1; display: flex; align-items: center; gap: 9px; height: 32px; padding: 0 30px 0 10px; border-radius: 8px; color: var(--ink-2); font-size: 14px; text-decoration: none; transition: color 0.12s, background-color 0.12s; }
.row .icon { color: var(--ink-3); transition: color 0.12s; }
.row .label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row .num { flex: none; font-family: var(--font-mono); font-size: 12px; color: var(--ink-4); }
.row .outmark { width: 12px; height: 12px; margin-left: auto; color: var(--ink-4); }
.row:hover { color: var(--ink-1); }
/* Without JS (or before it runs) the row paints the pill's tint itself. */
.navlist:not([data-glide]) .row:hover { background: color-mix(in srgb, var(--ink-1) 3.5%, transparent); }
.row:hover .icon, .row[aria-current='page'] .icon { color: var(--ink-1); }
.row[aria-current='page'] { color: var(--ink-1); font-weight: 500; background: var(--s-tint); }
.row[aria-current='page'] .num { color: var(--ink-3); }

/* A row's kids (the RFCs under RFCs), folded by the caret at its right edge. */
.fold > .caret { position: absolute; z-index: 2; right: 3px; top: 3px; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 6px; color: var(--ink-3); cursor: pointer; list-style: none; }
.fold > .caret:hover { background: var(--line); color: var(--ink-1); }
.fold > .caret .icon { width: 12px; height: 12px; transition: transform 0.18s; }
.fold:not([open]) > .caret .icon, .fold.closing > .caret .icon { transform: rotate(-90deg); }
.kids { margin: 2px 0 4px 17px; border-left: 1px solid var(--line-2); }
.kids .row { padding-left: 10px; }
.kids .row .icon { display: none; }

.foot { display: flex; align-items: center; gap: 4px; flex: none; padding: 8px 8px 8px 0; border-top: 1px solid var(--line); }
.foot a { display: inline-flex; align-items: center; height: 28px; padding: 0 8px; border-radius: 8px; color: var(--ink-3); font-family: var(--font-mono); font-size: 12px; text-decoration: none; transition: background-color 0.12s, color 0.12s; }
.foot a:hover { background: var(--s-tint); color: var(--ink-1); }

/* The page: a rounded pane, then one reading column (820px at most) with "On this page" beside it. */
.pane { min-width: 0; border-radius: 16px; box-shadow: inset 0 0 0 1px var(--line-2); }
.mbar, .scrim { display: none; }
.grid { display: grid; grid-template-columns: minmax(0, 1fr) 216px; gap: clamp(24px, 3vw, 56px); max-width: 1240px; margin-inline: auto; padding: 0 clamp(20px, 3.5vw, 48px); }
.grid.wide { grid-template-columns: minmax(0, 1fr); max-width: 1180px; }
main { min-width: 0; width: 100%; max-width: 820px; margin-inline: auto; padding-bottom: 72px; }
main.narrow { max-width: 560px; }
main.wide { max-width: none; }

/* The header: where the page sits, the title, the RFC line, the player (PageHead.svelte). */
.head { padding: 40px 0 28px; }
.crumb { display: flex; align-items: center; gap: 7px; min-height: 30px; margin: 0 0 14px; font-size: 13px; color: var(--ink-3); }
.crumb a { display: inline-flex; align-items: center; gap: 7px; color: inherit; text-decoration: none; }
.doc .crumb a:hover { color: var(--ink-1); }
.crumb span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.head h1 { margin: 0; font-size: clamp(30px, 3.4vw, 38px); line-height: 1.12; font-weight: 600; letter-spacing: -0.03em; color: var(--ink-1); overflow-wrap: anywhere; }
.head + .lede, .head + p.lede { margin-top: 0; }

/* The home page: the logo, large, then the lede in the reading colour. */
.hero { padding: 56px 0 8px; }
.hero-logo { margin: 0 0 8px; line-height: 0; }
.hero-logo .logo img { width: min(100%, 344px); height: auto; margin: 0 0 0 -8px; border-radius: 0; box-shadow: none; background: none; }
.hero ~ .lede { max-width: 34em; font-size: clamp(19px, 2.1vw, 22px); line-height: 1.45; color: var(--ink-1); letter-spacing: -0.015em; }

/* A goal: a row with its title and one line, folded; open, its few paragraphs. */
.goal { border-top: 1px solid var(--line); }
.goal:last-of-type { border-bottom: 1px solid var(--line); }
.goal > summary { display: flex; align-items: center; gap: 16px; padding: 16px 2px; list-style: none; cursor: pointer; }
.goal > summary::-webkit-details-marker { display: none; }
.goal-head { flex: 1; min-width: 0; }
.doc .goal h3 { margin: 0; font-size: 17px; }
.goal-line { display: block; margin-top: 2px; font-size: 15px; color: var(--ink-3); }
.goal > summary:hover .goal-line { color: var(--ink-2); }
.goal .chev { width: 14px; height: 14px; flex: none; color: var(--ink-3); transform: rotate(-90deg); transition: transform 0.18s; }
.goal[open] .chev { transform: none; }
.goal-body { max-width: 36em; padding: 0 2px 8px; }
.goal-body p { font-size: 15px; line-height: 1.65; }
@media (prefers-reduced-motion: reduce) { .goal .chev { transition: none; } }
.status::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 6px; border-radius: 50%; background: currentColor; vertical-align: 0.1em; }

/* On this page. */
.toc { position: sticky; top: 28px; align-self: start; max-height: calc(100svh - 56px); overflow-y: auto; overscroll-behavior: contain; padding: 108px 0 24px; font-size: 13px; scrollbar-width: thin; }
.toc p { margin: 0 0 8px; font-size: 12px; font-weight: 500; color: var(--ink-3); }
.toc ul { margin: 0; padding: 0; list-style: none; border-left: 1px solid var(--line); }
.toc a { display: block; margin-left: -1px; padding: 4px 12px; border-left: 1px solid transparent; color: var(--ink-3); line-height: 1.35; text-decoration: none; transition: color 0.12s, border-color 0.12s; }
.toc a:hover { color: var(--ink-1); }
.toc a.cur { color: var(--ink-1); border-left-color: var(--ink-1); }

/* Previous and Next. */
.pager { display: flex; justify-content: space-between; gap: 12px; margin-top: 56px; padding-top: 20px; border-top: 1px solid var(--line); }
.doc .pager a { display: grid; gap: 4px; min-width: 0; max-width: 48%; padding: 10px 16px; border-radius: 12px; box-shadow: inset 0 0 0 1px var(--line-2); color: var(--ink-1); text-decoration: none; transition: background-color 0.15s; }
.doc .pager a:hover { background: var(--s-tint); }
.pager .next { margin-left: auto; text-align: right; }
.pager .dir { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--ink-3); }
.pager .next .dir { justify-content: flex-end; }
.pager .dir .icon { width: 13px; height: 13px; }
.pager .name { display: inline-flex; align-items: center; gap: 7px; min-width: 0; font-size: 15px; }
.pager .name .icon { color: var(--ink-3); }
.pager .name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pager .next .name { justify-content: flex-end; }

/* Search (client/side.ts): a dialog over the page. */
.search { width: min(640px, calc(100vw - 24px)); max-height: min(70vh, 560px); margin: 12vh auto auto; padding: 0; border: 0; border-radius: 14px; background: var(--bg-3); color: var(--ink-2); box-shadow: 0 0 0 1px var(--line-2), 0 30px 70px -20px rgb(0 0 0 / 0.5); overflow: hidden; }
.search::backdrop { background: rgb(0 0 0 / 0.4); }
.search form { display: flex; align-items: center; gap: 10px; padding: 0 14px; border-bottom: 1px solid var(--line); }
.search form .icon { color: var(--ink-3); }
.search input { flex: 1; padding: 14px 0; border: 0; border-radius: 0; background: none; box-shadow: none; font-size: 16px; }
.search input:focus { box-shadow: none; }
.search ul { max-height: calc(min(70vh, 560px) - 56px); margin: 0; padding: 6px; overflow-y: auto; overscroll-behavior: contain; list-style: none; }
.search li a { display: block; padding: 8px 10px; border-radius: 8px; color: var(--ink-2); text-decoration: none; }
.search li a .t { display: block; color: var(--ink-1); font-size: 14px; font-weight: 500; }
.search li a .p { display: block; font-size: 13px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search li a:hover, .search li a[aria-selected='true'] { background: var(--s-tint); }
.search .none { padding: 14px; font-size: 14px; color: var(--ink-3); }

@media (max-width: 1200px) {
	.grid { grid-template-columns: minmax(0, 1fr); }
	.toc { display: none; }
}

/* A phone: the sidebar is a drawer behind Menu. */
@media (max-width: 800px) {
	.frame { grid-template-columns: minmax(0, 1fr); padding: 0 8px 8px; }
	.side { position: fixed; z-index: 40; top: 0; bottom: 0; left: 0; width: min(86vw, 320px); height: auto; margin: 0; padding: 12px 4px 0 12px; background: var(--bg); box-shadow: 0 0 0 1px var(--line-2), 0 20px 60px rgb(0 0 0 / 0.3); transform: translateX(-102%); visibility: hidden; transition: transform 0.24s cubic-bezier(0.2, 0.7, 0.3, 1), visibility 0s 0.24s; }
	.side:target, .side.open { transform: none; visibility: visible; transition-delay: 0s; }
	.side:target ~ .scrim, .side.open ~ .scrim { display: block; position: fixed; z-index: 30; inset: 0; background: rgb(0 0 0 / 0.4); }
	.closebtn { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 8px; color: var(--ink-3); }
	.closebtn:hover { background: var(--s-tint); color: var(--ink-1); }
	.pane { box-shadow: none; }
	.mbar { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 10px; margin: 0 -8px; padding: 8px 12px; background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--line); }
	.menubtn { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px; border: 0; border-radius: 8px; box-shadow: inset 0 0 0 1px var(--line-2); background: none; color: var(--ink-1); font: inherit; font-size: 13.5px; text-decoration: none; cursor: pointer; }
	.menubtn[hidden] { display: none; }
	.mbrand { flex: 1; line-height: 0; }
	.mbrand .logo img { width: 60px; height: auto; }
	.grid { padding: 0 12px; }
	.head { padding-top: 24px; }
	.hero { padding-top: 28px; }
	.pager { flex-direction: column; }
	.doc .pager a { max-width: none; }
	.pager .next { margin-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
	.side, .sechead .chev, .fold > .caret .icon, .navlist .glide-hov { transition: none; }
}

/* Moving between pages. The client router (client/nav.ts) swaps the page column without a load, inside a
   same-document view transition: the sidebar and the phone bar are their own layers and stay put, and only the page
   column cross-fades, quickly. The few navigations it leaves to the browser (a fallback) are
   the same cross-fade as a cross-document view transition (Chrome and Edge 126+, Safari 18.2+; elsewhere a plain
   load). Neither runs under prefers-reduced-motion (nav.ts skips its transition). */
@view-transition { navigation: auto; }
.side { view-transition-name: side; }
.mbar { view-transition-name: mbar; }
::view-transition-group(side), ::view-transition-group(mbar),
::view-transition-new(side), ::view-transition-new(mbar) { animation: none; }
::view-transition-old(side), ::view-transition-old(mbar) { display: none; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 120ms; }
@media (prefers-reduced-motion: reduce) {
	@view-transition { navigation: none; }
}
/* The router moves focus to the new page's title for screen readers; it is not a control, so no ring. A slow fetch
   shows the progress cursor. */
main h1[tabindex="-1"]:focus { outline: none; }
html.nav-wait, html.nav-wait * { cursor: progress; }

/* Who is here (client/lib/presence.ts): the pane's top line (on a phone, inside the phone bar), its list of everyone,
   and faces on the sidebar's rows. */
.topline { position: sticky; top: 0; z-index: 15; display: flex; align-items: center; gap: 8px; min-height: 48px; margin: 1px 1px 0; padding: 8px clamp(12px, 2vw, 20px); border-radius: 15px 15px 0 0; background: color-mix(in srgb, var(--bg) 82%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
.topline > span { display: contents; }
.tl-btn { display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 10px; border: 0; border-radius: 8px; box-shadow: inset 0 0 0 1px var(--line-2); background: none; color: var(--ink-2); font: inherit; font-size: 13px; text-decoration: none; white-space: nowrap; cursor: pointer; transition: color 0.12s, background-color 0.12s; }
.tl-btn:hover, .tl-btn[aria-expanded='true'] { color: var(--ink-1); background: var(--s-tint); }
.tl-btn svg { width: 14px; height: 14px; fill: currentColor; }
.tl-chat { color: var(--ink-1); }
/* The sidebar shut (client/lib/presence.ts): its column folds to nothing, the page takes the room. */
.tl-side { width: 30px; padding: 0; justify-content: center; }
.tl-side svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.4; }
.tl-side[aria-pressed='true'] svg path { stroke-dasharray: 2 1.6; }
.frame { transition: grid-template-columns 0.22s cubic-bezier(0.2, 0.7, 0.3, 1); }
body.side-shut .frame { grid-template-columns: 0 minmax(0, 1fr); padding-left: clamp(8px, 1vw, 14px); gap: 0; }
body.side-shut .frame > .side { visibility: hidden; overflow: hidden; padding: 0; }
@media (prefers-reduced-motion: reduce) { .frame { transition: none; } }
/* Chat at the left, everything else at the right. */
.topline > .tl-gap { display: block; flex: 1; }
.tl-bubble { flex: none; width: 14px; height: 12px; border: 1.5px solid currentColor; border-radius: 4px 4px 4px 1px; }
.tl-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 20%, transparent); }
.tl-count { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tl-user { padding-left: 4px; color: var(--ink-1); }
.tl-user .face { width: 22px; height: 22px; }
.tl-quiet { box-shadow: none; color: var(--ink-3); }
.tl-out { display: contents; }
.tl-signin { color: var(--ink-1); }
.tl-list { position: absolute; top: calc(100% + 2px); right: clamp(12px, 2vw, 20px); width: min(360px, calc(100vw - 24px)); max-height: min(60vh, 480px); overflow: auto; overscroll-behavior: contain; padding: 10px; border-radius: 12px; background: var(--pop-bg); box-shadow: var(--pop-ring), 0 16px 40px rgb(0 0 0 / 0.25); font-size: 13px; }
.tl-list[hidden] { display: none; }
.tl-list ul { margin: 0; padding: 0; list-style: none; }
.tl-list li { display: flex; align-items: center; gap: 10px; padding: 7px 6px; border-radius: 8px; }
.tl-list li:not(.tl-sub):hover { background: var(--s-tint); }
.tl-list li.away { opacity: 0.6; }
.tl-list li.tl-sub { margin-top: 6px; padding: 4px 6px 2px; color: var(--ink-4); font-size: 11px; letter-spacing: 0.02em; text-transform: uppercase; }
.tl-body { display: grid; flex: 1; min-width: 0; line-height: 1.3; }
.tl-name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.tl-list .who { overflow: hidden; color: var(--ink-1); font-weight: 500; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; }
.tl-list a.who:hover { text-decoration: underline; }
.tl-list .flag { font-size: 13px; line-height: 1; cursor: default; }
.tl-list .tag { padding: 0 5px; border-radius: 5px; background: var(--s-tint); color: var(--ink-3); font-size: 10.5px; line-height: 16px; }
.tl-meta { display: flex; align-items: center; gap: 6px; min-width: 0; color: var(--ink-4); font-size: 12px; white-space: nowrap; }
.tl-meta > * + *::before { content: '·'; margin-right: 6px; color: var(--ink-4); }
.tl-meta > .more::before { content: none; }
.tl-meta .where { overflow: hidden; color: var(--ink-3); text-decoration: none; text-overflow: ellipsis; }
.tl-meta .where:hover { color: var(--ink-1); }
.tl-head { margin: 0 4px 6px; color: var(--ink-3); }
.tl-list li.tl-head { border: 0; }
.tl-list p.tl-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tl-list .cursors-toggle { height: 24px; padding: 0 8px; font-size: 12px; }
.tl-list .face, .tl-list .flag, .tl-list .tag { flex: none; }
.tl-av { position: relative; flex: none; display: inline-grid; }
.tl-av .face { width: 28px; height: 28px; }
.tl-av .dot { position: absolute; right: -2px; bottom: -2px; width: 9px; height: 9px; border-radius: 50%; background: var(--pop-bg); box-shadow: inset 0 0 0 1.5px var(--ink-4), 0 0 0 2px var(--pop-bg); }
.tl-av .dot.on { background: var(--ok); box-shadow: 0 0 0 2px var(--pop-bg); }
.tl-list .more { margin-left: -2px; color: var(--ink-4); cursor: default; }
.tl-list .for { flex: none; font-variant-numeric: tabular-nums; }
.faces { display: inline-flex; align-items: center; }
.faces .face + .face { margin-left: -6px; }
.face { display: inline-grid; place-items: center; flex: none; width: 20px; height: 20px; overflow: hidden; border-radius: 50%; background: var(--bg-4); box-shadow: 0 0 0 2px var(--bg); transition: opacity 0.2s; }
.face img, .face svg { width: 100%; height: 100%; }
/* An anonymous reader's animal (gen/animals.ts, drawn from dist/animals.<hash>.svg): its tone slots from their hue `--h`. */
.face.animal { --a-bg: hsl(var(--h) 30% 25%); --a1: hsl(var(--h) 55% 62%); --a2: hsl(var(--h) 40% 39%); --a3: hsl(var(--h) 75% 88%); --a-ink: hsl(var(--h) 45% 11%); background: var(--a-bg); }
@media (prefers-color-scheme: light) {
	.face.animal { --a-bg: hsl(var(--h) 55% 82%); --a1: hsl(var(--h) 50% 57%); --a2: hsl(var(--h) 42% 34%); --a3: hsl(var(--h) 70% 97%); --a-ink: hsl(var(--h) 45% 14%); }
}
/* A bot's robot (client/lib/presence.ts): steel, with lit eyes, the same for every bot. */
.face.animal.bot { --a-bg: hsl(215 14% 22%); --a1: hsl(212 10% 63%); --a2: hsl(215 16% 30%); --a3: hsl(188 85% 70%); --a-ink: hsl(215 25% 10%); }
@media (prefers-color-scheme: light) {
	.face.animal.bot { --a-bg: hsl(212 18% 85%); --a1: hsl(212 9% 56%); --a2: hsl(215 18% 27%); --a3: hsl(186 90% 72%); --a-ink: hsl(215 25% 12%); }
}
.face.away { opacity: 0.45; }
.face.more { width: auto; min-width: 20px; padding: 0 4px; border-radius: 10px; color: var(--ink-3); font-size: 10.5px; }
.navlist .row > .faces { margin-left: auto; }
.navlist .row > .faces .face { width: 16px; height: 16px; box-shadow: 0 0 0 1.5px var(--bg); }
/* A phone: the line's buttons sit in the phone bar between the logo and search, icons and numbers only. */
@media (max-width: 800px) {
	.mbar .topline { position: relative; top: auto; z-index: auto; flex: none; min-height: 0; margin: 0; padding: 0; gap: 6px; background: none; backdrop-filter: none; -webkit-backdrop-filter: none; border-radius: 0; }
	.mbar .tl-btn { height: 32px; padding: 0 9px; }
	.mbar .tl-label, .mbar .tl-count, .mbar .tl-quiet, .mbar .tl-user > span:last-child { display: none; }
	.mbar .tl-side { display: none; } /* The sidebar is the menu's drawer here. */
	.mbar .tl-here .faces .face:nth-child(n + 3) { display: none; }
	.mbar .tl-list { position: fixed; top: 52px; right: 8px; }
}
/* A phone's width: the menu button is its icon, Chat goes (the feed's own button opens it there), so the bar fits. */
@media (max-width: 480px) {
	.mbar { gap: 6px; padding-inline: 8px; }
	.mbar > .menubtn { padding: 0 9px; }
	.mbar > .menubtn > span { display: none; }
	.mbar .mbrand { min-width: 0; }
	.mbar .tl-chat, .mbar .tl-gap { display: none; }
}

.tl-list .devices { display: inline-flex; gap: 2px; color: var(--ink-4); }
.tl-list .device { display: inline-grid; width: 13px; height: 13px; }
.tl-list .device svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; }

/* The chat's input, at the foot of the open feed (client/lib/chat.ts): one rounded field, the mention pop-up above it,
   who is writing above that. Comment forms take the same field (styles/site.css). */
.chat-compose { position: relative; }
.chat-pop { position: absolute; z-index: 3; left: 0; right: 0; bottom: 100%; margin: 0 0 6px; padding: 4px; list-style: none; border-radius: 12px; background: var(--bg-3); box-shadow: inset 0 0 0 1px var(--line-2), 0 12px 32px rgb(0 0 0 / 0.3); }
.chat-pop[hidden] { display: none; }
.chat-pop li { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 8px; color: var(--ink-2); font-size: 13px; cursor: pointer; }
.chat-pop li.on { background: var(--s-tint); color: var(--ink-1); }
.chat-pop .face { width: 18px; height: 18px; box-shadow: none; }
.chat-form { display: flex; align-items: flex-end; gap: 6px; padding: 5px 5px 5px 14px; border-radius: 18px; background: var(--bg-4); box-shadow: inset 0 0 0 1px transparent; transition: box-shadow 0.15s, background-color 0.15s; }
.chat-form:focus-within { background: var(--bg-3); box-shadow: inset 0 0 0 1px var(--line-2), 0 0 0 3px var(--s-tint); }
.chat-form textarea::placeholder { color: var(--ink-4); }
.chat-form textarea, .chat-form textarea:focus { flex: 1; width: auto; min-height: 26px; max-height: 140px; padding: 4px 0; border: 0; border-radius: 0; box-shadow: none; background: none; color: var(--ink-1); font: inherit; font-size: 13.5px; line-height: 1.35; resize: none; outline: none; }
.chat-send { display: grid; place-items: center; flex: none; width: 28px; height: 28px; padding: 0; border: 0; border-radius: 50%; background: var(--ink-1); color: var(--bg); cursor: pointer; transition: opacity 0.12s, background-color 0.12s; }
.chat-send svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.chat-send:disabled { background: transparent; color: var(--ink-4); cursor: default; }
.chat-typing { display: flex; align-items: center; gap: 7px; min-height: 22px; padding: 0 6px 6px; color: var(--ink-3); font-size: 12px; }
.chat-typing[hidden] { display: none; }
.chat-typing-faces { display: inline-flex; }
.chat-typing-faces .face { width: 18px; height: 18px; }
.chat-typing-faces .face + .face { margin-left: -5px; }
.dots { display: inline-flex; gap: 3px; align-items: center; }
.dots i { width: 4px; height: 4px; border-radius: 50%; background: currentColor; animation: dot 1.2s ease-in-out infinite; }
.dots i:nth-child(2) { animation-delay: 0.15s; }
.dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes dot { 0%, 60%, 100% { opacity: 0.3; transform: none; } 30% { opacity: 1; transform: translateY(-2px); } }
/* Links and `@login`s in a chat line: a mention marked, the reader's own stronger. */
.feed-text a { color: var(--ink-1); }
.feed-text .chat-at { padding: 0 2px; border-radius: 4px; background: var(--s-tint); color: var(--ink-1); font-weight: 500; text-decoration: none; }
.feed-text .chat-at:hover { text-decoration: underline; }
.feed-text .chat-at.me { background: color-mix(in srgb, var(--doc-code-ink) 20%, transparent); }

/* The feed (client/lib/feed.ts), like Minecraft's chat: passing lines at the bottom left of the page (chat, joins,
   leaves, the site's word), each on a small raised strip that fades; opened (T, or the phone's button), the history
   scrolls over the input on one surface. Clear of the sidebar. */
.feed { --feed-l: calc(var(--side-w) + 4px + 16px); position: fixed; z-index: 44; left: var(--feed-l); bottom: 16px; display: flex; flex-direction: column; align-items: flex-start; width: min(460px, calc(100vw - var(--feed-l) - 32px)); pointer-events: none; }
body.side-shut .feed { --feed-l: calc(clamp(8px, 1vw, 14px) + 16px); }
.feed-log { width: 100%; max-height: min(50vh, 420px); overflow: hidden; overscroll-behavior: contain; }
.feed-line { display: none; align-items: flex-start; gap: 8px; width: fit-content; max-width: 100%; margin-top: 4px; padding: 5px 10px 5px 6px; border-radius: 10px; background: color-mix(in srgb, var(--pop-bg) 88%, transparent); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: var(--pop-ring), 0 6px 18px rgb(0 0 0 / 0.16); color: var(--ink-2); font-size: 13px; line-height: 1.4; text-decoration: none; }
.feed-line.fresh { display: flex; pointer-events: auto; animation: feed-in 0.18s ease-out; }
.feed-line.fading { opacity: 0; transition: opacity 0.6s; }
@keyframes feed-in { from { opacity: 0; transform: translateY(6px); } }
.feed-line > .face { width: 18px; height: 18px; margin-top: 1px; box-shadow: none; }
.feed-line > svg { flex: none; width: 18px; height: 18px; margin-top: 1px; fill: none; stroke: var(--ink-2); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.feed-words { min-width: 0; overflow-wrap: anywhere; }
.feed:not(.open) .feed-words { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.feed-words b { color: var(--ink-1); font-weight: 500; }
.feed-note { color: var(--ink-4); font-size: 11.5px; }
.feed-join, .feed-leave { color: var(--ink-3); }
.feed-join b, .feed-leave b { color: var(--ink-2); }
.feed-leave > .face { opacity: 0.55; }
.feed-error > svg { stroke: var(--danger); }
.feed-error b { color: var(--danger); }
.feed-line.go, .feed:not(.open) .feed-line.jump { cursor: pointer; }
.feed-line.go:hover, .feed-line.go:focus-visible, .feed:not(.open) .feed-line.jump:hover { background: var(--bg-3); outline: none; }
.feed-line.mention { box-shadow: inset 2px 0 0 var(--doc-code-ink), var(--pop-ring), 0 6px 18px rgb(0 0 0 / 0.16); }
.feed-act { flex: none; align-self: center; margin-left: 4px; padding: 3px 10px; border: 0; border-radius: 10px; background: var(--ink-1); color: var(--bg); font: inherit; font-size: 12px; cursor: pointer; }
/* Open: every line of the history on one surface, scrollable, the input at the foot. */
.feed.open { pointer-events: auto; padding: 6px; border-radius: 16px; background: color-mix(in srgb, var(--bg-2) 94%, transparent); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); box-shadow: inset 0 0 0 1px var(--line-2), 0 20px 50px rgb(0 0 0 / 0.3); }
.feed.open .feed-log { overflow-y: auto; }
.feed.open .feed-line { display: flex; width: 100%; margin-top: 0; padding: 4px 8px 4px 6px; border-radius: 8px; background: none; backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: none; opacity: 1; animation: none; }
.feed.open .feed-line.mention { background: color-mix(in srgb, var(--doc-code-ink) 8%, transparent); box-shadow: inset 2px 0 0 var(--doc-code-ink); }
.feed.open .feed-line.go:hover { background: var(--s-tint); }
/* The message being edited in the input below. */
.feed.open .feed-line.editing { background: var(--s-tint); box-shadow: inset 2px 0 0 var(--ink-3); }
/* A line's tools (the reader's own message: Edit, Delete; a Translate), in the open history only, on hover. */
.feed-tools { display: none; flex: none; align-self: center; gap: 2px; margin-left: auto; padding-left: 6px; }
.feed.open .feed-line:hover > .feed-tools, .feed.open .feed-tools:focus-within { display: flex; }
@media (hover: none) { .feed.open .feed-tools { display: flex; } }
.feed-tool { display: grid; place-items: center; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 6px; background: none; color: var(--ink-3); cursor: pointer; }
.feed-tool.word { width: auto; padding: 0 6px; font: inherit; font-size: 12px; }
.feed-tool:hover { background: var(--s-tint); color: var(--ink-1); }
.feed-tool svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.feed-foot { width: 100%; margin-top: 6px; }
.feed:not(.open) .feed-foot { display: none; }
.feed-hint { margin: 6px 6px 2px; color: var(--ink-4); font-size: 11.5px; }
.feed-hint button, .feed-hint a { padding: 0; border: 0; background: none; color: var(--ink-2); font: inherit; text-decoration: none; cursor: pointer; }
.feed-hint button:hover, .feed-hint a:hover { color: var(--ink-1); text-decoration: underline; }
.feed-opener { display: none; }
@media (hover: none) {
	.feed-opener { display: grid; place-items: center; width: 40px; height: 40px; margin-top: 6px; padding: 0; border: 0; border-radius: 50%; background: var(--pop-bg); box-shadow: var(--pop-ring), 0 6px 18px rgb(0 0 0 / 0.2); color: var(--ink-2); pointer-events: auto; cursor: pointer; }
	.feed-opener svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
	.feed.open .feed-opener { display: none; }
}
/* A phone: across the screen with 16px gutters, over the home indicator. */
@media (max-width: 800px) {
	.feed { --feed-l: 16px; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom)); width: auto; }
	body.side-shut .feed { --feed-l: 16px; }
	.feed-log { max-height: 45svh; }
}
/* The line the history opened at (a passing line clicked), lit for a moment. */
.feed.open .feed-line.lit { animation: feed-lit 1.6s ease-out; }
@keyframes feed-lit { from { background: color-mix(in srgb, var(--doc-code-ink) 16%, transparent); } }
@media (prefers-reduced-motion: reduce) { .feed-line.fresh, .feed.open .feed-line.lit { animation: none; } .feed-line.fading { transition: none; } }

/* The drag handle (client/lib/resize.ts) on the sidebar's right edge. */
.resizer { position: absolute; z-index: 5; top: 0; bottom: 0; width: 9px; cursor: col-resize; touch-action: none; }
.side > .resizer { right: -6px; }
.resizer::after { content: ''; position: absolute; top: 50%; left: 3px; width: 3px; height: 36px; margin-top: -18px; border-radius: 2px; background: var(--line-2); opacity: 0; transition: opacity 0.15s; }
.resizer:hover::after, .resizer:focus-visible::after, .resizing .resizer::after { opacity: 1; }
.resizer:focus-visible { outline: none; }
.resizing, .resizing * { cursor: col-resize !important; user-select: none; }
@media (max-width: 800px) { .resizer { display: none; } }

/* What someone just said in the chat, out of their face in the sidebar (client/lib/presence.ts), for a few seconds. */
/* The site's tooltips (client/lib/tip.ts). */
/* The same raised surface as the speech bubbles and the feed, so they follow the theme. */
.tip { position: fixed; z-index: 60; max-width: 280px; padding: 4px 8px; border-radius: 7px; background: var(--pop-bg); box-shadow: var(--pop-ring), 0 6px 18px rgb(0 0 0 / 0.22); color: var(--ink-1); font-size: 12px; line-height: 1.35; pointer-events: none; animation: tip-in 0.1s ease-out; }
.tip[hidden] { display: none; }
@keyframes tip-in { from { opacity: 0; transform: translateY(2px); } }
.tip.below { animation-name: tip-in-below; }
@keyframes tip-in-below { from { opacity: 0; transform: translateY(-2px); } }
.say-bubble { position: fixed; z-index: 45; max-width: 240px; padding: 7px 10px; border-radius: 12px 12px 12px 4px; background: var(--pop-bg); box-shadow: var(--pop-ring), 0 8px 24px rgb(0 0 0 / 0.25); color: var(--ink-1); font-size: 12.5px; line-height: 1.35; pointer-events: none; animation: say-in 0.18s ease-out; }
.say-bubble b { display: block; margin-bottom: 1px; color: var(--ink-3); font-size: 11px; font-weight: 500; }
.say-bubble span { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.say-bubble.out { opacity: 0; transform: translateY(-4px); transition: opacity 0.3s, transform 0.3s; }
@keyframes say-in { from { opacity: 0; transform: scale(0.9) translateX(-6px); } }
.face.talking { box-shadow: 0 0 0 2px var(--bg), 0 0 0 3.5px var(--ok); }
.say-bubble.typing { padding: 9px 11px; color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) { .say-bubble, .dots i { animation: none; } }

/* The others on this page (client/lib/cursors.ts). Their pointers: an arrow in their colour (--c) and a chip with
   their face and name. One in the article is in a box over the whole document, so it scrolls with the page, below
   the sticky top line and the drawer; one on the sidebar, the top line or "On this page" is in a
   box over the window, above them, since they stay put as the page scrolls. Never in the way of a click. A pointer
   that rests fades. */
.cursors { position: absolute; top: 0; left: 0; z-index: 14; width: 100%; overflow: clip; pointer-events: none; }
.cursors-fixed { position: fixed; z-index: 36; inset: 0; width: auto; }
.cursor { position: absolute; top: 0; left: 0; display: flex; align-items: flex-start; transition: opacity 0.4s; will-change: transform; }
.cursor.idle { opacity: 0; transition-duration: 1s; }
.cursor svg { width: 16px; height: 20px; flex: none; fill: var(--c); stroke: var(--bg); stroke-width: 1.2; stroke-linejoin: round; filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.3)); }
/* A press: a ring from the pointer's tip, in their colour, gone in half a second. */
.cursor-click { position: absolute; top: 1.5px; left: 1.5px; width: 26px; height: 26px; margin: -13px 0 0 -13px; border-radius: 50%; box-shadow: inset 0 0 0 2px var(--c); pointer-events: none; animation: cursor-click 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
@keyframes cursor-click { from { opacity: 0.9; transform: scale(0.25); } to { opacity: 0; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .cursor-click { animation: cursor-click-still 0.4s steps(1) forwards; transform: scale(0.6); } @keyframes cursor-click-still { to { opacity: 0; } } }
.cursor-chip { display: inline-flex; align-items: center; gap: 4px; margin: 14px 0 0 -4px; padding: 2px 7px 2px 2px; border-radius: 10px; background: var(--c); color: #fff; font-size: 11px; font-weight: 500; line-height: 16px; white-space: nowrap; box-shadow: 0 2px 8px rgb(0 0 0 / 0.2); }
.cursor-chip .face { width: 16px; height: 16px; box-shadow: none; }
/* What someone types in the feed's input (T; client/lib/cursors.ts), in their colour (--c): a bubble under their name,
   or out of their face on the rail while their pointer is off this screen. A caret blinks while they write; a sent one
   stays where it was and fades after a while. */
.tl-hint kbd { padding: 0 5px; border-radius: 5px; box-shadow: inset 0 0 0 1px var(--line-2); font-family: var(--font-mono); font-size: 11px; line-height: 17px; color: var(--ink-3); }
.cursor-say { position: absolute; top: 38px; left: 12px; width: max-content; max-width: 260px; padding: 5px 10px; border-radius: 4px 12px 12px 12px; background: var(--pop-bg); box-shadow: var(--pop-ring), inset 0 0 0 1.5px var(--c), 0 8px 24px rgb(0 0 0 / 0.25); color: var(--ink-1); font-size: 12.5px; line-height: 1.35; white-space: normal; overflow-wrap: anywhere; pointer-events: none; animation: say-live-in 0.15s ease-out; transition: opacity 0.3s; }
.cursor-say.pinned { animation: none; }
.cursor-say.flip { left: 8px; transform: translateX(-100%); border-radius: 12px 4px 12px 12px; }
.cursor-say.on-rail { top: -4px; left: auto; right: 30px; border-radius: 12px 4px 12px 12px; }
.cursor-say.live::after { content: ""; display: inline-block; width: 1.5px; height: 1.05em; margin-left: 1px; vertical-align: -2px; background: var(--c); animation: say-caret 1s steps(1) infinite; }
.cursor-say.out { opacity: 0; }
@keyframes say-live-in { from { opacity: 0; } }
@keyframes say-caret { 50% { opacity: 0; } }
.tl-list .tl-hint { margin: 8px 4px 0; padding-top: 8px; border-top: 1px solid var(--line); color: var(--ink-3); font-size: 12px; }
@media (prefers-reduced-motion: reduce) { .cursor-say, .cursor-say.live::after { animation: none; transition: none; } }
/* Where each is reading: a thin rail at the right edge, the page's length top to bottom, a band in their colour for
   each viewport with their face on it (a button: it scrolls there), and a faint band for the reader's own. Above the
   sticky top line (a scrollbar runs the window's height), under the drawer and pop-ups. */
.reading { position: fixed; z-index: 16; top: 6px; right: 0; bottom: 10px; width: 6px; pointer-events: none; user-select: none; -webkit-user-select: none; }
.reading[hidden] { display: none; }
.reading-others, .reading-track { position: absolute; inset: 0; }
.reading-me, .reading-band { position: absolute; right: 1px; width: 4px; min-height: 4px; border-radius: 2px; }
.reading-me { background: color-mix(in srgb, var(--ink-1) 10%, transparent); }
.reading-band { background: color-mix(in srgb, var(--c) 55%, transparent); }
.reading-face { position: absolute; z-index: 1; top: 0; right: 6px; display: grid; padding: 0; border: 0; border-radius: 50%; background: none; cursor: pointer; pointer-events: auto; }
.reading-face .face { width: 18px; height: 18px; box-shadow: 0 0 0 2px var(--c); }
.reading-face:hover .face { opacity: 1; transform: scale(1.15); }
/* On a desk the rail is the page's scrollbar (client/lib/cursors.ts, the same media query), so the browser's goes:
   one scrollbar. A wider track to aim at; the thumb dims while the page
   rests and brightens as it scrolls, under the pointer and while dragged. Inner scroll areas keep their own. */
@media (hover: hover) and (pointer: fine) {
	html { scrollbar-width: none; }
	html::-webkit-scrollbar { display: none; }
	.reading.bar { width: 12px; pointer-events: auto; }
	.reading.bar :is(.reading-me, .reading-band) { right: 3px; width: 5px; border-radius: 3px; transition: width 0.15s, right 0.15s, background-color 0.3s; }
	.reading.bar .reading-me { background: color-mix(in srgb, var(--ink-1) 12%, transparent); }
	.reading.bar.live .reading-me { background: color-mix(in srgb, var(--ink-1) 28%, transparent); transition-duration: 0.15s, 0.15s, 0.1s; }
	.reading.bar:hover .reading-me { background: color-mix(in srgb, var(--ink-1) 36%, transparent); }
	.reading.bar.drag .reading-me { background: color-mix(in srgb, var(--ink-1) 46%, transparent); }
	.reading.bar:is(:hover, .drag) :is(.reading-me, .reading-band) { right: 2px; width: 8px; border-radius: 4px; }
}
@media (prefers-reduced-motion: reduce) { .reading-me, .reading-band { transition: none !important; } }

/* The goals' drawings (Art in content/schema.flecs, drawn by client/art.ts): a band of pixel cells in the page's own
   inks, on the page's background. art.ts reads these tokens, so a theme change only touches them. The one accent is
   the fire logo's orange (docs/brand/fire/gen.py, the dark and the light palette), for the one cell that matters. */
.art {
	--art-ink: var(--ink-1);
	--art-mid: var(--ink-3);
	--art-faint: var(--ink-4);
	--art-fire: #e0461a;
	height: 176px;
	margin: 2px 0 14px;
}
.art canvas { display: block; width: 100%; height: 100%; }
@media (prefers-color-scheme: light) {
	.art { --art-fire: #d63c12; }
}
@media (max-width: 520px) {
	.art { height: 160px; }
}

/* The course (/learn and its lessons; client/learn.ts, client/lib/diagrams.ts). Without JS a lesson is a page of steps
   under each other and each question shows its answer in a fold. With it (`main.lesson[data-on]`), the lesson is a
   screen of its own: the site's chrome steps aside, one step shows at a time between a thin bar at the top and the
   big button at the bottom, within thumb reach on a phone. The diagrams are pixel cells in the page's inks, as the
   home page's drawings are (art.css), with the fire orange for the one part that changed. */

/* ---------- Without JS, and before learn.ts starts ---------- */

main.lesson > section.step { padding: 8px 0 20px; border-top: 1px solid var(--line); }
main.lesson > section.step > h2 { margin: 20px 0 10px; font-size: 22px; }
.quiz { margin: 14px 0; padding: 16px 18px; border-radius: 14px; background: var(--bg-2); box-shadow: inset 0 0 0 1px var(--line); }
.quiz .prompt { margin: 0 0 12px; color: var(--ink-1); font-size: 17px; font-weight: 500; line-height: 1.45; }
.quiz .choices { margin: 0; padding: 0 0 0 20px; }
.quiz .choice { margin: 4px 0; }
.quiz .choice .why { display: none; }
.quiz .hint { color: var(--ink-3); font-size: 15px; }
.quiz details.answer summary { color: var(--ink-3); font-size: 14px; cursor: pointer; }
.quiz details.answer p { margin: 8px 0 0; font-size: 15px; }
figure.diagram { margin: 16px 0; }
figure.diagram figcaption { color: var(--ink-3); font-size: 15px; }

/* A module runs after the page is parsed: hold the stacked lesson back for a moment so it doesn't flash before the
   player takes over. If the script never comes, the lesson shows anyway after 1.5 s. */
@media (scripting: enabled) {
	body:has(main.lesson:not([data-on])) .frame { animation: lp-reveal 0s 1.5s both; }
}
@keyframes lp-reveal {
	from { visibility: hidden; }
	to { visibility: visible; }
}

/* ---------- The player ---------- */

body:has(main.lesson[data-on]) :is(.side, .scrim, .mbar, .toc) { display: none; }
body:has(main.lesson[data-on]) .frame { display: block; padding: 0; }
body:has(main.lesson[data-on]) .pane { border-radius: 0; box-shadow: none; }
body:has(main.lesson[data-on]) .grid { display: block; padding: 0 16px; }
main.lesson[data-on] {
	--foot-h: 96px;
	display: flex;
	flex-direction: column;
	max-width: 600px;
	min-height: 100svh;
	padding: 0 0 calc(var(--foot-h) + 24px);
}
main.lesson[data-on] > :is(.head, .pager) { display: none; }
/* The player keeps the page's discussion for the "Lesson complete" screen, and the top line (client/lib/presence.ts)
   out of the way. */
main.lesson[data-on]:not(:has(> .lp-end[data-cur])) > .discussion { display: none; }
main.lesson[data-on] > .discussion { padding-bottom: 120px; }
body:has(main.lesson[data-on]) .topline { display: none; }
main.lesson[data-on] > section.step:not([data-cur]) { display: none; }
main.lesson[data-on] > section.step {
	padding: 28px 0 0;
	border: 0;
}
main.lesson[data-on] > section.step > h2 {
	margin: 0 0 16px;
	font-size: clamp(25px, 5.2vw, 30px);
	line-height: 1.15;
	letter-spacing: -0.025em;
	color: var(--ink-1);
}
main.lesson[data-on] > section.step > h2:focus { outline: none; }
main.lesson[data-on] > section.step > :is(p, .lede) { font-size: 18px; line-height: 1.6; color: var(--ink-2); }
main.lesson[data-on] > section.step strong { color: var(--ink-1); font-weight: 600; }
main.lesson[data-on] > section.step > p.dim { font-size: 15.5px; line-height: 1.55; color: var(--ink-3); }
main.lesson[data-on] > section.step .art { margin: 18px 0; }

/* Sliding in: a short move from the side the reader is going, and a fade. */
main.lesson[data-on] > section.step.in-fwd { animation: lp-in 260ms cubic-bezier(0.2, 0.7, 0.3, 1); }
main.lesson[data-on] > section.step.in-back { animation: lp-in-back 260ms cubic-bezier(0.2, 0.7, 0.3, 1); }
@keyframes lp-in { from { opacity: 0; transform: translateX(28px); } }
@keyframes lp-in-back { from { opacity: 0; transform: translateX(-28px); } }

/* The top bar: back to the course, how far along, step k of n. */
.lp-top {
	position: sticky;
	top: 0;
	z-index: 10;
	display: grid;
	grid-template-columns: 40px 1fr auto 40px;
	align-items: center;
	gap: 12px;
	margin: 0 -16px;
	padding: calc(8px + env(safe-area-inset-top)) 16px 8px;
	background: var(--bg);
}
.lp-x { display: grid; place-items: center; width: 40px; height: 40px; margin-left: -8px; border-radius: 10px; color: var(--ink-3); }
.lp-x:hover { background: var(--s-tint); color: var(--ink-1); }
.lp-bar { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; }
.lp-bar i { display: block; height: 100%; width: calc(var(--p, 0) * 100%); border-radius: 3px; background: var(--ink-1); transition: width 0.4s cubic-bezier(0.2, 0.7, 0.3, 1); }
.lp-top[data-cover='true'] .lp-bar { visibility: hidden; }
.lp-snd { display: grid; place-items: center; width: 40px; height: 40px; margin-right: -8px; padding: 0; border: 0; border-radius: 10px; background: none; color: var(--ink-3); cursor: pointer; }
.lp-snd:hover { background: var(--s-tint); color: var(--ink-1); }
.lp-snd:focus-visible { outline: 2px solid var(--ink-1); outline-offset: 1px; }
.lp-count { min-width: 44px; font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-3); text-align: right; font-variant-numeric: tabular-nums; }

/* The bottom bar: feedback, Back and the big button. */
.lp-foot {
	position: fixed;
	z-index: 10;
	left: 0;
	right: 0;
	bottom: 0;
	padding: 12px max(16px, env(safe-area-inset-left)) calc(14px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-right));
	background: color-mix(in srgb, var(--bg) 92%, transparent);
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
	border-top: 1px solid var(--line);
}
.lp-foot > * { max-width: 600px; margin-inline: auto; }
.lp-row { display: flex; gap: 10px; }
.lp-back, .lp-go { height: 54px; border: 0; border-radius: 14px; font: inherit; cursor: pointer; transition: background-color 0.15s, color 0.15s, opacity 0.15s, transform 0.1s; }
.lp-back { display: grid; place-items: center; flex: none; width: 54px; background: none; box-shadow: inset 0 0 0 1px var(--line-2); color: var(--ink-2); }
.lp-back:hover:not(:disabled) { background: var(--s-tint); color: var(--ink-1); }
.lp-back:disabled { opacity: 0.35; cursor: default; }
.lp-go { flex: 1; background: var(--ink-1); color: var(--bg); font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.lp-go:hover:not(:disabled) { opacity: 0.9; }
.lp-go:active:not(:disabled), .lp-back:active:not(:disabled) { transform: scale(0.985); }
.lp-go:disabled { background: var(--line); color: var(--ink-4); cursor: default; }
.lp-go:focus-visible, .lp-back:focus-visible { outline: 2px solid var(--ink-1); outline-offset: 2px; }

.lp-fb { margin-bottom: 12px; padding: 12px 14px; border-radius: 12px; }
.lp-fb[hidden] { display: none; }
.lp-fb[data-tone='ok'] { background: color-mix(in srgb, var(--ok) 13%, var(--bg)); }
.lp-fb[data-tone='no'] { background: color-mix(in srgb, var(--danger) 12%, var(--bg)); }
.lp-fb p { margin: 0; }
.lp-fb-t { font-weight: 600; font-size: 15.5px; }
.lp-fb[data-tone='ok'] .lp-fb-t { color: var(--ok); }
.lp-fb[data-tone='no'] .lp-fb-t { color: var(--danger); }
.lp-fb-w { margin-top: 2px !important; font-size: 15px; line-height: 1.5; color: var(--ink-1); }
.lp-reveal { margin-left: 2px; padding: 0; border: 0; background: none; color: var(--ink-1); font: inherit; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }

/* The cover: which lesson, its line, and its steps as a row of cells (filled once seen; taps go back to one). */
main.lesson[data-on] > .lp-cover { display: flex; flex-direction: column; justify-content: center; flex: 1; padding-bottom: 8vh; }
.lp-eyebrow { margin: 0 0 10px; font-family: var(--font-mono); font-size: 12.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-3); }
main.lesson[data-on] > .lp-cover > h2 { font-size: clamp(32px, 7vw, 40px); }
main.lesson[data-on] > .lp-cover > .lp-line { margin: 0 0 14px; font-size: 19px; color: var(--ink-2); }
.lp-meta { margin: 0 0 22px; font-family: var(--font-mono); font-size: 13px; color: var(--ink-3); }
.lp-map { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.lp-map button { display: block; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 3px; background: var(--line); cursor: pointer; }
.lp-map button[data-q] { background: none; box-shadow: inset 0 0 0 2px var(--line-2); }
.lp-map button[data-state='seen'] { background: var(--ink-1); box-shadow: none; }
.lp-map button[data-state='seen'][data-q] { background: var(--ink-3); }
.lp-map button:disabled { cursor: default; }
.lp-map button:hover:not(:disabled) { opacity: 0.8; }

/* The end: a check in pixel cells (fire when every question was right the first time), the score, what's next. */
main.lesson[data-on] > .lp-end { display: flex; flex-direction: column; justify-content: center; flex: 1; padding-bottom: 8vh; }
.lp-seal { width: 72px; height: 56px; margin: 0 0 22px; }
.lp-seal svg { display: block; width: 100%; height: 100%; shape-rendering: crispEdges; }
.lp-seal rect { fill: var(--line); }
.lp-seal rect.on { fill: var(--ink-1); }
.lp-seal.all rect.on { fill: #e0461a; }
.lp-score { font-size: 18px !important; color: var(--ink-1) !important; }
.lp-next { color: var(--ink-3) !important; font-size: 16px !important; }
.lp-next a { color: var(--ink-1); }

/* ---------- Questions in the player ---------- */

main.lesson[data-on] .quiz { margin: 0; padding: 0; background: none; box-shadow: none; }
main.lesson[data-on] .quiz .prompt { margin: 0 0 18px; font-size: 19px; line-height: 1.45; }
main.lesson[data-on] .quiz :is(details.answer, .hint) { display: none; }
main.lesson[data-on] .quiz .choices { display: grid; gap: 10px; padding: 0; list-style: none; }
main.lesson[data-on] .quiz .choice { margin: 0; }
.pick {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	width: 100%;
	min-height: 56px;
	padding: 15px 16px;
	border: 0;
	border-radius: 14px;
	background: var(--bg-3);
	box-shadow: inset 0 0 0 1.5px var(--line-2);
	color: var(--ink-1);
	font: inherit;
	font-size: 16.5px;
	line-height: 1.4;
	text-align: left;
	cursor: pointer;
	transition: box-shadow 0.15s, background-color 0.15s, opacity 0.15s;
	-webkit-tap-highlight-color: transparent;
}
.pick .k { display: grid; place-items: center; flex: none; width: 24px; height: 24px; margin-top: -1px; border-radius: 6px; box-shadow: inset 0 0 0 1px var(--line-2); color: var(--ink-3); font-family: var(--font-mono); font-size: 12px; transition: background-color 0.15s, color 0.15s; }
.pick:hover:not(:disabled) { background: var(--bg-4); }
.pick[aria-pressed='true'] { box-shadow: inset 0 0 0 2px var(--ink-1); }
.pick[aria-pressed='true'] .k { background: var(--ink-1); color: var(--bg); box-shadow: none; }
.pick:disabled { cursor: default; }
.pick[data-mark='right'] { background: color-mix(in srgb, var(--ok) 10%, var(--bg-3)); box-shadow: inset 0 0 0 2px var(--ok); }
.pick[data-mark='right'] .k { background: var(--ok); color: var(--bg); box-shadow: none; }
.pick[data-mark='wrong'] { opacity: 0.55; box-shadow: inset 0 0 0 1.5px var(--danger); animation: lp-nudge 0.28s; }
.pick[data-mark='wrong'] .text { text-decoration: line-through; text-decoration-color: var(--danger); }
.pick[data-mark='wrong'] .k { color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger); }
.pick:disabled:not([data-mark]) { opacity: 0.7; }
.pick:focus-visible { outline: 2px solid var(--ink-1); outline-offset: 2px; }
@keyframes lp-nudge {
	25% { transform: translateX(-4px); }
	75% { transform: translateX(4px); }
}

/* ---------- Diagrams ---------- */

.diagram[data-drawn] { margin: 20px 0 4px; padding: 16px 14px 14px; border-radius: 16px; background: var(--code-bg); box-shadow: inset 0 0 0 1px var(--line); }
.quiz .diagram[data-drawn] { margin-top: 0; }
.dg-box { position: relative; width: 100%; }
.dg-wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; shape-rendering: crispEdges; }
.dg-wires rect { fill: var(--ink-4); transition: fill 0.25s; }
.dg-wire.lit rect { fill: var(--ink-1); }
.dg-wire.quiet:not(.lit) { display: none; }
.dg-part {
	position: absolute;
	transform: translate(-50%, -50%);
	display: inline-flex;
	align-items: center;
	gap: 8px;
	width: max-content;
	max-width: 48%;
	min-height: 34px;
	padding: 6px 11px 6px 9px;
	border: 0;
	border-radius: 9px;
	background: var(--bg-3);
	box-shadow: inset 0 0 0 1px var(--line-2);
	color: var(--ink-2);
	font: inherit;
	font-size: 13.5px;
	line-height: 1.2;
	text-align: left;
	cursor: pointer;
	transition: box-shadow 0.2s, color 0.2s, background-color 0.2s, opacity 0.3s;
	-webkit-tap-highlight-color: transparent;
}
.dg-part[data-at='l'] { transform: translate(0, -50%); }
.dg-part[data-at='r'] { transform: translate(-100%, -50%); }
.dg-part.code { font-family: var(--font-mono); font-size: 13px; }
.dg-part .led { flex: none; width: 8px; height: 8px; background: var(--ink-4); transition: background-color 0.2s; }
.dg-part:hover:not(:disabled) { background: var(--bg-4); color: var(--ink-1); }
/* Focus shows as the hover does, not as a second ring round a part's own (one selected style). */
.dg-part:focus { outline: none; }
.dg-part:focus-visible { background: var(--bg-4); color: var(--ink-1); }
.dg-part:focus-visible span { text-decoration: underline; text-underline-offset: 3px; }
.dg-part.fixed { cursor: default; background: var(--bg-2); color: var(--ink-1); font-weight: 500; }
.dg-part.fixed .led { background: var(--ink-1); }
.dg-part[data-state='lit'] { color: var(--ink-1); box-shadow: inset 0 0 0 1.5px var(--ink-3); }
.dg-part[data-state='lit'] .led { background: var(--ink-1); }
.dg-part[data-state='edit'] { color: var(--ink-1); box-shadow: inset 0 0 0 1.5px #e0461a; }
.dg-part[data-state='edit'] .led { background: #e0461a; }
.dg-part[data-state='hit'] { color: var(--ink-1); box-shadow: inset 0 0 0 1.5px var(--ok); }
.dg-part[data-state='hit'] .led { background: var(--ok); }
/* Replaced: still opaque (a wire never shows through a part), its label muted and struck through. */
.dg-part[data-state='old'] { color: var(--ink-3); }
.dg-part[data-state='old'] span { text-decoration: line-through; text-decoration-color: var(--ink-3); }
.dg-part[data-state='hide'] { opacity: 0; visibility: hidden; }
.dg-part[aria-pressed='true'] { color: var(--ink-1); box-shadow: inset 0 0 0 2px var(--ink-1); }
.dg-part[aria-pressed='true'] .led { background: var(--ink-1); }
.dg-part[data-mark='right'] { box-shadow: inset 0 0 0 2px var(--ok); }
.dg-part[data-mark='right'] .led { background: var(--ok); }
.dg-part[data-mark='wrong'] { box-shadow: inset 0 0 0 2px var(--danger); }
.dg-part[data-mark='wrong'] .led { background: var(--danger); }
.dg-part:disabled:not(.fixed) { cursor: default; }
@media (prefers-color-scheme: light) {
	.dg-part[data-state='edit'] { box-shadow: inset 0 0 0 1.5px #d63c12; }
	.dg-part[data-state='edit'] .led, .lp-seal.all rect.on { background: #d63c12; fill: #d63c12; }
}

.dg-say { min-height: 2.9em; margin: 12px 2px 0; font-size: 14.5px; line-height: 1.45; color: var(--ink-2); }
.dg-tools { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.dg-tools:first-child { margin: 0 0 14px; }
.dg-act { height: 36px; padding: 0 16px; border: 0; border-radius: 999px; background: var(--ink-1); color: var(--bg); font: inherit; font-size: 14px; font-weight: 500; cursor: pointer; }
.dg-act:hover { opacity: 0.88; }
.dg-modes { display: inline-flex; padding: 3px; border-radius: 10px; background: var(--bg); box-shadow: inset 0 0 0 1px var(--line); }
.dg-modes button { height: 30px; padding: 0 12px; border: 0; border-radius: 7px; background: none; color: var(--ink-3); font: inherit; font-size: 13.5px; cursor: pointer; }
.dg-modes button[aria-pressed='true'] { background: var(--bg-4); color: var(--ink-1); }

@media (max-width: 400px) {
	.dg-part { gap: 6px; padding: 5px 8px 5px 7px; font-size: 12.5px; }
	.dg-part.code { font-size: 12.5px; }
	.diagram[data-drawn] { padding: 14px 10px 12px; }
}

/* ---------- The course path (the home page) ---------- */

/* The course is a graph (renderer core course.rs lays it out): bands (.theme, one per Theme, under a divider with its
   name), each a list of nodes, one per row, a node's disc in its column (--col) of a narrow graph on the left and its
   text in one column to the right of it. The gutter left of column 0 (--gut) holds the tracks the edges from an
   earlier band run down. client/learn.ts sets each node's data-state (todo, doing, done, mastered), --p (how far into
   it) and data-new, marks the next one data-next, strokes the edges (.trail) and adds the counts and the mastery cells.
   Without JS it is a list of links per band on a plain dotted line. */
.course {
	--colw: 64px;
	--disc: 56px;
	--trk: 8px;
	--cgap: 4px;
	--gut: calc(var(--tracks, 0) * var(--trk) + 6px);
	--graph: calc(var(--cols, 1) * var(--colw));
	--fire: #e0461a;
	--canary: #d9a441;
	position: relative;
	margin: 22px 0 22px;
}
@media (prefers-color-scheme: light) {
	.course, .ulog, .ulog-bar { --fire: #d63c12; --canary: #9a6408; }
}
@media (max-width: 560px) {
	.course { --colw: 42px; --disc: 40px; --trk: 6px; --cgap: 10px; }
}
.ulog { --fire: #e0461a; --canary: #d9a441; }
/* The layout from course.rs, as attributes (the CSP refuses inline styles); course.rs MAX_COLS and MAX_TRACKS match. */
.course[data-cols='2'] { --cols: 2; } .course[data-cols='3'] { --cols: 3; } .course[data-cols='4'] { --cols: 4; }
.course[data-tracks='1'] { --tracks: 1; } .course[data-tracks='2'] { --tracks: 2; } .course[data-tracks='3'] { --tracks: 3; }
.course[data-tracks='4'] { --tracks: 4; } .course[data-tracks='5'] { --tracks: 5; } .course[data-tracks='6'] { --tracks: 6; }
.course[data-tracks='7'] { --tracks: 7; } .course[data-tracks='8'] { --tracks: 8; }
.course .node[data-col='1'] { --col: 1; } .course .node[data-col='2'] { --col: 2; } .course .node[data-col='3'] { --col: 3; }

/* The way in: the next node to start or finish (the first lesson without JS). */
.course-top { display: grid; gap: 14px; margin: 0 0 34px; }
.doc .course-go { display: inline-grid; justify-self: start; gap: 2px; min-width: min(100%, 320px); max-width: 100%; padding: 14px 22px 15px; border-radius: 16px; background: var(--ink-1); color: var(--bg); text-decoration: none; transition: background-color 0.2s; }
.course-go .k { font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.course-go .k::after { content: ' →'; }
.course-go .t { color: color-mix(in srgb, var(--bg) 70%, var(--ink-1)); font-size: 14.5px; }
.doc .course-go:hover { background: color-mix(in srgb, var(--ink-1) 88%, var(--bg)); }
.doc .course-go:active { box-shadow: inset 0 2px 6px rgb(0 0 0 / 0.28); }
.doc .course-go:focus-visible { outline: 2px solid var(--ink-1); outline-offset: 3px; }
@media (max-width: 560px) { .doc .course-go { justify-self: stretch; } }

/* The counts under it: lessons done, updates studied and new, questions right the first time, and Reset progress. */
.course-stats { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 22px; margin: 0; color: var(--ink-3); font-size: 14px; }
.course-stats b { color: var(--ink-1); font-family: var(--font-mono); font-size: 13.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
.course-stats span:empty { display: none; }
.c-reset { margin-left: auto; padding: 2px 0; border: 0; background: none; color: var(--ink-4); font: inherit; font-size: 13px; cursor: pointer; }
.c-reset:hover { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; }
.c-reset:focus-visible { outline: 2px solid var(--ink-1); outline-offset: 2px; border-radius: 4px; }
.c-reset[data-armed] { color: var(--danger); }
.c-reset[hidden] { display: none; }

/* A band: its divider (a rule across the whole width, the gutter's tracks crossing it), its number, name and line,
   set in the text column so the graph stays clear. */
.theme { position: relative; z-index: 1; }
.theme + .theme { margin-top: 6px; padding-top: 30px; border-top: 1px solid var(--line); }
.theme.dashed + .theme, .theme + .theme.dashed { border-top-style: dashed; border-top-color: var(--line-2); }
.theme-head { display: grid; gap: 2px; margin: 0 0 26px calc(var(--gut) + var(--graph) + var(--cgap)); }
.theme-k { color: var(--ink-3); font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; }
.doc .theme-head h3 { margin: 0; font-size: 19px; font-weight: 650; letter-spacing: -0.015em; }
.doc .theme-head p { margin: 2px 0 0; color: var(--ink-3); font-size: 14.5px; line-height: 1.45; }
.theme-canary .theme-k { color: var(--canary); }

.doc .path { position: relative; margin: 0; padding: 0 0 0 var(--gut); list-style: none; }
.doc .path .node { position: relative; margin: 0; padding: 0; }
.doc .path a { display: grid; grid-template-columns: var(--graph) minmax(0, 1fr); column-gap: var(--cgap); align-items: start; padding: 0 8px 30px 0; border-radius: 16px; color: inherit; text-decoration: none; }
.theme:last-of-type .path .node:last-child a { padding-bottom: 38px; }

/* A node: the disc with its glyph, centred in its column; the ring round it (how far into it); the check once done.
   An update's disc is smaller: it hangs off a lesson. */
.course .pin, .ulog .pin { position: relative; display: block; width: var(--disc); height: var(--disc); }
.course .pin { margin-left: calc(var(--col, 0) * var(--colw) + (var(--colw) - var(--disc)) / 2); }
.node.update { --disc: 40px; }
@media (max-width: 560px) {
	.course .node.update { --disc: 30px; }
	.doc .course .path a { padding-right: 0; }
	:is(.course, .ulog) .body .t { font-size: 16.5px; }
	.course .node.update .body .t { font-size: 15.5px; }
	.course .node.update .badge { right: -6px; bottom: -6px; }
}
.node.update .pin { margin-top: 2px; }
:is(.course, .ulog) .disc {
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	background: var(--bg-3);
	box-shadow: inset 0 0 0 1.5px var(--line-2);
	color: var(--ink-2);
	transition: background-color 0.25s, color 0.25s, box-shadow 0.25s;
}
:is(.course, .ulog) .disc .glyph { width: 56%; height: 56%; }
.node.update .disc .glyph { width: 62%; height: 62%; }
:is(.course, .ulog) .badge { position: absolute; right: -3px; bottom: -3px; display: none; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--ink-1); color: var(--bg); box-shadow: 0 0 0 3px var(--bg); }
:is(.course, .ulog) .badge svg { width: 14px; height: 14px; }
.node.update .badge { right: -5px; bottom: -5px; width: 18px; height: 18px; }
.node.update .badge svg { width: 12px; height: 12px; }
/* In a dashed band, a node not yet started has a dashed rim: what it teaches may still change. */
.theme.dashed .node[data-state='todo']:not([data-next]) .disc, .course:not([data-drawn]) .theme.dashed .disc { box-shadow: none; background-image: radial-gradient(circle closest-side, var(--bg-3) calc(100% - 1.5px), transparent calc(100% - 1px)), repeating-conic-gradient(var(--line-2) 0 10deg, transparent 10deg 20deg); }

/* Not started: quiet. */
.node[data-state='todo'] .disc { color: var(--ink-3); }
/* In progress: the ring fills as far as the reader has come. */
.node[data-state='doing'] .pin::before {
	content: '';
	position: absolute;
	inset: -6px;
	border-radius: 50%;
	background: conic-gradient(var(--ink-1) calc(var(--p, 0) * 1turn), var(--line-2) 0);
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
	mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
}
.node.update[data-state='doing'] .pin::before { inset: -5px; }
.node[data-state='doing'] .disc { color: var(--ink-1); }
/* Done: solid, the glyph cut out of it, and a check. Mastered (every question right the first time): the glyph's cell
   and the check in the fire orange. */
.node:is([data-state='done'], [data-state='mastered']) .disc { background: var(--ink-1); color: var(--bg); box-shadow: none; }
.node:is([data-state='done'], [data-state='mastered']) .badge { display: grid; }
.node[data-state='mastered'] .badge { background: var(--fire); color: #fff; }
.node[data-state='mastered'] .g-cell { fill: var(--fire); }
/* The next one: a ring in the ink and a soft halo, so the eye lands there. */
.node[data-next] .disc { color: var(--ink-1); box-shadow: inset 0 0 0 2px var(--ink-1), 0 0 0 7px var(--s-tint); }
.node[data-next][data-state='doing'] .disc { box-shadow: 0 0 0 9px var(--s-tint); }
/* New since the reader's last visit: a small dot on the disc, and the word by its eyebrow. */
.node[data-new]:not([data-state='done'], [data-state='mastered']) .pin::after { content: ''; position: absolute; top: -1px; right: -1px; width: 9px; height: 9px; border-radius: 50%; background: var(--fire); box-shadow: 0 0 0 2.5px var(--bg); }
.new { display: inline-block; margin-left: 8px; padding: 0 6px; border-radius: 4px; background: color-mix(in srgb, var(--fire) 14%, transparent); color: var(--fire); font-family: var(--font-sans); font-size: 11px; font-weight: 600; letter-spacing: 0.02em; line-height: 17px; text-transform: uppercase; vertical-align: 1px; }
.new[hidden] { display: none; }

:is(.course, .ulog) .body { display: grid; gap: 3px; min-width: 0; padding-top: 1px; }
:is(.course, .ulog) .body .n { color: var(--ink-3); font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.02em; }
:is(.course, .ulog) .body .t { color: var(--ink-1); font-size: 17.5px; font-weight: 600; letter-spacing: -0.015em; line-height: 1.3; }
:is(.course, .ulog) .body .l { color: var(--ink-2); font-size: 15px; line-height: 1.45; }
:is(.course, .ulog) .body .m { color: var(--ink-3); font-family: var(--font-mono); font-size: 12.5px; }
.course .node.update .body .t { font-size: 16px; }
.course .node.update .body .l { font-size: 14.5px; }
.node[data-state='todo']:not([data-next]) .body .t { color: var(--ink-2); }
.theme-canary .node.update .body .n, .ulog .tag.theme-canary { color: var(--canary); }

/* Mastery, in the node it belongs to: a cell per question. Solid: right the first time; mid: right later; faint: not
   yet. */
.course .qs { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 5px; }
.course .qs i { display: block; width: 10px; height: 10px; background: var(--line-2); transition: background-color 0.3s; }
.course .qs i[data-state='later'] { background: var(--ink-3); }
.course .qs i[data-state='first'] { background: var(--ink-1); }

/* The way on, on the next node. */
.course .go { justify-self: start; display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; padding: 8px 16px 8px 18px; border-radius: 999px; background: var(--ink-1); color: var(--bg); font-size: 14.5px; font-weight: 600; }
.course .go::after { content: '→'; }

/* Hovering a lesson, or the way in that leads to it, plays its glyph: a small act of what the lesson teaches, inside
   the disc, and its cell turns the fire orange when the act lands. Nothing else moves.
   pipeline: the sources flow along the curves, then the program is linked round its cell.
   functions: the grid holds still and dims; only the changed function rebuilds, in steps.
   sandbox: the code is written, then the walls close round it.
   sealed: the lid closes, and the seal sets.
   store: work travels from both machines into the store, a fire-orange bead down each line.
   The updates: fetch, the download comes down into the tray; why, the build's lines are written out; pass, the check
   is drawn; session, the second expansion opens on what the first left; anywhere, both checkouts reach the one run;
   inline, the code is written with no box round it. */
:is(:is(.doc .path, .ulog) a:is(:hover, :focus-visible), .course:has(.course-go:hover) .node[data-next]) .glyph {
	& :is(.flow, .link, .code, .wall, .lid) { stroke-dasharray: 1; animation: g-draw 0.4s cubic-bezier(0.4, 0, 0.2, 1) both; }
	&.g-pipeline .flow + .flow { animation-delay: 0.08s; }
	&.g-pipeline .link { animation-duration: 0.45s; animation-delay: 0.3s; }
	&.g-sandbox .code + .code { animation-delay: 0.1s; }
	&.g-sandbox .wall { animation-duration: 0.55s; animation-delay: 0.3s; animation-timing-function: cubic-bezier(0.6, 0, 0.3, 1); }
	&.g-sealed .lid { animation-duration: 0.5s; animation-timing-function: cubic-bezier(0.7, 0, 0.3, 1); }
	&.g-functions .fn { animation: g-dim 0.9s ease both; }
	&.g-functions .g-cell { animation: g-rebuild 0.42s steps(1) 0.12s both; }
	&.g-store .pulse { stroke-dasharray: 0.01 1.2; animation: g-travel 0.6s cubic-bezier(0.4, 0, 0.6, 1) 2; }
	&.g-store .pulse + .pulse { animation-delay: 0.12s; }
	& .g-cell { fill: var(--fire); transition: fill 0.12s var(--lands, 0.6s); }
	&.g-pipeline { --lands: 0.7s; }
	&.g-functions { --lands: 0.5s; }
	&.g-sandbox { --lands: 0.8s; }
	&.g-sealed { --lands: 0.45s; }
	&.g-store { --lands: 0.9s; }
	&.g-fetch .link { animation-delay: 0.3s; }
	&.g-why .code + .code { animation-delay: 0.08s; }
	&.g-why .code + .code + .code { animation-delay: 0.16s; }
	&.g-session .link { animation-delay: 0.25s; }
	&.g-anywhere .pulse { stroke-dasharray: 0.01 1.2; animation: g-travel 0.6s cubic-bezier(0.4, 0, 0.6, 1) 2; }
	&.g-anywhere .pulse + .pulse { animation-delay: 0.12s; }
	&.g-inline .code + .code { animation-delay: 0.1s; }
	&.g-fetch { --lands: 0.65s; }
	&.g-why { --lands: 0.5s; }
	&.g-pass { --lands: 0.4s; }
	&.g-session { --lands: 0.6s; }
	&.g-anywhere { --lands: 0.9s; }
	&.g-inline { --lands: 0.45s; }
}
.glyph .pulse { stroke: var(--fire); stroke-width: 2.4; stroke-opacity: 0; }
:is(.doc .path, .ulog) .node[data-state='todo']:not([data-next]) a:hover .disc { box-shadow: inset 0 0 0 1.5px var(--ink-3); }
/* Hidden until it starts: a round cap on a stroke of length 0 is still a dot. */
@keyframes g-draw { 0% { stroke-dashoffset: 1; stroke-opacity: 0; } 1% { stroke-opacity: 1; } 100% { stroke-dashoffset: 0; } }
@keyframes g-dim { 0%, 100% { opacity: 1; } 25%, 70% { opacity: 0.3; } }
@keyframes g-rebuild { 0% { opacity: 0.25; } 30% { opacity: 1; } 55% { opacity: 0.25; } 80%, 100% { opacity: 1; } }
@keyframes g-travel { from { stroke-opacity: 1; stroke-dashoffset: 0; } 90% { stroke-opacity: 1; } to { stroke-opacity: 0; stroke-dashoffset: -1; } }
@media (prefers-reduced-motion: reduce) {
	.doc .path a .glyph *, .course .glyph *, .ulog .glyph * { animation: none !important; transition: none !important; }
}
.doc .path a:hover .t, .ulog a:hover .t { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
:is(.doc .path, .ulog) a:focus-visible { outline: 2px solid var(--ink-1); outline-offset: 4px; }

/* The end of the path: a check in pixel cells, lit once every lesson and update is done. */
.path-end { position: relative; z-index: 1; display: grid; grid-template-columns: var(--graph) minmax(0, 1fr); column-gap: var(--cgap); align-items: center; margin-top: 8px; padding-left: var(--gut); }
.path-end .pin { --col: 0; }
.path-end .disc { background: var(--bg); box-shadow: inset 0 0 0 1.5px var(--line); }
.path-end .seal { width: 50%; height: auto; shape-rendering: crispEdges; }
.path-end .seal rect { fill: var(--line); }
.path-end .seal rect.on { fill: var(--ink-4); }
.path-end .body .t { font-size: 15.5px; color: var(--ink-3); }
.path-end .body .l { font-size: 14px; color: var(--ink-3); }
.course[data-all] .path-end .disc { background: var(--bg-3); box-shadow: inset 0 0 0 2px var(--ink-1), 0 0 0 7px var(--s-tint); }
.course[data-all] .path-end .seal rect.on { fill: var(--ink-1); }
.course[data-all='mastered'] .path-end .seal rect.on { fill: var(--fire); }
.course[data-all] .path-end .body .t { color: var(--ink-1); }
.course[data-all] .path-end .body .l { color: var(--ink-2); }

/* The edges. Without JS: a dotted line down column 0 of each band, behind the discs. */
.course:not([data-drawn]) .path::before {
	content: '';
	position: absolute;
	z-index: -1;
	top: calc(var(--disc) / 2);
	bottom: 30px;
	left: calc(var(--gut) + var(--colw) / 2 - 1.5px);
	width: 3px;
	background: repeating-linear-gradient(var(--line-2) 0 4px, transparent 4px 10px);
}
/* With it (client/learn.ts): each edge a line from pin to pin with a halo in the background under it, so a crossing
   reads as one passing over the other. Faint until the node it leaves from is done, then the ink; into a dashed band,
   dashed, and its accent once lit. */
.trail { position: absolute; z-index: 0; top: 0; left: 0; overflow: visible; pointer-events: none; }
.trail path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.trail .halo { stroke: var(--bg); stroke-width: 7; }
.trail .line { stroke: var(--line-2); stroke-width: 2.5; transition: stroke 0.4s; }
.trail .cross .line { stroke-width: 1.75; }
.trail .dash .line { stroke-dasharray: 5 5; stroke-linecap: butt; }
.trail .lit .line { stroke: var(--ink-1); }
.trail .lit.dash .line { stroke: var(--canary); }

/* ---------- What's new (/updates; render.rs update_log) ---------- */

/* Every update, newest first, under its date: its disc, version and tag, title, line and what it extends; New and
   each one's state from the reader's progress (client/learn.ts). */
.ulog-bar { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 18px; margin: 22px 0 0; color: var(--ink-3); font-size: 14px; }
.ulog-bar .c-reset { margin-left: auto; }
.ulog-day + .ulog-day { margin-top: 10px; }
.doc .ulog-date { margin: 28px 0 14px; padding: 0 0 8px; border-bottom: 1px solid var(--line); color: var(--ink-3); font-family: var(--font-mono); font-size: 12.5px; font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase; }
.doc .ulog-list { margin: 0; padding: 0; list-style: none; }
.doc .ulog-list .node { margin: 0; padding: 0; }
.doc .ulog-list a { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 16px; align-items: start; padding: 12px 8px 14px 0; border-radius: 14px; color: inherit; text-decoration: none; }
.ulog .body .v { font-variant-numeric: tabular-nums; }
.ulog .body .m { margin-top: 2px; }

/* A lesson page's glyph, above its title (the player shows it on its cover). */
.lesson-glyph { display: block; width: 40px; height: 40px; margin: 6px 0 10px; color: var(--ink-2); }
.lesson-glyph .glyph { display: block; width: 100%; height: 100%; }
.lp-cover .lesson-glyph { display: grid; place-items: center; width: 64px; height: 64px; margin: 0 0 18px; border-radius: 50%; background: var(--bg-3); box-shadow: inset 0 0 0 1.5px var(--line-2); color: var(--ink-1); }
.lp-cover .lesson-glyph .glyph { width: 34px; height: 34px; }

/* What's new's row: how many updates are new to the reader (client/side.ts). */
.row .count { flex: none; margin-left: auto; min-width: 18px; padding: 0 5px; border-radius: 9px; background: color-mix(in srgb, #e0461a 16%, transparent); color: #e0461a; font-family: var(--font-mono); font-size: 11px; font-weight: 600; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums; }
.row .count[hidden] { display: none; }
@media (prefers-color-scheme: light) { .row .count { color: #c2380f; } }

/* The sidebar's lesson rows: a mark where the icon would be. Hollow: not started; a dot: started; solid: finished;
   solid with the orange cell: every question right the first time (client/side.ts sets data-state). */
.row .mark { position: relative; flex: none; display: grid; place-items: center; width: 16px; height: 16px; }
.row .mark::before { content: ''; width: 10px; height: 10px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--line-2); box-sizing: border-box; }
.row[data-state='doing'] .mark::before { box-shadow: inset 0 0 0 1.5px var(--ink-2); background: radial-gradient(circle, var(--ink-2) 0 2px, transparent 2.5px); }
.row[data-state='done'] .mark::before, .row[data-state='mastered'] .mark::before { background: var(--ink-2); box-shadow: none; }
.row[data-state='mastered'] .mark::after { content: ''; position: absolute; top: 1px; right: 0; width: 5px; height: 5px; background: #e0461a; box-shadow: 0 0 0 1.5px var(--bg); }
.row[aria-current='page'] .mark::before { box-shadow: inset 0 0 0 1.5px var(--ink-1); }

@media (prefers-reduced-motion: reduce) {
	main.lesson[data-on] > section.step.in-fwd, main.lesson[data-on] > section.step.in-back, .pick[data-mark='wrong'] { animation: none; }
	.lp-bar i, .pick, .dg-part, .dg-wires rect, .course .qs i, .course .pin, :is(.course, .ulog) .disc, .doc .course-go, .trail .line { transition: none; }
}
