/* steward/static/steward.css — Steward's base stylesheet. * * Values come from theme.css, the stylesheet design system 6 ("Steward", * inheriting FabledSword) generates. The short names below are Steward's * aliases onto those tokens, kept so templates written against them still * render; new work writes the --fs-* token. Contrast is a CI guard * (tests/test_contrast.py): text 4.5:1 and control outlines 3:1 on page, * card and hover, and status text on its own tint over each of them. */ :root { --bg: var(--fs-surface-page); --bg-card: var(--fs-surface-raised); --bg-elevated: var(--fs-surface-hover); --border: color-mix(in srgb, var(--fs-border-color) 70%, var(--fs-surface-raised)); --border-mid: var(--fs-border-color); /* The outline that marks a control (input, select, ghost button): 3:1 on page, card and hover (WCAG 1.4.11), where --border-mid is ~1.4-1.9:1. */ --border-control: color-mix(in srgb, var(--fs-text-secondary) 45%, var(--fs-border-color)); --text: var(--fs-text-primary); --text-muted: var(--fs-text-secondary); --text-dim: var(--fs-text-tertiary); --gold: var(--fs-accent); --gold-hover: color-mix(in srgb, var(--fs-accent) 85%, var(--fs-text-primary)); --gold-dim: var(--fs-accent-soft); --accent: var(--fs-accent); --accent-hover: var(--gold-hover); /* Status: the -fg colour is the text and indicator; the -dim tint sits behind it. Warning, error and their mix are lifted toward the primary text: the house -fg falls to ~4.0:1 on its own tint over a hovered row (#5096). */ --green: var(--fs-success-fg); --green-dim: color-mix(in srgb, var(--fs-success) 20%, transparent); --yellow: color-mix(in srgb, var(--fs-warning-fg) 85%, var(--fs-text-primary)); --yellow-dim: color-mix(in srgb, var(--fs-warning) 20%, transparent); /* Between warning and error: the worse-than-warning band (slow, degraded). */ --orange: color-mix(in srgb, color-mix(in srgb, var(--fs-warning-fg) 50%, var(--fs-error-fg)) 82%, var(--fs-text-primary)); --orange-dim: color-mix(in srgb, var(--fs-warning) 20%, transparent); --red: color-mix(in srgb, var(--fs-error-fg) 85%, var(--fs-text-primary)); --red-dim: color-mix(in srgb, var(--fs-error) 20%, transparent); /* Info (acknowledged): lighter than the house --fs-info-fg (50%), which falls to 4.18:1 on its tint over a hovered row; 40% holds 5.09:1 there. */ --blue: color-mix(in srgb, var(--fs-info) 40%, var(--fs-text-primary)); --blue-dim: color-mix(in srgb, var(--fs-info) 20%, transparent); --font-serif: var(--fs-font-display); } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: var(--fs-font-body); background: var(--bg); color: var(--text); line-height: var(--fs-leading-body); } a { color: var(--accent); text-decoration: none; } a:hover { color: var(--accent-hover); } code { font-family: var(--fs-font-mono); font-size: 0.875em; background: var(--bg-elevated); padding: 0.1em 0.35em; border-radius: 3px; } #candle-glow { position: fixed; inset: 0; pointer-events: none; z-index: 0; background: radial-gradient(ellipse 80% 60% at 50% 40%, color-mix(in srgb, var(--fs-accent) 4.5%, transparent) 0%, transparent 70%), radial-gradient(ellipse 50% 40% at 20% 80%, color-mix(in srgb, var(--fs-accent) 2.5%, transparent) 0%, transparent 65%); } /* ── App shell: persistent left sidebar + content column ───────────────────── */ .app-shell { display: flex; min-height: 100vh; position: relative; z-index: 1; } .sidebar { width: 220px; flex-shrink: 0; background: var(--bg-card); border-right: 1px solid var(--border-mid); display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; z-index: 20; } .sidebar .brand { font-family: var(--font-serif); font-weight: 500; font-size: 1.15rem; letter-spacing: 0.01em; color: var(--gold); text-decoration: none; display: flex; align-items: center; gap: 0.5rem; padding: 0.85rem 1.25rem; border-bottom: 1px solid var(--border); } .sidebar .brand img { flex-shrink: 0; } /* Only the nav list scrolls when long — the brand and user/logout stay pinned. */ .side-nav { flex: 1; min-height: 0; overflow-y: auto; padding: 0.75rem 0; } .nav-group { margin-bottom: 0.9rem; } .nav-group-label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-dim); font-weight: 500; padding: 0 1.25rem; margin-bottom: 0.3rem; } .side-nav a { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 1.25rem; font-size: 0.9rem; color: var(--text-muted); border-left: 2px solid transparent; text-decoration: none; transition: color .12s, background .12s, border-color .12s; } .side-nav a:hover { color: var(--text); background: var(--bg-elevated); } .side-nav a.active { color: var(--gold); border-left-color: var(--gold); background: color-mix(in srgb, var(--gold) 8%, transparent); } /* A small count that needs attention: alerts beside the Alerts link, UniFi alarms. */ .count-badge { margin-left: auto; padding: 0 0.45em; border-radius: var(--fs-radius-sm); background: var(--red-dim); color: var(--red); font-size: 0.75rem; font-weight: 500; font-variant-numeric: tabular-nums; } .side-user { border-top: 1px solid var(--border); padding: 0.7rem 1.25rem; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; } .side-user form { margin: 0; } .side-user a { color: var(--text-muted); font-size: 0.84rem; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .side-user a:hover, .side-user a[aria-current="page"] { color: var(--text); } .side-user button { color: var(--text-muted); font-size: 0.84rem; text-decoration: none; display: flex; align-items: center; gap: 0.4rem; background: none; border: 0; padding: 0; font-family: inherit; cursor: pointer; } .side-user button:hover { color: var(--text); } /* Keyboard focus: a clear inset ring on every interactive sidebar element. */ .sidebar .brand:focus-visible, .side-nav a:focus-visible, .side-user button:focus-visible, .side-user a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; color: var(--text); } .app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; } .topbar { display: none; } /* slim mobile bar; shown only under 900px */ .nav-scrim { display: none; } /* Layout */ main { padding: 1.5rem 2rem; max-width: 1400px; margin: 0 auto; width: 100%; min-width: 0; box-sizing: border-box; position: relative; z-index: 1; } /* The dashboard keeps a cap too, a wider one: past 12 columns' worth it adds grid columns rather than stretching widgets (static/dash-layout.js). */ main.main-wide { max-width: 2400px; } /* Responsive: sidebar slides off-canvas under 900px, toggled by ☰ */ @media (max-width: 900px) { .sidebar { position: fixed; left: 0; top: 0; bottom: 0; height: 100%; transform: translateX(-100%); transition: transform .2s ease; box-shadow: var(--fs-shadow-3); } body.nav-open .sidebar { transform: translateX(0); } .topbar { display: flex; align-items: center; gap: 0.75rem; height: 48px; padding: 0 1rem; background: var(--bg-card); border-bottom: 1px solid var(--border-mid); position: sticky; top: 0; z-index: 15; } .sidebar-toggle { background: none; border: none; color: var(--text-muted); font-size: 1.3rem; cursor: pointer; line-height: 1; padding: 0.25rem; border-radius: 4px; } .sidebar-toggle:hover { color: var(--text); } .sidebar-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .topbar .brand-sm { font-family: var(--font-serif); color: var(--gold); font-weight: 500; font-size: 1.15rem; text-decoration: none; } body.nav-open .nav-scrim { display: block; position: fixed; inset: 0; background: var(--fs-overlay); z-index: 18; } } @media (prefers-reduced-motion: reduce) { .sidebar { transition: none; } .side-nav a { transition: none; } } /* Alerts */ .alert { padding: 0.75rem 1rem; border-radius: 6px; margin-bottom: 1rem; font-size: 0.9rem; } .alert-error { background: var(--red-dim); border: 1px solid color-mix(in srgb, var(--fs-error) 45%, transparent); color: var(--red); } .alert-success { background: var(--green-dim); border: 1px solid color-mix(in srgb, var(--fs-success) 60%, transparent); color: var(--green); } /* Cards */ .card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; margin-bottom: 1rem; } .card-flush { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; overflow-x: auto; overflow-y: hidden; margin-bottom: 1rem; } /* A table wider than the screen scrolls sideways inside its card instead of widening the page at phone width. Any card holding a table does this, so no page has to remember a wrapper; .table-wrap is for a table outside a card. (Only cards with a table: a plain card can hold a popover that must not clip.) */ .card:has(table.table) { overflow-x: auto; } .table-wrap { overflow-x: auto; } /* Typography */ .page-title { font-family: var(--font-serif); font-size: 1.6rem; font-weight: 500; color: var(--text); line-height: var(--fs-leading-heading); margin-bottom: 1.5rem; } /* The tiny micro-label: body face (display face only at 18px and up), caps, tracked. */ .section-title { font-family: var(--fs-font-body); font-size: var(--fs-size-tiny); font-weight: 500; color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--fs-tracking-tiny); } h1, h2 { font-family: var(--font-serif); font-weight: 500; } h3, h4 { font-family: var(--fs-font-body); font-weight: 500; } strong, b, th { font-weight: 500; } /* Tables */ .table { width: 100%; border-collapse: collapse; } .table th { text-align: left; padding: 0.6rem 1rem; color: var(--text-muted); font-weight: 500; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; border-bottom: 1px solid var(--border-mid); } .table td { padding: 0.7rem 1rem; border-bottom: 1px solid var(--border); font-size: 0.9rem; } /* The table's last row has no rule under it; a table may have several tbodys (the Alerts list: one per rule, its hosts in another, maybe hidden). */ .table tbody:last-child tr:last-child td, .table tbody:has(+ tbody[hidden]:last-child) tr:last-child td { border-bottom: none; } .table tbody tr:hover td { background: var(--bg-elevated); } .table .td-actions { text-align: right; white-space: nowrap; } /* A header that sorts its column (sort_th in _macros.html): reads as the header it is, with the arrow on the current sort. */ .sort-link { color: inherit; text-decoration: none; } .sort-link:hover, .sort-active { color: var(--text); } .sort-arrow { display: inline-block; min-width: 0.9em; text-align: center; } /* Search and filters above a list; the search box takes the spare width. */ .filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem; } .filter-bar input[type=search] { flex: 1 1 16rem; width: auto; } .filter-bar select { width: auto; flex: 0 0 auto; } .page-actions .filter-bar { margin: 0; } /* A small label that links somewhere, such as a group that filters the list. */ .chip { display: inline-block; margin: 0.1rem 0.3rem 0.1rem 0; padding: 0.05rem 0.45rem; font-size: 0.75rem; color: var(--text-muted); border: 1px solid var(--border); border-radius: var(--fs-radius-sm); white-space: nowrap; } .chip:hover { color: var(--text); border-color: var(--border-mid); } /* A table's own heading inside its .card-flush: the name, a count and a link. */ .table-caption { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; margin: 0; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border-mid); font-family: var(--fs-font-body); font-size: 0.95rem; font-weight: 500; } .table-caption .field-hint { margin-left: auto; } /* A name cell cut short with "…", whole on hover (its title); a second line under it; an image reference, long by nature, cut the same way. */ .cell-name { max-width: 18rem; } .cell-name > a { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .cell-sub { font-size: 0.75rem; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .table td.cell-image { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.8rem; color: var(--text-muted); } /* The Docker page's one-line answer, above its tiles (#5298). */ .page-verdict { margin: 0 0 0.75rem; font-size: 0.95rem; } .table tr.row-off > td { opacity: 0.55; } /* A covering alert rule's per-host rules (#5464), indented on a sunken band under it, opened by its "N hosts" toggle (#5483). */ .table tr.row-child:not(:hover) > td { background: var(--bg); } .table tr.row-child .cell-name { padding-left: 2rem; } .row-toggle { background: none; border: 0; padding: 0; font: inherit; color: var(--text-muted); cursor: pointer; text-decoration: underline dotted; text-underline-offset: 2px; } .row-toggle::before { content: "▸"; display: inline-block; margin-right: 0.25rem; transition: transform var(--fs-dur-fast) var(--fs-ease); } .row-toggle[aria-expanded="true"]::before { transform: rotate(90deg); } .row-toggle:hover { color: var(--text); } .row-toggle:focus-visible { outline: none; box-shadow: var(--fs-focus-ring); border-radius: var(--fs-radius-sm); } /* The rule form's metric preview (#5475): now, then the last day beside its sparkline. */ .metric-preview { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 1rem; margin-top: 0.4rem; font-size: 0.85rem; } .metric-preview-day { display: inline-flex; align-items: center; gap: 0.4rem; } .metric-preview-spark { color: var(--text-muted); line-height: 0; } /* A row that opens as a whole: its one .row-target link stretches over the row, and the actions cell sits above it so its buttons keep their own clicks. One real link per row, so keyboard and screen readers meet it once. */ .table tr.row-link { position: relative; cursor: pointer; } .table tr.row-link .row-target::after { content: ""; position: absolute; inset: 0; } .table tr.row-link .td-actions { position: relative; z-index: 1; cursor: auto; } /* A second link inside a row that opens as a whole: it sits above the row's target. */ .table tr.row-link .row-inner { position: relative; z-index: 1; } .table td.nowrap { white-space: nowrap; } /* An audit entry's details, one fact a line (milestone 490). */ .audit-facts { font-size: 0.8rem; color: var(--text-muted); } /* A divider row naming the group the rows under it fall in (Today, Older). */ /* A day group's divider reads above its rows: the primary text on a raised band, where column headers are muted on the card (#5214). Not the accent: that stays off chrome, and Steward's amber sits near its warning. */ .table tr.table-divider th { padding: 0.55rem 1rem; color: var(--text); background: var(--bg-elevated); border-top: 1px solid var(--border-mid); border-bottom: 1px solid var(--border-mid); } .table tbody tr.table-divider:hover th { background: var(--bg-elevated); } .cell-note { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.2rem; } /* An alert episode's own transitions, folded under it (#5316). */ .episode-steps { margin-top: 0.3rem; font-size: 0.8rem; } .episode-steps summary { cursor: pointer; color: var(--text-muted); } .episode-steps ol { margin: 0.35rem 0 0; padding-left: 1.1rem; display: grid; gap: 0.25rem; } /* A problem section's heading carries its own count, so no tile repeats it (#5214). */ .section-count { margin-bottom: 0.6rem; } .section-count > span:first-child { margin-left: 0.25rem; } /* A service's resource history: CPU and memory side by side, each a figure over a line that spans its half (docker/_usage_history.html). */ .history-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 1.25rem; } .history-pair .spark { color: var(--blue); margin-top: 0.4rem; } /* The Swarm page (#5303): one card per node, two or three a row on a wide screen; each card's own services table. */ .swarm-group { margin-bottom: 2rem; } .node-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr)); gap: 1rem; align-items: start; } .node-card { margin-bottom: 0; display: flex; flex-direction: column; gap: 0.6rem; } .node-card-head { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; margin: 0; font-family: var(--fs-font-body); font-size: 1rem; font-weight: 500; } .node-card-head .chip { margin: 0; } .node-card-figures { margin: 0; font-size: 0.85rem; } .node-tasks th, .node-tasks td { padding: 0.35rem 0.5rem; font-size: 0.82rem; } .node-tasks .cell-name { max-width: 12rem; } .node-tasks .cell-name > a { display: inline-block; max-width: 100%; vertical-align: bottom; } /* The Docker overview's one line per host of disk (#5306). */ .docker-disk-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem 1.25rem; margin: 0 0 1rem; font-size: 0.85rem; } .docker-disk-host { white-space: nowrap; } /* The Disk page (#5304, #5305): a section per host; images by repository, each repository's versions folded under it. */ .disk-host { margin: 2rem 0; } .disk-host-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.6rem; margin: 0 0 0.75rem; font-family: var(--fs-font-body); font-size: 1.05rem; font-weight: 500; } .disk-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 1rem; } .disk-actions form { margin: 0; } .image-repos .cell-name { max-width: 28rem; } .image-repos summary { cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .image-repos details[open] summary { margin-bottom: 0.5rem; } .image-versions th, .image-versions td { padding: 0.3rem 0.5rem; font-size: 0.8rem; } /* Forms */ .form-group { margin-bottom: 1rem; } label { display: block; margin-bottom: 0.3rem; font-size: 0.85rem; color: var(--text-muted); font-family: var(--fs-font-body); } input[type=text], input[type=search], input[type=email], input[type=password], input[type=number], input[type=url], select, textarea { width: 100%; padding: 0.5rem 0.75rem; background: var(--bg); border: 1px solid var(--border-control); border-radius: 5px; color: var(--text); font-size: 0.9rem; font-family: inherit; transition: border-color .15s; } input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); } /* Keyboard focus is always visible: the design system's ring on anything that takes focus. */ a:focus-visible, button:focus-visible, summary:focus-visible, [tabindex]:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: none; box-shadow: var(--fs-focus-ring); } select { cursor: pointer; } textarea { resize: vertical; } /* Form fields: .field wraps a .field-label, the .input and an optional .field-hint. */ .field { display: flex; flex-direction: column; gap: 0.2rem; margin-bottom: 0.9rem; } .field[hidden] { display: none; } .field-label { display: block; margin-bottom: 0; font-size: 0.75rem; color: var(--text-muted); } .field-hint { font-size: 0.75rem; color: var(--text-dim); } .field-error { font-size: 0.85rem; color: var(--red); margin-bottom: 0.75rem; } .input { width: 100%; padding: 0.4rem 0.65rem; background: var(--bg); border: 1px solid var(--border-control); border-radius: var(--fs-radius-sm); color: var(--text); font-size: 0.88rem; font-family: inherit; } .input:focus { outline: none; border-color: var(--accent); } .input:disabled { opacity: var(--fs-disabled-opacity); } /* Buttons */ .btn { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.45rem 1rem; background: var(--accent); color: var(--fs-surface-page); border: none; border-radius: 5px; cursor: pointer; font-size: 0.875rem; font-family: inherit; font-weight: 500; transition: background .15s; text-decoration: none; } .btn:hover { background: var(--accent-hover); color: var(--fs-surface-page); } .btn-sm { padding: 0.3rem 0.65rem; font-size: 0.8rem; } .btn-icon { padding: 0.3rem 0.5rem; line-height: 1; } .btn-ghost { background: transparent; color: var(--text-muted); border: 1px solid var(--border-control); } .btn-ghost:hover { background: var(--bg-elevated); color: var(--text); } .btn-danger { background: var(--fs-action-destructive); color: var(--fs-text-on-action); } .btn-danger:hover { background: var(--fs-action-destructive-hover); color: var(--fs-text-on-action); } .btn-warn { background: var(--yellow-dim); color: var(--yellow); border: 1px solid color-mix(in srgb, var(--fs-warning) 60%, transparent); } .btn-warn:hover { background: color-mix(in srgb, var(--fs-warning) 32%, transparent); } /* Badges / Status */ .badge { display: inline-block; padding: 0.2em 0.55em; border-radius: var(--fs-radius-sm); font-size: 0.75rem; font-weight: 500; letter-spacing: 0.02em; } .badge-green { background: var(--green-dim); color: var(--green); } .badge-red { background: var(--red-dim); color: var(--red); } .badge-yellow { background: var(--yellow-dim); color: var(--yellow); } .badge-orange { background: var(--orange-dim); color: var(--orange); } .badge-gold { background: var(--gold-dim); color: var(--fs-accent-fg); } .badge-dim { background: var(--bg-elevated); color: var(--text-muted); } .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .dot-up { background: var(--green); box-shadow: 0 0 4px var(--green); } .dot-down { background: var(--red); } .dot-warn { background: var(--yellow); } .dot-dim { background: var(--text-dim); } /* Tones the status_badge / status_dot macros draw (formatting.STATES). */ .badge-ok { background: var(--green-dim); color: var(--green); } .badge-warn { background: var(--yellow-dim); color: var(--yellow); } .badge-crit { background: var(--red-dim); color: var(--red); } .badge-info { background: var(--blue-dim); color: var(--blue); } .dot-ok { background: var(--green); } .dot-crit { background: var(--red); } .dot-info { background: var(--blue); } .dot-label { margin-left: 0.35rem; font-size: 0.85rem; } /* Text in a tone: status_class() results ('ok' / 'warn' / 'crit' / 'unknown') and the STATES tones. */ .tone-ok { color: var(--green); } .tone-warn { color: var(--yellow); } .tone-crit { color: var(--red); } .tone-info { color: var(--blue); } .tone-dim, .tone-unknown { color: var(--text-dim); } .tone-muted { color: var(--text-muted); } /* A figure column in a table: right-aligned, digits of equal width so the numbers line up down the column without a monospace face (#5279). */ .table th.num, .table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } /* Empty state */ .empty { color: var(--text-muted); font-size: 0.9rem; padding: 2rem; text-align: center; } .empty-state { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; color: var(--text-muted); font-size: 0.9rem; padding: 2rem 1rem; text-align: center; } /* Page header: title on the left, its actions on the right (page_header macro). */ .page-header { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: 0.75rem 1rem; margin-bottom: 1.5rem; } .page-header .page-title { margin-bottom: 0; } .page-subtitle { margin-top: 0.3rem; color: var(--text-muted); font-size: 0.9rem; } .page-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; } /* Stat tile (stat_tile macro): a label over one headline number. */ .stat-tile { display: flex; flex-direction: column; gap: 0.25rem; padding: 0.9rem 1rem; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--fs-radius-md); color: var(--text); min-width: 8rem; } a.stat-tile:hover { border-color: var(--border-mid); background: var(--bg-elevated); color: var(--text); } .stat-tile-label { font-size: var(--fs-size-tiny); font-weight: 500; color: var(--text-muted); text-transform: uppercase; letter-spacing: var(--fs-tracking-tiny); } .stat-tile-value { font-size: 1.6rem; font-weight: 500; line-height: 1.1; font-variant-numeric: tabular-nums; } .stat-tile-hint { font-size: 0.78rem; color: var(--text-dim); } .stat-ok .stat-tile-value { color: var(--green); } .stat-warn .stat-tile-value { color: var(--yellow); } .stat-crit .stat-tile-value { color: var(--red); } .stat-info .stat-tile-value { color: var(--blue); } .stat-dim .stat-tile-value { color: var(--text-dim); } .stat-strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: 0.75rem; margin-bottom: 1rem; } /* "Needs attention": what is wrong, first on a page. */ .problem-card { border-color: color-mix(in srgb, var(--fs-error) 45%, var(--border)); } .problem-list { list-style: none; display: flex; flex-direction: column; gap: 0.45rem; } .problem-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.6rem; overflow-wrap: anywhere; } /* A section's pages as tabs (section_tabs in _macros.html, #5328). It scrolls inside itself on a phone rather than widening the page. */ .section-tabs { display: flex; gap: 0.25rem; margin: 0 0 1.25rem; border-bottom: 1px solid var(--border); overflow-x: auto; } .section-tabs a { padding: 0.5rem 0.9rem; margin-bottom: -1px; border-bottom: 2px solid transparent; color: var(--text-muted); font-size: 0.9rem; white-space: nowrap; } .section-tabs a:hover { color: var(--text); } .section-tabs a[aria-current="page"] { color: var(--text); border-bottom-color: var(--accent); } /* A label/value list: