Files
istos 97d63216b6 site: take the six doors off the landing page
The page is now three things: what bench is, what installing costs, and
why to bother. The header nav is the way into the docs.

Removing them takes their CSS with them (.doors/.door* in the base sheet
and in all three breakpoints) and two tests that existed only for them —
the six-are-distinct check here and TheDoorsOpenOntoArticles in
test_site_pages. The hero-buttons test survives its class, renamed to say
what it now guards: the landing page's only links into the docs.

One test needed retargeting rather than deleting.
test_it_fails_before_anything_is_written removed /concepts/team-mode/
from the manifest to prove a dead internal link stops the build before
anything is written — but the link it relied on was a door. It now aims
at /guides/install/, which the hero button still hard-links.

Side effect worth having: the two reasons in "Why bench?" that nearly
repeated doors 03 and 04 no longer sit above them.
2026-07-31 17:20:49 +02:00

621 lines
26 KiB
CSS

/* ── Bench docs: the Daylight register of the board's own system ───────
The four state tokens are named exactly as manager/core/board.html
names them — --accent (surf), --calm (pine), --alarm (terracotta),
--idle (driftwood) — because the site and the board are one system,
and colour in both only ever means state. Their values are the board's
light theme; the neutrals are the docs design's paper register.
Fonts are self-hosted: reading bench's docs must not require a request
to anyone else. site/static/fonts/README.md says which files these
@font-face rules want and how to fetch them.
------------------------------------------------------------------- */
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;src:url("/static/fonts/IBMPlexSans-Regular.woff2") format("woff2")}
@font-face{font-family:'IBM Plex Sans';font-style:italic;font-weight:400;font-display:swap;src:url("/static/fonts/IBMPlexSans-Italic.woff2") format("woff2")}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;src:url("/static/fonts/IBMPlexSans-Medium.woff2") format("woff2")}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;src:url("/static/fonts/IBMPlexSans-SemiBold.woff2") format("woff2")}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url("/static/fonts/IBMPlexMono-Regular.woff2") format("woff2")}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url("/static/fonts/IBMPlexMono-Medium.woff2") format("woff2")}
@font-face{font-family:'Zilla Slab';font-style:normal;font-weight:600;font-display:swap;src:url("/static/fonts/ZillaSlab-SemiBold.woff2") format("woff2")}
:root{
/* paper */
--bg:#c9dde1; --canvas:#eaf3f4; --surface:#ffffff; --sunken:#e0eef1;
--border:#c5d7db; --border-soft:#d9e6e9;
--text:#12323b; --muted:#4d6e77; --dim:#87a1a8;
/* state — the same four the board carries */
--accent:#0d6e8c; --calm:#5f7f33; --alarm:#b1543a; --idle:#93a8ac;
--on-accent:#ffffff;
/* dark ink: code, terminals, chrome */
--ink:#0c1a20; --ink-deep:#0a161b; --ink-line:#1c343a;
--ink-text:#e9f3f3; --ink-muted:#95afb4; --ink-dim:#62828a;
--ink-accent:#56c2d8; --ink-calm:#a6c96f; --ink-alarm:#e08a63;
/* tinted callouts, both state colours */
--calm-wash:#f4f8e6; --calm-edge:#d6e2a8; --calm-ink:#4a6329;
--alarm-wash:#fbf1ec; --alarm-edge:#ecc9b8; --alarm-ink:#7a3c2a;
--sans:'IBM Plex Sans',system-ui,-apple-system,sans-serif;
--mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
--display:'Zilla Slab',Georgia,'Times New Roman',serif;
/* type scale, straight off the design */
/* The hero headline sits in a third of the row now, so it takes a
smaller step than the design's full-width 52px. */
--t-hero:52px; --t-hero-narrow:40px; --t-title:40px; --t-h2:23px; --t-h3:17px;
--t-lede:17px; --t-body:15px; --t-ui:13.5px; --t-code:12.5px;
--t-micro:10.5px;
--radius:11px; --shadow:0 20px 50px -34px rgba(18,50,59,.55);
--shadow-ink:0 18px 40px -30px rgba(12,26,32,.9);
/* The smallest thing a finger is asked to hit. It is a token rather
than a number typed seven times because it is one decision, and the
narrow steps below are where it is spent. */
--tap:44px;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
background:var(--canvas); color:var(--text);
font:var(--t-body)/1.68 var(--sans);
-webkit-font-smoothing:antialiased;
}
a{color:var(--accent);text-decoration:none}
a:hover{color:var(--text);text-decoration:underline}
::selection{background:var(--accent);color:var(--on-accent)}
.mono{font-family:var(--mono)}
.dim{color:var(--dim)}
.spacer{flex:1}
.rule{height:1px;background:var(--border-soft);margin:12px 0}
/* No image, anywhere, may widen the page. .prose img keeps its own
rule for the article body; this is the floor under every layout. */
img{max-width:100%;height:auto}
@media (prefers-reduced-motion: reduce){
*,*::before,*::after{animation:none !important;transition:none !important}
}
/* ── chrome ── */
.topbar{
display:flex;align-items:center;gap:10px;height:30px;padding:0 18px;
background:var(--text);color:#a9c4c9;
font:11px/1 var(--mono);
}
.topbar-org{color:var(--canvas);font-weight:500}
.topbar-sep{color:var(--muted)}
.topbar-repo{color:var(--ink-accent)}
.masthead{
display:flex;align-items:center;gap:20px;padding:14px 30px;
background:var(--surface);border-bottom:1px solid var(--border);
}
.masthead-flat{background:var(--canvas);border-bottom:0}
.wordmark{display:flex;align-items:baseline;gap:9px}
.wordmark:hover{text-decoration:none}
.wordmark-name{
font:600 21px/1 var(--display);letter-spacing:-.015em;color:var(--text);
}
.wordmark-tag{font:12px/1 var(--mono);color:var(--dim)}
.nav{display:flex;gap:18px;font-size:var(--t-ui)}
.nav-link{color:var(--muted);padding-bottom:2px;border-bottom:2px solid transparent}
.nav-link:hover{color:var(--text);text-decoration:none}
.nav-here{color:var(--text);font-weight:600;border-bottom-color:var(--accent)}
.button{
display:inline-block;padding:7px 13px;font:500 var(--t-ui)/1.4 var(--sans);
color:var(--text);background:transparent;
border:1px solid var(--border);border-radius:8px;
}
.button:hover{border-color:var(--accent);color:var(--accent);text-decoration:none}
.button-solid{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.button-solid:hover{background:var(--text);border-color:var(--text);color:var(--on-accent)}
.button-lg{padding:11px 18px;font-size:14px}
.footer{
display:flex;align-items:flex-end;gap:26px;padding:22px 26px;
background:var(--text);color:#a9c4c9;margin-top:40px;
}
.footer-mark{margin:0;font:9.5px/1.25 var(--mono);color:var(--muted)}
.footer-id{display:flex;flex-direction:column;gap:4px}
.footer-name{font:600 15px/1 var(--display);color:var(--canvas)}
/* The line that used to be the h1. It says what bench is about in the
register the product speaks in; the h1 above now says what it does
for you. */
.footer-line{font-size:var(--t-ui);color:var(--ink-muted)}
.footer-id .mono,.footer-repo{font-size:11px}
.footer-repo{color:#a9c4c9}
/* ── article layout (1a Harbour) ── */
.shell{
display:grid;grid-template-columns:236px minmax(0,1fr) 208px;
background:var(--surface);
}
/* Reference pages put a console in the gutter instead of a contents
list, and a console of settings is only useful if the settings are
legible: at 208px every BOARD_AGENT_MODEL_* line was cut mid-key.
So the room right of the nav is split three fifths prose, two
fifths console. Articles keep the narrow gutter — a list of
headings needs no more. */
.page-reference .shell{
grid-template-columns:236px minmax(0,3fr) minmax(0,2fr);
}
.side{
border-right:1px solid var(--border-soft);
padding:22px 16px 40px;display:flex;flex-direction:column;gap:22px;
}
.side-group{display:flex;flex-direction:column;gap:7px}
.side-label{
font:var(--t-micro)/1 var(--mono);letter-spacing:.1em;
text-transform:uppercase;color:var(--dim);padding-left:9px;
}
.side-link{font-size:var(--t-ui);color:var(--muted);padding:4px 9px;border-radius:0 6px 6px 0}
.side-link:hover{color:var(--text);text-decoration:none}
.side-here{
font-weight:600;color:var(--text);background:var(--sunken);
border-left:2px solid var(--accent);
}
.side-note{
display:flex;flex-direction:column;gap:5px;margin-top:6px;
padding:11px 12px;background:var(--canvas);
border:1px solid var(--border-soft);border-radius:10px;
font-size:12.5px;line-height:1.45;color:var(--muted);
}
.side-note .mono{font-size:var(--t-micro)}
.gutter{border-left:1px solid var(--border-soft);padding:30px 18px}
.toc{display:flex;flex-direction:column;gap:9px;position:sticky;top:20px}
.toc-label{
font:var(--t-micro)/1 var(--mono);letter-spacing:.1em;
text-transform:uppercase;color:var(--dim);margin-bottom:2px;
}
.toc-link{
font-size:12.5px;color:var(--muted);
border-left:2px solid var(--sunken);padding-left:9px;
}
.toc-link:hover{color:var(--accent);border-left-color:var(--accent);text-decoration:none}
.gutter-link{font-size:12.5px;line-height:1.5;color:var(--muted)}
.marginalia{
margin-top:36px;font:italic 11px/1.55 var(--mono);color:var(--alarm);
transform:rotate(-1.2deg);transform-origin:left top;
}
.marginalia .mono{font-size:11px}
.crumbs{
display:flex;align-items:center;gap:8px;margin-bottom:16px;
font:11.5px/1 var(--mono);color:var(--dim);
}
.crumb-here{color:var(--muted)}
/* ── generated prose ── */
.page-article .prose,.page-reference .prose{padding:30px 40px 44px;min-width:0}
/* The lede is the article's own sentence; everything after it is the
slice. It reads wider and quieter than body copy, as in the design. */
.prose-lede{
margin:0 0 26px;max-width:60ch;
font-size:var(--t-lede);line-height:1.6;color:var(--muted);
text-wrap:pretty;
}
.prose h1{
font:600 var(--t-title)/1.1 var(--display);letter-spacing:-.02em;
margin:0 0 12px;
}
.prose h2{
font:600 var(--t-h2)/1.3 var(--display);letter-spacing:-.01em;
margin:34px 0 10px;scroll-margin-top:20px;
}
.prose h3{font:600 var(--t-h3)/1.4 var(--sans);margin:26px 0 8px}
/* The lede is the body's first paragraph. The collapsed contents strip
sits between it and the h1 — display:none at the design's width, but
still a sibling — so the adjacency has to name it too, or the lede
would quietly become an ordinary paragraph on desktop. */
.prose h1 + p,.prose .menu-contents + p,.prose > p:first-child{
font-size:var(--t-lede);line-height:1.6;color:var(--muted);max-width:60ch;
}
.prose p{margin:0 0 16px;color:var(--muted);max-width:64ch;text-wrap:pretty}
.prose strong{color:var(--text);font-weight:600}
.prose ul,.prose ol{margin:0 0 18px;padding-left:22px;max-width:64ch;color:var(--muted)}
.prose li{margin:0 0 7px}
.prose li > ul,.prose li > ol{margin:7px 0 0}
.prose hr{border:0;border-top:1px solid var(--border-soft);margin:30px 0}
.prose blockquote{
margin:0 0 20px;padding:14px 16px;background:var(--canvas);
border:1px solid var(--border-soft);border-left:3px solid var(--accent);
border-radius:0 10px 10px 0;color:var(--text);
}
.prose blockquote p:last-child{margin:0}
/* No page slices an image today. When one does, it is the only element
in generated markdown that arrives with its own intrinsic width, and
a 1200px screenshot on a 390px screen would widen the page itself. */
.prose img{max-width:100%;height:auto}
.prose code{
font:var(--t-code)/1.5 var(--mono);
background:var(--canvas);border-radius:4px;padding:1px 5px;
color:var(--text);
}
.prose pre{
margin:0 0 24px;padding:16px 18px;overflow-x:auto;
background:var(--ink);color:var(--ink-text);
font:var(--t-code)/1.75 var(--mono);
border-radius:var(--radius);box-shadow:var(--shadow-ink);
}
.prose pre code{background:transparent;padding:0;color:inherit;font-size:inherit}
.prose table{
border-collapse:separate;border-spacing:0;margin:0 0 26px;width:100%;
background:var(--surface);border:1px solid var(--border-soft);
border-radius:10px;overflow:hidden;font-size:var(--t-ui);
}
.prose th{
text-align:left;padding:9px 14px;background:var(--canvas);
border-bottom:1px solid var(--border-soft);
font:var(--t-micro)/1.4 var(--mono);letter-spacing:.08em;
text-transform:uppercase;color:var(--dim);
}
.prose td{padding:11px 14px;border-bottom:1px solid var(--canvas);color:var(--muted);vertical-align:top}
.prose tr:last-child td{border-bottom:0}
/* Prev/next along the same order the sidebar shows. An absent neighbour
leaves a .spacer in its slot, so `next →` stays right-hand on the first
page exactly as it does on every other. */
.flow{
display:flex;gap:14px;margin-top:44px;padding-top:22px;
border-top:1px solid var(--border-soft);
}
.flow-link{
display:flex;flex-direction:column;gap:5px;flex:0 1 auto;max-width:46%;
padding:12px 16px;background:var(--surface);
border:1px solid var(--border-soft);border-radius:11px;color:var(--text);
}
.flow-link:hover{border-color:var(--accent);color:var(--text);text-decoration:none}
.flow-next{margin-left:auto;text-align:right}
.flow-dir{font-size:var(--t-micro);letter-spacing:.08em;color:var(--dim)}
.flow-title{font:600 15px/1.3 var(--display)}
/* ── reference layout (1c Logbook) ──
The article's three columns with the gutter given over to a console:
a reference page is scanned for one name rather than read down, so
every entry on it is listed once more in the machine register, with
the default it actually has. It links the same anchors "On this page"
does, which is why the 1080px step can fold the whole column away —
the contents strip already hands those anchors back.
Ink, mono and one breathing dot: the console is the board's own
register, and this is a page about the file the board reads. A page
whose body has no entries renders the box with nothing in it, so —
as with the contents strip — the sheet drops it rather than pinning
an empty terminal beside the prose. */
.console-well{position:sticky;top:20px}
.console{border-radius:12px;overflow:hidden;box-shadow:var(--shadow-ink)}
.console:not(:has(a)){display:none}
.console-bar{
display:flex;align-items:center;gap:8px;padding:9px 12px;
background:var(--ink-deep);font:11px/1.3 var(--mono);color:var(--ink-dim);
}
.console-dot{
width:6px;height:6px;border-radius:99px;background:var(--ink-accent);
flex:0 0 auto;
}
.console-name{
color:var(--ink-muted);font-size:10.5px;
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.console-body{
display:flex;flex-direction:column;padding:8px 0;
max-height:min(64vh,520px);overflow:auto;
background:var(--ink);
}
/* One entry per line, and a line that does not fit scrolls inside the
console rather than wrapping: a key broken across two lines stops
looking like a key. */
.console-line{
padding:2px 12px;font:var(--t-code)/1.75 var(--mono);
color:var(--ink-muted);white-space:nowrap;
}
.console-line:hover{
background:var(--ink-line);color:var(--ink-text);text-decoration:none;
}
.console-key{color:var(--ink-accent)}
.console-sign{color:var(--ink-dim)}
.console-value{color:var(--ink-text)}
/* The flag under a setting's heading: the lines exactly as the file
writes them. It is a value you set, not a terminal that printed
something, so it takes the design's light strip rather than the ink
every other code block on the site wears — which is the whole reason
the generator fences these as `env`. */
.prose pre:has(code.language-env){
padding:12px 14px;background:var(--surface);color:var(--text);
border:1px solid var(--border-soft);border-radius:9px;box-shadow:none;
}
/* ── home layout (1b Dockside) ── */
/* One third words, two thirds board. The claim this page makes is a
board, so the board is what it shows first and shows large. */
.hero{
display:grid;grid-template-columns:1fr 2fr;gap:40px;
padding:40px 44px 34px;align-items:center;
}
.hero-copy{display:flex;flex-direction:column;gap:20px}
.eyebrow{
font:11px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;
color:var(--accent);
}
.hero h1{
margin:0;font:600 var(--t-hero-narrow)/1.08 var(--display);
letter-spacing:-.025em;text-wrap:balance;
}
.lede{
margin:0;max-width:44ch;font-size:var(--t-lede);line-height:1.62;
color:var(--muted);text-wrap:pretty;
}
.hero-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.aside-note{font-size:11.5px;font-style:italic;color:var(--dim)}
.terminal{border-radius:12px;overflow:hidden;box-shadow:0 24px 46px -30px rgba(12,26,32,.85)}
.terminal-bar{
display:flex;align-items:center;gap:8px;padding:9px 14px;
background:var(--ink-deep);
}
.dot{width:8px;height:8px;border-radius:99px}
.dot-alarm{background:var(--ink-alarm)}
.dot-calm{background:var(--ink-calm)}
.terminal-title{font-size:11px;color:var(--ink-dim);margin-left:6px}
/* The transcript below is real output with the long stretches cut, and
the bar is where it says so — a claim about the block, not decoration. */
.terminal-note{font-size:10.5px;color:var(--ink-dim);letter-spacing:.04em}
.terminal-body{
margin:0;padding:18px;background:var(--ink);color:var(--ink-text);
font:var(--t-code)/1.85 var(--mono);
/* The release url is 72 characters and has to wrap rather than clip;
`anywhere` breaks it, and breaks a word only when a word is what
does not fit — the transcript's prose lines wrap normally. */
white-space:pre-wrap;overflow-wrap:anywhere;
}
.t-calm{color:var(--ink-calm)}
.t-accent{color:var(--ink-accent)}
.t-muted{color:var(--ink-muted)}
.t-dim{color:var(--ink-dim)}
/* The board itself, in the hero's larger column. */
.shot{margin:0;padding:0;min-width:0}
.shot-img{
display:block;width:100%;height:auto;
border:1px solid var(--border);border-radius:12px;
box-shadow:var(--shadow);background:var(--ink);
}
.shot-cap{
padding:10px 2px 0;max-width:70ch;
font-size:12.5px;line-height:1.55;color:var(--dim);text-wrap:pretty;
}
/* Half and half: what it takes to start, beside what starting looks
like. It carries the terminal the hero used to, which is what lets
the hero be one thing rather than two. */
.install{
display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:center;
padding:34px 44px;background:var(--sunken);
border-top:1px solid var(--border-soft);
border-bottom:1px solid var(--border-soft);
}
.install-copy{display:flex;flex-direction:column;gap:14px;min-width:0}
.install-title{
margin:0;font:600 var(--t-h2)/1.25 var(--display);letter-spacing:-.01em;
}
.install-copy p{margin:0;max-width:52ch;color:var(--muted);text-wrap:pretty}
.install .terminal{min-width:0}
/* Why bench: the landing page's one content section, between the
install band and the footer. Two columns rather than three, so the
first reason — the one that needs a sentence, not a phrase — has
somewhere to put it. */
.why{padding:8px 44px 30px}
.why-title{
margin:0 0 20px;font:600 var(--t-h2)/1.3 var(--display);
letter-spacing:-.01em;color:var(--text);
}
.why-list{
display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
gap:22px 40px;
}
.why-reason{display:flex;flex-direction:column;gap:6px}
.why-lead{
font:600 var(--t-h3)/1.4 var(--display);color:var(--text);
text-wrap:pretty;
}
.why-text{
font-size:var(--t-ui);line-height:1.6;color:var(--muted);
text-wrap:pretty;
}
/* The strip at the foot of the landing page. It carries the version and
nothing else measurable, because the version is the only thing about
itself this site can measure. */
.strip{
display:flex;align-items:center;gap:14px;flex-wrap:wrap;
padding:18px 44px;background:var(--sunken);
border-top:1px solid var(--border-soft);
}
.strip-label{
font-size:var(--t-micro);letter-spacing:.1em;text-transform:uppercase;
color:var(--dim);
}
.strip-version{
font-size:var(--t-code);padding:4px 10px;background:var(--surface);
border:1px solid var(--border);border-radius:99px;color:var(--accent);
}
.strip-text{font-size:12.5px;line-height:1.55;color:var(--muted);max-width:64ch}
.strip-text .mono{font-size:var(--t-code)}
.strip-link{font-size:12px;color:var(--accent)}
/* ── 404 (layout "notfound") ── */
.lost{
display:flex;flex-direction:column;align-items:flex-start;gap:18px;
padding:76px 44px 96px;max-width:60ch;
}
.lost-code{
font-size:11px;letter-spacing:.14em;color:var(--alarm);
}
.lost h1{
margin:0;font:600 var(--t-hero)/1.05 var(--display);
letter-spacing:-.025em;text-wrap:balance;
}
/* ── the columns a narrow screen folds away ──
The article is drawn with three columns and a phone has room for one.
Both of the ones it loses come back as a <details> the page can open:
the section nav as a menu under the masthead, the contents as a strip
under the title. Each is display:none until the step that hides its
column shows it, so at the design's width none of this renders — and
because the strips are <details>, one menu that opens and closes cost
this site no script at all. */
.menu{display:none}
.menu-summary{
display:flex;align-items:center;gap:8px;min-height:var(--tap);
padding:9px 18px;cursor:pointer;list-style:none;
font:500 var(--t-ui)/1.4 var(--sans);color:var(--text);
background:var(--surface);border-bottom:1px solid var(--border-soft);
}
.menu-summary::-webkit-details-marker{display:none}
.menu-summary::after{content:"▾";margin-left:auto;font-size:11px;color:var(--dim)}
.menu[open] > .menu-summary::after{content:"▴"}
.menu-panel{
display:flex;flex-direction:column;gap:4px;
max-height:min(62vh,460px);overflow-y:auto;
padding:10px 14px 16px;background:var(--surface);
border-bottom:1px solid var(--border-soft);
}
.menu-panel .side-link,.menu-panel .toc-link{
display:flex;align-items:center;min-height:var(--tap);
}
.menu-panel .side-group{gap:2px}
/* The contents strip sits inside the prose, so it is a card rather than
a bar across the page — and it says "On this page" once: the summary
is the label, and $toc's own label folds away underneath it. */
.menu-contents{
margin:0 0 22px;border:1px solid var(--border-soft);
border-radius:10px;overflow:hidden;
}
.menu-contents .menu-summary{
background:var(--canvas);border-bottom:0;padding:9px 14px;
}
.menu-contents[open] .menu-summary{border-bottom:1px solid var(--border-soft)}
.menu-contents .menu-panel{border-bottom:0;padding:8px 14px 12px}
.menu-contents .toc-label{display:none}
/* A body with no h2s has no contents: render_contents gives the strip
nothing, and a summary over an empty panel is worse than no strip. */
.menu-contents:not(:has(a)){display:none}
/* ── narrow ──
The design is drawn at 1180px and everything below this comment is
what happens under it. Three steps, each giving up what no longer
fits and handing back a way to reach it: 1080 the contents gutter,
760 the section sidebar and the top of the type scale, 480 the last
of the desktop's padding. Every query is a max-width at or below
1080, so at the design's own width the sheet above is the whole
stylesheet. */
@media (max-width:1080px){
.shell{grid-template-columns:220px minmax(0,1fr)}
/* Same specificity as the base override, or the console's track
would survive here as two fifths of empty grid. */
.page-reference .shell{grid-template-columns:220px minmax(0,1fr)}
.gutter{display:none}
.menu-contents{display:block}
.hero{grid-template-columns:minmax(0,1fr);gap:28px;padding:32px 24px}
.install{grid-template-columns:minmax(0,1fr);gap:26px;padding:28px 24px}
.why{padding:8px 24px 26px}
.strip{padding:18px 24px}
/* Only a code block or a table may scroll sideways, so a token that
cannot break — a url, a curl one-liner in running text — breaks
rather than making the page wider than the screen. Fenced code is
untouched: white-space:pre forbids wrapping, which is why `pre`
carries overflow-x:auto instead. */
.prose :not(pre) > code{overflow-wrap:anywhere}
.prose h1,.prose h2,.prose h3{overflow-wrap:break-word}
/* A table is the one block that cannot reflow — its columns are its
meaning — so it becomes its own scroller. display:block makes the
table element the scroll container; the two edge shadows are
painted on the box (scroll) and covered by a patch of surface
painted on the content (local), so each one appears only while
there really is more that way. The cost is that a table narrower
than the column no longer stretches to fill it: the inner table box
an unblocked <table> generates sizes to its own content. */
.prose table{
display:block;width:100%;max-width:100%;overflow-x:auto;
background-image:
linear-gradient(to right,var(--surface),rgba(255,255,255,0)),
linear-gradient(to left,var(--surface),rgba(255,255,255,0)),
linear-gradient(to right,rgba(18,50,59,.20),rgba(18,50,59,0)),
linear-gradient(to left,rgba(18,50,59,.20),rgba(18,50,59,0));
background-position:0 0,100% 0,0 0,100% 0;
background-size:26px 100%,26px 100%,13px 100%,13px 100%;
background-repeat:no-repeat;
background-attachment:local,local,scroll,scroll;
}
}
@media (max-width:760px){
:root{
/* The design's 52px hero and 40px title are drawn for a 1180px
frame. The step comes down; the voice does not — --display is
still Zilla Slab, here and at every width below. */
--t-hero:36px; --t-title:30px; --t-h2:21px; --t-h3:16.5px;
--t-lede:16.5px;
}
.shell{grid-template-columns:minmax(0,1fr)}
.page-reference .shell{grid-template-columns:minmax(0,1fr)}
.side{display:none}
.menu{display:block}
.page-article .prose,.page-reference .prose{padding:24px 20px 36px}
.why-list{grid-template-columns:minmax(0,1fr);gap:18px}
.masthead{padding:12px 18px;gap:12px;flex-wrap:wrap}
.crumbs{flex-wrap:wrap}
.footer{flex-wrap:wrap;gap:16px 20px;padding:20px 18px}
/* A spacer holds one end of a row against the other. Once the row
wraps there are no two ends, and all it can still do is take a
line of its own — so it goes, and the footer stacks. */
.footer .spacer{display:none}
.lost{padding:48px 20px 64px}
/* Tap targets: everything a finger has to hit is at least --tap tall.
Links inside running prose are the exception, because a line of
text cannot be 44px without stopping being a line of text. */
.wordmark,.nav-link,.button,.side-link,.toc-link,.strip-link,
.footer-repo{
display:inline-flex;align-items:center;min-height:var(--tap);
}
.button{justify-content:center}
.nav{gap:4px;flex-wrap:wrap}
.nav-link{padding:0 8px}
.side-link{padding:0 9px}
.toc-link{padding:0 0 0 9px}
}
@media (max-width:480px){
:root{
--t-hero:31px; --t-title:26px; --t-h2:19px;
/* Body text goes the other way: 15px is a desktop reading distance
and a phone is held closer to nothing. The lede keeps its notch
above it, or it stops being a lede. */
--t-body:16px; --t-lede:17.5px;
}
.topbar{padding:0 14px}
.masthead{padding:10px 14px;gap:8px 12px}
/* As in the footer: with the button no longer held at a far edge,
the wordmark, the nav and it share the row until they cannot, and
then wrap. */
.masthead .spacer{display:none}
.hero{padding:26px 16px}
.hero-actions{gap:8px}
.hero-actions .button{width:100%}
.why{padding:8px 16px 22px}
.strip{padding:16px}
.install{padding:24px 16px}
.page-article .prose,.page-reference .prose{padding:20px 16px 32px}
.menu-summary{padding:9px 14px}
.footer{padding:18px 14px}
.lost{padding:40px 16px 56px}
}