apsis-book/frontend/src/app.css

1364 lines
24 KiB
CSS

/*
* The visual design of the service.
*
* The palette is a single dark theme. Colour carries meaning in the graph
* and in the tables, so the variables are named by role rather than by hue.
*/
: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;
--group-overview: #7fd1ff;
--group-time: #b8a2ff;
--group-geometry: #5fd39a;
--group-elements: #e8c26a;
--group-propagation: #f28b82;
--group-methods: #93a2b8;
--group-input: #93a2b8;
--group-prepare: #b8a2ff;
--group-branch: #e8c26a;
--group-propagate: #7fd1ff;
--group-verify: #5fd39a;
--group-fields: #5fd39a;
--group-crosscheck: #e8c26a;
--group-error: #f28b82;
--group-output: #5fd39a;
--group-validate: #b8a2ff;
--group-convert: #7fd1ff;
--group-store: #b8a2ff;
--group-frames: #5fd39a;
--group-rotate: #7fd1ff;
--group-geodetic: #e8c26a;
--radius: 8px;
--radius-small: 5px;
--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
--sidebar-width: 19rem;
--toc-width: 15rem;
}
* {
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;
}
.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;
}
.sidebar-chapter {
margin-bottom: 0.5rem;
}
/* The chapter head is a row: the title is a link to the chapter listing
and the chevron folds the group. They sit apart so the two do not look
like one control. */
.sidebar-chapter-head {
display: flex;
align-items: center;
gap: 0.1rem;
margin-bottom: 0.15rem;
padding-left: 0.35rem;
border-left: 2px solid var(--border-strong);
}
.sidebar-chapter-title {
flex: 1 1 auto;
font-size: 0.78rem;
color: var(--text);
margin: 0;
font-weight: 700;
letter-spacing: 0.02em;
text-transform: uppercase;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sidebar-chapter-title:hover {
color: var(--accent);
text-decoration: none;
}
.sidebar-chapter-toggle {
flex: 0 0 auto;
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: rgba(11, 15, 23, 0.9);
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: #04121c;
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;
}
.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(11rem, 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: rgba(232, 194, 106, 0.1);
}
.notice.error {
border-color: var(--negative);
background: rgba(242, 139, 130, 0.1);
}
.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;
}
.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: rgba(127, 209, 255, 0.04);
}
/* Scalars */
.scalars {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(15rem, 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: #c792ea;
}
.signature .ty {
color: #82aaff;
}
.signature .fn {
color: #7fd1ff;
}
.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(28rem, 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(20rem, 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;
}
/* 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(16rem, 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);
}
}
/* 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;
}
}
@media (max-width: 960px) {
.app {
flex-direction: column;
}
.sidebar {
width: 100%;
flex: none;
height: auto;
position: relative;
max-height: 45vh;
}
.doc-layout {
flex-direction: column;
}
.doc-toc {
position: relative;
top: 0;
width: 100%;
flex: none;
max-height: none;
}
.content {
padding: 1.25rem 1rem 3rem;
}
}