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>
1081 lines
28 KiB
SCSS
1081 lines
28 KiB
SCSS
// 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; }
|
||
}
|