2026-08-14 09:40:03 +12:00
|
|
|
|
/* One vocabulary for the whole console.
|
|
|
|
|
|
Every screen is built from the components below — card, tile, field, tag, table, list.
|
|
|
|
|
|
A page that needs a look of its own is a missing component, not a licence for a style
|
|
|
|
|
|
attribute: there are no inline styles in the page components, on purpose, and no CSS
|
|
|
|
|
|
modules either. One stylesheet, read top to bottom, is what a strict no-dependency
|
|
|
|
|
|
console has instead of a design system nobody can see the whole of.
|
|
|
|
|
|
|
|
|
|
|
|
The palette takes its cues from GitHub's dark interface: near-black chrome, a cool
|
|
|
|
|
|
charcoal work area, restrained borders and one deliberate green for live or primary
|
|
|
|
|
|
actions. An operator can scan dense operational data without the interface competing
|
|
|
|
|
|
for attention.
|
|
|
|
|
|
|
|
|
|
|
|
The console is darker than the television app rather than lighter. What makes a card
|
|
|
|
|
|
hard to find is not the darkness of the page behind it but the absence of anything
|
|
|
|
|
|
*between* them — so the page drops to near-black and the separation is done properly,
|
|
|
|
|
|
by a card that sits a measurable step above it and a hairline visible on a bad monitor.
|
|
|
|
|
|
Four steps, and they are the whole scale: page, card, raised (a control), high (a
|
|
|
|
|
|
control under the pointer). A fifth value is a decision that has not been made yet.
|
|
|
|
|
|
|
|
|
|
|
|
The accent is spent only on what is live, selected or primary. Beside it are three
|
|
|
|
|
|
secondary tones with no verdict attached — info (blue), note (violet), data (teal) —
|
|
|
|
|
|
which is what lets a page distinguish one kind of thing from another without every
|
|
|
|
|
|
coloured element reading as a warning. Green means good, amber means look, red means
|
|
|
|
|
|
wrong; the other three mean nothing at all, which is the point. A tone is passed, never
|
|
|
|
|
|
derived: the library is teal, a person violet, a television blue, on every page. */
|
|
|
|
|
|
|
|
|
|
|
|
:root {
|
|
|
|
|
|
color-scheme: dark;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
--oled: #000;
|
|
|
|
|
|
--bg: #080b10;
|
|
|
|
|
|
--rail-bg: var(--oled);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
--top-bg: rgba(1, 4, 9, 0.94);
|
|
|
|
|
|
--surface: #0d1117;
|
|
|
|
|
|
--surface-lift: #161b22;
|
|
|
|
|
|
--surface-hi: #21262d;
|
|
|
|
|
|
--line: #30363d;
|
|
|
|
|
|
--line-soft: #21262d;
|
|
|
|
|
|
--text: #f0f6fc;
|
|
|
|
|
|
--muted: #b1bac4;
|
|
|
|
|
|
--quiet: #7d8590;
|
|
|
|
|
|
--accent: #2ea043;
|
|
|
|
|
|
--accent-ink: #56d364;
|
|
|
|
|
|
--accent-wash: rgba(46, 160, 67, 0.16);
|
|
|
|
|
|
--danger: #e5534b;
|
|
|
|
|
|
--danger-ink: #ff9b94;
|
|
|
|
|
|
--danger-wash: rgba(229, 83, 75, 0.13);
|
|
|
|
|
|
--warn: #e0ad4e;
|
|
|
|
|
|
--warn-ink: #f2cb78;
|
|
|
|
|
|
--warn-wash: rgba(239, 196, 107, 0.13);
|
|
|
|
|
|
--info: #4f9cd8;
|
|
|
|
|
|
--info-ink: #93cbef;
|
|
|
|
|
|
--info-wash: rgba(79, 156, 216, 0.14);
|
|
|
|
|
|
--note: #a07ce8;
|
|
|
|
|
|
--note-ink: #bda1f5;
|
|
|
|
|
|
--note-wash: rgba(160, 124, 232, 0.14);
|
|
|
|
|
|
--data: #3fc2b6;
|
|
|
|
|
|
--data-ink: #6fdcd0;
|
|
|
|
|
|
--data-wash: rgba(63, 194, 182, 0.13);
|
|
|
|
|
|
--rail: 236px;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
--safe-top: env(safe-area-inset-top, 0px);
|
|
|
|
|
|
--safe-right: env(safe-area-inset-right, 0px);
|
|
|
|
|
|
--safe-bottom: env(safe-area-inset-bottom, 0px);
|
|
|
|
|
|
--safe-left: env(safe-area-inset-left, 0px);
|
|
|
|
|
|
--top: calc(58px + var(--safe-top));
|
2026-08-14 09:40:03 +12:00
|
|
|
|
--radius: 8px;
|
|
|
|
|
|
--radius-sm: 6px;
|
|
|
|
|
|
--radius-xs: 4px;
|
|
|
|
|
|
--sans: "Inter Variable", Inter, "Segoe UI", sans-serif;
|
|
|
|
|
|
--mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
* {
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
[hidden] {
|
|
|
|
|
|
display: none !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
|
margin: 0;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
background:
|
|
|
|
|
|
radial-gradient(circle at 72% -20%, rgba(63, 194, 182, 0.045), transparent 38rem),
|
|
|
|
|
|
var(--bg);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
color: var(--text);
|
|
|
|
|
|
font: 16.5px/1.55 var(--sans);
|
|
|
|
|
|
font-weight: 450;
|
|
|
|
|
|
letter-spacing: 0;
|
|
|
|
|
|
-webkit-font-smoothing: antialiased;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
min-width: 320px;
|
|
|
|
|
|
min-height: 100dvh;
|
|
|
|
|
|
background: var(--bg);
|
|
|
|
|
|
-webkit-tap-highlight-color: transparent;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
a {
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Minimal animation, and none of it decorative. The only movement in the console is a
|
|
|
|
|
|
thing appearing (a toast, a panel) and the one spinner that says a request is in
|
|
|
|
|
|
flight. Anybody honouring the platform's reduce-motion setting gets neither. */
|
|
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
|
|
|
*,
|
|
|
|
|
|
*::before,
|
|
|
|
|
|
*::after {
|
|
|
|
|
|
animation-duration: 0.001ms !important;
|
|
|
|
|
|
animation-iteration-count: 1 !important;
|
|
|
|
|
|
transition-duration: 0.001ms !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.skip {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: -9999px;
|
|
|
|
|
|
top: 8px;
|
|
|
|
|
|
z-index: 60;
|
|
|
|
|
|
padding: 8px 14px;
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.skip:focus {
|
|
|
|
|
|
left: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Focus is visible everywhere. The console is driven from a keyboard as much as a mouse,
|
|
|
|
|
|
and a focus ring that only some controls have is worse than none. */
|
|
|
|
|
|
:focus-visible {
|
|
|
|
|
|
outline: 2px solid var(--accent);
|
|
|
|
|
|
outline-offset: 2px;
|
|
|
|
|
|
border-radius: var(--radius-xs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- top bar ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* The bar spans the whole width above both the rail and the page, and carries the things
|
|
|
|
|
|
that are true of the console rather than of any one screen: which gateway this is,
|
|
|
|
|
|
whether it is answering, the search, the notification bell and the way out. */
|
|
|
|
|
|
.topbar {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
inset: 0 0 auto 0;
|
|
|
|
|
|
z-index: 30;
|
|
|
|
|
|
height: var(--top);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
padding: var(--safe-top) max(clamp(14px, 2vw, 22px), var(--safe-right)) 0 var(--safe-left);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
background: var(--top-bg);
|
|
|
|
|
|
border-bottom: 1px solid var(--line);
|
|
|
|
|
|
box-shadow: 0 1px 0 rgba(240, 246, 252, 0.02), 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
|
|
|
|
backdrop-filter: blur(14px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-brand {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 11px;
|
|
|
|
|
|
flex: 0 0 var(--rail);
|
|
|
|
|
|
/* 22px is the rail's own padding plus a link's, so the mark sits in the same column as
|
|
|
|
|
|
the navigation icons under it rather than a few pixels to their left. */
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
padding: 0 22px;
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* Round, because the wordmark beside it is the only other thing in this corner and two
|
|
|
|
|
|
rounded rectangles side by side read as a control rather than as a signature. */
|
|
|
|
|
|
.brand-mark {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
|
height: 30px;
|
|
|
|
|
|
flex: 0 0 30px;
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
letter-spacing: -0.06em;
|
|
|
|
|
|
}
|
|
|
|
|
|
.brand-word {
|
|
|
|
|
|
font-size: 17px;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
letter-spacing: -0.01em;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-spacer {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-tools {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar .omni {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
2026-08-15 09:23:26 +12:00
|
|
|
|
width: min(820px, calc(100vw - var(--rail) - 380px));
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
/* The version is set in the console's monospace because it is read character by character
|
|
|
|
|
|
when somebody is working out which tree a container was deployed from. */
|
|
|
|
|
|
.topbar-version {
|
|
|
|
|
|
font: 11.5px/1 var(--mono);
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-status {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 38px;
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
flex: 0 0 38px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: 1px solid transparent;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: inherit;
|
|
|
|
|
|
cursor: pointer;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
transition: background .16s ease, border-color .16s ease, color .16s ease;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar-status:hover:not(:disabled),
|
|
|
|
|
|
.topbar-status:focus-visible {
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-status:disabled {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
cursor: default;
|
|
|
|
|
|
opacity: 1;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar-status .dot {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
width: 9px;
|
|
|
|
|
|
height: 9px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--quiet);
|
2026-08-16 21:20:55 +12:00
|
|
|
|
box-shadow: 0 0 0 3px rgba(125, 133, 144, .12);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar-status[data-tone="ok"] .dot {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
background: var(--accent-ink);
|
|
|
|
|
|
box-shadow: 0 0 0 3px var(--accent-wash), 0 0 9px rgba(86, 211, 100, .28);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar-status[data-tone="bad"] .dot {
|
|
|
|
|
|
background: var(--danger);
|
2026-08-16 21:20:55 +12:00
|
|
|
|
box-shadow: 0 0 0 3px var(--danger-wash);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-16 12:13:51 +12:00
|
|
|
|
/* The account is an identity first and an exit second. Keeping sign-out in this menu
|
|
|
|
|
|
prevents an unexplained door icon from competing with the operational controls. */
|
|
|
|
|
|
.account-menu {
|
|
|
|
|
|
position: relative;
|
2026-08-16 21:20:55 +12:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
height: 38px;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-trigger {
|
|
|
|
|
|
max-width: 190px;
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
padding: 0 9px 0 5px;
|
|
|
|
|
|
border-color: var(--line);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-trigger:hover:not(:disabled),
|
|
|
|
|
|
.account-menu[data-open="true"] .account-trigger {
|
|
|
|
|
|
border-color: rgba(86, 211, 100, .5);
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-avatar {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 27px;
|
|
|
|
|
|
height: 27px;
|
|
|
|
|
|
flex: 0 0 27px;
|
|
|
|
|
|
border: 1px solid rgba(86, 211, 100, .36);
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
font-weight: 750;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-name {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-caret {
|
|
|
|
|
|
width: 12px;
|
|
|
|
|
|
height: 12px;
|
|
|
|
|
|
transition: transform .16s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-menu[data-open="true"] .account-caret {
|
|
|
|
|
|
transform: rotate(180deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-panel {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: calc(100% + 8px);
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
width: min(280px, calc(100vw - 24px));
|
|
|
|
|
|
padding: 7px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
|
|
|
|
|
|
z-index: 40;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-identity {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 11px;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
padding: 9px 10px 12px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-avatar-large {
|
|
|
|
|
|
width: 34px;
|
|
|
|
|
|
height: 34px;
|
|
|
|
|
|
flex-basis: 34px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-identity span:last-child {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-identity small,
|
|
|
|
|
|
.account-identity b {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-identity small {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-identity b {
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-panel form {
|
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-panel form button {
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
border-color: transparent;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-panel form button:hover:not(:disabled) {
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-14 09:40:03 +12:00
|
|
|
|
@media (max-width: 900px) {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.topbar-version {
|
2026-08-14 09:40:03 +12:00
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- omni search ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.omni {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-input {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni[data-open="true"] .omni-input {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.omni-input input[type="search"] {
|
2026-08-14 09:40:03 +12:00
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
height: 100%;
|
|
|
|
|
|
padding: 0;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
border: 0;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
border-radius: 0;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
background: none;
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
font: inherit;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-input input::placeholder {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-input .ico {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
flex: 0 0 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* The shortcut is printed on the control because it is the only thing on the page saying
|
|
|
|
|
|
the console can be driven from the keyboard. */
|
|
|
|
|
|
.omni-key {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
padding: 2px 6px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font: 10.5px/1.3 var(--mono);
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-panel {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: calc(100% + 6px);
|
2026-08-16 21:20:55 +12:00
|
|
|
|
right: auto;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
max-height: min(50vh, 420px);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
padding: 6px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
|
|
|
|
|
|
z-index: 40;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 8px 10px;
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-item .ico {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
flex: 0 0 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-item.on,
|
|
|
|
|
|
.omni-item:hover {
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-item b {
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-item small {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11.5px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-item span {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-group {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 10.5px;
|
|
|
|
|
|
letter-spacing: 0.08em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- notification bell ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.bell {
|
|
|
|
|
|
position: relative;
|
2026-08-16 21:20:55 +12:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
height: 38px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.bell-button {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
2026-08-16 21:20:55 +12:00
|
|
|
|
width: 38px;
|
|
|
|
|
|
height: 38px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-button:hover {
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell[data-open="true"] .bell-button {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* The badge counts unread events. It is a count rather than a dot because "there is news"
|
|
|
|
|
|
and "there are fourteen things you have not read" are different amounts of urgency. */
|
|
|
|
|
|
.bell-badge {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: -6px;
|
|
|
|
|
|
right: -6px;
|
|
|
|
|
|
min-width: 17px;
|
|
|
|
|
|
height: 17px;
|
|
|
|
|
|
padding: 0 4px;
|
|
|
|
|
|
border-radius: 9px;
|
|
|
|
|
|
background: var(--danger);
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font: 700 10.5px/17px var(--sans);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-panel {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: calc(100% + 8px);
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
width: min(420px, 92vw);
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
|
|
|
|
|
|
z-index: 40;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-head {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 11px 14px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line);
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-head b {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-list {
|
|
|
|
|
|
max-height: min(58vh, 460px);
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 11px;
|
|
|
|
|
|
padding: 11px 14px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-item:last-child {
|
|
|
|
|
|
border-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-item:hover {
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* An unread row wears a bar down its left edge rather than a different background: the
|
|
|
|
|
|
list is read by scanning, and a row that changes colour when it is read makes the whole
|
|
|
|
|
|
panel reflow visually the moment it is opened. */
|
|
|
|
|
|
.bell-item[data-unread="true"] {
|
|
|
|
|
|
box-shadow: inset 2px 0 0 var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-item .glyph {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-body {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-body b {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-body p {
|
|
|
|
|
|
margin: 2px 0 0;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-body time {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-top: 3px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-foot {
|
|
|
|
|
|
padding: 9px 14px;
|
|
|
|
|
|
border-top: 1px solid var(--line);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-foot a {
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- rail ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.rail {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: var(--top);
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: var(--rail);
|
2026-08-15 09:23:26 +12:00
|
|
|
|
padding: 12px 12px max(20px, var(--safe-bottom));
|
2026-08-14 09:40:03 +12:00
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
background: var(--rail-bg);
|
|
|
|
|
|
border-right: 1px solid var(--line);
|
|
|
|
|
|
z-index: 20;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail-group + .rail-group {
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.rail-group:first-child {
|
|
|
|
|
|
margin-bottom: 9px;
|
|
|
|
|
|
padding-bottom: 9px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.rail-head {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
padding: 9px 10px 5px;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font: 600 10.5px/1 var(--sans);
|
|
|
|
|
|
letter-spacing: 0.1em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail-head .caret {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
transition: transform 0.12s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail-head[aria-expanded="false"] .caret {
|
|
|
|
|
|
transform: rotate(-90deg);
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.rail-head-static {
|
|
|
|
|
|
cursor: default;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.rail a {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 7px 10px;
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail a:hover {
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail a[aria-current="page"] {
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail a .ico {
|
|
|
|
|
|
flex: 0 0 17px;
|
|
|
|
|
|
opacity: 0.85;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail a[aria-current="page"] .ico {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* A rail item may carry the same badge the bell does, so news is visible without the
|
|
|
|
|
|
panel being open. */
|
|
|
|
|
|
.rail-badge {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
min-width: 18px;
|
|
|
|
|
|
padding: 0 5px;
|
|
|
|
|
|
border-radius: 9px;
|
|
|
|
|
|
background: var(--danger);
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font: 700 10.5px/17px var(--sans);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- page ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.page {
|
|
|
|
|
|
width: min(calc(100vw - var(--rail)), 1920px);
|
2026-08-16 12:13:51 +12:00
|
|
|
|
min-width: 0;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
margin: var(--top) 0 0 calc(var(--rail) + max(0px, (100vw - var(--rail) - 1920px) / 2));
|
|
|
|
|
|
padding: clamp(24px, 2.4vw, 44px) clamp(22px, 3vw, 56px) 80px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head h1 {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
letter-spacing: -0.02em;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head p {
|
|
|
|
|
|
margin: 5px 0 0;
|
|
|
|
|
|
max-width: 68ch;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.page-head-title {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head-icon {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
flex: 0 0 40px;
|
|
|
|
|
|
width: 40px;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head-icon .ico {
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head-text {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.page-head-row .page-head-actions {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.crumbs {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.crumbs a {
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.crumbs a:hover {
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-15 09:23:26 +12:00
|
|
|
|
@media (max-width: 1400px) {
|
2026-08-14 09:40:03 +12:00
|
|
|
|
:root {
|
|
|
|
|
|
--rail: 0px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail {
|
|
|
|
|
|
transform: translateX(-100%);
|
2026-08-15 09:23:26 +12:00
|
|
|
|
transition: transform 0.2s cubic-bezier(.22, 1, .36, 1);
|
|
|
|
|
|
width: min(320px, calc(100vw - 72px));
|
|
|
|
|
|
padding-right: 14px;
|
|
|
|
|
|
padding-left: max(14px, var(--safe-left));
|
|
|
|
|
|
background: rgba(8, 12, 18, .98);
|
|
|
|
|
|
box-shadow: none;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.rail[data-open="true"] {
|
|
|
|
|
|
transform: none;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
box-shadow: 24px 0 80px rgba(0, 0, 0, 0.58);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar-brand {
|
|
|
|
|
|
flex: 0 0 auto;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
padding: 0 4px 0 12px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.page {
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.rail-scrim {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1400px) {
|
|
|
|
|
|
.rail-scrim {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
inset: var(--top) 0 0 0;
|
|
|
|
|
|
z-index: 19;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: auto;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: rgba(1, 4, 9, .58);
|
|
|
|
|
|
backdrop-filter: blur(5px);
|
|
|
|
|
|
animation: rail-scrim-in .16s ease-out;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail-scrim:hover:not(:disabled) {
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: rgba(1, 4, 9, .58);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes rail-scrim-in {
|
|
|
|
|
|
from { opacity: 0; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.rail-toggle {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
width: 34px;
|
|
|
|
|
|
height: 34px;
|
|
|
|
|
|
margin-left: 8px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
@media (max-width: 1400px) {
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.rail-toggle {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- error banner ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.banner {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
padding: 11px 14px;
|
|
|
|
|
|
border: 1px solid var(--danger);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--danger-wash);
|
|
|
|
|
|
color: var(--danger-ink);
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.banner button {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: inherit;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
font: inherit;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- cards ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.card {
|
|
|
|
|
|
padding: 16px 18px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.card + .card,
|
|
|
|
|
|
.grid + .card,
|
|
|
|
|
|
.card + .grid,
|
|
|
|
|
|
.grid + .grid {
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 11px;
|
|
|
|
|
|
margin-bottom: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head h2 {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
font-size: 14.5px;
|
|
|
|
|
|
font-weight: 620;
|
|
|
|
|
|
letter-spacing: -0.01em;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head p {
|
|
|
|
|
|
margin: 2px 0 0;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head-text {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head-actions {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-foot {
|
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
|
padding-top: 13px;
|
|
|
|
|
|
border-top: 1px solid var(--line-soft);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
.grid[data-cols="2"] {
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
.grid[data-cols="wide"] {
|
|
|
|
|
|
grid-template-columns: minmax(0, 2fr) minmax(300px, 1fr);
|
|
|
|
|
|
}
|
|
|
|
|
|
@media (max-width: 1100px) {
|
|
|
|
|
|
.grid[data-cols="wide"] {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- tiles ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.tiles {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile {
|
|
|
|
|
|
padding: 13px 15px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile .glyph {
|
2026-08-14 11:47:32 +12:00
|
|
|
|
/* Summary cards share tile padding, so their marker always starts at the same top-left
|
|
|
|
|
|
inset. The SVG itself remains centred by .glyph's grid treatment. */
|
|
|
|
|
|
margin: 0 0 9px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.tile b {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
letter-spacing: -0.03em;
|
|
|
|
|
|
line-height: 1.15;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile b.small {
|
|
|
|
|
|
font-size: 14.5px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
letter-spacing: -0.01em;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile span {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-top: 3px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* A tile that links somewhere behaves like one; a tile that does not must not look like
|
|
|
|
|
|
it does. */
|
|
|
|
|
|
a.tile {
|
|
|
|
|
|
color: inherit;
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
a.tile:hover {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- glyphs, tags, chips ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.ico {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: 1em;
|
|
|
|
|
|
height: 1em;
|
|
|
|
|
|
font-size: 17px;
|
|
|
|
|
|
fill: none;
|
|
|
|
|
|
stroke: currentColor;
|
|
|
|
|
|
stroke-width: 1.7;
|
|
|
|
|
|
stroke-linecap: round;
|
|
|
|
|
|
stroke-linejoin: round;
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
|
height: 30px;
|
|
|
|
|
|
flex: 0 0 30px;
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile .glyph .ico { width: 18px; height: 18px; margin: auto; }
|
|
|
|
|
|
|
|
|
|
|
|
.loading-page { display: grid; gap: 20px; }
|
|
|
|
|
|
.loading-heading { display: grid; gap: 10px; max-width: 48rem; }
|
|
|
|
|
|
.loading-heading .skeleton:first-child { height: 34px; width: 28%; }
|
|
|
|
|
|
.loading-heading .skeleton:last-child { height: 18px; width: 72%; }
|
|
|
|
|
|
.loading-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
|
|
|
|
|
|
.loading-tiles .skeleton { height: 132px; }
|
|
|
|
|
|
.loading-card { display: grid; gap: 12px; min-height: 180px; padding: 22px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
|
|
|
|
|
|
.loading-card .skeleton:first-child { height: 20px; width: 32%; }
|
|
|
|
|
|
.loading-card .skeleton:not(:first-child) { height: 14px; }
|
|
|
|
|
|
@media (max-width: 820px) { .loading-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
|
|
|
|
|
.glyph .ico {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph[data-tone="ok"] {
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph[data-tone="warn"] {
|
|
|
|
|
|
background: var(--warn-wash);
|
|
|
|
|
|
color: var(--warn-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph[data-tone="bad"] {
|
|
|
|
|
|
background: var(--danger-wash);
|
|
|
|
|
|
color: var(--danger-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph[data-tone="info"] {
|
|
|
|
|
|
background: var(--info-wash);
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph[data-tone="note"] {
|
|
|
|
|
|
background: var(--note-wash);
|
|
|
|
|
|
color: var(--note-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.glyph[data-tone="data"] {
|
|
|
|
|
|
background: var(--data-wash);
|
|
|
|
|
|
color: var(--data-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tag {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 5px;
|
|
|
|
|
|
padding: 2px 8px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 11.5px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* A verdict tag carries a dot in its own colour: tone alone is no signal to somebody who
|
|
|
|
|
|
cannot separate the green from the amber. */
|
|
|
|
|
|
.tag[data-tone]::before {
|
|
|
|
|
|
content: "";
|
|
|
|
|
|
width: 6px;
|
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: currentColor;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tag[data-tone="ok"] {
|
|
|
|
|
|
border-color: rgba(82, 181, 75, 0.35);
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tag[data-tone="warn"] {
|
|
|
|
|
|
border-color: rgba(239, 196, 107, 0.35);
|
|
|
|
|
|
background: var(--warn-wash);
|
|
|
|
|
|
color: var(--warn-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tag[data-tone="bad"] {
|
|
|
|
|
|
border-color: rgba(229, 83, 75, 0.35);
|
|
|
|
|
|
background: var(--danger-wash);
|
|
|
|
|
|
color: var(--danger-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tag[data-tone="info"] {
|
|
|
|
|
|
border-color: rgba(79, 156, 216, 0.35);
|
|
|
|
|
|
background: var(--info-wash);
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tag[data-tone="note"] {
|
|
|
|
|
|
border-color: rgba(160, 124, 232, 0.35);
|
|
|
|
|
|
background: var(--note-wash);
|
|
|
|
|
|
color: var(--note-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tag[data-tone="data"] {
|
|
|
|
|
|
border-color: rgba(63, 194, 182, 0.35);
|
|
|
|
|
|
background: var(--data-wash);
|
|
|
|
|
|
color: var(--data-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chip {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 5px;
|
|
|
|
|
|
padding: 3px 9px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-xs);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font: 11.5px/1.5 var(--mono);
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.chip[data-tone="ok"] {
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chip[data-tone="warn"] {
|
|
|
|
|
|
color: var(--warn-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chip[data-tone="bad"] {
|
|
|
|
|
|
color: var(--danger-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chip[data-tone="info"] {
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chip[data-tone="note"] {
|
|
|
|
|
|
color: var(--note-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chip[data-tone="data"] {
|
|
|
|
|
|
color: var(--data-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.chips {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- tables ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* Dense but readable, which is most of what this console is for. The wrapper is what
|
|
|
|
|
|
scrolls, so a wide table never makes the page scroll sideways. */
|
|
|
|
|
|
.table-wrap {
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
overscroll-behavior-inline: contain;
|
|
|
|
|
|
-webkit-overflow-scrolling: touch;
|
|
|
|
|
|
margin: 0 -18px -16px;
|
|
|
|
|
|
padding: 0 18px 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
table {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-width: max-content;
|
|
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-15 09:23:26 +12:00
|
|
|
|
/* Tablets get a drawer shell rather than a squeezed desktop rail. The controls remain in
|
|
|
|
|
|
one calm bar in both orientations; only the least useful labels disappear as space gets
|
|
|
|
|
|
tighter, while the live status itself always remains visible. */
|
|
|
|
|
|
@media (max-width: 1400px) {
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.topbar {
|
|
|
|
|
|
display: flex;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
gap: 10px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
height: var(--top);
|
2026-08-15 09:23:26 +12:00
|
|
|
|
padding: var(--safe-top) max(16px, var(--safe-right)) 0 max(16px, var(--safe-left));
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar-brand {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail-toggle {
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-spacer {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar .omni {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
left: auto;
|
|
|
|
|
|
transform: none;
|
|
|
|
|
|
flex: 1 1 auto;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
width: auto;
|
|
|
|
|
|
max-width: 640px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.omni-key,
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.topbar-version {
|
2026-08-14 09:40:03 +12:00
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-tools {
|
|
|
|
|
|
display: contents;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-button,
|
|
|
|
|
|
.rail-toggle {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
width: 40px;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-status {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
width: 40px;
|
|
|
|
|
|
flex-basis: 40px;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
min-width: 40px;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
background: var(--surface);
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.omni-input,
|
|
|
|
|
|
.bell,
|
|
|
|
|
|
.bell-button,
|
|
|
|
|
|
.account-menu,
|
|
|
|
|
|
.account-trigger {
|
|
|
|
|
|
height: 40px;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.page {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
padding: clamp(24px, 3vw, 34px) max(24px, calc(var(--safe-right) + 10px)) max(64px, calc(var(--safe-bottom) + 36px)) max(24px, calc(var(--safe-left) + 10px));
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.table-wrap {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
margin: 0 -18px -16px;
|
|
|
|
|
|
padding: 0 18px 18px;
|
|
|
|
|
|
scrollbar-gutter: stable;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
table {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
th,
|
|
|
|
|
|
td {
|
|
|
|
|
|
padding-right: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
|
2026-08-16 12:13:51 +12:00
|
|
|
|
@media (max-width: 1100px) {
|
|
|
|
|
|
.account-trigger {
|
|
|
|
|
|
width: 40px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-name,
|
|
|
|
|
|
.account-caret {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-15 09:23:26 +12:00
|
|
|
|
@media (max-width: 820px) {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.brand-word {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar-status {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 40px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page {
|
|
|
|
|
|
padding: 22px max(16px, var(--safe-right)) max(56px, calc(var(--safe-bottom) + 28px)) max(16px, var(--safe-left));
|
|
|
|
|
|
}
|
|
|
|
|
|
.grid,
|
|
|
|
|
|
.grid[data-cols="2"],
|
|
|
|
|
|
.grid[data-cols="wide"],
|
|
|
|
|
|
.grid.two {
|
|
|
|
|
|
grid-template-columns: minmax(0, 1fr);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tiles {
|
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
.table-wrap {
|
|
|
|
|
|
margin-right: -16px;
|
|
|
|
|
|
margin-left: -16px;
|
|
|
|
|
|
padding-right: 16px;
|
|
|
|
|
|
padding-left: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-16 12:13:51 +12:00
|
|
|
|
|
2026-08-16 21:20:55 +12:00
|
|
|
|
/* A phone keeps every global control on one row. Search is the only flexible item: the
|
|
|
|
|
|
navigation and identity controls retain useful targets while the field gives up width
|
|
|
|
|
|
before the header can wrap. Its relative wrapper still anchors the results directly
|
|
|
|
|
|
beneath the field at exactly the width available here. */
|
2026-08-16 12:13:51 +12:00
|
|
|
|
@media (max-width: 680px) {
|
|
|
|
|
|
:root {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
--top: calc(60px + var(--safe-top));
|
2026-08-16 12:13:51 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar {
|
|
|
|
|
|
align-items: center;
|
2026-08-16 21:20:55 +12:00
|
|
|
|
flex-wrap: nowrap;
|
|
|
|
|
|
gap: clamp(4px, 1.5vw, 8px);
|
|
|
|
|
|
padding: calc(var(--safe-top) + 8px) max(8px, var(--safe-right)) 8px max(8px, var(--safe-left));
|
2026-08-16 12:13:51 +12:00
|
|
|
|
}
|
|
|
|
|
|
.rail-toggle { order: 1; }
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.topbar-brand {
|
|
|
|
|
|
order: 2;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
flex: 0 0 auto;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
}
|
|
|
|
|
|
.topbar .omni {
|
2026-08-16 21:20:55 +12:00
|
|
|
|
order: 3;
|
|
|
|
|
|
flex: 1 1 96px;
|
|
|
|
|
|
width: 0;
|
|
|
|
|
|
min-width: 0;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
max-width: none;
|
|
|
|
|
|
}
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.topbar-status {
|
|
|
|
|
|
order: 4;
|
|
|
|
|
|
margin-left: 0;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
}
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.bell { order: 5; }
|
|
|
|
|
|
.account-menu { order: 6; }
|
|
|
|
|
|
.brand-mark {
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
|
height: 30px;
|
|
|
|
|
|
flex-basis: 30px;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
}
|
|
|
|
|
|
.account-panel,
|
|
|
|
|
|
.bell-panel {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: calc(var(--top) + 8px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.account-panel {
|
|
|
|
|
|
right: max(12px, var(--safe-right));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 370px) {
|
|
|
|
|
|
.tiles {
|
|
|
|
|
|
grid-template-columns: minmax(0, 1fr);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
th {
|
|
|
|
|
|
padding: 0 12px 8px 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--line);
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
letter-spacing: 0.07em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
td {
|
|
|
|
|
|
padding: 9px 12px 9px 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
}
|
|
|
|
|
|
tr:last-child td {
|
|
|
|
|
|
border-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
tbody tr:hover td {
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
th:last-child,
|
|
|
|
|
|
td:last-child {
|
|
|
|
|
|
padding-right: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
td.num,
|
|
|
|
|
|
th.num {
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
font-variant-numeric: tabular-nums;
|
|
|
|
|
|
}
|
|
|
|
|
|
td.mono {
|
|
|
|
|
|
font: 12px/1.5 var(--mono);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
td.nowrap,
|
|
|
|
|
|
th.nowrap {
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
td.muted {
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* A sortable header is a button, so it is reachable from a keyboard. */
|
|
|
|
|
|
th button {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: inherit;
|
|
|
|
|
|
font: inherit;
|
|
|
|
|
|
letter-spacing: inherit;
|
|
|
|
|
|
text-transform: inherit;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
th button:hover {
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
th[aria-sort] button {
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.table-row-link {
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.table-row-link:hover {
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- lists ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 11px 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item:last-child {
|
|
|
|
|
|
border-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item .list-body {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item b {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item p {
|
|
|
|
|
|
margin: 2px 0 0;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item .list-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- controls ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
button,
|
|
|
|
|
|
.btn {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 7px;
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
padding: 0 13px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
font: 600 13px/1 var(--sans);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
button:hover:not(:disabled),
|
|
|
|
|
|
.btn:hover {
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
border-color: #2c3542;
|
|
|
|
|
|
}
|
|
|
|
|
|
button:disabled {
|
|
|
|
|
|
opacity: 0.45;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-variant="primary"] {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
color: #06240a;
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-variant="primary"]:hover:not(:disabled) {
|
|
|
|
|
|
background: var(--accent-ink);
|
|
|
|
|
|
border-color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-variant="danger"] {
|
|
|
|
|
|
border-color: rgba(229, 83, 75, 0.4);
|
|
|
|
|
|
background: var(--danger-wash);
|
|
|
|
|
|
color: var(--danger-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-variant="danger"]:hover:not(:disabled) {
|
|
|
|
|
|
background: rgba(229, 83, 75, 0.22);
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-variant="quiet"] {
|
|
|
|
|
|
border-color: transparent;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-variant="quiet"]:hover:not(:disabled) {
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-size="sm"] {
|
|
|
|
|
|
height: 26px;
|
|
|
|
|
|
padding: 0 9px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.field {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field > span {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field > small {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-top: 5px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
input[type="text"],
|
|
|
|
|
|
input[type="password"],
|
|
|
|
|
|
input[type="search"],
|
|
|
|
|
|
input[type="number"],
|
|
|
|
|
|
input[type="date"],
|
2026-08-15 09:23:26 +12:00
|
|
|
|
input[type="time"],
|
|
|
|
|
|
input[type="datetime-local"],
|
2026-08-14 09:40:03 +12:00
|
|
|
|
input[type="url"],
|
|
|
|
|
|
select,
|
|
|
|
|
|
textarea {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
font: inherit;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
textarea {
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
min-height: 74px;
|
|
|
|
|
|
padding: 8px 10px;
|
|
|
|
|
|
resize: vertical;
|
|
|
|
|
|
}
|
|
|
|
|
|
input:focus,
|
|
|
|
|
|
select:focus,
|
|
|
|
|
|
textarea:focus {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
input::placeholder,
|
|
|
|
|
|
textarea::placeholder {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
select {
|
|
|
|
|
|
appearance: none;
|
|
|
|
|
|
padding-right: 26px;
|
|
|
|
|
|
background-image: linear-gradient(45deg, transparent 50%, var(--quiet) 50%),
|
|
|
|
|
|
linear-gradient(135deg, var(--quiet) 50%, transparent 50%);
|
|
|
|
|
|
background-position: calc(100% - 14px) 14px, calc(100% - 9px) 14px;
|
|
|
|
|
|
background-size: 5px 5px;
|
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.fields {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 13px;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A switch, not a checkbox: the console is full of on/off policy and a control that says
|
|
|
|
|
|
which way it is pointing from across the room is worth the extra markup. */
|
|
|
|
|
|
.check {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 11px;
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check input {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check .switch {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 34px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
flex: 0 0 34px;
|
|
|
|
|
|
margin-top: 1px;
|
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
transition: background 0.12s ease, border-color 0.12s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check .switch::after {
|
|
|
|
|
|
content: "";
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 2px;
|
|
|
|
|
|
left: 2px;
|
|
|
|
|
|
width: 14px;
|
|
|
|
|
|
height: 14px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--muted);
|
|
|
|
|
|
transition: transform 0.12s ease, background 0.12s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check input:checked + .switch {
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.check input:checked + .switch::after {
|
|
|
|
|
|
transform: translateX(14px);
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.check input:focus-visible + .switch {
|
|
|
|
|
|
outline: 2px solid var(--accent);
|
|
|
|
|
|
outline-offset: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check input:disabled + .switch {
|
|
|
|
|
|
opacity: 0.45;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check-body b {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check-body p {
|
|
|
|
|
|
margin: 2px 0 0;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A row of exclusive choices — a date window, a severity — where a select would hide the
|
|
|
|
|
|
options behind a click. */
|
|
|
|
|
|
.segments {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
padding: 2px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.segments button {
|
|
|
|
|
|
height: 26px;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.segments button[aria-pressed="true"] {
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- filter bar ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* Fast filtering is most of what makes a table useful, so the controls sit above it in a
|
|
|
|
|
|
row of their own rather than behind a "filters" disclosure nobody opens. */
|
|
|
|
|
|
.filters {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
margin-bottom: 14px;
|
|
|
|
|
|
padding: 13px 15px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .field {
|
|
|
|
|
|
flex: 1 1 160px;
|
|
|
|
|
|
max-width: 260px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .field.grow {
|
|
|
|
|
|
flex: 2 1 240px;
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .filter-actions {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filter-summary {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- charts ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* One bar chart, drawn with divs. A charting library would be the single largest
|
|
|
|
|
|
dependency in the console for the sake of four bar charts. */
|
|
|
|
|
|
.bars {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
|
gap: 3px;
|
|
|
|
|
|
height: 92px;
|
|
|
|
|
|
padding-top: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
flex: 1 1 0;
|
|
|
|
|
|
min-width: 3px;
|
|
|
|
|
|
border-radius: 2px 2px 0 0;
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
border-top: 2px solid var(--accent);
|
|
|
|
|
|
min-height: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar[data-tone="bad"] {
|
|
|
|
|
|
background: var(--danger-wash);
|
|
|
|
|
|
border-top-color: var(--danger);
|
|
|
|
|
|
}
|
|
|
|
|
|
.bar[data-empty="true"] {
|
|
|
|
|
|
background: var(--line-soft);
|
|
|
|
|
|
border-top-color: var(--line);
|
|
|
|
|
|
}
|
|
|
|
|
|
.bars-axis {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A proportion bar, for one number against a total. */
|
|
|
|
|
|
.meter {
|
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
background: var(--surface-hi);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.meter > div {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.meter[data-tone="warn"] > div {
|
|
|
|
|
|
background: var(--warn);
|
|
|
|
|
|
}
|
|
|
|
|
|
.meter[data-tone="bad"] > div {
|
|
|
|
|
|
background: var(--danger);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- log / code ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.logview {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
height: 62vh;
|
|
|
|
|
|
min-height: 320px;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
overflow: auto;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: #080a0e;
|
|
|
|
|
|
font: 12px/1.6 var(--mono);
|
2026-08-15 09:23:26 +12:00
|
|
|
|
contain: layout paint style;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
2026-08-14 11:47:32 +12:00
|
|
|
|
.loghead {
|
|
|
|
|
|
position: sticky;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
display: grid;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
grid-template-columns: 150px 46px minmax(180px, 1fr) minmax(240px, 2fr);
|
2026-08-14 11:47:32 +12:00
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 7px 12px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line);
|
|
|
|
|
|
background: #10131a;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: .08em;
|
|
|
|
|
|
text-transform: uppercase;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
min-width: 760px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logbody {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
min-width: 760px;
|
2026-08-14 11:47:32 +12:00
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.logline {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 3px 12px;
|
|
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
|
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.logline[data-virtual="true"] {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 150px 46px minmax(180px, 1fr) minmax(240px, 2fr);
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
height: 48px;
|
|
|
|
|
|
padding-top: 4px;
|
|
|
|
|
|
padding-bottom: 4px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
contain: strict;
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.logline:hover {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.03);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logline time {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
2026-08-14 11:47:32 +12:00
|
|
|
|
.logline time small {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.logline .lvl {
|
|
|
|
|
|
flex: 0 0 46px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logline[data-level="ERROR"] .lvl {
|
|
|
|
|
|
color: var(--danger-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logline[data-level="WARN"] .lvl {
|
|
|
|
|
|
color: var(--warn-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logline[data-level="INFO"] .lvl {
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logline[data-level="DEBUG"] .lvl {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logline .msg {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
2026-08-14 09:40:03 +12:00
|
|
|
|
}
|
|
|
|
|
|
.logline .attrs {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
2026-08-14 11:47:32 +12:00
|
|
|
|
@media (min-width: 900px) {
|
|
|
|
|
|
.logline {
|
|
|
|
|
|
display: grid;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
grid-template-columns: 150px 46px minmax(180px, 1fr) minmax(240px, 2fr);
|
2026-08-14 11:47:32 +12:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-14 09:40:03 +12:00
|
|
|
|
.logline .attrs b {
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.logattrs-button {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
height: 28px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font: inherit;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logattrs-button:hover:not(:disabled) {
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logattrs-button:focus-visible {
|
|
|
|
|
|
outline: 1px solid var(--accent);
|
|
|
|
|
|
outline-offset: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector {
|
|
|
|
|
|
margin-top: 12px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector-head {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector-head > div {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector-head b,
|
|
|
|
|
|
.log-inspector-head span {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector-head span {
|
|
|
|
|
|
margin-top: 3px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font: 11px/1.5 var(--mono);
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector dl {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: minmax(130px, max-content) minmax(0, 1fr);
|
|
|
|
|
|
gap: 5px 14px;
|
|
|
|
|
|
margin: 12px 0 0;
|
|
|
|
|
|
padding-top: 10px;
|
|
|
|
|
|
border-top: 1px solid var(--line);
|
|
|
|
|
|
font: 12px/1.5 var(--mono);
|
|
|
|
|
|
}
|
|
|
|
|
|
.log-inspector dt { color: var(--muted); }
|
|
|
|
|
|
.log-inspector dd { min-width: 0; margin: 0; overflow-wrap: anywhere; }
|
2026-08-14 11:47:32 +12:00
|
|
|
|
.logdetails {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logdetails summary {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
list-style: none;
|
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logdetails summary::-webkit-details-marker { display: none; }
|
|
|
|
|
|
.logdetails summary::before {
|
|
|
|
|
|
content: '›';
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
margin-right: 6px;
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logdetails[open] summary::before { transform: rotate(90deg); }
|
|
|
|
|
|
.logdetails dl {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: minmax(130px, max-content) minmax(0, 1fr);
|
|
|
|
|
|
gap: 4px 12px;
|
|
|
|
|
|
margin: 7px 0 2px;
|
|
|
|
|
|
padding: 8px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: rgba(255, 255, 255, .025);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logdetails dt { color: var(--muted); }
|
|
|
|
|
|
.logdetails dd { min-width: 0; margin: 0; color: var(--text); overflow-wrap: anywhere; }
|
2026-08-14 09:40:03 +12:00
|
|
|
|
|
|
|
|
|
|
pre.code {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 12px 14px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: #080a0e;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font: 12px/1.6 var(--mono);
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- misc ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.empty {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 22px 0;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.muted {
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.quiet {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
.mono {
|
|
|
|
|
|
font-family: var(--mono);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.note {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 10px 13px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-left: 2px solid var(--info);
|
|
|
|
|
|
border-radius: var(--radius-xs);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.note[data-tone="warn"] {
|
|
|
|
|
|
border-left-color: var(--warn);
|
|
|
|
|
|
}
|
|
|
|
|
|
.note[data-tone="bad"] {
|
|
|
|
|
|
border-left-color: var(--danger);
|
|
|
|
|
|
}
|
|
|
|
|
|
.note[data-tone="ok"] {
|
|
|
|
|
|
border-left-color: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.stack {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.row.tight {
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.spacer {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* One spinner, and it is the only thing in the console that moves on its own. */
|
|
|
|
|
|
.spinner {
|
|
|
|
|
|
width: 14px;
|
|
|
|
|
|
height: 14px;
|
|
|
|
|
|
border: 2px solid var(--line);
|
|
|
|
|
|
border-top-color: var(--accent);
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
animation: spin 0.7s linear infinite;
|
|
|
|
|
|
}
|
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
|
to {
|
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The page's own loading state: a shape rather than a spinner, so the layout does not
|
|
|
|
|
|
jump when the data lands. */
|
|
|
|
|
|
.skeleton {
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: linear-gradient(90deg, var(--surface) 25%, var(--surface-lift) 50%, var(--surface) 75%);
|
|
|
|
|
|
background-size: 300% 100%;
|
|
|
|
|
|
animation: shimmer 1.3s ease-in-out infinite;
|
|
|
|
|
|
}
|
|
|
|
|
|
@keyframes shimmer {
|
|
|
|
|
|
to {
|
|
|
|
|
|
background-position: -300% 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- toasts ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* A mutation says what happened here rather than in the error banner, which is reserved
|
|
|
|
|
|
for the console failing to talk to the gateway at all. */
|
|
|
|
|
|
.toasts {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
right: 18px;
|
|
|
|
|
|
bottom: 18px;
|
|
|
|
|
|
z-index: 50;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
max-width: min(420px, 90vw);
|
|
|
|
|
|
}
|
|
|
|
|
|
.toast {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 11px 14px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-left: 3px solid var(--accent);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
box-shadow: 0 14px 34px rgba(0, 0, 0, 0.5);
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
animation: toast-in 0.14s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.toast[data-tone="bad"] {
|
|
|
|
|
|
border-left-color: var(--danger);
|
|
|
|
|
|
}
|
|
|
|
|
|
.toast[data-tone="warn"] {
|
|
|
|
|
|
border-left-color: var(--warn);
|
|
|
|
|
|
}
|
|
|
|
|
|
.toast button {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
@keyframes toast-in {
|
|
|
|
|
|
from {
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
transform: translateY(6px);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- dialog ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.scrim {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
inset: 0;
|
|
|
|
|
|
z-index: 45;
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background: rgba(4, 6, 9, 0.7);
|
|
|
|
|
|
backdrop-filter: blur(2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dialog {
|
|
|
|
|
|
width: min(520px, 100%);
|
|
|
|
|
|
max-height: 86vh;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
padding: 20px 22px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius);
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dialog h2 {
|
|
|
|
|
|
margin: 0 0 6px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dialog p {
|
|
|
|
|
|
margin: 0 0 16px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dialog-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- key/value rows ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* A label on the left, a verdict on the right. The console's densest way of stating a
|
|
|
|
|
|
handful of facts about one subject, and the shape the overview is built from. */
|
|
|
|
|
|
.kv {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
.kv-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 9px 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.kv-row:last-child {
|
|
|
|
|
|
border-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.kv-row > span:first-child {
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.kv-row > span:last-child {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A tile strip with no card around it, for a group of numbers inside one. */
|
|
|
|
|
|
.tiles.plain {
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
.tiles.plain .tile {
|
|
|
|
|
|
padding: 10px 12px;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tiles.plain .tile b {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.hint {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A two-column card grid that does not collapse as eagerly as the default. */
|
|
|
|
|
|
.grid.two {
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
@media (max-width: 980px) {
|
|
|
|
|
|
.grid.two {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- linkable list rows ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* A row that is a destination. The whole row is the target rather than a link inside it,
|
|
|
|
|
|
because a list of people is read by scanning names and clicking one. */
|
|
|
|
|
|
.list-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 12px 18px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line-soft);
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-row:last-child {
|
|
|
|
|
|
border-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-row:hover {
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-main {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-title {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 7px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-meta {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-row .list-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* A card that holds nothing but a list: the rows carry their own padding, so the card
|
|
|
|
|
|
must not add a second inset around them. */
|
|
|
|
|
|
.card.flush {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Initials behind a name. Emby has no avatar for most households, and a row of identical
|
|
|
|
|
|
grey circles says nothing — the letters are what makes one row distinguishable from the
|
|
|
|
|
|
next at a glance. */
|
|
|
|
|
|
.avatar {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 34px;
|
|
|
|
|
|
height: 34px;
|
|
|
|
|
|
flex: 0 0 34px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--note-wash);
|
|
|
|
|
|
color: var(--note-ink);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: 0.02em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The presence dot: three-valued, and the tone is passed rather than derived. */
|
|
|
|
|
|
.dot-state {
|
|
|
|
|
|
width: 7px;
|
|
|
|
|
|
height: 7px;
|
|
|
|
|
|
flex: 0 0 7px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dot-state[data-tone="ok"] {
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dot-state[data-tone="warn"] {
|
|
|
|
|
|
background: var(--warn);
|
|
|
|
|
|
}
|
|
|
|
|
|
.dot-state[data-tone="bad"] {
|
|
|
|
|
|
background: var(--danger);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A column of switches, for a list of people or of options. */
|
|
|
|
|
|
.checks.columns {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 0 24px;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.crumb {
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.crumb:hover {
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A run of small chips inside a table cell — a device's build history. */
|
|
|
|
|
|
.versions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- journey visits ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* One visit read from its first step to its last. A timeline rather than a table because
|
|
|
|
|
|
the shape of a visit — how many steps, and how far apart — is most of what is being
|
|
|
|
|
|
read, and a table of five rows hides it. */
|
|
|
|
|
|
.visit {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.visit + .visit {
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.visit header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
margin-bottom: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.visit header b {
|
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.visit header span {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.visit header .tag {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-answers {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
|
|
|
gap: 1px;
|
|
|
|
|
|
margin: 0 0 15px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-xs);
|
|
|
|
|
|
background: var(--line);
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-answer {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
padding: 11px 12px 11px 38px;
|
|
|
|
|
|
background: var(--surface);
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-answer .ico {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 13px;
|
|
|
|
|
|
left: 12px;
|
|
|
|
|
|
width: 16px;
|
|
|
|
|
|
height: 16px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-answer[data-kind="entry"] .ico,
|
|
|
|
|
|
.journey-answer[data-kind="outcome"] .ico { color: var(--accent); }
|
|
|
|
|
|
.journey-answer[data-kind="selection"] .ico { color: var(--note-ink); }
|
|
|
|
|
|
.journey-answer span,
|
|
|
|
|
|
.journey-answer b {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-answer span {
|
|
|
|
|
|
margin-bottom: 3px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
letter-spacing: .04em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-answer b {
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-timeline {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0 0 0 14px;
|
|
|
|
|
|
list-style: none;
|
|
|
|
|
|
border-left: 1px solid var(--line);
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-timeline li {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 7px 0 7px 5px;
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.timeline-dot {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: -18px;
|
|
|
|
|
|
top: 12px;
|
|
|
|
|
|
width: 7px;
|
|
|
|
|
|
height: 7px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
.timeline-dot[data-action="select"],
|
|
|
|
|
|
.timeline-dot[data-action="open"] { background: var(--note-ink); }
|
|
|
|
|
|
.timeline-dot[data-action="close"] { background: var(--quiet); }
|
|
|
|
|
|
.journey-timeline li > div { min-width: 0; }
|
|
|
|
|
|
.journey-timeline li b {
|
|
|
|
|
|
display: inline;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-timeline li div span {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.journey-timeline li time {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
padding-left: 10px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.visits {
|
|
|
|
|
|
max-height: 60vh;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
@media (max-width: 640px) {
|
|
|
|
|
|
.journey-answers { grid-template-columns: 1fr; }
|
|
|
|
|
|
.journey-timeline li { align-items: flex-start; flex-wrap: wrap; }
|
|
|
|
|
|
.journey-timeline li time { width: 100%; margin: 2px 0 0; padding-left: 0; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A headline number over a proportion bar, for one figure that has a denominator. */
|
|
|
|
|
|
.summary {
|
|
|
|
|
|
padding: 13px 15px;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.summary-head {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-bottom: 9px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.summary-head b {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.summary-head strong {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
letter-spacing: -0.03em;
|
|
|
|
|
|
}
|
|
|
|
|
|
.summary p {
|
|
|
|
|
|
margin: 9px 0 0;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.summary-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.table-sub {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.route-arrow {
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
details summary {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
padding: 6px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- theme swatch ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* A palette rendered as its own three colours. The custom properties are the only inline
|
|
|
|
|
|
style in the console, and they are values rather than layout: what a colour scheme looks
|
|
|
|
|
|
like cannot be described in a class name. */
|
|
|
|
|
|
.swatch {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 34px;
|
|
|
|
|
|
height: 22px;
|
|
|
|
|
|
flex: 0 0 34px;
|
|
|
|
|
|
margin-top: 1px;
|
|
|
|
|
|
border-radius: var(--radius-xs);
|
|
|
|
|
|
background: var(--swatch-surface, var(--surface-hi));
|
|
|
|
|
|
border: 1px solid var(--swatch-hairline, var(--line));
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.swatch i {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
inset: auto 0 0 0;
|
|
|
|
|
|
height: 7px;
|
|
|
|
|
|
background: var(--swatch-accent, var(--accent));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A caption inside a card, above a group of controls that belong together. Quieter than a
|
|
|
|
|
|
heading, because the card already has one. */
|
|
|
|
|
|
.group-label {
|
|
|
|
|
|
margin: 4px 0 2px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: 0.08em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
.group + .group {
|
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
|
padding-top: 14px;
|
|
|
|
|
|
border-top: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
2026-08-15 09:23:26 +12:00
|
|
|
|
|
|
|
|
|
|
/* ---------- hero scheduler ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
.hero-pins {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-pin {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 30px minmax(0, 1fr) auto auto;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
min-height: 52px;
|
|
|
|
|
|
padding: 8px 10px;
|
|
|
|
|
|
border: 1px solid var(--line-soft);
|
|
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-pin-order {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
place-items: center;
|
|
|
|
|
|
width: 26px;
|
|
|
|
|
|
height: 26px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: var(--note-wash);
|
|
|
|
|
|
color: var(--note-ink);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 750;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-pin > span:nth-child(2) {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-pin b,
|
|
|
|
|
|
.hero-pin small {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-pin b { font-size: 13.5px; }
|
|
|
|
|
|
.hero-pin small { margin-top: 2px; color: var(--quiet); font-size: 11.5px; }
|
|
|
|
|
|
|
|
|
|
|
|
.hero-schedule-list {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 100px minmax(0, 1fr) auto;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 1px solid var(--line);
|
|
|
|
|
|
border-radius: 11px;
|
|
|
|
|
|
background: linear-gradient(135deg, var(--surface-lift), rgba(13, 17, 23, .74));
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule::before {
|
|
|
|
|
|
content: "";
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
inset: 0 auto 0 0;
|
|
|
|
|
|
width: 3px;
|
|
|
|
|
|
background: var(--quiet);
|
|
|
|
|
|
opacity: .4;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule[data-enabled="true"]::before {
|
|
|
|
|
|
background: var(--info);
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-time {
|
|
|
|
|
|
align-self: stretch;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
padding-right: 14px;
|
|
|
|
|
|
border-right: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-time b {
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
letter-spacing: .08em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-time span {
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font: 12px/1.4 var(--mono);
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-main { min-width: 0; }
|
|
|
|
|
|
.hero-schedule-title {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-title h3 {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
color: var(--text);
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 650;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-main > p {
|
|
|
|
|
|
margin: 4px 0 8px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.hero-schedule-dialog {
|
|
|
|
|
|
width: min(760px, 100%);
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-dialog-head {
|
|
|
|
|
|
padding: 24px 26px 20px;
|
|
|
|
|
|
border-bottom: 1px solid var(--line);
|
|
|
|
|
|
background:
|
|
|
|
|
|
radial-gradient(circle at 90% -40%, var(--info-wash), transparent 240px),
|
|
|
|
|
|
var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-kicker {
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
font-size: 10.5px;
|
|
|
|
|
|
font-weight: 750;
|
|
|
|
|
|
letter-spacing: .1em;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-dialog-head h2 {
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
font-size: 21px;
|
|
|
|
|
|
letter-spacing: -.025em;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-dialog-head p { margin-bottom: 0; }
|
|
|
|
|
|
.hero-schedule-dialog > .fields,
|
|
|
|
|
|
.hero-schedule-dialog > .schedule-days,
|
|
|
|
|
|
.hero-schedule-dialog > .schedule-options,
|
|
|
|
|
|
.hero-schedule-dialog > .check {
|
|
|
|
|
|
margin-right: 26px;
|
|
|
|
|
|
margin-left: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin: 20px 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
min-height: 68px;
|
|
|
|
|
|
padding: 11px 13px;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
white-space: normal;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button b,
|
|
|
|
|
|
.schedule-frequency button span {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button span {
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
color: var(--quiet);
|
|
|
|
|
|
font-size: 11.5px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button[aria-pressed="true"] {
|
|
|
|
|
|
border-color: var(--info);
|
|
|
|
|
|
background: var(--info-wash);
|
|
|
|
|
|
color: var(--info-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button[aria-pressed="true"] span { color: var(--muted); }
|
|
|
|
|
|
.schedule-days {
|
|
|
|
|
|
margin-top: 18px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border: 1px solid var(--line-soft);
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-days-head {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-days-head > b { font-size: 12.5px; }
|
|
|
|
|
|
.schedule-days-head > div {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-days-head button {
|
|
|
|
|
|
height: 28px;
|
|
|
|
|
|
padding: 0 8px;
|
|
|
|
|
|
border-color: transparent;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 11.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-day-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(7, minmax(0, 1fr));
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-day-grid button {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-day-grid button[aria-pressed="true"] {
|
|
|
|
|
|
border-color: var(--accent);
|
|
|
|
|
|
background: var(--accent-wash);
|
|
|
|
|
|
color: var(--accent-ink);
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-options {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: minmax(0, 2fr) minmax(140px, 1fr);
|
|
|
|
|
|
align-items: start;
|
|
|
|
|
|
gap: 22px;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
padding-top: 18px;
|
|
|
|
|
|
border-top: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-option-label {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-bottom: 3px;
|
|
|
|
|
|
color: var(--muted);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-placement-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
|
|
|
gap: 6px 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-dialog > .check { margin-top: 8px; }
|
|
|
|
|
|
.hero-schedule-dialog > .dialog-actions {
|
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
|
padding: 18px 26px;
|
|
|
|
|
|
border-top: 1px solid var(--line);
|
|
|
|
|
|
background: var(--surface-lift);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 820px) {
|
|
|
|
|
|
.hero-pin {
|
|
|
|
|
|
grid-template-columns: 30px minmax(0, 1fr) auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-pin > button:last-child { grid-column: 3; }
|
|
|
|
|
|
.hero-schedule {
|
|
|
|
|
|
grid-template-columns: 78px minmax(0, 1fr);
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-actions {
|
|
|
|
|
|
grid-column: 1 / -1;
|
|
|
|
|
|
padding-top: 10px;
|
|
|
|
|
|
border-top: 1px solid var(--line-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
.hero-schedule-actions button { flex: 1 1 0; }
|
|
|
|
|
|
.hero-schedule-dialog-head { padding: 22px 20px 18px; }
|
|
|
|
|
|
.hero-schedule-dialog > .fields,
|
|
|
|
|
|
.hero-schedule-dialog > .schedule-days,
|
|
|
|
|
|
.hero-schedule-dialog > .schedule-options,
|
|
|
|
|
|
.hero-schedule-dialog > .check {
|
|
|
|
|
|
margin-right: 20px;
|
|
|
|
|
|
margin-left: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency {
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
margin: 16px 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
min-height: 62px;
|
|
|
|
|
|
padding: 9px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.schedule-frequency button span { display: none; }
|
|
|
|
|
|
.schedule-days-head { align-items: flex-start; }
|
|
|
|
|
|
.schedule-days-head > div { flex-wrap: wrap; justify-content: flex-end; }
|
|
|
|
|
|
.schedule-day-grid { gap: 4px; }
|
|
|
|
|
|
.schedule-day-grid button { min-width: 0; padding: 0 3px; font-size: 11px; }
|
|
|
|
|
|
.schedule-options { grid-template-columns: 1fr; }
|
|
|
|
|
|
.schedule-placement-grid { grid-template-columns: 1fr; }
|
|
|
|
|
|
.hero-schedule-dialog > .dialog-actions { padding: 16px 20px max(16px, var(--safe-bottom)); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------- tablet and touch refinement ---------- */
|
|
|
|
|
|
|
|
|
|
|
|
/* iPad is an operating surface, not a large phone. Cards gain enough separation to be
|
|
|
|
|
|
parsed at arm's length, but data remains dense and two-column where portrait width can
|
|
|
|
|
|
genuinely support it. */
|
2026-08-16 12:13:51 +12:00
|
|
|
|
@media (pointer: coarse) and (min-width: 821px) and (max-width: 1400px) {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
.page-head {
|
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head h1 {
|
|
|
|
|
|
font-size: 26px;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head p {
|
|
|
|
|
|
max-width: 72ch;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card {
|
|
|
|
|
|
padding: 20px 22px;
|
|
|
|
|
|
border-color: rgba(99, 110, 123, .42);
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, .025), 0 14px 40px rgba(0, 0, 0, .14);
|
|
|
|
|
|
}
|
|
|
|
|
|
.card + .card,
|
|
|
|
|
|
.grid + .card,
|
|
|
|
|
|
.card + .grid,
|
|
|
|
|
|
.grid + .grid {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.grid {
|
|
|
|
|
|
gap: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head {
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head h2 {
|
|
|
|
|
|
font-size: 15.5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head p {
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-foot {
|
|
|
|
|
|
margin-top: 18px;
|
|
|
|
|
|
padding-top: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tiles {
|
|
|
|
|
|
gap: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile {
|
|
|
|
|
|
min-height: 112px;
|
|
|
|
|
|
padding: 16px 17px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
background: linear-gradient(145deg, var(--surface-lift), var(--surface));
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile b {
|
|
|
|
|
|
font-size: 27px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters {
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .field {
|
|
|
|
|
|
flex: 1 1 calc(50% - 6px);
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .field.grow {
|
|
|
|
|
|
flex-basis: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-row {
|
|
|
|
|
|
min-height: 64px;
|
|
|
|
|
|
padding: 14px 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item {
|
|
|
|
|
|
min-height: 60px;
|
|
|
|
|
|
padding: 13px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.loghead,
|
|
|
|
|
|
.logbody {
|
|
|
|
|
|
min-width: 680px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.loghead,
|
|
|
|
|
|
.logline[data-virtual="true"] {
|
|
|
|
|
|
grid-template-columns: 128px 44px minmax(160px, 1fr) minmax(220px, 1.4fr);
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logview {
|
|
|
|
|
|
height: min(66dvh, 720px);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 820px) {
|
|
|
|
|
|
.page-head-row {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: minmax(0, 1fr);
|
|
|
|
|
|
gap: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head-row .page-head-actions {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card {
|
|
|
|
|
|
padding: 17px 18px;
|
|
|
|
|
|
border-radius: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head {
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head-actions {
|
|
|
|
|
|
width: 100%;
|
2026-08-16 12:13:51 +12:00
|
|
|
|
margin-left: 0;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
}
|
|
|
|
|
|
.card-foot > button,
|
|
|
|
|
|
.card-foot > .btn {
|
|
|
|
|
|
flex: 1 1 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
min-height: 104px;
|
|
|
|
|
|
padding: 14px;
|
|
|
|
|
|
background: linear-gradient(145deg, var(--surface-lift), var(--surface));
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile b {
|
|
|
|
|
|
font-size: 23px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tile span {
|
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .field,
|
|
|
|
|
|
.filters .field.grow {
|
|
|
|
|
|
flex: 1 1 100%;
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.filters .filter-actions {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item,
|
|
|
|
|
|
.list-row,
|
|
|
|
|
|
.list-main {
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item,
|
|
|
|
|
|
.list-row {
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-item .list-actions,
|
|
|
|
|
|
.list-row .list-actions {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
padding-left: 46px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.kv-row {
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
.dialog {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
max-height: min(88dvh, 720px);
|
|
|
|
|
|
padding: 22px;
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.scrim {
|
|
|
|
|
|
align-items: end;
|
|
|
|
|
|
padding: 12px max(12px, var(--safe-right)) max(12px, var(--safe-bottom)) max(12px, var(--safe-left));
|
|
|
|
|
|
}
|
|
|
|
|
|
.dialog-actions > button {
|
|
|
|
|
|
flex: 1 1 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-panel {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
top: calc(var(--top) + 8px);
|
|
|
|
|
|
right: max(12px, var(--safe-right));
|
|
|
|
|
|
left: max(12px, var(--safe-left));
|
|
|
|
|
|
width: auto;
|
|
|
|
|
|
max-height: calc(100dvh - var(--top) - var(--safe-bottom) - 20px);
|
|
|
|
|
|
border-radius: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bell-list {
|
|
|
|
|
|
max-height: calc(100dvh - var(--top) - var(--safe-bottom) - 120px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.toasts {
|
|
|
|
|
|
right: max(12px, var(--safe-right));
|
|
|
|
|
|
bottom: max(12px, var(--safe-bottom));
|
|
|
|
|
|
left: max(12px, var(--safe-left));
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Coarse pointers need a target, not merely larger text. This is deliberately scoped to
|
|
|
|
|
|
tablet widths so a desktop browser with touch support keeps the compact operations UI. */
|
|
|
|
|
|
@media (pointer: coarse) and (max-width: 1400px) {
|
|
|
|
|
|
button,
|
|
|
|
|
|
.btn {
|
|
|
|
|
|
min-width: 44px;
|
|
|
|
|
|
height: 44px;
|
|
|
|
|
|
padding-right: 15px;
|
|
|
|
|
|
padding-left: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
button[data-size="sm"] {
|
|
|
|
|
|
min-width: 38px;
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
padding-right: 11px;
|
|
|
|
|
|
padding-left: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar .rail-toggle,
|
|
|
|
|
|
.topbar .bell-button,
|
|
|
|
|
|
.topbar .topbar-status,
|
2026-08-16 12:13:51 +12:00
|
|
|
|
.topbar .account-trigger {
|
2026-08-15 09:23:26 +12:00
|
|
|
|
width: 44px;
|
|
|
|
|
|
height: 44px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
2026-08-16 21:20:55 +12:00
|
|
|
|
.topbar .bell,
|
|
|
|
|
|
.topbar .account-menu {
|
|
|
|
|
|
height: 44px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.topbar .omni-input {
|
|
|
|
|
|
height: 44px;
|
2026-08-15 09:23:26 +12:00
|
|
|
|
}
|
|
|
|
|
|
.rail a {
|
|
|
|
|
|
min-height: 46px;
|
|
|
|
|
|
padding: 10px 12px;
|
|
|
|
|
|
border-radius: 9px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.rail-head {
|
|
|
|
|
|
min-height: 42px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
input[type="text"],
|
|
|
|
|
|
input[type="password"],
|
|
|
|
|
|
input[type="search"],
|
|
|
|
|
|
input[type="number"],
|
|
|
|
|
|
input[type="date"],
|
|
|
|
|
|
input[type="time"],
|
|
|
|
|
|
input[type="datetime-local"],
|
|
|
|
|
|
input[type="url"],
|
|
|
|
|
|
select {
|
|
|
|
|
|
height: 44px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
select {
|
|
|
|
|
|
background-position: calc(100% - 16px) 20px, calc(100% - 11px) 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
textarea {
|
|
|
|
|
|
min-height: 104px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check {
|
|
|
|
|
|
min-height: 52px;
|
|
|
|
|
|
padding-top: 14px;
|
|
|
|
|
|
padding-bottom: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check .switch {
|
|
|
|
|
|
width: 40px;
|
|
|
|
|
|
height: 24px;
|
|
|
|
|
|
flex-basis: 40px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check .switch::after {
|
|
|
|
|
|
width: 18px;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.check input:checked + .switch::after {
|
|
|
|
|
|
transform: translateX(16px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.segments {
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.segments button {
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.crumb,
|
|
|
|
|
|
.crumbs a,
|
|
|
|
|
|
.table-row-link {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
min-height: 36px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-16 12:13:51 +12:00
|
|
|
|
/* Short laptop screens benefit from vertical density, while retaining the same readable
|
|
|
|
|
|
widths and full-size pointer targets. */
|
|
|
|
|
|
@media (pointer: fine) and (min-width: 821px) and (max-height: 800px) {
|
|
|
|
|
|
.page {
|
|
|
|
|
|
padding-top: 20px;
|
|
|
|
|
|
padding-bottom: 52px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.page-head {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card {
|
|
|
|
|
|
padding-top: 14px;
|
|
|
|
|
|
padding-bottom: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.card-head {
|
|
|
|
|
|
margin-bottom: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-15 09:23:26 +12:00
|
|
|
|
@media (hover: none) {
|
|
|
|
|
|
tbody tr:hover td,
|
|
|
|
|
|
.list-row:hover,
|
|
|
|
|
|
.bell-item:hover,
|
|
|
|
|
|
a.tile:hover {
|
|
|
|
|
|
background: inherit;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|