Files
ferrix/docs/sass/site.scss
T
Rayhaan JaufeerallyandClaude Opus 5.5 dc275f99d7
ci / check (push) Canceled after 0s
ci / docs (push) Canceled after 0s
ci / interop (push) Canceled after 0s
ci / fuzz (push) Canceled after 0s
Add a documentation website, built with Zola
The documentation moves from READMEs into a site in docs/: getting
started, a user guide, operations, a reference, and development pages,
written in the style of network vendors' documentation (docs/STYLE.md).
bin/bgp/README.md and docs/RFCs.md are folded into it.

- A theme of its own in the International Typographic Style, in blues,
  with self-hosted Inter and JetBrains Mono, search over Zola's index,
  dark mode, and no resources loaded from other hosts.
- Example configurations in docs/examples/, shown on the pages and
  checked with `bgp --check` in CI.
- A test that fails when a field of config.proto is missing from the
  configuration reference.
- A CI job that builds the site; Zola fails on broken links and anchors.
- A hardened systemd unit, tried under systemd with kernel routes on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:12:43 +02:00

1081 lines
28 KiB
SCSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The site's one stylesheet, in the manner of the International
// Typographic Style: a neo-grotesque, a strict grid, hairline rules, flush
// left, no ornament, and one colour, blue, used for what matters.
//
// Colours are tokens on :root, redefined for the dark theme, which follows
// the system unless the reader picked one.
// Inter, variable in weight and optical size, and JetBrains Mono; served
// from the site itself (see static/fonts/README.md).
@font-face {
font-family: "Inter";
src: url("fonts/InterVariable.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("fonts/JetBrainsMono-Regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("fonts/JetBrainsMono-Medium.woff2") format("woff2");
font-weight: 500 700;
font-style: normal;
font-display: swap;
}
:root {
color-scheme: light;
--bg: #ffffff;
--bg-tint: #f3f6fb; // code, the panels
--bg-hover: #eef2f9;
--ink: #0a1b33; // headings, the strong rules
--text: #26354d;
--muted: #687891;
--rule: #dce3ee;
--rule-strong: #0a1b33;
--blue: #1f45e0; // links, marks, the one colour
--blue-deep: #0b2fa8; // International Klein Blue, near enough
--blue-tint: #e9eefc;
--on-blue: #ffffff;
--signal: #d4372c; // caution, used once in a while
// Code.
--tok-comment: #8794a8;
--tok-string: #0b2fa8;
--tok-constant: #1f45e0;
--tok-tag: #0a1b33;
--tok-field: #43577a;
--tok-keyword: #0b2fa8;
--display: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
--sans: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
--mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;
--topbar: 56px;
--gutter: 32px;
}
@mixin dark {
color-scheme: dark;
--bg: #06101e;
--bg-tint: #0b1729;
--bg-hover: #0f1d33;
--ink: #f1f5fc;
--text: #c8d2e2;
--muted: #8291a9;
--rule: #18263b;
--rule-strong: #c8d2e2;
--blue: #7095ff;
--blue-deep: #2a4fe0;
--blue-tint: #0f2142;
--on-blue: #ffffff;
--signal: #ff6b5e;
--tok-comment: #5f6f88;
--tok-string: #9fb6ff;
--tok-constant: #7095ff;
--tok-tag: #f1f5fc;
--tok-field: #b4c1d6;
--tok-keyword: #9fb6ff;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) { @include dark; }
}
:root[data-theme="dark"] { @include dark; }
// ---------------------------------------------------------------------------
// Base
*, *::before, *::after { box-sizing: border-box; }
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
scroll-padding-top: calc(var(--topbar) + 24px);
}
body {
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
background: var(--bg);
color: var(--text);
font: 15.5px/1.65 var(--sans);
font-feature-settings: "cv11", "ss01";
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a { color: inherit; text-decoration: none; }
img, svg { display: block; }
.icon { flex: none; }
code, kbd, pre { font-family: var(--mono); }
button { font: inherit; color: inherit; }
::selection { background: var(--blue); color: var(--on-blue); }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.skip {
position: absolute;
left: 12px;
top: -48px;
z-index: 100;
padding: 8px 14px;
background: var(--blue);
color: var(--on-blue);
&:focus { top: 12px; }
}
kbd {
display: inline-flex;
align-items: center;
font-size: 11px;
line-height: 1;
padding: 3px 5px;
border: 1px solid var(--rule);
color: var(--muted);
}
// A small label in the monospace: section numbers and the like.
.eyebrow {
display: block;
margin: 0 0 12px;
font: 500 12px/1.4 var(--mono);
color: var(--blue);
}
// ---------------------------------------------------------------------------
// Top bar
.topbar {
position: sticky;
top: 0;
z-index: 40;
height: var(--topbar);
background: var(--bg);
border-bottom: 1px solid var(--rule-strong);
}
.topbar-inner {
height: 100%;
padding: 0 var(--gutter);
display: flex;
align-items: center;
gap: 40px;
}
.brand {
display: flex;
align-items: center;
gap: 10px;
font: 600 18px/1 var(--display);
letter-spacing: -0.02em;
color: var(--ink);
}
.brand-mark { width: 12px; height: 12px; background: var(--blue); }
.brand-version { font: 400 12px var(--mono); letter-spacing: 0; color: var(--muted); }
.topnav {
display: flex;
gap: 28px;
a {
font-size: 14px;
color: var(--muted);
&:hover { color: var(--ink); }
&[aria-current="page"] { color: var(--ink); }
}
}
.topbar-actions {
margin-left: auto;
display: flex;
align-items: center;
gap: 4px;
}
.search-button {
display: flex;
align-items: center;
gap: 10px;
width: 220px;
height: 34px;
padding: 0 8px 0 10px;
margin-right: 12px;
border: 1px solid var(--rule);
background: transparent;
color: var(--muted);
font-size: 13.5px;
cursor: pointer;
&:hover { border-color: var(--muted); }
.search-button-key { margin-left: auto; }
}
.icon-button {
display: inline-grid;
place-items: center;
width: 34px;
height: 34px;
border: 0;
background: transparent;
color: var(--muted);
cursor: pointer;
&:hover { color: var(--ink); }
}
.menu-button { display: none; margin-left: -8px; }
// The icon for the theme one would switch to.
.theme-icon-light { display: none; }
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) .theme-icon-light { display: block; }
:root:not([data-theme="light"]) .theme-icon-dark { display: none; }
}
:root[data-theme="dark"] .theme-icon-light { display: block; }
:root[data-theme="dark"] .theme-icon-dark { display: none; }
// ---------------------------------------------------------------------------
// Buttons and links
.button {
display: inline-flex;
align-items: center;
gap: 10px;
height: 46px;
padding: 0 22px;
font-size: 15px;
font-weight: 500;
border: 1px solid transparent;
cursor: pointer;
.icon { width: 16px; height: 16px; transition: transform 0.15s; }
&:hover .icon { transform: translateX(3px); }
}
.button-primary {
background: var(--blue-deep);
color: var(--on-blue);
&:hover { background: var(--ink); color: var(--bg); }
}
.button-ghost {
color: var(--ink);
border-color: var(--rule-strong);
background: transparent;
&:hover { background: var(--ink); color: var(--bg); }
}
.text-link {
display: inline-flex;
align-items: center;
gap: 6px;
font-weight: 500;
color: var(--blue);
.icon { width: 15px; height: 15px; transition: transform 0.15s; }
&:hover .icon { transform: translateX(3px); }
}
// ---------------------------------------------------------------------------
// The front page: a poster, then a datasheet, then numbered sections.
.layout-home main { flex: 1; }
.home-section {
padding: 0 var(--gutter);
border-top: 1px solid var(--rule-strong);
}
// A section's number and name on the left, its content on a grid to the
// right: the same two columns all the way down the page.
.home-grid {
display: grid;
grid-template-columns: 3fr 9fr;
gap: var(--gutter);
padding: 28px 0 96px;
}
.home-label {
font: 600 13px/1.4 var(--display);
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--ink);
.eyebrow { margin-bottom: 4px; }
}
.hero {
position: relative;
min-height: min(calc(100vh - var(--topbar)), 760px);
display: flex;
flex-direction: column;
color: #ffffff;
background: #06112e;
overflow: hidden;
}
// The photograph, printed in two colours as Swiss posters printed theirs:
// in black and white, its darks become deep navy and its lights the blue
// of the site. A shade on the left keeps the text legible.
.hero-photo {
position: absolute;
inset: 0;
img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-position: 60% 50%;
filter: grayscale(1) contrast(1.15) brightness(1.05);
}
}
// Above the image: the colour, then the shade.
.hero-tone, .hero-shade { position: absolute; inset: 0; }
.hero-tone { background: #1f45e0; mix-blend-mode: multiply; }
.hero-shade {
background: linear-gradient(90deg,
rgba(5, 14, 40, 0.86) 0%,
rgba(5, 14, 40, 0.62) 40%,
rgba(5, 14, 40, 0.12) 78%,
rgba(5, 14, 40, 0) 100%);
}
.hero-copy {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
max-width: 820px;
padding: 96px var(--gutter) 40px;
.eyebrow { color: #b8c7ff; }
}
.hero-title {
margin: 0 0 32px;
font: 700 clamp(52px, 7vw, 100px)/0.96 var(--display);
letter-spacing: -0.05em;
color: #ffffff;
}
.hero-text {
max-width: 33em;
margin: 0 0 40px;
font-size: 19px;
line-height: 1.6;
color: #e3e9ff;
code { color: #ffffff; }
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.hero-foot {
margin-top: auto;
padding-top: 48px;
font: 13px var(--mono);
color: #b8c7ff;
.prompt { color: #ffffff; margin-right: 8px; user-select: none; }
}
.hero-credit {
position: relative;
margin: 0;
padding: 0 var(--gutter) 20px;
text-align: right;
font: 11.5px var(--mono);
color: rgba(255, 255, 255, 0.7);
a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: #ffffff; }
}
.button-light {
background: #ffffff;
color: var(--blue-deep);
&:hover { background: #dfe6ff; }
}
.button-outline-light {
color: #ffffff;
border-color: rgba(255, 255, 255, 0.75);
&:hover { background: #ffffff; color: #0a1b33; }
}
.spec {
margin: 0;
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: var(--gutter);
div {
display: grid;
grid-template-columns: 11em 1fr;
gap: 16px;
padding: 13px 0;
border-bottom: 1px solid var(--rule);
font-size: 14.5px;
}
dt { color: var(--muted); }
dd { margin: 0; color: var(--ink); }
}
.features {
display: grid;
grid-template-columns: repeat(4, 1fr);
column-gap: var(--gutter);
row-gap: 48px;
}
.feature {
display: block;
padding-top: 14px;
border-top: 1px solid var(--rule-strong);
h3 {
margin: 10px 0 8px;
font: 600 17px/1.3 var(--display);
letter-spacing: -0.015em;
color: var(--ink);
}
p { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
code { font-size: 0.9em; color: var(--text); }
.eyebrow { margin: 0; }
&:hover h3 { color: var(--blue); }
}
.phases, .checks {
list-style: none;
margin: 0 0 28px;
padding: 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
column-gap: var(--gutter);
li {
display: flex;
gap: 14px;
padding: 10px 0;
border-bottom: 1px solid var(--rule);
font: 14px var(--mono);
color: var(--ink);
}
span { color: var(--muted); }
}
.home-note { max-width: 44em; margin: 0 0 20px; color: var(--text); }
.checks {
grid-template-columns: repeat(3, 1fr);
li { font-family: var(--sans); font-size: 15px; }
span { font: 13px var(--mono); color: var(--blue); }
}
.start {
display: grid;
grid-template-columns: 4fr 7fr;
gap: var(--gutter);
align-items: start;
pre {
margin: 0;
padding: 22px 24px;
background: var(--bg-tint);
font-size: 13px;
line-height: 1.8;
color: var(--ink);
overflow-x: auto;
}
.prompt { color: var(--blue); user-select: none; }
.comment { color: var(--tok-comment); }
p { margin: 0 0 24px; font-size: 17px; max-width: 30em; }
}
.not-found {
flex: 1;
padding: 120px var(--gutter);
h1 { margin: 0 0 16px; font: 700 64px/1 var(--display); letter-spacing: -0.045em; color: var(--ink); }
p { margin: 0 0 32px; font-size: 18px; max-width: 30em; }
}
// ---------------------------------------------------------------------------
// The documentation: contents, page, and what is on the page
.docs-layout {
flex: 1;
width: 100%;
display: grid;
grid-template-columns: 264px minmax(0, 1fr) 236px;
}
.sidebar {
position: sticky;
top: var(--topbar);
height: calc(100vh - var(--topbar));
overflow-y: auto;
padding: 32px 24px 48px var(--gutter);
border-right: 1px solid var(--rule);
scrollbar-width: thin;
}
.nav-group {
margin-bottom: 28px;
ul { list-style: none; margin: 0; padding: 0; }
li a {
position: relative;
display: block;
padding: 4px 0;
font-size: 14px;
color: var(--muted);
&:hover { color: var(--ink); }
&[aria-current="page"] {
color: var(--ink);
font-weight: 500;
&::before {
content: "";
position: absolute;
left: -16px;
top: 50%;
width: 7px;
height: 7px;
margin-top: -3.5px;
background: var(--blue);
}
}
}
}
.nav-group-title {
display: flex;
gap: 10px;
margin-bottom: 8px;
font: 600 12px/1.4 var(--display);
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--ink);
span { font: 500 11.5px var(--mono); letter-spacing: 0; color: var(--blue); }
&:hover, &[aria-current="page"] { color: var(--blue); }
}
.docs-main {
min-width: 0;
padding: 44px 64px 96px;
}
.toc-column { padding: 44px var(--gutter) 48px 0; }
.toc {
position: sticky;
top: calc(var(--topbar) + 44px);
max-height: calc(100vh - var(--topbar) - 88px);
overflow-y: auto;
font-size: 13px;
counter-reset: toc;
ul { list-style: none; margin: 0; padding: 0; }
ul ul { padding-left: 26px; }
> ul > li > a::before {
counter-increment: toc;
content: counter(toc, decimal-leading-zero);
display: inline-block;
width: 26px;
font: 11.5px var(--mono);
color: var(--muted);
}
a {
display: block;
padding: 4px 0;
color: var(--muted);
line-height: 1.45;
&:hover { color: var(--ink); }
&.active { color: var(--ink); }
&.active::before { color: var(--blue) !important; }
}
}
.toc-title {
margin: 0 0 12px;
font: 600 12px var(--display);
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--ink);
}
.page-header {
margin-bottom: 40px;
padding-bottom: 32px;
border-bottom: 1px solid var(--rule);
h1 {
margin: 0;
color: var(--ink);
font: 680 48px/1.02 var(--display);
letter-spacing: -0.04em;
}
.lead {
margin: 18px 0 0;
font-size: 19px;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
}
// Text written in Markdown. Its second-level headings are numbered, as the
// contents beside them are.
.prose {
max-width: 760px;
font-size: 16px;
line-height: 1.72;
color: var(--text);
counter-reset: h2;
> :first-child { margin-top: 0; }
p, ul, ol, table, pre, blockquote, figure, details { margin: 0 0 1.3em; }
h2, h3, h4 {
color: var(--ink);
font-family: var(--display);
font-weight: 600;
text-wrap: balance;
a { color: inherit; text-decoration: none; }
}
h2 {
margin: 2.6em 0 0.8em;
padding-top: 14px;
border-top: 1px solid var(--rule-strong);
font-size: 26px;
line-height: 1.2;
letter-spacing: -0.03em;
&::before {
counter-increment: h2;
content: counter(h2, decimal-leading-zero);
display: block;
margin-bottom: 10px;
font: 500 12px var(--mono);
letter-spacing: 0;
color: var(--blue);
}
}
.page-header + h2 { margin-top: 0; }
h3 { margin: 2em 0 0.6em; font-size: 19px; letter-spacing: -0.02em; }
h4 { margin: 1.6em 0 0.5em; font-size: 16px; }
a:not(.card) {
color: var(--blue);
text-decoration: underline;
text-decoration-color: color-mix(in srgb, var(--blue) 35%, transparent);
text-decoration-thickness: 1px;
text-underline-offset: 3px;
&:hover { text-decoration-color: currentColor; }
}
// A heading is a link to itself, and looks like a heading.
:is(h2, h3, h4) a { color: inherit !important; text-decoration: none !important; }
strong { color: var(--ink); font-weight: 600; }
ul, ol { padding-left: 1.25em; }
li { margin: 0.35em 0; padding-left: 0.2em; }
ul > li::marker { content: "– "; color: var(--muted); }
ol > li::marker { font: 500 0.85em var(--mono); color: var(--blue); }
li > ul, li > ol { margin: 0.35em 0; }
hr { border: 0; border-top: 1px solid var(--rule); margin: 3em 0; }
:not(pre) > code {
padding: 0.12em 0.35em;
font-size: 0.85em;
color: var(--ink);
background: var(--bg-tint);
white-space: nowrap;
}
a code { color: inherit; }
blockquote {
padding: 0 0 0 20px;
border-left: 1px solid var(--rule-strong);
color: var(--muted);
}
table {
display: block;
width: max-content;
max-width: 100%;
overflow-x: auto;
border-collapse: collapse;
font-size: 14.5px;
line-height: 1.55;
}
th, td {
padding: 10px 20px 10px 0;
text-align: left;
vertical-align: top;
border-bottom: 1px solid var(--rule);
}
th {
padding-top: 0;
font: 600 11.5px/1.4 var(--display);
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--ink);
border-bottom-color: var(--rule-strong);
white-space: nowrap;
}
td code { white-space: normal; overflow-wrap: anywhere; }
td:first-child code { white-space: nowrap; overflow-wrap: normal; }
// The type of a configuration field, under its name.
td .type {
display: block;
margin-top: 4px;
font-size: 12.5px;
color: var(--muted);
white-space: nowrap;
}
details {
border-top: 1px solid var(--rule-strong);
padding: 12px 0;
summary { cursor: pointer; font-weight: 600; color: var(--ink); }
}
// A whole configuration file, with its name above it.
figure.example {
margin: 0 0 1.5em;
figcaption {
padding: 8px 0;
font: 12px var(--mono);
color: var(--muted);
border-top: 1px solid var(--rule-strong);
}
.code-block, pre { margin: 0 !important; }
}
figure.diagram {
padding: 0 0 8px;
border-top: 1px solid var(--rule-strong);
overflow-x: auto;
svg { margin: 24px 0 0; max-width: 100%; height: auto; }
figcaption { margin-top: 16px; font-size: 14px; color: var(--muted); max-width: 40em; }
.box { fill: var(--bg); stroke: var(--rule-strong); stroke-width: 1; }
.box-accent { fill: var(--blue-deep); stroke: var(--blue-deep); }
.t { fill: var(--ink); font: 600 14px var(--display); }
.s { fill: var(--muted); font: 12px var(--sans); }
.t.on-accent, .s.on-accent { fill: var(--on-blue); }
.edge { fill: none; stroke: var(--ink); stroke-width: 1; }
.edge-back { stroke: var(--blue); stroke-dasharray: 4 4; }
.head { fill: var(--ink); }
}
}
// Code blocks. The highlighter names each token; the colours are ours.
.prose pre {
position: relative;
padding: 18px 22px;
font-size: 13.5px;
line-height: 1.7;
color: var(--ink);
background: var(--bg-tint);
overflow-x: auto;
tab-size: 4;
scrollbar-width: thin;
code { display: block; min-width: max-content; }
}
.z-comment { color: var(--tok-comment); }
.z-string { color: var(--tok-string); }
.z-constant { color: var(--tok-constant); }
.z-keyword, .z-storage { color: var(--tok-keyword); font-weight: 500; }
.z-entity.z-name.z-tag, .z-entity.z-name { color: var(--tok-tag); font-weight: 500; }
.z-support, .z-variable { color: var(--tok-field); }
.z-punctuation.z-definition.z-comment { color: var(--tok-comment); }
.code-block {
position: relative;
margin: 0 0 1.3em;
pre { margin: 0 !important; }
&:hover .copy-button { opacity: 1; }
}
.copy-button {
position: absolute;
top: 8px;
right: 8px;
display: grid;
place-items: center;
width: 30px;
height: 30px;
border: 1px solid var(--rule);
background: var(--bg);
color: var(--muted);
cursor: pointer;
opacity: 0;
transition: opacity 0.15s;
&:hover { color: var(--ink); border-color: var(--muted); }
&:focus-visible { opacity: 1; }
&.copied { color: var(--blue); opacity: 1; }
.icon { width: 14px; height: 14px; }
}
@media (hover: none) { .copy-button { opacity: 1; } }
// > [!NOTE] and the like, which Zola writes as a blockquote with a class
// and no title: a rule above, the kind in capitals, the text.
.prose blockquote[class^="markdown-alert-"] {
--alert: var(--blue);
--alert-title: "Note";
padding: 12px 0 2px;
border: 0;
border-top: 2px solid var(--alert);
color: var(--text);
font-size: 15px;
> :last-child { margin-bottom: 0.6em; }
&::before {
content: var(--alert-title);
display: block;
margin-bottom: 4px;
font: 600 11.5px var(--display);
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--alert);
}
}
.prose blockquote.markdown-alert-tip { --alert-title: "Tip"; }
.prose blockquote.markdown-alert-important { --alert: var(--ink); --alert-title: "Important"; }
.prose blockquote.markdown-alert-warning { --alert: var(--signal); --alert-title: "Warning"; }
.prose blockquote.markdown-alert-caution { --alert: var(--signal); --alert-title: "Caution"; }
// The pages of a group, as a list with rules between.
.cards {
max-width: 760px;
margin-bottom: 48px;
border-top: 1px solid var(--rule-strong);
}
.card {
display: grid;
grid-template-columns: 3.6em 1fr;
gap: 4px 0;
padding: 16px 0;
border-bottom: 1px solid var(--rule);
&:hover .card-title { color: var(--blue); }
}
.card-number { font: 500 12px/1.9 var(--mono); color: var(--blue); grid-row: span 2; }
.card-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
font: 600 17px var(--display);
letter-spacing: -0.015em;
color: var(--ink);
.icon { width: 16px; height: 16px; color: var(--muted); }
}
.card-text { font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.group-overview {
max-width: 760px;
margin-bottom: 24px;
h2 {
display: flex;
gap: 14px;
align-items: baseline;
margin: 0 0 6px;
font: 600 24px var(--display);
letter-spacing: -0.03em;
color: var(--ink);
span { font: 500 12px var(--mono); color: var(--blue); letter-spacing: 0; }
a:hover { color: var(--blue); }
}
> p { margin: 0 0 16px; color: var(--muted); }
}
.pager {
max-width: 760px;
margin-top: 72px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--gutter);
}
.pager-link {
display: flex;
flex-direction: column;
gap: 4px;
padding-top: 12px;
border-top: 1px solid var(--rule-strong);
&:hover .pager-title { color: var(--blue); }
}
.pager-next { text-align: right; grid-column: 2; }
.pager-label { font: 12px var(--mono); color: var(--muted); }
.pager-title { font: 600 18px var(--display); letter-spacing: -0.02em; color: var(--ink); }
.page-source {
max-width: 760px;
margin: 32px 0 0;
font-size: 13px;
a {
display: inline-flex;
align-items: center;
gap: 6px;
color: var(--muted);
&:hover { color: var(--ink); }
}
.icon { width: 14px; height: 14px; }
}
// ---------------------------------------------------------------------------
// Footer
.footer { border-top: 1px solid var(--rule-strong); }
.footer-inner {
padding: 24px var(--gutter);
display: grid;
grid-template-columns: 3fr 9fr;
gap: var(--gutter);
font-size: 13.5px;
color: var(--muted);
}
.footer-brand { display: flex; align-items: center; gap: 10px; color: var(--ink); font-weight: 500; }
.footer-links { display: flex; flex-wrap: wrap; gap: 28px; a:hover { color: var(--ink); } }
.footer-links span { margin-left: auto; }
// ---------------------------------------------------------------------------
// Search
.search {
position: fixed;
inset: 0;
z-index: 60;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 12vh 16px 16px;
&[hidden] { display: none; }
}
.search-backdrop {
position: absolute;
inset: 0;
background: color-mix(in srgb, var(--ink) 30%, transparent);
animation: fade-in 0.12s ease;
}
.search-dialog {
position: relative;
width: 100%;
max-width: 640px;
max-height: 70vh;
display: flex;
flex-direction: column;
background: var(--bg);
border: 1px solid var(--rule-strong);
overflow: hidden;
animation: fade-in 0.12s ease;
}
.search-field {
display: flex;
align-items: center;
gap: 12px;
padding: 0 16px;
border-bottom: 1px solid var(--rule-strong);
color: var(--muted);
input {
flex: 1;
height: 56px;
border: 0;
outline: 0;
background: transparent;
color: var(--ink);
font: 17px var(--sans);
&::placeholder { color: var(--muted); }
&::-webkit-search-cancel-button { display: none; }
}
kbd { cursor: pointer; }
}
.search-results {
list-style: none;
margin: 0;
padding: 0;
overflow-y: auto;
&:empty { display: none; }
li { border-bottom: 1px solid var(--rule); }
a {
display: block;
padding: 12px 16px 12px 18px;
border-left: 3px solid transparent;
&:hover { background: var(--bg-hover); }
&[aria-selected="true"] { border-left-color: var(--blue); background: var(--blue-tint); }
&[aria-selected="true"] .search-result-title { color: var(--blue); }
}
}
.search-result-section { display: block; font: 11.5px var(--mono); color: var(--muted); margin-bottom: 2px; }
.search-result-title { display: block; font: 600 15.5px var(--display); color: var(--ink); }
.search-result-text {
display: -webkit-box;
margin-top: 3px;
font-size: 13.5px;
line-height: 1.5;
color: var(--muted);
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
mark { background: transparent; color: var(--ink); font-weight: 600; }
}
.search-empty { margin: 0; padding: 28px 18px; color: var(--muted); }
@keyframes fade-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
}
// ---------------------------------------------------------------------------
// Narrower screens
@media (max-width: 1240px) {
.docs-layout { grid-template-columns: 248px minmax(0, 1fr); }
.toc-column { display: none; }
.docs-main { padding: 40px 48px 80px; }
.features { grid-template-columns: repeat(2, 1fr); }
.phases { grid-template-columns: repeat(3, 1fr); }
.checks { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 960px) {
:root { --gutter: 24px; }
.topnav { display: none; }
.menu-button { display: inline-grid; }
.search-button { width: auto; border: 0; margin-right: 0; }
.search-button-label, .search-button-key { display: none; }
.docs-layout { grid-template-columns: minmax(0, 1fr); }
.sidebar {
position: fixed;
top: var(--topbar);
left: 0;
bottom: 0;
z-index: 30;
width: min(320px, 86vw);
height: auto;
padding-left: 40px;
background: var(--bg);
border-right: 1px solid var(--rule-strong);
transform: translateX(-102%);
transition: transform 0.2s ease;
visibility: hidden;
}
body.menu-open .sidebar { transform: none; visibility: visible; }
body.menu-open::after {
content: "";
position: fixed;
inset: var(--topbar) 0 0 0;
z-index: 20;
background: color-mix(in srgb, var(--ink) 25%, transparent);
}
.docs-main { padding: 32px var(--gutter) 64px; }
.hero { min-height: 0; }
.hero-copy { padding: 64px var(--gutter) 32px; }
.hero-shade { background: linear-gradient(180deg, rgba(5, 14, 40, 0.55), rgba(5, 14, 40, 0.85)); }
.hero-credit { text-align: left; }
.home-grid { grid-template-columns: minmax(0, 1fr); gap: 20px; padding-bottom: 72px; }
.spec { grid-template-columns: minmax(0, 1fr); }
.start { grid-template-columns: minmax(0, 1fr); }
.footer-inner { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
:root { --gutter: 16px; }
.topbar-inner { gap: 16px; }
.brand-version { display: none; }
.page-header h1 { font-size: 36px; }
.page-header .lead { font-size: 17px; }
.prose { font-size: 15.5px; }
.prose h2 { font-size: 22px; }
.prose pre { font-size: 12.5px; padding: 14px 16px; }
.hero-text { font-size: 17px; }
.spec div { grid-template-columns: 9em 1fr; }
.features { grid-template-columns: minmax(0, 1fr); row-gap: 32px; }
.phases { grid-template-columns: repeat(2, 1fr); }
.checks { grid-template-columns: minmax(0, 1fr); }
.pager { grid-template-columns: minmax(0, 1fr); }
.pager-next { grid-column: 1; }
}