/* ================================================================
   EclipsVault design system
   Layers: fonts → tokens → base → shell → components → pages → overlays → legacy
   Influences: Apple HIG — restraint, hairline borders, generous space,
   a single accent used sparingly, soft depth, calm motion.
   New features should COMPOSE these components (panel, page-header,
   data-table, badge, button, field, flash) rather than add one-off CSS.
   ================================================================ */

/* ---- Typeface --------------------------------------------------- */
/* Geist, served from this origin. Not from Google Fonts, and not by @import:
   the vault's own Content-Security-Policy is style-src 'self'; font-src 'self',
   so a CDN import is blocked outright — and relaxing the policy to allow it
   would let a third party inject stylesheets into pages that display secrets,
   which is a real exfiltration channel (attribute selectors + url()), and would
   leak every user's address to that third party on every page load. It would
   also simply fail on the isolated networks this product is deployed into.

   Two variable files carry every weight (~138 KB total, less than a handful of
   static weights would cost), so the whole family is one request each and works
   with no network at all. SIL OFL 1.1 — see fonts/OFL.txt, kept alongside as
   the licence requires. */
@font-face {
    font-family: 'Geist';
    src: url('/fonts/geist-variable.woff2') format('woff2');
    font-weight: 100 900;   /* variable axis: any weight the design asks for */
    font-style: normal;
    font-display: swap;     /* text is readable immediately; it is not decoration */
}

@font-face {
    font-family: 'Geist Mono';
    src: url('/fonts/geist-mono-variable.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/* ---- Tokens ---------------------------------------------------- */
/* The dark palette is the default. A light palette is provided under
   :root[data-theme="light"]; the server stamps data-theme on <html> from the
   EclipsVault.Theme cookie (no inline script, no flash), and the sidebar toggle
   flips it live. Components reference tokens only, so this block is the whole theme. */
:root {
    color-scheme: dark;

    /* Layered near-black surfaces (cool, low-chroma) */
    --bg: #0a0b0f;
    --bg-sidebar: rgba(18, 20, 27, 0.72);
    /* Glass: the same raised surface, translucent, for elements that sit over the page
       backdrop. A token rather than a literal rgba() so the light theme can answer for
       itself — hardcoding a dark rgba here is how a "glass" panel ends up as a grey
       smear on white. */
    --bg-raised-glass: rgba(20, 22, 30, 0.72);
    --glass-blur: saturate(160%) blur(14px);
    --bg-raised: #14161e;
    --bg-raised-2: #181b25;
    --bg-inset: #0d0e13;
    --bg-hover: #1c1f2a;

    /* Hairline borders */
    --border: rgba(255, 255, 255, 0.07);
    --border-strong: rgba(255, 255, 255, 0.12);

    --text: #edeef2;
    --text-secondary: #b6bcca;
    --text-muted: #7f8798;
    --text-faint: #5b6273;

    /* Accent: warm eclipse corona amber, used sparingly */
    --accent: #ff9f0a;              /* aligns with Apple systemOrange */
    --accent-hover: #ffb84d;
    --accent-press: #d97f00;
    --accent-soft: rgba(255, 159, 10, 0.14);
    --accent-line: rgba(255, 159, 10, 0.30);

    --danger: #ff453a;              /* systemRed (dark) */
    --danger-soft: rgba(255, 69, 58, 0.14);
    --warn: #ffd60a;                /* systemYellow (dark) */
    --warn-soft: rgba(255, 214, 10, 0.12);
    --ok: #30d158;                  /* systemGreen (dark) */
    --ok-soft: rgba(48, 209, 88, 0.14);

    --radius-lg: 16px;
    --radius: 12px;
    --radius-sm: 8px;
    --radius-pill: 980px;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.55);

    --sidebar-width: 244px;
    --ease: cubic-bezier(0.32, 0.72, 0, 1);
    --dur: 200ms;

    /* System faces stay behind Geist: font-display:swap paints in them first, and they are
       what renders if the woff2 ever fails to load. */
    --font: 'Geist', -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    --mono: 'Geist Mono', ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace;

    /* Optical sizing: display type wants tighter tracking than body copy, which wants none. */
    --tracking-display: -0.03em;
    --tracking-heading: -0.02em;
}

/* ---- Light palette --------------------------------------------- */
/* Only color tokens change. Surfaces invert to layered whites, borders become
   black-alpha hairlines, and the amber accent deepens so it stays readable as
   link/button text on light — while keeping the same warm identity. */
:root[data-theme="light"] {
    color-scheme: light;

    --bg: #f3f4f7;
    --bg-sidebar: rgba(244, 245, 248, 0.80);
    /* Light glass is nearly opaque on purpose. White-on-white has almost no contrast to
       begin with, so the panel edge is the only thing separating content from page — let
       it go translucent and the layering disappears rather than deepens. */
    --bg-raised-glass: rgba(255, 255, 255, 0.86);
    --bg-raised: #ffffff;
    --bg-raised-2: #f6f7f9;
    --bg-inset: #eceef2;
    --bg-hover: #ebedf1;

    --border: rgba(0, 0, 0, 0.09);
    --border-strong: rgba(0, 0, 0, 0.16);

    --text: #1c1d22;
    --text-secondary: #4a4e58;
    --text-muted: #697080;
    --text-faint: #9aa0ac;

    --accent: #b45f04;
    --accent-hover: #8f4b00;
    --accent-press: #703b00;
    --accent-soft: rgba(180, 95, 4, 0.12);
    --accent-line: rgba(180, 95, 4, 0.32);

    --danger: #d70015;
    --danger-soft: rgba(215, 0, 21, 0.10);
    --warn: #8a6a00;
    --warn-soft: rgba(180, 140, 0, 0.15);
    --ok: #1a7f37;
    --ok-soft: rgba(26, 127, 55, 0.13);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.08);
    --shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
    --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.16);
}

/* A couple of rules bake in a white overlay for depth; on light they need a dark one. */
:root[data-theme="light"] .data-table tbody tr:hover td { background: rgba(0, 0, 0, 0.03); }
:root[data-theme="light"] .button.primary { box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25) inset; }

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

html { height: 100%; }

body {
    margin: 0;
    min-height: 100vh;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font);
    font-size: 15px;
    line-height: 1.5;
    /* No tracking at body size. The -0.01em here was compensating for SF Pro's looser
       metrics; Geist is drawn tight already, and carrying the compensation over would
       close up running text that people have to read carefully. */
    letter-spacing: 0;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;

    /* Lining, tabular figures everywhere. This is a screen full of counts, sequence numbers
       and timestamps in columns: proportional digits make them jitter between rows and make
       two numbers of the same magnitude look different lengths. */
    font-variant-numeric: tabular-nums lining-nums;
}

/* Ambient corona. Glass needs something behind it to be glass — blur a flat colour and you get
   the same flat colour, so the whole layer would be cost with no effect. Two very low-opacity
   radial pools give the backdrop something to pick up, and they are the eclipse the product is
   named for: a warm corona bleeding past a dark disc. Fixed and behind everything, so it does
   not move with scroll or intercept a single click. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(60rem 40rem at 78% -8%, rgba(255, 159, 10, 0.10), transparent 60%),
        radial-gradient(48rem 34rem at 8% 102%, rgba(120, 90, 255, 0.07), transparent 62%);
}

:root[data-theme="light"] body::before {
    background:
        radial-gradient(60rem 40rem at 78% -8%, rgba(255, 159, 10, 0.13), transparent 60%),
        radial-gradient(48rem 34rem at 8% 102%, rgba(120, 90, 255, 0.08), transparent 62%);
}

h1, h2, h3 { font-weight: 620; letter-spacing: var(--tracking-heading); margin: 0; line-height: 1.25; }
h1 { font-size: 1.5rem; letter-spacing: var(--tracking-display); }
h2 { font-size: 1.06rem; }

a { color: var(--accent); text-decoration: none; transition: color var(--dur) var(--ease); }
a:hover { color: var(--accent-hover); }

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

.muted { color: var(--text-muted); }
.mono { font-family: var(--mono); }

::selection { background: var(--accent-soft); color: var(--text); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

button { font-family: inherit; }

/* Motion restraint for users who ask for it */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ---- App shell -------------------------------------------------- */
.shell { display: flex; min-height: 100vh; }

.sidebar {
    width: var(--sidebar-width);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg-sidebar);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-right: 1px solid var(--border);
    padding: 1.2rem 0.85rem;
    position: sticky;
    top: 0;
    height: 100vh;
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.35rem 0.65rem 1.2rem;
    font-size: 1.08rem;
    font-weight: 650;
    color: var(--text);
    letter-spacing: -0.02em;
}
.brand:hover { color: var(--text); }
/* Eclipse logomark — the favicon's twin: a dark disc haloed by the accent ring. */
.brand-mark {
    width: 1.05em;
    height: 1.05em;
    border-radius: 50%;
    background: #05060a;
    border: 1.5px solid var(--accent);
    flex-shrink: 0;
}

/* ---- Command trigger (the ⌘K front door) -------------------------- */
/* Dressed as a search field because that is the shape people already know how to read: a
   magnifier, grey prompt text, a shortcut on the right. It sits directly under the brand — the
   first thing in the rail — because a shortcut is only discoverable if you meet it before you
   need it. */
.command-trigger {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    margin-bottom: 0.9rem;
    padding: 0.42rem 0.55rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-inset);
    color: var(--text-muted);
    font-family: inherit;
    font-size: 0.86rem;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
                color var(--dur) var(--ease);
}
.command-trigger:hover { border-color: var(--border-strong); background: var(--bg-hover); color: var(--text); }
.command-trigger svg { width: 15px; height: 15px; flex-shrink: 0; opacity: 0.8; }
/* The label yields and the keycap holds its size — if anything has to give in a narrow rail it
   should be the word "Search", not the shortcut this element exists to advertise. */
.command-trigger-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.command-trigger kbd { flex-shrink: 0; }

.sidenav { display: flex; flex-direction: column; gap: 2px; flex: 1; overflow-y: auto; }

.nav-section {
    padding: 1.15rem 0.65rem 0.4rem;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-faint);
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.52rem 0.65rem;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-size: 0.92rem;
    font-weight: 500;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.nav-item svg { width: 18px; height: 18px; flex-shrink: 0; opacity: 0.85; }
.nav-item:hover { background: var(--bg-hover); color: var(--text); }
.nav-item.active { background: var(--accent-soft); color: var(--accent); }
.nav-item.active svg { opacity: 1; }

/* Active indicator: an accent rule on the leading edge, which reads as "you are here" at a
   glance down the rail in a way a tinted background alone does not. It grows from the centre
   rather than sliding between items — the items are links, so the browser repaints the page
   anyway and there is no continuous element to slide. */
.nav-item { position: relative; }
.nav-item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 0;
    transform: translateY(-50%);
    border-radius: 0 2px 2px 0;
    background: var(--accent);
    transition: height var(--dur) var(--ease);
}
.nav-item.active::before { height: 60%; }
.nav-item:hover::before { height: 30%; background: var(--border-strong); }
.nav-item.active:hover::before { height: 60%; background: var(--accent); }

/* Collapsible nav groups (native <details>, no script). A group opens itself and tints its
   header when one of its children is the active page. */
.nav-group { display: flex; flex-direction: column; }
.nav-group-summary { cursor: pointer; list-style: none; }
.nav-group-summary::-webkit-details-marker { display: none; }
.nav-group-summary .nav-chevron { width: 14px; height: 14px; margin-left: auto; opacity: 0.55; transition: transform var(--dur) var(--ease); }
.nav-group[open] > .nav-group-summary .nav-chevron { transform: rotate(90deg); }
.nav-group-summary.has-active { color: var(--accent); }
.nav-group-summary.has-active svg { opacity: 1; }
/* Children indented under the header, with a guide line so the grouping reads at a glance. */
.nav-group-items { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 2px 1.45rem; padding-left: 0.4rem; border-left: 1px solid var(--border); }

.sidebar-footer {
    border-top: 1px solid var(--border);
    padding-top: 0.85rem;
    margin-top: 0.85rem;
}

/* ---- Account menu -------------------------------------------------- */
/* The card is now the whole footer, so the name finally gets the full width — the theme toggle
   and the sign-out button that used to flank it were where the missing pixels went. */
.account-menu { position: relative; }
.account-menu > summary { list-style: none; }
.account-menu > summary::-webkit-details-marker { display: none; }

.user-card {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.3rem;
    min-width: 0;
    border-radius: var(--radius-sm);
    color: var(--text);
    cursor: pointer;
    transition: background var(--dur) var(--ease);
}
.user-card:hover { background: var(--bg-hover); text-decoration: none; color: var(--text); }
.account-menu[open] > .user-card { background: var(--bg-hover); }

/* Points up, because that is where the panel opens — the sidebar's foot has nothing below it.
   A chevron that points down at a menu that appears above it is a small lie. */
.user-chevron { width: 15px; height: 15px; flex-shrink: 0; margin-left: auto; color: var(--text-faint); }

.account-menu-panel {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% + 6px);
    z-index: 30;
    padding: 0.3rem;
    background: var(--bg-raised-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.account-menu-panel .menu-item { border-radius: var(--radius-sm); }
.menu-sep { height: 1px; margin: 0.25rem 0; background: var(--border); }

/* Round avatar images at every size. */
.avatar-img, .avatar-sm, .avatar-lg {
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    background: var(--bg-inset);
}
.avatar-img { width: 34px; height: 34px; }
.avatar-sm { width: 30px; height: 30px; }
.avatar-lg { width: 96px; height: 96px; border-radius: 22px; }

.user-meta { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.user-name { font-size: 0.88rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* One line, like the name above it. The clearance names all fit (TopSecret is the longest at
   ~53px in ~98px), so the clipping here is a backstop, not the plan — the plan is in the view,
   which stopped printing the word "clearance" after them. */
.user-clearance {
    font-size: 0.72rem;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.icon-button {
    background: none;
    border: none;
    color: var(--text-muted);
    padding: 0.4rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: grid;
    place-items: center;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.icon-button svg { width: 17px; height: 17px; }
.icon-button:hover { background: var(--bg-hover); color: var(--danger); }

.content {
    flex: 1;
    min-width: 0;
    padding: 2rem 2.4rem 1rem;
    max-width: 1280px;
    display: flex;
    flex-direction: column;
    animation: content-in 320ms var(--ease);
}

@keyframes content-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

.content-footer {
    margin-top: auto;
    padding: 2.2rem 0 0.6rem;
    color: var(--text-faint);
    font-size: 0.78rem;
}

/* ---- Page header ------------------------------------------------ */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 1.6rem;
    flex-wrap: wrap;
}

.page-sub { margin: 0.4rem 0 0; color: var(--text-muted); font-size: 0.92rem; display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.page-actions { display: flex; gap: 0.6rem; flex-shrink: 0; }

/* ---- Panels & grids --------------------------------------------- */
.panel {
    /* Translucent over the page backdrop, so panels read as sheets above the surface rather
       than holes cut in it. The solid colour stays as the fallback: backdrop-filter is what
       makes this legible, and where it is unsupported an unblurred translucent panel would
       just be text over text. */
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.4rem 1.6rem;
    margin-bottom: 1.2rem;
    box-shadow: var(--shadow-sm);
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .panel, .stat-card {
        background: var(--bg-raised-glass);
        -webkit-backdrop-filter: var(--glass-blur);
        backdrop-filter: var(--glass-blur);
    }
}

.panel.highlight { border-color: var(--accent-line); background: linear-gradient(180deg, rgba(255, 159, 10, 0.06), var(--bg-raised) 60%); }
.panel.narrow { max-width: 520px; margin-left: auto; margin-right: auto; }
.panel.narrow-left { max-width: 660px; }

.panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
}

.two-col { display: grid; grid-template-columns: 3fr 2fr; gap: 1.2rem; align-items: start; margin-bottom: 1.2rem; }
/* min-width:0 lets the grid tracks shrink so inner scroll containers (e.g. .table-scroll)
   actually scroll, instead of a wide child forcing the whole page to scroll sideways. */
.two-col > .panel { margin-bottom: 0; min-width: 0; }
.stack { display: flex; flex-direction: column; gap: 1.2rem; }
.stack > .panel { margin-bottom: 0; min-width: 0; }

@media (max-width: 1000px) {
    .two-col { grid-template-columns: 1fr; }
}

/* ---- Stat cards -------------------------------------------------- */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    margin-bottom: 1.4rem;
}

.stat-card {
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.15rem 1.3rem;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    color: var(--text);
    box-shadow: var(--shadow-sm);
    transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}

/* Only the linked cards lift — the lift is the affordance that says this one goes somewhere,
   so lifting a plain stat would be a promise the card cannot keep. */
a.stat-card:hover {
    transform: translateY(-3px);
    border-color: var(--accent-line);
    color: var(--text);
    text-decoration: none;
    box-shadow: var(--shadow), 0 0 0 1px var(--accent-soft);
}
.stat-card { transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.stat-card.attention { border-color: rgba(255, 214, 10, 0.35); }
.stat-card.alert { border-color: rgba(255, 69, 58, 0.4); background: linear-gradient(180deg, var(--danger-soft), var(--bg-raised) 65%); }

.stat-value { font-size: 1.9rem; font-weight: 680; letter-spacing: -0.03em; }
.stat-label { font-size: 0.84rem; color: var(--text-secondary); font-weight: 600; }
.stat-detail { font-size: 0.76rem; color: var(--text-faint); }

/* ---- Buttons ----------------------------------------------------- */
.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.5rem 1.1rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--bg-raised-2);
    color: var(--text);
    font-size: 0.9rem;
    font-weight: 550;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease),
                background var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

.button:hover { background: var(--bg-hover); border-color: var(--border-strong); color: var(--text); text-decoration: none; }
.button:active { transform: scale(0.97); }

.button.primary { background: var(--accent); border-color: transparent; color: #1a1204; font-weight: 620; box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset; }
.button.primary:hover { background: var(--accent-hover); color: #1a1204; }
.button.danger { border-color: rgba(255, 69, 58, 0.5); color: var(--danger); background: transparent; }
.button.danger:hover { background: var(--danger); color: #fff; border-color: var(--danger); }
.button.small { padding: 0.28rem 0.72rem; font-size: 0.8rem; }
.button.wide { width: 100%; }
.button.copied { border-color: var(--ok); color: var(--ok); }

.button-row { display: flex; gap: 0.6rem; flex-wrap: wrap; }

/* ---- Keycaps ------------------------------------------------------ */
/* A shortcut should look like the key you press. The heavier bottom edge is the whole trick —
   one line of fake depth that reads as a keycap instead of a code span, which is what stops
   "⌘K" from looking like a variable name. A component rather than a rule scoped to the palette:
   a shortcut renders the same wherever the product mentions one. */
kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    padding: 0.1rem 0.3rem;
    border: 1px solid var(--border-strong);
    border-bottom: 2px solid var(--border-strong);
    border-radius: 5px;
    background: var(--bg-raised-2);
    color: var(--text-muted);
    font-family: var(--mono);
    font-size: 0.7rem;
    line-height: 1.4;
    white-space: nowrap;
}

.link-button {
    background: none;
    border: none;
    color: var(--text);
    cursor: pointer;
    font-size: 1rem;
    padding: 0;
}
.link-button:hover { color: var(--accent); }

.inline-form { display: inline; }

/* ---- Forms -------------------------------------------------------- */
/* min-width:0 lets a field (and its width:100% control) shrink inside a flex row, so a
   two-column .field-row can never overflow the page — some browsers give form controls a
   large intrinsic min-width otherwise. flex-wrap is a safety net for very tight widths. */
.field { margin-bottom: 1.05rem; display: flex; flex-direction: column; gap: 0.35rem; flex: 1; min-width: 0; }
.field label { font-size: 0.84rem; font-weight: 600; color: var(--text-secondary); }
.field-row { display: flex; gap: 1rem; flex-wrap: wrap; }

/* ---- Input affix (show/hide password) ---------------------------- */
/* The wrapper is built by site.js around any input[data-reveal], so a view opts in with one
   attribute and no field has to repeat the markup. */
.input-affix { position: relative; display: flex; align-items: center; }
.input-affix > input { padding-right: 2.6rem; }

.affix-button {
    position: absolute;
    right: 0.35rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.affix-button:hover { color: var(--text); background: var(--bg-hover); }
.affix-button svg { width: 17px; height: 17px; }

/* ---- Password strength ------------------------------------------- */
/* Advisory, not a gate: the two rules the vault actually enforces (length, breach corpus) are
   reported as text by the field's own validation and the live breach check. This says how
   expensive the password would be to guess, which no pass/fail can express.

   The top margin keeps the bar clear of the input. Butted right up under the field it reads as
   a green bottom border on the input — a statement about the field — rather than a separate
   verdict about the password. */
.strength { display: flex; flex-direction: column; gap: 0.3rem; margin-top: 0.55rem; }
/* `display` here outranks the user agent's [hidden] rule, so the meter needs to opt back out
   explicitly — without this it shows an empty track before a single character is typed. */
.strength[hidden] { display: none; }

.strength-track {
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--bg-inset);
    overflow: hidden;
}

.strength-fill {
    display: block;
    height: 100%;
    width: 0;
    border-radius: var(--radius-pill);
    background: var(--text-faint);
    transition: width var(--dur) var(--ease), background var(--dur) var(--ease);
}

.strength-label { margin: 0; font-size: 0.76rem; color: var(--text-muted); }

.strength[data-score="0"] .strength-fill,
.strength[data-score="1"] .strength-fill { background: var(--danger); }
.strength[data-score="2"] .strength-fill { background: var(--warn); }
.strength[data-score="3"] .strength-fill { background: var(--accent); }
.strength[data-score="4"] .strength-fill { background: var(--ok); }

.strength[data-score="0"] .strength-label,
.strength[data-score="1"] .strength-label { color: var(--danger); }
.strength[data-score="4"] .strength-label { color: var(--ok); }

@media (max-width: 640px) { .field-row { flex-direction: column; gap: 0; } }

input, textarea, select {
    background: var(--bg-inset);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text);
    padding: 0.6rem 0.8rem;
    font-size: 0.95rem;
    font-family: inherit;
    width: 100%;
    transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

textarea { resize: vertical; font-family: var(--mono); font-size: 0.88rem; line-height: 1.5; }

input::placeholder, textarea::placeholder { color: var(--text-faint); }

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

input.code-input {
    font-family: var(--mono);
    font-size: 1.5rem;
    letter-spacing: 0.5em;
    text-align: center;
    padding-left: 0.5em;
}

.hint { font-size: 0.83rem; margin: -0.2rem 0 1.1rem; line-height: 1.5; overflow-wrap: anywhere; }

.field-error, .validation-summary { color: var(--danger); font-size: 0.84rem; }
.validation-summary:empty { display: none; }
.validation-summary ul { margin: 0.3rem 0 1rem; padding-left: 1.2rem; }

/* ---- Flash toasts ------------------------------------------------ */
.flash {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1rem 0.75rem 1.1rem;
    border-radius: var(--radius);
    border: 1px solid var(--border-strong);
    background: var(--bg-raised-2);
    box-shadow: var(--shadow);
    margin-bottom: 1.2rem;
    font-size: 0.92rem;
    position: relative;
    overflow: hidden;
    animation: flash-in 360ms var(--ease);
}
.flash::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; }
.flash-success::before { background: var(--ok); }
.flash-error::before { background: var(--danger); }
.flash-info::before { background: var(--accent); }
.flash-hide { opacity: 0; transform: translateY(-6px); }

@keyframes flash-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

.flash-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 0.2rem;
}
.flash-close:hover { color: var(--text); }

/* ---- Tables -------------------------------------------------------- */
/* Wide tables scroll inside their own box so the page never scrolls horizontally. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll .data-table { min-width: 640px; }

.table-toolbar { margin-bottom: 1rem; }
.table-search { max-width: 340px; }

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

.data-table th {
    text-align: left;
    color: var(--text-faint);
    font-weight: 600;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.5rem 0.7rem;
    border-bottom: 1px solid var(--border-strong);
    white-space: nowrap;
}

.data-table td { padding: 0.65rem 0.7rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr { transition: background var(--dur) var(--ease); }
.data-table tbody tr:hover td { background: rgba(255, 255, 255, 0.025); }
.data-table tr[data-href] { cursor: pointer; }
.data-table .row-critical td { background: var(--danger-soft); }

.cell-strong { font-weight: 600; }
.cell-strong .badge { margin-left: 0.4rem; }
.cell-actions { text-align: right; white-space: nowrap; }
.cell-actions .inline-form + .inline-form,
.cell-actions .button + .inline-form { margin-left: 0.4rem; }
.cell-wrap { max-width: 340px; }

.empty-state {
    text-align: center;
    padding: 3rem 1.5rem;
    max-width: 32rem;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
}
.empty-state .empty-icon {
    width: 54px;
    height: 54px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
    margin-bottom: 0.5rem;
}
.empty-state .empty-icon svg { width: 26px; height: 26px; }
.empty-state h3 { margin: 0; font-size: 1.05rem; font-weight: 650; letter-spacing: -0.01em; }
.empty-state p { margin: 0; color: var(--text-muted); line-height: 1.55; }
.empty-state .button { margin-top: 0.9rem; }

/* ---- Badges --------------------------------------------------------- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.13rem 0.6rem;
    border-radius: var(--radius-pill);
    font-size: 0.73rem;
    font-weight: 600;
    border: 1px solid var(--border-strong);
    color: var(--text-muted);
    white-space: nowrap;
    letter-spacing: 0;
}

.badge.env-development { color: var(--ok); border-color: transparent; background: var(--ok-soft); }
.badge.env-staging { color: var(--warn); border-color: transparent; background: var(--warn-soft); }
.badge.env-production { color: var(--danger); border-color: transparent; background: var(--danger-soft); }

/* Classification badges. The glow rises with the classification, so the most dangerous thing on
   a page is the thing your eye lands on first — on a screen full of pills that all look alike,
   "which of these is the production root key?" should not need reading. Restrained on purpose:
   this is a signal, not decoration, and if every badge glowed none of them would mean anything.
   No animation, either — a pulsing badge in the corner of the eye is a thing operators learn to
   tune out, which is the opposite of what a TopSecret marker is for. */
.badge.sens-1 { color: var(--text-muted); }
.badge.sens-2 { color: var(--ok); border-color: transparent; background: var(--ok-soft); }
.badge.sens-3 {
    color: var(--warn);
    border-color: rgba(255, 214, 10, 0.32);
    background: var(--warn-soft);
}
.badge.sens-4 {
    color: var(--danger);
    border-color: rgba(255, 69, 58, 0.34);
    background: var(--danger-soft);
    box-shadow: 0 0 12px rgba(255, 69, 58, 0.16);
    font-weight: 650;
}
.badge.env-production { box-shadow: 0 0 10px rgba(255, 69, 58, 0.12); }

.badge.tone-ok { color: var(--ok); border-color: transparent; background: var(--ok-soft); }
.badge.tone-warn { color: var(--warn); border-color: transparent; background: var(--warn-soft); }
.badge.tone-danger { color: var(--danger); border-color: transparent; background: var(--danger-soft); }
.badge.tone-muted { color: var(--text-muted); }
.badge.tone-critical {
    color: #fff;
    border-color: transparent;
    background: var(--danger);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.68rem;
}

/* ---- Activity list (dashboard) --------------------------------------- */
.activity-list { list-style: none; margin: 0; padding: 0; }

.activity-item {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.6rem 0.2rem;
    border-bottom: 1px solid var(--border);
    font-size: 0.88rem;
}
.activity-item:last-child { border-bottom: none; }
.activity-item.critical { background: var(--danger-soft); border-radius: var(--radius-sm); padding-left: 0.55rem; padding-right: 0.55rem; }
.activity-target { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-secondary); }
.activity-meta { color: var(--text-faint); font-size: 0.78rem; white-space: nowrap; }

/* ---- Personal activity feed (My activity page) ------------------------- */
.activity-feed { list-style: none; margin: 0; padding: 0; }

.feed-item {
    display: flex;
    gap: 0.85rem;
    align-items: flex-start;
    padding: 0.85rem 0.35rem;
    border-bottom: 1px solid var(--border);
}
.feed-item:last-child { border-bottom: none; }

.feed-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--bg-inset);
    border: 1px solid var(--border);
    color: var(--text-secondary);
}
.feed-icon svg { width: 18px; height: 18px; }
.feed-item.sev-warn .feed-icon { color: var(--warn); border-color: transparent; background: var(--warn-soft); }
.feed-item.sev-critical .feed-icon { color: #fff; border-color: transparent; background: var(--danger); }

.feed-body { flex: 1; min-width: 0; }
.feed-title-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.feed-title { font-size: 0.9rem; font-weight: 550; color: var(--text); }
.feed-resource { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed-meta { margin-top: 0.2rem; font-size: 0.78rem; color: var(--text-faint); }
.feed-time { flex-shrink: 0; color: var(--text-faint); font-size: 0.78rem; white-space: nowrap; padding-top: 0.15rem; }

.pager { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: 1.1rem; }
.pager-side { display: flex; gap: 0.6rem; min-width: 90px; }
.pager-side:last-child { justify-content: flex-end; }
.pager-page { color: var(--text-muted); font-size: 0.82rem; }

/* Right-aligned action on a feed row (signed-in devices). */
.feed-action { flex-shrink: 0; align-self: center; }
.feed-item.session-current .feed-icon { color: var(--ok); border-color: transparent; background: var(--ok-soft); }
.current-pill { font-size: 0.78rem; }

/* ---- Security checkup -------------------------------------------------- */
.checkup-hero { display: flex; align-items: center; gap: 1.6rem; flex-wrap: wrap; }

.score-ring { position: relative; width: 132px; height: 132px; flex-shrink: 0; }
.score-ring svg { display: block; }
.ring-track { stroke: var(--border); }
/* The value arc inherits the grade colour via currentColor; its length is set server-side
   as a stroke-dasharray presentation attribute, so no inline style is needed (CSP-clean). */
.ring-value { stroke: currentColor; transition: stroke-dasharray var(--dur) var(--ease); }
.score-center { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; }
.score-number { font-size: 2rem; font-weight: 680; color: var(--text); line-height: 1; }
.score-outof { font-size: 0.72rem; color: var(--text-faint); }

.checkup-summary { flex: 1; min-width: 240px; display: flex; flex-direction: column; gap: 0.5rem; }
.grade-label { display: inline-block; font-size: 0.82rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; }
.checkup-lead { margin: 0; color: var(--text-secondary); font-size: 0.95rem; }
.checkup-counts { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.2rem; }

/* Grade colour, shared by the ring (currentColor) and the headline label. */
.grade-strong { color: var(--ok); }
.grade-good { color: var(--ok); }
.grade-fair { color: var(--warn); }
.grade-atrisk { color: var(--danger); }

/* Per-control icon chip, coloured by standing (mirrors the activity feed's severity chips). */
.feed-item.check-pass .feed-icon { color: var(--ok); border-color: transparent; background: var(--ok-soft); }
.feed-item.check-warn .feed-icon { color: var(--warn); border-color: transparent; background: var(--warn-soft); }
.feed-item.check-fail .feed-icon { color: #fff; border-color: transparent; background: var(--danger); }
.check-rec { margin-top: 0.3rem; font-size: 0.82rem; color: var(--text-secondary); }

/* ---- My access (permission matrix) ------------------------------------ */
.access-matrix { width: 100%; border-collapse: collapse; font-size: 0.86rem; min-width: 520px; }
.access-matrix th, .access-matrix td { padding: 0.6rem 0.8rem; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
.access-matrix tr:last-child th, .access-matrix tr:last-child td { border-bottom: none; }
.access-matrix thead th { color: var(--text-muted); font-weight: 600; font-size: 0.8rem; }
.access-matrix tbody th { font-weight: 500; }
.cell-icon { width: 15px; height: 15px; vertical-align: middle; margin-right: 0.35rem; }
.access-matrix td span { vertical-align: middle; }
.cell-allow { color: var(--ok); background: var(--ok-soft); }
.cell-deny { color: var(--text-muted); }
.access-hint { margin: 0.9rem 0 0; font-size: 0.82rem; line-height: 1.5; }

.panel.callout-warn { border-left: 3px solid var(--warn); }

/* ---- Quick actions ----------------------------------------------------- */
.quick-actions { display: flex; flex-direction: column; gap: 0.6rem; }

.quick-action {
    display: flex;
    flex-direction: column;
    gap: 0.12rem;
    padding: 0.8rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text);
    background: var(--bg-inset);
    transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.quick-action:hover { border-color: var(--accent-line); background: var(--bg-hover); color: var(--text); text-decoration: none; transform: translateX(2px); }
.quick-action span { font-size: 0.8rem; }

/* ---- Detail grid & secret views ----------------------------------------- */
.detail-grid {
    display: grid;
    grid-template-columns: 130px 1fr;
    gap: 0.5rem 1rem;
    margin: 0.4rem 0 1.2rem;
    font-size: 0.9rem;
    min-width: 0;
}
.detail-grid dt { color: var(--text-muted); }
.detail-grid dd { margin: 0; color: var(--text-secondary); overflow-wrap: anywhere; }

.secret-code {
    display: block;
    background: var(--bg-inset);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 0.75rem 0.9rem;
    font-family: var(--mono);
    font-size: 0.88rem;
    word-break: break-all;
    margin: 0.4rem 0 1rem;
}
.secret-code.small { font-size: 0.76rem; }

.revealed-box {
    border: 1px solid var(--accent-line);
    border-radius: var(--radius);
    padding: 1rem 1.15rem;
    background: linear-gradient(180deg, var(--accent-soft), transparent 75%);
}
.revealed-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.4rem; }

.danger-zone {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    border: 1px solid rgba(255, 69, 58, 0.35);
    border-radius: var(--radius);
    padding: 0.9rem 1.1rem;
    margin-top: 1.2rem;
    background: linear-gradient(180deg, var(--danger-soft), transparent 85%);
}
.danger-zone p { margin: 0.15rem 0 0; font-size: 0.82rem; }

/* ---- Networks page -------------------------------------------------------- */
.current-ip { display: flex; justify-content: space-between; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.current-ip-value { display: flex; align-items: center; gap: 0.7rem; margin: 0.4rem 0; }
.current-ip-value code { font-size: 1.3rem; font-weight: 600; }
.current-ip p { margin: 0.35rem 0 0; max-width: 560px; font-size: 0.85rem; }

.add-network-form { display: flex; gap: 0.6rem; margin-bottom: 1rem; flex-wrap: wrap; }
.add-network-form input { flex: 1; min-width: 150px; }
.add-network-form .button { flex-shrink: 0; }
.input-narrow { flex: 0 0 auto; max-width: 150px; }

.cidr-list { list-style: none; margin: 0; padding: 0; font-size: 0.88rem; }
.cidr-list li { padding: 0.4rem 0; border-bottom: 1px solid var(--border); color: var(--text-muted); }
.cidr-list li:last-child { border-bottom: none; }

/* ---- TOTP enrollment -------------------------------------------------------- */
.totp-secret { margin: 1.2rem 0; }

.totp-qr {
    display: block;
    width: 216px;
    height: 216px;
    padding: 12px;
    background: #fff;
    border-radius: var(--radius);
    margin: 0.5rem auto 1rem;
    image-rendering: pixelated;
    box-shadow: var(--shadow);
}

/* ---- ABAC denial ------------------------------------------------------------- */
.denial-reasons { margin: 0.6rem 0 1rem; padding-left: 1.3rem; }
.denial-reasons li { margin: 0.4rem 0; color: var(--danger); }

/* ---- Auth pages ---------------------------------------------------------------- */
.auth-body {
    background:
        radial-gradient(ellipse 70% 50% at 50% -10%, rgba(255, 159, 10, 0.10), transparent 70%),
        var(--bg);
}

.auth-wrap {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
    gap: 1.2rem;
}

.auth-brand { font-size: 1.35rem; padding: 0; }

.auth-card {
    width: 100%;
    max-width: 440px;
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 2rem 2.1rem;
    box-shadow: var(--shadow-lg);
    animation: content-in 380ms var(--ease);
}

.auth-card h1 { font-size: 1.3rem; margin-bottom: 0.45rem; }
.auth-card > .muted { margin-top: 0; font-size: 0.9rem; line-height: 1.5; }
.auth-card form { margin-top: 1.4rem; }

.auth-card.landing { max-width: 520px; text-align: left; }
.landing-points { margin: 1.1rem 0 1.5rem; padding-left: 1.2rem; color: var(--text-muted); font-size: 0.9rem; }
.landing-points li { margin: 0.45rem 0; }

.footnote { color: var(--text-faint); font-size: 0.8rem; margin: 1rem 0 0; line-height: 1.5; }
.auth-footnote { color: var(--text-faint); font-size: 0.78rem; }

.auth-wrap .flash { width: 100%; max-width: 440px; margin-bottom: 0; }

/* Step indicator for the multi-step auth flow */
.step-track { display: flex; gap: 6px; margin-bottom: 1.1rem; }
.step { height: 3px; flex: 1; border-radius: 2px; background: var(--border-strong); transition: background var(--dur) var(--ease); }
.step.active { background: var(--accent); }
.step.done { background: var(--accent-press); }

/* ---- Overlays: custom confirm dialog ------------------------------------------- */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    display: grid;
    place-items: center;
    z-index: 1000;
    padding: 1rem;
    animation: fade-in 180ms var(--ease);
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.modal {
    width: 100%;
    max-width: 400px;
    background: var(--bg-raised-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    padding: 1.5rem 1.6rem;
    box-shadow: var(--shadow-lg);
    animation: modal-in 260ms var(--ease);
}
@keyframes modal-in { from { opacity: 0; transform: scale(0.96) translateY(8px); } to { opacity: 1; transform: none; } }

/* ---- Command palette (⌘K) ---------------------------------------------------- */
/* Sits high rather than centred: the list grows downward as you type, and a centred panel that
   grows from the middle moves its own first result out from under the cursor. */
.palette-backdrop { place-items: start center; padding-top: 12vh; }

.palette {
    width: 100%;
    max-width: 560px;
    background: var(--bg-raised-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    animation: modal-in 200ms var(--ease);
}

.palette-field {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.9rem 1rem;
    border-bottom: 1px solid var(--border);
}
.palette-field svg { width: 17px; height: 17px; color: var(--text-faint); flex-shrink: 0; }

/* Not the standard input: this one is the whole panel's field, so the usual border and background
   would draw a box inside a box. */
.palette-input {
    flex: 1;
    border: 0;
    background: none;
    padding: 0;
    font-size: 0.98rem;
    color: var(--text);
}
.palette-input:focus { outline: none; box-shadow: none; }
.palette-input::placeholder { color: var(--text-faint); }

.palette-list {
    list-style: none;
    margin: 0;
    padding: 0.35rem;
    max-height: 46vh;
    overflow-y: auto;
}

.palette-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 0.65rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
}
/* Keyboard and mouse drive the same single highlight — :hover as a separate visual state would
   mean two "selected" rows whenever the pointer rests somewhere the arrows are not. */
.palette-item.is-active { background: var(--bg-hover); }

.palette-kind {
    flex-shrink: 0;
    font-size: 0.66rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-faint);
    width: 3.4rem;
}
.palette-label { color: var(--text); font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.palette-meta { color: var(--text-muted); font-size: 0.78rem; white-space: nowrap; }
/* Pushes the badge to the trailing edge so the classifications line up in a column. */
.palette-item .badge { margin-left: auto; }

.palette-empty { padding: 1.1rem 0.65rem; text-align: center; color: var(--text-muted); font-size: 0.86rem; }

.palette-hint {
    display: flex;
    gap: 1rem;
    margin: 0;
    padding: 0.6rem 1rem;
    border-top: 1px solid var(--border);
    background: var(--bg-inset);
    color: var(--text-faint);
    font-size: 0.72rem;
}
.palette-hint kbd { margin-right: 0.15rem; }

@media (max-width: 640px) {
    .palette-hint { display: none; }   /* no modifier keys to advertise on a touch keyboard */
    .palette-backdrop { padding-top: 6vh; }
}

.modal h3 { margin-bottom: 0.5rem; }
.modal p { color: var(--text-secondary); font-size: 0.9rem; margin: 0 0 1.3rem; line-height: 1.5; }
.modal-actions { display: flex; justify-content: flex-end; gap: 0.6rem; }

/* ---- Profile page --------------------------------------------------------------- */
.visually-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.avatar-editor { display: flex; align-items: center; gap: 1.3rem; flex-wrap: wrap; }
.avatar-editor-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.avatar-editor-actions .hint { flex-basis: 100%; margin: 0.2rem 0 0; }
/* A <label> styled as a button to trigger the hidden file input. */
label.button { cursor: pointer; }

.settings-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.9rem 0;
    border-bottom: 1px solid var(--border);
}
.settings-row:last-child { border-bottom: none; }
.settings-row p { margin: 0.15rem 0 0; font-size: 0.83rem; }
.settings-row > div:first-child { min-width: 0; }

/* ---- User cell (admin list) ----------------------------------------------------- */
.user-cell { display: flex; align-items: center; gap: 0.65rem; }
.user-cell-text { display: flex; flex-direction: column; min-width: 0; }
.user-cell-sub { font-size: 0.76rem; }
.data-table tr.row-muted td { opacity: 0.55; }

/* ---- Row overflow menu (details/summary) ---------------------------------------- */
.row-menu { position: relative; display: inline-block; }
.row-menu > summary { list-style: none; display: inline-flex; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu-panel {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    z-index: 30;
    min-width: 160px;
    padding: 0.3rem;
    background: var(--bg-raised-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    display: flex;
    flex-direction: column;
    gap: 1px;
    text-align: left;
}
.menu-item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    text-align: left;
    padding: 0.45rem 0.6rem;
    background: none;
    border: none;
    color: var(--text);
    font-size: 0.85rem;
    border-radius: 6px;
    cursor: pointer;
}
.menu-item svg { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.85; }
/* Colour pinned on hover, not just background: these rows are a mix of <a> and <button>, and the
   global a:hover turns links amber — so without this the one link in a menu would light up amber
   while the buttons beside it did not, in a menu whose whole point is that the rows are peers. */
.menu-item:hover { background: var(--bg-hover); color: var(--text); }
.menu-item.danger { color: var(--danger); }
.menu-item.danger:hover { background: var(--danger); color: #fff; }

/* ---- Notice banner (dashboard alerts) ------------------------------------------- */
.notice {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.7rem;
    padding: 0.8rem 1.1rem;
    border-radius: var(--radius);
    border: 1px solid var(--border-strong);
    background: var(--bg-raised);
    margin-bottom: 1.4rem;
    font-size: 0.92rem;
    overflow-wrap: anywhere;
}
.notice svg { width: 20px; height: 20px; flex-shrink: 0; }
.notice-warn { border-color: rgba(255, 214, 10, 0.4); background: linear-gradient(180deg, var(--warn-soft), var(--bg-raised) 70%); }
.notice-warn svg { color: var(--warn); }
.notice-ok { border-color: rgba(48, 209, 88, 0.4); background: linear-gradient(180deg, var(--ok-soft), var(--bg-raised) 70%); }
.notice-critical { border-color: rgba(255, 69, 58, 0.5); background: linear-gradient(180deg, var(--danger-soft), var(--bg-raised) 70%); }
.notice strong { margin-right: 0.15rem; }

/* ---- MFA recovery codes --------------------------------------------------------- */
.recovery-panel { max-width: 640px; }
.recovery-codes {
    list-style: none;
    margin: 1.4rem 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.6rem;
    counter-reset: recovery;
}
.recovery-codes li {
    counter-increment: recovery;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--bg-raised);
    font-size: 1.15rem;
    letter-spacing: 0.12em;
    user-select: all;
}
.recovery-codes li::before {
    content: counter(recovery);
    font-family: var(--sans, inherit);
    font-size: 0.75rem;
    letter-spacing: normal;
    color: var(--text-faint);
    min-width: 1.2em;
    text-align: right;
}
.recovery-actions { display: flex; flex-wrap: wrap; gap: 0.7rem; }

@media (max-width: 560px) {
    .recovery-codes { grid-template-columns: 1fr; }
    /* Phone widths: drop the fixed label column and let long button labels wrap so
       nothing forces horizontal page scroll. */
    .detail-grid { grid-template-columns: 1fr; gap: 0.15rem 0; }
    .detail-grid dt { margin-top: 0.55rem; }
    .detail-grid dt:first-child { margin-top: 0; }
    .button { white-space: normal; }
}

@media print {
    .sidebar, .content-footer, .recovery-actions, .flash, .notice { display: none !important; }
    .recovery-codes li { border-color: #000; background: #fff; color: #000; }
}

/* ---- Rotate + version-history timeline ------------------------------------------ */
details.rotate > summary { list-style: none; display: inline-flex; cursor: pointer; }
details.rotate > summary::-webkit-details-marker { display: none; }
.rotate-form { margin-top: 0.9rem; }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline-item { position: relative; display: flex; gap: 0.9rem; padding: 0 0 1.1rem 0; }
.timeline-item:not(:last-child) .timeline-dot::after {
    content: ""; position: absolute; left: 5px; top: 14px; bottom: -6px; width: 2px; background: var(--border-strong);
}
.timeline-dot { position: relative; width: 12px; flex-shrink: 0; }
.timeline-dot::before {
    content: ""; position: absolute; left: 0; top: 4px; width: 12px; height: 12px;
    border-radius: 50%; background: var(--bg-raised); border: 2px solid var(--accent);
}
.timeline-body { flex: 1; min-width: 0; }
.timeline-head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.timeline-note { margin: 0.2rem 0 0; font-size: 0.85rem; }
.timeline-actions { display: flex; gap: 0.5rem; margin-top: 0.5rem; }

/* ---- Theme toggle --------------------------------------------------------------- */
/* Show the icon of the theme you'd switch TO: a sun in dark mode, a moon in light. */
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: inline; }
.auth-theme-toggle { position: absolute; top: 1.2rem; right: 1.2rem; }

/* ---- Access requests ------------------------------------------------------------ */
.field textarea {
    width: 100%;
    padding: 0.6rem 0.75rem;
    background: var(--bg-raised-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-family: var(--font);
    font-size: 0.92rem;
    line-height: 1.5;
    resize: vertical;
}
.field textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.review-approve input { max-width: 74px; }

/* ---- API key scope form --------------------------------------------------------- */
.issue-key-form { margin-bottom: 1.2rem; }
.field-inline-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.field-inline-row .field { flex: 1 1 180px; min-width: 0; }
.check-inline { display: flex; align-items: center; gap: 0.5rem; flex: 1 1 200px; font-size: 0.88rem; color: var(--text-secondary); }
.check-inline input { width: auto; }
.key-scopes { display: inline-flex; flex-wrap: wrap; gap: 0.35rem; }

/* ---- Passkeys ------------------------------------------------------------------- */
.passkey-add { margin-top: 1.1rem; }
.passkey-status { min-height: 1.2rem; margin: 0.6rem 0 0; font-size: 0.84rem; color: var(--text-muted); }
.passkey-status.status-error { color: var(--danger); }
.passkey-status.status-ok { color: var(--text-muted); }

/* Inline field note (e.g. live breached-password verdict). */
.field-note { min-height: 1.15rem; margin: -0.4rem 0 0.6rem; font-size: 0.83rem; color: var(--text-muted); }
.field-note.status-error { color: var(--danger); }
.field-note.status-ok { color: var(--ok); }
.auth-divider { display: flex; align-items: center; gap: 0.8rem; margin: 1.3rem 0 1rem; color: var(--text-muted); font-size: 0.8rem; }
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* ---- Legacy shell (kept for any bare partials) --------------------------------- */
.topbar { display: flex; justify-content: space-between; align-items: center; padding: 0.9rem 2rem; background: var(--bg-raised); border-bottom: 1px solid var(--border); }
.container { flex: 1; width: 100%; max-width: 1080px; margin: 0 auto; padding: 2rem; }
.footer { padding: 1rem 2rem; border-top: 1px solid var(--border); color: var(--text-muted); font-size: 0.8rem; text-align: center; }
