1687 lines
34 KiB
CSS
1687 lines
34 KiB
CSS
/*
|
|
* The visual design of the service.
|
|
*
|
|
* Colour carries meaning in the graph and in the tables, so the variables
|
|
* are named by role rather than by hue. The dark palette is the default and
|
|
* the light one overrides the same variables, so every rule is written once.
|
|
* A reader's stored choice sets `data-theme` on the document element.
|
|
*/
|
|
|
|
:root {
|
|
color-scheme: dark;
|
|
|
|
--background: #0b0f17;
|
|
--surface: #121826;
|
|
--surface-raised: #18202f;
|
|
--border: #243044;
|
|
--border-strong: #35455f;
|
|
|
|
--text: #dfe7f1;
|
|
--text-muted: #93a2b8;
|
|
--text-faint: #64748b;
|
|
|
|
--accent: #7fd1ff;
|
|
--accent-strong: #4cb4e8;
|
|
--accent-soft: rgba(127, 209, 255, 0.12);
|
|
|
|
--positive: #5fd39a;
|
|
--warning: #e8c26a;
|
|
--negative: #f28b82;
|
|
|
|
--shadow: rgba(0, 0, 0, 0.35);
|
|
--graph-surface: #161d2b;
|
|
--graph-grid: #1e2738;
|
|
|
|
--topbar: rgba(11, 15, 23, 0.9);
|
|
--scrim: rgba(0, 0, 0, 0.45);
|
|
--warning-soft: rgba(232, 194, 106, 0.1);
|
|
--negative-soft: rgba(242, 139, 130, 0.1);
|
|
--accent-faint: rgba(127, 209, 255, 0.04);
|
|
--on-accent: #04121c;
|
|
|
|
--syntax-keyword: #c792ea;
|
|
--syntax-type: #82aaff;
|
|
--syntax-function: #7fd1ff;
|
|
|
|
/* One hue per layer, so that a legend with ten entries is readable. The
|
|
concept graph uses these directly; the flow graphs reuse the earlier
|
|
stage names. */
|
|
/* Layout. Both are fixed proportions: the sidebar is a share of the
|
|
window and the table of contents is a share of the reading column, so
|
|
neither changes size with the length of a title. */
|
|
--sidebar-width: 19rem;
|
|
--toc-width: 15rem;
|
|
|
|
/* Graph group colours. */
|
|
--group-overview: #7fd1ff;
|
|
--group-foundation: #a3e635;
|
|
--group-physics: #4ade80;
|
|
--group-geometry: #34d399;
|
|
--group-elements: #fbbf24;
|
|
--group-orbit: #fb923c;
|
|
--group-propagation: #f87171;
|
|
--group-rf: #e879f9;
|
|
--group-network: #c084fc;
|
|
--group-ops: #818cf8;
|
|
--group-sim: #38bdf8;
|
|
--group-methods: #94a3b8;
|
|
|
|
/* Flow stages */
|
|
--group-input: #94a3b8;
|
|
--group-parse: #7dd3fc;
|
|
--group-prepare: #a78bfa;
|
|
--group-propagate: #38bdf8;
|
|
--group-verify: #4ade80;
|
|
--group-fields: #4ade80;
|
|
--group-crosscheck: #fbbf24;
|
|
--group-branch: #fbbf24;
|
|
--group-error: #f87171;
|
|
--group-output: #4ade80;
|
|
--group-validate: #a78bfa;
|
|
--group-convert: #38bdf8;
|
|
--group-store: #a78bfa;
|
|
--group-frames: #4ade80;
|
|
--group-rotate: #38bdf8;
|
|
--group-geodetic: #fbbf24;
|
|
--group-time: #a78bfa;
|
|
--group-general: #94a3b8;
|
|
--group-damping: #4ade80;
|
|
--group-frameset: #4ade80;
|
|
}
|
|
|
|
/*
|
|
* The light palette. It is a full override rather than a filter, because a
|
|
* filter inverts the graph colours and makes the legend meaningless. The
|
|
* background is tinted rather than pure white, because a long page of
|
|
* pure white is harder to read than a page that is not.
|
|
*/
|
|
:root[data-theme='light'] {
|
|
color-scheme: light;
|
|
|
|
--background: #f4f6fa;
|
|
--surface: #ffffff;
|
|
--surface-raised: #eef1f6;
|
|
--border: #d3dae4;
|
|
--border-strong: #b3bfcd;
|
|
|
|
--text: #16202e;
|
|
--text-muted: #4a5769;
|
|
--text-faint: #6b7787;
|
|
|
|
--accent: #0b6fa4;
|
|
--accent-strong: #08587f;
|
|
--accent-soft: rgba(11, 111, 164, 0.1);
|
|
|
|
--positive: #147d54;
|
|
--warning: #9a6510;
|
|
--negative: #b3261e;
|
|
|
|
--shadow: rgba(15, 30, 50, 0.12);
|
|
--graph-surface: #ffffff;
|
|
--graph-grid: #dce3ec;
|
|
|
|
--topbar: rgba(255, 255, 255, 0.9);
|
|
--scrim: rgba(15, 30, 50, 0.35);
|
|
--warning-soft: rgba(154, 101, 16, 0.1);
|
|
--negative-soft: rgba(179, 38, 30, 0.09);
|
|
--accent-faint: rgba(11, 111, 164, 0.05);
|
|
--on-accent: #ffffff;
|
|
|
|
--syntax-keyword: #7c3aed;
|
|
--syntax-type: #1d4ed8;
|
|
--syntax-function: #0b6fa4;
|
|
|
|
/* The graph hues are darkened so that a thin stroke stays legible on a
|
|
light background; the dark values are too pale to read here. */
|
|
--group-overview: #0b6fa4;
|
|
--group-foundation: #4d7c0f;
|
|
--group-physics: #15803d;
|
|
--group-geometry: #0f766e;
|
|
--group-elements: #a16207;
|
|
--group-orbit: #c2410c;
|
|
--group-propagation: #b91c1c;
|
|
--group-rf: #86198f;
|
|
--group-network: #6d28d9;
|
|
--group-ops: #3730a3;
|
|
--group-sim: #0369a1;
|
|
--group-methods: #475569;
|
|
--group-input: #475569;
|
|
--group-parse: #0369a1;
|
|
--group-prepare: #5b21b6;
|
|
--group-propagate: #0369a1;
|
|
--group-verify: #15803d;
|
|
--group-fields: #15803d;
|
|
--group-crosscheck: #a16207;
|
|
--group-branch: #a16207;
|
|
--group-error: #b91c1c;
|
|
--group-output: #15803d;
|
|
--group-validate: #5b21b6;
|
|
--group-convert: #0369a1;
|
|
--group-store: #5b21b6;
|
|
--group-frames: #0f766e;
|
|
--group-rotate: #0369a1;
|
|
--group-geodetic: #a16207;
|
|
--group-time: #5b21b6;
|
|
--group-general: #475569;
|
|
--group-damping: #15803d;
|
|
--group-frameset: #0f766e;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
background: var(--background);
|
|
color: var(--text);
|
|
font-family: var(--sans);
|
|
font-size: 15px;
|
|
line-height: 1.65;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
a {
|
|
color: var(--accent);
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4 {
|
|
line-height: 1.25;
|
|
font-weight: 600;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 1.9rem;
|
|
margin: 0 0 0.5rem;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 1.35rem;
|
|
margin: 2.25rem 0 0.75rem;
|
|
padding-bottom: 0.4rem;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
h3 {
|
|
font-size: 1.1rem;
|
|
margin: 1.75rem 0 0.5rem;
|
|
}
|
|
|
|
h4 {
|
|
font-size: 1rem;
|
|
margin: 1.25rem 0 0.4rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
p {
|
|
margin: 0.75rem 0;
|
|
}
|
|
|
|
ul,
|
|
ol {
|
|
margin: 0.75rem 0;
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
li {
|
|
margin: 0.3rem 0;
|
|
}
|
|
|
|
code {
|
|
font-family: var(--mono);
|
|
font-size: 0.88em;
|
|
background: var(--surface-raised);
|
|
padding: 0.12em 0.35em;
|
|
border-radius: var(--radius-small);
|
|
}
|
|
|
|
pre {
|
|
margin: 0;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
pre code {
|
|
background: none;
|
|
padding: 0;
|
|
font-size: 0.85rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
blockquote {
|
|
margin: 1rem 0;
|
|
padding: 0.25rem 1rem;
|
|
border-left: 3px solid var(--border-strong);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
hr {
|
|
border: none;
|
|
border-top: 1px solid var(--border);
|
|
margin: 2rem 0;
|
|
}
|
|
|
|
/* Layout */
|
|
|
|
.app {
|
|
display: flex;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* The frame carries the surface and the rule, so the column is drawn for
|
|
the whole page. The sidebar itself is sticky and scrolls; without the
|
|
frame the column would end one viewport down and look cut off on a long
|
|
page. */
|
|
.sidebar-frame {
|
|
flex: 0 0 var(--sidebar-width);
|
|
background: var(--surface);
|
|
border-right: 1px solid var(--border);
|
|
}
|
|
|
|
.sidebar {
|
|
position: sticky;
|
|
top: 0;
|
|
height: 100vh;
|
|
overflow-y: auto;
|
|
padding: 1.25rem 0 2rem;
|
|
}
|
|
|
|
.sidebar-brand {
|
|
display: block;
|
|
padding: 0 1.25rem 1rem;
|
|
border-bottom: 1px solid var(--border);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.sidebar-brand a {
|
|
color: var(--text);
|
|
font-size: 1.05rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.01em;
|
|
}
|
|
|
|
.sidebar-brand p {
|
|
margin: 0.15rem 0 0;
|
|
color: var(--text-faint);
|
|
font-size: 0.78rem;
|
|
}
|
|
|
|
.sidebar nav {
|
|
padding: 0 0.75rem;
|
|
}
|
|
|
|
.sidebar-section {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
/* The group separates the concepts from the implementation, so it is
|
|
written differently from the layers inside it. */
|
|
.sidebar-group-title {
|
|
color: var(--accent);
|
|
font-size: 0.72rem;
|
|
line-height: 1.35;
|
|
font-weight: 700;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
padding-bottom: 0.35rem;
|
|
margin: 0 0 0.55rem 0.4rem;
|
|
border-bottom: 1px solid var(--border-strong);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.sidebar-section h2 {
|
|
font-size: 0.72rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
color: var(--text-faint);
|
|
margin: 0 0 0.5rem 0.5rem;
|
|
border: none;
|
|
padding: 0;
|
|
}
|
|
|
|
/* A layer in the sidebar. It is a two column grid: the title and the fold
|
|
control, so that every layer occupies the same box whatever the length
|
|
of its name. A row that grew with its text would give the sidebar an
|
|
irregular rhythm down its length. */
|
|
.sidebar-chapter {
|
|
/* One box per layer, whatever the length of its name, so the sidebar has a
|
|
regular rhythm down its length rather than one that follows the text. */
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) 1.1rem;
|
|
align-items: center;
|
|
column-gap: 0.15rem;
|
|
margin-bottom: 0.15rem;
|
|
padding-left: 0.4rem;
|
|
border-left: 2px solid var(--border-strong);
|
|
min-height: 1.35rem;
|
|
margin-bottom: 0.15rem;
|
|
}
|
|
|
|
/* The document links belong to the layer but are not part of its header
|
|
row, so they take the whole width below it. Without this they are
|
|
placed in the header's first column and a link with no space to break is
|
|
set one character per line. */
|
|
.sidebar-chapter > a.item {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.sidebar-chapter-title {
|
|
min-width: 0;
|
|
font-size: 0.78rem;
|
|
line-height: 1.35;
|
|
color: var(--text);
|
|
margin: 0;
|
|
font-weight: 700;
|
|
letter-spacing: 0.02em;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.sidebar-chapter-title:hover {
|
|
color: var(--accent);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.sidebar-chapter-toggle {
|
|
width: 1.1rem;
|
|
height: 1.1rem;
|
|
padding: 0;
|
|
border: none;
|
|
background: none;
|
|
color: var(--text-faint);
|
|
font-size: 0.65rem;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
transition: transform 0.12s ease;
|
|
}
|
|
|
|
.sidebar-chapter.collapsed .sidebar-chapter-toggle {
|
|
transform: rotate(-90deg);
|
|
}
|
|
|
|
.sidebar-chapter-toggle:hover {
|
|
color: var(--accent);
|
|
background: none;
|
|
}
|
|
|
|
.sidebar a.item {
|
|
display: block;
|
|
padding: 0.3rem 0.5rem;
|
|
border-radius: var(--radius-small);
|
|
color: var(--text-muted);
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
.sidebar a.item:hover {
|
|
background: var(--surface-raised);
|
|
color: var(--text);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.sidebar a.item.active {
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.main {
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.topbar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.75rem 1.5rem;
|
|
border-bottom: 1px solid var(--border);
|
|
background: var(--topbar);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 20;
|
|
backdrop-filter: blur(6px);
|
|
}
|
|
|
|
.search-box {
|
|
flex: 0 1 auto;
|
|
max-width: 34rem;
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.search-box input {
|
|
flex: 1 1 auto;
|
|
/* Without this the input keeps its intrinsic width as its minimum and
|
|
squeezes the button until the label wraps. */
|
|
min-width: 0;
|
|
}
|
|
|
|
/* A button label is a single line; a narrow flex item must not break it. */
|
|
button {
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.content {
|
|
padding: 1.75rem 2.5rem 4rem;
|
|
width: 100%;
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
/* A document is a measure of text plus the table of contents beside it, so
|
|
the reading column keeps a comfortable line length while the table of
|
|
contents sits at its right. The width is capped so that the pair stays
|
|
centred on a very wide screen rather than drifting apart. */
|
|
.content.doc {
|
|
max-width: calc(62rem + var(--toc-width) + 2.5rem);
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* The graph and the crate grid use the whole width; a wide screen shows
|
|
more of them rather than more margin. */
|
|
.content.wide {
|
|
max-width: none;
|
|
}
|
|
|
|
/* Controls */
|
|
|
|
input,
|
|
select,
|
|
textarea,
|
|
button {
|
|
font-family: inherit;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
input[type='text'],
|
|
input[type='number'],
|
|
input[type='search'],
|
|
select,
|
|
textarea {
|
|
width: 100%;
|
|
background: var(--surface);
|
|
color: var(--text);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-small);
|
|
padding: 0.45rem 0.6rem;
|
|
transition: border-color 0.12s ease;
|
|
}
|
|
|
|
input:focus,
|
|
select:focus,
|
|
textarea:focus {
|
|
outline: none;
|
|
border-color: var(--accent-strong);
|
|
}
|
|
|
|
textarea {
|
|
font-family: var(--mono);
|
|
font-size: 0.82rem;
|
|
line-height: 1.5;
|
|
resize: vertical;
|
|
min-height: 6rem;
|
|
}
|
|
|
|
button {
|
|
background: var(--accent-strong);
|
|
color: var(--on-accent);
|
|
border: none;
|
|
border-radius: var(--radius-small);
|
|
padding: 0.45rem 0.9rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button:hover:not(:disabled) {
|
|
background: var(--accent);
|
|
}
|
|
|
|
button:disabled {
|
|
opacity: 0.55;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
button.secondary {
|
|
background: var(--surface-raised);
|
|
color: var(--text);
|
|
border: 1px solid var(--border-strong);
|
|
}
|
|
|
|
button.secondary:hover:not(:disabled) {
|
|
background: var(--border);
|
|
}
|
|
|
|
button.ghost {
|
|
background: none;
|
|
color: var(--text-muted);
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
button.ghost:hover:not(:disabled) {
|
|
background: var(--surface-raised);
|
|
color: var(--text);
|
|
}
|
|
|
|
/* Cards and panels */
|
|
|
|
.card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 1.1rem 1.25rem;
|
|
}
|
|
|
|
/* Cards stacked outside a grid. Inside a grid the `gap` spaces them, and a
|
|
sibling margin would add a second gap, pushing every card after the first
|
|
in a row down by one row gap while the first stays flush. */
|
|
.card + .card {
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.grid.cards > .card + .card {
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* A filter field is a control, not a paragraph, so it is given a measure
|
|
rather than the whole width of the page. */
|
|
.filter-field {
|
|
max-width: 34rem;
|
|
}
|
|
|
|
.card h3 {
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* The root of a page that renders cards. It carries no style of its own;
|
|
it exists so that the cards under it can be measured together. */
|
|
.page-root {
|
|
display: block;
|
|
}
|
|
|
|
/* A grid of cards stretches every card in a row to the height of the
|
|
tallest. The card is a column so that its action sits at the bottom of
|
|
every card rather than floating at the height of the text above it. */
|
|
.grid.cards > .card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
}
|
|
|
|
.card-action {
|
|
margin-top: auto;
|
|
padding-top: 0.75rem;
|
|
align-self: flex-start;
|
|
}
|
|
|
|
/* A card is a column, so its button would otherwise stretch across the
|
|
whole card rather than sit under the text. */
|
|
.grid.cards > .card > button,
|
|
.grid.cards > .card > a {
|
|
align-self: flex-start;
|
|
}
|
|
|
|
/* The tag row follows the summary; only the action is pushed to the bottom,
|
|
so the actions of a row line up regardless of how many tags a card has. */
|
|
.card-tags {
|
|
padding-top: 0.15rem;
|
|
}
|
|
|
|
/* A summary is clamped so that one long paragraph does not stretch its card
|
|
far past the cards beside it. */
|
|
.card-clamp {
|
|
/* The text is not truncated: the card height is uniform across the page,
|
|
so a card with a longer summary simply carries more lines and the
|
|
action stays on the bottom line of every card. */
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
/*
|
|
* A grid whose track is wider than a narrow screen.
|
|
*
|
|
* `minmax(28rem, 1fr)` makes a track that is at least 28rem wide, so on a
|
|
* phone the column stays 448 pixels wide and the page scrolls sideways. The
|
|
* `min(…, 100%)` lets the track shrink to the width it actually has, so a
|
|
* narrow screen gets one narrow column rather than one wide one.
|
|
*/
|
|
|
|
/*
|
|
* A card on the interface index shows what a crate is, in one or two lines.
|
|
*
|
|
* The cards there are in a grid with three columns on a wide screen, so a
|
|
* single long summary made every card in its row as tall as the longest one.
|
|
* The text is cut rather than the card stretched, because the rest of the
|
|
* summary is on the page the card leads to.
|
|
*/
|
|
.crate-grid .card-clamp {
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 2;
|
|
line-clamp: 2;
|
|
overflow: hidden;
|
|
margin: 0.4rem 0 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* A layer heading on the interface index. */
|
|
.api-layer-heading {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.5rem;
|
|
margin: 1.75rem 0 0;
|
|
font-size: 1.05rem;
|
|
}
|
|
|
|
.api-layer-heading a {
|
|
color: var(--text);
|
|
}
|
|
|
|
.api-layer-summary {
|
|
margin: 0.25rem 0 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.grid {
|
|
display: grid;
|
|
gap: 1rem;
|
|
}
|
|
|
|
/*
|
|
* A card grid has a fixed number of columns rather than as many as fit.
|
|
*
|
|
* `auto-fill` sizes the columns to the width available *and* to the number
|
|
* of cards in the row, so a section of three cards and a section of four end
|
|
* up with different card widths on the same page. A fixed column count keeps
|
|
* one rhythm down the page: every card is the same width, and a section that
|
|
* does not fill a row leaves the gap at the end rather than widening the
|
|
* cards. The columns collapse on a narrow screen, where a fluid width is the
|
|
* right answer.
|
|
*/
|
|
.grid.cards {
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
}
|
|
|
|
.grid.metrics {
|
|
grid-template-columns: repeat(auto-fill, minmax(min(11rem, 100%), 1fr));
|
|
}
|
|
|
|
.metric {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 0.85rem 1rem;
|
|
}
|
|
|
|
.metric .value {
|
|
font-size: 1.45rem;
|
|
font-weight: 600;
|
|
color: var(--accent);
|
|
font-family: var(--mono);
|
|
}
|
|
|
|
.metric .label {
|
|
color: var(--text-faint);
|
|
font-size: 0.78rem;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
.page-header {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.page-header p {
|
|
color: var(--text-muted);
|
|
max-width: 60rem;
|
|
}
|
|
|
|
.breadcrumb {
|
|
color: var(--text-faint);
|
|
font-size: 0.82rem;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
|
|
.breadcrumb a {
|
|
color: var(--text-faint);
|
|
}
|
|
|
|
.tag {
|
|
display: inline-block;
|
|
white-space: nowrap;
|
|
background: var(--surface-raised);
|
|
border: 1px solid var(--border);
|
|
color: var(--text-muted);
|
|
border-radius: 999px;
|
|
padding: 0.05rem 0.6rem;
|
|
font-size: 0.75rem;
|
|
margin: 0 0.3rem 0.3rem 0;
|
|
}
|
|
|
|
.badge {
|
|
display: inline-block;
|
|
white-space: nowrap;
|
|
border-radius: var(--radius-small);
|
|
padding: 0.05rem 0.4rem;
|
|
font-size: 0.72rem;
|
|
font-family: var(--mono);
|
|
border: 1px solid var(--border-strong);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.notice {
|
|
border-left: 3px solid var(--accent-strong);
|
|
background: var(--accent-soft);
|
|
padding: 0.6rem 0.9rem;
|
|
border-radius: var(--radius-small);
|
|
margin: 1rem 0;
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
.notice.warning {
|
|
border-color: var(--warning);
|
|
background: var(--warning-soft);
|
|
}
|
|
|
|
.notice.error {
|
|
border-color: var(--negative);
|
|
background: var(--negative-soft);
|
|
}
|
|
|
|
.notice.muted {
|
|
border-color: var(--border-strong);
|
|
background: var(--surface);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.empty {
|
|
color: var(--text-faint);
|
|
font-style: italic;
|
|
padding: 1rem 0;
|
|
}
|
|
|
|
/* Search results */
|
|
|
|
.result-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.result {
|
|
padding: 0.85rem 1.1rem;
|
|
border-bottom: 1px solid var(--border);
|
|
background: var(--surface);
|
|
}
|
|
|
|
.result:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.result:hover {
|
|
background: var(--surface-raised);
|
|
}
|
|
|
|
.result-title {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.result-summary {
|
|
margin: 0.35rem 0 0.55rem;
|
|
color: var(--text-muted);
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
.result-meta {
|
|
display: flex;
|
|
gap: 0.35rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* Documentation */
|
|
|
|
.doc-body {
|
|
min-width: 0;
|
|
/*
|
|
* A doc comment names items by their full path, as in
|
|
* `NoiseTemperature::from_noise_figure_db`, and a path has no space in it
|
|
* to break at. Left alone it makes the page scroll sideways on a phone,
|
|
* because the column can shrink but the word cannot.
|
|
*/
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.doc-body h1,
|
|
.doc-body h2,
|
|
.doc-body h3 {
|
|
position: relative;
|
|
scroll-margin-top: 4.5rem;
|
|
}
|
|
|
|
.doc-body .anchor {
|
|
opacity: 0;
|
|
margin-left: 0.4rem;
|
|
color: var(--text-faint);
|
|
font-weight: 400;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.doc-body h1:hover .anchor,
|
|
.doc-body h2:hover .anchor,
|
|
.doc-body h3:hover .anchor {
|
|
opacity: 1;
|
|
}
|
|
|
|
.doc-body figure.code {
|
|
margin: 1rem 0;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.doc-body figure.code figcaption {
|
|
padding: 0.3rem 0.8rem;
|
|
background: var(--surface-raised);
|
|
border-bottom: 1px solid var(--border);
|
|
color: var(--text-faint);
|
|
font-size: 0.72rem;
|
|
font-family: var(--mono);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
}
|
|
|
|
.doc-body figure.code pre {
|
|
padding: 0.9rem 1rem;
|
|
}
|
|
|
|
.doc-body a.concept-link {
|
|
border-bottom: 1px dotted var(--accent-strong);
|
|
}
|
|
|
|
.doc-layout {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) var(--toc-width);
|
|
gap: 2.5rem;
|
|
align-items: start;
|
|
}
|
|
|
|
/* A document with no headings gets the full width rather than an empty
|
|
column at its right. */
|
|
.doc-layout.no-toc {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
max-width: 46rem;
|
|
}
|
|
|
|
.doc-toc {
|
|
position: sticky;
|
|
top: 4.5rem;
|
|
align-self: start;
|
|
font-size: 0.85rem;
|
|
max-height: calc(100vh - 6rem);
|
|
overflow-y: auto;
|
|
padding-left: 1rem;
|
|
border-left: 1px solid var(--border);
|
|
}
|
|
|
|
/* Tables */
|
|
|
|
.table-wrap {
|
|
overflow-x: auto;
|
|
margin: 1rem 0;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
th,
|
|
td {
|
|
text-align: left;
|
|
padding: 0.5rem 0.8rem;
|
|
border-bottom: 1px solid var(--border);
|
|
vertical-align: top;
|
|
}
|
|
|
|
/* A table cell that holds an identifier is kept on one line so that the
|
|
column does not break a name across two lines. */
|
|
td:first-child {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
th {
|
|
background: var(--surface-raised);
|
|
color: var(--text-muted);
|
|
font-weight: 600;
|
|
font-size: 0.78rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
th.numeric,
|
|
td.numeric {
|
|
text-align: right;
|
|
font-family: var(--mono);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
tbody tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background: var(--accent-faint);
|
|
}
|
|
|
|
/* Scalars */
|
|
|
|
.scalars {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
|
|
gap: 0.6rem 1.5rem;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.scalar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 0.75rem;
|
|
padding: 0.35rem 0;
|
|
border-bottom: 1px dashed var(--border);
|
|
}
|
|
|
|
.scalar .label {
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.scalar .value {
|
|
font-family: var(--mono);
|
|
font-size: 0.85rem;
|
|
text-align: right;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.scalar .unit {
|
|
color: var(--text-faint);
|
|
margin-left: 0.3rem;
|
|
}
|
|
|
|
/* Graph and charts */
|
|
|
|
.graph-canvas {
|
|
width: 100%;
|
|
/* The aspect of the layout space, so the drawing fills the canvas
|
|
instead of being letterboxed inside it. */
|
|
aspect-ratio: 2 / 1;
|
|
min-height: 20rem;
|
|
max-height: 46rem;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
display: block;
|
|
cursor: grab;
|
|
touch-action: none;
|
|
}
|
|
|
|
.graph-canvas:active {
|
|
cursor: grabbing;
|
|
}
|
|
|
|
.graph-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
flex-wrap: wrap;
|
|
margin: 0.75rem 0;
|
|
}
|
|
|
|
.legend {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.75rem;
|
|
margin-top: 0.5rem;
|
|
font-size: 0.78rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.legend span {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
}
|
|
|
|
.legend i {
|
|
width: 0.75rem;
|
|
height: 0.75rem;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
}
|
|
|
|
.chart {
|
|
width: 100%;
|
|
height: 14rem;
|
|
display: block;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
margin: 0.75rem 0;
|
|
}
|
|
|
|
/* Signature and code blocks */
|
|
|
|
.signature {
|
|
font-family: var(--mono);
|
|
font-size: 0.82rem;
|
|
background: var(--surface-raised);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-small);
|
|
padding: 0.5rem 0.7rem;
|
|
overflow-x: auto;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
}
|
|
|
|
.signature .kw {
|
|
color: var(--syntax-keyword);
|
|
}
|
|
|
|
.signature .ty {
|
|
color: var(--syntax-type);
|
|
}
|
|
|
|
.signature .fn {
|
|
color: var(--syntax-function);
|
|
}
|
|
|
|
.api-item {
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
background: var(--surface);
|
|
padding: 0.85rem 1rem;
|
|
margin-bottom: 0.6rem;
|
|
}
|
|
|
|
.api-item header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.6rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* The items of one crate, two to a row, so that a crate with dozens of
|
|
items stays a reasonable height. */
|
|
.item-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(min(28rem, 100%), 1fr));
|
|
gap: 0.6rem;
|
|
align-items: start;
|
|
}
|
|
|
|
.item-grid .api-item {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.api-item .name {
|
|
font-family: var(--mono);
|
|
font-size: 0.95rem;
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.api-item .doc {
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem;
|
|
margin: 0.5rem 0 0;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
/* A doc comment rendered as Markdown. The block spacing is tightened
|
|
because the comment is a fragment rather than a document. */
|
|
.api-doc {
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.api-doc p {
|
|
margin: 0.4rem 0;
|
|
}
|
|
|
|
.api-doc ul,
|
|
.api-doc ol {
|
|
margin: 0.4rem 0;
|
|
padding-left: 1.2rem;
|
|
}
|
|
|
|
.api-doc h1,
|
|
.api-doc h2,
|
|
.api-doc h3,
|
|
.api-doc h4 {
|
|
font-size: 0.9rem;
|
|
margin: 0.75rem 0 0.3rem;
|
|
color: var(--text);
|
|
}
|
|
|
|
.api-doc figure.code {
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
.api-doc figure.code figcaption {
|
|
display: none;
|
|
}
|
|
|
|
.api-doc .table-wrap {
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
/* A crate summary on the crate page */
|
|
|
|
.crate-summary {
|
|
color: var(--text-muted);
|
|
font-size: 0.9rem;
|
|
max-width: 60rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.crate-summary p {
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
/* A link to another interface item, rendered from a doc comment. */
|
|
.api-doc a.api-link,
|
|
.crate-summary a.api-link {
|
|
color: var(--accent);
|
|
border-bottom: 1px dotted var(--accent-strong);
|
|
}
|
|
|
|
/* The interface items a tool calls */
|
|
|
|
.calls {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 0.4rem;
|
|
margin-top: 0.9rem;
|
|
padding-top: 0.75rem;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.calls-label {
|
|
color: var(--text-faint);
|
|
font-size: 0.78rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
margin-right: 0.2rem;
|
|
}
|
|
|
|
/* The interface index */
|
|
|
|
.crate-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
|
|
gap: 0.75rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.crate-card {
|
|
display: block;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: 0.85rem 1rem;
|
|
color: var(--text);
|
|
}
|
|
|
|
.crate-card:hover {
|
|
border-color: var(--accent-strong);
|
|
background: var(--surface-raised);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.crate-card header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.crate-card .name {
|
|
font-family: var(--mono);
|
|
font-size: 0.95rem;
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.crate-card p {
|
|
margin: 0.5rem 0 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
/* The group heading on the document index, which separates the concepts
|
|
from the implementation. */
|
|
.docs-group-title {
|
|
padding-bottom: 0.4rem;
|
|
margin-bottom: 1rem;
|
|
border-bottom: 1px solid var(--border-strong);
|
|
color: var(--accent);
|
|
}
|
|
|
|
/* A subject within a layer, shown above the documents of that subject. */
|
|
.docs-subject {
|
|
margin: 1.5rem 0 0.5rem;
|
|
color: var(--text);
|
|
font-size: 0.95rem;
|
|
border-left: 2px solid var(--border-strong);
|
|
padding-left: 0.6rem;
|
|
}
|
|
|
|
.sidebar-subject {
|
|
font-size: 0.72rem;
|
|
color: var(--text-muted);
|
|
margin: 0.35rem 0 0.15rem 0.55rem;
|
|
padding-left: 0.45rem;
|
|
border-left: 2px solid var(--border);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* A tool in the tool index. The card is a link, so the whole area is the
|
|
target and the hover is the affordance. */
|
|
.tool-card {
|
|
color: var(--text);
|
|
}
|
|
|
|
.tool-card:hover {
|
|
border-color: var(--accent-strong);
|
|
background: var(--surface-raised);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.tool-card h4 {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.35rem;
|
|
margin: 0 0 0.35rem;
|
|
font-size: 0.98rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
/* The chevron marks the card as an entry point to a page of its own, which
|
|
is what a reader cannot otherwise tell from a heading. */
|
|
.tool-go {
|
|
color: var(--text-faint);
|
|
font-size: 1.05rem;
|
|
line-height: 1;
|
|
transition: transform 0.12s ease, color 0.12s ease;
|
|
}
|
|
|
|
.tool-card:hover .tool-go {
|
|
color: var(--accent);
|
|
transform: translateX(2px);
|
|
}
|
|
|
|
/* The form a tool opens, given room to breathe under the index. */
|
|
.tool-form {
|
|
scroll-margin-top: 4.5rem;
|
|
}
|
|
|
|
.tool-card p {
|
|
margin: 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.86rem;
|
|
}
|
|
|
|
.tool-card.selected {
|
|
border-color: var(--accent);
|
|
background: var(--accent-soft);
|
|
}
|
|
|
|
/* The table of contents beside a document. */
|
|
|
|
.toc-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
/* A deeper heading is indented, so the levels of the document are visible
|
|
without reading the text. */
|
|
.toc-item {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.15rem;
|
|
margin: 0.1rem 0;
|
|
}
|
|
|
|
.toc-item.level-3 {
|
|
padding-left: 0.85rem;
|
|
}
|
|
|
|
.toc-item.level-4 {
|
|
padding-left: 1.7rem;
|
|
}
|
|
|
|
.toc-item.level-5,
|
|
.toc-item.level-6 {
|
|
padding-left: 2.55rem;
|
|
}
|
|
|
|
.toc-toggle {
|
|
flex: 0 0 auto;
|
|
width: 1rem;
|
|
height: 1rem;
|
|
padding: 0;
|
|
border: none;
|
|
background: none;
|
|
color: var(--text-faint);
|
|
font-size: 0.7rem;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
transition: transform 0.12s ease;
|
|
}
|
|
|
|
.toc-toggle.collapsed {
|
|
transform: rotate(-90deg);
|
|
}
|
|
|
|
.toc-toggle:hover {
|
|
color: var(--accent);
|
|
background: none;
|
|
}
|
|
|
|
.toc-link {
|
|
color: var(--text-muted);
|
|
font-size: 0.85rem;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* A row of links that wrap, used for the item filter results. */
|
|
.chip-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.4rem;
|
|
margin-top: 0.85rem;
|
|
}
|
|
|
|
.chip {
|
|
display: inline-flex;
|
|
align-items: baseline;
|
|
gap: 0.4rem;
|
|
background: var(--surface-raised);
|
|
border: 1px solid var(--border);
|
|
border-radius: 999px;
|
|
padding: 0.2rem 0.7rem;
|
|
font-family: var(--mono);
|
|
font-size: 0.78rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.chip:hover {
|
|
border-color: var(--accent-strong);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.chip-note {
|
|
color: var(--text-faint);
|
|
font-size: 0.72rem;
|
|
}
|
|
|
|
.kind {
|
|
font-family: var(--mono);
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
padding: 0.05rem 0.4rem;
|
|
border-radius: var(--radius-small);
|
|
background: var(--surface-raised);
|
|
border: 1px solid var(--border-strong);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Tool forms */
|
|
|
|
.form-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
|
|
gap: 0.9rem 1.25rem;
|
|
}
|
|
|
|
.field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.field.wide {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.field label {
|
|
font-size: 0.82rem;
|
|
color: var(--text-muted);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.field .help {
|
|
font-size: 0.75rem;
|
|
color: var(--text-faint);
|
|
}
|
|
|
|
.field .unit {
|
|
font-size: 0.72rem;
|
|
color: var(--text-faint);
|
|
font-family: var(--mono);
|
|
}
|
|
|
|
.field.invalid input,
|
|
.field.invalid textarea,
|
|
.field.invalid select {
|
|
border-color: var(--negative);
|
|
}
|
|
|
|
.spinner {
|
|
display: inline-block;
|
|
width: 0.85rem;
|
|
height: 0.85rem;
|
|
border: 2px solid var(--border-strong);
|
|
border-top-color: var(--accent);
|
|
border-radius: 50%;
|
|
animation: spin 0.7s linear infinite;
|
|
vertical-align: -0.1rem;
|
|
margin-right: 0.4rem;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Formulas.
|
|
*
|
|
* The output is MathML, which the browser sets itself, so only the container
|
|
* needs styling: the family to read in, and the room a display formula takes.
|
|
* `math` inherits the surrounding colour, so a formula follows the theme
|
|
* without a second set of variables.
|
|
*/
|
|
.math {
|
|
/* The browser's default math font is fine on a dark background and thin on
|
|
a light one, so the family is only suggested and the browser may use its
|
|
own. */
|
|
font-size: 1.02em;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.math-display {
|
|
display: block;
|
|
margin: 1.1rem 0;
|
|
/* A formula is centred on its own, as a formula rather than as a line of
|
|
prose. Overflow scrolls rather than being clipped, because a long
|
|
formula stays readable when it can be scrolled and disappears when it
|
|
cannot. */
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
text-align: center;
|
|
}
|
|
|
|
:root[data-theme='light'] .math {
|
|
/* On a light background the browser's math font is thin, so it is asked
|
|
for a slightly heavier weight to match the text around it. */
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* The drawer toggle. It is only useful while the sidebar is a drawer, so it
|
|
is hidden by default and the narrow-screen rule below reveals it. */
|
|
.menu-button {
|
|
display: none;
|
|
}
|
|
|
|
/* Responsive */
|
|
|
|
@media (max-width: 1180px) {
|
|
.grid.cards {
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
}
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.grid.cards {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
}
|
|
|
|
@media (max-width: 700px) {
|
|
/* The counters are a summary, not navigation, so they are the first
|
|
thing to go when the bar is tight. */
|
|
.topbar .badge {
|
|
display: none;
|
|
}
|
|
|
|
.topbar {
|
|
padding: 0.6rem 1rem;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Below this width there is no room for a sidebar beside the page, so the
|
|
* sidebar becomes a drawer that covers the page and is opened from the top
|
|
* bar. It is a drawer rather than a stacked block because a block would push
|
|
* the page down by half the screen, and the navigation is long.
|
|
*
|
|
* The drawer is a normal element rather than a dialog because it holds no
|
|
* state to trap and no action to confirm; what it does need is to be
|
|
* dismissible, which the overlay and the close button both do.
|
|
*/
|
|
@media (max-width: 960px) {
|
|
.app {
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* The sidebar is a drawer here, so the button that opens it is needed. */
|
|
.menu-button {
|
|
display: inline-flex;
|
|
}
|
|
|
|
/* The frame holds the width of the sidebar beside the page. Once the
|
|
sidebar is a drawer the frame has nothing to hold, and left in the flow
|
|
it would push the page down by its own width. */
|
|
.sidebar-frame {
|
|
flex: 0 0 auto;
|
|
width: 0;
|
|
height: 0;
|
|
border-right: none;
|
|
background: none;
|
|
overflow: visible;
|
|
}
|
|
|
|
.sidebar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
width: min(20rem, 84vw);
|
|
/* The frame that carried the background is empty in this layout, so the
|
|
drawer carries it itself; without this the page shows through it. */
|
|
background: var(--surface);
|
|
border-right: 1px solid var(--border);
|
|
max-width: none;
|
|
height: 100dvh;
|
|
z-index: 40;
|
|
/* The drawer sits over the page, so it needs its own edge to lift it
|
|
off the content behind it. */
|
|
box-shadow: var(--shadow);
|
|
/* Closed by default on a narrow screen; the open class is set by the
|
|
top bar button. */
|
|
transform: translateX(-100%);
|
|
transition: transform 160ms ease;
|
|
}
|
|
|
|
.sidebar.open {
|
|
transform: translateX(0);
|
|
}
|
|
|
|
/* Tapping outside the drawer dismisses it. It covers the page, so it is
|
|
placed below the drawer and above the page. */
|
|
.sidebar-scrim {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 30;
|
|
background: var(--scrim);
|
|
border: none;
|
|
padding: 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.content {
|
|
padding: 1.25rem 1rem 3rem;
|
|
}
|
|
|
|
.doc-layout {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.doc-layout.no-toc {
|
|
max-width: none;
|
|
}
|
|
|
|
.doc-toc {
|
|
position: static;
|
|
max-height: none;
|
|
width: 100%;
|
|
border-left: none;
|
|
border-top: 1px solid var(--border);
|
|
padding-left: 0;
|
|
padding-top: 0.75rem;
|
|
}
|
|
}
|