/*
 * Umbraco Hosting — design system.
 *
 * Everything is expressed as tokens first and components second, so a colour or a step in the type
 * scale changes in one place. Both themes are chosen deliberately: the dark values are their own
 * steps against a dark surface, not an inverted copy of the light ones.
 */

:root {
    /* --- palette: neutrals ------------------------------------------------ */
    --surface: #ffffff;
    --surface-sunken: #f6f7f9;
    --surface-raised: #ffffff;
    --surface-inset: #f1f3f5;

    --ink: #12141a;
    --ink-secondary: #4d545e;
    --ink-muted: #7b828c;

    --rule: #e4e7ec;
    --rule-strong: #cdd2da;

    /* --- palette: accents -------------------------------------------------
     * Blue carries actions and identity. The status hues are reserved: they never stand in for a
     * brand colour, so "green" always means healthy and nothing else. */
    --accent: #2a78d6;
    --accent-hover: #2062b4;
    --accent-ink: #ffffff;
    --accent-wash: #eaf2fd;

    --good: #0f8a4d;
    --good-wash: #e7f5ed;
    --warn: #b26a00;
    --warn-wash: #fdf3e2;
    --bad: #c8322f;
    --bad-wash: #fdeceb;

    /* --- type ------------------------------------------------------------- */
    --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;

    --text-xs: 0.75rem;
    --text-sm: 0.8125rem;
    --text-base: 0.9375rem;
    --text-md: 1rem;
    --text-lg: 1.25rem;
    --text-xl: 1.625rem;
    --text-2xl: 2.25rem;
    --text-3xl: clamp(2.25rem, 1.6rem + 2.6vw, 3.25rem);

    /* --- space, shape, depth ---------------------------------------------- */
    --s1: 0.25rem;
    --s2: 0.5rem;
    --s3: 0.75rem;
    --s4: 1rem;
    --s5: 1.5rem;
    --s6: 2rem;
    --s7: 3rem;
    --s8: 4rem;

    --radius: 8px;
    --radius-lg: 12px;
    --radius-pill: 999px;

    --shadow-sm: 0 1px 2px rgba(18, 20, 26, 0.06), 0 1px 3px rgba(18, 20, 26, 0.04);
    --shadow-md: 0 4px 12px rgba(18, 20, 26, 0.08), 0 1px 3px rgba(18, 20, 26, 0.04);

    --focus: 0 0 0 3px rgba(42, 120, 214, 0.35);

    color-scheme: light;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --surface: #14161a;
        --surface-sunken: #0e1013;
        --surface-raised: #1b1e24;
        --surface-inset: #22262d;

        --ink: #f2f4f7;
        --ink-secondary: #b3bac4;
        --ink-muted: #8891a0;

        --rule: #282c34;
        --rule-strong: #3a3f4a;

        --accent: #5b9bea;
        --accent-hover: #79aff1;
        --accent-ink: #0b0e13;
        --accent-wash: #17263a;

        --good: #3ec07a;
        --good-wash: #11291d;
        --warn: #e2a33f;
        --warn-wash: #2c2210;
        --bad: #ef6f6c;
        --bad-wash: #2e1716;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
        --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.55);

        --focus: 0 0 0 3px rgba(91, 155, 234, 0.4);

        color-scheme: dark;
    }
}

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

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

/*
 * The page is a column: header, content that takes the slack, footer. Without this the footer sits
 * directly under short content and leaves a band of background below it, which reads as broken.
 */
body {
    margin: 0;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--surface-sunken);
    color: var(--ink);
    font: var(--text-base) / 1.6 var(--font);
    -webkit-font-smoothing: antialiased;
}

body > main,
body > .page-body {
    flex: 1 0 auto;
}

body > .site-footer {
    flex: none;
}

/* A single visible focus treatment everywhere, so keyboard users are never guessing. */
:where(a, button, input, select, textarea, summary):focus-visible {
    outline: none;
    box-shadow: var(--focus);
    border-radius: var(--radius);
}

h1, h2, h3, h4 {
    margin: 0;
    line-height: 1.2;
    letter-spacing: -0.02em;
    font-weight: 650;
}

p { margin: 0; }

a { color: var(--accent); }

.wrap {
    width: 100%;
    max-width: 76rem;
    margin-inline: auto;
    padding-inline: var(--s5);
}

.wrap-narrow {
    width: 100%;
    max-width: 30rem;
    margin-inline: auto;
    padding-inline: var(--s5);
}

.stack > * + * { margin-top: var(--s4); }
.stack-lg > * + * { margin-top: var(--s6); }

.muted { color: var(--ink-muted); }
.secondary { color: var(--ink-secondary); }
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
.nums { font-variant-numeric: tabular-nums; }

/* --- app chrome ----------------------------------------------------------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    backdrop-filter: saturate(1.4) blur(10px);
    border-bottom: 1px solid var(--rule);
}

.topbar-inner {
    display: flex;
    align-items: center;
    gap: var(--s5);
    min-height: 60px;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    font-weight: 680;
    font-size: var(--text-md);
    letter-spacing: -0.02em;
    color: var(--ink);
    text-decoration: none;
    white-space: nowrap;
}

.brand-mark {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    background: linear-gradient(135deg, var(--accent), #7c4bd0);
    flex: none;
}

.topnav {
    display: flex;
    align-items: center;
    gap: var(--s1);
    margin-inline-start: auto;
    flex-wrap: wrap;
}

.topnav a {
    padding: var(--s2) var(--s3);
    border-radius: var(--radius);
    color: var(--ink-secondary);
    text-decoration: none;
    font-size: var(--text-base);
}

.topnav a:hover { background: var(--surface-inset); color: var(--ink); }
.topnav a[aria-current="page"] { color: var(--ink); background: var(--surface-inset); font-weight: 600; }

/* --- header menus ---------------------------------------------------------
 *
 * Opened by :hover and :focus-within and by nothing else, so they work with scripting off and before
 * any script has run. The trigger is a real link to the page the menu is about; the script in the
 * layout only keeps aria-expanded truthful and adds Escape.
 *
 * The wrapper has no padding of its own between the trigger and the panel — the panel starts at
 * 100% and the header's own padding is the only gap — because a hover menu with a gap under it
 * closes while the pointer crosses towards it. */

.nav-menu-wrap { position: relative; }

/* Pushed to the end of the row and given a rule to sit behind, so the account is visibly not one of
 * the working destinations next to it. */
.nav-menu-end {
    margin-inline-start: var(--s3);
    padding-inline-start: var(--s3);
    border-inline-start: 1px solid var(--rule);
}

.nav-trigger { display: inline-flex; align-items: center; gap: var(--s2); }

.nav-caret {
    width: 0;
    height: 0;
    border-inline: 4px solid transparent;
    border-block-start: 5px solid currentColor;
    opacity: 0.55;
    transition: transform 120ms ease;
}

.nav-menu-wrap:hover .nav-caret,
.nav-menu-wrap:focus-within .nav-caret { transform: rotate(180deg); }

.nav-menu {
    display: none;
    position: absolute;
    inset-block-start: 100%;
    inset-inline-end: 0;
    z-index: 30;
    min-width: 16rem;
    padding: var(--s2);
    background: var(--surface-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.nav-menu-wrap:hover .nav-menu,
.nav-menu-wrap:focus-within .nav-menu { display: block; }

/* Escape, from the layout's script. Last, so it wins over the two rules above — which are still true
 * at that moment, because focus has deliberately been put back on the trigger. */
.nav-menu-wrap[data-dismissed="true"] .nav-menu { display: none; }

.topnav .nav-menu a {
    display: block;
    padding: var(--s2) var(--s3);
    color: var(--ink);
    font-weight: 550;
}

.topnav .nav-menu a[aria-current="page"] { color: var(--accent); background: var(--accent-wash); }

.nav-menu-hint {
    display: block;
    margin-block-start: 2px;
    color: var(--ink-muted);
    font-size: var(--text-xs);
    font-weight: 400;
    line-height: 1.35;
}

/* Signing out is a POST, so it is a button rather than a link. Styled as one of the entries because
 * it is one of the entries — a button that looks like a button here would read as the menu's primary
 * action, which signing out is not. */
.nav-menu-form {
    margin-block-start: var(--s2);
    padding-block-start: var(--s2);
    border-block-start: 1px solid var(--rule);
}

.nav-menu-form button {
    display: block;
    width: 100%;
    padding: var(--s2) var(--s3);
    border: 0;
    border-radius: var(--radius);
    background: none;
    color: var(--ink-secondary);
    font: inherit;
    font-weight: 550;
    text-align: start;
    cursor: pointer;
}

.nav-menu-form button:hover { background: var(--surface-inset); color: var(--ink); }

/* Narrow screens have no hover and no room for a panel pinned to a trigger. The menus become plain
 * stacked lists under the header, which is the same markup read in source order. */
@media (max-width: 44rem) {
    .nav-menu-end { margin-inline-start: 0; padding-inline-start: 0; border-inline-start: 0; }
    .nav-caret { display: none; }

    .nav-menu {
        display: block;
        position: static;
        min-width: 0;
        padding: 0;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        background: none;
    }

    .nav-menu-wrap[data-dismissed="true"] .nav-menu { display: block; }
    .nav-menu-hint { display: none; }
}

/* --- buttons -------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    padding: 0.5rem 0.875rem;
    border: 1px solid transparent;
    border-radius: var(--radius);
    background: var(--surface-raised);
    color: var(--ink);
    font: inherit;
    font-weight: 550;
    line-height: 1.4;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 120ms ease, border-color 120ms ease;
}

.btn:hover { background: var(--surface-inset); }

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

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

.btn-outline { border-color: var(--rule-strong); }
.btn-outline:hover { border-color: var(--ink-muted); }

.btn-danger { color: var(--bad); border-color: var(--rule-strong); }
.btn-danger:hover { background: var(--bad-wash); border-color: var(--bad); }

.btn-sm { padding: 0.3125rem 0.625rem; font-size: var(--text-sm); }
.btn-lg { padding: 0.6875rem 1.25rem; font-size: var(--text-md); }

.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* --- surfaces ------------------------------------------------------------- */

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

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

.card-head {
    display: flex;
    align-items: center;
    gap: var(--s4);
    padding: var(--s4) var(--s5);
    border-bottom: 1px solid var(--rule);
}

.card-head h2 { font-size: var(--text-md); }
.card-head .btn-row { margin-inline-start: auto; }

.page-head {
    display: flex;
    align-items: flex-end;
    gap: var(--s4);
    flex-wrap: wrap;
    margin-bottom: var(--s5);
}

.page-head h1 { font-size: var(--text-xl); }
.page-head .btn-row { margin-inline-start: auto; }

main { padding-block: var(--s6) var(--s8); }

/* --- status --------------------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--s1);
    padding: 0.125rem 0.5rem;
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

/* The dot is the second channel: status never rests on colour alone. */
.badge::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: none;
}

.badge-good { background: var(--good-wash); color: var(--good); }
.badge-warn { background: var(--warn-wash); color: var(--warn); }
.badge-bad { background: var(--bad-wash); color: var(--bad); }
.badge-idle { background: var(--surface-inset); color: var(--ink-muted); }

/* --- tables --------------------------------------------------------------- */

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

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-base);
}

table.data th,
table.data td {
    padding: var(--s3) var(--s5);
    text-align: left;
    border-bottom: 1px solid var(--rule);
    vertical-align: middle;
}

table.data th {
    font-size: var(--text-xs);
    font-weight: 620;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-muted);
    background: var(--surface-inset);
    white-space: nowrap;
}

table.data tbody tr:last-child td { border-bottom: none; }
table.data tbody tr:hover { background: var(--surface-inset); }
table.data td.right, table.data th.right { text-align: right; }

/* --- forms ---------------------------------------------------------------- */

.field { display: grid; gap: var(--s2); }
.field label { font-size: var(--text-sm); font-weight: 600; }
.field .hint { font-size: var(--text-sm); color: var(--ink-muted); }

.input, .select {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
}

.input:focus, .select:focus { outline: none; box-shadow: var(--focus); border-color: var(--accent); }

/* A run of settings under a heading, on a page that holds forty of them.
 *
 * Two columns where there is room. These are short labelled boxes rather than prose, and one column of
 * them is a page you scroll for a while to find out it had nothing else on it. The rule and the heading
 * are what make the subject visible while scrolling past — a gap alone reads as spacing, not structure. */

.settings-group {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    gap: var(--s4) var(--s5);
    align-items: start;
    margin: 0;
    padding: var(--s5) 0 0;
    border: 0;
    border-top: 1px solid var(--rule);
}

.settings-group:first-of-type { padding-top: 0; border-top: 0; }

/* A rendered legend sits outside the fieldset's own layout box, so it is above the grid rather than in
 * it — the span is there for the engine that disagrees, where it would otherwise take one cell and
 * push the first setting sideways. */
.settings-group > legend {
    grid-column: 1 / -1;
    width: 100%;
    padding: 0 0 var(--s3);
    color: var(--ink);
    font-size: var(--text-sm);
    font-weight: 650;
    letter-spacing: 0.01em;
}

/* A checkbox has its explanation inside the label, so it is taller than the boxes beside it and reads
 * better spanning the row. */
.settings-group > .field:has(.check) { grid-column: 1 / -1; }

/* --- messages ------------------------------------------------------------- */

.notice {
    display: flex;
    gap: var(--s3);
    padding: var(--s4);
    border-radius: var(--radius);
    border: 1px solid var(--rule);
    background: var(--surface-inset);
    font-size: var(--text-base);
}

.notice-error { background: var(--bad-wash); border-color: color-mix(in srgb, var(--bad) 35%, transparent); color: var(--bad); }
.notice-ok { background: var(--good-wash); border-color: color-mix(in srgb, var(--good) 35%, transparent); color: var(--good); }
.notice-info { background: var(--accent-wash); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }

/* An empty state is a designed state, not a blank area. */
.empty {
    display: grid;
    justify-items: center;
    gap: var(--s3);
    padding: var(--s8) var(--s5);
    text-align: center;
    color: var(--ink-muted);
}

.empty h3 { font-size: var(--text-md); color: var(--ink); }
.empty p { max-width: 40ch; }

/* --- landing -------------------------------------------------------------- */

.hero {
    padding-block: var(--s8) var(--s7);
    text-align: center;
    background:
        radial-gradient(60rem 24rem at 50% -8rem, var(--accent-wash), transparent 70%),
        var(--surface);
    border-bottom: 1px solid var(--rule);
}

.hero h1 {
    font-size: var(--text-3xl);
    max-width: 20ch;
    margin-inline: auto;
}

.hero p.lede {
    margin-top: var(--s4);
    margin-inline: auto;
    max-width: 56ch;
    font-size: var(--text-lg);
    line-height: 1.5;
    color: var(--ink-secondary);
}

.hero .btn-row { justify-content: center; margin-top: var(--s6); }

.eyebrow {
    display: inline-block;
    margin-bottom: var(--s4);
    padding: 0.25rem 0.75rem;
    border-radius: var(--radius-pill);
    background: var(--surface-inset);
    border: 1px solid var(--rule);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-secondary);
}

.section-head { text-align: center; margin-bottom: var(--s6); }
.section-head h2 { font-size: var(--text-2xl); }
.section-head p { margin-top: var(--s3); color: var(--ink-secondary); font-size: var(--text-md); }

.plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: var(--s5);
    align-items: start;
}

.plan {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: var(--s5);
    background: var(--surface-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.plan-featured {
    border-color: var(--accent);
    box-shadow: var(--shadow-md);
}

.plan-flag {
    position: absolute;
    top: calc(var(--s3) * -1);
    left: 50%;
    transform: translateX(-50%);
    padding: 0.125rem 0.625rem;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: var(--accent-ink);
    font-size: var(--text-xs);
    font-weight: 650;
    white-space: nowrap;
}

.plan h3 { font-size: var(--text-md); }
.plan .plan-note { margin-top: var(--s2); color: var(--ink-muted); font-size: var(--text-sm); min-height: 2.6em; }

.price { display: flex; align-items: baseline; gap: var(--s2); margin-block: var(--s4); }
.price .amount { font-size: var(--text-2xl); font-weight: 680; letter-spacing: -0.03em; }
.price .per { color: var(--ink-muted); font-size: var(--text-sm); }

.spec { list-style: none; margin: 0 0 var(--s5); padding: 0; display: grid; gap: var(--s2); font-size: var(--text-base); }
.spec li { display: flex; gap: var(--s2); align-items: baseline; }
.spec .k { color: var(--ink-muted); min-width: 8.5rem; }
.spec .v { font-variant-numeric: tabular-nums; }

.plan .btn { margin-top: auto; }

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

.feature h3 { font-size: var(--text-md); margin-bottom: var(--s2); }
.feature p { color: var(--ink-secondary); }

section.band { padding-block: var(--s8); }
section.band + section.band { border-top: 1px solid var(--rule); }
section.band.on-surface { background: var(--surface); }

/* --- stat tiles ----------------------------------------------------------- */

.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--s4);
}

.stat {
    padding: var(--s4) var(--s5);
    background: var(--surface-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
}

.stat .label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-muted); }
.stat .value { margin-top: var(--s2); font-size: var(--text-xl); font-weight: 650; letter-spacing: -0.02em; }
.stat .sub { margin-top: var(--s1); font-size: var(--text-sm); color: var(--ink-muted); }

/*
 * Checkbox and radio rows. The whole row is the label, so the hit target is the sentence rather than
 * a 13px square, and the accent colour comes from the theme so both schemes get a control that
 * belongs to the page.
 */
.check {
    display: flex;
    align-items: flex-start;
    gap: var(--s3);
    padding: var(--s2) 0;
    cursor: pointer;
    font-size: var(--text-base);
}

.check input {
    margin: 0;
    flex: none;
    width: 1.05rem;
    height: 1.05rem;
    accent-color: var(--accent);

    /* Optical alignment with the first line of the label rather than its box. */
    margin-top: 0.15rem;
}

.check input:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.check .note {
    display: block;
    margin-top: var(--s1);
    font-size: var(--text-sm);
    color: var(--ink-muted);
}

/* --- meter ---------------------------------------------------------------- */

.meter { height: 6px; border-radius: var(--radius-pill); background: var(--surface-inset); overflow: hidden; }
.meter > span { display: block; height: 100%; background: var(--accent); border-radius: inherit; }
.meter.is-warn > span { background: var(--warn); }
.meter.is-bad > span { background: var(--bad); }

/* --- sub navigation (instance dashboard) ---------------------------------- */

.subnav {
    display: flex;
    gap: var(--s1);
    overflow-x: auto;
    border-bottom: 1px solid var(--rule);
    margin-bottom: var(--s5);
}

.subnav a {
    padding: var(--s3) var(--s4);
    border-bottom: 2px solid transparent;
    color: var(--ink-secondary);
    text-decoration: none;
    font-weight: 550;
    white-space: nowrap;
}

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

/* Keyed off aria-current so the visual and accessible states cannot drift apart. */
.subnav a[aria-current="page"] {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* The second row of a two-level nav: which tab within the section the first row selected.
 *
 * Pills rather than a second underlined row, because two rows of underlined tabs read as two peers
 * and the point of the pair is that one is inside the other. */

.subnav:has(+ .subnav-inner) { margin-bottom: var(--s3); }

.subnav-inner {
    border-bottom: 0;
    margin-bottom: var(--s5);
}

.subnav-inner a {
    padding: var(--s2) var(--s3);
    border-bottom: 0;
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
}

.subnav-inner a:hover { background: var(--surface-inset); }

.subnav-inner a[aria-current="page"] {
    color: var(--ink);
    background: var(--surface-inset);
    border-bottom-color: transparent;
}

/* --- folded-away values ----------------------------------------------------
 *
 * For a value that is the customer's own and readable on request, but should not be on screen by
 * default — a variable named like an API key that was never marked as a credential. A details element
 * rather than a script, so the fallback with scripting off is "it opens" rather than "it is gone". */

.reveal > summary {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    color: var(--ink-secondary);
    font-size: var(--text-sm);
    cursor: pointer;
    list-style: none;
}

.reveal > summary::-webkit-details-marker { display: none; }
.reveal > summary:hover { color: var(--ink); }

.reveal[open] > summary {
    margin-bottom: var(--s1);
    font-size: var(--text-xs);
}

/* Which of the two labels the summary is showing is a fact about the element's own state, so it is
 * expressed as one — no script has to remember to change the word. */
.reveal-open { display: none; }
.reveal[open] .reveal-closed { display: none; }
.reveal[open] .reveal-open { display: inline; }

/* --- key/value lists ------------------------------------------------------- */

.kv {
    display: grid;
    grid-template-columns: minmax(9rem, max-content) 1fr;
    gap: var(--s3) var(--s5);
    margin: 0;
}

.kv dt { color: var(--ink-muted); font-size: var(--text-sm); }
.kv dd { margin: 0; overflow-wrap: anywhere; }

@media (max-width: 34rem) {
    .kv { grid-template-columns: 1fr; gap: var(--s1); }
    .kv dd + dt { margin-top: var(--s3); }
}

/* --- charts ---------------------------------------------------------------- */

.chart {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

.chart .axis { stroke: var(--rule); stroke-width: 1; }
.chart .grid { stroke: var(--rule); stroke-width: 1; stroke-dasharray: 2 3; }
.chart .tick { fill: var(--ink-muted); font-size: 10px; font-family: var(--font); }

/* 2px lines, and the area is a wash rather than a solid so an overlapping series stays readable. */
.chart .line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart .area { fill: var(--accent); opacity: 0.12; }

/*
 * Bars for a small number of discrete buckets — months of revenue, not a time series. Plain elements
 * rather than SVG: twelve columns are cheaper as a grid than as a drawing, they reflow at narrow
 * widths, and each bar can carry its own title for a hover reading without any script.
 */
.bars {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    align-items: end;
    gap: var(--s2);
    height: 9rem;
}

.bars .bar-col {
    display: grid;
    grid-template-rows: 1fr auto;
    gap: var(--s2);
    height: 100%;
    min-width: 0;
}

/* The track is the full height, so bars grow from a common baseline. */
.bars .bar-track {
    display: flex;
    align-items: flex-end;
    height: 100%;
    background: var(--surface-inset);
    border-radius: var(--radius);
    overflow: hidden;
}

.bars .bar-fill {
    width: 100%;
    background: var(--accent);
    border-radius: var(--radius) var(--radius) 0 0;
    min-height: 2px;
}

.bars .bar-label {
    text-align: center;
    font-size: var(--text-xs);
    color: var(--ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s4);
    margin-top: var(--s3);
    font-size: var(--text-sm);
    color: var(--ink-secondary);
}

.chart-legend .swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 3px;
    margin-inline-end: var(--s2);
    vertical-align: baseline;
}

.chart-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
    gap: var(--s5);
}

/* --- log viewer ------------------------------------------------------------ */

.logview {
    margin: 0;
    padding: var(--s4);
    max-height: 26rem;
    overflow: auto;
    background: var(--surface-inset);
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    line-height: 1.55;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    color: var(--ink-secondary);
}

/* --- danger zone ----------------------------------------------------------- */

.danger {
    border-color: color-mix(in srgb, var(--bad) 40%, var(--rule));
}

.danger .card-head { border-bottom-color: color-mix(in srgb, var(--bad) 25%, var(--rule)); }
.danger .card-head h2 { color: var(--bad); }

.danger-row {
    display: flex;
    align-items: center;
    gap: var(--s5);
    padding: var(--s4) var(--s5);
    border-bottom: 1px solid var(--rule);
    flex-wrap: wrap;
}

.danger-row:last-child { border-bottom: none; }
.danger-row .btn-row { margin-inline-start: auto; }
.danger-row h3 { font-size: var(--text-base); margin-bottom: var(--s1); }
.danger-row p { color: var(--ink-muted); font-size: var(--text-sm); max-width: 52ch; }

/* --- breadcrumbs and page heads ------------------------------------------- */

.crumbs {
    display: flex;
    gap: var(--s2);
    align-items: center;
    font-size: var(--text-sm);
    color: var(--ink-muted);
    margin-bottom: calc(var(--s5) * -1 + var(--s2));
}

.crumbs a { color: var(--ink-secondary); text-decoration: none; }
.crumbs a:hover { color: var(--ink); text-decoration: underline; }

.head-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s3);
    margin-top: var(--s2);
    font-size: var(--text-sm);
}

/* A table cell's primary link: reads as text until you need it. */
.row-title { color: var(--ink); text-decoration: none; font-weight: 600; }
.row-title:hover { color: var(--accent); text-decoration: underline; }

.split-label {
    display: flex;
    justify-content: space-between;
    gap: var(--s3);
    margin-bottom: var(--s2);
    font-size: var(--text-sm);
}

/* --- segmented range picker ------------------------------------------------ */

.range-picker {
    display: flex;
    margin-inline-start: auto;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius);
    overflow: hidden;
}

.range-picker a {
    padding: 0.3125rem 0.75rem;
    color: var(--ink-secondary);
    text-decoration: none;
    font-size: var(--text-sm);
    white-space: nowrap;
    border-inline-start: 1px solid var(--rule-strong);
}

.range-picker a:first-child { border-inline-start: none; }
.range-picker a:hover { background: var(--surface-inset); color: var(--ink); }

.range-picker a[aria-current="page"] {
    background: var(--accent);
    color: var(--accent-ink);
    font-weight: 600;
}

.chart-scale {
    margin-top: var(--s2);
    font-size: var(--text-xs);
    color: var(--ink-muted);
}

/* --- misc ------------------------------------------------------------------ */

.hint { font-size: var(--text-sm); color: var(--ink-muted); }

.split { display: flex; gap: var(--s5); flex-wrap: wrap; align-items: flex-start; }
.split > * { flex: 1 1 20rem; min-width: 0; }

.inline-form { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: flex-start; }
.inline-form .field { flex: 1 1 14rem; }

.copy-field { display: flex; gap: var(--s2); }
.copy-field .input { flex: 1 1 auto; }

/* --- footer --------------------------------------------------------------- */

.site-footer {
    border-top: 1px solid var(--rule);
    background: var(--surface);
    color: var(--ink-muted);
    font-size: var(--text-sm);
}

.site-footer .wrap { display: flex; flex-wrap: wrap; gap: var(--s4); padding-block: var(--s5); }
.site-footer a { color: var(--ink-secondary); text-decoration: none; }
.site-footer a:hover { color: var(--ink); }
.site-footer .spacer { margin-inline-start: auto; }

@media (max-width: 40rem) {
    .topbar-inner { flex-wrap: wrap; padding-block: var(--s3); }
    .topnav { margin-inline-start: 0; width: 100%; }
    .page-head .btn-row { margin-inline-start: 0; }

    /* The section nav wraps on a phone instead of scrolling sideways.
       Ten admin sections do not fit across a handset, and a horizontally scrolling row gives no sign
       that anything is off to the right: no scrollbar is drawn on iOS or Android, so everything past
       the fourth entry is simply invisible to anyone who does not think to swipe a navigation bar.
       That is how a whole section can be shipped, be present in the markup, and still not exist as
       far as the person using it is concerned. Two or three lines of nav is the right price for
       every section being visible. */
    .subnav {
        flex-wrap: wrap;
        overflow-x: visible;
        gap: 0 var(--s1);
    }

    .subnav a { padding-inline: var(--s3); }

    /* Wide content still scrolls — a data table has no sensible narrow form — but it gets an edge
       shadow so it is obvious there is more of it. */
    .table-scroll {
        background:
            linear-gradient(to right, var(--surface) 30%, transparent) left / 2rem 100% no-repeat,
            linear-gradient(to left, var(--surface) 30%, transparent) right / 2rem 100% no-repeat;
        background-attachment: local, local;
    }
}

/* --- public status page ---------------------------------------------------------------

   The daily availability strip. One element per day rather than an SVG, because the shape is a
   sequence of identical bars and flexbox already draws that — an SVG would need a viewBox that
   changes with the window length and would not reflow on a phone. */

.status-headline {
    display: flex;
    align-items: center;
    gap: var(--s3);
}

.status-dot {
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 50%;
    flex: none;
}

.status-good { background: var(--good); }
.status-warn { background: var(--warn); }
.status-bad  { background: var(--bad); }

.uptime-bars {
    display: flex;
    gap: 2px;
    align-items: stretch;
    height: 2.5rem;
}

.uptime-day {
    flex: 1 1 0;

    /* Below this a day is a hairline nobody can hover, and ninety of them on a narrow phone would
       otherwise round to nothing at all. The row scrolls instead. */
    min-width: 3px;
    border-radius: 2px;
}

.uptime-day-good { background: var(--good); }
.uptime-day-warn { background: var(--warn); }
.uptime-day-bad  { background: var(--bad); }

.uptime-legend {
    display: flex;
    justify-content: space-between;
    font-size: var(--text-xs);
}

@media (max-width: 40rem) {
    /* Ninety three-pixel bars do not fit a phone, so the strip scrolls rather than shrinking each
       day past the point of being readable or tappable. */
    .uptime-bars {
        overflow-x: auto;
    }
}

/* Hidden from sight, kept for screen readers.
   
   Used since Security.cshtml and _Version.cshtml were written and never actually defined, so every
   "visually hidden" label on the platform has been rendering in full — the empty-looking column
   headers in those tables were showing the word "Actions". Also what makes the file pickers work: a
   file input styled as a button is a label wrapping a hidden input, and hidden has to mean hidden to
   the eye but not to assistive technology, which display:none is not. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* --- content templates ---------------------------------------------------
 *
 * The picker in the order flow and on a site's Design tab. A template is a *look*, so the card leads
 * with a screenshot and the words come second — a grid of titles and taglines would make five very
 * different designs indistinguishable at the moment somebody is choosing between them.
 *
 * The card is a label wrapping a radio, so the whole thing is one target and the browser does the
 * keyboard handling. Selection is styled off :has(:checked) rather than a class the server writes,
 * which is what makes it respond to the click rather than to the next page load. */

.tpl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: var(--s4);
    align-items: stretch;
}

.tpl {
    position: relative;
    display: flex;
    flex-direction: column;
    cursor: pointer;
    background: var(--surface-raised);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: border-color 0.12s, box-shadow 0.12s;
}

.tpl:hover { border-color: var(--rule-strong); box-shadow: var(--shadow-md); }

.tpl:has(input:checked) {
    border-color: var(--accent);
    box-shadow: var(--focus);
}

/* The radio itself is off-screen: the card is the control. Keeping it focusable rather than hidden
   with display:none is what preserves arrow-key movement through the group. */
.tpl input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.tpl:has(input:focus-visible) { box-shadow: var(--focus); border-color: var(--accent); }

.tpl-shot {
    position: relative;
    aspect-ratio: 16 / 9;
    background: var(--surface-inset);
    border-bottom: 1px solid var(--rule);
    overflow: hidden;
}

.tpl-shot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    display: block;
}

/* The blank site has no screenshot, and a missing image would leave a hole exactly where every
   other card carries its whole argument. A drawn placeholder says "empty page" instead. */
.tpl-blank {
    display: grid;
    place-items: center;
    height: 100%;
    gap: var(--s2);
    background:
        repeating-linear-gradient(
            45deg,
            transparent 0 10px,
            color-mix(in srgb, var(--rule) 55%, transparent) 10px 11px);
}

.tpl-blank span {
    padding: var(--s2) var(--s3);
    border-radius: var(--radius-pill);
    background: var(--surface-raised);
    border: 1px solid var(--rule);
    font-size: var(--text-xs);
    color: var(--ink-muted);
    font-weight: 600;
}

.tpl-preview {
    position: absolute;
    right: var(--s2);
    bottom: var(--s2);
    padding: 0.25rem 0.625rem;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-pill);
    background: var(--surface-raised);
    color: var(--ink-secondary);
    font: inherit;
    font-size: var(--text-xs);
    font-weight: 600;
    cursor: pointer;
    opacity: 0.94;
}

.tpl-preview:hover { color: var(--ink); border-color: var(--ink-muted); }

.tpl-body {
    display: flex;
    flex-direction: column;
    gap: var(--s1);
    padding: var(--s4);
}

.tpl-title {
    display: flex;
    align-items: center;
    gap: var(--s2);
    font-weight: 650;
}

/* The tick only exists once the card is chosen. A permanently visible empty circle reads as a
   checkbox somebody forgot to tick. */
.tpl-tick {
    flex: none;
    width: 1.125rem;
    height: 1.125rem;
    border-radius: 50%;
    border: 1px solid var(--rule-strong);
    display: grid;
    place-items: center;
    font-size: 0.6875rem;
    color: transparent;
}

.tpl:has(input:checked) .tpl-tick {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-ink);
}

.tpl-tagline { font-size: var(--text-sm); color: var(--ink-secondary); }

.tpl-industry {
    margin-top: var(--s2);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-muted);
}

.tpl-current {
    position: absolute;
    top: var(--s2);
    left: var(--s2);
    padding: 0.125rem 0.5rem;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: var(--accent-ink);
    font-size: var(--text-xs);
    font-weight: 650;
}

/* --- the preview dialog --------------------------------------------------
 *
 * The design's own home page in an iframe, not a picture of it. A screenshot answers "what colour is
 * it"; somebody choosing a design wants to scroll it, read the copy at full size and see what it does
 * at a phone's width. So the dialog is mostly stage, and the width buttons resize the frame rather
 * than scaling it — the page inside re-runs its own media queries, which is the thing being shown. */

.tpl-dialog {
    width: min(76rem, 94vw);
    height: min(88vh, 60rem);
    max-width: none;
    max-height: none;
    padding: 0;
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    background: var(--surface-raised);
    color: var(--ink);
    box-shadow: var(--shadow-md);
    overflow: hidden;
}

.tpl-dialog[open] {
    display: flex;
    flex-direction: column;
}

.tpl-dialog::backdrop { background: rgba(10, 12, 16, 0.6); }

.tpl-dialog-head {
    display: flex;
    align-items: center;
    gap: var(--s3);
    flex: none;
    padding: var(--s3) var(--s4);
    border-bottom: 1px solid var(--rule);
}

.tpl-dialog-head h3 { font-size: var(--text-md); margin-inline-end: auto; }

.tpl-dialog-x {
    flex: none;
    width: 1.75rem;
    height: 1.75rem;
    border: 0;
    border-radius: var(--radius);
    background: none;
    color: var(--ink-muted);
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

.tpl-dialog-x:hover { background: var(--surface-inset); color: var(--ink); }

.tpl-widths {
    display: flex;
    gap: 2px;
    padding: 2px;
    border-radius: var(--radius);
    background: var(--surface-inset);
}

.tpl-widths button {
    padding: 0.25rem 0.625rem;
    border: 0;
    border-radius: calc(var(--radius) - 2px);
    background: none;
    color: var(--ink-muted);
    font: inherit;
    font-size: var(--text-xs);
    font-weight: 600;
    cursor: pointer;
}

.tpl-widths button[aria-pressed="true"] {
    background: var(--surface-raised);
    color: var(--ink);
    box-shadow: var(--shadow-sm);
}

/* The stage is the only part that grows, so the frame gets whatever height is left rather than the
   dialog growing past the viewport. */
.tpl-dialog-stage {
    flex: 1 1 auto;
    min-height: 12rem;
    display: flex;
    justify-content: center;
    padding: var(--s3);
    background: var(--surface-sunken);
    overflow: hidden;
}

.tpl-frame {
    width: 100%;
    height: 100%;
    max-width: 100%;
    border-radius: var(--radius);
    overflow: hidden;
    background: #fff;
    box-shadow: var(--shadow-sm);
    transition: width 0.18s ease;
}

.tpl-frame iframe {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

.tpl-dialog-text {
    flex: none;
    padding: var(--s4);
    display: grid;
    gap: var(--s2);
    border-top: 1px solid var(--rule);
    max-height: 30vh;
    overflow-y: auto;
}

.tpl-dialog-text p { color: var(--ink-secondary); }

.tpl-highlights {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
}

.tpl-highlights li {
    padding: 0.1875rem 0.625rem;
    border-radius: var(--radius-pill);
    background: var(--surface-inset);
    font-size: var(--text-sm);
}

.tpl-dialog-foot {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
    align-items: center;
    flex: none;
    padding: var(--s3) var(--s4);
    border-top: 1px solid var(--rule);
    background: var(--surface);
}

.tpl-dialog-foot .spacer { flex: 1 1 auto; }

@media (max-width: 40rem) {
    /* Three device widths are meaningless on a phone, where the stage is already narrower than the
       narrowest of them. */
    .tpl-widths { display: none; }
    .tpl-dialog { height: 92vh; }
}
