/* ==========================================================================
   HostnameLayer — application stylesheet
   --------------------------------------------------------------------------
   One file for the whole app. Every page used to carry its own <style> block
   (~3,500 duplicated lines), which is why they had drifted into three
   different fonts and four different greys.

   Order matters, so keep it:
     1. Tokens        — the only place raw colour/size values are allowed
     2. Reset & base
     3. Typography
     4. Layout        — shell, nav, page header, grid
     5. Components    — card, button, form, table, chip, alert, modal
     6. Utilities
     7. Responsive

   Rules of thumb when extending this:
     - No hard-coded hex outside §1. If you need a new colour, add a token.
     - Space in multiples of 4px via --sp-*, so vertical rhythm holds.
     - Components own their layout; pages compose components. A page should
       almost never need its own CSS.
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
    /* --- Surfaces -------------------------------------------------------
       Four steps only. More than that and "which grey?" becomes a coin
       toss every time someone adds a panel. Each step is a real elevation:
       canvas → card → raised control → input well.                        */
    --canvas:        #0b0c10;
    --surface:       #111318;
    --surface-2:     #171a21;
    --surface-3:     #1e222b;
    --well:          #0e1015;

    /* --- Lines ----------------------------------------------------------
       Borders carry structure on dark; shadows read as muddy smears.       */
    --line:          rgba(255, 255, 255, .07);
    --line-strong:   rgba(255, 255, 255, .13);
    --line-faint:    rgba(255, 255, 255, .04);

    /* --- Text -----------------------------------------------------------
       Three weights of emphasis, measured against --surface.              */
    --ink:           #e6e8ee;   /* 15.2:1 */
    --ink-2:         #9ba1b0;   /*  7.2:1 */
    --ink-3:         #858c9d;   /*  5.5:1 */
    --ink-inverse:   #0b0c10;

    /* --- Brand ----------------------------------------------------------
       The logo's indigo. The only saturated colour in a neutral UI, so it
       always reads as "this is the action".                                */
    --brand:         #6d5dff;
    --brand-hi:      #8b7eff;
    --brand-lo:      #5647e0;
    --brand-wash:    rgba(109, 93, 255, .13);
    --brand-line:    rgba(109, 93, 255, .34);

    /* --- Semantic -------------------------------------------------------
       Reserved for state, never decoration.

       The -text sibling exists because contrast inverts with the theme: on
       white it had to be DARKER than the fill colour, on this canvas it has
       to be LIGHTER. Components reference the token, so the split survives
       a theme flip without touching a single component rule.               */
    --ok:            #34d399;
    --ok-text:       #34d399;   /*  9.7:1 on --surface */
    --ok-wash:       rgba(16, 185, 129, .12);
    --ok-line:       rgba(16, 185, 129, .3);

    --warn:          #fbbf24;
    --warn-text:     #fbbf24;   /* 11.1:1 */
    --warn-wash:     rgba(245, 158, 11, .11);
    --warn-line:     rgba(245, 158, 11, .28);

    --bad:           #fb7185;
    --bad-text:      #fb7185;   /*  6.9:1 */
    --bad-wash:      rgba(244, 63, 94, .11);
    --bad-line:      rgba(244, 63, 94, .28);

    --info:          #a5b4fc;

    /* --- Type -----------------------------------------------------------
       Two families. Syne is the brand voice and is used ONLY for the
       wordmark and page titles. Inter does all the working text. Mono is
       for anything you might compare digit by digit — ids, counts, URLs.  */
    --font-display:  'Syne', 'Inter', system-ui, sans-serif;
    --font-ui:       'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono:     'JetBrains Mono', ui-monospace, 'SF Mono', Consolas, monospace;

    /* Minor-third-ish scale, rounded to whole pixels so text stays crisp. */
    --t-xs:          .75rem;    /* 12 — chips, table headers, meta          */
    --t-sm:          .8125rem;  /* 13 — table body, secondary               */
    --t-base:        .875rem;   /* 14 — the app's default                   */
    --t-md:          1rem;      /* 16 — emphasis, lead paragraphs           */
    --t-lg:          1.25rem;   /* 20 — card titles                         */
    --t-xl:          1.625rem;  /* 26 — page titles                         */
    --t-2xl:         2.25rem;   /* 36 — stat figures                        */

    /* --- Space ----------------------------------------------------------
       4px grid. Every margin/padding in this file uses one of these.      */
    --sp-1:  4px;   --sp-2:  8px;   --sp-3: 12px;  --sp-4: 16px;
    --sp-5: 20px;   --sp-6: 24px;   --sp-8: 32px;  --sp-10: 40px;
    --sp-12: 48px;  --sp-16: 64px;

    /* --- Radius ---------------------------------------------------------- */
    --r-sm:   6px;
    --r:     10px;
    --r-lg:  14px;
    --r-xl:  20px;
    --r-pill: 999px;

    /* --- Motion ---------------------------------------------------------
       Short and unfussy. Anything over 200ms starts to feel like latency. */
    --ease:   cubic-bezier(.4, 0, .2, 1);
    --fast:   .12s var(--ease);
    --base:   .18s var(--ease);

    /* --- Depth ----------------------------------------------------------
       Used sparingly: menus, modals, toasts. Not cards.                   */
    --lift:   0 2px 8px rgba(0, 0, 0, .28);
    --lift-2: 0 16px 40px rgba(0, 0, 0, .5);

    /* --- Layout ---------------------------------------------------------- */
    --shell:  1200px;
    --nav-h:  60px;
}


/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */

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

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

body {
    min-height: 100vh;
    background: var(--canvas);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: var(--t-base);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'cv02', 'cv03', 'cv04';
}

img, svg { display: block; max-width: 100%; }

a { color: var(--brand-hi); text-decoration: none; transition: color var(--fast); }
a:hover { color: var(--ink); }

/* One focus treatment everywhere. Visible, never removed — keyboard users
   are not an edge case. :focus-visible so mouse clicks stay quiet. */
:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

::selection { background: var(--brand-wash); color: var(--ink); }

/* Scrollbars, so long tables don't get a bright OS-default bar. */
* { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: var(--r-pill); border: 2px solid var(--canvas); }
::-webkit-scrollbar-thumb:hover { background: #2a2f3a; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}


/* ==========================================================================
   3. TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4 { font-weight: 700; line-height: 1.25; letter-spacing: -.02em; color: var(--ink); }

.t-title    { font-family: var(--font-display); font-size: var(--t-xl); font-weight: 800; letter-spacing: -.03em; color: var(--ink); }
.t-section  { font-size: var(--t-lg); font-weight: 700; }
.t-lead     { font-size: var(--t-md); color: var(--ink-2); }
.t-body     { font-size: var(--t-base); color: var(--ink-2); }
.t-meta     { font-size: var(--t-xs); color: var(--ink-3); }

/* Small caps label — section headers, table headers, stat captions. */
.t-label {
    font-size: var(--t-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ink-3);
}

/* Any figure a human might compare against another figure. */
.t-num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum';
}

.mono { font-family: var(--font-mono); font-size: .9em; font-variant-numeric: tabular-nums; }

.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* ==========================================================================
   4. LAYOUT
   ========================================================================== */

.shell { max-width: var(--shell); margin: 0 auto; padding: var(--sp-8) var(--sp-6) var(--sp-16); }

/* --- Top navigation ---------------------------------------------------- */

/* The bar is full-bleed; its contents sit in the same --shell column as the
   page, so the logo aligns with the page title and the account control with
   the page actions. */
.nav {
    position: sticky; top: 0; z-index: 60;
    height: var(--nav-h);
    background: rgba(11, 12, 16, .78);
    backdrop-filter: saturate(170%) blur(16px);
    border-bottom: 1px solid var(--line);
    /* A glass edge rather than a drop shadow: one hairline of light along the
       top of the bar, which is what a real translucent surface does. */
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .045);
    transition: border-color var(--base), background var(--base);
}

/* Depth appears only when there is something underneath to separate from. A
   permanent shadow under a sticky bar is a shadow cast by nothing. */
.nav.is-scrolled {
    background: rgba(11, 12, 16, .9);
    border-bottom-color: var(--line-strong);
}

.nav-inner {
    max-width: var(--shell);
    height: 100%;
    margin: 0 auto;
    padding: 0 var(--sp-6);   /* must match .shell, or the logo and the page
                                 title sit on different left edges */
    display: flex; align-items: center; gap: var(--sp-2);
}

/* Divides identity from navigation. Two groups that mean different things
   should not read as one undifferentiated row of links. */
.nav-sep {
    width: 1px; height: 20px;
    background: var(--line-strong);
    margin: 0 var(--sp-3) 0 var(--sp-4);
    flex-shrink: 0;
}

/* Takes the slack, which puts the account control on the right edge and the
   whitespace between the nav and the account — after the content, where it
   reads as room to breathe rather than a gap between two clumps. */
.nav-end { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); }

/* --- Logo — unchanged from the original mark ---------------------------
   Layers glyph in the brand gradient, "Hostname" + muted "Layer" wordmark
   in Syne. Identical on every page including the login screen.           */
.brand { display: flex; align-items: center; gap: var(--sp-3); flex-shrink: 0; }

/* Prominence from finish, not size. The mark stays 32px; a light edge along
   its top and a brand glow that only appears on hover give it the presence of
   a pressed object instead of a flat coloured square. */
.brand-mark {
    width: 32px; height: 32px;
    border-radius: 9px;
    background: linear-gradient(135deg, var(--brand) 0%, #a78bfa 55%, #22d3ee 100%);
    display: grid; place-items: center;
    color: #fff; font-size: 15px;
    flex-shrink: 0;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3),
                0 1px 2px rgba(0, 0, 0, .4);
    transition: box-shadow var(--base), transform var(--base);
}
.brand:hover .brand-mark {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35),
                0 2px 10px -2px rgba(109, 93, 255, .55);
    transform: translateY(-1px);
}
.brand:hover .brand-word span { color: var(--ink-2); }
.brand-word span { transition: color var(--fast); }
.brand-mark.lg { width: 46px; height: 46px; border-radius: 13px; font-size: 21px; }

.brand-word {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.0625rem;
    letter-spacing: -.03em;
    color: var(--ink);
    line-height: 1;
    white-space: nowrap;
}
.brand-word span { color: var(--ink-3); }
.brand-word.lg { font-size: 1.375rem; }

.brand-tag {
    font-size: .6875rem;
    color: var(--ink-3);
    letter-spacing: .07em;
    text-transform: uppercase;
    margin-top: 4px;
}

/* --- Nav links --------------------------------------------------------- */

.nav-links { display: flex; align-items: center; gap: 1px; height: 100%; }

/* Full-height tabs. The hover fill is inset so it stays a pill inside the bar
   rather than a floor-to-ceiling block, and the current page is marked by a
   rule seated on the bar's bottom edge. */
.nav-link {
    position: relative;
    display: flex; align-items: center; gap: var(--sp-2);
    height: 100%; padding: 0 var(--sp-3);
    border-radius: 0;
    color: var(--ink-2);
    font-size: var(--t-sm); font-weight: 500;
    white-space: nowrap;
    transition: color var(--fast);
}
.nav-link::before {
    content: '';
    position: absolute; inset: 13px 2px;
    border-radius: var(--r-sm);
    background: transparent;
    transition: background var(--fast);
}
.nav-link > * { position: relative; z-index: 1; }
.nav-link:hover { color: var(--ink); }
.nav-link:hover::before { background: var(--surface-2); }
.nav-link:focus-visible { outline: none; }
.nav-link:focus-visible::before { outline: 2px solid var(--brand); outline-offset: 0; }
.nav-link i { font-size: 15px; color: var(--ink-3); transition: color var(--fast); }
.nav-link:hover i { color: var(--ink-2); }

/* "You are here", not "this is a button". The old filled lozenge read as the
   one thing on the bar you were meant to press. Colour is spent on a 2px rule
   and the icon; the label simply goes to full strength. */
.nav-link[aria-current="page"] { color: var(--ink); font-weight: 600; }
.nav-link[aria-current="page"] i { color: var(--brand-hi); }
.nav-link[aria-current="page"]::after {
    content: '';
    position: absolute; left: 6px; right: 6px; bottom: -1px; height: 2px;
    background: linear-gradient(90deg, var(--brand), var(--brand-hi));
    border-radius: 2px 2px 0 0;
}

.nav-badge {
    min-width: 17px; height: 17px; padding: 0 5px;
    display: inline-grid; place-items: center;
    border-radius: var(--r-pill);
    background: var(--brand); color: #fff;
    font-size: .625rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* --- User menu --------------------------------------------------------- */

.usermenu { position: relative; }

/* A bordered control, not a link. The account area governs a different scope
   from the nav beside it — signing out is not the same kind of act as
   changing page — so it is drawn as a container you open rather than an item
   you follow. */
.usermenu-btn {
    display: flex; align-items: center; gap: var(--sp-2);
    height: 34px; padding: 0 var(--sp-2) 0 3px;
    background: var(--surface-2);
    border: 1px solid var(--line); border-radius: var(--r-pill);
    color: var(--ink-2); font-family: inherit; font-size: var(--t-sm); font-weight: 500;
    cursor: pointer;
    transition: background var(--fast), border-color var(--fast), color var(--fast);
}
.usermenu-btn .avatar { width: 26px; height: 26px; border-radius: 50%; }
.usermenu-btn > i { color: var(--ink-3); transition: transform var(--base); }
.usermenu-btn:hover { background: var(--surface-3); border-color: var(--line-strong); color: var(--ink); }
.usermenu-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.usermenu.open .usermenu-btn { background: var(--surface-3); border-color: var(--line-strong); color: var(--ink); }
.usermenu.open .usermenu-btn > i { transform: rotate(180deg); }

.avatar {
    width: 26px; height: 26px;
    border-radius: var(--r-sm);
    background: linear-gradient(135deg, var(--brand), #a78bfa);
    display: grid; place-items: center;
    color: #fff; font-size: .75rem; font-weight: 700;
    flex-shrink: 0;
}

.usermenu-panel {
    position: absolute; top: calc(100% + 6px); right: 0;
    min-width: 232px;
    background: var(--surface-2);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    box-shadow: var(--lift-2);
    padding: var(--sp-1);
    opacity: 0; visibility: hidden; transform: translateY(-6px);
    transition: opacity var(--base), transform var(--base), visibility var(--base);
}
.usermenu.open .usermenu-panel { opacity: 1; visibility: visible; transform: translateY(0); }

.usermenu-head { padding: var(--sp-3) var(--sp-3) var(--sp-2); border-bottom: 1px solid var(--line); margin-bottom: var(--sp-1); }
.usermenu-mail { font-size: var(--t-xs); color: var(--ink-3); margin-top: 2px; word-break: break-all; }

.usermenu-item {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-sm);
    color: var(--ink-2); font-size: var(--t-sm);
    transition: background var(--fast), color var(--fast);
}
.usermenu-item:hover { background: var(--surface-3); color: var(--ink); }
.usermenu-item.danger { color: var(--bad-text); }
.usermenu-item.danger:hover { background: var(--bad-wash); color: var(--bad); }
.usermenu-sep { height: 1px; background: var(--line); margin: var(--sp-1) 0; }

/* --- Page header ------------------------------------------------------- */

.page-head {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: var(--sp-4); flex-wrap: wrap;
    margin-bottom: var(--sp-6);
}
.page-head p { color: var(--ink-2); font-size: var(--t-sm); margin-top: var(--sp-1); }

/* --- Grids ------------------------------------------------------------- */

.grid { display: grid; gap: var(--sp-4); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.stack   { display: flex; flex-direction: column; gap: var(--sp-4); }
.row     { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.row-end { display: flex; align-items: center; gap: var(--sp-2); justify-content: flex-end; flex-wrap: wrap; }

/* --- Centred single-card pages (login, reset, OTP) --------------------- */

.auth-shell {
    min-height: 100vh;
    display: grid; place-items: center;
    padding: var(--sp-6) var(--sp-4);
    position: relative;
    overflow: hidden;
}

/* One soft brand wash behind the card. Restraint: a single light source,
   not the four competing glows the old pages had. */
.auth-shell::before {
    content: '';
    position: absolute; inset: -30% 0 auto -20%;
    width: 640px; height: 640px;
    background: radial-gradient(circle, rgba(109, 93, 255, .12) 0%, transparent 68%);
    filter: blur(30px);
    pointer-events: none;
}

.auth-card {
    position: relative;
    width: 100%; max-width: 420px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    padding: var(--sp-8);
    overflow: hidden;
    /* A real lift: on a near-white canvas a hairline alone leaves the card
       looking painted on rather than placed. */
    box-shadow: var(--lift-2);
}
.auth-card::before {
    content: '';
    position: absolute; inset: 0 0 auto 0; height: 3px;
    background: linear-gradient(90deg, var(--brand), #8b7eff 60%, #22d3ee);
}
.auth-card .brand { margin-bottom: var(--sp-6); }
.auth-foot {
    margin-top: var(--sp-6); padding-top: var(--sp-5);
    border-top: 1px solid var(--line);
    text-align: center; font-size: var(--t-sm); color: var(--ink-3);
}


/* ==========================================================================
   5. COMPONENTS
   ========================================================================== */

/* --- Card -------------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--lift);
    overflow: hidden;
}
.card-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-4); flex-wrap: wrap;
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--line);
}
.card-title { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--t-base); font-weight: 650; color: var(--ink); }
.card-title i { color: var(--ink-3); font-size: 15px; }
.card-body { padding: var(--sp-5); }
.card-foot { padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--line); background: var(--well); }

/* --- Buttons -----------------------------------------------------------
   One .btn base, modifiers for intent and size. Height is fixed so a row
   of mixed buttons always lines up. */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
    height: 38px; padding: 0 var(--sp-4);
    border: 1px solid transparent; border-radius: var(--r);
    background: var(--surface-2); color: var(--ink);
    font-family: inherit; font-size: var(--t-sm); font-weight: 600;
    line-height: 1; white-space: nowrap; cursor: pointer;
    transition: background var(--fast), border-color var(--fast), color var(--fast), opacity var(--fast);
}
.btn i { font-size: 15px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn-primary { background: var(--brand); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--brand-hi); color: #fff; }
.btn-primary:active:not(:disabled) { background: var(--brand-lo); }

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

.btn-ghost { background: transparent; color: var(--ink-2); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }

.btn-danger { background: transparent; border-color: var(--bad-line); color: var(--bad-text); }
.btn-danger:hover:not(:disabled) { background: var(--bad-wash); }

.btn-sm { height: 30px; padding: 0 var(--sp-3); font-size: var(--t-xs); border-radius: var(--r-sm); }
.btn-sm i { font-size: 13px; }
.btn-block { width: 100%; }
.btn-lg { height: 44px; padding: 0 var(--sp-5); font-size: var(--t-base); }

/* --- Forms ------------------------------------------------------------- */

.field { margin-bottom: var(--sp-4); }
.field:last-child { margin-bottom: 0; }

.label {
    display: block;
    font-size: var(--t-sm); font-weight: 550; color: var(--ink-2);
    margin-bottom: var(--sp-2);
}

.input, .select, .textarea {
    width: 100%;
    background: var(--well);
    border: 1px solid var(--line);
    border-radius: var(--r);
    color: var(--ink);
    font-family: inherit; font-size: var(--t-base);
    padding: 0 var(--sp-3);
    height: 40px;
    outline: none;
    transition: border-color var(--fast), background var(--fast), box-shadow var(--fast);
}
.textarea { height: auto; min-height: 150px; max-height: 300px; padding: var(--sp-3); resize: vertical; line-height: 1.6; }
.textarea.mono-input { font-family: var(--font-mono); font-size: var(--t-sm); }

.input::placeholder, .textarea::placeholder { color: var(--ink-3); }

.input:focus, .select:focus, .textarea:focus {
    border-color: var(--brand-line);
    background: var(--surface-2);
    box-shadow: 0 0 0 3px var(--brand-wash);
}
.input:disabled { opacity: .55; cursor: not-allowed; }

/* Leading icon inside a field. */
.input-wrap { position: relative; }
.input-wrap .input-icon {
    position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%);
    color: var(--ink-3); font-size: 15px; pointer-events: none;
    transition: color var(--fast);
}
.input-wrap:focus-within .input-icon { color: var(--brand-hi); }
.input-wrap .input { padding-left: 38px; }

.input-wrap .input-action {
    position: absolute; right: var(--sp-2); top: 50%; transform: translateY(-50%);
    background: none; border: none; color: var(--ink-3);
    cursor: pointer; padding: var(--sp-1); font-size: 15px; line-height: 1;
    transition: color var(--fast);
}
.input-wrap .input-action:hover { color: var(--ink); }
.input-wrap .input.has-action { padding-right: 40px; }

.hint { font-size: var(--t-xs); color: var(--ink-3); margin-top: var(--sp-2); }
.hint.bad { color: var(--bad); }

/* --- File picker --------------------------------------------------------
   The native control renders its own "No file chosen" text that can't be
   styled and can't be removed, so the real input is taken out of the visual
   flow and a label is styled in its place. The input stays focusable, and
   :focus-within paints the focus ring on the label — keyboard users get the
   same affordance as mouse users. */
.filepick { position: relative; display: flex; align-items: center; gap: var(--sp-2); }

.filepick-input {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    pointer-events: none;
}

.filepick-label {
    flex: 0 1 auto;
    display: inline-flex; align-items: center; gap: var(--sp-2);
    min-height: 34px;
    padding: 0 var(--sp-3);
    border: 1px dashed var(--line-strong);
    border-radius: var(--r);
    background: var(--well);
    cursor: pointer;
    transition: border-color var(--fast), background var(--fast), box-shadow var(--fast);
}
.filepick-label:hover { border-color: var(--brand-line); background: var(--surface-2); }

.filepick-input:focus-visible + .filepick-label {
    border-color: var(--brand-line);
    box-shadow: 0 0 0 3px var(--brand-wash);
}

.filepick-icon {
    width: 20px; height: 20px;
    display: grid; place-items: center;
    border-radius: 4px;
    background: transparent;
    color: var(--ink-2);
    font-size: 13px;
    flex-shrink: 0;
    transition: background var(--fast), color var(--fast);
}

.filepick-text { min-width: 0; }
.filepick-main {
    display: inline; font-size: var(--t-sm); font-weight: 550; color: var(--ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.filepick-sub { display: inline; font-size: var(--t-xs); color: var(--ink-3); margin-left: 6px; }

/* Filled state — solid border and a green mark, so "a file is attached" is
   obvious at a glance rather than needing to be read. */
.filepick.has-file .filepick-label { border-style: solid; border-color: var(--ok-line); background: var(--ok-wash); }
.filepick.has-file .filepick-icon  { background: var(--ok); color: #04231a; }
.filepick.has-file .filepick-main  { color: var(--ok); }

.filepick-clear {
    display: none;
    align-items: center; justify-content: center;
    width: 30px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--surface-2);
    color: var(--ink-3);
    cursor: pointer;
    transition: color var(--fast), border-color var(--fast);
}
.filepick.has-file .filepick-clear { display: flex; }
.filepick-clear:hover { color: var(--bad); border-color: var(--bad-line); }

/* Short facts about a control, as a wrapping list rather than a paragraph.
   Four scannable items beat one sentence nobody finishes reading. */
.hint-facts {
    display: flex; flex-wrap: wrap;
    gap: var(--sp-2) var(--sp-4);
    list-style: none;
    margin-top: var(--sp-3);
    padding: 0;
}
.hint-facts li {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--t-xs);
    color: var(--ink-3);
    white-space: nowrap;
}
.hint-facts i { font-size: 12px; opacity: .8; }

/* Checkbox / radio */
.check { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; font-size: var(--t-sm); color: var(--ink-2); user-select: none; }
.check input { width: 15px; height: 15px; accent-color: var(--brand); cursor: pointer; }

/* Segmented control — replaces the old sliding pill switch. Honest about
   being a radio group, and it scales past two options. */
.segment {
    display: inline-flex;
    background: var(--well);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 3px;
    gap: 2px;
}
.segment input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.segment label {
    display: flex; align-items: center; gap: var(--sp-2);
    height: 26px; padding: 0 var(--sp-3);
    border-radius: var(--r-sm);
    font-size: var(--t-sm); font-weight: 550; color: var(--ink-2);
    cursor: pointer; white-space: nowrap;
    transition: background var(--fast), color var(--fast);
}
.segment label:hover { color: var(--ink); }
.segment input:checked + label { background: var(--brand); color: #fff; }
.segment input:focus-visible + label { outline: 2px solid var(--brand); outline-offset: 2px; }

/* --- Table -------------------------------------------------------------
   Dense by intent: this app is for scanning long submission histories, so
   rows are 13px/compact and numbers are tabular. */
.table-scroll { overflow-x: auto; }

.table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }

.table thead th {
    /* top MUST stay 0.
       The parent .table-scroll sets overflow-x, which makes it the sticky
       containing block instead of the viewport. Any positive `top` therefore
       offsets the header downward *inside the table* and covers the first
       row, rather than clearing the nav. An earlier attempt to dodge the nav
       with top:var(--nav-h) did exactly that and hid row 1.
       The header is not viewport-sticky as a result — that would need the
       scroll container removed, which would cost horizontal scrolling on
       wide tables. Not worth the trade. */
    position: sticky; top: 0; z-index: 1;
    background: var(--surface);
    text-align: left;
    padding: 10px var(--sp-4);
    font-size: .6875rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: .06em;
    color: var(--ink-3);
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
.table tbody td {
    padding: 11px var(--sp-4);
    border-bottom: 1px solid var(--line-faint);
    vertical-align: middle;
    color: var(--ink-2);
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background var(--fast); }
.table tbody tr:hover { background: var(--surface-2); }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table td.mid, .table th.mid { text-align: center; }
.table .strong { color: var(--ink); font-weight: 600; }

/* --- Responsive tables -------------------------------------------------
   Below 860px a wide data table stops being a table and becomes a stack of
   labelled rows. Horizontal scrolling on a phone means the columns on the
   right are effectively invisible — people don't discover them.

   Each <td> needs data-label="Column name" for the label to appear. Tables
   without it still stack, just without the left-hand caption. */
@media (max-width: 860px) {
    .table.stackable thead { display: none; }

    .table.stackable,
    .table.stackable tbody,
    .table.stackable tr,
    .table.stackable td { display: block; width: 100%; }

    .table.stackable tr {
        border: 1px solid var(--line);
        border-radius: var(--r);
        margin-bottom: var(--sp-3);
        padding: var(--sp-2) var(--sp-3);
        background: var(--surface);
    }
    .table.stackable tr:hover { background: var(--surface); }

    .table.stackable td {
        border: 0;
        padding: var(--sp-2) 0;
        display: flex;
        gap: var(--sp-4);
        align-items: flex-start;
        justify-content: space-between;
        text-align: right;
    }
    .table.stackable td + td { border-top: 1px solid var(--line-faint); }

    /* The column name, carried over from the hidden header. */
    .table.stackable td::before {
        content: attr(data-label);
        flex: 0 0 34%;
        text-align: left;
        font-size: var(--t-xs);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: .06em;
        color: var(--ink-3);
        padding-top: 2px;
    }
    /* Cells with no label give their content the full width. */
    .table.stackable td:not([data-label])::before { content: none; }
    .table.stackable td.cell-wide { display: block; text-align: left; }
    .table.stackable td.cell-wide::before { display: block; margin-bottom: var(--sp-2); }

    /* Fixed pixel truncation is meaningless once stacked — let it wrap. */
    .table.stackable .truncate {
        max-width: none !important;
        white-space: normal;
        overflow-wrap: anywhere;
    }
    .table.stackable td > .row { justify-content: flex-end; }
    .table.stackable td.cell-wide > .row { justify-content: flex-start; }
}

/* --- URL cell actions --------------------------------------------------
   site: and inurl: were ghost buttons — effectively invisible against the
   row until hovered, which is no use for something you're meant to notice
   and click. They now read as outlined, labelled controls. */
.url-actions { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-top: 5px; }

.url-action {
    display: inline-flex; align-items: center; gap: 4px;
    height: auto; padding: 0;
    border: 0; background: none;
    color: var(--ink-2);
    font-family: inherit; font-size: var(--t-xs); font-weight: 500;
    line-height: 1; white-space: nowrap; cursor: pointer;
    transition: color var(--fast);
}
.url-action:hover { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.url-action i { font-size: 11px; opacity: .7; }
.url-action .op { font-family: var(--font-mono); color: var(--ink-3); }

/* --- Chips / badges ---------------------------------------------------- */

.chip {
    display: inline-flex; align-items: center; gap: 5px;
    height: 20px; padding: 0 7px;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    background: var(--surface-2);
    color: var(--ink-2);
    font-size: .6875rem; font-weight: 600;
    white-space: nowrap;
}
.chip i { font-size: 11px; }
.chip-brand { background: var(--brand-wash); border-color: var(--brand-line); color: var(--info); }
.chip-ok    { background: var(--ok-wash);    border-color: var(--ok-line);    color: var(--ok-text); }
.chip-warn  { background: var(--warn-wash);  border-color: var(--warn-line);  color: var(--warn-text); }
.chip-bad   { background: var(--bad-wash);   border-color: var(--bad-line);   color: var(--bad-text); }

/* Status dot for table rows — cheaper visual weight than a full chip. */
.dot { width: 6px; height: 6px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.dot-ok { background: var(--ok); } .dot-bad { background: var(--bad); }
.dot-warn { background: var(--warn); } .dot-idle { background: var(--ink-3); }

/* --- Inline row state --------------------------------------------------
   The submissions table carries three status columns. As filled pills that
   was thirty coloured boxes on a ten-row screen, all shouting equally, so
   none of them read. Inline, a state is a dot and a word: the dot always
   carries the fact, but only warnings and failures take colour in the text.
   The ordinary case — sent, reachable — stays quiet, which is the point:
   nothing is worth noticing about a row that worked.

   Tone classes come from stateClass() in includes/urlcheck.php. */
.st {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--t-xs); font-weight: 550;
    color: var(--ink-2); white-space: nowrap;
}
.st .dot { width: 7px; height: 7px; background: var(--ok); }

.st-warn { color: var(--warn-text); }  .st-warn  .dot { background: var(--warn); }
.st-bad  { color: var(--bad-text);  }  .st-bad   .dot { background: var(--bad); }
.st-brand{ color: var(--info);      }  .st-brand .dot { background: var(--brand); }
.st-idle { color: var(--ink-3);     }  .st-idle  .dot { background: var(--ink-3); opacity: .55; }

/* Where the state is also the way into the stored evidence. */
button.st {
    border: 0; background: none; padding: 0;
    font-family: inherit; cursor: pointer;
}
button.st:hover { text-decoration: underline; text-underline-offset: 3px; }
button.st:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: var(--r-sm); }

/* --- Alerts ------------------------------------------------------------ */

.alert {
    display: flex; align-items: flex-start; gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--surface-2);
    font-size: var(--t-sm);
    margin-bottom: var(--sp-4);
}
.alert i { font-size: 16px; flex-shrink: 0; margin-top: 1px; }
.alert-body { flex: 1; min-width: 0; }
.alert-title { font-weight: 650; color: var(--ink); }
.alert-title + div { color: var(--ink-2); margin-top: 2px; }
.alert-close {
    background: none; border: none; color: var(--ink-3);
    cursor: pointer; padding: 2px; font-size: 15px; line-height: 1;
    transition: color var(--fast);
}
.alert-close:hover { color: var(--ink); }

.alert-ok   { background: var(--ok-wash);   border-color: var(--ok-line); }
.alert-ok i, .alert-ok .alert-title { color: var(--ok-text); }
.alert-warn { background: var(--warn-wash); border-color: var(--warn-line); }
.alert-warn i, .alert-warn .alert-title { color: var(--warn-text); }
.alert-bad  { background: var(--bad-wash);  border-color: var(--bad-line); }
.alert-bad i, .alert-bad .alert-title { color: var(--bad-text); }

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

.meter { height: 4px; background: var(--surface-3); border-radius: var(--r-pill); overflow: hidden; }
.meter > span { display: block; height: 100%; background: linear-gradient(90deg, var(--brand), #a78bfa); border-radius: var(--r-pill); }

/* --- Empty state ------------------------------------------------------- */

.empty { padding: var(--sp-16) var(--sp-6); text-align: center; color: var(--ink-3); }
.empty i { font-size: 30px; opacity: .4; display: block; margin-bottom: var(--sp-4); }
.empty-title { color: var(--ink-2); font-weight: 600; margin-bottom: var(--sp-1); }

/* --- Toast ------------------------------------------------------------- */

.toast {
    position: fixed; bottom: var(--sp-6); left: 50%;
    transform: translate(-50%, 12px);
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-5);
    background: var(--surface-3);
    border: 1px solid var(--line-strong);
    border-radius: var(--r);
    box-shadow: var(--lift-2);
    font-size: var(--t-sm); color: var(--ink);
    opacity: 0; visibility: hidden; z-index: 200;
    transition: opacity var(--base), transform var(--base), visibility var(--base);
}
.toast.show { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
.toast i { color: var(--ok-text); }

/* --- Pagination -------------------------------------------------------- */

.pager { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.pager-links { display: flex; gap: var(--sp-1); }
.pager-links a, .pager-links span {
    min-width: 32px; height: 32px; padding: 0 var(--sp-2);
    display: inline-grid; place-items: center;
    border-radius: var(--r-sm); border: 1px solid var(--line);
    font-size: var(--t-sm); color: var(--ink-2);
    font-variant-numeric: tabular-nums;
    transition: border-color var(--fast), color var(--fast), background var(--fast);
}
.pager-links a:hover { border-color: var(--line-strong); color: var(--ink); }
.pager-links .on { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600; }
.pager-links .gap { border-color: transparent; color: var(--ink-3); }

/* ==========================================================================
   KPI STRIP — figures first, no card chrome per number
   ========================================================================== */

.kpis {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--lift);
    overflow: hidden;
}
.kpi { padding: var(--sp-4) var(--sp-5); border-left: 1px solid var(--line); }
.kpi:first-child { border-left: 0; }
.kpi-label {
    font-size: .6875rem; font-weight: 600; color: var(--ink-3);
    text-transform: uppercase; letter-spacing: .06em;
}
.kpi-value {
    font-size: 1.625rem; font-weight: 600; color: var(--ink);
    letter-spacing: -.025em; line-height: 1.15; margin-top: 5px;
    font-variant-numeric: tabular-nums; font-feature-settings: 'tnum';
}
.kpi.is-ok   .kpi-value { color: var(--ok-text); }
.kpi.is-warn .kpi-value { color: var(--warn-text); }
.kpi.is-bad  .kpi-value { color: var(--bad-text); }
.kpi.is-zero .kpi-value { color: var(--ink-3) !important; }
.kpi-sub { font-size: var(--t-xs); color: var(--ink-3); margin-top: 2px; }

/* A five-across strip needs tighter gutters than four. */
@media (max-width: 1100px) {
    .kpis { grid-template-columns: repeat(2, 1fr) !important; }
}

/* --- Divider ----------------------------------------------------------- */
.rule { height: 1px; background: var(--line); border: 0; margin: var(--sp-5) 0; }

/* --- Entity card -------------------------------------------------------
   For lists of *few, rich* things — user accounts, integrations — where a
   dense table wastes the room each row actually needs. Tables stay the right
   answer for the submission log; this is the right answer for seven users. */
.ecard {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
    transition: border-color var(--fast);
}
.ecard:hover { border-color: var(--line-strong); }
.ecard.is-off { opacity: .62; }

.ecard-top {
    display: flex; align-items: flex-start; gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
}
.ecard-id { flex: 1; min-width: 0; }
.ecard-name {
    font-size: var(--t-md); font-weight: 650; color: var(--ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ecard-chips { display: flex; gap: 5px; flex-wrap: wrap; margin-top: var(--sp-2); }

/* Metrics strip — a quiet band between identity and actions, so the numbers
   read as supporting detail rather than competing with the name. */
.ecard-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-5);
    background: var(--well);
    border-top: 1px solid var(--line-faint);
    border-bottom: 1px solid var(--line-faint);
}
.metric-label {
    font-size: .6875rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: .07em;
    color: var(--ink-3); margin-bottom: 3px;
}
.metric-value {
    font-size: var(--t-md); font-weight: 650; color: var(--ink);
    font-variant-numeric: tabular-nums; line-height: 1.2;
}
.metric-sub { font-size: var(--t-xs); color: var(--ink-3); margin-top: 2px; }

.ecard-actions {
    display: flex; gap: var(--sp-2); flex-wrap: wrap;
    padding: var(--sp-4) var(--sp-5);
}

/* --- Modal --------------------------------------------------------------
   Destructive and credential actions get a real dialog rather than an input
   wedged into a table row. */
.modal {
    position: fixed; inset: 0; z-index: 300;
    display: grid; place-items: center;
    padding: var(--sp-5);
    background: rgba(4, 5, 8, .72);
    backdrop-filter: blur(3px);
    opacity: 0; visibility: hidden;
    transition: opacity var(--base), visibility var(--base);
}
.modal.open { opacity: 1; visibility: visible; }

.modal-panel {
    width: 100%; max-width: 420px;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-lg);
    box-shadow: var(--lift-2);
    transform: translateY(10px) scale(.99);
    transition: transform var(--base);
}
.modal.open .modal-panel { transform: none; }

.modal-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-5) var(--sp-3);
}
.modal-title { font-size: var(--t-md); font-weight: 650; color: var(--ink); }
.modal-body { padding: 0 var(--sp-5) var(--sp-5); }
.modal-foot {
    display: flex; justify-content: flex-end; gap: var(--sp-2);
    padding: var(--sp-4) var(--sp-5);
    border-top: 1px solid var(--line);
    background: var(--well);
}


/* ==========================================================================
   6. UTILITIES
   ========================================================================== */

.mt-0 { margin-top: 0 } .mt-2 { margin-top: var(--sp-2) } .mt-4 { margin-top: var(--sp-4) }
.mt-6 { margin-top: var(--sp-6) } .mt-8 { margin-top: var(--sp-8) }
.mb-0 { margin-bottom: 0 } .mb-2 { margin-bottom: var(--sp-2) } .mb-4 { margin-bottom: var(--sp-4) }
.mb-6 { margin-bottom: var(--sp-6) } .mb-8 { margin-bottom: var(--sp-8) }

.muted  { color: var(--ink-2) } .faint { color: var(--ink-3) }
.ok { color: var(--ok-text) } .bad { color: var(--bad-text) } .warn { color: var(--warn-text) }
.right { text-align: right } .center { text-align: center }
.nowrap { white-space: nowrap }
.grow { flex: 1; min-width: 0 }
.hidden { display: none !important }

/* Screen-reader-only: real text for assistive tech, invisible on screen. */
.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

@keyframes spin { to { transform: rotate(360deg); } }
.spin { animation: spin .7s linear infinite; }

@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.rise { animation: rise .3s var(--ease) both; }



/* ==========================================================================
   7. RESPONSIVE
   ========================================================================== */

@media (max-width: 900px) {
    .shell { padding: var(--sp-6) var(--sp-4) var(--sp-12); }
    .nav-inner { padding: 0 var(--sp-4); }
    .nav-link span { display: none; }
    .nav-link { padding: 0 var(--sp-2); }
}

@media (max-width: 820px) {
    .kpis { grid-template-columns: repeat(2, 1fr); }
    .kpi { border-top: 1px solid var(--line); }
    .kpi:nth-child(-n+2) { border-top: 0; }
    .kpi:nth-child(3) { border-left: 0; }
}

@media (max-width: 640px) {
    :root { --t-xl: 1.375rem; --t-2xl: 1.75rem; }
    .shell { padding: var(--sp-5) var(--sp-3) var(--sp-12); }
    .nav-inner { padding: 0 var(--sp-3); }
    .usermenu-btn span { display: none; }
    .card-head { padding: var(--sp-4); }
    .card-body { padding: var(--sp-4); }
    .auth-card { padding: var(--sp-6); }
    .table thead th, .table tbody td { padding: var(--sp-3) var(--sp-3); }
}

@media (max-width: 420px) {
}

@media print {
    .nav, .btn, .pager, .toast { display: none !important; }
    body { background: #fff; color: #000; }
    .card, .stat { border-color: #ddd; background: #fff; }
}

/* --- Link Checker result cards -----------------------------------------
   The verdict chip leads each card; the numeric scores sit below it and are
   deliberately smaller. A grade invites arguing with the algorithm, a
   verdict invites fixing the page. */
.lc-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: var(--sp-5);
}
.lc-card.lc-pending { opacity: .55; }

.lc-head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: var(--sp-4); flex-wrap: wrap;
}
.lc-id { min-width: 0; flex: 1; }
.lc-url {
    display: block;
    font-size: var(--t-base); font-weight: 650; color: var(--ink);
    overflow-wrap: anywhere;
}
a.lc-url:hover { color: var(--brand-hi); }

.lc-blockers { margin-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
.lc-blocker {
    display: flex; align-items: flex-start; gap: var(--sp-2);
    padding: var(--sp-3);
    border: 1px solid var(--bad-line);
    background: var(--bad-wash);
    border-radius: var(--r);
    color: var(--bad);
    font-size: var(--t-sm); font-weight: 600;
}

.lc-more { margin-top: var(--sp-4); }
.lc-more > summary {
    cursor: pointer;
    font-size: var(--t-sm);
    color: var(--ink-2);
    padding: var(--sp-2) 0;
    list-style: none;
}
.lc-more > summary::-webkit-details-marker { display: none; }
.lc-more > summary::before {
    content: '▸';
    display: inline-block;
    margin-right: var(--sp-2);
    color: var(--ink-3);
    transition: transform var(--fast);
}
.lc-more[open] > summary::before { transform: rotate(90deg); }
.lc-more > summary:hover { color: var(--ink); }
.lc-more > summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--r-sm); }

.lc-detail {
    margin-top: var(--sp-3);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--line);
}

@media (max-width: 900px) {
    .lc-head { flex-direction: column; gap: var(--sp-3); }
}
