/* 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); }

/* A long address or identifier in running text has no space to break at, so
   without this it sets the width of the whole page on a phone: one 450px URL in
   a <code> was enough to make the home page scroll sideways. <pre> is not
   affected -- it does not wrap, and scrolls inside its own box. */
code { overflow-wrap: anywhere; }

.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: 6px 14px; flex-wrap: wrap; 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: minmax(0, 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; min-width: 0; }
.stack > .pane > pre { flex: 1; min-height: 0; overflow: auto; }

.stack[data-tabbed] { display: grid; grid-template-columns: minmax(0, 1fr); }
.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;
	/* Also the containing block for the visually-hidden .sr spans inside the
	   table: an absolutely positioned box is clipped only by an ancestor that
	   contains it, and without this one every .sr sat at its static position, far
	   right of the page, and made the whole document scroll sideways. */
	position: relative;
	border: 1px solid var(--line);
	border-radius: 10px;
	/* Edge shadows appear only on a side that has more table beyond it (`local`
	   backgrounds travel with the content, `scroll` ones stay), so a table cut off
	   by a phone screen reads as scrollable, not as finished. */
	background:
		linear-gradient(to right, var(--panel) 30%, rgba(0, 0, 0, 0)) left center / 2.5rem 100% no-repeat,
		linear-gradient(to left, var(--panel) 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,
		var(--panel);
	background-attachment: local, local, scroll, scroll, scroll;
	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;
	position: relative;
	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; }
}

/* ---------- sponsored slot ----------
   A card, not a row: its own element, border and badge, so it cannot be taken
   for a verified entry and a script reading the table cannot pick it up. */
.sponsor-slot { padding: 14px 0 0; }
.sponsor-card {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 6px 14px;
	align-items: start;
	border: 1px dashed var(--ink-3);
	border-radius: 10px;
	background: var(--panel);
	padding: 12px 16px;
}
.sponsor-badge {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--claim);
	border: 1px solid var(--claim);
	border-radius: 999px;
	padding: 2px 9px;
	white-space: nowrap;
}
.sponsor-badge.open { color: var(--ink-2); border-color: var(--ink-3); }
.sponsor-body p, .sponsor-meta { margin: 0; }
.sponsor-line { font-size: 15px; }
.sponsor-name { font-weight: 600; }
.sponsor-pitch { color: var(--ink); font-size: 14px; }
.sponsor-call code { font-size: 12.5px; background: var(--panel-2); padding: 1px 5px; border-radius: 4px; margin-right: 6px; overflow-wrap: anywhere; }
.sponsor-probe, .sponsor-meta { font-size: 12.5px; }
.sponsor-meta { grid-column: 2; }
.sponsor-slot.house .sponsor-card { border-color: var(--line); }

@media (max-width: 560px) {
	.sponsor-card { grid-template-columns: 1fr; }
	.sponsor-meta { grid-column: 1; }
}

a.cta {
	display: inline-block;
	background: var(--accent);
	color: var(--ground);
	font-weight: 600;
	text-decoration: none;
	border-radius: 7px;
	padding: 9px 16px;
	margin-right: 12px;
}
a.cta:hover { filter: brightness(1.06); }
.sw .sponsor-thanks {
	border: 1px solid var(--ok);
	background: var(--accent-soft);
	border-radius: 8px;
	padding: 10px 14px;
	margin: 0 0 1.25rem;
}
