/* ==========================================================================
   CallGuard — design system
   One file, no build step. Tokens first, then primitives, then screens.
   ========================================================================== */

@font-face {
    font-family: 'Inter';
    src: url('fonts/InterVariable.woff2') format('woff2');
    font-weight: 100 900;
    font-display: swap;
}

:root {
    --bg:            #070a12;
    --bg-2:          #0b0f1a;
    --surface:       rgba(255, 255, 255, 0.035);
    --surface-2:     rgba(255, 255, 255, 0.06);
    --surface-3:     rgba(255, 255, 255, 0.09);
    --line:          rgba(255, 255, 255, 0.08);
    --line-strong:   rgba(255, 255, 255, 0.16);

    --text:          #e7ebf3;
    --muted:         #8c95a8;
    --faint:         #5b6375;

    --accent:        #22d3a5;
    --accent-deep:   #0fb48a;
    --accent-soft:   rgba(34, 211, 165, 0.14);
    --accent-2:      #7c8cf8;
    --accent-2-soft: rgba(124, 140, 248, 0.14);

    --good:  #34d399;
    --warn:  #fbbf24;
    --bad:   #fb7185;
    --info:  #60a5fa;

    --good-soft: rgba(52, 211, 153, 0.14);
    --warn-soft: rgba(251, 191, 36, 0.14);
    --bad-soft:  rgba(251, 113, 133, 0.14);
    --info-soft: rgba(96, 165, 250, 0.14);

    --radius:    10px;
    --radius-sm: 7px;
    --shadow:    0 24px 60px -20px rgba(0, 0, 0, 0.6);
    --shadow-sm: 0 10px 30px -14px rgba(0, 0, 0, 0.55);

    --sidebar-w: 216px;
    --ease: cubic-bezier(0.22, 1, 0.36, 1);
    --input-fill: #0e111a;   /* opaque stand-in for the input background, for autofill */
}

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

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

body {
    margin: 0;
    min-height: 100vh;
    background: var(--bg);
    color: var(--text);
    font: 13px/1.5 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-feature-settings: 'cv11', 'ss01', 'ss03';
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* Ambient background: two soft glows and a faint grid. Fixed, so it stays
   put while content scrolls. */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -2;
    background:
        radial-gradient(900px 600px at 8% -10%, rgba(34, 211, 165, 0.13), transparent 60%),
        radial-gradient(800px 600px at 100% 110%, rgba(124, 140, 248, 0.12), transparent 60%),
        var(--bg);
}

body::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
    background-size: 32px 32px;
    mask-image: radial-gradient(ellipse at 50% 0%, black 20%, transparent 75%);
    -webkit-mask-image: radial-gradient(ellipse at 50% 0%, black 20%, transparent 75%);
}

a { color: var(--info); text-decoration: none; }
a:hover { text-decoration: underline; }

.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;
}

.num { font-variant-numeric: tabular-nums; }
.mono {
    font-family: ui-monospace, 'JetBrains Mono', SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
}

/* ==========================================================================
   Primitives
   ========================================================================== */

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

.btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 11px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--line);
    background: var(--surface-2);
    color: var(--text);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    transition: background .18s var(--ease), border-color .18s var(--ease),
                transform .18s var(--ease), box-shadow .18s var(--ease);
    white-space: nowrap;
}
.btn:hover { background: var(--surface-3); border-color: var(--line-strong); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }

.btn svg { width: 14px; height: 14px; flex: none; }

.btn-primary {
    border-color: transparent;
    background: linear-gradient(135deg, var(--accent), var(--accent-deep));
    color: #04100c;
    font-weight: 600;
    box-shadow: 0 8px 24px -10px rgba(34, 211, 165, 0.7);
}
.btn-primary:hover {
    background: linear-gradient(135deg, #3ae0b5, var(--accent));
    box-shadow: 0 12px 28px -10px rgba(34, 211, 165, 0.85);
    transform: translateY(-1px);
}

.btn-ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }

.btn-danger { color: var(--bad); }
.btn-danger:hover { background: var(--bad-soft); border-color: rgba(251, 113, 133, 0.35); }

.btn-sm { padding: 4px 8px; font-size: 11.5px; border-radius: 6px; }
.btn-sm svg { width: 12px; height: 12px; }

.toggle[aria-pressed="true"] {
    border-color: rgba(34, 211, 165, 0.45);
    background: var(--accent-soft);
    color: var(--accent);
}

.btn.is-busy svg { animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* --- inputs ------------------------------------------------------------- */

.input, select.input, textarea.input {
    width: 100%;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--line);
    background: rgba(0, 0, 0, 0.22);
    color: var(--text);
    font: inherit;
    font-size: 12.5px;
    transition: border-color .18s var(--ease), box-shadow .18s var(--ease), background .18s;
}
.input::placeholder { color: var(--faint); }
.input:hover { border-color: var(--line-strong); }
.input:focus {
    outline: none;
    border-color: rgba(34, 211, 165, 0.6);
    box-shadow: 0 0 0 4px rgba(34, 211, 165, 0.12);
    background: rgba(0, 0, 0, 0.3);
}
select.input {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 30px;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--muted) 50%),
        linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position: calc(100% - 15px) 55%, calc(100% - 10px) 55%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    cursor: pointer;
}
select.input option { background: #0f1422; color: var(--text); }

.field { display: flex; flex-direction: column; gap: 4px; }
.field > label {
    font-size: 11.5px;
    font-weight: 500;
    color: var(--muted);
    letter-spacing: .01em;
}
.field .hint { font-size: 11px; color: var(--faint); }

.input-wrap { position: relative; }
.input-wrap .input { padding-right: 38px; }
.input-wrap .eye {
    position: absolute;
    right: 6px; top: 50%;
    transform: translateY(-50%);
    width: 28px; height: 28px;
    display: grid; place-items: center;
    border: 0; border-radius: 6px;
    background: transparent; color: var(--muted);
    cursor: pointer;
}
.input-wrap .eye:hover { background: var(--surface-2); color: var(--text); }
.input-wrap .eye svg { width: 15px; height: 15px; }

.input-wrap .eye:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* The password toggle carries both icons and swaps them with a class, rather
   than looking one up in templates/_icons.php -- the auth pages do not include
   that partial. */
.eye .i-off { display: none; }
.eye[aria-pressed="true"] .i-off { display: block; }
.eye[aria-pressed="true"] .i-on { display: none; }

/* Chrome paints its own near-white background over an autofilled field, which
   wrecks a dark form. An opaque inset shadow covers it; the absurd transition
   delay stops the colour ever being applied in the first place. */
input.input:-webkit-autofill,
input.input:-webkit-autofill:hover,
input.input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--text);
    -webkit-box-shadow: 0 0 0 1000px var(--input-fill) inset;
    box-shadow: 0 0 0 1000px var(--input-fill) inset;
    caret-color: var(--text);
    transition: background-color 9999s ease-in-out 0s;
}
input.input:-webkit-autofill:focus {
    -webkit-box-shadow: 0 0 0 1000px var(--input-fill) inset, 0 0 0 4px rgba(34, 211, 165, 0.12);
    box-shadow: 0 0 0 1000px var(--input-fill) inset, 0 0 0 4px rgba(34, 211, 165, 0.12);
}

.switch {
    position: relative;
    display: inline-flex;
    align-items: center;
    width: 38px; height: 21px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--surface-2);
    cursor: pointer;
    transition: background .2s, border-color .2s;
}
.switch::after {
    content: '';
    position: absolute;
    left: 3px; top: 3px;
    width: 13px; height: 13px;
    border-radius: 50%;
    background: var(--muted);
    transition: transform .2s var(--ease), background .2s;
}
.switch[aria-checked="true"] { background: var(--accent-soft); border-color: rgba(34, 211, 165, 0.5); }
.switch[aria-checked="true"]::after { transform: translateX(17px); background: var(--accent); }

/* --- badges & pills ----------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
    border: 1px solid transparent;
}
.badge::before {
    content: '';
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: .9;
}
.b-good { background: var(--good-soft); color: var(--good); border-color: rgba(52, 211, 153, 0.25); }
.b-bad  { background: var(--bad-soft);  color: var(--bad);  border-color: rgba(251, 113, 133, 0.25); }
.b-warn { background: var(--warn-soft); color: var(--warn); border-color: rgba(251, 191, 36, 0.25); }
.b-mute { background: var(--surface-2); color: var(--muted); border-color: var(--line); }

.pill {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 5px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.pill-super { background: var(--accent-2-soft); color: #a5b0ff; }
.pill-admin { background: var(--accent-soft);   color: var(--accent); }
.pill-user  { background: var(--surface-2);     color: var(--muted); }

.pill-ui    { background: var(--accent-soft); color: var(--accent); }
.pill-env   { background: var(--info-soft);   color: var(--info); }
.pill-unset { background: var(--bad-soft);    color: var(--bad); }

.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 7px; vertical-align: middle; }
.dot-on  { background: var(--good); box-shadow: 0 0 0 3px var(--good-soft); }
.dot-off { background: var(--faint); }

/* --- panels ------------------------------------------------------------- */

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
.panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--line);
}
.panel-head h2 {
    margin: 0;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .01em;
}
.panel-head .sub { margin-left: 8px; }
.panel-body { padding: 14px; }

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

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

table {
    width: 100%;
    border-collapse: collapse;
}
th {
    text-align: left;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
    padding: 8px 12px;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
td {
    padding: 9px 12px;
    border-bottom: 1px solid var(--line);
    vertical-align: top;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background .15s; }
tbody tr:hover td { background: rgba(255, 255, 255, 0.02); }

/* --- dashboard tables --------------------------------------------------- */
/* Counts read down a column, so they right-align against a shared edge and
   stay narrow; the name column absorbs the slack instead of the gaps between
   figures doing it. Widths are set on the header cells only -- the table
   algorithm propagates them, and setting them on every row fights it. */

#pubtable th:nth-child(n+2),
#pubtable td:nth-child(n+2) { text-align: right; white-space: nowrap; }
/* Percentages, not pixels: fixed widths leave every spare pixel to column one
   and strand the name a screen away from its own figures. */
#pubtable th:nth-child(2),
#pubtable th:nth-child(3),
#pubtable th:nth-child(4) { width: 14%; }
#pubtable th:last-child { width: 26%; }
#pubtable td { vertical-align: middle; }
#pubtable td:last-child .bar {
    width: 160px;
    height: 6px;
    margin-right: 10px;
    vertical-align: middle;
}

/* The timestamp and the duration/confidence pair are each one idea. Let them
   size themselves rather than wrapping "94% confident" onto two lines. */
#calltable td:first-child,
#calltable th:nth-child(5),
#calltable td:nth-child(5) { white-space: nowrap; }
#calltable th:nth-child(5),
#calltable td:nth-child(5) { text-align: right; }

.empty {
    padding: 32px 16px;
    text-align: center;
    color: var(--muted);
}
.empty strong { display: block; color: var(--text); margin-bottom: 4px; font-weight: 600; }

.sub { color: var(--muted); font-size: 12.5px; }
.faint { color: var(--faint); }

.quote {
    color: var(--muted);
    font-style: italic;
    font-size: 13px;
    border-left: 2px solid var(--line-strong);
    padding-left: 8px;
    margin-top: 5px;
}

.bar {
    position: relative;
    display: inline-block;
    width: 80px; height: 5px;
    border-radius: 3px;
    background: var(--surface-3);
    overflow: hidden;
    vertical-align: middle;
    margin-right: 8px;
}
.bar > i {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 3px;
    background: linear-gradient(90deg, var(--warn), var(--bad));
}

/* --- notices & toasts --------------------------------------------------- */

.notice {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 10px 12px;
    border-radius: var(--radius);
    border: 1px solid rgba(251, 191, 36, 0.3);
    background: linear-gradient(180deg, rgba(251, 191, 36, 0.10), rgba(251, 191, 36, 0.05));
    color: #fde68a;
    margin-bottom: 14px;
}
.notice svg { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--warn); }
.notice strong { color: #fef3c7; }
.notice code {
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 12.5px;
    background: rgba(0, 0, 0, 0.3);
    padding: 1px 6px;
    border-radius: 5px;
}

/* --- modal -------------------------------------------------------------- */
/* Native <dialog>: focus trapping, Escape, and inertness of the page behind
   are the browser's job rather than ours. */

.modal {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text);
    max-width: min(420px, calc(100vw - 32px));
    width: 100%;
}
.modal::backdrop {
    background: rgba(4, 7, 14, 0.62);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}
.modal-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 22px;
    border-radius: 14px;
    border: 1px solid var(--line-strong);
    background: linear-gradient(180deg, #141a29, #0e1320);
    box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.07);
}
.modal-card h2 {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -.02em;
}
.modal-sub {
    margin: -4px 0 0;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--muted);
}
.modal-sub strong { color: var(--text); font-weight: 600; }
.modal-card .input { min-height: 42px; font-size: 14px; }
.modal-card .input-wrap .eye { width: 38px; height: 38px; right: 2px; }
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 2px;
}
/* An author `display` beats the user-agent [hidden] rule, so anything that
   sets one and is toggled with the attribute has to say so. */
.modal-actions[hidden],
.modal-row[hidden] { display: none; }

/* --- delete confirmation ------------------------------------------------ */
/* Pushed left so it is nowhere near Save. */
.ud-delete-open { margin-right: auto; }

.modal-danger {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 16px;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(251, 113, 133, 0.35);
    background: var(--bad-soft);
}
.modal-danger[hidden] { display: none; }
.modal-danger h3 {
    margin: 0;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
    color: #fecdd3;
}
.modal-danger .modal-sub { margin: 0; }
.modal-danger .modal-sub strong { color: #fecdd3; }
.modal-danger label strong {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--text);
}
.modal-danger .modal-actions { margin-top: 0; }
.modal-actions .btn { min-height: 36px; }

/* .err is display:flex, which beats the user-agent [hidden] rule. */
.err[hidden] { display: none; }


/* --- capabilities ------------------------------------------------------- */

/* Landscape account dialog: role beside password, the capability groups
   beside each other. Stacked, this ran to roughly 850px tall — taller than a
   laptop viewport, so the Save button fell below the fold. */
.modal-wide { max-width: min(840px, calc(100vw - 32px)); }
.modal-section {
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

.modal-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 24px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}
/* The row owns the rule; its cells must not each draw their own. */
.modal-row .modal-section { padding-top: 0; border-top: 0; }
.modal-section h3 {
    margin: 0 0 10px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
}

#ud-caps {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px 24px;
    align-items: start;
}
#ud-caps .cap-group + .cap-group { margin-top: 0; }

.cap-group + .cap-group { margin-top: 14px; }
.cap-group h4 {
    margin: 0 0 6px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--faint);
}
.cap-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background .15s var(--ease);
}
.cap-row:hover { background: var(--surface-2); }
.cap-row input { margin-top: 2px; width: 15px; height: 15px; accent-color: var(--accent); flex: none; }
.cap-row strong { display: block; font-size: 12.5px; font-weight: 600; }
.cap-row .sub { display: block; font-size: 11.5px; line-height: 1.45; }
.cap-row-off { opacity: .45; cursor: not-allowed; }
.cap-row-off:hover { background: transparent; }

/* Row summary in the account table. */
.cap-sum { display: flex; flex-direction: column; gap: 1px; }
.cap-count { font-size: 12.5px; font-weight: 600; color: var(--good); }
.cap-count-cut { color: var(--warn); }
.cap-sum .sub { font-size: 11px; }

/* Clickable account rows. */
.row-clickable { cursor: pointer; }
.row-clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Below the point where two columns stop fitting, fall back to the stack. */
@media (max-width: 760px) {
    .modal-row,
    #ud-caps { grid-template-columns: minmax(0, 1fr); }
    .modal-row { gap: 14px; }
    #ud-caps .cap-group + .cap-group { margin-top: 14px; }
}


/* My account: the read-only list of what this person holds. */
.cap-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.cap-list li { display: flex; align-items: flex-start; gap: 10px; }
.cap-list strong { display: block; font-size: 12.5px; font-weight: 600; }
.cap-list .sub { display: block; font-size: 11.5px; line-height: 1.45; }
.cap-mark {
    flex: none;
    width: 20px; height: 20px;
    border-radius: 6px;
    display: grid; place-items: center;
    margin-top: 1px;
}
.cap-mark svg { width: 12px; height: 12px; }
.cap-on  .cap-mark { background: var(--good-soft); color: var(--good); }
.cap-off .cap-mark { background: var(--surface-2); color: var(--faint); }
.cap-off strong, .cap-off .sub { color: var(--faint); }

/* The avatar doubles as the link to My account. */
.avatar-link { text-decoration: none; transition: box-shadow .18s var(--ease); }
.avatar-link:hover, .avatar-link.active { box-shadow: 0 0 0 2px var(--accent); text-decoration: none; }


.toasts {
    position: fixed;
    right: 20px; bottom: 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    z-index: 100;
    pointer-events: none;
}
.toast {
    pointer-events: auto;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 220px;
    max-width: 360px;
    padding: 9px 12px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--line-strong);
    background: rgba(14, 18, 30, 0.92);
    backdrop-filter: blur(12px);
    box-shadow: var(--shadow);
    font-size: 12.5px;
}
.toast::before {
    content: '';
    width: 8px; height: 8px;
    border-radius: 50%;
    flex: none;
    background: var(--info);
}
.toast.ok::before  { background: var(--good); box-shadow: 0 0 12px var(--good); }
.toast.err::before { background: var(--bad);  box-shadow: 0 0 12px var(--bad); }

/* ==========================================================================
   App shell: sidebar + main
   ========================================================================== */

.shell {
    display: grid;
    grid-template-columns: var(--sidebar-w) 1fr;
    min-height: 100vh;
}

.sidebar {
    position: sticky;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    padding: 16px 12px;
    border-right: 1px solid var(--line);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.012));
    backdrop-filter: blur(14px);
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 2px 6px 16px;
}
/* The mark is the shield itself and carries its own gradient, so the tile
   that used to sit behind it is gone. See templates/_logo.php. */
.brand .mark {
    width: 32px; height: 32px;
    display: grid; place-items: center;
    flex: none;
}
.brand .mark .cg-mark {
    width: 100%; height: 100%;
    filter: drop-shadow(0 6px 14px rgba(34, 211, 165, 0.30));
}
.brand .name { display: block; font-weight: 700; font-size: 15.5px; letter-spacing: -.01em; }
.brand .tag { display: block; font-size: 11.5px; color: var(--muted); margin-top: 0; }
.brand:hover { text-decoration: none; }
.brand, .brand span { color: var(--text); }

.nav { display: flex; flex-direction: column; gap: 2px; }
.nav-label {
    padding: 10px 8px 4px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--faint);
}
.nav a {
    position: relative;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 9px;
    border-radius: 7px;
    color: var(--muted);
    font-size: 14px;
    font-weight: 500;
    transition: background .18s var(--ease), color .18s var(--ease);
}
.nav a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.nav a.active { background: var(--accent-soft); color: var(--accent); }
.nav a.active::before {
    content: '';
    position: absolute;
    left: -12px; top: 8px; bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--accent);
}
.nav a svg { width: 17px; height: 17px; flex: none; }

.sidebar .spacer { flex: 1; }

.userchip {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px;
    border-radius: 9px;
    border: 1px solid var(--line);
    background: var(--surface);
}
.avatar {
    width: 28px; height: 28px;
    border-radius: 8px;
    display: grid; place-items: center;
    font-weight: 700;
    font-size: 12px;
    color: #04100c;
    background: linear-gradient(135deg, #9ff5dd, var(--accent));
    flex: none;
}
.userchip .who { min-width: 0; flex: 1; }
.userchip .who .n {
    font-weight: 600;
    font-size: 13.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.userchip form { margin: 0; }
.icon-btn {
    width: 28px; height: 28px;
    display: grid; place-items: center;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: background .15s, color .15s;
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
.icon-btn svg { width: 15px; height: 15px; }

.main {
    min-width: 0;
    padding: 18px 22px 48px;
}
/* No width cap. Everything in .main used to stop at 1440px, which left a
   band of dead space down the right of a wide monitor -- and because there
   was no auto margin it was not even centred. Tables and charts are what
   this app is for, and they earn the extra width. */

.topbar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
}
.topbar h1 {
    margin: 0;
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -.02em;
}
.topbar .subtitle { color: var(--muted); margin-top: 2px; font-size: 12px; }
.topbar .actions { display: flex; align-items: center; gap: 8px; }

.status { font-size: 11.5px; color: var(--muted); min-height: 1em; }
.topbar select.input-sm { width: auto; padding: 6px 28px 6px 9px; font-size: 12px; }

/* --- filters ------------------------------------------------------------ */

.filters {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    margin-bottom: 12px;
}
.filters select.input { width: auto; min-width: 136px; padding-top: 6px; padding-bottom: 6px; }

/* --- stat cards --------------------------------------------------------- */

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 10px;
    margin-bottom: 14px;
}
.card {
    position: relative;
    padding: 14px 15px 15px;
    border-radius: var(--radius);
    border: 1px solid var(--line);
    background: var(--surface);
    backdrop-filter: blur(12px);
    overflow: hidden;
    transition: transform .2s var(--ease), border-color .2s var(--ease);
}
.card:hover { transform: translateY(-2px); border-color: var(--line-strong); }
.card .l {
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
}
.card .n {
    margin-top: 6px;
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -.025em;
    line-height: 1.05;
}

/* The tone marker is a rule along the top edge. It used to be an 80px circle
   blurred by 30px, which spread wider than the card is tall -- overflow
   clipped it square, so every tile carried a hard-edged colour block instead
   of a glow. */
.card .glow {
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 2px;
    background: var(--accent);
    -webkit-mask-image: linear-gradient(90deg, #000, transparent 72%);
    mask-image: linear-gradient(90deg, #000, transparent 72%);
    pointer-events: none;
}
.card.tone-bad  .glow { background: var(--bad); }
.card.tone-warn .glow { background: var(--warn); }
.card.tone-good .glow { background: var(--good); }
.card.tone-info .glow { background: var(--accent-2); }
.card.tone-mute .glow { background: var(--faint); }

/* A soft directional wash, low enough not to fight the number. */
.card.tone-bad  { background: linear-gradient(150deg, rgba(251, 113, 133, 0.10), transparent 58%), var(--surface); }
.card.tone-warn { background: linear-gradient(150deg, rgba(251, 191, 36, 0.10), transparent 58%), var(--surface); }
.card.tone-good { background: linear-gradient(150deg, rgba(52, 211, 153, 0.10), transparent 58%), var(--surface); }
.card.tone-info { background: linear-gradient(150deg, rgba(124, 140, 248, 0.10), transparent 58%), var(--surface); }

.card.tone-bad .n  { color: #fda4af; }
.card.tone-good .n { color: #6ee7b7; }
.card.tone-warn .n { color: #fcd34d; }

.stack { display: flex; flex-direction: column; gap: 14px; }

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

.chart-row {
    display: grid;
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
    gap: 14px;
    margin-bottom: 14px;
    align-items: stretch;
}
.chart-row .panel { display: flex; flex-direction: column; }
.chart-row .panel-body { flex: 1; display: flex; flex-direction: column; justify-content: center; }

.chart-host { display: flex; flex-direction: column; gap: 12px; }
.chart-svg { display: block; width: 100%; height: auto; overflow: visible; }

.chart-empty {
    margin: 0;
    padding: 28px 8px;
    text-align: center;
    color: var(--muted);
    font-size: 12.5px;
}

.pie-slice { transition: opacity .15s var(--ease); cursor: default; }
.chart-svg:hover .pie-slice { opacity: .55; }
.chart-svg .pie-slice:hover { opacity: 1; }

/* Donut leader labels. The line is hairline on purpose: it is a pointer, not
   a rule, and anything heavier competes with the segment it points at. */
.pie-lead {
    fill: none;
    stroke: rgba(255, 255, 255, .26);
    stroke-width: 1;
    stroke-linejoin: round;
    stroke-linecap: round;
}
.pie-name {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .01em;
    fill: var(--text);
    dominant-baseline: middle;
}
.pie-meta {
    font-size: 10.5px;
    fill: var(--muted);
    font-variant-numeric: tabular-nums;
    dominant-baseline: middle;
}
.pie-total { margin-top: 2px; }

/* The leaders are decoration for the segment they point at, so they fade with
   it rather than staying lit over a dimmed ring. */
.pie-leaders { transition: opacity .15s var(--ease); }
.pie-svg:hover .pie-leaders { opacity: .85; }

/* Trend */
.chart-grid { stroke: rgba(255, 255, 255, 0.07); stroke-width: 1; }
.chart-tick { font-size: 10px; fill: var(--faint); font-variant-numeric: tabular-nums; }
.trend-area-total   { fill: rgba(124, 140, 248, 0.16); }
.trend-area-flagged { fill: rgba(251, 113, 133, 0.20); }
.trend-line-total   { stroke: var(--accent-2); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.trend-line-flagged { stroke: var(--bad);      stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.trend-hit { fill: transparent; }
.trend-hit:hover { fill: rgba(255, 255, 255, 0.05); }

/* Legend */
.chart-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.chart-legend-row { flex-direction: row; gap: 16px; }
.chart-legend li { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.chart-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.chart-legend-name { color: var(--text); }
.chart-legend-value { margin-left: auto; color: var(--muted); font-size: 11.5px; }
.chart-legend-total {
    margin-top: 4px;
    padding-top: 8px;
    border-top: 1px solid var(--line);
    color: var(--faint);
    font-size: 11px;
}

@media (max-width: 1100px) {
    .chart-row { grid-template-columns: minmax(0, 1fr); }
}

.why { max-width: 380px; }
.rec { margin-top: 5px; }
.signal { color: var(--bad); font-weight: 500; }

.lbl { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.lbl select.input { width: auto; padding: 4px 26px 4px 8px; font-size: 12px; }
.ok { color: var(--good); font-size: 11px; font-weight: 500; min-width: 40px; }

/* ==========================================================================
   Admin console
   ========================================================================== */

#settings { margin-top: 26px; scroll-margin-top: 16px; }
#settings-root { margin-top: 0; }

.grid-2 {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 14px;
    align-items: start;
}

.form { display: flex; flex-direction: column; gap: 10px; }
.form .row { display: flex; gap: 10px; }
.form .row > * { flex: 1; }
.form-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 4px; }

.user-row-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.user-row-actions select.input { width: auto; padding: 4px 26px 4px 8px; font-size: 11.5px; }

/* --- team table --------------------------------------------------------- */
/* The account row carries six columns plus its actions. Let the ones that
   are a single idea stay on one line rather than wrapping mid-value. */

#usertable td, #usertable th { vertical-align: middle; }
#usertable td:nth-child(2),
#usertable td:nth-child(3),
#usertable td:nth-child(5),
#usertable td:nth-child(6) { white-space: nowrap; }
#usertable td:last-child { white-space: nowrap; text-align: right; }
#usertable .pill { white-space: nowrap; }
#usertable td:nth-child(6) { max-width: 200px; white-space: normal; }
.user-row-actions { flex-wrap: nowrap; }


.settings-group { margin-bottom: 14px; }
.setting {
    display: grid;
    grid-template-columns: minmax(200px, 1fr) minmax(0, 1.4fr);
    gap: 18px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--line);
}
.setting:last-child { border-bottom: none; }
.setting .meta .label { font-weight: 600; font-size: 13px; }
.setting .meta .help { margin-top: 3px; font-size: 11.5px; color: var(--muted); line-height: 1.45; }
.setting .meta .state { margin-top: 7px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.setting .meta .state .faint { font-size: 12px; }
.setting .control { display: flex; flex-direction: column; gap: 6px; }
.setting .control .line { display: flex; gap: 6px; align-items: center; }
.setting .control .line .input { flex: 1; }
.setting .masked {
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 12px;
    color: var(--muted);
}

.kbd {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 5px;
    border: 1px solid var(--line-strong);
    background: var(--surface-2);
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 12px;
}

.info-box {
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(96, 165, 250, 0.25);
    background: var(--info-soft);
    color: #bfdbfe;
    font-size: 12px;
    line-height: 1.55;
}
.info-box code {
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 12px;
    word-break: break-all;
}

/* ==========================================================================
   Auth screens (login, setup, error)
   ========================================================================== */

.auth-page {
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: 24px;
    position: relative;
    /* Only the horizontal axis is clipped. Clipping both would cut the form
       off on a short screen (landscape phone) instead of letting it scroll. */
    overflow-x: hidden;
}

/* The ambient layers from body::before/::after are tuned for the dashboard,
   where there is content to sit on. Behind a sign-in form they stack with the
   aurora and turn to soup, so the auth pages bring their own. */
.auth-page::before {
    background:
        radial-gradient(1100px 720px at 12% -12%, rgba(34, 211, 165, 0.10), transparent 62%),
        radial-gradient(900px 700px at 104% 112%, rgba(124, 140, 248, 0.10), transparent 62%),
        var(--bg);
}
.auth-page::after { display: none; }

.aurora {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
}
.aurora span {
    position: absolute;
    width: 46vmax; height: 46vmax;
    border-radius: 50%;
    filter: blur(80px);
    opacity: .26;
    animation: drift 34s ease-in-out infinite alternate;
}
.aurora span:nth-child(1) { left: -14vmax; top: -18vmax; background: var(--accent); }
.aurora span:nth-child(2) { right: -16vmax; bottom: -20vmax; background: var(--accent-2); animation-delay: -12s; }
.aurora span:nth-child(3) { left: 32vw; top: 58vh; width: 26vmax; height: 26vmax; background: #2563eb; opacity: .14; animation-delay: -22s; }

@keyframes drift {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(5vmax, 3vmax, 0) scale(1.1); }
}

/* --- shared auth controls ----------------------------------------------- */
/* Deliberately larger than the dashboard controls. Dense inputs are right
   above a data table; on a sign-in form they are just small. 48px also clears
   the 44px touch minimum and the 16px iOS auto-zoom threshold. */

.auth-page .field { gap: 7px; }
.auth-page .field > label {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text);
}
.auth-page .field .hint { font-size: 12px; color: var(--muted); line-height: 1.5; }

.auth-page .input {
    min-height: 48px;
    padding: 12px 15px;
    font-size: 16px;
    border-radius: 10px;
}
.auth-page .input-wrap .input { padding-right: 52px; }
.auth-page .input-wrap .eye {
    width: 44px; height: 44px;
    right: 2px;
    border-radius: 8px;
}
.auth-page .input-wrap .eye svg { width: 18px; height: 18px; }

.auth-page .btn-primary {
    width: 100%;
    justify-content: center;
    min-height: 48px;
    padding: 0 18px;
    font-size: 14.5px;
    border-radius: 10px;
    margin-top: 4px;
}

/* Caps Lock warning under the password field. */
.caps {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0 0;
    font-size: 12px;
    color: var(--warn);
}
.caps svg { width: 14px; height: 14px; flex: none; }
.caps[hidden] { display: none; }
/* --- split layout (login) ----------------------------------------------- */

.auth-page.auth-split { padding: 0; place-items: stretch; }
/* The viewport-wide aurora bleeds across both columns and washes the panel
   flat. The split screen lights each column separately instead. */
.auth-split .aurora { display: none; }

.auth-shell {
    width: 100%;
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
}

.auth-aside {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 44px;
    padding: 56px clamp(40px, 5vw, 76px);
    overflow: hidden;
    background:
        radial-gradient(70% 48% at 4% -4%, rgba(34, 211, 165, 0.26), transparent 66%),
        radial-gradient(85% 55% at 18% 108%, rgba(124, 140, 248, 0.20), transparent 68%),
        radial-gradient(40% 30% at 92% 42%, rgba(34, 211, 165, 0.07), transparent 70%),
        linear-gradient(168deg, #0e1728 0%, #0a0f1c 50%, #070a12 100%);
}
/* The pitch is the middle child; centring it in the leftover space reads
   better than letting space-between drop it wherever the copy ends. */
.auth-pitch { margin: auto 0; padding: 8px 0; }
/* Faint grid, faded out downwards so it reads as texture and not as a table. */
.auth-aside::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
    background-size: 38px 38px;
    mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .35) 45%, transparent 80%);
    -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .35) 45%, transparent 80%);
}
/* A hard full-height rule cuts the screen in two. This one fades at both ends. */
.auth-aside::after {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0;
    width: 1px;
    background: linear-gradient(180deg, transparent, var(--line-strong) 22%, var(--line-strong) 78%, transparent);
}
.auth-aside > * { position: relative; max-width: 470px; }

.auth-aside .brand { padding: 0; }
.auth-aside .brand .mark { width: 42px; height: 42px; }
.auth-aside .brand .name { font-size: 16.5px; }
.auth-aside .brand .tag { font-size: 11.5px; }

.auth-pitch h2 {
    margin: 0 0 34px;
    font-size: clamp(28px, 3vw, 40px);
    line-height: 1.14;
    font-weight: 700;
    letter-spacing: -.032em;
    color: var(--text);
}
/* A thin accent rule under the headline, matching the brand mark. */
.auth-pitch h2::after {
    content: '';
    display: block;
    width: 46px; height: 3px;
    margin-top: 22px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.auth-points {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 20px;
}
.auth-points li { display: flex; align-items: flex-start; gap: 14px; }
.pt-ico {
    flex: none;
    width: 38px; height: 38px;
    border-radius: 11px;
    display: grid;
    place-items: center;
    color: var(--accent);
    background: rgba(34, 211, 165, 0.10);
    border: 1px solid rgba(34, 211, 165, 0.24);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.pt-ico svg { width: 18px; height: 18px; }
.pt-txt {
    font-size: 14px;
    line-height: 1.6;
    color: var(--muted);
}
.pt-txt strong { color: var(--text); font-weight: 600; }

.auth-aside-foot {
    margin: 0;
    padding-top: 20px;
    border-top: 1px solid var(--line);
    font-size: 12px;
    line-height: 1.6;
    color: var(--muted);
}

.auth-panel {
    position: relative;
    display: grid;
    place-items: center;
    padding: 48px 40px;
    background: linear-gradient(180deg, #0a0e18 0%, #070a12 100%);
}
/* Keeps the form from floating on flat black. */
.auth-panel::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(64% 46% at 50% 40%, rgba(124, 140, 248, 0.10), transparent 70%),
        radial-gradient(50% 34% at 78% 8%, rgba(34, 211, 165, 0.06), transparent 72%);
}

/* The form gets the same glass surface the dashboard uses for cards. Without
   it the right half is a flat slab next to a lit one. */
.auth-form {
    position: relative;
    width: 100%;
    max-width: 404px;
    padding: 34px 34px 26px;
    border-radius: 18px;
    border: 1px solid var(--line);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.018));
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    box-shadow: 0 34px 80px -34px rgba(0, 0, 0, 0.8), inset 0 1px 0 rgba(255, 255, 255, 0.07);
}

.auth-head { margin-bottom: 24px; }
.auth-form h1 {
    margin: 0 0 6px;
    font-size: 27px;
    font-weight: 700;
    letter-spacing: -.028em;
    line-height: 1.2;
}
.auth-form .lede {
    margin: 0;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.55;
}
.auth-form form { display: flex; flex-direction: column; gap: 16px; }

.auth-form .foot {
    margin-top: 26px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
    font-size: 11.5px;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: 8px;
}
.auth-form .foot svg { width: 14px; height: 14px; flex: none; }

/* --- entrance ------------------------------------------------------------ */
/* CSS, not GSAP. A JS timeline that never ticks -- a background tab pausing
   rAF, a script error -- leaves the form at opacity 0, and an invisible
   sign-in form is a locked door. A CSS animation always reaches its end state,
   and prefers-reduced-motion collapses it below. */

@keyframes auth-rise {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
}

@keyframes auth-shake {
    0%, 100% { transform: translateX(0); }
    18%      { transform: translateX(-7px); }
    38%      { transform: translateX(6px); }
    58%      { transform: translateX(-4px); }
    78%      { transform: translateX(2px); }
}

.auth-aside .brand           { animation: auth-rise .6s var(--ease) .05s both; }
.auth-pitch h2               { animation: auth-rise .6s var(--ease) .13s both; }
.auth-points li:nth-child(1) { animation: auth-rise .6s var(--ease) .21s both; }
.auth-points li:nth-child(2) { animation: auth-rise .6s var(--ease) .28s both; }
.auth-points li:nth-child(3) { animation: auth-rise .6s var(--ease) .35s both; }
.auth-aside-foot             { animation: auth-rise .6s var(--ease) .42s both; }

.auth-form .auth-head        { animation: auth-rise .6s var(--ease) .10s both; }
.auth-form form              { animation: auth-rise .6s var(--ease) .18s both; }
.auth-form .foot             { animation: auth-rise .6s var(--ease) .28s both; }

.auth-card                   { animation: auth-rise .6s var(--ease) both; }

/* The form column takes the shake so it does not fight the rise on .auth-form
   form, which animates transform too. */
.auth-page[data-error="1"] .auth-form,
.auth-page[data-error="1"] .auth-card { animation: auth-shake .5s var(--ease) .34s both; }

@media (prefers-reduced-motion: reduce) {
    /* The global rule collapses duration but not delay, which would leave
       content held at opacity 0 by the backwards fill. */
    .auth-page *, .auth-page *::before, .auth-page *::after { animation-delay: 0s !important; }
}


/* --- single card (setup, error) ----------------------------------------- */

.auth-card {
    width: 100%;
    max-width: 420px;
    padding: 32px 32px 24px;
    border-radius: 16px;
    border: 1px solid var(--line-strong);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.025));
    backdrop-filter: blur(22px);
    -webkit-backdrop-filter: blur(22px);
    box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.auth-card .brand { padding: 0 0 20px; }
.auth-card h1 {
    margin: 0 0 6px;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -.025em;
    line-height: 1.2;
}
.auth-card .lede {
    margin: 0 0 20px;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.55;
}
.auth-card form { display: flex; flex-direction: column; gap: 16px; }
.auth-card .foot {
    margin-top: 20px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
    font-size: 11.5px;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: 8px;
}
.auth-card .foot svg { width: 14px; height: 14px; flex: none; }

.err {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 11px 12px;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(251, 113, 133, 0.35);
    background: var(--bad-soft);
    color: #fecdd3;
    font-size: 13px;
    line-height: 1.45;
}
.err svg { width: 16px; height: 16px; flex: none; color: var(--bad); }

.error-code {
    font-size: 52px;
    font-weight: 800;
    letter-spacing: -.04em;
    line-height: 1;
    background: linear-gradient(135deg, var(--accent), var(--accent-2));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    margin-bottom: 10px;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 1100px) {
    .grid-2 { grid-template-columns: 1fr; }
    .setting { grid-template-columns: 1fr; gap: 12px; }
}

@media (max-width: 900px) {
    .shell { grid-template-columns: 1fr; }
    .sidebar {
        position: static;
        height: auto;
        flex-direction: row;
        align-items: center;
        flex-wrap: wrap;
        gap: 8px;
        padding: 10px 12px;
        border-right: 0;
        border-bottom: 1px solid var(--line);
    }
    .brand { padding: 0 8px 0 0; }
    .brand .tag { display: none; }
    /* Wrap, or the nav items force the shell wider than the screen and the
       whole page scrolls sideways. The sidebar wraps; this did not. */
    .nav { flex-direction: row; flex-wrap: wrap; }
    .nav-label { display: none; }
    .nav a.active::before { display: none; }
    .sidebar .spacer { flex: 1; }
    .userchip { padding: 6px 8px; }
    .userchip .who { display: none; }
    .main { padding: 14px 12px 32px; }
    .topbar { flex-direction: column; align-items: flex-start; }
}


/* Below 900px the left column folds down to a brand strip and the form takes
   the screen. The pitch is context, not something to scroll past on a phone. */
@media (max-width: 900px) {
    .auth-shell { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
    .auth-aside {
        flex-direction: row;
        align-items: center;
        gap: 0;
        padding: 16px 20px;
        border-right: 0;
        border-bottom: 1px solid var(--line);
    }
    .auth-aside .auth-pitch,
    .auth-aside .auth-aside-foot { display: none; }
    .auth-aside .brand .mark { width: 32px; height: 32px; }
    .auth-aside .brand .name { font-size: 15px; }
    /* The sidebar rule above hides .tag on small screens; here it is the only
       thing naming the product, so it stays. */
    .auth-aside .brand .tag { display: block; }

    .auth-panel { align-items: start; padding: 36px 20px 48px; }
    .auth-form { max-width: 420px; }
}

@media (max-width: 480px) {
    .auth-page { padding: 20px 16px; }
    .auth-panel { padding: 24px 14px 36px; }
    .auth-form { padding: 24px 20px 18px; border-radius: 14px; }
    .auth-form h1 { font-size: 23px; }
    .auth-head { margin-bottom: 20px; }
    .auth-card { padding: 26px 20px 20px; border-radius: 14px; }
    .auth-aside { padding: 14px 16px; }
}
/* ==========================================================================
   Motion
   ========================================================================== */

/*
 * `.will-animate` is a JS hook and nothing more -- it deliberately sets no
 * opacity.
 *
 * It used to be `opacity: 0`, with GSAP responsible for revealing it. That
 * makes every screen depend on an animation library succeeding: one failed
 * request for gsap.min.js or ui.js, one parse error, and the dashboard renders
 * as an empty page. The sign-in form was caught doing exactly that.
 *
 * CG.staggerIn() now uses gsap.from(), so the element's real state IS the
 * finished state and the animation only ever plays backwards from an offset.
 * Worst case is no animation, never no content.
 */

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

/* ==========================================================================
   Status (tick / cross) and problem cells
   ========================================================================== */

.st { display: flex; align-items: center; gap: 9px; }
.st-icon {
    width: 26px; height: 26px;
    flex: none;
    border-radius: 50%;
    display: grid; place-items: center;
    border: 1px solid transparent;
}
.st-icon svg { width: 15px; height: 15px; }
.st-icon.sm { width: 20px; height: 20px; }
.st-icon.sm svg { width: 12px; height: 12px; }

.st-good    { color: var(--good); }
.st-bad     { color: var(--bad); }
.st-warn    { color: var(--warn); }
.st-neutral { color: var(--muted); }
.st-failed  { color: var(--bad); }
.st-pending { color: var(--info); }

.st-icon.st-good    { background: var(--good-soft); border-color: rgba(52, 211, 153, 0.35); box-shadow: 0 0 18px -6px var(--good); }
.st-icon.st-bad     { background: var(--bad-soft);  border-color: rgba(251, 113, 133, 0.35); box-shadow: 0 0 18px -6px var(--bad); }
.st-icon.st-warn    { background: var(--warn-soft); border-color: rgba(251, 191, 36, 0.35); }
.st-icon.st-neutral { background: var(--surface-2); border-color: var(--line); }
.st-icon.st-failed  { background: var(--bad-soft);  border-color: rgba(251, 113, 133, 0.35); }
.st-icon.st-pending { background: var(--info-soft); border-color: rgba(96, 165, 250, 0.35); }

.st-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.st-number { font-size: 13.5px; font-weight: 600; color: var(--text); }
.st-label { font-size: 12.5px; font-weight: 600; letter-spacing: .01em; }

.problem { max-width: 400px; }
.problem .p-title { font-weight: 600; font-size: 13.5px; }
.problem .p-body { margin-top: 2px; color: var(--text); opacity: .95; font-size: 13px; }
.problem .p-signals { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }

.chip {
    display: inline-flex; align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11.5px; font-weight: 600;
    border: 1px solid transparent;
}
.chip-bad { background: var(--bad-soft); color: var(--bad); border-color: rgba(251, 113, 133, 0.3); }

tr.row-bad td:first-child,
tr.row-failed td:first-child { box-shadow: inset 3px 0 0 var(--bad); }
tr.row-good td:first-child { box-shadow: inset 3px 0 0 var(--good); }
tr.row-warn td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

/* ==========================================================================
   Reports
   ========================================================================== */

/*
 * Flex, not grid.
 *
 * `repeat(auto-fit, minmax(160px, 1fr))` gave every filter an identical track,
 * which is the one thing a filter bar must not do: the period switch needs
 * ~230px for four buttons and the toggles ~180px, while a select is happy at
 * 150px. Equal tracks meant the wide controls overflowed their cell and drew
 * on top of the next field -- "Range" landing inside the Month box.
 *
 * Each field now asks for the width it actually needs and wraps to a new row
 * when there is not enough, which is what a toolbar should do.
 */
.filter-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: flex-end;
}

/* No grow. Letting fields absorb the leftover space stretched a single select
   to 800px on a wide screen; a filter keeps the width it needs and the row
   simply ends where it ends. */
.filter-grid > .field {
    flex: 0 1 165px;
    min-width: 148px;
}

/* Controls whose width is set by their contents, not by the layout. */
.filter-grid > .field-period,
.filter-grid > .field-toggles,
.filter-grid > .field-apply {
    flex: 0 0 auto;
    min-width: 0;
}

/* A select plus a direction button; cramped below this. */
.filter-grid > .field-sort { flex: 0 1 252px; min-width: 220px; }

/* Native date/month pickers carry a browser-drawn calendar button, so they
   need a little more than a plain select and do not benefit from more. */
.filter-grid > .field-date { flex: 0 1 190px; min-width: 170px; }

/* Push the primary action to the end of the row, away from the filters. */
.filter-grid > .field-apply { margin-left: auto; }

/* Flex children default to min-width:auto, which is what let content push
   past its box in the first place. */
.filter-grid .line { display: flex; gap: 8px; align-items: center; min-width: 0; }
.filter-grid .line > .input { flex: 1 1 auto; min-width: 0; }
.filter-grid .line > .btn { flex: 0 0 auto; }
.filter-grid .field[hidden] { display: none; }
.field-apply .btn { justify-content: center; }

.seg {
    display: inline-flex;
    flex: none;
    padding: 3px;
    border-radius: 10px;
    border: 1px solid var(--line);
    background: rgba(0, 0, 0, 0.25);
    gap: 2px;
}
.seg button {
    border: 0;
    background: transparent;
    color: var(--muted);
    font: inherit; font-weight: 500;
    padding: 5px 12px;
    border-radius: 6px;
    font-size: 12.5px;
    cursor: pointer;
    transition: background .18s var(--ease), color .18s var(--ease);
}
.seg button:hover { color: var(--text); }
.seg button.on { background: var(--accent-soft); color: var(--accent); }

.reports-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); margin-bottom: 14px; }

.bk-row {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr) 110px 44px 48px;
    gap: 10px;
    align-items: center;
    padding: 6px 0;
    border-bottom: 1px solid var(--line);
}
.bk-row:last-child { border-bottom: none; }
.bk-label { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bk-bar { width: 100%; margin: 0; }
.bk-num { text-align: right; font-weight: 600; }
.bk-pct { text-align: right; }
.bar > i.fill-good    { background: linear-gradient(90deg, #10b981, var(--good)); }
.bar > i.fill-bad     { background: linear-gradient(90deg, #e11d48, var(--bad)); }
.bar > i.fill-warn    { background: linear-gradient(90deg, #d97706, var(--warn)); }
.bar > i.fill-neutral { background: linear-gradient(90deg, #475569, var(--muted)); }

.pager { display: flex; align-items: center; gap: 10px; }
.panel-foot { padding: 8px 14px; border-top: 1px solid var(--line); display: flex; justify-content: flex-end; }
.panel-foot .pager:empty { display: none; }
.panel-foot:has(.pager:empty) { display: none; }

/* ==========================================================================
   Secret banner and key/value rows
   ========================================================================== */

.notice-ok {
    border-color: rgba(52, 211, 153, 0.35);
    background: linear-gradient(180deg, rgba(52, 211, 153, 0.12), rgba(52, 211, 153, 0.05));
    color: #d1fae5;
}
.notice-ok svg { color: var(--good); }
.notice-ok strong { color: #ecfdf5; }
.notice .grow { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.notice .icon-btn { flex: none; margin: -4px -6px 0 0; }

.kv {
    display: grid;
    grid-template-columns: 70px minmax(0, 1fr) auto;
    gap: 8px;
    align-items: center;
}
.kv > span:first-child { font-size: 12px; }
.kv code.wrap, code.wrap {
    display: block;
    padding: 5px 8px;
    border-radius: 6px;
    background: rgba(0, 0, 0, 0.3);
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 11.5px;
    word-break: break-all;
    line-height: 1.5;
    color: var(--text);
}
.info-box .kv { margin-bottom: 8px; }
.info-box .kv > span:first-child { color: #bfdbfe; }

@media (max-width: 1100px) {
    .reports-grid { grid-template-columns: 1fr; }
    .kv { grid-template-columns: 1fr; }
}

/* --- "Reviewed as" -------------------------------------------------------
 * The reviewer's verdict, coloured on the same binary rule as everything else:
 * green if a person confirmed the call is qualified, red if it is not.
 *
 * Whether they agreed with the model is a separate fact and gets no colour of
 * its own — just a muted "changed" tag — so green never has to mean two things
 * at once. It did once, and rendered "Prank or abusive" in green.
 */
.rv {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
}
.rv-ico { display: inline-flex; }
.rv-ico svg { width: 14px; height: 14px; }

.rv-changed {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 6px;
    border-radius: 5px;
    background: var(--surface-2);
    border: 1px solid var(--line);
    color: var(--muted);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    vertical-align: 1px;
}

/* The verdict picker sits under the current verdict, so the column reads as
   "this is the answer, and here is where you change it". */
.rv-cell { min-width: 168px; }
.rv-cell .rv + .rv-select,
.rv-cell .rv-changed + .rv-select { margin-top: 6px; }
.rv-select {
    display: block;
    width: 100%;
    max-width: 168px;
    padding: 4px 26px 4px 8px;
    font-size: 11.5px;
}
.rv-select:disabled { opacity: .5; }

/* Multi-line settings (the email wording). */
textarea.input {
    min-height: 84px;
    resize: vertical;
    line-height: 1.5;
    font-family: inherit;
}
.setting .control textarea.input { width: 100%; }

/* Mailer tabs sit in the header next to the actions. */
#mailer-tabs { flex: none; }
.panel-head .actions { display: flex; align-items: center; gap: 10px; }

/* --- expandable nav group (Mailer) --------------------------------------- */

.nav-group { display: flex; flex-direction: column; }

.nav-toggle {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 7px 9px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: background .18s var(--ease), color .18s var(--ease);
}
.nav-toggle:hover { background: var(--surface-2); color: var(--text); }
.nav-toggle.active { color: var(--text); }
.nav-toggle > svg:first-child { width: 15px; height: 15px; flex: none; }
.nav-toggle .chev {
    width: 14px; height: 14px;
    margin-left: auto;
    flex: none;
    transition: transform .2s var(--ease);
}
.nav-group.open .nav-toggle .chev { transform: rotate(180deg); }

/* Collapsed by default; the group opens when its page is active or clicked. */
.nav-sub {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .22s var(--ease);
}
.nav-group.open .nav-sub { grid-template-rows: 1fr; }

/* Exactly one child, and it must clip: 0fr gives the row no height, and only
   overflow:hidden stops the links spilling out of it while it is collapsed.
   A second direct child here would land in an implicit auto row and stay
   visible when the group is shut -- put new links inside the wrapper. */
.nav-sub > * { overflow: hidden; min-height: 0; }
.nav-sub-inner {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-top: 2px;
}

.nav-sub a {
    display: block;
    position: relative;
    margin-left: 24px;
    padding: 6px 9px;
    border-radius: 6px;
    color: var(--muted);
    font-size: 12.5px;
}
.nav-sub a::before {
    content: '';
    position: absolute;
    left: -10px; top: 0; bottom: 0;
    width: 1px;
    background: var(--line);
}
.nav-sub a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.nav-sub a.active { background: var(--accent-soft); color: var(--accent); }
.nav-sub a.active::before { background: var(--accent); width: 2px; left: -10px; }

.crumb {
    font-size: 13px;
    font-weight: 500;
    color: var(--muted);
    margin-left: 6px;
}
.crumb::before { content: '/'; margin-right: 6px; color: var(--faint); }

/* --- message viewer ------------------------------------------------------ */

.modal-back {
    position: fixed;
    inset: 0;
    z-index: 90;
    background: rgba(3, 6, 12, .68);
    backdrop-filter: blur(3px);
    display: grid;
    place-items: center;
    padding: 24px;
}
.modal {
    width: 100%;
    max-width: 760px;
    max-height: 86vh;
    display: flex;
    flex-direction: column;
    border-radius: var(--radius);
    border: 1px solid var(--line-strong);
    background: #10141f;
    box-shadow: var(--shadow);
    overflow: hidden;
}
.modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--line);
}
.modal-head h2 { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.4; }
.modal-body { padding: 16px; overflow: auto; }

/* The delete confirmation. Deliberately plain: a destructive dialog should
   read like a sentence, not a form. */
.confirm-filters {
    list-style: none;
    margin: 4px 0 14px;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.confirm-filters li {
    font-size: 11.5px;
    color: var(--muted);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: 5px;
    padding: 2px 8px;
}
.confirm-label {
    display: block;
    margin: 14px 0 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
}
#confirm-delete { width: 100%; letter-spacing: .08em; }

/* Per-row delete. Quiet until the row is under the cursor: a destructive
   control on every row should not be the loudest thing in the table. */
.row-actions { width: 1%; text-align: right; white-space: nowrap; }
.row-delete {
    opacity: 0;
    color: var(--muted);
    transition: opacity .15s var(--ease), color .15s var(--ease), background .15s var(--ease);
}
tr:hover .row-delete,
.row-delete:focus-visible { opacity: 1; }
.row-delete:hover { color: var(--bad); background: var(--bad-soft); }

/* Touch has no hover, so the control must always be reachable there. */
@media (hover: none) {
    .row-delete { opacity: 1; }
}
.modal-foot {
    padding: 12px 16px;
    border-top: 1px solid var(--line);
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}
.mail-meta { display: grid; grid-template-columns: 78px minmax(0, 1fr); gap: 6px 12px; margin-bottom: 14px; }
.mail-meta dt { color: var(--muted); font-size: 12px; }
.mail-meta dd { margin: 0; font-size: 12.5px; word-break: break-word; }
.mail-body {
    margin: 0;
    padding: 14px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--line);
    background: rgba(0, 0, 0, .28);
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--text);
}
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover td { background: rgba(255, 255, 255, .04); }

/* ------------------------------------------------------- one call, opened */

/* A row in either call table opens this. It lives in the shared stylesheet
   rather than the dashboard's own, because the Reports table uses it too and
   only the dashboard loads dashboard.css. Tokens are the shared ones, so the
   panel follows whatever theme the page is wearing. */
.modal-call { max-width: 640px; width: min(92vw, 640px); }
.modal-call .modal-body { max-height: 68vh; }

.cd-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px 16px;
    margin-bottom: 4px;
}
.cd-field { min-width: 0; }
.cd-label {
    font-size: 8.5px;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 2px;
}
.cd-value { font-size: 12px; color: var(--text); overflow-wrap: anywhere; }
.cd-value.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; }

.cd-head {
    margin: 14px 0 5px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .10em;
    text-transform: uppercase;
    color: var(--muted);
}

.cd-reason { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--text); }

/* Set apart, so it is obviously the caller's words rather than the model's
   summary of them. */
.cd-quote {
    margin: 8px 0 0;
    padding: 7px 11px;
    border-left: 2px solid var(--accent);
    background: var(--surface-2);
    border-radius: 0 6px 6px 0;
    font-size: 12px;
    font-style: italic;
    color: var(--text);
}

.cd-signals { display: flex; flex-wrap: wrap; gap: 6px; }

.cd-error {
    margin: 0;
    padding: 7px 11px;
    border-radius: 6px;
    font-size: 12px;
    color: var(--bad);
    background: var(--bad-soft);
    border: 1px solid var(--line);
}

.cd-transcript {
    margin: 0;
    padding: 10px 12px;
    max-height: 240px;
    overflow: auto;
    border-radius: 8px;
    border: 1px solid var(--line);
    background: rgba(0, 0, 0, 0.28);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11.5px;
    line-height: 1.6;
    color: var(--text);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* A row that opens something should say so before it is clicked. */
tr.clickable { cursor: pointer; }
tr.clickable:hover > td { background: var(--surface-2); }
tr.clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ------------------------------------------------------------ chart tooltip */

/* One element, reused by every chart. Fixed so the script can position it from
   clientX/clientY, and pointer-events off so it can never sit between the
   cursor and the shape it describes — that would make it flicker. */
.chart-tip {
    position: fixed;
    z-index: 120;
    pointer-events: none;
    min-width: 128px;
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid var(--line);
    background: rgba(10, 14, 24, 0.96);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
    font-size: 11.5px;
    line-height: 1.45;
    color: var(--text);
}
.chart-tip[hidden] { display: none; }

.tip-head {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-bottom: 5px;
    padding-bottom: 5px;
    border-bottom: 1px solid var(--line);
    font-weight: 600;
}
.tip-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }

.tip-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
}
.tip-row span { color: var(--muted); }
.tip-row b { font-weight: 600; font-variant-numeric: tabular-nums; }

/* The hovered segment stays lit while the others recede. */
.chart-svg .pie-slice { transition: opacity .12s var(--ease); }
