/* One file, no dependency on the outside world. A public page on a tenant's
   domain must not open a connection to third parties — otherwise it needs a
   consent banner, and that costs more clicks than the design brings in. This
   file serves the admin area too, for the same reason: one stylesheet, one
   trust boundary, nothing fetched from anywhere else.

   HOW THIS FILE IS ORGANISED. Tokens first, then the base, then the public
   pages, then the administration shell (sidebar, topbar, content), then the
   building blocks every page is assembled from (racks, tiles, tables, forms,
   buttons, badges, notices, empty states, modal). A page never carries its own
   stylesheet: if a page needs a new shape, the shape is added here, named, and
   reused by the next page that needs it. */

/* ─── Tokens ─────────────────────────────────────────────────────────────── */

:root {
    /* Surfaces, darkest to lightest. The base is the page; each surface above it
       is one step closer to the eye — a panel on the page, a field on a panel. */
    --base: #0b0d12;
    --surface: #12151c;
    --surface-2: #181c25;
    --surface-3: #1f2430;
    --surface-hover: #1c212b;

    --border: #242a37;
    --border-soft: #1b202a;
    --border-strong: #323a4b;

    --text: #e9ebf1;
    --muted: #9aa3b7;
    --dim: #646d84;

    /* The one brand colour. Amber on near-black reads as a mixing desk, not
       as a spreadsheet — and it is the only saturated colour on the page, so
       it always means "this is the thing to press" or "this is the current
       one". The soft variant is the same hue at low opacity, for tints behind
       an active nav item or a focused field. */
    --accent: #f3b13f;
    --accent-ink: #1a1304;
    --accent-soft: rgba(243, 177, 63, .14);
    --accent-ring: rgba(243, 177, 63, .32);

    --good: #3fd59a;
    --bad: #ff6f61;
    --warn: #e8b04f;
    --info: #6aa9ff;

    --radius-lg: 14px;
    --radius: 10px;
    --radius-sm: 7px;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
    --shadow: 0 6px 24px rgba(0, 0, 0, .35);
    --shadow-lg: 0 24px 64px rgba(0, 0, 0, .55);

    --mono: ui-monospace, "SF Mono", "IBM Plex Mono", Menlo, Consolas, monospace;
    --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

    /* The admin shell's two fixed dimensions. Named because the content, the
       drawer and the topbar all have to agree on them. */
    --sidebar-w: 248px;
    --topbar-h: 56px;

    /* Panel padding, named so a table can cancel it and sit flush. */
    --pad: 1rem;

    color-scheme: dark;
}

@media (prefers-color-scheme: light) {
    :root {
        --base: #f4f5f9;
        --surface: #ffffff;
        --surface-2: #f5f6fa;
        --surface-3: #eceef5;
        --surface-hover: #f1f3f8;

        --border: #e2e5ee;
        --border-soft: #eceef4;
        --border-strong: #cfd4e1;

        --text: #161922;
        --muted: #5d6578;
        --dim: #8b93a6;

        --accent: #c47a0b;
        --accent-ink: #ffffff;
        --accent-soft: rgba(196, 122, 11, .12);
        --accent-ring: rgba(196, 122, 11, .28);

        --good: #118f5e;
        --bad: #d7453a;
        --warn: #b7790c;
        --info: #2466c8;

        --shadow-sm: 0 1px 2px rgba(20, 24, 40, .06);
        --shadow: 0 6px 24px rgba(20, 24, 40, .08);
        --shadow-lg: 0 24px 64px rgba(20, 24, 40, .18);

        color-scheme: light;
    }
}

/* ─── Base ───────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }

/* NOTHING SCROLLS SIDEWAYS. A page that can be pushed wider than the window is
   one where a column, a button or half a heading is somewhere the eye never goes.

   `clip` AND NOT `hidden`: `hidden` on the root makes body a scroll container,
   and position: sticky then resolves against a box that never scrolls — the
   sidebar and the topbar stopped sticking. `clip` establishes no scroll
   container, so sticky resolves against the viewport, where it belongs.

   `break-word` and not `anywhere` for the general case: `anywhere` also counts
   the break when working out an element's minimum width, which collapses prose
   in a flex child to a ragged column. Where the min-width contribution IS the
   point — a cell holding an ISRC, a token, a signed URL — `anywhere` is set on
   that cell instead. */
html, body { overflow-x: clip; max-width: 100%; }
body { overflow-wrap: break-word; }

img, video, canvas, iframe { max-width: 100%; }
input, select, textarea { max-width: 100%; }

body {
    margin: 0;
    background: var(--base);
    color: var(--text);
    font: 14.5px/1.55 var(--sans);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1 {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.015em;
    line-height: 1.2;
    margin: 0 0 .3rem;
}

/* A section title inside a panel: small, firm, upper-case. The page title is
   the only large heading; everything underneath it is a labelled panel. */
h2 {
    font-size: .78rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--muted);
    margin: 0;
}

h3 { font-size: 1rem; font-weight: 650; margin: 1.25rem 0 .5rem; letter-spacing: -.005em; }
a { color: inherit; }
p { margin: .6rem 0; }

code { font-family: var(--mono); font-size: .85em; overflow-wrap: anywhere; }

.aside { color: var(--muted); }
p.aside { max-width: 70ch; }
.small { font-size: .85rem; }

::selection { background: var(--accent-ring); }

/* One focus ring for everything that can be focused. Visible on keyboard focus
   only; a mouse click on a button must not leave an orange box behind. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
h1:focus-visible { outline: none; }   /* enhanced navigation focuses the h1 */

/* ─── Icons ──────────────────────────────────────────────────────────────── */

/* Inline SVG from the sprite in App.razor, drawn in the current text colour.
   Stroke icons at 1.75 — thin enough to sit beside 14px text, thick enough to
   survive a non-retina screen. */
.ico {
    width: 1.1em;
    height: 1.1em;
    flex: 0 0 auto;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
    vertical-align: -.18em;
}

/* ─── Public pages: link page, gate, promo, status ────────────────────────── */

.public {
    max-width: 560px;
    margin: 0 auto;
    padding: 3rem 1.25rem 4rem;
}

.linkpage header { text-align: center; margin-bottom: 2rem; }
.linkpage .avatar { border-radius: 50%; object-fit: cover; box-shadow: var(--shadow); }
.linkpage h1 { font-size: 1.6rem; font-weight: 700; margin: .9rem 0 .35rem; }
.linkpage .bio { color: var(--muted); margin: 0; }

.blocks { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }

.blocks .block {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: 1rem 1.15rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    font-weight: 550;
    transition: transform .14s ease, border-color .14s ease, box-shadow .14s ease;
}

.blocks .block:hover { transform: translateY(-2px); border-color: var(--accent); box-shadow: var(--shadow); }
.blocks .block .platform { color: var(--muted); font-weight: 400; font-size: .85rem; }
.blocks .block.release { border-left: 3px solid var(--accent); }
.blocks .block.gate { border-left: 3px solid var(--good); }

/* A player is not a link — nothing to lift on hover. Its own rules are inlined
   by LinkPage from ReleaseEmbedPage.CardStyle so the link page and the embed
   cannot drift apart; nothing about the card belongs here. */
.blocks .block.player { flex-direction: column; align-items: stretch; gap: .6rem; cursor: default; }
.blocks .block.player:hover { transform: none; border-color: var(--border); box-shadow: var(--shadow-sm); }

.signup { margin-top: 2.5rem; display: grid; gap: .6rem; }
.signup form { display: grid; gap: .5rem; }
.signup .wording { color: var(--muted); font-size: .85rem; margin: 0; }

/* The gate's action-before-the-form block: siblings with nothing between them
   in the rendered markup, laid out as a grid rather than leaning on incidental
   whitespace. */
.gate .block { display: grid; gap: .5rem; }

/* THE CARD a visitor meets when there is nothing else on the page: the sign-in
   page, a status code, a gate that has closed, a link page with no tenant. One
   shape for all of them, centred, with the brand mark above when the page has
   one to show. */
.empty {
    max-width: 480px;
    margin: 8vh auto 0;
    padding: 2.25rem 2rem 2rem;
    text-align: center;
    color: var(--muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}

.empty h1 { color: var(--text); font-size: 1.35rem; margin-bottom: .5rem; }
.empty p { margin: .5rem 0; }
.empty .buttons { justify-content: center; margin-top: 1.4rem; margin-bottom: 0; }
.empty .brand-mark { margin: 0 auto 1.1rem; }

/* The logo: a rounded amber tile with a waveform. The one picture in the whole
   application, so it is drawn here once and used by the sidebar, the sign-in
   card and the status pages alike. */
.brand-mark {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: linear-gradient(145deg, #f8c766, var(--accent) 55%, #d98f1e);
    color: var(--accent-ink);
    display: grid;
    place-items: center;
    box-shadow: 0 2px 8px rgba(243, 177, 63, .35), inset 0 1px 0 rgba(255, 255, 255, .35);
    flex: 0 0 auto;
}

.brand-mark .ico { width: 20px; height: 20px; stroke-width: 2.2; }

/* ─── Administration shell ────────────────────────────────────────────────── */

.admin { display: flex; min-height: 100vh; align-items: stretch; }

/* STICKY AND EXACTLY ONE SCREEN TALL. align-self: flex-start stops the flex
   stretch (otherwise the sidebar is as tall as the document and the foot ends
   up hundreds of pixels below the fold); sticky keeps it in view; the height is
   what the screen has, not what the content wants. */
.sidebar {
    width: var(--sidebar-w);
    flex: 0 0 var(--sidebar-w);
    background: var(--surface);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    align-self: flex-start;
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100dvh;   /* the mobile browser bar eats part of 100vh */
}

/* The links scroll when there are too many for the screen; the foot does not
   move. min-height: 0 is what allows a flex child to shrink below its content. */
.sidebar .nav { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding: .6rem .75rem 1rem; scrollbar-width: thin; }
.sidebar .foot { flex: 0 0 auto; }

.sidebar .brand {
    display: flex;
    align-items: center;
    gap: .7rem;
    height: var(--topbar-h);
    padding: 0 1.1rem;
    border-bottom: 1px solid var(--border-soft);
    font-weight: 700;
    font-size: .95rem;
    letter-spacing: -.01em;
    text-decoration: none;
}

.sidebar .brand small {
    display: block;
    font-family: var(--mono);
    font-size: .62rem;
    font-weight: 500;
    color: var(--dim);
    letter-spacing: .08em;
    text-transform: uppercase;
    margin-top: .1rem;
}

/* A group label is a visual break in the list, not a link — it must not look
   clickable. */
.sidebar .group {
    font-size: .66rem;
    font-weight: 650;
    color: var(--dim);
    text-transform: uppercase;
    letter-spacing: .1em;
    padding: 1.1rem .65rem .35rem;
}

.sidebar .item {
    position: relative;
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .46rem .65rem;
    margin: 1px 0;
    border-radius: var(--radius-sm);
    color: var(--muted);
    text-decoration: none;
    font-size: .875rem;
    font-weight: 500;
    line-height: 1.3;
    transition: background .12s ease, color .12s ease;
}

.sidebar .item .ico { width: 17px; height: 17px; color: var(--dim); transition: color .12s ease; }
.sidebar .item:hover { color: var(--text); background: var(--surface-hover); }
.sidebar .item:hover .ico { color: var(--muted); }

/* The current page: tinted, bright, and marked with a short amber bar on the
   left — a mark that survives a quick scan of a 25-item list far better than a
   background change alone. */
.sidebar .item.active { color: var(--text); background: var(--accent-soft); font-weight: 600; }
.sidebar .item.active .ico { color: var(--accent); }
.sidebar .item.active::before {
    content: "";
    position: absolute;
    left: -.75rem;
    top: 22%;
    bottom: 22%;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--accent);
}

/* The door between the label's own view and the platform administration. Drawn
   as a distinct card at the top of the list rather than as one more link, so
   it reads as "change mode" and not as "another page". */
.sidebar .switch-side {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin: .3rem 0 .4rem;
    padding: .55rem .7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    color: var(--text);
    font-size: .82rem;
    font-weight: 550;
    text-decoration: none;
    transition: border-color .12s ease, background .12s ease;
}

.sidebar .switch-side .ico { color: var(--accent); width: 16px; height: 16px; }
.sidebar .switch-side:hover { border-color: var(--border-strong); background: var(--surface-3); }
.sidebar .switch-side .arrow { margin-left: auto; color: var(--dim); }

.sidebar .foot {
    border-top: 1px solid var(--border-soft);
    padding: .7rem .85rem;
}

/* The language picker: a globe and a borderless select, so the foot reads as
   one quiet control and not as a form. */
.sidebar .language {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    color: var(--dim);
}

.sidebar .language select {
    flex: 1;
    font-size: .82rem;
    padding: .35rem 1.8rem .35rem .5rem;
    background-color: transparent;
    border-color: transparent;
    color: var(--muted);
}

.sidebar .language select:hover { border-color: var(--border); color: var(--text); }

/* ─── Topbar ─────────────────────────────────────────────────────────────── */

/* Which tenant, who is signed in, and how to switch either. The sidebar
   underneath is left to do the one thing a sidebar is for: get somewhere else. */
.topbar {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-height: var(--topbar-h);
    padding: 0 1.5rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 30;
}

.workspace {
    display: flex;
    align-items: center;
    gap: .6rem;
    min-width: 0;
    padding: .3rem .5rem .3rem .3rem;
    border-radius: var(--radius-sm);
}

.workspace .avatar {
    width: 30px;
    height: 30px;
    flex: 0 0 30px;
    border-radius: 8px;
    background: linear-gradient(145deg, var(--surface-3), var(--surface-2));
    border: 1px solid var(--border);
    color: var(--text);
    display: grid;
    place-items: center;
    font-weight: 700;
    font-size: .72rem;
    letter-spacing: .02em;
    text-transform: uppercase;
}

.workspace .name {
    font-weight: 650;
    font-size: .9rem;
    line-height: 1.15;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.workspace .switch {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .76rem;
    font-weight: 550;
    color: var(--muted);
    text-decoration: none;
    padding: .25rem .5rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    white-space: nowrap;
    transition: color .12s ease, border-color .12s ease;
}

.workspace .switch:hover { color: var(--text); border-color: var(--border-strong); }
.workspace .switch .ico { width: 13px; height: 13px; }

.topbar .spacer { flex: 1; }

.topbar .who {
    display: flex;
    align-items: center;
    gap: .6rem;
    font-size: .84rem;
    color: var(--muted);
    min-width: 0;
}

.topbar .who .name { color: var(--text); max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.topbar .who .signout,
.topbar .who .signin {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    color: var(--muted);
    text-decoration: none;
    font-size: .82rem;
    font-weight: 550;
    padding: .35rem .6rem;
    border-radius: var(--radius-sm);
    white-space: nowrap;
    transition: color .12s ease, background .12s ease;
}

.topbar .who .signout:hover, .topbar .who .signin:hover { color: var(--text); background: var(--surface-hover); }
.topbar .who .signin { color: var(--accent); }

/* Column flex: the topbar and the content stack vertically underneath it. */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* The content grows to a limit and is centred past it: on a 2560 px screen the
   leftover space is split rather than piled up on one side. Prose keeps its own
   measure separately (.lede, p.aside), because a reading width is a property of
   text and not of the page. */
.content {
    min-width: 0;
    width: 100%;
    max-width: 1440px;
    margin-inline: auto;
    padding: 1.9rem 2.25rem 4.5rem;
}

/* The switch, the button that flips it and the sheet behind the drawer. None of
   the three exists on a wide screen — see the media query below. */
.nav-switch, .nav-open-button, .nav-scrim { display: none; }

@media (max-width: 800px) {
    .admin { flex-direction: column; align-items: stretch; }

    /* A DRAWER, NOT A BAR ACROSS THE TOP. The sidebar slides in over the page
       and slides back out; the page underneath keeps its whole screen.

       Off-screen with a transform AND visibility: hidden — a transform moves a
       thing without hiding it, so a closed drawer was still twenty-five reachable
       links for the Tab key and the screen reader. The delay on `visibility`
       keeps the slide: it flips at the END of the close and the START of the
       open. */
    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: min(84vw, 300px);
        z-index: 60;
        border-right: 1px solid var(--border);
        transform: translateX(-100%);
        visibility: hidden;
        transition: transform .2s ease, visibility 0s .2s;
        overflow-y: auto;
    }
    .nav-switch:checked ~ .sidebar {
        transform: none;
        visibility: visible;
        transition: transform .2s ease, visibility 0s;
        box-shadow: var(--shadow-lg);
    }

    /* The page behind an open drawer does not scroll. Safe here and only here:
       on this width the topbar is static and the drawer is fixed, so nothing
       depends on the root staying a non-scroll-container. */
    html:has(.nav-switch:checked) { overflow: hidden; }

    .nav-switch:checked ~ .nav-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 50;
        border: 0;
        padding: 0;
        background: rgba(4, 6, 12, .55);
        backdrop-filter: blur(2px);
    }

    /* Out of sight, still focusable — a menu nobody can reach by keyboard is a
       menu that needs a pointer. */
    .nav-switch {
        display: block;
        position: absolute;
        width: 1px; height: 1px;
        margin: -1px; padding: 0; border: 0;
        overflow: hidden; clip-path: inset(50%);
    }
    .nav-switch:focus-visible ~ .main .nav-open-button { outline: 2px solid var(--accent); outline-offset: 2px; }

    .nav-open-button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 38px;
        height: 38px;
        background: none;
        border: 1px solid var(--border);
        border-radius: var(--radius-sm);
        color: var(--text);
        cursor: pointer;
        flex: 0 0 auto;
    }
    .nav-open-button .ico { width: 18px; height: 18px; }
    .nav-open-button .label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

    .topbar { position: static; padding: 0 .9rem; gap: .5rem; }
    /* One row, always. The account's name and badge give way first; the
       tenant and the way out stay. */
    .topbar .who .name, .topbar .who .badge { display: none; }
    .topbar .who { flex: 0 0 auto; }
    /* Narrower still, the words give way and the icons stay. */
    @media (max-width: 420px) {
        .workspace .switch > :not(.ico), .topbar .who .signout > :not(.ico) { display: none; }
        .workspace .switch, .topbar .who .signout { padding: .35rem .45rem; }
        .workspace .switch .ico, .topbar .who .signout .ico { width: 16px; height: 16px; }
    }
    .workspace .name { max-width: 40vw; }
    .content { padding: 1.1rem 1rem 3rem; }
}

/* ─── The address a page ends up at ──────────────────────────────────────── */

.address {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin: .35rem 0 .9rem;
    font-size: .9rem;
}

.address .label { color: var(--dim); font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .07em; }
.address a { color: var(--accent); word-break: break-all; text-decoration: none; font-family: var(--mono); font-size: .85rem; }
.address a:hover { text-decoration: underline; }
.address.missing a { color: var(--muted); font-family: inherit; }

.address .copy {
    font: inherit;
    font-size: .74rem;
    font-weight: 550;
    padding: .18rem .55rem;
    color: var(--muted);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
}

.address .copy:hover { color: var(--text); border-color: var(--border-strong); }

/* ─── View header ────────────────────────────────────────────────────────── */

/* Every page starts with these: what this is, in one line what it is for, and
   the one or two actions the page is mostly there for. */
.view-head {
    display: flex;
    align-items: flex-end;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}

.view-head .title { flex: 1 1 20rem; min-width: 0; }
.view-head h1 { margin: 0; }
.view-head .lede, .view-head > p { color: var(--muted); margin: .35rem 0 0; max-width: 70ch; font-size: .92rem; }
.view-head .actions { display: flex; gap: .5rem; flex-wrap: wrap; }

/* ─── Rack: the one container every section of content sits in ──────────── */

.rack {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    margin-bottom: 1.1rem;
    overflow: hidden;
}

.rack-head {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .7rem var(--pad);
    border-bottom: 1px solid var(--border-soft);
    flex-wrap: wrap;
}

/* 0 1 auto: it does not grow, but it may shrink — a heading forbidden to shrink
   is a heading that makes the page wider than the screen. */
.rack-head h2 { flex: 0 1 auto; min-width: 0; color: var(--text); }
.rack-head .spacer { flex: 1; }
.rack-head, .rack-head > * { min-width: 0; }

/* overflow-x, not visible: .rack itself clips (for the rounded corners), and
   without a scrollable escape hatch a table wider than the panel is cut off
   mid-button with no way to reach the rest. Scrolling loses nothing. */
.rack-body { padding: var(--pad); overflow-x: auto; min-width: 0; }
.rack-body > :first-child { margin-top: 0; }
.rack-body > :last-child { margin-bottom: 0; }

/* A table that is the whole body sits flush with the panel's edges: the row
   lines run edge to edge and the first column lines up with the header text.
   `only-child` and not `first-child`, so a body with a form above its table
   keeps its padding. */
.rack-body > .list:only-child, .rack-body > .table:only-child {
    width: calc(100% + 2 * var(--pad));
    margin: calc(-1 * var(--pad));
}

.rack-empty { padding: 1.5rem; text-align: center; color: var(--muted); font-size: .88rem; }

/* The shape of a populated page, faded — shown next to NoTenant so the page
   reads as "pick a tenant to see this" rather than as an empty install. */
.skeleton { opacity: .45; margin-top: 1.25rem; }
.skeleton-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .75rem; margin-bottom: 1.1rem; }
.skeleton-tile { height: 4.2rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.skeleton-rack { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem; display: grid; gap: .65rem; }
.skeleton-row { height: 1rem; background: var(--border-soft); border-radius: 4px; }

.bar { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.bar .spacer { flex: 1; }

/* ─── Tiles: a number with a name ─────────────────────────────────────────── */

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: .8rem; margin-bottom: 1.25rem; }

.tile {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 1rem 1.15rem 1.05rem;
    display: grid;
    gap: .3rem;
    color: inherit;
    text-decoration: none;
}

a.tile { transition: border-color .14s ease, transform .14s ease; }
a.tile:hover { border-color: var(--border-strong); transform: translateY(-1px); }

.tile .label { color: var(--muted); font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; order: -1; }
.tile .number { font-size: 1.85rem; font-weight: 700; line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.tile .number.small { font-size: 1.05rem; }
.tile .hint { font-family: var(--mono); font-size: .7rem; color: var(--dim); }
.tile.warning { border-color: var(--warn); }
.tile.warning .number { color: var(--warn); }

/* ─── Quick links: the "where do I start" cards on an empty overview ──────── */

.quick-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: .8rem; }

.quick {
    display: flex;
    align-items: flex-start;
    gap: .85rem;
    padding: 1rem 1.1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    color: inherit;
    text-decoration: none;
    transition: border-color .14s ease, transform .14s ease, box-shadow .14s ease;
}

.quick:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: var(--shadow); }

.quick .ico-box {
    width: 36px;
    height: 36px;
    flex: 0 0 36px;
    border-radius: 9px;
    background: var(--accent-soft);
    color: var(--accent);
    display: grid;
    place-items: center;
}

.quick .ico-box .ico { width: 18px; height: 18px; }
.quick strong { display: block; font-size: .92rem; font-weight: 650; margin-bottom: .15rem; }
.quick span { display: block; color: var(--muted); font-size: .83rem; line-height: 1.45; }

/* ─── Tables ─────────────────────────────────────────────────────────────── */

.list, .table { width: 100%; border-collapse: collapse; }

.list th, .table th {
    text-align: left;
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 650;
    color: var(--dim);
    padding: .6rem .85rem;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
    white-space: nowrap;
}

/* `anywhere` here and `break-word` on the body, deliberately: a cell is exactly
   the place where the min-width contribution matters. */
.list td, .table td {
    padding: .62rem .85rem;
    border-top: 1px solid var(--border-soft);
    vertical-align: middle;
    font-size: .88rem;
    overflow-wrap: anywhere;
}

.list tbody tr:first-child td, .table tbody tr:first-child td { border-top: 0; }
.list tbody tr:hover td, .table tbody tr:hover td { background: var(--surface-hover); }
.list .actions, .table .actions { text-align: right; white-space: nowrap; }

/* Everything in an actions cell sits on ONE line, centred against everything
   else on it, with a declared gap — Razor drops whitespace-only nodes between
   elements, so whether two buttons end up with a space between them would
   otherwise depend on how the file happens to be indented. */
.list .actions > *, .table .actions > * { vertical-align: middle; }
.list .actions > * + *, .table .actions > * + * { margin-left: .4rem; }
.list .actions .address, .table .actions .address { display: inline-flex; margin: 0; }
.list .actions .address a, .table .actions .address a { word-break: normal; }

/* Inputs inside a table row: compact, and no wider than the cell. */
.list td > input, .table td > input, .list td > select, .table td > select { min-height: 2rem; padding: .25rem .5rem; font-size: .85rem; }

/* ─── Tables in the space they actually have ──────────────────────────────────
   NO SIDEWAYS SCROLL, ANYWHERE. Container queries and not the viewport, because
   the viewport is the wrong number: at 1024 px the window is wide and the rack
   is 718, since the sidebar and the padding have taken the rest.

     under 900  headers and action cells stop being `nowrap`.
     under 520  a row becomes a block: one field per line, the header hidden,
                the actions at the end where a thumb reaches them.

   Hiding the header only works if the cells name their own column, so every
   <td> under a named <th> carries a data-label. Cells under a BLANK header —
   the actions column, a thumbnail — deliberately have none. */
.rack-body { container-type: inline-size; }

@container (max-width: 900px) {
    .list th, .table th,
    .list .actions, .table .actions { white-space: normal; }
    .list th, .table th { overflow-wrap: anywhere; }
}

@container (max-width: 520px) {
    .list, .table { display: block; }
    .list thead, .table thead { display: none; }
    .list tbody, .table tbody { display: block; }

    .list tr, .table tr {
        display: block;
        padding: .7rem .2rem;
        border-top: 1px solid var(--border-soft);
    }
    .list tr:first-child, .table tr:first-child { border-top: 0; }

    .list td, .table td {
        display: block;
        border-top: 0;
        padding: .2rem .3rem;
    }

    .list td[data-label]::before, .table td[data-label]::before {
        content: attr(data-label);
        display: block;
        font-size: .66rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: .08em;
        color: var(--dim);
        margin-bottom: .1rem;
    }

    .list .actions, .table .actions, .list td.actions, .table td.actions {
        text-align: left;
        white-space: normal;
        display: flex;
        flex-wrap: wrap;
        gap: .35rem;
        padding-top: .5rem;
    }

    .list .actions > * + *, .table .actions > * + * { margin-left: 0; }
    .list tbody tr:hover td, .table tbody tr:hover td { background: none; }
}

tr.selected td { background: var(--accent-soft) !important; }

/* A row that opens its own detail on click. Focusable on purpose: tab reaches
   the row and Enter opens it. The outline is inset because a row is flush
   against the rack's edge. */
tr.click { cursor: pointer; }
tr.click:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ─── Badges ─────────────────────────────────────────────────────────────── */

/* A tinted pill in the state's own colour. The tint is derived from the text
   colour, so a new state needs one line (its colour) and not three. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .16rem .55rem;
    border-radius: 999px;
    background: color-mix(in srgb, currentColor 13%, transparent);
    color: var(--muted);
    font-size: .7rem;
    font-weight: 650;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    line-height: 1.5;
}

.badge::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }

.badge.good, .badge.active, .badge.verified, .badge.live, .badge.done, .badge.ready { color: var(--good); }
.badge.bad, .badge.suspended, .badge.failed, .badge.error { color: var(--bad); }
.badge.pending, .badge.warning, .badge.scheduled, .badge.processing { color: var(--warn); }
.badge.platform { color: var(--accent); }
.badge.info { color: var(--info); }

.thumbnail { display: block; width: 72px; height: 72px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border); }

/* ─── Buttons ────────────────────────────────────────────────────────────── */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    min-height: 2.35rem;
    padding: .45rem .95rem;
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    font: inherit;
    font-size: .88rem;
    font-weight: 550;
    line-height: 1.2;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color .12s ease, background .12s ease, transform .08s ease, filter .12s ease;
}

.button:hover:not(:disabled) { border-color: var(--border-strong); background: var(--surface-3); }
.button:active:not(:disabled) { transform: translateY(1px); }
.button:disabled { opacity: .5; cursor: not-allowed; box-shadow: none; }

.button.primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-ink);
    font-weight: 650;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .25), inset 0 1px 0 rgba(255, 255, 255, .25);
}
.button.primary:hover:not(:disabled) { filter: brightness(1.07); border-color: var(--accent); background: var(--accent); }

.button.danger { color: var(--bad); }
.button.danger:hover:not(:disabled) { border-color: var(--bad); background: color-mix(in srgb, var(--bad) 10%, transparent); }

.button.ghost { background: transparent; border-color: transparent; box-shadow: none; color: var(--muted); }
.button.ghost:hover:not(:disabled) { background: var(--surface-hover); color: var(--text); border-color: transparent; }

.button.small { min-height: 1.9rem; padding: .25rem .65rem; font-size: .8rem; }
.button.wide { width: 100%; text-align: left; display: grid; gap: .1rem; justify-content: unset; }
.button .ico { width: 15px; height: 15px; }

.buttons { display: flex; gap: .6rem; margin: 1rem 0; flex-wrap: wrap; align-items: center; }
.rack-body > .buttons:last-child { margin-bottom: 0; }

/* ─── Forms ──────────────────────────────────────────────────────────────── */

/* A FORM HAS A WIDTH, and it is not the panel's. A text field stretched to
   1100 px on a wide screen reads as a design mistake and is harder to fill in:
   the eye loses the caret, and the label floats far from the field's end.
   Fields are capped at a comfortable line; what sits beside them (tables,
   tiles, button strips) still takes the full panel. The two-column layout and
   the modal are narrower than the cap anyway, so nothing changes there. */
.field { display: grid; gap: .85rem; margin: 1rem 0; max-width: 42rem; }
.field.horizontal { grid-auto-flow: column; grid-auto-columns: 1fr auto; align-items: end; }

/* Two fields side by side where they belong together: a period's start and
   end, a country and a registrant. */
.field.pair { grid-template-columns: 1fr 1fr; }
@media (max-width: 560px) { .field.pair { grid-template-columns: 1fr; } }

.field label {
    display: grid;
    gap: .35rem;
    font-size: .82rem;
    font-weight: 550;
    color: var(--muted);
}

.field label.checkbox { display: flex; flex-direction: row; align-items: center; gap: .55rem; font-size: .88rem; font-weight: 500; color: var(--text); }
.field label.checkbox input { width: auto; }

/* `field inline`: lay these out along one line. The badge needs its own note
   because a grid item stretches to its column by default. */
.field.inline { display: flex; flex-wrap: wrap; align-items: end; gap: .7rem; max-width: none; }
.field.inline > label { flex: 1 1 12rem; }
.field label > .badge { justify-self: start; }

/* A hint under a field, inside its label. */
.field label > .aside, .field > .aside { font-weight: 400; font-size: .8rem; line-height: 1.45; }

input, select, textarea {
    min-height: 2.4rem;
    padding: .45rem .7rem;
    background: var(--base);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: .9rem;
    width: 100%;
    transition: border-color .12s ease, box-shadow .12s ease;
}

@media (prefers-color-scheme: light) {
    input, select, textarea { background: #fff; }
}

input::placeholder, textarea::placeholder { color: var(--dim); }
textarea { min-height: 6rem; resize: vertical; line-height: 1.5; }

input:hover, select:hover, textarea:hover { border-color: var(--border-strong); }
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-ring);
}

input:disabled, select:disabled, textarea:disabled { opacity: .55; cursor: not-allowed; }

/* A select with the browser's chevron replaced by ours, so it matches the
   field beside it in both colour schemes. The image is a data: URL, which the
   page's img-src allows. */
select {
    appearance: none;
    padding-right: 2.2rem;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239aa3b7' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right .65rem center;
    cursor: pointer;
}

select[multiple] { background-image: none; padding-right: .7rem; }

input[type="checkbox"], input[type="radio"] { width: auto; min-height: 0; accent-color: var(--accent); }
input[type="number"] { font-variant-numeric: tabular-nums; }

/* The native file control looks like a 2005 form on either colour scheme. The
   file name stays where the browser puts it; only the button is redrawn, as
   the same button every other control on the page uses. */
input[type="file"] {
    padding: .3rem .3rem;
    cursor: pointer;
    color: var(--muted);
    font-size: .85rem;
}

input[type="file"]::file-selector-button {
    font: inherit;
    font-size: .82rem;
    font-weight: 550;
    color: var(--text);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: .35rem .75rem;
    margin-right: .75rem;
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease;
}

input[type="file"]:hover::file-selector-button { border-color: var(--border-strong); background: var(--surface-3); }

/* ─── Notices ────────────────────────────────────────────────────────────── */

.notice {
    display: block;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
    padding: .85rem 1.1rem;
    margin: 1rem 0;
    font-size: .9rem;
    box-shadow: var(--shadow-sm);
}

.notice.warning { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn) 6%, var(--surface)); }
.notice.bad { border-left-color: var(--bad); background: color-mix(in srgb, var(--bad) 6%, var(--surface)); }
.notice.good { border-left-color: var(--good); background: color-mix(in srgb, var(--good) 6%, var(--surface)); }
.notice h2, .notice h3 { margin-top: 0; text-transform: none; letter-spacing: normal; font-size: 1rem; color: var(--text); }
.notice p:first-child { margin-top: 0; }
.notice p:last-child { margin-bottom: 0; }
.notice .button { margin-left: .5rem; vertical-align: middle; }
.notice > .button:first-child { margin-left: 0; }

/* ─── Empty states ───────────────────────────────────────────────────────── */

/* A page with nothing in it yet says what would be here and how to put the
   first thing in. A bare "No releases yet." sentence answers the first
   question and not the second. */
.empty-state {
    text-align: center;
    padding: 2.75rem 1.5rem;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    margin: 1rem 0;
}

.empty-state .ico-box {
    width: 44px;
    height: 44px;
    margin: 0 auto .9rem;
    border-radius: 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--dim);
    display: grid;
    place-items: center;
}

.empty-state .ico-box .ico { width: 22px; height: 22px; }
.empty-state h3 { margin: 0 0 .3rem; font-size: 1rem; }
.empty-state p { color: var(--muted); margin: 0 auto; max-width: 46ch; font-size: .9rem; }
.empty-state .buttons { justify-content: center; margin: 1.1rem 0 0; }

/* ─── Two columns, lists, steps, diffs, rows ─────────────────────────────── */

.two-column { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; align-items: start; }
@media (max-width: 950px) { .two-column { grid-template-columns: 1fr; } }

.block-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .6rem; }

.block-list li {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: .7rem;
    display: grid;
    gap: .45rem;
}

.block-list .row { display: flex; gap: .4rem; }
.block-list .id { font-family: var(--mono); font-size: .8rem; }

.steps { list-style: none; padding: 0; margin: 0; display: grid; gap: .2rem; }
.steps li { display: grid; grid-template-columns: 1.2rem 1fr; gap: .5rem; font-size: .88rem; padding: .15rem 0; }
.steps li .kind { color: var(--dim); }
.steps li.done .kind { color: var(--good); }
.steps li.pending { color: var(--muted); }

.diff { list-style: none; padding: 0; margin: 0; display: grid; gap: .3rem; }

.diff li {
    display: grid;
    grid-template-columns: 1.2rem 10rem 1fr;
    gap: .5rem;
    padding: .45rem .6rem;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    font-size: .85rem;
}

.diff .kind { font-weight: 700; text-align: center; }
.diff .id { font-family: var(--mono); color: var(--muted); font-size: .8rem; }
.diff li.add .kind { color: var(--good); }
.diff li.remove .kind { color: var(--bad); }
.diff li.modify .kind { color: var(--warn); }
.diff li.unchanged, .diff li.foreignkept { opacity: .55; }

.tenant-choice .list { list-style: none; padding: 0; margin: 0; display: grid; gap: .5rem; }
.tenant-choice .button.wide { padding: .8rem 1rem; }

.rows { display: flex; flex-direction: column; gap: .4rem; }

.row {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .65rem .8rem;
    background: var(--surface-2);
    border: 1px solid var(--border-soft);
    border-radius: var(--radius-sm);
}

.row .row-main { min-width: 0; flex: 1; }
.row .row-title { font-weight: 600; font-size: .88rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row .row-sub { font-family: var(--mono); font-size: .74rem; color: var(--dim); margin-top: .1rem; }

/* ─── The bar that appears when the circuit is gone ──────────────────────── */

/* display:none IS the switch: the framework sets display:block on
   #blazor-error-ui when a circuit dies. Fixed to the bottom and above
   everything, because it has to be readable over a page that is still fully
   drawn and no longer reacts to anything. */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: auto 0 0 0;
    z-index: 1000;
    padding: .85rem 3rem .85rem 1.25rem;
    background: var(--bad);
    color: #fff;
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .35);
    font-size: .95rem;
}

#blazor-error-ui strong { margin-right: .5rem; }
#blazor-error-ui .reload { color: #fff; margin-left: .75rem; font-weight: 600; }

#blazor-error-ui .dismiss {
    position: absolute;
    top: .5rem;
    right: 1rem;
    color: #fff;
    text-decoration: none;
    font-size: 1.2rem;
    line-height: 1;
}

/* ─── Modal ──────────────────────────────────────────────────────────────── */

/* A native <dialog>, shown with showModal() — the backdrop is the ::backdrop
   pseudo-element that comes with it. WIDTH and not only max-width: a <dialog>
   is `width: fit-content` in every browser's own stylesheet, so without a
   declared width each modal came out as wide as its longest line. */
.modal {
    padding: 0;
    border: none;
    border-radius: var(--radius-lg);
    background: transparent;
    width: min(620px, calc(100vw - 2rem));
    max-height: calc(100vh - 4rem);
    max-height: calc(100dvh - 4rem);
}

.modal-wide { width: min(920px, calc(100vw - 2rem)); }
.modal-narrow { width: min(420px, calc(100vw - 2rem)); }

.modal::backdrop { background: rgba(4, 6, 12, .6); backdrop-filter: blur(3px); }

.modal-box {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    max-height: inherit;
}

.modal-head {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .9rem 1.25rem;
    border-bottom: 1px solid var(--border-soft);
    flex: 0 0 auto;
}

.modal-head h2 { flex: 1; margin: 0; font-size: 1rem; font-weight: 650; text-transform: none; letter-spacing: -.005em; color: var(--text); }

.modal-close {
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--muted);
    font-size: 1.35rem;
    line-height: 1;
    padding: 0;
    cursor: pointer;
}

.modal-close:hover { color: var(--text); background: var(--surface-hover); }

.modal-body { padding: 1.25rem; overflow-y: auto; overflow-x: auto; }
.modal-body > :first-child { margin-top: 0; }
.modal-body > :last-child { margin-bottom: 0; }
.modal-body .field { max-width: none; }

/* A rack inside a modal is a section of the modal, not a panel on a page:
   no shadow, and it sits on the modal's own surface. */
.modal-body .rack { box-shadow: none; background: var(--surface-2); }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* A pair nested inside a field list is one row of that list, not a form of
   its own: no extra margin above and below. */
.field > .field { margin: 0; }

/* A button placed directly in a field list is one control, not a row: a grid
   item stretches to its column by default, which made "Add recording" a bar
   the width of the dialog. */
.field > .button { justify-self: start; }
