/* ============================================================
   defaudit — design system for ISA Scanner
   Premium enterprise security platform · Black + Violet
   Ported from the Claude Design prototype and bridged onto
   Bootstrap 5.3.7 so every server-rendered screen adopts it.
   ============================================================ */

/* ===================== 1. TOKENS ===================== */
:root {
  --font-sans: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --r-xs: 5px;  --r-sm: 7px;  --r: 10px;  --r-md: 12px;
  --r-lg: 16px; --r-xl: 22px; --r-pill: 999px;

  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px;
  --s9: 48px; --s10: 64px;

  --sev-critical: #f43f5e;
  --sev-high:     #fb7a3c;
  --sev-medium:   #f0b429;
  --sev-low:      #38bdf8;
  --sev-info:     #8b93a0;

  --ok:      #2bb673;
  --warn:    #f0b429;
  --danger:  #f43f5e;
  --running: var(--accent);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --fast: 120ms;
  --med: 200ms;

  --radius-scale: 1;
}

/* ---------------- DARK (default / primary) ---------------- */
:root,
[data-theme="dark"] {
  --bg:          #0a0b0d;
  --bg-subtle:   #0d0e11;
  --bg-inset:    #070809;
  --surface:     #141518;
  --surface-2:   #1a1c20;
  --surface-3:   #212329;
  --border:      #24262c;
  --border-strong:#31343b;
  --border-faint:#1a1c20;

  --text:        #f3f4f6;
  --text-muted:  #9ca3af;
  --text-faint:  #6b7079;
  --text-inverse:#0a0b0d;

  --accent:        #7c5cff;
  --accent-hover:  #8e72ff;
  --accent-press:  #6a47f0;
  --accent-fg:     #ffffff;
  --accent-subtle: rgba(124,92,255,0.14);
  --accent-border: rgba(124,92,255,0.34);
  --accent-glow:   rgba(124,92,255,0.24);
  --accent-grad:   linear-gradient(135deg, #8e72ff, #6a47f0);

  --sev-low: #4cc3ff;

  --shadow-sm: 0 1px 2px rgba(0,0,0,0.4);
  --shadow:    0 4px 16px rgba(0,0,0,0.35), 0 1px 2px rgba(0,0,0,0.4);
  --shadow-lg: 0 18px 48px rgba(0,0,0,0.5), 0 4px 12px rgba(0,0,0,0.4);
  --shadow-pop:0 12px 40px rgba(0,0,0,0.55);

  --grid-line: rgba(255,255,255,0.035);
  --chart-grid: #20232a;
  color-scheme: dark;
}

/* ---------------- LIGHT ---------------- */
[data-theme="light"] {
  --bg:          #f6f7f9;
  --bg-subtle:   #eef0f3;
  --bg-inset:    #e9ebef;
  --surface:     #ffffff;
  --surface-2:   #f7f8fa;
  --surface-3:   #eef0f3;
  --border:      #e6e8ec;
  --border-strong:#d4d8de;
  --border-faint:#eef0f3;

  --text:        #0b0c0e;
  --text-muted:  #5b626c;
  --text-faint:  #8b919b;
  --text-inverse:#ffffff;

  --accent:        #6d28d9;
  --accent-hover:  #5b21b6;
  --accent-press:  #4c1d95;
  --accent-fg:     #ffffff;
  --accent-subtle: rgba(109,40,217,0.08);
  --accent-border: rgba(109,40,217,0.24);
  --accent-glow:   rgba(109,40,217,0.16);
  --accent-grad:   linear-gradient(135deg, #7c4ddb, #6d28d9);

  --sev-low: #2196d6;

  --shadow-sm: 0 1px 2px rgba(16,24,40,0.06);
  --shadow:    0 6px 20px rgba(16,24,40,0.08), 0 1px 2px rgba(16,24,40,0.05);
  --shadow-lg: 0 20px 48px rgba(16,24,40,0.14), 0 4px 10px rgba(16,24,40,0.06);
  --shadow-pop:0 12px 40px rgba(16,24,40,0.16);

  --grid-line: rgba(10,12,16,0.03);
  --chart-grid: #eceef2;
  color-scheme: light;
}

/* ===================== 2. BOOTSTRAP BRIDGE =====================
   Remap Bootstrap 5.3 design variables onto defaudit tokens so
   stock Bootstrap markup (cards, tables, forms, badges, alerts,
   dropdowns, modals…) renders in the defaudit theme everywhere. */
:root,
[data-theme] {
  --bs-body-font-family: var(--font-sans);
  --bs-body-bg: var(--bg);
  --bs-body-color: var(--text);
  --bs-secondary-color: var(--text-muted);
  --bs-tertiary-color: var(--text-faint);
  --bs-emphasis-color: var(--text);
  --bs-secondary-bg: var(--surface-2);
  --bs-tertiary-bg: var(--surface-3);
  --bs-border-color: var(--border);
  --bs-border-color-translucent: var(--border);
  --bs-link-color: var(--accent);
  --bs-link-color-rgb: 124,92,255;
  --bs-link-hover-color: var(--accent-hover);
  --bs-heading-color: var(--text);
  --bs-primary: var(--accent);
  --bs-primary-rgb: 124,92,255;
  --bs-code-color: #e0769a;
  --bs-font-monospace: var(--font-mono);
  --bs-emphasis-color-rgb: 243,244,246;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv01","ss01";
}
h1,h2,h3,h4,h5,h6 { color: var(--text); font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }
::selection { background: var(--accent-glow); }
hr, .dropdown-divider { border-color: var(--border); color: var(--border); opacity: 1; }
code, kbd, samp, pre { font-family: var(--font-mono); }
code { color: #e0769a; }
.font-monospace { font-family: var(--font-mono) !important; }
.text-muted { color: var(--text-muted) !important; }
.text-dark { color: var(--text) !important; }
.text-body { color: var(--text) !important; }
small, .small { font-size: 0.86em; }

/* scrollbar */
*::-webkit-scrollbar { width: 11px; height: 11px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 3px solid var(--bg); }
*::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

/* focus */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-xs); }

/* ---- Bootstrap: layout helpers ---- */
.bg-light { background-color: var(--surface-2) !important; color: var(--text) !important; }
.bg-white { background-color: var(--surface) !important; }
.bg-body, .bg-body-tertiary, .bg-body-secondary { background-color: var(--surface) !important; }
.border, .border-top, .border-bottom, .border-start, .border-end { border-color: var(--border) !important; }

/* ---- Bootstrap: cards ---- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: calc(var(--r-md) * var(--radius-scale));
  box-shadow: var(--shadow-sm);
  color: var(--text);
}
.card.shadow-sm, .card.shadow { box-shadow: var(--shadow-sm) !important; }
.card-header {
  background: transparent;
  border-bottom: 1px solid var(--border-faint);
  padding: var(--s4) var(--s5);
  font-weight: 600;
  color: var(--text);
}
.card-header .card-title { color: var(--text); }
.card-body { padding: var(--s5); }
.card-title { font-size: 14px; font-weight: 600; }
.card-footer { background: var(--surface-2); border-top: 1px solid var(--border-faint); }
.card.border-0 { border: 1px solid var(--border) !important; }
/* neutralise hard-coded light backgrounds/borders in legacy templates */
.card[style*="linear-gradient"], .card[style*="#ffffff"], .card[style*="#f8f9fa"] {
  background: var(--surface) !important;
}
.card-header[style*="linear-gradient"] { background: var(--surface-2) !important; }
.card-header[style*="linear-gradient"] .card-title { color: var(--text) !important; }

/* ---- Bootstrap: buttons ---- */
.btn {
  --bs-btn-border-radius: calc(var(--r-sm) * var(--radius-scale));
  border-radius: calc(var(--r-sm) * var(--radius-scale));
  font-weight: 500;
  font-size: 13.5px;
  letter-spacing: -0.01em;
  padding: 8px 14px;
  /* Neutral default — mirrors the prototype's bare .btn. Variant classes
     (.btn-primary, .btn-outline-*, .btn--ghost…) are defined later and win. */
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  transition: background var(--fast) var(--ease), border-color var(--fast), transform var(--fast), box-shadow var(--fast);
}
.btn:hover { background: var(--surface-3); border-color: var(--text-faint); color: var(--text); }
.btn:active { transform: translateY(0.5px); }
.btn-primary {
  background: var(--accent); border-color: transparent; color: var(--accent-fg);
  box-shadow: 0 1px 0 rgba(255,255,255,0.12) inset, 0 2px 8px var(--accent-glow);
}
.btn-primary:hover, .btn-primary:focus { background: var(--accent-hover); border-color: transparent; color: var(--accent-fg); }
.btn-primary:active, .btn-primary:disabled { background: var(--accent-press); border-color: transparent; color: var(--accent-fg); }
.btn-secondary {
  background: var(--surface-2); border-color: var(--border-strong); color: var(--text);
}
.btn-secondary:hover { background: var(--surface-3); border-color: var(--text-faint); color: var(--text); }
.btn-outline-primary { color: var(--accent); border-color: var(--accent-border); background: transparent; }
.btn-outline-primary:hover { background: var(--accent); border-color: transparent; color: var(--accent-fg); }
.btn-outline-secondary { color: var(--text-muted); border-color: var(--border-strong); background: transparent; }
.btn-outline-secondary:hover { background: var(--surface-2); border-color: var(--text-faint); color: var(--text); }
.btn-success { background: var(--ok); border-color: transparent; color: #fff; }
.btn-success:hover { background: color-mix(in srgb, var(--ok) 86%, white); border-color: transparent; color: #fff; }
.btn-outline-success { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, transparent); }
.btn-outline-success:hover { background: var(--ok); color: #fff; border-color: transparent; }
.btn-warning { background: var(--warn); border-color: transparent; color: #1a1205; }
.btn-warning:hover { background: color-mix(in srgb, var(--warn) 88%, white); color: #1a1205; }
.btn-danger { background: var(--danger); border-color: transparent; color: #fff; }
.btn-danger:hover { background: color-mix(in srgb, var(--danger) 88%, white); color: #fff; }
.btn-outline-danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.btn-outline-danger:hover { background: var(--danger); color: #fff; border-color: transparent; }
.btn-outline-info { color: var(--sev-low); border-color: color-mix(in srgb, var(--sev-low) 40%, transparent); }
.btn-outline-info:hover { background: var(--sev-low); color: #06222e; border-color: transparent; }
.btn-light { background: var(--surface-2); border-color: var(--border-strong); color: var(--text); }
.btn-light:hover { background: var(--surface-3); color: var(--text); }
.btn-link { background: transparent; border-color: transparent; color: var(--accent); text-decoration: none; }
.btn-link:hover { background: var(--surface-2); color: var(--accent-hover); }
.btn-sm { padding: 5px 11px; font-size: 12.5px; }
.btn-lg { padding: 11px 20px; font-size: 15px; }

/* ---- Bootstrap: forms ---- */
.form-control, .form-select {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: 13.5px;
  padding: 8px 12px;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.form-control::placeholder { color: var(--text-faint); }
.form-control:focus, .form-select:focus {
  background: var(--surface);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
  color: var(--text);
}
.form-control:disabled, .form-control[readonly] { background: var(--surface-2); color: var(--text-muted); opacity: 1; }
.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px 16px;
  padding-right: 34px;
}
.form-select option { background: var(--surface); color: var(--text); }
.form-label { font-size: 12.5px; font-weight: 550; color: var(--text); margin-bottom: 6px; }
.form-text { color: var(--text-faint); font-size: 12px; }
.input-group-text { background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text-muted); }
.form-check-input { background-color: var(--surface-2); border-color: var(--border-strong); }
.form-check-input:checked { background-color: var(--accent); border-color: var(--accent); }
.form-check-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.form-check-label { color: var(--text); }

/* ---- Bootstrap: tables ---- */
.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--text);
  --bs-table-border-color: var(--border-faint);
  --bs-table-hover-bg: var(--surface-2);
  --bs-table-hover-color: var(--text);
  --bs-table-striped-bg: var(--surface-2);
  --bs-table-striped-color: var(--text);
  color: var(--text);
  font-size: 13.5px;
  border-color: var(--border-faint);
}
.table thead th {
  text-align: left; font-size: 11.5px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--text-faint); padding: 12px 16px; border-bottom: 1px solid var(--border);
  background: transparent;
}
.table tbody td, .table tbody th { padding: 13px 16px; border-bottom: 1px solid var(--border-faint); vertical-align: middle; color: var(--text); }
.table > :not(caption) > * > * { background: transparent; box-shadow: none; }

/* Compact variant: tighter cells so wide result tables fit the page width */
.table-sm { font-size: 12.5px; }
.table-sm thead th { padding: 8px 10px; font-size: 11px; }
.table-sm tbody td, .table-sm tbody th { padding: 7px 10px; }
.table-sm code, .table-sm .mono { font-size: 11.5px; }
.table-sm .badge { font-size: 10.5px; padding: 3px 7px; }

/* ---- Bootstrap: badges ---- */
.badge {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.01em;
  border-radius: var(--r-pill); padding: 4px 9px;
}
.badge.bg-primary { background: var(--accent-subtle) !important; color: var(--accent) !important; border: 1px solid var(--accent-border); }
.badge.bg-secondary { background: var(--surface-3) !important; color: var(--text-muted) !important; }
.badge.bg-success { background: color-mix(in srgb, var(--ok) 15%, transparent) !important; color: var(--ok) !important; border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent); }
.badge.bg-danger { background: color-mix(in srgb, var(--danger) 15%, transparent) !important; color: var(--danger) !important; border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent); }
.badge.bg-warning { background: color-mix(in srgb, var(--warn) 15%, transparent) !important; color: var(--warn) !important; border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent); }
.badge.bg-info { background: color-mix(in srgb, var(--sev-low) 15%, transparent) !important; color: var(--sev-low) !important; border: 1px solid color-mix(in srgb, var(--sev-low) 30%, transparent); }

/* ---- Bootstrap: alerts ---- */
.alert { border-radius: var(--r); border: 1px solid var(--border-strong); background: var(--surface); font-size: 13.5px; padding: 13px 15px; color: var(--text); }
.alert-info { border-color: var(--accent-border); background: var(--accent-subtle); color: var(--text); }
.alert-success { border-color: color-mix(in srgb, var(--ok) 35%, transparent); background: color-mix(in srgb, var(--ok) 9%, transparent); color: var(--text); }
.alert-warning { border-color: color-mix(in srgb, var(--warn) 38%, transparent); background: color-mix(in srgb, var(--warn) 10%, transparent); color: var(--text); }
.alert-danger { border-color: color-mix(in srgb, var(--danger) 38%, transparent); background: color-mix(in srgb, var(--danger) 9%, transparent); color: var(--text); }
.alert-secondary { border-color: var(--border-strong); background: var(--surface-2); color: var(--text-muted); }
/* Bootstrap pins the dismiss button to the alert's top-right corner and pads it
   by 1.25rem vertically, which centres the glyph against Bootstrap's own 1rem
   alert padding. Ours is 13px, so the button is taller than the alert it sits in
   and the glyph lands below the middle. Anchor it to the vertical centre instead,
   and reserve room for it on the right — our .alert padding above otherwise
   overrides Bootstrap's padding-right and lets long text run under the button. */
.alert-dismissible { padding-right: 40px; }
.alert-dismissible .btn-close { top: 50%; right: 7px; transform: translateY(-50%); padding: 8px; }

/* ---- Bootstrap: dropdowns ---- */
.dropdown-menu {
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg); padding: 6px; color: var(--text);
}
.dropdown-item { color: var(--text); border-radius: var(--r-sm); padding: 8px 11px; font-size: 13.5px; }
.dropdown-item:hover, .dropdown-item:focus { background: var(--surface-2); color: var(--text); }
.dropdown-item.active, .dropdown-item:active { background: var(--accent); color: var(--accent-fg); }

/* ---- Bootstrap: modals ---- */
.modal-content { background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-lg); box-shadow: var(--shadow-lg); color: var(--text); }
.modal-header { border-bottom: 1px solid var(--border-faint); }
.modal-footer { border-top: 1px solid var(--border-faint); background: var(--surface-2); }
.modal-backdrop.show { opacity: 0.55; }
.btn-close { filter: invert(1) grayscale(1) brightness(1.6); }
[data-theme="light"] .btn-close { filter: none; }
/* Bootstrap marks focus with a 4px box-shadow ring. The invert() above turns
   that translucent blue into a pale block around the glyph, so clicking the
   button flashes what looks like a stray white rectangle. Drop the ring and let
   the glyph carry the state instead: it sits dimmed and brightens to full on
   hover and focus alike, so the interaction still reads. */
.btn-close {
  --bs-btn-close-focus-shadow: none;
  --bs-btn-close-hover-opacity: 1;
  transition: opacity 0.15s ease-in-out;
}

/* ---- Bootstrap: list groups ---- */
.list-group-item { background: transparent; border-color: var(--border-faint); color: var(--text); }

/* ---- Bootstrap: progress ---- */
.progress { background: var(--surface-3); border-radius: 999px; height: 6px; }
.progress-bar { background: var(--accent); }

/* ---- Bootstrap: nav tabs / pills ---- */
.nav-tabs { border-bottom: 1px solid var(--border); }
.nav-tabs .nav-link { color: var(--text-muted); border: none; font-weight: 500; }
.nav-tabs .nav-link:hover { color: var(--text); border: none; }
.nav-tabs .nav-link.active { color: var(--text); background: transparent; border: none; border-bottom: 2px solid var(--accent); }

/* ===================== 3. COMPONENTS ===================== */
.mono { font-family: var(--font-mono); font-feature-settings: "tnum"; }
.tnum { font-variant-numeric: tabular-nums; }
/* timestamp: time leads, date trails — always one line */
.ts { display: inline-flex; align-items: baseline; gap: 6px; flex-shrink: 0; white-space: nowrap; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.ts__t { font-weight: 600; color: var(--text-muted); }
.ts__d { font-size: 0.9em; color: var(--text-faint); }
.u-mut { color: var(--text-muted); }
.u-faint { color: var(--text-faint); }
.u-row { display: flex; align-items: center; }
.u-col { display: flex; flex-direction: column; }
.u-gap1 { gap: var(--s1); } .u-gap2 { gap: var(--s2); }
.u-gap3 { gap: var(--s3); } .u-gap4 { gap: var(--s4); }
.u-grow { flex: 1; }
.u-spread { display: flex; align-items: center; justify-content: space-between; }
.u-wrap { flex-wrap: wrap; }
.u-center { align-items: center; }

/* defaudit button (used in rewritten screens) */
.btn.btn--primary { background: var(--accent); border-color: transparent; color: var(--accent-fg);
  box-shadow: 0 1px 0 rgba(255,255,255,0.12) inset, 0 2px 8px var(--accent-glow); }
.btn.btn--primary:hover { background: var(--accent-hover); }
.btn.btn--ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn.btn--ghost:hover { background: var(--surface-2); color: var(--text); }
.btn.btn--block { width: 100%; }

/* badges: severity */
.badge.sev { display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px;
  border-radius: var(--r-pill); font-size: 11.5px; font-weight: 600; border: 1px solid transparent;
  --c: var(--sev-info); color: var(--c);
  background: color-mix(in srgb, var(--c) 13%, transparent);
  border-color: color-mix(in srgb, var(--c) 28%, transparent); }
.badge.sev .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
/* Modifiers use a 2-class selector so they match the specificity of the
   `.badge.sev` default `--c` above; otherwise that default would win and every
   vulnerability/severity tag would render in the gray info colour. */
.sev.sev--critical { --c: var(--sev-critical); }
.sev.sev--high { --c: var(--sev-high); }
.sev.sev--medium { --c: var(--sev-medium); }
.sev.sev--low { --c: var(--sev-low); }
.sev.sev--info { --c: var(--sev-info); }
.sev.sev--solid { background: var(--c); color: #fff; border-color: transparent; }
.sev.sev--zero { --c: var(--text-faint); opacity: 0.55; }

/* status badges */
/* flex-shrink: 0 keeps the pill at its natural width inside the flex rows of the
   scan lists — it used to be repeated as an inline style on individual badges,
   which the shared "status_badge" block cannot carry. */
.badge.status { display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px;
  border-radius: var(--r-pill); font-size: 11.5px; font-weight: 600; border: 1px solid transparent;
  flex-shrink: 0;
  --c: var(--text-faint); color: var(--c);
  background: color-mix(in srgb, var(--c) 12%, transparent);
  border-color: color-mix(in srgb, var(--c) 26%, transparent); }
.badge.status { text-transform: capitalize; }
.badge.status .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
/* 2-class selectors so the status colour wins over the `.badge.status` default. */
.status.status--running { --c: var(--accent); }
.status--running .dot { animation: da-pulse 1.2s var(--ease) infinite; }
.status.status--completed { --c: var(--ok); }
/* Completed, but one or more tools failed — amber to signal partial coverage. */
.status.status--completed_with_errors { --c: var(--warn); }
.status.status--queued, .status.status--pending { --c: var(--warn); }
/* Pulse the dot while a scan waits (ISA-455): a static badge read as "the
   system is stuck", so both waiting states animate to signal it is alive. */
.status--queued .dot,
.status--pending .dot { animation: da-pulse 1.2s var(--ease) infinite; }
.status.status--failed { --c: var(--danger); }
.status.status--idle, .status.status--cancelled { --c: var(--text-faint); }
@keyframes da-pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.4; transform: scale(0.7); } }

/* tech chips */
.chip { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 9px;
  border-radius: var(--r-xs); font-size: 12px; font-weight: 500;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted); }
.chip .tk { width: 9px; height: 9px; border-radius: 2.5px; }

/* card helpers */
.card--pad { padding: var(--s5); }
.card--hover { transition: border-color var(--med), transform var(--med), box-shadow var(--med); cursor: pointer; }
.card--hover:hover { border-color: var(--border-strong); box-shadow: var(--shadow); transform: translateY(-2px); }
.scan-list-item { transition: border-color var(--fast), box-shadow var(--fast), transform var(--fast); }
.scan-list-item:hover { border-color: var(--border-strong); box-shadow: var(--shadow); transform: translateY(-1px); }
.da-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
  padding: var(--s4) var(--s5); border-bottom: 1px solid var(--border-faint); }
.da-card__title { font-size: 14px; font-weight: 600; }
.da-card__sub { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; }

/* KPI cards */
.kpi { position: relative; overflow: hidden; }
.kpi__label { font-size: 12.5px; color: var(--text-muted); font-weight: 500; display: flex; align-items: center; gap: 7px; }
.kpi__value { font-size: 32px; font-weight: 650; letter-spacing: -0.03em; margin-top: 10px; font-variant-numeric: tabular-nums; line-height: 1; }
.kpi__value .unit { font-size: 15px; color: var(--text-faint); font-weight: 500; margin-left: 3px; }
.kpi__foot { margin-top: 12px; display: flex; align-items: center; gap: 7px; font-size: 12px; }
.kpi__ico { width: 34px; height: 34px; border-radius: var(--r-sm); display: grid; place-items: center;
  background: var(--accent-subtle); color: var(--accent); border: 1px solid var(--accent-border); }
.trend-up { color: var(--ok); } .trend-down { color: var(--danger); }
.trend-up.bad { color: var(--danger); } .trend-down.good { color: var(--ok); }

/* table helpers */
.tbl { width: 100%; border-collapse: collapse; font-size: 13.5px; color: var(--text); }
.tbl thead th { text-align: left; font-size: 11.5px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--text-faint); padding: 10px 16px; border-bottom: 1px solid var(--border); }
.tbl tbody td { padding: 13px 16px; border-bottom: 1px solid var(--border-faint); vertical-align: middle; }
.tbl tbody tr { transition: background var(--fast); }
.tbl tbody tr:hover { background: var(--surface-2); }
.tbl tbody tr:last-child td { border-bottom: none; }
.tbl--clickable tbody tr { cursor: pointer; }
.tbl .num { font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
.cell-strong { font-weight: 600; color: var(--text); }
.cell-mut { color: var(--text-muted); }

/* An unread notification row. The accent stripe is what separates it from a
   read one at a glance; the tinted background is deliberately faint so a page
   of unread rows does not read as a page of warnings. */
.notif--unread > td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
.notif--unread { background: color-mix(in srgb, var(--accent) 5%, transparent); }

/* inputs (defaudit native) */
.field { display: flex; flex-direction: column; gap: 6px; }
.field__label { font-size: 12.5px; font-weight: 550; color: var(--text); }
.field__hint { font-size: 12px; color: var(--text-faint); }
.input, .select, .textarea {
  height: 38px; padding: 0 12px; width: 100%;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); color: var(--text); font-size: 13.5px;
  transition: border-color var(--fast), box-shadow var(--fast); }
.textarea { height: auto; padding: 10px 12px; resize: vertical; min-height: 84px; }
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.input::placeholder, .textarea::placeholder { color: var(--text-faint); }
.input--mono { font-family: var(--font-mono); }
.select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; padding-right: 34px; }
.input-grp { display: flex; align-items: center; gap: 8px; height: 38px; padding: 0 12px;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm); }
.input-grp:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.input-grp input { border: none; background: transparent; outline: none; height: 100%; flex: 1; color: var(--text); font-size: 13.5px; }
.input-grp svg { width: 16px; height: 16px; color: var(--text-faint); flex-shrink: 0; }

/* toggle switch */
.switch { position: relative; width: 38px; height: 22px; border-radius: 999px; background: var(--surface-3);
  border: 1px solid var(--border-strong); cursor: pointer; transition: background var(--fast), border-color var(--fast); flex-shrink: 0; display: inline-block; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--text-muted); transition: transform var(--fast) var(--ease), background var(--fast); }
.switch[data-on="true"] { background: var(--accent); border-color: transparent; }
.switch[data-on="true"]::after { transform: translateX(16px); background: #fff; }

/* segmented control */
.seg { display: inline-flex; padding: 3px; gap: 2px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
.seg a, .seg button { height: 28px; padding: 0 12px; border: none; background: transparent; color: var(--text-muted);
  font-size: 12.5px; font-weight: 500; border-radius: var(--r-xs); transition: all var(--fast); display: inline-flex; align-items: center; gap: 6px; }
.seg a:hover, .seg button:hover { color: var(--text); }
.seg a[data-active="true"], .seg button[data-active="true"] { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

/* misc */
.divider { height: 1px; background: var(--border-faint); border: none; margin: 0; }
.vr-line { width: 1px; align-self: stretch; background: var(--border); }
.kbd { font-family: var(--font-mono); font-size: 11px; padding: 2px 6px; border-radius: 5px; background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted); }
.tag-count { font-family: var(--font-mono); font-size: 11px; padding: 1px 7px; border-radius: 999px; background: var(--surface-3); color: var(--text-muted); }
.avatar { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 600; color: #fff; flex-shrink: 0; letter-spacing: 0.02em; }
.pbar { height: 6px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.pbar__fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width var(--med) var(--ease); }
.sevbar { display: flex; height: 8px; border-radius: 999px; overflow: hidden; background: var(--surface-3); }
.sevbar > span { display: block; height: 100%; }
.health { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 500; }
.health .dot { width: 7px; height: 7px; border-radius: 50%; }

/* defaudit alert (native) */
.da-alert { display: flex; align-items: flex-start; gap: 12px; padding: 13px 15px; border-radius: var(--r);
  border: 1px solid var(--border-strong); background: var(--surface); font-size: 13.5px; }
.da-alert i, .da-alert svg { font-size: 18px; flex-shrink: 0; margin-top: 1px; }
.da-alert--info { border-color: var(--accent-border); background: var(--accent-subtle); }
.da-alert--info > i, .da-alert--info > svg { color: var(--accent); }
.da-alert--success { border-color: color-mix(in srgb, var(--ok) 35%, transparent); background: color-mix(in srgb, var(--ok) 9%, transparent); }
.da-alert--success > i { color: var(--ok); }
.da-alert__title { font-weight: 600; }
.da-alert__body { color: var(--text-muted); margin-top: 2px; }

/* empty state */
.empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: var(--s9) var(--s5); gap: 10px; }
.empty__ico { width: 52px; height: 52px; border-radius: var(--r-md); display: grid; place-items: center; background: var(--surface-2); border: 1px solid var(--border); color: var(--text-faint); font-size: 22px; }
.empty h3, .empty h4 { font-size: 15px; }
.empty p { font-size: 13px; color: var(--text-muted); max-width: 340px; }

/* tabs (defaudit native) */
.da-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); }
.da-tabs a, .da-tabs button { position: relative; height: 40px; padding: 0 14px; border: none; background: transparent;
  color: var(--text-muted); font-size: 13.5px; font-weight: 500; transition: color var(--fast); display: inline-flex; align-items: center; gap: 7px; }
.da-tabs a:hover { color: var(--text); }
.da-tabs a[data-active="true"] { color: var(--text); }
.da-tabs a[data-active="true"]::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: -1px; height: 2px; background: var(--accent); border-radius: 2px; }

/* code/log boxes */
.logbox { background: var(--bg-inset); border: 1px solid var(--border); border-radius: var(--r); padding: 14px 16px;
  font-family: var(--font-mono); font-size: 12px; line-height: 1.7; max-height: 280px; overflow-y: auto; color: var(--text); }
.logbox .ts { color: var(--text-faint); }
.logbox .ok { color: var(--ok); } .logbox .warn { color: var(--warn); } .logbox .err { color: var(--danger); } .logbox .inf { color: var(--accent); }
.code-snip { background: var(--bg-inset); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 11px 13px; font-family: var(--font-mono); font-size: 12px; margin-top: 10px; overflow-x: auto; color: var(--text); }

/* ===================== 4. APP SHELL / SCREENS ===================== */

/* top navbar */
.nav.da-nav, header.da-nav {
  position: sticky; top: 0; z-index: 50;
  min-height: 58px; display: flex; align-items: center; gap: var(--s5);
  padding: 0 var(--s6);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid var(--border);
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 650; font-size: 15.5px; letter-spacing: -0.03em; color: var(--text); }
.brand__mark { width: 27px; height: 27px; border-radius: 8px; display: grid; place-items: center;
  background: linear-gradient(150deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #0a0b0d));
  box-shadow: 0 2px 8px var(--accent-glow), inset 0 1px 0 rgba(255,255,255,0.25); color: #fff; }
.brand__mark i { font-size: 15px; color: #fff; }
.brand b { font-weight: 650; } .brand .suffix { color: var(--text-faint); font-weight: 500; }

.da-nav__links { display: flex; align-items: center; gap: 2px; margin-left: var(--s4); }
.da-nav__link { display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 12px; border-radius: var(--r-sm);
  color: var(--text-muted); font-size: 13.5px; font-weight: 500; transition: all var(--fast); }
.da-nav__link i { font-size: 15px; opacity: 0.85; }
.da-nav__link:hover { color: var(--text); background: var(--surface-2); }
.da-nav__link.active { color: var(--text); background: var(--surface-2); }
.da-nav__link.active i { color: var(--accent); opacity: 1; }
.da-nav__right { margin-left: auto; display: flex; align-items: center; gap: 10px; }

.icon-btn { width: 34px; height: 34px; display: grid; place-items: center; border-radius: var(--r-sm);
  border: 1px solid transparent; background: transparent; color: var(--text-muted); transition: all var(--fast); }
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn i { font-size: 17px; }

/* Unread counter on a nav icon (the notification bell). It is pinned to the
   icon's top-right corner and sits against the glyph rather than floating away
   from it, so the count reads as part of the bell instead of as a stray badge.
   The ring in the header's own colour keeps the two shapes readable where they
   overlap. min-width plus padding lets "99+" widen the pill without moving it. */
.icon-btn--count { position: relative; }
/* Lock marker for a nav icon the current plan does not include. It occupies the
   same corner as the unread count — the two states are mutually exclusive — and
   is muted rather than red: this is an invitation to upgrade, not an alert. */
.icon-btn__lock { position: absolute; top: 0; right: 0; display: grid; place-items: center;
  width: 14px; height: 14px; border-radius: var(--r-pill);
  background: var(--surface-3); color: var(--text-faint);
  box-shadow: 0 0 0 2px var(--bg); }
.icon-btn__lock i { font-size: 8px; }
.icon-btn__count { position: absolute; top: 0; right: 0; min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: var(--r-pill); background: var(--danger); color: #fff;
  font-size: 9.5px; font-weight: 700; line-height: 15px; text-align: center;
  box-shadow: 0 0 0 2px var(--bg); }

.usermenu { display: flex; align-items: center; gap: 9px; padding: 4px 10px 4px 4px; border-radius: var(--r-pill);
  border: 1px solid var(--border); background: var(--surface); transition: all var(--fast); color: var(--text); }
.usermenu:hover { border-color: var(--border-strong); color: var(--text); }
.usermenu__name { font-size: 12.5px; font-weight: 600; line-height: 1.1; }
.usermenu__role { font-size: 11px; color: var(--text-faint); line-height: 1.1; }

/* page container */
.page { width: 100%; max-width: 1340px; margin: 0 auto; padding: var(--s7) var(--s6) var(--s10); }
.page--wide { max-width: 1500px; }
.page--narrow { max-width: 920px; }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s4); margin-bottom: var(--s6); }
.page-head h1 { font-size: 23px; letter-spacing: -0.035em; }
.page-head .sub { color: var(--text-muted); font-size: 13.5px; margin-top: 5px; }
/* Action cluster on the right of a page header. Every page puts its header
   buttons in here so spacing and alignment are decided once rather than being
   re-invented per template. Note there is no size rule: header buttons are
   always the default .btn size, and importance is carried by the variant
   (.btn-primary for the main action, .btn-outline-* for the rest) — never by
   .btn-sm/.btn-lg. page_head_test.go enforces both halves of that. */
.page-head__actions { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: var(--s2); }
.breadcrumb-da { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-faint); margin-bottom: 14px; white-space: nowrap; }
.breadcrumb-da a { color: var(--text-faint); }
.breadcrumb-da a:hover { color: var(--text-muted); }

/* grids */
.grid { display: grid; gap: var(--s4); }
.kpi-grid { grid-template-columns: repeat(4, 1fr); }
.kpi-grid--3 { grid-template-columns: repeat(3, 1fr); }
.dash-2col { display: grid; grid-template-columns: 1.55fr 1fr; gap: var(--s4); align-items: stretch; }
.dash-3col { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); align-items: stretch; }
/* equal-height rows: cards in a dashboard row stretch to match, so the
   vertical gap between stacked rows stays uniform on both columns */
.dash-2col > .card, .dash-3col > .card { display: flex; flex-direction: column; }
.dash-2col > .card > .card-body, .dash-3col > .card > .card-body { flex: 1 1 auto; }
/* center the donut/severity content vertically when its card is stretched */
.dash-2col > .card > .card-body.card-body--center { display: flex; flex-direction: column; justify-content: center; }
@media (max-width: 1100px) { .kpi-grid { grid-template-columns: repeat(2,1fr); } .dash-2col, .dash-3col { grid-template-columns: 1fr; } }

/* severity legend */
.sevlist { display: flex; flex-direction: column; gap: 2px; }
.sevlist__row { display: flex; align-items: center; gap: 10px; padding: 9px 4px; border-bottom: 1px solid var(--border-faint); }
.sevlist__row:last-child { border-bottom: none; }
.sevlist__dot { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
.sevlist__name { font-size: 13px; font-weight: 500; flex: 1; }
.sevlist__val { font-family: var(--font-mono); font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }
.sevlist__pct { font-size: 11.5px; color: var(--text-faint); width: 42px; text-align: right; font-variant-numeric: tabular-nums; }

/* recent scan rows */
.scanrow { display: flex; align-items: center; gap: 14px; padding: 12px 4px; border-bottom: 1px solid var(--border-faint); transition: background var(--fast); border-radius: 8px; }
.scanrow:hover { background: var(--surface-2); }
.scanrow:last-child { border-bottom: none; }
.scanrow__ico { width: 36px; height: 36px; border-radius: var(--r-sm); display: grid; place-items: center; flex-shrink: 0; background: var(--surface-2); border: 1px solid var(--border); font-size: 16px; }
.scanrow__main { flex: 1; min-width: 0; }
.scanrow__name { font-size: 13.5px; font-weight: 600; }
.scanrow__meta { font-size: 12px; color: var(--text-faint); margin-top: 1px; }

/* quick actions */
.qa { display: flex; flex-direction: column; gap: 8px; }
.qa__btn { display: flex; align-items: center; gap: 12px; padding: 13px 14px; border-radius: var(--r); text-align: left;
  border: 1px solid var(--border); background: var(--surface); transition: all var(--med); color: var(--text); }
.qa__btn:hover { border-color: var(--accent-border); background: var(--accent-subtle); transform: translateX(2px); color: var(--text); }
.qa__btn .ico { width: 36px; height: 36px; border-radius: var(--r-sm); display: grid; place-items: center; flex-shrink: 0; background: var(--accent-subtle); color: var(--accent); border: 1px solid var(--accent-border); font-size: 18px; }
.qa__txt b { font-size: 13.5px; font-weight: 600; display: block; }
.qa__txt span { font-size: 12px; color: var(--text-faint); }

/* project cards */
.proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: var(--s4); }
.projcard { padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.projcard__top { display: flex; align-items: flex-start; gap: 12px; }
.projcard__logo { width: 42px; height: 42px; border-radius: var(--r-sm); display: grid; place-items: center; flex-shrink: 0; background: var(--surface-2); border: 1px solid var(--border); font-weight: 700; font-size: 16px; }
.projcard__name { font-size: 15px; font-weight: 600; letter-spacing: -0.02em; }
.projcard__repo { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 240px; }
.projcard__stats { display: flex; align-items: center; gap: 16px; padding-top: 13px; border-top: 1px solid var(--border-faint); }
.projcard__stat { display: flex; flex-direction: column; gap: 1px; }
.projcard__stat b { font-size: 17px; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.projcard__stat span { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; }
/* A stat with nothing to show — a scan that never finished has no duration —
   renders an em dash. The column is as wide as its label, so the dash would
   otherwise sit against the left edge and read as a clipped value; centring it
   over the label makes it read as "no value". */
.projcard__stat b.is-empty { text-align: center; }

/* project grouping */
.proj-group { margin-bottom: var(--s5); }
.proj-group__head { display: flex; align-items: center; gap: 10px; margin: 22px 0 13px; }
.proj-group__head:first-child, .proj-group:first-child .proj-group__head { margin-top: 4px; }
.proj-group__dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 0%, transparent); }
.proj-group__title { font-size: 13px; font-weight: 650; letter-spacing: -0.01em; color: var(--text); }
.proj-group__rule { flex: 1; height: 1px; background: var(--border-faint); }
.proj-group-row td { background: var(--surface-2) !important; font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.proj-group-row .proj-group__dot { display: inline-block; vertical-align: middle; margin-right: 8px; }

/* stepper / wizard */
.wizard { display: grid; grid-template-columns: 248px 1fr; gap: var(--s7); align-items: start; }
@media (max-width: 900px) { .wizard { grid-template-columns: 1fr; } }
.stepper { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 80px; }
.stepper__item { display: flex; align-items: center; gap: 13px; padding: 11px 12px; border-radius: var(--r); transition: background var(--fast); }
.stepper__num { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; flex-shrink: 0;
  font-size: 12.5px; font-weight: 600; border: 1.5px solid var(--border-strong); color: var(--text-faint); background: var(--surface); transition: all var(--med); }
.stepper__item[data-state="active"] { background: var(--surface-2); }
.stepper__item[data-state="active"] .stepper__num { border-color: var(--accent); color: var(--accent); background: var(--accent-subtle); box-shadow: 0 0 0 4px var(--accent-glow); }
.stepper__item[data-state="done"] .stepper__num { background: var(--accent); border-color: transparent; color: #fff; }
.stepper__lbl b { font-size: 13px; font-weight: 600; display: block; }
.stepper__lbl span { font-size: 11.5px; color: var(--text-faint); }
.stepper__item[data-state="todo"] .stepper__lbl b { color: var(--text-faint); }
.stepper__line { width: 1.5px; height: 8px; background: var(--border); margin-left: 25px; }
.stepper__line[data-done="true"] { background: var(--accent); }
.wizard__panel { min-height: 380px; }
.wizard__foot { display: flex; align-items: center; justify-content: space-between; margin-top: var(--s5); padding-top: var(--s5); border-top: 1px solid var(--border-faint); }

/* horizontal mini stepper (auth setup) */
.hsteps { display: flex; align-items: center; gap: 0; margin-bottom: var(--s6); }
.hsteps__node { display: flex; align-items: center; gap: 10px; }
.hsteps__dot { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 600; border: 1.5px solid var(--border-strong); color: var(--text-faint); background: var(--surface); flex-shrink: 0; }
.hsteps__node[data-state="active"] .hsteps__dot { border-color: var(--accent); color: var(--accent); background: var(--accent-subtle); }
.hsteps__node[data-state="done"] .hsteps__dot { background: var(--accent); border-color: transparent; color: #fff; }
.hsteps__lbl { font-size: 12.5px; font-weight: 500; color: var(--text-muted); white-space: nowrap; }
.hsteps__bar { flex: 1; height: 1.5px; background: var(--border); margin: 0 12px; min-width: 24px; }
.hsteps__bar[data-done="true"] { background: var(--accent); }

/* detection rows */
.detect-row { display: flex; align-items: center; gap: 14px; padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); margin-bottom: 10px; }
.detect-row__bar { flex: 1; max-width: 200px; }
.conf { font-family: var(--font-mono); font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }

/* scan detail */
.scan-layout { display: grid; grid-template-columns: 320px 1fr; gap: var(--s5); align-items: start; }
@media (max-width: 1000px) { .scan-layout { grid-template-columns: 1fr; } }
.tool-step { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r); border: 1px solid var(--border); background: var(--surface); margin-bottom: 8px; transition: all var(--med); }
.tool-step[data-state="running"] { border-color: var(--accent-border); background: var(--accent-subtle); }
.tool-step[data-state="done"] { opacity: 0.78; }
.tool-step__ico { width: 30px; height: 30px; border-radius: var(--r-xs); display: grid; place-items: center; flex-shrink: 0; background: var(--surface-2); border: 1px solid var(--border); }
.tool-step__name { font-size: 13px; font-weight: 600; flex: 1; }
.tool-step__time { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint); }

/* finding */
.finding { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); margin-bottom: 10px; overflow: hidden; transition: border-color var(--fast); }
.finding:hover { border-color: var(--border-strong); }
.finding__head { display: flex; align-items: center; gap: 13px; padding: 14px 16px; cursor: pointer; }
.finding__sevbar { width: 3px; align-self: stretch; border-radius: 3px; flex-shrink: 0; min-height: 36px; }
.finding__title { font-size: 13.5px; font-weight: 600; }
.finding__loc { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint); margin-top: 2px; }
.finding__body { padding: 0 16px 16px 32px; font-size: 13px; color: var(--text-muted); border-top: 1px solid var(--border-faint); padding-top: 14px; }
.finding__body h5 { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); margin-bottom: 5px; }
.remediation { background: color-mix(in srgb, var(--ok) 7%, transparent); border: 1px solid color-mix(in srgb, var(--ok) 22%, transparent); border-radius: var(--r-sm); padding: 11px 13px; margin-top: 12px; }

/* filter bar */
.filterbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: var(--s4); }

/* auth */
.auth-wrap { min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr; }
@media (max-width: 880px) { .auth-wrap { grid-template-columns: 1fr; } .auth-aside { display: none; } }
.auth-aside { position: relative; background: var(--bg-inset); border-right: 1px solid var(--border); overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; padding: 44px; }
.auth-aside__grid { position: absolute; inset: 0; background-image: linear-gradient(var(--grid-line) 1px, transparent 1px), linear-gradient(90deg, var(--grid-line) 1px, transparent 1px); background-size: 34px 34px; -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 40%, #000, transparent); mask-image: radial-gradient(ellipse 80% 70% at 50% 40%, #000, transparent); }
.auth-aside__glow { position: absolute; width: 460px; height: 460px; border-radius: 50%; top: -120px; right: -120px; background: radial-gradient(circle, var(--accent-glow), transparent 70%); filter: blur(20px); }
.auth-main { display: grid; place-items: center; padding: 44px; min-height: 100vh; }
.auth-card { width: 100%; max-width: 388px; }
.auth-card h1 { font-size: 25px; letter-spacing: -0.04em; }
.otp-input { display: flex; gap: 9px; }
.otp-input input { width: 46px; height: 54px; text-align: center; font-family: var(--font-mono); font-size: 22px; font-weight: 600; background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm); color: var(--text); }
.otp-input input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.qr-box { width: 168px; height: 168px; border-radius: var(--r); background: #fff; border: 1px solid var(--border-strong); padding: 12px; flex-shrink: 0; }
.backup-codes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.backup-codes code { font-family: var(--font-mono); font-size: 13px; padding: 9px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-xs); text-align: center; letter-spacing: 0.05em; color: var(--text); }

/* reports */
.report-preview { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.report-preview__head { padding: 28px 32px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.report-cover-mark { width: 40px; height: 40px; border-radius: 9px; display: grid; place-items: center; background: linear-gradient(150deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #0a0b0d)); color: #fff; font-size: 22px; }

/* settings rows */
.set-row { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 16px 0; border-bottom: 1px solid var(--border-faint); }
.set-row:last-child { border-bottom: none; }
.set-row__info b { font-size: 13.5px; font-weight: 600; display: block; }
.set-row__info span { font-size: 12.5px; color: var(--text-faint); }

/* audit log */
.audit-row { display: flex; align-items: center; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--border-faint); font-size: 13px; }
.audit-row__time { font-size: 11.5px; width: 134px; }
/* Fixed width so the details column starts on the same x across every row.
   The longest translated labels (French runs to 38 characters) are ellipsised
   rather than allowed to widen the column; the row's title attribute carries
   the underlying action code. */
.audit-row__action { font-size: 12px; font-weight: 600; width: 210px; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* route fade */
.route-fade { animation: routeIn 280ms var(--ease) both; }
@keyframes routeIn { from { transform: translateY(7px); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .route-fade { animation: none; } }

/* footer */
.da-footer { border-top: 1px solid var(--border); background: var(--bg); color: var(--text-faint); }
.da-footer__inner { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 0; text-align: center; }
.da-footer__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px 22px; }
.da-footer__brand { display: inline-flex; align-items: center; gap: 8px; color: var(--text); font-weight: 650; font-size: 14px; letter-spacing: -0.03em; }
.da-footer__brand b { font-weight: 650; }
.da-footer__brand .suffix { color: var(--text-faint); font-weight: 500; }
.da-footer__org { font-size: 13px; font-weight: 500; color: var(--text-muted); }
.da-footer__link { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--text-muted); text-decoration: none; transition: color var(--fast); }
.da-footer__link:hover, .da-footer__link:focus-visible { color: var(--accent); }
.da-footer__link i { font-size: 14px; opacity: 0.9; }
.da-footer__copy { font-size: 12px; color: var(--text-faint); }
@media (max-width: 576px) {
    .da-footer__inner { padding: 7px 0; gap: 3px; }
    .da-footer__row { flex-wrap: nowrap; gap: 8px; }
    .da-footer__brand { font-size: 12px; }
    .da-footer__org { font-size: 11px; white-space: nowrap; }
    .da-footer__link span { display: none; }
    .da-footer__link i { font-size: 15px; }
    .da-footer__copy { font-size: 10px; }
}

/* ===================== 5. LEGACY POLISH =====================
   Lifts the still-Bootstrap screens toward the defaudit look
   without touching their markup. */
h1.h3 { font-size: 23px !important; letter-spacing: -0.035em; }
h1 { font-size: 23px; letter-spacing: -0.035em; }
h2 { font-size: 19px; }

/* semantic text utilities */
.text-primary { color: var(--accent) !important; }
.text-success { color: var(--ok) !important; }
.text-danger { color: var(--danger) !important; }
.text-warning { color: var(--warn) !important; }
.text-info { color: var(--sev-low) !important; }
.text-white-50 { color: rgba(255,255,255,0.6) !important; }

/* dark badge (used for tool names) → chip-like */
.badge.bg-dark { background: var(--surface-3) !important; color: var(--text) !important; border: 1px solid var(--border-strong); }

/* striped/light table heads */
.table-light, .table .table-light, thead.table-light th { background: var(--surface-2) !important; color: var(--text-faint) !important; }
.table-danger-subtle, tr.table-danger-subtle > * { background: color-mix(in srgb, var(--danger) 8%, transparent) !important; }

/* button groups */
.btn-group > .btn { border-radius: 0; }
.btn-group > .btn:first-child { border-top-left-radius: var(--r-sm); border-bottom-left-radius: var(--r-sm); }
.btn-group > .btn:last-child { border-top-right-radius: var(--r-sm); border-bottom-right-radius: var(--r-sm); }

/* A row action that submits — disable a user, pause a schedule, revoke a token —
   has to wrap its button in a form, and every rule above is a child combinator
   that the wrapper hides the button from. Such a button kept the standalone .btn
   look, fully rounded and full-size, sitting beside square-edged small ones: the
   edit button showed one rounded corner and one square, the toggle next to it
   was rounded on both. Dropping the form out of the layout puts its button back
   in the group's own flex row, and the rules below give it whatever its position
   in the group earns. !important is needed on the display alone, to outrank the
   .d-inline utility these forms carry. */
.btn-group > form { display: contents !important; }
.btn-group > form > .btn { border-radius: 0; margin-left: -1px; }
.btn-group > form:first-child > .btn { margin-left: 0; border-top-left-radius: var(--r-sm); border-bottom-left-radius: var(--r-sm); }
.btn-group > form:last-child > .btn { border-top-right-radius: var(--r-sm); border-bottom-right-radius: var(--r-sm); }
.btn-group-sm > form > .btn { padding: 5px 9px; }

/* ---- Bootstrap: pagination ---- */
/* Re-skin the pager to match the app's buttons: individually rounded, themed
   chips that mirror the neutral .btn (surface fill, strong border, r-sm radius)
   with an accent "active" page like .btn-primary. Without this the shared
   pagination partial fell through to raw Bootstrap — a joined pill with a bright
   blue (#0d6efd) active box and blue Prev/Next links that clashed with the
   dark/light theme. Applies everywhere the partial is used: audit log, scans
   list and scan findings. */
.pagination { gap: 6px; margin: 0; align-items: center; }
.page-item { margin: 0; }
.page-link {
  display: block;
  min-width: 36px;
  text-align: center;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm) !important; /* override Bootstrap's first/last-only rounding */
  margin-left: 0 !important;             /* drop Bootstrap's -1px overlap so the gap shows */
  color: var(--text);
  font-weight: 500;
  font-size: 13px;
  line-height: 1.5;
  padding: 6px 12px;
  transition: background var(--fast) var(--ease), border-color var(--fast), color var(--fast), box-shadow var(--fast);
}
.pagination-sm .page-link { min-width: 32px; padding: 5px 10px; font-size: 12.5px; }
.page-link:hover { background: var(--surface-3); border-color: var(--text-faint); color: var(--text); z-index: 1; }
.page-link:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); z-index: 2; }
.page-item.active .page-link {
  background: var(--accent);
  border-color: transparent;
  color: var(--accent-fg);
  box-shadow: 0 1px 0 rgba(255,255,255,0.12) inset, 0 2px 8px var(--accent-glow);
}
.page-item.disabled .page-link {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text-faint);
  opacity: 0.6;
}

/* preformatted / code blocks */
pre { background: var(--bg-inset); border: 1px solid var(--border); border-radius: var(--r-sm); color: var(--text); padding: 11px 13px; }
pre.bg-light, pre.bg-dark { background: var(--bg-inset) !important; color: var(--text) !important; }
.bg-dark.text-light, pre.bg-dark.text-light { background: var(--bg-inset) !important; color: var(--text) !important; }

/* nav pills (some admin pages) */
.nav-pills .nav-link { color: var(--text-muted); border-radius: var(--r-sm); }
.nav-pills .nav-link.active { background: var(--accent); color: var(--accent-fg); }

/* card-header titles keep weight */
.card-header h5, .card-header .card-title { font-size: 14px; font-weight: 600; margin: 0; }

/* legacy "container-fluid" inside .page: trim doubled top padding */
.page > .container-fluid, .page > .container { padding-left: 0; padding-right: 0; }

/* inputs group addon radius pairing with bootstrap input-group */
.input-group > .form-control:focus { z-index: 3; }

/* accordion (if any) */
.accordion-item { background: var(--surface); border-color: var(--border); }
.accordion-button { background: var(--surface); color: var(--text); }
.accordion-button:not(.collapsed) { background: var(--accent-subtle); color: var(--text); box-shadow: none; }
.accordion-button::after { filter: invert(0.7); }

/* list group hover */
.list-group-item-action:hover { background: var(--surface-2); color: var(--text); }

/* ===================== 6. ACCENT POLISH =====================
   Visual lift centred on the violet accent. Token-driven, so it
   tracks any future --accent change automatically. */

/* primary buttons: subtle accent gradient + lift on hover */
.btn-primary, .btn.btn--primary {
  background: var(--accent-grad, var(--accent));
  box-shadow: 0 1px 0 rgba(255,255,255,0.14) inset, 0 2px 10px var(--accent-glow);
}
.btn-primary:hover, .btn.btn--primary:hover {
  background: var(--accent-grad, var(--accent-hover));
  filter: brightness(1.06);
  box-shadow: 0 1px 0 rgba(255,255,255,0.16) inset, 0 4px 16px var(--accent-glow);
}
.btn-primary:active, .btn.btn--primary:active { filter: brightness(0.97); box-shadow: 0 1px 4px var(--accent-glow); }

/* brand mark: richer violet gradient + glow */
.brand__mark {
  background: var(--accent-grad, var(--accent));
  box-shadow: 0 2px 10px var(--accent-glow), inset 0 1px 0 rgba(255,255,255,0.28);
}

/* active nav item: accent underline indicator */
.da-nav__link.active { position: relative; }
.da-nav__link.active::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: -1px; height: 2px;
  border-radius: 2px; background: var(--accent-grad, var(--accent));
  box-shadow: 0 0 8px var(--accent-glow);
}

/* KPI cards: thin accent top strip (reveals on hover) + accent ring on hover */
.kpi { isolation: isolate; }
.kpi::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--accent-grad, var(--accent));
  opacity: 0; transition: opacity var(--med) var(--ease);
}
.kpi.card--hover:hover { border-color: var(--accent-border); }
.kpi.card--hover:hover::before { opacity: 1; }
.kpi.card--hover:hover .kpi__ico {
  background: var(--accent-grad, var(--accent)); color: #fff; border-color: transparent;
  box-shadow: 0 2px 10px var(--accent-glow);
}
.kpi__ico { transition: background var(--med), color var(--med), border-color var(--med), box-shadow var(--med); }

/* quick-action icon tiles: gradient on hover */
.qa__btn:hover .ico {
  background: var(--accent-grad, var(--accent)); color: #fff; border-color: transparent;
  box-shadow: 0 2px 10px var(--accent-glow);
}
.qa__btn .ico { transition: background var(--med), color var(--med), border-color var(--med), box-shadow var(--med); }

/* segmented / tab active markers pick up the gradient */
.nav-tabs .nav-link.active { border-bottom-color: transparent; box-shadow: inset 0 -2px 0 var(--accent); }

/* ===================== 7. AMBIENT DEPTH & TEXTURE =====================
   Premium "command-center" atmosphere: layered violet glows + a fine
   grid texture fixed to the viewport, plus subtle elevation on surfaces.
   Token-driven and theme-aware. */

/* app backdrop: dual radial glow + hairline grid (fixed, behind everything) */
body {
  background-color: var(--bg);
  background-image:
    radial-gradient(1000px 560px at 78% -12%, var(--accent-glow), transparent 60%),
    radial-gradient(760px 520px at -8% -6%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 58%),
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 100% 100%, 100% 100%, 48px 48px, 48px 48px;
  background-position: 0 0, 0 0, 0 0, 0 0;
  background-attachment: fixed;
  background-repeat: no-repeat, no-repeat, repeat, repeat;
}

/* glass nav floats above the textured backdrop */
.nav.da-nav, header.da-nav {
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: saturate(170%) blur(14px);
  -webkit-backdrop-filter: saturate(170%) blur(14px);
}

/* surfaces gain quiet depth: hairline top highlight + softer elevation */
.card {
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.04);
}
[data-theme="light"] .card { box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.6); }
.card--hover { transition: border-color var(--med) var(--ease), transform var(--med) var(--ease), box-shadow var(--med) var(--ease); }
.card--hover:hover {
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255,255,255,0.05), 0 0 0 1px var(--accent-border);
}

/* card section headers: subtle accent tick before the title */
.da-card__head .da-card__title { position: relative; padding-left: 12px; }
.da-card__head .da-card__title::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 13px; border-radius: 2px; background: var(--accent-grad, var(--accent));
}

/* refined empty-state icon with accent tint */
.empty__ico { color: var(--accent); background: var(--accent-subtle); border-color: var(--accent-border); }

/* page-load orchestration: gentle staggered rise for top-level blocks.
   fill-mode is "backwards" (NOT both/forwards) on purpose: a forwards-filling
   transform/opacity animation would leave .route-fade as a permanent stacking
   context, trapping any position:fixed modal inside it underneath the backdrop. */
.route-fade { animation: daRise 420ms var(--ease) backwards; }
.route-fade > .page-head { animation: daRise 420ms var(--ease) backwards; }
.route-fade > .kpi-grid { animation: daRise 460ms var(--ease) 60ms backwards; }
.route-fade > .dash-2col { animation: daRise 500ms var(--ease) 120ms backwards; }
.route-fade > .dash-2col ~ .dash-2col { animation-delay: 180ms; }
@keyframes daRise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .kpi::before, .kpi__ico, .qa__btn .ico { transition: none; }
  .route-fade, .route-fade > * { animation: none !important; }
  body { background-attachment: scroll; }
}

/* ===================== 8. LAYOUT FIXES & LIST COMPONENTS =====================
   Sticky footer, tighter rhythm, flush in-card tables, plus a few
   reusable "list page" components (stat strip, identity pills, avatars). */

/* sticky footer — keep the footer pinned to the bottom on short pages */
body { min-height: 100dvh; display: flex; flex-direction: column; }
body > main { flex: 1 0 auto; }
.da-footer { flex-shrink: 0; margin-top: 0; }

/* tighter vertical rhythm inside content pages */
.page { padding-bottom: var(--s7); }
.page .mb-4 { margin-bottom: var(--s4) !important; }
.page .mt-4 { margin-top: var(--s4) !important; }
.page .mb-5 { margin-bottom: var(--s6) !important; }
.page .mt-5 { margin-top: var(--s6) !important; }

/* in-card Bootstrap tables sit flush to the card edges (no boxed-in look) */
.card-body:has(> .table-responsive),
.card-body:has(> .table):not(:has(> .table-sm)) {
  padding: 0; overflow: hidden; border-radius: 0 0 var(--r-md) var(--r-md);
}
.card-body:has(> .table-responsive) > .table-responsive { border-radius: inherit; }
.card .table { margin-bottom: 0; }
.card .table tbody tr { transition: background var(--fast); }
.card .table tbody tr:last-child td { border-bottom: none; }
.card .table thead th { background: var(--surface-2); }

/* unify small outline action buttons into a clean segmented group */
.btn-group-sm > .btn { padding: 5px 9px; }
.btn-group .btn.btn-outline-secondary,
.btn-group .btn.btn-outline-primary,
.btn-group .btn.btn-outline-danger,
.btn-group .btn.btn-outline-warning,
.btn-group .btn.btn-outline-success { border-color: var(--border-strong); color: var(--text-muted); background: var(--surface); }
.btn-group .btn.btn-outline-primary:hover { background: var(--accent-subtle); color: var(--accent); border-color: var(--accent-border); }
.btn-group .btn.btn-outline-danger:hover { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 34%, transparent); }
.btn-group .btn.btn-outline-success:hover { background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 34%, transparent); }
.btn-group .btn.btn-outline-warning:hover { background: color-mix(in srgb, var(--warn) 14%, transparent); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 34%, transparent); }

/* sticky info sidebar for two-column form pages */
@media (min-width: 992px) { .side-sticky { position: sticky; top: 78px; } }

/* ---- stat strip: compact KPI row above tables ---- */
.stat-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s3); margin-bottom: var(--s4); }
@media (max-width: 820px) { .stat-strip { grid-template-columns: repeat(2, 1fr); } }
.stat-strip__item {
  display: flex; align-items: center; gap: 13px; padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.04);
  position: relative; overflow: hidden; transition: border-color var(--med) var(--ease), transform var(--med) var(--ease);
}
.stat-strip__item::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--c, var(--accent)); opacity: 0.85;
}
.stat-strip__item:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.stat-strip__ico {
  width: 38px; height: 38px; border-radius: var(--r-sm); display: grid; place-items: center; flex-shrink: 0;
  font-size: 18px; --c: var(--accent); color: var(--c);
  background: color-mix(in srgb, var(--c) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 30%, transparent);
}
.stat-strip__txt { min-width: 0; }
.stat-strip__val { font-size: 22px; font-weight: 650; letter-spacing: -0.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.stat-strip__lbl { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.045em; margin-top: 4px; }
.stat-strip__item.tone-ok      { --c: var(--ok); }
.stat-strip__item.tone-danger  { --c: var(--danger); }
.stat-strip__item.tone-warn    { --c: var(--warn); }
.stat-strip__item.tone-accent  { --c: var(--accent); }
.stat-strip__item.tone-accent .stat-strip__ico { background: var(--accent-grad); color: #fff; border-color: transparent; box-shadow: 0 2px 10px var(--accent-glow); }

/* ---- identity pills (roles, key types, etc.) ---- */
.idpill {
  display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 9px 0 7px;
  border-radius: var(--r-pill); font-size: 11.5px; font-weight: 600; text-transform: capitalize;
  --c: var(--text-muted); color: var(--c); border: 1px solid color-mix(in srgb, var(--c) 28%, transparent);
  background: color-mix(in srgb, var(--c) 13%, transparent);
}
.idpill i { font-size: 12px; }
.idpill--admin   { --c: var(--danger); }
.idpill--manager { --c: var(--warn); }
.idpill--user    { --c: var(--accent); }
.idpill--viewer  { --c: var(--text-faint); }

/* ---- table identity cell: gradient avatar + name/sub ---- */
.tcell { display: flex; align-items: center; gap: 11px; }
.tcell__av {
  width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center; flex-shrink: 0;
  font-size: 13px; font-weight: 700; color: #fff; letter-spacing: 0.02em; text-transform: uppercase;
  background: var(--accent-grad, var(--accent)); box-shadow: inset 0 1px 0 rgba(255,255,255,0.22), 0 2px 8px var(--accent-glow);
}
.tcell__av--muted { background: var(--surface-3); color: var(--text-muted); box-shadow: none; border: 1px solid var(--border-strong); }
.tcell__name { font-weight: 600; font-size: 13.5px; line-height: 1.25; }
.tcell__sub { font-size: 11.5px; color: var(--text-faint); font-family: var(--font-mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 280px; }

/* ---- modal content: wrap long strings so nothing overflows the dialog ---- */
.modal-body { overflow-wrap: anywhere; word-break: break-word; }
.modal-body code { white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-all;
  background: var(--bg-inset); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 1px 6px; color: var(--text); }
.modal-body pre { white-space: pre-wrap; overflow-wrap: anywhere; }
.modal-body a { overflow-wrap: anywhere; word-break: break-all; }
.modal-lg, .modal-xl { --bs-modal-width: min(820px, calc(100vw - 32px)); }
/* finding-detail modal polish */
.modal[id^="finding-"] .modal-body > .row { margin: 0 0 16px; padding-bottom: 14px; border-bottom: 1px solid var(--border-faint); gap: 12px 0; }
.modal[id^="finding-"] .modal-body strong { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); font-weight: 600; margin-bottom: 4px; }
.modal[id^="finding-"] .modal-body > div { margin-bottom: 16px; }
.modal[id^="finding-"] .modal-body p { color: var(--text-muted); margin: 0; line-height: 1.6; }
.modal[id^="finding-"] .modal-body ul { margin: 0; padding-left: 0; list-style: none; }
.modal[id^="finding-"] .modal-body ul li { margin-bottom: 6px; }
.modal-body .badge.bg-light { background: var(--surface-3) !important; color: var(--text) !important; border: 1px solid var(--border-strong); }

/* ---- metric grid (report summary / severity stats) ---- */
.metric-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s3); }
@media (max-width: 560px) { .metric-grid { grid-template-columns: repeat(2, 1fr); } }
.metric {
  text-align: center; padding: 16px 10px;
  background: var(--surface-2); border: 1px solid var(--border-faint);
  border-radius: var(--r); border-top: 2px solid var(--c, var(--accent));
  transition: border-color var(--fast), transform var(--fast) var(--ease);
}
.metric:hover { transform: translateY(-1px); }
.metric__head { display: flex; align-items: center; justify-content: center; gap: 7px; margin-bottom: 9px; font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.metric__head .dot { width: 9px; height: 9px; border-radius: 3px; background: var(--c, var(--accent)); flex-shrink: 0; }
.metric__val { font-size: 26px; font-weight: 680; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1; color: var(--c, var(--text)); }
.metric__sub { font-size: 11px; color: var(--text-faint); margin-top: 6px; display: block; }

/* ---- pricing plan cards ---- */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--s4); align-items: stretch; }
.plan {
  position: relative; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--s6) var(--s5) var(--s5);
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.04);
  transition: transform var(--med) var(--ease), border-color var(--med) var(--ease), box-shadow var(--med) var(--ease);
}
.plan:hover { transform: translateY(-3px); border-color: var(--border-strong); box-shadow: var(--shadow); }
.plan--featured { border-color: var(--accent-border); box-shadow: var(--shadow), 0 0 0 1px var(--accent-border); }
.plan--featured::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-lg); pointer-events: none;
  background: radial-gradient(120% 60% at 50% 0%, var(--accent-glow), transparent 60%); opacity: 0.5; }
.plan--featured:hover { box-shadow: var(--shadow-lg), 0 0 0 1px var(--accent-border); }
.plan > * { position: relative; z-index: 1; }
.plan__badge {
  position: absolute; top: 0; right: 18px; transform: translateY(-50%); z-index: 2;
  background: var(--accent-grad); color: #fff; font-size: 10px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  padding: 4px 11px; border-radius: var(--r-pill); box-shadow: 0 2px 10px var(--accent-glow);
}
.plan__name { font-size: 17px; font-weight: 650; letter-spacing: -0.02em; }
.plan__desc { font-size: 12.5px; color: var(--text-muted); margin-top: 5px; min-height: 34px; line-height: 1.45; }
/* promo banner: sits under the price it explains, so every card's price still
   lands on the same line across the row */
.plan__promo { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
.plan__promo-badge {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--accent-grad); color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 0.03em;
  padding: 3px 9px; border-radius: var(--r-pill); box-shadow: 0 2px 10px var(--accent-glow);
}
.plan__promo-badge i { font-size: 10px; }
.plan__promo-note { font-size: 11.5px; color: var(--text-muted); }
.plan__price { display: flex; align-items: baseline; flex-wrap: wrap; gap: 5px; margin: 14px 0 2px; }
.plan__price-was { font-size: 15px; color: var(--text-faint); text-decoration-thickness: 1px; align-self: center; }
.plan__price b { font-size: 34px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; }
.plan__price b.free { color: var(--ok); }
.plan__price .cur { font-size: 19px; font-weight: 650; align-self: flex-start; margin-top: 4px; }
.plan__price span { font-size: 13px; color: var(--text-faint); }
.plan__divider { height: 1px; background: var(--border-faint); margin: 18px 0; border: none; }
.plan__features { list-style: none; padding: 0; margin: 0 0 20px; display: flex; flex-direction: column; gap: 10px; flex: 1 1 auto; }
.plan__features li { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; color: var(--text); }
.plan__features li i { font-size: 14px; margin-top: 1px; flex-shrink: 0; color: var(--ok); }
.plan__features li.off { color: var(--text-faint); }
.plan__features li.off i { color: var(--text-faint); }
.plan__features li .val { color: var(--text-muted); margin-left: 2px; }
.plan__cta { margin-top: auto; }
@media (max-width: 560px) { .plan-grid { grid-template-columns: 1fr; } }

/* styled bullet lists inside info cards */
.card-body ul.small { padding-left: 0; margin-bottom: 0; list-style: none; }
.card-body ul.small li { position: relative; padding-left: 18px; margin-bottom: 7px; }
.card-body ul.small li::before { content: ""; position: absolute; left: 2px; top: 7px; width: 6px; height: 6px; border-radius: 2px; background: var(--accent); opacity: 0.7; }
.card-body ul.small li:last-child { margin-bottom: 0; }

/* Pre-auth language switcher (login / setup pages, no nav bar) */
.da-lang-switch { position: fixed; top: 16px; right: 16px; z-index: 1050; }

/* ---- submit-button loading state (added by main.js on form submit) ---- */
.loading { position: relative; color: transparent !important; pointer-events: none; }
.loading::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border: 2px solid rgba(255, 255, 255, 0.4); border-top-color: #fff;
  border-radius: 50%; animation: da-spin 0.7s linear infinite;
}
@keyframes da-spin { to { transform: rotate(360deg); } }

/* ============================================================
   Configurable dashboard — per-user widget layout
   The dashboard is a 12-column grid of widgets whose order and
   visibility come from the user's saved layout (user_layouts).
   Spans are fixed per widget in the Go registry; only order and
   visibility are user-editable, so a handful of span classes is
   all the grid needs.
   ============================================================ */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--s4);
  align-items: stretch;
}
/* Width comes from the widget's own --span (twelfths of the grid), set inline
   from the user's saved layout. A custom property rather than a class per width:
   any of the offered widths works without the stylesheet enumerating them, and
   the editor can preview a change by rewriting one property. */
.dash-w { min-width: 0; grid-column: span var(--span, 12); }

/* Cards fill their grid cell so neighbours in a row line up, matching the
   stretch behaviour the old .dash-2col wrapper provided. */
.dash-w > .card { height: 100%; display: flex; flex-direction: column; }
.dash-w > .card > .card-body { flex: 1 1 auto; }

/* Medium screens: --span-md is the width the server picked for this size, so
   narrow widgets pair up instead of shrinking into unreadable columns. */
@media (max-width: 1100px) {
  .dash-w { grid-column: span var(--span-md, 12); }
}
@media (max-width: 640px) {
  .dash-w { grid-column: span 12; }
}

/* ---- layout editor (/dashboard?edit=1) ---- */
.dash-edit__bar {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s3);
  margin-bottom: var(--s4); padding: var(--s3) var(--s4);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.dash-edit__hint { color: var(--text-muted); font-size: 13px; }
/* The editor bar has its own action group: .page-head__actions is the page
   header's wrapper and stays reserved for it (see page_head_test.go). */
.dash-edit__actions { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

/* In edit mode a widget is represented by a placeholder rather than its real
   body, so what the user arranges is what they will get. Each widget is wrapped
   in a dashed frame carrying a settings bar above its live preview. */
.dash-w--cfg {
  display: flex; flex-direction: column;
  border: 1px dashed var(--border-strong);
  border-radius: var(--r);
  background: var(--surface);
  overflow: hidden;
}
.dash-cfg {
  display: flex; align-items: center; gap: var(--s3);
  flex-shrink: 0; padding: var(--s2) var(--s3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  /* transition lives with the drag states below, so the lift is defined once */
}

/* The live preview. Dimmed slightly so the settings bar stays the thing you
   read first, and scaled down a touch so more of the layout fits on screen
   while arranging it. */
.dash-w__preview {
  flex: 1 1 auto; padding: var(--s3);
  opacity: 0.82;
  min-width: 0;
  /* Backstop for the inert attribute: a browser that does not implement it
     would otherwise let a click inside the preview follow a link straight out
     of the editor, losing unsaved changes. This does not cover focus, which is
     why the attribute is still the primary mechanism. */
  pointer-events: none;
}
.dash-w__preview > .card { height: 100%; }
/* Inside the preview the cards are already framed by the widget itself, so drop
   the second border and any hover affordance they would normally show. */
.dash-w__preview .card--hover { transform: none !important; box-shadow: none !important; }
/* The grip is the only thing that starts a drag, and in edit mode the widgets
   otherwise look like the dashboard the user already knows — nothing would say
   which part of them is grabbable. So it is drawn as an accent-tinted control
   with a move cursor rather than as a faint decoration. */
.dash-cfg__grip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex-shrink: 0;
  color: var(--accent);
  background: var(--accent-subtle);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-xs);
  cursor: grab;
  transition: background var(--fast), color var(--fast), border-color var(--fast), transform var(--fast);
  /* Required for pointer-event dragging: without it the browser claims the
     gesture for scrolling on touch devices and no pointermove arrives. */
  touch-action: none;
  /* Touch handles need saying twice. touch-action settles the scrolling, but on
     iOS a press on the handle still raises the selection callout and the text
     magnifier, and either one takes the gesture away mid-drag. The tap
     highlight is the grey flash Safari and Chrome paint over a tapped control,
     which has nothing to highlight on a handle that is about to move. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.dash-cfg__grip:hover { color: var(--accent-fg); background: var(--accent); border-color: var(--accent); transform: translateY(-1px); }
.dash-cfg__grip:active, .dash-grid--dragging .dash-cfg__grip { cursor: grabbing; }
.dash-cfg__grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Opening the editor, every grip pulses a few times so the eye lands on the
   handles before anything else. Three cycles and it settles: a permanent
   animation would be noise for the rest of the session, and the hover and drag
   states carry the affordance from there. */
@keyframes dash-grip-hint {
  0%, 55%, 100% { box-shadow: 0 0 0 0 transparent; }
  20% { box-shadow: 0 0 0 5px var(--accent-glow); }
}
.dash-grid--edit .dash-cfg__grip { animation: dash-grip-hint 1.5s var(--ease) 3; }
.dash-cfg__ico { color: var(--accent); flex-shrink: 0; }
.dash-cfg__vis {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: 12.5px; color: var(--text-muted);
  flex-shrink: 0; cursor: pointer; margin: 0;
}
/* The width select takes the slack so the bar reads as one control strip
   rather than a row of items pushed to the left. */
.dash-cfg__width { flex: 1 1 auto; min-width: 0; margin: 0; }
.dash-cfg__width .form-select { width: 100%; max-width: 160px; font-size: 12.5px; padding-top: 3px; padding-bottom: 3px; }
/* The width selector is a control, not part of the drag surface: the editor
   grid sets user-select:none for Firefox's sake, which would otherwise make the
   select feel inert. */
.dash-cfg__width, .dash-cfg__vis { user-select: auto; -webkit-user-select: auto; }

/* Below this the width select and the visibility checkbox stop fitting side by
   side and the checkbox label would be clipped, so they stack. Keyed off the
   widget's own width, not the viewport's: at any window size some widgets are
   narrow and others are not. */
.dash-grid--edit .dash-w { container-type: inline-size; }
@container (max-width: 300px) {
  .dash-cfg { flex-wrap: wrap; row-gap: var(--s2); }
  .dash-cfg__width { flex-basis: 100%; }
  .dash-cfg__width .form-select { max-width: none; }
}

/* A widget switched off keeps its place and its preview, so you can see what
   you are about to lose, but reads as inactive. */
.dash-w--off { border-style: dotted; opacity: 0.6; }
.dash-w--off .dash-w__preview { opacity: 0.35; filter: grayscale(0.6); }

/* No text selection anywhere in the editor. This is not cosmetic: Firefox does
   not let preventDefault() on pointerdown cancel the underlying mousedown, so
   without it a press on a placeholder starts a selection drag, Gecko takes the
   gesture over and stops delivering pointermove — dragging dies. Chrome does
   cancel it, which is why this only ever broke in Firefox. */
.dash-grid--edit { user-select: none; -webkit-user-select: none; }

/* Reorder animation. main.js drives this with FLIP: it transforms a widget back
   to its previous position and clears the transform, and this transition is what
   carries it across. Grid placement itself is not animatable, so without the
   pair the widgets would simply appear in their new cells. The same transition
   also carries a released card from under the pointer back into its slot.
   The frame's own highlight rides along in the same declaration, because a
   second transition rule on .dash-w would replace this one rather than add
   to it — and transform is what the animation depends on.
   The curve is not var(--ease): that one spends nearly all its travel in the
   first third, which suits a control snapping open and is too abrupt for half a
   dozen cards gliding past each other. This one starts and lands softly.
   position is here so the card being dragged can be raised above the ones it
   travels over (z-index, on .dash-w--dragging below). */
.dash-grid--edit .dash-w {
  position: relative;
  transition: transform 300ms cubic-bezier(0.25, 0.8, 0.25, 1), border-color var(--fast), box-shadow var(--fast), opacity var(--fast);
}

/* Pointing at a widget marks the whole frame, because the frame is the unit
   that moves — the handle only starts the gesture. Not applied mid-drag: with a
   widget in flight the grid is already reflowing under the pointer, and lighting
   up whatever it passes over reads as noise rather than as feedback. */
.dash-grid--edit:not(.dash-grid--dragging) .dash-w--cfg:hover,
.dash-grid--edit:not(.dash-grid--dragging) .dash-w--cfg:focus-within {
  border-color: var(--accent); border-style: solid;
  box-shadow: var(--shadow);
}
.dash-grid--edit:not(.dash-grid--dragging) .dash-w--cfg:hover .dash-cfg,
.dash-grid--edit:not(.dash-grid--dragging) .dash-w--cfg:focus-within .dash-cfg {
  background: var(--accent-subtle);
}

/* Drag states, applied by main.js. The dragged widget rides under the pointer —
   main.js pins it there with a transform — so it is drawn as a lifted card and
   raised above the neighbours it passes over. It stays legible rather than
   ghosted: it is the thing being placed, and the empty slot it leaves plus the
   grid reflowing around it already say where it came from.
   Deliberately no transform here: transform is what pins the card to the
   pointer, and a scale declared in CSS would be overwritten every frame. */
.dash-w--dragging { opacity: 0.9; z-index: 3; }
.dash-w--dragging.dash-w--cfg { border-color: var(--accent); border-style: solid; box-shadow: var(--shadow); }
.dash-w--dragging .dash-cfg { background: var(--accent-subtle); }
.dash-grid--dragging .dash-cfg { cursor: grabbing; }
.dash-grid--dragging .dash-cfg__vis { pointer-events: none; }

/* Reduced motion: main.js skips the FLIP measurement entirely, and this keeps
   the stylesheet from animating anything on its own. */
@media (prefers-reduced-motion: reduce) {
  .dash-grid--edit .dash-w { transition: none; }
  .dash-grid--edit .dash-cfg__grip { animation: none; }
}

/* Keyboard reordering: the widget being moved is highlighted so the focus
   position is visible while arrow keys shift it. */
.dash-w--kbd.dash-w--cfg { border-color: var(--accent); border-style: solid; }
.dash-w--kbd .dash-cfg { background: var(--accent-subtle); }

/* ---- small screens: no customization at all ----
   Phone-sized viewports (Bootstrap's md cutoff) have no room for it: the grid
   collapses to one column, so widths stop meaning anything and only order is
   left, and dragging cards around while the page wants to scroll is a fight
   rather than a feature. The entry point goes first, the editing chrome with
   it, and anyone
   who reaches ?edit=1 anyway — a bookmark, a shared link, a rotated tablet —
   gets the notice instead of a half-working editor. main.js makes the same
   check before it binds dragging, so a window resized across this line stops
   responding to drags too. */
.dash-edit__mobile { display: none; margin-bottom: var(--s4); }

@media (max-width: 767.98px) {
  .dash-customize { display: none; }
  .dash-edit__bar, .dash-cfg { display: none; }
  .dash-edit__mobile { display: flex; }
  /* Without its settings bar the frame is just a frame, so it stops advertising
     that something can be dropped into it and shows the widget plainly. */
  .dash-w--cfg { border-style: solid; }
  .dash-w__preview { opacity: 1; }
}
