/* stillworks. Served from the app and linked through RenderOptions.Stylesheets:
   the default CSP is default-src 'self', so an inline <style> is dropped -- and
   so is an inline style attribute, which is why the track fills below are a
   ladder of classes rather than a width written onto each bar. */

:root {
	--ground: #f6f7f4;
	--panel: #ffffff;
	--panel-2: #eef1ec;
	--line: #d8ded6;
	--line-soft: #e6eae2;
	--ink: #131a16;
	--ink-2: #46534c;
	--ink-3: #77857c;
	--accent: #167a4a;
	--accent-soft: #d8efe1;
	--ok: #167a4a;
	--claim: #9a6a10;
	--fail: #a63d32;
	--none: #9aa79f;
	--key-chip: #6b4fb0;
	--key-chip-bg: #ece6fa;
	--shadow: 0 1px 2px rgba(19, 26, 22, .06), 0 8px 24px -16px rgba(19, 26, 22, .30);
	--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
	--sans: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;

	/* The names the endpoint and traffic pages were written against, kept as
	   aliases rather than as a second palette. A var() alias resolves at use
	   time, so these follow whichever theme block is in force and there is
	   exactly one set of colours on the site. */
	--muted: var(--ink-2);
	--bg: var(--ground);
	--bad: var(--fail);
	--warn: var(--claim);
	--edge: var(--ink-3);
}

@media (prefers-color-scheme: dark) {
	:root {
		--ground: #0e1311;
		--panel: #151b18;
		--panel-2: #1c2320;
		--line: #29332e;
		--line-soft: #212a26;
		--ink: #e8efe9;
		--ink-2: #a3b0a8;
		--ink-3: #78857d;
		--accent: #4fd08a;
		--accent-soft: #16301f;
		--ok: #4fd08a;
		--claim: #d6a544;
		--fail: #e3796a;
		--none: #5d6a63;
		--key-chip: #b9a2f0;
		--key-chip-bg: #241c3a;
		--shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -16px rgba(0, 0, 0, .8);
	}
}

:root[data-theme="dark"] {
	--ground: #0e1311; --panel: #151b18; --panel-2: #1c2320; --line: #29332e; --line-soft: #212a26;
	--ink: #e8efe9; --ink-2: #a3b0a8; --ink-3: #78857d; --accent: #4fd08a; --accent-soft: #16301f;
	--ok: #4fd08a; --claim: #d6a544; --fail: #e3796a; --none: #5d6a63;
	--key-chip: #b9a2f0; --key-chip-bg: #241c3a;
	--shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -16px rgba(0, 0, 0, .8);
}

:root[data-theme="light"] {
	--ground: #f6f7f4; --panel: #ffffff; --panel-2: #eef1ec; --line: #d8ded6; --line-soft: #e6eae2;
	--ink: #131a16; --ink-2: #46534c; --ink-3: #77857c; --accent: #167a4a; --accent-soft: #d8efe1;
	--ok: #167a4a; --claim: #9a6a10; --fail: #a63d32; --none: #9aa79f;
	--key-chip: #6b4fb0; --key-chip-bg: #ece6fa;
	--shadow: 0 1px 2px rgba(19, 26, 22, .06), 0 8px 24px -16px rgba(19, 26, 22, .30);
}

* { box-sizing: border-box; }

body {
	margin: 0;
	background: var(--ground);
	color: var(--ink);
	font-family: var(--sans);
	font-size: 15px;
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

/* godjango's shared stylesheet caps the layout's <main> at 42rem -- a prose
   measure, correct for the login form it was written for. Every page here is a
   wide data table or a full-bleed section inside that element, so it was
   silently clamped: 1280, 1440 and 1920 all rendered at 632px of usable width.

   No framework hook is needed. Application stylesheets are linked after
   godjango's in the document head, so a rule of equal specificity wins on order
   alone; #main raises it further so the reason is legible rather than depending
   on link order surviving a refactor. */
main#main {
	max-width: none;
	margin: 0;
	padding: 0;
}

a { color: var(--accent); }
code, kbd, pre { font-family: var(--mono); }

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 20px; }

.sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

/* A row's drawer is written into every page and hidden. [hidden] is (0,1,0) and
   tr is (0,0,1), so the UA rule already wins -- but only by one point, and a
   later table rule of any weight would quietly un-hide fifty-five drawers. */
[hidden] { display: none !important; }

/* ---------- masthead ---------- */
.masthead { border-bottom: 1px solid var(--line); background: var(--panel); }

/* Wordmark and probe clock hold one row; the tagline gets its own full-width
   line below, so a longer sentence never shoves the clock onto a line of its
   own. */
.masthead .wrap { padding-top: 16px; padding-bottom: 16px; }
.topline { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 7px; }

.mark {
	font-family: var(--mono);
	font-size: 17px;
	font-weight: 600;
	letter-spacing: -.02em;
	display: inline-flex;
	align-items: center;
	gap: 9px;
	color: var(--ink);
	text-decoration: none;
}

.mark .glyph {
	width: 15px;
	height: 15px;
	border: 2.5px solid var(--accent);
	border-radius: 2px;
	display: inline-block;
}

.masthead p { margin: 0; color: var(--ink-2); font-size: 13.5px; max-width: 74ch; }

.shout {
	font-family: var(--mono);
	font-weight: 700;
	color: var(--accent);
	letter-spacing: .04em;
	text-transform: uppercase;
	font-size: 13px;
	white-space: nowrap;
}

.probe-clock {
	font-family: var(--mono);
	font-size: 11.5px;
	color: var(--ink-3);
	display: flex;
	align-items: center;
	gap: 7px;
	white-space: nowrap;
	flex: none;
}

.pulse {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--ok);
	box-shadow: 0 0 0 0 var(--ok);
	animation: pulse 2.6s ease-out infinite;
}

@keyframes pulse {
	0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 60%, transparent); }
	70% { box-shadow: 0 0 0 7px transparent; }
	100% { box-shadow: 0 0 0 0 transparent; }
}

@media (prefers-reduced-motion: reduce) {
	.pulse { animation: none; }
}

/* ---------- the fastest path ---------- */
.lede { padding: 28px 0 24px; }
.pitch { max-width: 72ch; margin-bottom: 22px; }

.eyebrow {
	font-size: 10.5px;
	letter-spacing: .13em;
	text-transform: uppercase;
	color: var(--ink-3);
	margin: 0 0 8px;
	font-weight: 600;
}

.lede h1 {
	font-size: 28px;
	line-height: 1.2;
	margin: 0 0 10px;
	letter-spacing: -.022em;
	text-wrap: balance;
	font-weight: 650;
}

.lede h1 em { font-style: normal; color: var(--accent); }
.lede .sub { margin: 0; color: var(--ink-2); font-size: 14px; max-width: 68ch; }
.lede .sub code { font-size: 12.5px; background: var(--panel-2); padding: 1px 5px; border-radius: 4px; }

/* Both cards stretch to the row height. The left card decides that height (its
   code pane absorbs the slack); the right card's stack has a flex-basis of 0 so
   a long snippet scrolls instead of making the row taller. */
.steps { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: stretch; }
.step { display: flex; flex-direction: column; }
.step .snippet { flex: 1; min-height: 0; }
.step:not(.step-2) .snippet > .stack { flex: 1; }
.step-2 .stack { flex: 1 1 0; }

@media (max-width: 900px) {
	.steps { grid-template-columns: 1fr; }
	.step-2 .stack { flex: none; }
	.step:not(.step-2) .snippet > .stack { flex: none; }
}

.step-head {
	display: flex;
	align-items: center;
	gap: 9px;
	font-size: 11px;
	letter-spacing: .11em;
	text-transform: uppercase;
	color: var(--ink-2);
	font-weight: 600;
	margin-bottom: 9px;
}

.step-head .num {
	width: 19px;
	height: 19px;
	border-radius: 50%;
	border: 1px solid var(--accent);
	color: var(--accent);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-family: var(--mono);
	font-size: 11px;
	letter-spacing: 0;
	flex: none;
}

.snippet-head span.tab {
	font-family: var(--mono);
	font-size: 12px;
	color: var(--ink);
	border-bottom: 2px solid var(--accent);
	padding: 6px 10px 7px;
}

.returns {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 5px;
	padding: 11px 14px;
	border-top: 1px dashed var(--line);
}

.returns-label {
	font-size: 10px;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--ink-3);
	font-weight: 600;
	margin-right: 4px;
}

.returns code {
	font-size: 11px;
	color: var(--ink-2);
	background: var(--panel-2);
	border: 1px solid var(--line-soft);
	border-radius: 5px;
	padding: 2px 6px;
}

/* ---------- snippets and their language panes ----------
   Without the script every pane is a block under its own label, so nothing is
   unreachable and the tabs -- which would be inert -- are never shown. The
   script adds data-tabbed, and from then on all the panes occupy one grid cell:
   the card is always as tall as its longest snippet, and switching languages
   moves nothing else on the page. */
.stack { display: block; min-height: 0; }
.stack > .pane { display: flex; flex-direction: column; min-height: 0; }
.stack > .pane > pre { flex: 1; min-height: 0; overflow: auto; }

.stack[data-tabbed] { display: grid; }
.stack[data-tabbed] > .pane { grid-area: 1 / 1; visibility: hidden; }
.stack[data-tabbed] > .pane[data-active] { visibility: visible; }

.pane-label {
	display: block;
	font-family: var(--mono);
	font-size: 10.5px;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--ink-3);
	padding: 8px 16px 0;
}

.stack[data-tabbed] .pane-label { display: none; }

.snippet {
	display: flex;
	flex-direction: column;
	border: 1px solid var(--line);
	border-radius: 10px;
	background: var(--panel);
	box-shadow: var(--shadow);
	overflow: hidden;
}

.snippet-head {
	display: flex;
	align-items: center;
	gap: 4px;
	padding: 7px 8px 0 8px;
	border-bottom: 1px solid var(--line-soft);
	background: var(--panel-2);
}

/* A head or foot whose only children are the controls the script reveals is not
   a strip of chrome with nothing in it. Without this, a visitor with JavaScript
   switched off gets an empty bordered bar above and below every drawer. */
.snippet-head:not(:has(> :not([hidden]))),
.snippet-foot:not(:has(> :not([hidden]))) { display: none; }

.snippet-head .who {
	margin-left: auto;
	padding: 0 8px 7px;
	font-family: var(--mono);
	font-size: 11px;
	color: var(--ink-3);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.tab {
	appearance: none;
	border: 0;
	background: none;
	font: inherit;
	font-size: 12px;
	color: var(--ink-3);
	padding: 6px 10px 7px;
	border-bottom: 2px solid transparent;
	cursor: pointer;
	font-family: var(--mono);
}

.tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
.tab:hover { color: var(--ink); }

.snippet pre {
	margin: 0;
	padding: 14px 16px;
	overflow-x: auto;
	font-size: 12.5px;
	line-height: 1.65;
	color: var(--ink);
	background: var(--panel);
}

.snippet-foot {
	display: flex;
	gap: 8px;
	align-items: center;
	flex-wrap: wrap;
	padding: 10px 12px;
	border-top: 1px solid var(--line-soft);
	background: var(--panel-2);
}

.snippet-foot .note { font-size: 11.5px; color: var(--ink-3); margin-left: auto; text-align: right; }

button.btn {
	appearance: none;
	font: inherit;
	font-size: 12.5px;
	cursor: pointer;
	border: 1px solid var(--line);
	background: var(--panel);
	color: var(--ink);
	border-radius: 7px;
	padding: 6px 12px;
	display: inline-flex;
	align-items: center;
	gap: 7px;
}

button.btn:hover { border-color: var(--ink-3); }
button.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--ground); font-weight: 600; }
button.btn.primary:hover { filter: brightness(1.06); }

/* Busy is said in the attribute and drawn from it, rather than by disabling the
   button: a disabled button leaves the tab order, so the browser drops focus to
   <body> and a keyboard visitor's place is lost at exactly the moment something
   they asked for is happening. */
button.btn[aria-busy="true"] { color: var(--ink-3); cursor: progress; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- controls ---------- */
.controls {
	position: sticky;
	top: 0;
	z-index: 20;
	background: color-mix(in srgb, var(--ground) 92%, transparent);
	backdrop-filter: blur(8px);
	border-top: 1px solid var(--line);
	border-bottom: 1px solid var(--line);
}

.controls .wrap {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px 14px;
	padding-top: 10px;
	padding-bottom: 10px;
}

.field-form { display: flex; align-items: center; gap: 8px; flex: 1 1 280px; min-width: 200px; }
.field { position: relative; flex: 1 1 auto; min-width: 0; }

.field input {
	width: 100%;
	font: inherit;
	font-size: 13px;
	font-family: var(--mono);
	padding: 7px 10px 7px 30px;
	border-radius: 7px;
	border: 1px solid var(--line);
	background: var(--panel);
	color: var(--ink);
}

.field input::placeholder { color: var(--ink-3); }

.field .icon {
	position: absolute;
	left: 10px;
	top: 50%;
	transform: translateY(-50%);
	color: var(--ink-3);
	font-size: 12px;
	pointer-events: none;
}

.group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

.group > .glabel {
	font-size: 10.5px;
	letter-spacing: .11em;
	text-transform: uppercase;
	color: var(--ink-3);
	font-weight: 600;
	margin-right: 2px;
}

/* A chip is a link, because a filtered shelf has an address. The pressed state
   is aria-current, which is an anchor's attribute; aria-pressed is a button's
   and is matched too, for the one chip that is a submit button. */
.chip {
	appearance: none;
	font: inherit;
	font-size: 12px;
	cursor: pointer;
	white-space: nowrap;
	border: 1px solid var(--line);
	background: var(--panel);
	color: var(--ink-2);
	border-radius: 999px;
	padding: 4px 11px;
	text-decoration: none;
	display: inline-block;
	line-height: 1.5;
}

.chip:hover { color: var(--ink); border-color: var(--ink-3); }

.chip[aria-current="true"],
.chip[aria-pressed="true"] {
	background: var(--accent-soft);
	border-color: var(--accent);
	color: var(--accent);
	font-weight: 600;
}

.chip.go { flex: none; }

.count { margin-left: auto; font-family: var(--mono); font-size: 12px; color: var(--ink-3); white-space: nowrap; }
.count b { color: var(--ink); font-weight: 600; }

/* ---------- the table ---------- */
.board { padding: 18px 0 40px; }
.caption { margin: 0 0 10px; font-size: 12.5px; color: var(--ink-2); max-width: 78ch; }
.board .warn { max-width: 78ch; font-size: 12.5px; font-weight: 400; }

.legend {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 18px;
	align-items: center;
	font-size: 12px;
	color: var(--ink-2);
	padding: 0 0 12px;
}

.legend .item { display: inline-flex; align-items: center; gap: 6px; }

/* The route from the table to the sentence that defines its columns. It sits
   with the dot key because that is where somebody already looking for a key
   will be, and it is a plain link so it works with no script at all. */
.legend a.legend-more { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

.dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.dot.yes { background: var(--ok); }
.dot.claimed { background: none; border: 1.5px solid var(--claim); }
.dot.no, .dot.claimed-no { background: none; border: 1.5px solid var(--fail); position: relative; }

.dot.no::after,
.dot.claimed-no::after {
	content: "";
	position: absolute;
	inset: 50% -1px auto -1px;
	height: 1.5px;
	background: var(--fail);
	transform: rotate(-45deg);
}

.dot.unknown { background: none; border: 1.5px dashed var(--none); }

.board .scroll {
	overflow-x: auto;
	border: 1px solid var(--line);
	border-radius: 10px;
	background: var(--panel);
	box-shadow: var(--shadow);
}

.board table { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 940px; font-size: 13.5px; }

.board thead th {
	position: sticky;
	top: 45px;
	z-index: 5;
	background: var(--panel-2);
	color: var(--ink-2);
	font-size: 10.5px;
	letter-spacing: .1em;
	text-transform: uppercase;
	font-weight: 600;
	text-align: left;
	padding: 9px 12px;
	border-bottom: 1px solid var(--line);
	white-space: nowrap;
}

.board thead th.sortable a.sort { color: inherit; text-decoration: none; display: inline-block; }
.board thead th.sortable a.sort:hover { color: var(--ink); text-decoration: underline; }
.board thead th .arrow { opacity: .35; font-size: 9px; margin-left: 3px; }
.board thead th[aria-sort] { color: var(--ink); }
.board thead th[aria-sort] .arrow { opacity: 1; color: var(--accent); }

.board tbody td { padding: 9px 12px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.board tbody tr:last-child td { border-bottom: 0; }
.board tbody tr.row:hover td { background: var(--panel-2); }
.board tbody tr.row.open td { background: var(--panel-2); }

.model { font-family: var(--mono); font-size: 13px; color: var(--ink); display: block; }
.provider { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); display: block; margin-top: 2px; }
.provider a { color: inherit; }
.provider a:hover { color: var(--accent); }

.board td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; color: var(--ink-2); }
.board th.num { text-align: right; }
.board td.cap { text-align: center; }
.board td.cap .dot { display: inline-block; }

/* A feature heading is a link to its own definition. The dotted underline is
   the only thing on the row that says so -- a heading styled exactly like the
   four beside it would be a link nobody tries. */
.board thead th.cap a.cap-head {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px dotted currentColor;
}

.board thead th.cap a.cap-head:hover { color: var(--ink); border-bottom-style: solid; }

.authchip {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	font-size: 11px;
	font-family: var(--mono);
	border-radius: 999px;
	padding: 2px 8px;
	white-space: nowrap;
	border: 1px solid transparent;
}

.authchip.none { background: var(--accent-soft); color: var(--accent); }
.authchip.key { background: var(--key-chip-bg); color: var(--key-chip); }

.bar { display: flex; align-items: center; gap: 7px; }
.bar .track { width: 42px; height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; flex: none; }
/* display:block, which the mock this was drawn from did not have. The fill is a
   <span> inside a track that is not a flex container, so it stayed inline and an
   inline box takes neither a width nor a height: every bar measured 0x0 and every
   row painted an empty grey track. On a site whose whole claim is that it
   publishes what it measured, a meter that reads zero for a row that answered ten
   of ten is the worst possible thing for it to draw. */
.bar .fill { display: block; height: 100%; background: var(--ok); border-radius: 3px; }
.bar .fill.warn { background: var(--claim); }
.bar span { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* The fill widths. A ladder of classes rather than a style attribute: the
   Content-Security-Policy is default-src 'self', which drops an inline style
   with no error anywhere, so every bar would have been empty in production and
   full in local development. Five-percent steps are two pixels on a 42px track;
   the exact fraction is printed beside the bar. */
.bar .fill.w0 { width: 0; }
.bar .fill.w5 { width: 5%; }
.bar .fill.w10 { width: 10%; }
.bar .fill.w15 { width: 15%; }
.bar .fill.w20 { width: 20%; }
.bar .fill.w25 { width: 25%; }
.bar .fill.w30 { width: 30%; }
.bar .fill.w35 { width: 35%; }
.bar .fill.w40 { width: 40%; }
.bar .fill.w45 { width: 45%; }
.bar .fill.w50 { width: 50%; }
.bar .fill.w55 { width: 55%; }
.bar .fill.w60 { width: 60%; }
.bar .fill.w65 { width: 65%; }
.bar .fill.w70 { width: 70%; }
.bar .fill.w75 { width: 75%; }
.bar .fill.w80 { width: 80%; }
.bar .fill.w85 { width: 85%; }
.bar .fill.w90 { width: 90%; }
.bar .fill.w95 { width: 95%; }
.bar .fill.w100 { width: 100%; }

.board td.act { text-align: right; white-space: nowrap; }
.board td.act .btn { font-size: 11.5px; padding: 4px 9px; }
.board tbody tr.row { cursor: pointer; }

/* Fixed width and a rotation, never a text swap -- a label that changes length
   would move everything to its right every time a row opened. */
.board th.caret-col, .board td.caret-cell { width: 34px; padding-left: 10px; padding-right: 0; }

.caret {
	display: block;
	width: 24px;
	text-align: center;
	color: var(--ink-3);
	font-size: 34px;
	line-height: .5;
	height: 18px;
	text-decoration: none;
	transform: rotate(90deg);
	transition: transform .16s ease;
}

.board tr.row:hover .caret { color: var(--ink-2); }
.board tr.row.open .caret { transform: rotate(270deg); color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
	.caret { transition: none; }
}

/* ---------- the expanded drawer ---------- */
.board tr.detail td { padding: 0; background: var(--panel-2); border-bottom: 1px solid var(--line); }

.drawer {
	display: grid;
	grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
	gap: 18px;
	padding: 16px 14px 18px;
}

@media (max-width: 860px) {
	.drawer { grid-template-columns: 1fr; }
}

.drawer .snippet { box-shadow: none; }
.facts { font-size: 12.5px; color: var(--ink-2); }
.facts dl { display: grid; grid-template-columns: max-content 1fr; gap: 5px 14px; margin: 0 0 12px; }
.facts dt { color: var(--ink-3); font-size: 11px; letter-spacing: .07em; text-transform: uppercase; }
.facts dd { margin: 0; font-family: var(--mono); font-size: 12px; color: var(--ink); overflow-wrap: anywhere; }
.tryout { border-top: 1px dashed var(--line); padding-top: 12px; }
.tryout .note { font-size: 11.5px; color: var(--ink-3); }

.empty { padding: 40px 16px; text-align: center; color: var(--ink-3); font-size: 13.5px; }
.empty b { color: var(--ink); }

/* ---------- checked and not listed ---------- */
.rejected { padding: 0 0 40px; }
.rejected summary {
	cursor: pointer;
	font-size: 12.5px;
	color: var(--ink-2);
	padding: 9px 0;
	border-top: 1px solid var(--line-soft);
}
.rejected summary:hover { color: var(--ink); }
.rejected summary .hint { color: var(--ink-3); }
.rejected details[open] summary { color: var(--ink); }

.rejects { margin: 6px 0 0; max-width: 82ch; }
.rejects dt {
	font-size: 13px;
	font-weight: 600;
	color: var(--ink);
	margin: 14px 0 3px;
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	align-items: baseline;
}
.rejects dt code { font-family: var(--mono); font-size: 11.5px; font-weight: 400; color: var(--ink-3); }
.rejects dd { margin: 0; font-size: 12.5px; color: var(--ink-2); }

/* ---------- footer ---------- */
.foot { border-top: 1px solid var(--line); background: var(--panel); }

.foot .wrap {
	padding: 22px 20px 40px;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
	gap: 22px;
	align-items: start;
}

.foot h3 { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 7px; }
.foot p { margin: 0 0 8px; font-size: 12.5px; color: var(--ink-2); max-width: 52ch; }
.foot code { font-size: 12px; background: var(--panel-2); padding: 1px 5px; border-radius: 4px; }
.foot .legend-panel { max-width: none; margin: 1rem 0 0; font-size: 12.5px; }
.foot .site-foot { margin-top: 1rem; }

/* ---------- toaster ----------
   Results land here instead of inside the card. A call that reported itself in
   place would push every row below it down, which is the thing being avoided. */
.toaster {
	position: fixed;
	right: 22px;
	bottom: 22px;
	z-index: 60;
	pointer-events: none;
	display: flex;
	flex-direction: column;
	gap: 10px;
	width: min(400px, calc(100vw - 32px));
}

.toast {
	pointer-events: auto;
	display: flex;
	gap: 10px;
	align-items: flex-start;
	padding: 11px 12px;
	border-radius: 10px;
	border: 1px solid var(--line);
	background: var(--panel);
	box-shadow: 0 10px 34px -14px rgba(0, 0, 0, .5), 0 1px 2px rgba(0, 0, 0, .10);
	animation: toast-in .22s cubic-bezier(.21, 1.02, .73, 1);
}

.toast.leaving { animation: toast-out .16s ease forwards; }

@keyframes toast-in {
	from { opacity: 0; transform: translateY(14px) scale(.97); }
	to { opacity: 1; transform: none; }
}

@keyframes toast-out {
	to { opacity: 0; transform: translateY(6px) scale(.98); }
}

@media (prefers-reduced-motion: reduce) {
	.toast, .toast.leaving { animation: none; }
}

.toast .glyph-slot { width: 15px; height: 15px; flex: none; margin-top: 2px; display: grid; place-items: center; }
.toast .tick { width: 15px; height: 15px; border-radius: 50%; background: var(--ok); position: relative; }

.toast .tick::after {
	content: "";
	position: absolute;
	left: 4px;
	top: 3.5px;
	width: 4px;
	height: 7px;
	border: solid var(--panel);
	border-width: 0 1.6px 1.6px 0;
	transform: rotate(42deg);
}

.toast .cross { width: 15px; height: 15px; border-radius: 50%; background: var(--fail); position: relative; }

.toast .cross::before,
.toast .cross::after {
	content: "";
	position: absolute;
	left: 3.5px;
	top: 6.7px;
	width: 8px;
	height: 1.6px;
	background: var(--panel);
}

.toast .cross::before { transform: rotate(45deg); }
.toast .cross::after { transform: rotate(-45deg); }

.toast .spin {
	width: 14px;
	height: 14px;
	border-radius: 50%;
	border: 2px solid var(--line);
	border-top-color: var(--accent);
	animation: spin .7s linear infinite;
}

@keyframes spin {
	to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
	.toast .spin { animation: none; }
}

.toast .body { min-width: 0; flex: 1; }
.toast .title { font-size: 13px; font-weight: 600; color: var(--ink); display: block; }
.toast .desc { margin-top: 3px; font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); overflow-wrap: anywhere; display: block; }

.toast .dismiss {
	appearance: none;
	border: 0;
	background: none;
	cursor: pointer;
	color: var(--ink-3);
	font-size: 15px;
	line-height: 1;
	padding: 2px 2px 2px 8px;
	flex: none;
}

.toast .dismiss:hover { color: var(--ink); }
.toaster:has(.toast.wide) { width: min(620px, calc(100vw - 32px)); }

.toast .payload {
	margin: 8px 0 0;
	padding: 10px 11px;
	border-radius: 7px;
	background: var(--panel-2);
	border: 1px solid var(--line-soft);
	font-size: 11.5px;
	line-height: 1.55;
	max-height: 300px;
	overflow: auto;
	white-space: pre;
}

/* ---------- the pages that are not the shelf ----------
   The endpoint page, the traffic page and the two message pages keep the column
   layout they were written for. They share the palette above rather than a
   second one, which is why every colour here is a variable. */
.sw {
	max-width: 76rem;
	margin: 0 auto;
	padding: 2rem 1.25rem 4rem;
}

.sw .measure,
.sw .tag,
.sw p { max-width: 46rem; }

.sw .small { font-size: .85rem; }
.sw h1 { font-size: 2rem; margin: 0 0 .35rem; letter-spacing: -.02em; }
.sw h2 { font-size: 1.1rem; margin: 2.75rem 0 .75rem; letter-spacing: -.01em; }
.sw .tag { color: var(--ink-2); margin: 0 0 1.75rem; }
.sw .lede { font-size: 1.05rem; max-width: 46rem; }

.sw table { border-collapse: collapse; width: 100%; font-size: .92rem; }

.sw th,
.sw td {
	text-align: left;
	padding: .55rem .65rem;
	border-bottom: 1px solid var(--line);
	vertical-align: top;
}

.sw th {
	font-weight: 600;
	color: var(--ink-2);
	font-size: .72rem;
	text-transform: uppercase;
	letter-spacing: .06em;
	white-space: nowrap;
}

.sw tbody tr:hover { background: var(--panel-2); }
.sw code, .sw pre { font-family: var(--mono); font-size: .86em; }

/* Snippets wrap rather than scroll inside their own box: a value you cannot see
   is one you cannot check before pasting. Wrapping is visual only -- the
   newlines the clipboard receives are the ones in the text. */
.sw pre {
	background: var(--panel-2);
	padding: .9rem 1.1rem;
	border-radius: .45rem;
	border: 1px solid var(--line);
	white-space: pre-wrap;
	overflow-wrap: anywhere;
	margin: 0;
}

.sw .snippet { max-width: 52rem; margin: .75rem 0; }
.sw .snippet pre { border: 0; border-radius: 0; background: var(--panel); }

/* The paste block: the first thing on an endpoint page, and the answer to the
   only question most visitors arrive with. */
.sw .start {
	border: 1px solid var(--line);
	border-radius: .6rem;
	padding: 1.1rem 1.25rem 1.35rem;
	margin: 1.5rem 0 2rem;
	background: var(--panel);
	max-width: 66rem;
}

.sw .start-h { margin: 0 0 .35rem; font-size: 1.05rem; }

.sw .start-facts {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: .3rem .9rem;
	margin: 0 0 .35rem;
	font-size: .9rem;
}

.sw .start-facts dt {
	color: var(--ink-3);
	font-size: .72rem;
	text-transform: uppercase;
	letter-spacing: .06em;
	padding-top: .15rem;
}

.sw .start-facts dd { margin: 0; overflow-wrap: anywhere; }

/* Collapsible prose. <details> is HTML, not script, so it still opens with
   JavaScript switched off -- which the glossary in particular has to, because
   the alternative was a title attribute and a phone has no hover. */
details.legend-panel {
	border: 1px solid var(--line);
	border-radius: .45rem;
	padding: .1rem .9rem;
	margin: 1rem 0;
	max-width: 54rem;
}

details.legend-panel > summary { cursor: pointer; padding: .6rem 0; font-size: .9rem; color: var(--ink-2); }
details.legend-panel[open] > summary { border-bottom: 1px solid var(--line); margin-bottom: .6rem; }
.legend-body { padding-bottom: .6rem; }

.legend-body h3 {
	font-size: .78rem;
	text-transform: uppercase;
	letter-spacing: .06em;
	color: var(--ink-3);
	margin: 1.1rem 0 .5rem;
}

.legend-body dl { margin: 0; }
.legend-body dt { font-weight: 600; margin-top: .6rem; }
.legend-body dd { margin: .15rem 0 0; color: var(--ink-2); font-size: .9rem; max-width: 46rem; }
.legend-body p { color: var(--ink-2); font-size: .9rem; max-width: 46rem; }
/* A term that links to the call it was read from. Inherits the term's weight so
   the list still reads as a glossary rather than a row of links. */
.legend-body dt a { color: inherit; text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--accent); }
.legend-body dt a:hover { color: var(--accent); }
.legend-body .snippet { max-width: 46rem; margin-top: .4rem; }
/* This one snippet wraps rather than scrolls. The clipped half of every other
   snippet is a model id; the clipped half of this one is ?feature=… , which is
   the entire reason the block is here — and on a phone nobody scrolls a code
   pane sideways to find out what they were not told. */
.legend-body .snippet pre { white-space: pre-wrap; overflow-wrap: anywhere; }

.site-foot {
	margin-top: 2rem;
	padding-top: 1rem;
	border-top: 1px solid var(--line);
	font-size: .85rem;
	display: flex;
	flex-wrap: wrap;
	gap: .35rem 1.25rem;
}

.ok { color: var(--ok); font-weight: 600; }
.bad { color: var(--fail); font-weight: 600; }
.warn { color: var(--claim); font-weight: 600; }
.muted { color: var(--ink-2); }

.when { color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* The traffic page leads with four numbers, because those four are what the
   project is judged on. */
.sw .stats { display: flex; flex-wrap: wrap; gap: 1.5rem 2.5rem; margin: 1.5rem 0 1rem; }
.sw .stat { display: flex; flex-direction: column; }
.sw .stat-n { font-size: 2.1rem; font-variant-numeric: tabular-nums; letter-spacing: -.03em; line-height: 1.1; }
.sw .stat-l { color: var(--ink-3); font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; }

.sw ul { max-width: 46rem; padding-left: 1.1rem; }
.sw li { margin-bottom: .45rem; }

/* The detail tables are wide by nature; let them scroll rather than squeeze.
   The shadows are the affordance: without them a table that runs off the edge
   looks like a table that simply ends. They appear only on the side there is
   actually more content on, because `local` backgrounds scroll with the content
   while `scroll` ones stay put. */
.sw .scroll {
	overflow-x: auto;
	background:
		linear-gradient(to right, var(--ground) 30%, rgba(0, 0, 0, 0)) left center / 2.5rem 100% no-repeat,
		linear-gradient(to left, var(--ground) 30%, rgba(0, 0, 0, 0)) right center / 2.5rem 100% no-repeat,
		radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, .28), rgba(0, 0, 0, 0)) left center / .9rem 100% no-repeat,
		radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, .28), rgba(0, 0, 0, 0)) right center / .9rem 100% no-repeat;
	background-attachment: local, local, scroll, scroll;
}

/* max-content, not 100%: forced to the container width the cells squeeze until
   the last column is sliced in half. A row may be wider than the page; it may
   not be cut. */
.sw .scroll > table { width: 100%; min-width: max-content; }

.sw .scroll-note { display: block; }
.narrow-only { display: none; }
.sw .scroll-note .narrow-only { display: none; }

/* A long URL inside prose or a list item wraps rather than pushing the page
   wider. */
.sw p code,
.sw li code,
.sw dd code { overflow-wrap: anywhere; }

/* The clipboard fallback's scratch field. Off-screen rather than display:none,
   which cannot be selected, and in the stylesheet rather than inline, which the
   default-src 'self' policy drops. */
.offscreen-copy { position: fixed; top: 0; left: -9999px; opacity: 0; }

/* Below this width the feature matrix costs more than it tells. .detail folds
   the columns an endpoint page can spare on a phone; the shelf's own table
   scrolls instead, because every column on it is a measurement and the row that
   would be folded away is the one somebody is looking for. */
@media (max-width: 760px) {
	.sw .detail { display: none; }
	.narrow-only { display: block; }
	.sw .scroll-note .narrow-only { display: inline; }
	.sw .start { padding: .9rem 1rem 1.1rem; }
	.sw .start-facts { grid-template-columns: 1fr; gap: 0 0; }
	.sw .start-facts dd { margin-bottom: .5rem; }
	.sw tbody td code { overflow-wrap: anywhere; white-space: normal; }
	.sw .snippet pre { font-size: .72rem; line-height: 1.35; padding: .7rem .8rem; }
	.sw .snippet { margin: .5rem 0; }
	.lede h1 { font-size: 23px; }
	.lede { padding: 20px 0 18px; }
	.count { margin-left: 0; }
	.toaster { right: 12px; bottom: 12px; }
	.snippet-foot .note { margin-left: 0; text-align: left; }
}
