/*
 * Laika Infrastructure Platform: the application's stylesheet (ported from
 * Laika Monitor).
 *
 * Served by the framework's asset manager as /assets/template/css/theme.css,
 * with a content hash on the query string, so it can be cached forever and
 * still change the moment this file does.
 *
 * One file, no build step and no CSS framework. The rules below are a small
 * design system rather than a page's worth of styling: tokens first, then the
 * shell, then the components pages are assembled from. A page that needs
 * something new adds a component here; it does not add a <style> block.
 *
 *   1. Tokens
 *   2. Reset and base
 *   3. Shell: top bar, page, footer
 *   4. Typography and layout helpers
 *   5. Cards
 *   6. Forms
 *   7. Buttons
 *   8. Alerts
 *   9. Badges and status
 *  10. Tables
 *  11. Auth pages
 *  12. Marketing and empty states
 *  13. Error pages
 *  14. Figures: stat tiles
 *  15. Figures: charts
 */

/* ---- 1. Tokens ---------------------------------------------------------- */

:root {
    color-scheme: light dark;

    --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
        "Liberation Mono", monospace;

    /* Surfaces and ink. Named by role, never by colour: "--surface" survives a
       redesign, "--white" does not. */
    --bg: #f6f8fa;
    --surface: #ffffff;
    --surface-sunken: #f1f4f7;
    --line: #dde3ea;
    --line-strong: #c6cfd9;

    --ink: #111a24;
    --ink-soft: #46586b;
    --ink-faint: #6b7d90;

    --accent: #0d6c64;
    --accent-hover: #0a5750;
    --accent-ink: #ffffff;
    --accent-soft: #e2f1ef;

    --up: #0f8a52;
    --down: #c0342b;
    --degraded: #b26a00;
    --paused: #6b7d90;
    --info: #1f5fa8;

    /* Chart marks. Their own tokens rather than --accent, because the brand
       teal (#0d6c64) is too muted to read as data: it fails the chroma floor
       (C 0.081 < 0.10). These steps were validated against the surface and
       against --down, the failure marker: light CVD dE 11.0, normal 27.4. */
    --chart-line: #00897b;
    --chart-fail: var(--down);
    /* A second series (a server's network out): the info blue, and dashed,
       so the two are told apart by more than colour. */
    --chart-line-2: var(--info);

    --radius-sm: 6px;
    --radius: 10px;

    --shadow-sm: 0 1px 2px rgba(16, 26, 36, 0.06);
    --shadow: 0 1px 3px rgba(16, 26, 36, 0.08), 0 8px 24px rgba(16, 26, 36, 0.06);

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;

    --measure: 68rem;
}

/* The dark palette is the same roles with different values, which is the whole
   reason the roles are named that way. */
@media (prefers-color-scheme: dark) {
    :root {
        --bg: #0d1218;
        --surface: #141b23;
        --surface-sunken: #1a232c;
        --line: #26313c;
        --line-strong: #38454f;

        --ink: #e8eef4;
        --ink-soft: #a7b6c4;
        --ink-faint: #8394a3;

        --accent: #2aa397;
        --accent-hover: #34b8ab;
        --accent-ink: #06201e;
        --accent-soft: #10312e;

        --up: #34b46f;
        --down: #e06b61;
        --degraded: #d99425;
        --paused: #8394a3;
        --info: #5b9bdd;

        /* Validated on the dark surface: CVD dE 9.8, normal 24.8. */
        --chart-line: #2aa397;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
        --shadow: 0 1px 3px rgba(0, 0, 0, 0.5), 0 8px 24px rgba(0, 0, 0, 0.35);
    }
}

/* ---- 2. Reset and base -------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-sans);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }

/* Keyboard focus stays visible everywhere. Removing it is the most common
   accessibility regression in a hand-written stylesheet. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

code, kbd, samp, pre { font-family: var(--font-mono); font-size: 0.875em; }

/* ---- 3. Shell ----------------------------------------------------------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}

.topbar-inner {
    max-width: var(--measure);
    margin: 0 auto;
    padding: var(--space-3) var(--space-5);
    display: flex;
    align-items: center;
    gap: var(--space-5);
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--ink);
    font-weight: 650;
    letter-spacing: -0.015em;
    text-decoration: none;
    white-space: nowrap;
}

.brand:hover { color: var(--ink); }

.brand-mark {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
    flex: none;
}

.nav {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin-left: auto;
    flex-wrap: wrap;
}

.nav-link {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    font-size: 0.9375rem;
    font-weight: 500;
    text-decoration: none;
}

.nav-link:hover { background: var(--surface-sunken); color: var(--ink); }
.nav-link[aria-current="page"] { background: var(--accent-soft); color: var(--accent); }

.nav-user {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding-left: var(--space-3);
    margin-left: var(--space-2);
    border-left: 1px solid var(--line);
    color: var(--ink-soft);
    font-size: 0.9375rem;
}

.avatar {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    display: inline-grid;
    place-items: center;
    background: var(--accent-soft);
    color: var(--accent);
    font-size: 0.8125rem;
    font-weight: 650;
    flex: none;
}

.page {
    flex: 1 0 auto;
    width: 100%;
    max-width: var(--measure);
    margin: 0 auto;
    padding: var(--space-6) var(--space-5) var(--space-7);
}

.site-footer {
    border-top: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink-faint);
    font-size: 0.875rem;
}

.site-footer-inner {
    max-width: var(--measure);
    margin: 0 auto;
    padding: var(--space-5);
    display: flex;
    gap: var(--space-4);
    flex-wrap: wrap;
    justify-content: space-between;
}

/* ---- 4. Typography and layout helpers ----------------------------------- */

h1, h2, h3 { margin: 0 0 var(--space-3); letter-spacing: -0.02em; line-height: 1.25; }
h1 { font-size: 1.75rem; font-weight: 650; }
h2 { font-size: 1.25rem; font-weight: 650; }
h3 { font-size: 1rem; font-weight: 650; }

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

.muted { color: var(--ink-faint); }
.small { font-size: 0.875rem; }
.lead { font-size: 1.0625rem; color: var(--ink-soft); }

.page-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-5);
}

.page-head-text { flex: 1 1 22rem; }
.page-head p { margin: 0; color: var(--ink-faint); }

.stack > * + * { margin-top: var(--space-4); }
.stack-tight > * + * { margin-top: var(--space-2); }

.grid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

/* The one spacing utility. It exists because the Content-Security-Policy
   refuses style attributes, so a template cannot nudge one thing by hand. */
.spaced { margin-top: var(--space-5); }

/* Read aloud, never shown. A column of buttons still needs a heading, and
   "Actions" printed above them is noise to everybody who can see them. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ---- 5. Cards ----------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.card-head {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--line);
}

.card-head h2 { margin: 0; }
.card-head p { margin: var(--space-1) 0 0; color: var(--ink-faint); font-size: 0.875rem; }

.card-body { padding: var(--space-5); }

.card-foot {
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--line);
    background: var(--surface-sunken);
    border-radius: 0 0 var(--radius) var(--radius);
    font-size: 0.875rem;
    color: var(--ink-faint);
}

/* ---- 6. Forms ----------------------------------------------------------- */

.field { margin-bottom: var(--space-4); }

.field > label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: 0.9375rem;
    font-weight: 550;
}

.input {
    width: 100%;
    padding: 0.625rem 0.75rem;
    background: var(--surface);
    color: var(--ink);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: 0.9375rem;
}

.input::placeholder { color: var(--ink-faint); }

.input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.input[aria-invalid="true"] { border-color: var(--down); }

.hint { margin: var(--space-2) 0 0; color: var(--ink-faint); font-size: 0.8125rem; }

.field-error {
    margin: var(--space-2) 0 0;
    color: var(--down);
    font-size: 0.8125rem;
    font-weight: 500;
}

fieldset { border: 0; margin: 0; padding: 0; }

/* A checkbox and its words, which belong on one line and must stay clickable
   together -- a label whose text is beside the box rather than above it. */
.choice {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    margin-bottom: var(--space-2);
    font-size: 0.9375rem;
}

.choice input { margin: 0; accent-color: var(--accent); }

/* The heading over a group of choices, where there is no single control for a
   <label> to point at. */
.label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: 0.9375rem;
    font-weight: 550;
}

/* A key somebody copies may be longer than its cell. The face is set above. */
code { word-break: break-all; }

/* Something to paste into a terminal or a crontab: one line that must not be
   wrapped, because a wrapped command is a different command. It scrolls
   inside itself instead of widening the page. */
.snippet {
    margin: var(--space-2) 0 0;
    padding: var(--space-3) var(--space-4);
    overflow-x: auto;
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    color: var(--ink);
    line-height: 1.5;
    white-space: pre;
}

.snippet code { word-break: normal; }

/* Two or three mutually exclusive choices that each lead to a different form:
   links rather than radio buttons, because each one is its own page. The
   current one is marked with aria-current, which is also what styles it. */
.switch {
    display: inline-flex;
    gap: var(--space-1);
    padding: var(--space-1);
    margin-bottom: var(--space-5);
    background: var(--surface-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.switch a {
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    font-size: 0.9375rem;
    font-weight: 550;
    text-decoration: none;
}

.switch a:hover { color: var(--ink); }

.switch a[aria-current="page"] {
    background: var(--surface);
    color: var(--ink);
    box-shadow: var(--shadow-sm);
}

/* ---- 7. Buttons --------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 0.5625rem 1rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-ink);
    font: inherit;
    font-size: 0.9375rem;
    font-weight: 550;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
}

.btn:hover { background: var(--accent-hover); color: var(--accent-ink); }

.btn-secondary {
    background: var(--surface);
    border-color: var(--line-strong);
    color: var(--ink);
}

.btn-secondary:hover { background: var(--surface-sunken); color: var(--ink); }

.btn-quiet { background: transparent; color: var(--ink-soft); }
.btn-quiet:hover { background: var(--surface-sunken); color: var(--ink); }

.btn-danger { background: var(--down); color: #fff; }
.btn-danger:hover { background: var(--down); filter: brightness(0.92); color: #fff; }

.btn-block { width: 100%; }
.btn-sm { padding: 0.375rem 0.6875rem; font-size: 0.875rem; }

/* ---- 8. Alerts ---------------------------------------------------------- */

.alert {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
    border: 1px solid var(--line);
    border-left: 3px solid var(--ink-faint);
    border-radius: var(--radius-sm);
    background: var(--surface);
    font-size: 0.9375rem;
    box-shadow: var(--shadow-sm);
}

.alert p { margin: 0; }
.alert-success { border-left-color: var(--up); }
.alert-error { border-left-color: var(--down); }
.alert-warning { border-left-color: var(--degraded); }
.alert-info { border-left-color: var(--info); }

/* ---- 9. Badges and status ----------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    background: var(--surface-sunken);
    color: var(--ink-soft);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    text-transform: uppercase;
}

.badge::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: currentColor;
}

.badge-up { color: var(--up); }
.badge-down { color: var(--down); }
.badge-degraded { color: var(--degraded); }
.badge-paused,
.badge-pending { color: var(--paused); }

/* ---- 10. Tables --------------------------------------------------------- */

.table-wrap { overflow-x: auto; }

.table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }

.table th,
.table td {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
}

.table th {
    color: var(--ink-faint);
    font-size: 0.75rem;
    font-weight: 650;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-sunken); }
.table .numeric { text-align: right; font-variant-numeric: tabular-nums; }

/* ---- 11. Auth pages ----------------------------------------------------- */

/* A narrow column, vertically centred, with no navigation to wander into:
   somebody on this page is doing one thing. */
.auth {
    width: 100%;
    max-width: 25rem;
    margin: var(--space-7) auto;
    padding: 0 var(--space-4);
}

.auth-head { text-align: center; margin-bottom: var(--space-5); }
.auth-head h1 { font-size: 1.375rem; }
.auth-head p { margin: 0; color: var(--ink-faint); font-size: 0.9375rem; }

.auth-foot {
    margin-top: var(--space-4);
    text-align: center;
    font-size: 0.9375rem;
    color: var(--ink-faint);
}

.auth-aside {
    margin-top: var(--space-2);
    text-align: right;
    font-size: 0.8125rem;
}

/* ---- 12. Marketing and empty states ------------------------------------- */

.hero { padding: var(--space-6) 0 var(--space-5); max-width: 42rem; }
.hero h1 { font-size: 2.25rem; }
.hero .lead { font-size: 1.125rem; }

.feature { padding: var(--space-5); }
.feature h3 { margin-bottom: var(--space-2); }
.feature p { color: var(--ink-faint); font-size: 0.9375rem; }

.empty {
    padding: var(--space-7) var(--space-5);
    text-align: center;
    color: var(--ink-faint);
}

.empty h2 { color: var(--ink); }

.kv {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--space-2) var(--space-5);
    font-size: 0.9375rem;
    margin: 0;
}

.kv dt { color: var(--ink-faint); }
.kv dd { margin: 0; }

/* ---- 13. Error pages ---------------------------------------------------- */

.error-page {
    max-width: 32rem;
    margin: var(--space-7) auto;
    text-align: center;
}

.error-page .status {
    margin: 0 0 var(--space-2);
    font-size: 3.5rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.03em;
    color: var(--accent);
}

.error-page p { color: var(--ink-soft); }
.error-page .actions { justify-content: center; margin-top: var(--space-5); }

/* ---- 14. Figures: stat tiles -------------------------------------------- */

/* A KPI row: label, value, and a line of context. Values are proportional
   figures -- tabular-nums is for columns that must align, and makes a large
   standalone number look loose. Text wears ink tokens; state is carried by the
   status dot beside the label and by the word, never by colouring the number. */
.stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

.stat {
    padding: var(--space-4) var(--space-5);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.stat-label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-2);
    color: var(--ink-soft);
    font-size: 0.8125rem;
    font-weight: 550;
}

.stat-value {
    margin: 0;
    color: var(--ink);
    font-size: 1.75rem;
    font-weight: 650;
    line-height: 1.1;
    letter-spacing: -0.02em;
}

.stat-note { margin: var(--space-2) 0 0; color: var(--ink-faint); font-size: 0.8125rem; }

/* The one hero number a view leads with. */
.stat-hero .stat-value { font-size: 3rem; }

.dot {
    width: 0.5rem;
    height: 0.5rem;
    flex: none;
    border-radius: 50%;
    background: var(--paused);
}

.dot-up { background: var(--up); }
.dot-down { background: var(--down); }
.dot-degraded { background: var(--degraded); }

/* ---- 15. Figures: charts ------------------------------------------------ */

/* Thin marks, recessive chrome. A 2px line with round joins, the area a 10%
   wash of the same hue, hairline solid gridlines one step off the surface, and
   markers with a 2px surface ring so they stay legible where they cross the
   line. Hit targets are larger than the marks, and invisible. */
.chart { margin: 0; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }

.chart-grid { stroke: var(--line); stroke-width: 1; shape-rendering: crispEdges; }
.chart-tick { fill: var(--ink-faint); font-size: 12px; font-variant-numeric: tabular-nums; }

.chart-line {
    fill: none;
    stroke: var(--chart-line);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.chart-area { fill: var(--chart-line); fill-opacity: 0.1; stroke: none; }

.chart-dot,
.chart-fail { stroke: var(--surface); stroke-width: 2; }
.chart-dot { fill: var(--chart-line); opacity: 0; }
.chart-fail { fill: var(--chart-fail); }

/* Dots appear on hover rather than on every point: sixty markers on a line
   is noise, and the line already says where each answer was. */
.chart-hit:hover .chart-dot,
.chart-dot-lone { opacity: 1; }
.chart-target { fill: transparent; }

/* A server's charts have one or two series. The second is dashed, and each
   moment is a full-height band whose tooltip reads every series at once. */
.chart-line-2 { stroke: var(--chart-line-2); stroke-dasharray: 6 4; }
.chart-band { fill: var(--line); fill-opacity: 0; }
.chart-band:hover { fill-opacity: 0.5; }

.chart-key-line {
    width: 1.25rem;
    flex: none;
    border-top: 2px solid var(--chart-line);
}

.chart-key-line-2 { border-top: 2px dashed var(--chart-line-2); }

.chart-key {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    color: var(--ink-soft);
    font-size: 0.8125rem;
}

.chart-key-fail {
    width: 0.625rem;
    height: 0.625rem;
    flex: none;
    border-radius: 50%;
    background: var(--chart-fail);
}

/* Windows high-contrast replaces every colour; the line and the failure marker
   must still be told apart, so they take two different system colours. */
@media (forced-colors: active) {
    .chart-line { stroke: CanvasText; }
    .chart-line-2 { stroke: LinkText; }
    .chart-key-line { border-top-color: CanvasText; }
    .chart-key-line-2 { border-top-color: LinkText; }
    .chart-area { fill: none; }
    .chart-fail { fill: Mark; stroke: Canvas; }
    .chart-key-fail, .dot { forced-color-adjust: none; background: Mark; }
    /* The shadow is what marks the current choice, and forced colours drop it. */
    .switch a[aria-current="page"] { outline: 2px solid Highlight; }
}

/* ---- Narrow screens ----------------------------------------------------- */

@media (max-width: 40rem) {
    .topbar-inner { padding: var(--space-3) var(--space-4); gap: var(--space-3); }
    .page { padding: var(--space-5) var(--space-4) var(--space-6); }
    .nav { gap: 0; }
    .nav-user { padding-left: var(--space-2); margin-left: var(--space-1); }
    .nav-user-name { display: none; }
    h1 { font-size: 1.5rem; }
    .hero h1 { font-size: 1.875rem; }
}

/* A package's features: a tick or a cross, then the name (Package page). */
.feature-list {
    list-style: none;
    padding: 0;
    margin: 0.5rem 0 0;
    display: grid;
    gap: 0.25rem;
}
