/* Platform Admin — login, first-run setup, and TOTP enrolment.

   Same visual system as admin.css: Brain's warm-clay dark chrome, 0.5rem panel /
   0.375rem control radii, Brain's denser type scale. Every colour, size, radius and
   shadow comes from _theme.css — this file declares NO tokens. The :root block that
   used to live here (a full copy of the pre-Brain cool-grey palette, plus a
   [data-theme="light"] block) shadowed every shared token and left /login rendering
   as a different product from the rest of admin. Both are gone. Dark only; see
   _theme.css for why there is no light mode.

   Shared controls (.pa-btn, .pa-input, .pa-icon-btn) are kept byte-identical to their
   admin.css counterparts so the two files cannot drift apart silently.

   SCOPE: login.eta is the only consumer of this file. It previously carried a full
   copy of the admin shell — topbar, nav, tables, badges, panels, tenant detail,
   dashboard — that /login never renders. Those rules were removed: they referenced
   --topbar-h / --nav-w, which _theme.css does not define, and their .pa-tab
   duplicate overrode the TOTP tab component below. admin.css is their only home. */


/* Levirge Admin — design tokens.

   Ported from Levirge Brain (`brain/assets/css/ui.css`) so the two products read as
   one system: the same "Claude Desktop dark" warm-clay chrome. Brain's token NAMES
   are kept verbatim wherever Brain has one, so a rule can be moved between the two
   codebases without translation. Brain's hex/rgb literals are converted to HSL here
   because rules/ui-and-js.md forbids hex and rgb for palette colours; the converted
   values are the same colours, and each is annotated with the Brain source literal.

   DARK ONLY. Brain has no light mode — no `prefers-color-scheme` block and no
   `body.light` override anywhere in `brain/assets/`. Rather than invent a light
   palette with no source of truth to match, admin follows Brain and ships dark only.

   TWO NAME COLLISIONS between Brain and admin's previous token set. Brain's meaning
   wins; admin's callers were migrated:
     --accent   Brain = success green. Admin previously = the amber brand highlight,
                which in Brain's vocabulary is --brand / --clay. Admin's callers now
                use --brand.
     --line-2   Brain = the STRONGER of its two borders. Admin previously used it as
                the default border, which in Brain's vocabulary is --line. Admin's
                callers now use --line.

   This is the single source of truth for the admin panel's tokens — admin.css
   declares none of its own. login.css also @imports this file but still carries its
   own full :root block from the pre-Brain palette, so the login page is unaffected
   by everything here and is NOT yet on the Brain palette. Porting it is follow-up
   work; until then, do not assume a token changed here reaches /login. */

:root {
    /* ── Surfaces ─────────────────────────────────────────
       Three-tier hierarchy required by rules/ui-and-js.md: canvas → panel → raised. */
    --bg: hsl(60 2% 12%); /* Brain rgb(31, 31, 30) — page canvas */
    --sidebar: hsl(60 2% 10%); /* Brain #1a1a19 */
    --panel: hsl(0 0% 15%); /* Brain rgb(38, 38, 38) — cards, sidebar, panels */
    --raised: hsl(60 2% 17%); /* Brain #2d2d2b — hover, selected, dropdowns */
    --hover: hsl(60 2% 21%); /* one step above --raised (Brain has no explicit token) */
    --code-bg: hsl(60 2% 10%); /* Brain #1a1a19 — inset surfaces: inputs, code, tables */

    /* ── Lines ────────────────────────────────────────────
       Brain ships two. --line-1 is an admin addition for hairline row dividers. */
    --line-1: hsl(60 3% 17%);
    --line: hsl(60 3% 22%); /* Brain #3a3a37 — default border */
    --line-2: hsl(60 3% 28%); /* Brain #4a4a46 — stronger border, elevated surfaces */
    --top-highlight: hsl(0 0% 100% / 0.06);

    /* ── Text ─────────────────────────────────────────────
       Headings ~92%, body ~64%, never pure white (rules/ui-and-js.md). */
    --text: hsl(48 12% 92%); /* Brain #ecebe7 */
    --muted: hsl(45 6% 64%); /* Brain #a8a59c */
    --faint: hsl(44 5% 47%); /* Brain #7d7a72 */
    --dim: hsl(44 5% 38%); /* below Brain's --faint, for de-emphasised labels */

    /* ── Brand and semantic colour ────────────────────────── */
    --brand: hsl(36 68% 54%); /* Brain #d99a3a */
    --clay: hsl(38 72% 57%); /* Brain #e0a542 — lighter brand tone, hover/active */
    --clay-soft: hsl(38 26% 18%); /* Brain #3a3122 */
    --brand-soft: hsl(36 68% 54% / 0.18);
    --brand-line: hsl(36 68% 54% / 0.42);
    --link: hsl(212 73% 67%); /* Brain #6fa8e8 */
    --accent: hsl(148 44% 56%); /* Brain #5cc08a — success green */
    --stuck: hsl(4 73% 67%); /* Brain #e8736b — error / blocked */

    /* ── Status palette ───────────────────────────────────
       Badges and gauges. Anchored on Brain's --accent / --clay / --stuck / --link so
       status colour sits in the same key as the chrome. --env-iris has no Brain
       counterpart and is derived to match their lightness and chroma. */
    --env-mint: var(--accent);
    --env-mint-soft: hsl(148 44% 56% / 0.18);
    --env-mint-line: hsl(148 44% 56% / 0.45);
    --env-amber: var(--clay);
    --env-amber-soft: hsl(38 72% 57% / 0.18);
    --env-amber-line: hsl(38 72% 57% / 0.45);
    --env-rose: var(--stuck);
    --env-rose-soft: hsl(4 73% 67% / 0.18);
    --env-rose-line: hsl(4 73% 67% / 0.45);

    /* Live connection state (ui-ws-status). Aliases onto the existing semantic
       colours rather than new hues — "connected" and "succeeded" should not be
       two different greens. Degraded is the reconnect-backoff window, which is
       genuinely distinct from offline: the socket is retrying, not given up. */
    --status-online: var(--accent);
    --status-degraded: var(--brand);
    --status-offline: var(--stuck);
    --env-cyan: var(--link);
    --env-cyan-soft: hsl(212 73% 67% / 0.18);
    --env-cyan-line: hsl(212 73% 67% / 0.45);
    --env-iris: hsl(265 58% 71%);
    --env-iris-soft: hsl(265 58% 71% / 0.18);
    --env-iris-line: hsl(265 58% 71% / 0.45);

    /* ── Depth ────────────────────────────────────────────
       Two-layer stack — tight contact shadow + long ambient (rules/ui-and-js.md).
       Inset surfaces get --shadow-inset and never an outer drop shadow. */
    --shadow-sm: 0 1px 2px hsl(0 0% 0% / 0.40), 0 4px 12px hsl(0 0% 0% / 0.22);
    --shadow-md: 0 1px 3px hsl(0 0% 0% / 0.45), 0 8px 24px hsl(0 0% 0% / 0.28);
    --shadow-inset: inset 0 1px 3px hsl(0 0% 0% / 0.25);

    /* ── Type ─────────────────────────────────────────────
       Brain's stack and scale: 1rem body, 0.875rem nav/controls, 0.8rem table and
       secondary text, 0.72rem captions. Denser than admin's previous 1rem baseline. */
    --font-sans: ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
    --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --font-size-xs: 0.72rem;
    --font-size-sm: 0.8rem;
    --font-size-base: 0.875rem;
    --font-size-md: 0.95rem;
    --font-size-lg: 1.1rem;
    --font-size-xl: 1.6rem;

    /* ── Radius ───────────────────────────────────────────
       Brain: 0.5rem panels, 0.375–0.4rem controls and nav rows, 0.6rem popovers. */
    --radius-xs: 0.25rem;
    --radius-sm: 0.375rem;
    --radius-md: 0.4rem;
    --radius-lg: 0.5rem;
    --radius-xl: 0.6rem;
    --radius-pill: 999rem;

    /* ── Shell metrics ────────────────────────────────────── */
    --sidebar-w: 15rem;
    /* Height of the shell's header band. The sidebar's logo row and every page's
       .pa-panel-header both size from this, so they line up by construction
       rather than by two paddings that happen to match. They cannot be aligned
       with subgrid — they sit in different subtrees, and subgrid only inherits
       tracks from a shared parent grid. */
    --shell-head-h: 2.125rem;
    --shell-gap: 0.5rem;

    /* ── Aliases ──────────────────────────────────────────
       Left: the semantic names rules/ui-and-js.md mandates, plus admin's original
       token names. Right: the Brain token each resolves to. Callers may use either
       vocabulary; there is exactly one value behind each pair. */
    --bg-base: var(--bg);
    --bg-surface: var(--panel);
    --bg-raised: var(--raised);
    --bg-hover: var(--hover);
    --bg-inset: var(--code-bg);
    --border: var(--line);
    --highlight: var(--brand);
    --text-primary: var(--text);
    --text-muted: var(--muted);
    --fg-0: var(--text);
    --fg-1: var(--muted);
    --fg-2: var(--faint);
    --fg-3: var(--dim);
    --line-3: var(--line-2);
}



*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
[hidden] {
    display: none !important;
}

/* Thin visible scrollbars, matching Brain (`brain/assets/css/ui.css`). The previous
   reset hid them entirely; in a shell where only the panes scroll that left no
   indication that a long table had more rows below the fold. */
::-webkit-scrollbar {
    width: 0.375rem;
    height: 0.375rem;
}
::-webkit-scrollbar-track {
    background: transparent;
}
::-webkit-scrollbar-thumb {
    background: var(--line-2);
    border-radius: 0.1875rem;
}
* {
    scrollbar-width: thin;
    scrollbar-color: var(--line-2) transparent;
}


/* The workspace picker renders the product's own mark — same rules as admin.css. */

/* Product icon. The artwork is selected in CSS by `data-product`, so there is no
   src for the page to guess and no onerror to catch a guess that was wrong.

   background-image, NOT a mask: brain ships a two-tone icon (its own brand gold
   over grey) and a mask can only paint one colour, so the artwork carries its
   own colours.

   brain and search have artwork of their own today. Every other product —
   including any added through the API — gets the Levirge mark, which is a
   deliberate icon rather than a broken-image slot. Adding one is a single
   rule below. */
.pa-product-icon {
    display: inline-block;
    width: 1.25rem;
    height: 1.25rem;
    background: url("/img/logo.svg") center / contain no-repeat;
}

/* The product view's header mark. */
.pa-product-icon--lg {
    width: 1.5rem;
    height: 1.5rem;
}

.pa-product-icon[data-product="brain"] {
    background-image: url("/img/products/brain.svg");
}

.pa-product-icon[data-product="search"] {
    background-image: url("/img/products/search.svg");
}



/* ── Page ────────────────────────────────────────────
   A single centred card on the canvas — no shell, no scroll container. */

body {
    display: grid;
    align-items: center;
    justify-content: center;
    min-height: 100dvh;

    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    letter-spacing: -0.005em;
}

/* ── Card ────────────────────────────────────────────
   Brain's panel treatment: --panel on --bg, --radius-lg, one hairline border with a
   lit top edge, and the two-layer ambient shadow. */

.pa-login-card {
    display: grid;
    gap: 1.5rem;
    width: min(22rem, 90vw);
    padding: 2.5rem 2rem;

    background: var(--panel);
    border: 1px solid var(--line);
    border-top-color: var(--top-highlight);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.pa-login-logo {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}

.pa-login-wordmark {
    font-size: var(--font-size-lg);
    font-weight: 600;
    color: var(--text);
}

/* ── Banners ─────────────────────────────────────────
   The first-run notice carries the brand tone; errors carry --stuck's rose. */

.pa-login-notice {
    background: var(--brand-soft);
    border: 1px solid var(--brand-line);
    border-radius: var(--radius-md);
    padding: 0.625rem 0.875rem;
    font-size: var(--font-size-sm);
    color: var(--text);
}

.pa-login-error {
    background: var(--env-rose-soft);
    border: 1px solid var(--env-rose-line);
    border-radius: var(--radius-md);
    padding: 0.625rem 0.875rem;
    font-size: var(--font-size-sm);
    color: var(--env-rose);
}

/* ── Fields ──────────────────────────────────────────── */

.pa-login-form {
    display: grid;
    gap: 1rem;
}

.pa-field {
    display: grid;
    gap: 0.3125rem;
}

/* Invite-signup TNC row: checkbox beside label — single-axis alignment. */
.pa-field--checkbox {
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 0.5rem;
    font-size: var(--font-size-sm);
    color: var(--fg-1);
}

.pa-field-label {
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--faint);
}

/* Mirrors admin.css .pa-input — keep the two in sync. */
.pa-input {
    background: var(--bg-inset);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-inset);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    padding: 0.4rem 0.6rem;
    min-width: 0;
}
.pa-input::placeholder {
    color: var(--dim);
}
.pa-input:hover:not(:disabled):not([readonly]) {
    border-color: var(--line-2);
}
.pa-input:focus {
    outline: none;
    border-color: var(--brand-line);
}

/* The email field is the page's primary input — one step up the scale, not the
   1.5rem of the pre-Brain palette, which overwhelmed the denser type scale. */
.pa-input[type="email"] {
    font-size: var(--font-size-lg);
    padding: 0.5rem 0.6rem;
}

/* ── Buttons ─────────────────────────────────────────
   Mirrors admin.css — keep the two in sync. */

.pa-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--raised);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    padding: 0.4375rem 0.875rem;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
    white-space: nowrap;
}
.pa-btn:hover {
    background: var(--hover);
    border-color: var(--line-2);
}
.pa-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

/* Brand fill takes dark text, not white — white on Brain's clay fails AA. */
.pa-btn--primary {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--bg);
    font-weight: 600;
}
.pa-btn--primary:hover:not(:disabled) {
    background: var(--clay);
    border-color: var(--clay);
}

.pa-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--faint);
    cursor: pointer;
    padding: 0.375rem;
    transition: background 0.12s, color 0.12s;
}
.pa-icon-btn:hover {
    background: var(--raised);
    color: var(--text);
}

/* ── CSS-only tab panel ──────────────────────────────
   QR code / manual key, switched by the radio inside each label — no JS. Each
   .pa-tab sits in the header row; its panel is stacked in the body row and revealed
   by the :has(input:checked) sibling match. */

.pa-tabs {
    display: grid;
    grid-template-rows: [header-start] 2.2rem [header-end body-start] 1fr [body-end];
    grid-template-columns: 1fr 1fr;
}

.pa-tab {
    grid-row: header-start / header-end;
    display: grid;
    align-items: center;
    justify-items: center;
    padding: 0 0.75rem;
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--faint);
    cursor: pointer;
    border-bottom: 0.125rem solid var(--line);
    user-select: none;
    white-space: nowrap;
    transition: color 0.12s, border-color 0.12s;
}
.pa-tab input[type="radio"] {
    display: none;
}
.pa-tab:hover {
    color: var(--muted);
}
.pa-tab:has(input:checked) {
    color: var(--text);
    border-bottom-color: var(--brand);
}

.pa-tab-panel {
    grid-area: body-start / 1 / body-end / -1;
    visibility: hidden;
    padding-top: 1rem;
}
.pa-tab:has(input:checked) + .pa-tab-panel {
    visibility: visible;
}

/* ── TOTP enrolment ──────────────────────────────────── */

.pa-totp-setup {
    display: grid;
    gap: 1rem;
}

.pa-totp-instructions {
    font-size: var(--font-size-sm);
    color: var(--faint);
}

.pa-qr-wrap {
    display: flex;
    justify-content: center;
}

/* The QR quiet zone must stay white for scanners — this is a functional surface,
   not a palette colour, so it takes no token. */
.pa-qr-svg-wrap {
    position: relative;
    display: inline-flex;
    border-radius: var(--radius-md);
    background: hsl(0 0% 100%);
    padding: 0.5rem;
}
.pa-qr-svg-wrap svg {
    display: block;
    width: 11rem;
    height: 11rem;
}
.pa-qr-logo {
    position: absolute;
    inset: 50% auto auto 50%;
    transform: translate(-50%, -50%);
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-xs);
    background: hsl(0 0% 100%);
    padding: 0.125rem;
    object-fit: contain;
}

/* ── Manual setup key ────────────────────────────────── */

.pa-secret-block {
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 0.75rem 1rem;
}

.pa-secret-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.625rem;
}

.pa-secret-label {
    font-size: var(--font-size-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--dim);
}

.pa-secret-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.375rem;
}

.pa-secret-chunk {
    display: grid;
    place-items: center;
    font-family: var(--font-mono);
    font-size: var(--font-size-md);
    font-weight: 500;
    letter-spacing: 0.12em;
    color: var(--text);
    padding: 0.5rem 0;
}

/* Bordered variant of .pa-icon-btn — it sits on --raised, where a borderless icon
   button has no edge to read against. */
.pa-copy-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    color: var(--faint);
    cursor: pointer;
    padding: 0.3125rem;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.pa-copy-btn:hover {
    background: var(--hover);
    border-color: var(--line-2);
    color: var(--text);
}

/* ── 6-digit code grid ───────────────────────────────── */

.pa-totp-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.5rem;
}

.pa-totp-cell {
    display: grid;
    place-items: center;
    height: 3rem;
    background: var(--bg-inset);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-inset);
    transition: border-color 0.12s;
}
.pa-totp-cell input {
    width: 100%;
    height: 100%;
    background: transparent;
    border: none;
    outline: none;
    text-align: center;
    font-family: var(--font-mono);
    font-size: var(--font-size-xl);
    font-weight: 500;
    color: var(--text);
    caret-color: var(--brand);
    padding: 0;
}
.pa-totp-cell input::placeholder {
    color: var(--dim);
}
.pa-totp-cell:focus-within {
    border-color: var(--brand-line);
}

/* ── Workspace picker (ADR-0025) ──────────────────────
   Same card as the login form; the rows are the only new furniture. */

.pa-ws-card {
    max-width: 26rem;
}

.pa-ws-lede {
    color: var(--muted);
    font-size: var(--font-size-sm);
    margin: 0 0 0.25rem;
}

.pa-ws-list {
    display: grid;
    gap: 0.4rem;
}

/* A whole row is the submit button — the tenant id rides as its value, so there
   is one control per workspace and no separate "continue" step to mis-click. */
.pa-ws-row {
    display: grid;
    grid-template-columns: 2.2rem minmax(0, 1fr);
    align-items: center;
    gap: 0.65rem;
    width: 100%;
    padding: 0.55rem 0.6rem;
    background: var(--bg-inset);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    color: var(--text);
    font-family: inherit;
    font-size: var(--font-size-base);
    text-align: left;
    cursor: pointer;
}

.pa-ws-row:hover {
    background: var(--raised);
    border-color: var(--line-2);
}

.pa-ws-mark {
    display: grid;
    place-items: center;
    width: 2.2rem;
    height: 2.2rem;
    border-radius: var(--radius-sm);
    background: var(--raised);
    border: 1px solid var(--line-3);
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    text-transform: lowercase;
}

.pa-ws-body {
    display: grid;
    min-width: 0;
}

.pa-ws-name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pa-ws-meta {
    color: var(--faint);
    font-size: var(--font-size-xs);
}
