:root {
  /* Command-center palette aligned with the reference design
     (design/reference.html, also exported as --apex-* tokens in
     /static/theme.css). Variable NAMES are preserved so every
     downstream rule keeps working; the values now point at the
     restrained cool / warning / critical palette. Red is reserved
     for active critical signals — see the --bad / --critical
     comments below. */
  --bg: #08101F;          /* deep navy, never pure black */
  --panel: #111E36;       /* card / panel surface */
  --panel-2: #18253E;     /* hover / elevated surface */
  --border: #1E2D48;
  --text: #E8EEF7;
  --muted: #8A9AB5;
  --accent: #5BC8E6;      /* cool primary */
  --accent-2: #3FA7C2;
  --accent-3: #5BC8E6;    /* (was purple — consolidated into accent) */
  --accent-glow: rgba(91, 200, 230, 0.45);
  --good: #6FCF97;
  --warn: #F2B14A;        /* warning amber */
  --bad: #F2B14A;         /* "high severity" — amber, NOT red. Red is
                             reserved for actual critical signals. */
  --critical: #E85D5D;    /* the only red token; used on .sev-critical
                             and .status-error / .status-failed only. */
  /* Text on an accent-coloured fill (dark accent is light → dark text). */
  --on-accent: #08101F;
  /* Monospace code / log blocks. */
  --code-bg: #0E1A2E;
  --code-fg: #C9D1D9;

  /* Per-section accent palette — preserves the existing UX of
     "each section has an identity colour" but pulled from the
     restrained reference palette. Threats keeps red because that
     section semantically IS about active threats; other sections
     fold into cool / warning / success only. */
  --sect-dashboard: #5BC8E6;  /* cool primary */
  --sect-threats:   #E85D5D;  /* critical red — section = active threats */
  --sect-cves:      #F2B14A;  /* warning amber — vulnerabilities */
  --sect-iocs:      #6FCF97;  /* success green — informational indicators */
  --sect-hunt:      #F2B14A;  /* warning amber */
  --sect-map:       #5BC8E6;  /* cool primary */
  --sect-payload:   #5BC8E6;  /* cool primary (was magenta) */
  --sect-about:     #8A9AB5;  /* neutral muted */
  --page-accent: var(--accent);
  --page-accent-glow: var(--accent-glow);
  /* The --apex-font-* tokens live in /static/theme.css (loaded
     before this file per base.html), so they're available here
     without redeclaration. */
}

/* ---- Light theme ---------------------------------------------------------
   Activated by data-theme="light" on <html> (set by the topbar toggle and
   applied before first paint by the inline <head> script). Overrides every
   :root custom property; the whole UI is variable-driven so the override
   re-themes it. Accent + severity colours are darkened so they stay
   readable on a light background — the .sev-* badges render the colour as
   text on a faint tint. */
[data-theme="light"] {
  --bg: #f0f2f7;
  --panel: #ffffff;
  --panel-2: #e7ebf2;
  --border: #ccd3e1;
  --text: #131822;
  --muted: #4b5563;
  --accent: #0e7ec6;
  --accent-2: #0b5f95;
  --accent-3: #0e7ec6;          /* consolidated into accent */
  --accent-glow: rgba(14, 126, 198, 0.32);
  --good: #15803d;
  --warn: #b2782b;              /* warning amber */
  --bad: #b2782b;               /* high severity = warning amber, not red */
  --critical: #be1748;          /* red reserved for actual critical signals */
  --on-accent: #ffffff;
  --code-bg: #eef1f6;
  --code-fg: #1a2230;
  /* Section identity preserved with the restrained palette
     (cool / warning / success). Threats stays red because the
     section semantically IS active threats. */
  --sect-dashboard: #0e7ec6;
  --sect-threats:   #be1748;
  --sect-cves:      #b2782b;
  --sect-iocs:      #15803d;
  --sect-hunt:      #b2782b;
  --sect-map:       #0e7ec6;
  --sect-payload:   #0e7ec6;
  --sect-about:     #4b5468;
  --page-accent: var(--accent);
  --page-accent-glow: var(--accent-glow);
}

/* Per-section accent override. Body data-section is emitted by
   base.html from the request path. --page-accent and --page-accent-glow
   are then consumed by .card top-border, h2 colour, .topbar nav a.is-active,
   button.primary box-shadow, etc. */
body[data-section="dashboard"] { --page-accent: var(--sect-dashboard); --page-accent-glow: var(--accent-glow); }
body[data-section="threats"]   { --page-accent: var(--sect-threats);   --page-accent-glow: rgba(255, 94, 114, 0.45); }
body[data-section="cves"]      { --page-accent: var(--sect-cves);      --page-accent-glow: rgba(183, 139, 255, 0.45); }
body[data-section="iocs"]      { --page-accent: var(--sect-iocs);      --page-accent-glow: rgba(111, 255, 176, 0.40); }
body[data-section="hunt"]      { --page-accent: var(--sect-hunt);      --page-accent-glow: rgba(255, 193,  77, 0.42); }
body[data-section="map"]       { --page-accent: var(--sect-map);       --page-accent-glow: rgba( 94, 232, 255, 0.45); }
body[data-section="payload"]   { --page-accent: var(--sect-payload);   --page-accent-glow: rgba(255,  94, 212, 0.45); }
body[data-section="about"]     { --page-accent: var(--sect-about);     --page-accent-glow: rgba(154, 164, 190, 0.30); }
[data-theme="light"] body[data-section="threats"] { --page-accent-glow: rgba(192, 50, 47, 0.26); }
[data-theme="light"] body[data-section="cves"]    { --page-accent-glow: rgba(109, 52, 198, 0.24); }
[data-theme="light"] body[data-section="iocs"]    { --page-accent-glow: rgba( 15, 143,  90, 0.24); }
[data-theme="light"] body[data-section="hunt"]    { --page-accent-glow: rgba(178, 120,  43, 0.24); }
[data-theme="light"] body[data-section="payload"] { --page-accent-glow: rgba(193,  45, 143, 0.24); }

/* Topbar light/dark toggle button. */
.theme-toggle {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0.35rem 0.55rem;
  margin-right: 0.6rem;
}
.theme-toggle:hover { border-color: var(--accent); }

* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: var(--apex-font-body);
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* Display typography — Instrument Serif for the page-level
   hierarchy (h1, h2), plus a slightly tighter h3 still in Serif
   for sub-headings. Per-page rules in dashboard.css and elsewhere
   can override on a case-by-case basis. */
h1, h2 {
  font-family: var(--apex-font-display);
  font-weight: 400;
  letter-spacing: -0.005em;
}
h3 {
  font-family: var(--apex-font-display);
  font-weight: 400;
}
/* Technical data — anything that's an identifier, hash, IP, CVE
   number, timestamp, or log line gets JetBrains Mono. The
   `.mono` utility class and `table.data .col-date` are the
   common hooks; <code>/<pre> are already mono via the default
   browser stylesheet but we pin the family so it matches. */
code, pre, kbd, samp, .mono { font-family: var(--apex-font-mono); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.95em; }

.topbar {
  display: flex; align-items: center; gap: 1.5rem;
  padding: 0.85rem 1.25rem; background: var(--panel);
  border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 10;
  box-shadow: 0 6px 20px rgba(0,0,0,0.32);
  /* Anchor the page-loading bar to the bottom edge of the menu. The
     bar itself is `position: absolute` relative to this element. */
  /* `position: sticky` already establishes a positioning context for
     absolute children, so no extra rule is needed. */
}
[data-theme="light"] .topbar { box-shadow: 0 4px 14px rgba(31, 95, 196, 0.10); }
.brand a {
  color: var(--text); font-weight: 600; font-size: 1.05rem;
  display: inline-flex; align-items: center; gap: 0.5rem;
}
.brand .logo {
  color: var(--accent); margin-right: 0.25rem; letter-spacing: 0.18em; font-weight: 800;
  text-shadow: 0 0 12px var(--accent-glow);
}
.topbar nav { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.topbar nav a {
  color: var(--muted); font-weight: 500;
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.35rem 0.65rem; border-radius: 6px;
  transition: background 0.12s ease, color 0.12s ease, box-shadow 0.18s ease;
}
.topbar nav a:hover {
  color: var(--text); background: var(--panel-2); text-decoration: none;
}
.topbar nav a.is-active {
  color: var(--page-accent);
  background: var(--panel-2);
  box-shadow: 0 0 14px var(--page-accent-glow), inset 0 0 0 1px var(--border);
}
.topbar nav a .nav-icon {
  font-size: 1.05em; line-height: 1; display: inline-block;
  filter: saturate(1.2);
}
.vt-lookup { display: flex; gap: 0.4rem; }
.topbar-spacer { flex: 1 1 auto; }
.admin-nav {
  display: flex; align-items: center; gap: 0.85rem;
  padding: 0.3rem 0.85rem;
  background:
    linear-gradient(135deg, rgba(255,61,110,0.18), rgba(243,182,100,0.12));
  border: 1px solid rgba(255,61,110,0.30);
  border-radius: 999px;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.20), 0 4px 12px rgba(255,61,110,0.10);
}
.admin-nav a {
  color: var(--muted); font-weight: 500;
  transition: color 0.15s ease;
}
.admin-nav a:hover { color: var(--warn); text-decoration: none; }
.admin-nav-label {
  font-size: 0.7em; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--warn);
  padding-right: 0.4rem; border-right: 1px solid rgba(255,61,110,0.30);
}
.vt-lookup input {
  background: var(--panel-2); border: 1px solid var(--border); color: var(--text);
  padding: 0.35rem 0.6rem; border-radius: 4px; min-width: 260px;
}

/* Top-edge page-loading bar. Triggered by base.html's nav-bar JS on
   internal link clicks + form submits; resets when the next page
   renders. Sits above all chrome (z-index 10500) so it's visible even
   when modals are open. */
/* Outbound-navigation progress bar. Hidden by default; JS shows it on
   internal-link clicks and form submits, then asymptotes width toward
   ~92% so it keeps animating until the next page actually arrives.
   The new page's DOM has the bar back at 0% / hidden, so the bar
   visually disappears the instant the page is fully loaded — never
   reaches 100% on its own. */
.page-loading-bar {
  position: fixed;
  top: 0; left: 0;
  height: 2px;                          /* half the previous 4 px */
  width: 0%;
  z-index: 2147483647;
  pointer-events: none;
  /* Neon green gradient — classic CRT-cyber green for high visibility
     on the dark navy UI. */
  background: linear-gradient(90deg,
    #39ff14 0%,
    #66ff66 50%,
    #39ff14 100%);
  box-shadow:
    0 0 10px rgba(57,255,20,1.0),
    0 0 26px rgba(57,255,20,0.85),
    0 4px 14px rgba(102,255,102,0.55);
  opacity: 0;
  transition: width 0.32s ease-out, opacity 0.22s ease;
}
.page-loading-bar.active { opacity: 1; }

/* Global search banner — sits between the topbar and main content,
   visible on every page so an analyst can paste any IOC / CVE / hash
   and get a local-first then external (VT / MalwareBazaar / AI)
   lookup. The input is the centerpiece; wide-flex so it stretches to
   fill the row. */
.global-search {
  padding: 0.85rem 1.25rem;
  background:
    linear-gradient(180deg, rgba(122,184,255,0.06), transparent 80%),
    var(--panel);
  border-bottom: 1px solid var(--border);
}
.global-search-form {
  display: flex; gap: 0.5rem; align-items: center;
  max-width: 1400px; margin: 0 auto;
}
.global-search-form input[type="text"] {
  flex: 1 1 auto;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 0.55rem 0.85rem; font-size: 0.95rem;
}
.global-search-form input[type="text"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(122,184,255,0.18);
}

/* VirusTotal enrichment card on /iocs/{id} and the JSON-details modal
   used by both the IOC detail page and the threat detail page's
   per-indicator icons. */
.vt-card {
  background: var(--panel-2);
  border: 1px solid rgba(122,184,255,0.20);
  border-radius: 10px;
  padding: 0.75rem 1rem;
  margin-bottom: 0.75rem;
}
.vt-stats {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  margin-bottom: 0.6rem;
}
.vt-stats .stat { min-width: 140px; }
.vt-card-actions {
  display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center;
}
/* Action boxes (replace the small ghost buttons). Each box is itself
   the clickable element (button or anchor) — no inner button, so the
   whole panel is the hit target. The Flagged Vendors box additionally
   contains a small pill ("Full list of vendors") that opens a second
   modal; the pill stops propagation so it doesn't also trigger the
   parent's flagged-only modal. */
.vt-action-boxes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0.6rem;
  align-items: stretch;
}
.vt-action-box {
  display: flex; align-items: flex-start; gap: 0.65rem;
  padding: 0.85rem 1rem;
  background:
    linear-gradient(180deg, rgba(122,184,255,0.08), transparent 70%),
    var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text); text-align: left; cursor: pointer;
  text-decoration: none;
  font: inherit;
  position: relative;
  transition: border-color 0.15s ease, transform 0.12s ease;
}
.vt-action-box:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
  text-decoration: none;
}
.vt-action-box .vt-box-icon {
  font-size: 1.4rem; line-height: 1;
  flex-shrink: 0;
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--panel); border-radius: 8px;
  border: 1px solid var(--border);
}
.vt-action-box .vt-box-text { display: flex; flex-direction: column; gap: 0.2rem; flex: 1; min-width: 0; }
.vt-action-box .vt-box-text strong { font-size: 0.95em; }
.vt-action-box .vt-box-text small {
  color: var(--muted); font-size: 0.78em;
  word-break: break-word; line-height: 1.35;
}
.vt-action-link .vt-box-text small { word-break: break-all; }
/* The "Full list of vendors" pill button stitched into the bottom of
   the Flagged Vendors box. Stops propagation in JS so a click on the
   pill doesn't also fire the parent box's flagged-only modal. */
.vt-box-pill {
  position: absolute; right: 0.75rem; bottom: 0.6rem;
  padding: 0.15rem 0.7rem;
  background: rgba(122,184,255,0.18);
  border: 1px solid rgba(122,184,255,0.32);
  border-radius: 99px;
  color: var(--accent);
  font-size: 0.72em; font-weight: 600;
  cursor: pointer;
  letter-spacing: 0.02em;
}
.vt-box-pill:hover { filter: brightness(1.15); }

/* Structured VT "Details" modal — replaces the raw-JSON view. Sections
   render as a label/value grid; nested data (ELF / PE / signature
   info) drops to a syntax-highlighted JSON pre block. */
.vt-modal-wide { width: min(820px, 95vw); }
.vt-details-body {
  max-height: 70vh; overflow-y: auto;
  padding-right: 0.4rem;
}
/* Determinate progress bar shown while the per-row 🛰 VT modal waits
   for the agent's vt_lookup result. The bar's `value` is bumped in
   seconds on every 2 s poll tick, fills to `max` exactly when the
   60 s timeout fires. */
.vt-progress-wrap {
  display: flex; align-items: center; gap: 0.5rem;
  margin: 0.5rem 0 0.75rem;
}
.vt-progress {
  flex: 1; height: 0.65rem;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid rgba(122,184,255,0.25);
  border-radius: 4px;
  background: rgba(122,184,255,0.08);
  overflow: hidden;
}
.vt-progress::-webkit-progress-bar {
  background: rgba(122,184,255,0.08);
  border-radius: 4px;
}
.vt-progress::-webkit-progress-value {
  background: var(--accent, #7ab8ff);
  border-radius: 4px;
  transition: width 0.4s ease;
}
.vt-progress::-moz-progress-bar {
  background: var(--accent, #7ab8ff);
  border-radius: 4px;
}
.vt-progress-elapsed { font-variant-numeric: tabular-nums; }
.vt-section-title {
  margin: 0.75rem 0 0.35rem;
  font-size: 0.92em; font-weight: 700;
  color: var(--accent);
  text-transform: uppercase; letter-spacing: 0.04em;
  border-bottom: 1px solid rgba(122,184,255,0.18);
  padding-bottom: 0.2rem;
}
.vt-prop-grid {
  display: grid;
  grid-template-columns: minmax(120px, auto) 1fr;
  gap: 0.3rem 1rem;
  margin: 0.3rem 0 0.5rem;
  font-size: 0.88em;
}
.vt-prop-label { color: var(--muted); }
.vt-prop-value {
  color: var(--text); word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.95em;
}
.vt-names-list {
  list-style: disc; margin: 0.25rem 0 0.6rem 1.3rem;
  font-size: 0.86em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  word-break: break-all;
}
.vt-tag-row {
  display: flex; flex-wrap: wrap; gap: 0.3rem;
  margin: 0.3rem 0 0.6rem;
}
.vt-details-pre {
  max-height: 30vh; overflow: auto; margin: 0.25rem 0 0.5rem;
  padding: 0.65rem 0.85rem;
  background: var(--code-bg); color: var(--code-fg);
  border: 1px solid var(--border); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78em; line-height: 1.4;
  white-space: pre-wrap; word-break: break-all;
}

/* Threat-Hunt VT IP modal: Fetch / Rescan button row at the top. */
.vt-ip-actions {
  display: flex; gap: 0.5rem; flex-wrap: wrap;
  margin: 0 0 0.85rem;
}
.vt-rel-summary {
  cursor: pointer; color: var(--accent);
  padding: 0.2rem 0; font-size: 0.92em;
}

/* Top-right floating overlay for in-flight + recently-finished AI
   Forensic Analysis jobs. Each job becomes a stacked card with a
   spinner (running) or check/x (done/error). Click the embedded
   "View →" link to jump to the result page. */
.ai-jobs-overlay {
  position: fixed; top: 1rem; right: 1rem;
  z-index: 9998;  /* below the log panel (9999) but above page content */
  display: flex; flex-direction: column; gap: 0.55rem;
  pointer-events: none;  /* let clicks pass to whatever's underneath */
  max-width: 380px;
}
.ai-job-badge {
  pointer-events: auto;
  display: flex; gap: 0.65rem; align-items: flex-start;
  padding: 0.6rem 0.9rem;
  background:
    linear-gradient(135deg, rgba(122,184,255,0.16) 0%, rgba(183,139,255,0.08) 100%),
    var(--panel);
  border: 1px solid rgba(122,184,255,0.30);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.45);
  font-size: 0.88em;
  animation: ai-job-slidein 0.22s ease-out;
}
.ai-job-done {
  border-color: rgba(95,208,124,0.35);
  background:
    linear-gradient(135deg, rgba(95,208,124,0.16) 0%, transparent 100%),
    var(--panel);
}
.ai-job-error {
  border-color: rgba(239,106,106,0.40);
  background:
    linear-gradient(135deg, rgba(239,106,106,0.16) 0%, transparent 100%),
    var(--panel);
}
/* Remediation-type badges get a slightly warmer tint so analysts can
   visually tell a remediation search from an AI analysis at a glance.
   Phase coloring (done = green border, error = red border) still wins
   via more-specific selectors below. */
.ai-job-type-remediation {
  background:
    linear-gradient(135deg, rgba(243,182,100,0.18) 0%, rgba(122,184,255,0.08) 100%),
    var(--panel);
  border-color: rgba(243,182,100,0.35);
}
.ai-job-text { flex: 1; }
.ai-job-text strong { display: block; font-size: 0.95em; }
.ai-job-sub { font-size: 0.82em; margin-top: 0.15rem; word-break: break-word; }
.ai-job-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  font-weight: 700; font-size: 0.85em;
  background: var(--panel-2);
}
.ai-job-done .ai-job-icon { background: rgba(95,208,124,0.20); color: var(--good); }
.ai-job-error .ai-job-icon { background: rgba(239,106,106,0.20); color: var(--bad); }
.ai-spinner {
  border: 2px solid rgba(122,184,255,0.25);
  border-top-color: var(--accent);
  animation: search-spin 0.85s linear infinite;  /* reuse the search-spin keyframes */
}
.ai-job-link {
  align-self: center; margin-left: 0.25rem;
  color: var(--accent); font-weight: 600; font-size: 0.85em;
}
.ai-job-fadeout {
  opacity: 0; transform: translateX(20px);
  transition: opacity 0.22s ease, transform 0.22s ease;
}
@keyframes ai-job-slidein {
  from { opacity: 0; transform: translateX(20px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Search progress modal — appears while /api/search/start runs in the
   background. Steps light up as the server reports phase changes. */
.search-progress-modal {
  width: min(560px, 92vw);
  background: var(--panel); color: var(--text);
  border: 1px solid rgba(122,184,255,0.30); border-radius: 12px;
  padding: 1.25rem 1.5rem;
  box-shadow: 0 18px 48px rgba(0,0,0,0.55);
}
.search-progress-modal::backdrop {
  background: rgba(0,0,0,0.55); backdrop-filter: blur(2px);
}
.search-progress-modal h3 {
  margin: 0 0 0.5rem; display: flex; align-items: center; gap: 0.6rem;
  font-size: 1rem;
}
.search-progress-phase {
  margin: 0 0 0.85rem;
  color: var(--accent);
  font-size: 0.95rem;
}
.search-progress-steps {
  list-style: none; padding: 0; margin: 0 0 0.75rem;
  display: flex; flex-direction: column; gap: 0.35rem;
}
.search-progress-steps li {
  display: flex; align-items: center; gap: 0.55rem;
  font-size: 0.88em;
  color: var(--muted);
}
.search-progress-steps li.step-active {
  color: var(--accent);
}
.search-progress-steps li.step-done {
  color: var(--good);
  text-decoration: line-through;
  text-decoration-color: rgba(95,208,124,0.45);
}
.search-progress-steps .step-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.1em; height: 1.1em;
  font-family: ui-monospace, monospace; font-size: 1.05em;
}
.search-progress-actions {
  display: flex; justify-content: flex-end; gap: 0.5rem;
  margin-top: 0.5rem;
}
.search-spinner {
  display: inline-block; width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid rgba(122,184,255,0.25);
  border-top-color: var(--accent);
  animation: search-spin 0.85s linear infinite;
}
@keyframes search-spin { to { transform: rotate(360deg); } }

main { max-width: none; margin: 1.5rem 0; padding: 0 1.25rem; }
table.data { table-layout: auto; font-size: 0.85em; }
table.data td.col-date, table.data th.col-date { white-space: nowrap; }
footer { text-align: center; color: var(--muted); padding: 1.5rem 0; }

h1, h2, h3 { margin: 1.25rem 0 0.5rem; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.2rem; color: var(--text); }
h3 { font-size: 1.05rem; }
.subtitle { color: var(--muted); font-weight: 500; }
.breadcrumb { color: var(--muted); margin: 0.25rem 0; }
.meta { display: flex; gap: 1.25rem; color: var(--muted); font-size: 0.9em; }

.stats { display: flex; flex-wrap: wrap; gap: 1rem; margin: 1rem 0 1.5rem; }
.stat {
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  padding: 1rem 1.25rem; min-width: 160px;
}
.stat .num { display: block; font-size: 1.75rem; font-weight: 700; color: var(--accent); }
.stat .label { color: var(--muted); font-size: 0.9em; }
/* A stat box rendered as a link (clickable KPI on the dashboard). */
a.stat { text-decoration: none; color: inherit; cursor: pointer;
  transition: border-color 0.12s ease, transform 0.12s ease; }
a.stat:hover { border-color: var(--accent); transform: translateY(-2px); }

table.data {
  width: 100%; border-collapse: collapse; background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  margin-bottom: 1rem;
}
table.data th, table.data td {
  padding: 0.4rem 0.55rem; text-align: left; border-bottom: 1px solid var(--border);
  vertical-align: top;
}
table.data th { background: var(--panel-2); font-weight: 600; color: var(--muted); font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.04em; }
table.data tr:last-child td { border-bottom: 0; }
.status-cell, .err { color: var(--muted); font-size: 0.85em; max-width: 360px; }
/* Keep identifier-like cells (CVE IDs, IOC values, OTX pulse IDs) on one
   line — they're short, recognizable tokens, and wrapping them shreds the
   visual grid. The width:1% trick keeps the column as tight as the content. */
table.data td code,
table.data th:first-child,
table.data td:first-child { white-space: nowrap; width: 1%; }
table.data td:nth-child(2) {
  min-width: 280px;
  word-break: break-word; overflow-wrap: anywhere;
}

.section-head .actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* Dashboard charts. */
.charts-grid {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  margin-bottom: 1rem;
}
.chart-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 1rem 1.25rem;
  display: flex; flex-direction: column;
}
.chart-card h3 { margin: 0 0 0.5rem; font-size: 0.95em; color: var(--muted); }
.chart-card canvas { flex: 1; min-height: 240px; max-height: 320px; width: 100% !important; height: auto !important; }
.chart-card-wide { grid-column: 1 / -1; }
.chart-card-wide canvas { max-height: 420px; }

/* Topbar Sign-in pinned right. The lookup form is placed between nav and
   userbox; userbox is auto-margin-left so it hugs the right edge. */
.topbar .userbox { margin-left: auto; }
.userbox a.primary {
  padding: 0.4rem 0.85rem; background: var(--accent); color: var(--on-accent);
  border-radius: 6px; font-weight: 600;
}
.userbox a.primary:hover { filter: brightness(1.1); }

/* Make the Download link in the backups table look like a button. */
a.btnlike {
  display: inline-block;
  font-size: 0.85em; padding: 0.2rem 0.55rem;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 4px; color: var(--text); text-decoration: none;
  margin-right: 0.25rem;
}
a.btnlike:hover { background: var(--panel-2); }

/* About page WYSIWYG. */
.about-toolbar { display: flex; justify-content: flex-end; margin: 0 0 0.5rem; }
.about-content { max-width: none; }
.about-content h1 { margin-top: 0; }
.about-editor-area {
  background: #f6f8fa; color: #161b22; min-height: 360px;
  border-radius: 0 0 6px 6px;
}
.ql-toolbar.ql-snow { background: var(--panel-2); border-color: var(--border) !important; border-radius: 6px 6px 0 0; }
.ql-container.ql-snow { border-color: var(--border) !important; }

/* Live log footer panel — admin-only, fixed to bottom, collapsible. */
.logpanel {
  position: fixed !important; left: 0 !important; right: 0 !important;
  bottom: 0 !important;
  display: flex; flex-direction: column;
  background: var(--panel); border-top: 1px solid var(--border);
  z-index: 9999 !important;
  height: 35vh; max-height: 50vh; min-height: 2.2rem;
  transition: height 0.15s ease;
  box-shadow: 0 -8px 24px rgba(0,0,0,0.35);
}
.logpanel.logpanel-collapsed { height: 2.2rem !important; }
.logpanel.logpanel-collapsed #logpanel-body { display: none !important; }
.logpanel.logpanel-fullscreen {
  top: 5vh !important; left: 5vw !important; right: 5vw !important;
  bottom: 5vh !important;
  height: auto !important; max-height: none !important;
  border-radius: 10px;
  border: 1px solid var(--border);
  /* The huge box-shadow doubles as a modal backdrop without needing an
     extra DOM element. */
  box-shadow:
    0 14px 48px rgba(0,0,0,0.55),
    0 0 0 100vmax rgba(0,0,0,0.7);
}
.logpanel.logpanel-fullscreen #logpanel-toggle { display: none; }
.logpanel.logpanel-fullscreen #logpanel-body { display: block !important; }
.logpanel-head {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.35rem 0.75rem;
  background: var(--panel-2); border-bottom: 1px solid var(--border);
  font-size: 0.85em;
}
.logpanel-title { font-weight: 600; color: var(--muted); margin-right: 0.5rem; }
.logpanel-head input {
  flex: 1; max-width: 360px; font-size: 0.85em;
  padding: 0.25rem 0.5rem;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 4px; color: var(--text);
}
.logpanel-head button {
  font-size: 0.85em; padding: 0.2rem 0.55rem;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 4px; cursor: pointer; color: var(--text);
}
.logpanel-head button:hover { background: var(--panel-2); }
#logpanel-body {
  flex: 1; overflow: auto; margin: 0; padding: 0.5rem 0.75rem;
  background: var(--code-bg); color: var(--code-fg);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78em; line-height: 1.4;
  white-space: pre-wrap; word-break: break-all;
}
/* Bump bottom margin on <main> so the collapsed footer panel doesn't cover
   the bottom of pages. Add another fudge when expanded — handled by JS via
   the body class would be cleaner, but margin against the collapsed height
   keeps things simple. */
body { padding-bottom: 2.5rem; }

form.stacked fieldset {
  border: 1px solid var(--border); border-radius: 8px;
  padding: 0.75rem 1rem 0.5rem; margin: 0; display: flex; flex-direction: column;
  gap: 0.5rem; background: var(--panel-2);
}
form.stacked fieldset legend { padding: 0 0.4rem; color: var(--muted); font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.04em; }

.ai-analysis {
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 1rem 1.25rem; margin-bottom: 1rem;
}
.ai-analysis h2 { margin: 1rem 0 0.5rem; font-size: 1.15em; color: var(--accent); }
.ai-analysis h3 { margin: 0.75rem 0 0.4rem; font-size: 1em; color: var(--accent); }
.ai-analysis p { margin: 0.4rem 0; }
.ai-analysis ul, .ai-analysis ol { margin: 0.4rem 0 0.6rem 1.25rem; }
.ai-analysis code { background: var(--panel); padding: 0.1rem 0.35rem; border-radius: 4px; font-size: 0.9em; }
.ai-analysis pre { background: var(--panel); padding: 0.75rem; border-radius: 6px; overflow-x: auto; font-size: 0.85em; }
.ai-analysis pre code { background: transparent; padding: 0; }

.sev { display: inline-block; padding: 0.1rem 0.5rem; border-radius: 99px; font-size: 0.75em; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; white-space: nowrap; word-break: keep-all; overflow-wrap: normal; font-family: var(--apex-font-mono); }
/* Severity tints — paired with the recoloured tokens above. The
   "high" tint is amber (warning), NOT red — red is reserved for
   .sev-critical only so it actually means something when it
   appears. */
.sev-info     { background: rgba(138,154,181,0.12); color: var(--muted); }
.sev-low      { background: rgba(111,207,151,0.12); color: var(--good); }
.sev-medium   { background: rgba(91,200,230,0.15);  color: var(--accent); }
.sev-high     { background: rgba(242,177,74,0.12);  color: var(--warn); }
.sev-critical { background: rgba(232,93,93,0.12);   color: var(--critical); }

/* CVSS score "analog meter" — semicircular dial rendered on the CVE
   detail page. Needle inherits currentColor so the foreground stays
   readable in both light & dark themes. */
.cvss-meter { display: inline-block; vertical-align: middle; color: var(--fg, #e6edf3); }
[data-theme="light"] .cvss-meter { color: #1f2937; }
.cvss-score-cell { display: flex; align-items: center; gap: 0.6rem; }
.cvss-score-num { font-weight: 600; font-size: 1.05rem; }

/* "VT Reputation & Enrichment" cell (Threat Hunt, Indicators of
   Compromise, CVE detail). Keep the column narrow: the verdict badge
   sits on its own line; the flagged-vendors pill button and the modal
   button stack below and wrap, instead of one long line that forces a
   very wide table. The pill opens the shared flagged-vendors modal. */
table.data td.vt-cell { white-space: normal; max-width: 260px; }
table.data td.vt-cell .sev { white-space: normal; }
.vt-cell .vt-sub { display: flex; align-items: center; gap: 0.3rem; flex-wrap: wrap; margin-top: 0.2rem; }
.vt-cell .vt-sub .vendor-count-badge { margin-left: 0; }

/* Homepage "definition" paragraph — a readable lead describing what the
   tool is (also serves as on-page SEO content). Spans the full content
   width, justified so the text aligns flush to both edges. */
.tool-intro { line-height: 1.65; margin: 0.25rem 0 1.5rem; text-align: justify; }

/* Agent install download buttons on /admin/agents. */
.agent-downloads { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.6rem 0; }

.status { font-weight: 600; text-transform: uppercase; font-size: 0.75em; letter-spacing: 0.05em; font-family: var(--apex-font-mono); }
.status-ok      { color: var(--good); }
.status-running { color: var(--accent); }
/* Errors are critical signals — use --critical so the red is
   meaningful (matches the .sev-critical / dashboard semantics). */
.status-error,
.status-failed  { color: var(--critical); }

button, .ghost {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  padding: 0.4rem 0.85rem; border-radius: 4px; cursor: pointer;
  font-size: 0.9rem;
}
button:hover { border-color: var(--accent-2); }
button.primary {
  background: var(--accent-2); border-color: var(--accent-2); color: white;
  box-shadow: 0 0 14px var(--page-accent-glow);
  transition: box-shadow 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
button.primary:hover {
  background: var(--accent); border-color: var(--accent);
  box-shadow: 0 0 22px var(--page-accent-glow);
}
button.danger { background: transparent; border-color: var(--bad); color: var(--bad); }
button.danger:hover {
  background: rgba(255, 94, 114, 0.10);
  box-shadow: 0 0 16px rgba(255, 94, 114, 0.35);
}
.ghost { display: inline-block; }

.actions-bar, .section-head { display: flex; align-items: center; gap: 0.75rem; margin: 0.75rem 0; }
.section-head { justify-content: space-between; }

form.inline { display: inline; }
form.stacked { display: flex; flex-direction: column; gap: 0.75rem; max-width: 720px; }
form.stacked label { display: flex; flex-direction: column; font-size: 0.9rem; color: var(--muted); gap: 0.25rem; }
form.stacked input[type=text], form.stacked input[type=password],
form.stacked input:not([type]), form.stacked textarea, form.stacked select {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  padding: 0.45rem 0.65rem; border-radius: 4px; font-family: inherit; font-size: 0.95rem;
}
form.stacked textarea { font-family: ui-monospace, monospace; }
form.stacked label small { color: var(--muted); font-size: 0.8em; margin-top: 0.15rem; }
form.stacked .row { margin-top: 0.25rem; }

.filter-bar { display: flex; gap: 0.5rem; align-items: center; margin: 0.75rem 0 1.25rem; flex-wrap: wrap; }
.filter-bar input, .filter-bar select {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  padding: 0.4rem 0.6rem; border-radius: 4px;
}
.filter-bar input[type=text] { min-width: 440px; flex: 1 1 440px; max-width: 720px; }

.actions { display: flex; gap: 0.4rem; align-items: flex-start; flex-direction: column; }
.actions details { background: var(--panel-2); padding: 0.4rem 0.6rem; border-radius: 4px; border: 1px solid var(--border); }

.empty { color: var(--muted); padding: 0.75rem 0; }
.flash {
  display: inline-block; background: rgba(108,182,255,0.12); color: var(--accent);
  padding: 0.35rem 0.7rem; border-radius: 4px; font-size: 0.9em; margin-left: 0.5rem;
}

.cards { list-style: none; padding: 0; display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); }
.card { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 0.85rem 1rem; }
.card-title { font-weight: 600; margin-bottom: 0.35rem; }
.card .tag { display: inline-block; font-size: 0.75em; background: var(--panel-2); color: var(--muted); padding: 0.1rem 0.5rem; border-radius: 99px; }
.card p { color: var(--muted); margin: 0.4rem 0; font-size: 0.92em; }
.card-foot { color: var(--muted); font-size: 0.8em; margin-top: 0.5rem; }

ul.refs { list-style: none; padding: 0; }
ul.refs li { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 0.6rem 0.85rem; margin-bottom: 0.5rem; }
ul.refs .snippet { color: var(--muted); font-size: 0.9em; margin: 0.35rem 0 0; }
.tag { display: inline-block; font-size: 0.7em; background: var(--panel-2); color: var(--muted); padding: 0.1rem 0.5rem; border-radius: 99px; margin-left: 0.4rem; }

.desc { white-space: pre-wrap; }

.help { margin-top: 1.5rem; color: var(--muted); }
.help summary { cursor: pointer; }
.help code { color: var(--text); background: var(--panel-2); padding: 0 0.25rem; border-radius: 3px; }

.danger-zone { margin-top: 2rem; padding-top: 1rem; border-top: 1px dashed var(--border); }

.muted { color: var(--muted); }
.error {
  display: block; background: rgba(239,106,106,0.12); color: var(--bad);
  padding: 0.5rem 0.75rem; border-radius: 4px; margin-bottom: 0.75rem;
}

.auth-card {
  max-width: 420px; margin: 3rem auto; background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px; padding: 1.5rem 1.75rem;
}
.auth-card h1 { margin-top: 0; }

.userbox {
  display: flex; align-items: center; gap: 0.6rem; color: var(--muted);
  font-size: 0.9em;
}
.userbox .user-email { color: var(--text); }
.role-tag {
  display: inline-block; padding: 0.1rem 0.5rem; border-radius: 99px;
  font-size: 0.7em; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.05em;
}
.role-admin { background: rgba(108,182,255,0.18); color: var(--accent); }
.role-collaborator { background: rgba(95,208,124,0.15); color: var(--good); }

.pager {
  display: flex; gap: 0.5rem; align-items: center; justify-content: center;
  margin: 1rem 0; color: var(--muted);
}
.pager a { padding: 0.3rem 0.7rem; border: 1px solid var(--border); border-radius: 4px; }
.pager .ghost.disabled { opacity: 0.4; pointer-events: none; padding: 0.3rem 0.7rem; border: 1px solid var(--border); border-radius: 4px; }
.pager-info { margin: 0.5rem 0; font-size: 0.9em; }
.page-size-control {
  margin: 0 0 1rem; font-size: 0.9em; color: var(--muted);
  display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem;
}
.page-size-control label { display: inline-flex; align-items: center; gap: 0.4rem; }
.page-size-control select { padding: 0.25rem 0.5rem; }

.auth-card-wide { max-width: 640px; }
.qr-row { display: flex; gap: 1.25rem; align-items: flex-start; margin: 1rem 0 1.5rem; flex-wrap: wrap; }
.qr-box {
  background: white; padding: 0.6rem; border-radius: 8px; flex: 0 0 auto;
  display: inline-flex; line-height: 0;
}
.qr-box svg { width: 220px; height: 220px; display: block; }
.qr-side { flex: 1 1 250px; min-width: 250px; }
.secret-block {
  display: inline-block; background: var(--panel-2); border: 1px solid var(--border);
  padding: 0.5rem 0.75rem; border-radius: 4px; font-size: 0.95em; word-break: break-all;
  margin: 0.4rem 0;
}

.backup-codes {
  list-style: none; padding: 0; margin: 1rem 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 0.5rem;
}
.backup-codes li {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 4px;
  padding: 0.5rem 0.75rem; text-align: center;
}
.backup-codes code { font-size: 1.05em; letter-spacing: 0.05em; }

/* ---------------------------------------------------------------------------
   Theme refresh: vibrant topbar, richer palette, subtle depth cues.
   Layered as overrides at the bottom so the structural rules above stay
   readable.
   --------------------------------------------------------------------------- */

body {
  background:
    radial-gradient(1100px 600px at 90% -10%, rgba(183,139,255,0.10), transparent 70%),
    radial-gradient(900px 500px at -10% -10%, rgba(122,184,255,0.10), transparent 65%),
    var(--bg);
}

.topbar {
  background:
    linear-gradient(120deg,
      rgba(122,184,255,0.16) 0%,
      rgba(183,139,255,0.10) 45%,
      rgba(122,184,255,0.04) 100%),
    linear-gradient(180deg, #182238 0%, #121a2c 100%);
  border-bottom: 1px solid rgba(122,184,255,0.22);
  box-shadow:
    0 1px 0 0 rgba(183,139,255,0.18) inset,
    0 8px 28px rgba(0,0,0,0.55),
    0 0 0 1px rgba(255,255,255,0.02);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* APEX wordmark — gradient text. */
.brand a { color: var(--text); }
.brand .logo {
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-3) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 0 18px rgba(122,184,255,0.35);
}

/* Nav links: subtle hover glow + animated underline. */
.topbar nav a {
  position: relative;
  padding: 0.2rem 0.1rem;
  transition: color 0.15s ease;
}
.topbar nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -4px;
  height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-3));
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.2s ease;
}
.topbar nav a:hover { color: var(--text); text-decoration: none; }
.topbar nav a:hover::after { transform: scaleX(1); }

/* VirusTotal/MalwareBazaar lookup buttons in the topbar — a bit more energy. */
.vt-lookup input {
  background: rgba(10, 14, 23, 0.55);
  border-color: rgba(122,184,255,0.20);
}
.vt-lookup input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(122,184,255,0.18);
}

/* Sign-in / userbox button: gradient pill. */
.userbox a.primary {
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-3) 100%);
  color: var(--on-accent); box-shadow: 0 4px 14px rgba(122,184,255,0.28);
}
.userbox a.primary:hover { filter: brightness(1.08); box-shadow: 0 6px 18px rgba(183,139,255,0.35); }

/* Stat cards — accent strip on top for a touch of life. */
.stat {
  position: relative; overflow: hidden;
  background:
    linear-gradient(180deg, rgba(122,184,255,0.06), transparent 60%),
    var(--panel);
}
.stat::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-3));
  opacity: 0.8;
}

/* Chart cards — match the stat-card flair. */
.chart-card { position: relative; overflow: hidden; }
.chart-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--accent-3), var(--accent));
  opacity: 0.6;
}

/* Primary buttons — subtle gradient. */
button.primary {
  background: linear-gradient(135deg, var(--accent-2) 0%, var(--accent) 100%);
  border-color: transparent; color: var(--on-accent); font-weight: 600;
  box-shadow: 0 2px 14px var(--page-accent-glow);
}
button.primary:hover {
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-3) 100%);
  border-color: transparent;
  box-shadow: 0 4px 22px var(--page-accent-glow);
}

/* Severity badges — a little outline so they pop on the panel bg. */
.sev-low { box-shadow: inset 0 0 0 1px rgba(95,208,124,0.35); }
.sev-medium { box-shadow: inset 0 0 0 1px rgba(243,182,100,0.35); }
.sev-high { box-shadow: inset 0 0 0 1px rgba(239,106,106,0.35); }
.sev-critical {
  box-shadow:
    inset 0 0 0 1px rgba(255, 61, 110, 0.55),
    0 0 14px rgba(255, 61, 110, 0.45);
  animation: apex-critical-pulse 2.4s ease-in-out infinite;
}
@keyframes apex-critical-pulse {
  0%, 100% { box-shadow: inset 0 0 0 1px rgba(255,61,110,0.55), 0 0 10px rgba(255,61,110,0.32); }
  50%      { box-shadow: inset 0 0 0 1px rgba(255,61,110,0.55), 0 0 18px rgba(255,61,110,0.62); }
}
[data-theme="light"] .sev-critical { animation: none; box-shadow: inset 0 0 0 1px rgba(190, 23, 72, 0.45); }
@media (prefers-reduced-motion: reduce) { .sev-critical { animation: none; } }

/* Table header — slightly brighter accent text for legibility on dark. */
table.data th { color: var(--muted); border-bottom: 1px solid var(--border); }
table.data tbody tr:hover td { background: rgba(122,184,255,0.04); }

/* /admin/jobs — live background-batch monitor. One card per known
   skill/batch, polled every 3s, with a tailable inline log. */
.jobs-grid {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  margin: 1rem 0;
}
.job-card {
  background:
    linear-gradient(180deg, rgba(122,184,255,0.05), transparent 60%),
    var(--panel);
  border: 1px solid var(--border); border-radius: 10px;
  padding: 0.9rem 1.1rem;
  display: flex; flex-direction: column; gap: 0.5rem;
}
.job-card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.job-card-head h3 { margin: 0; font-size: 0.95rem; color: var(--text); }
.job-status {
  font-size: 0.7em; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.08em; padding: 0.15rem 0.55rem; border-radius: 99px;
  background: var(--panel-2); color: var(--muted);
  border: 1px solid var(--border);
}
.job-status-running { background: rgba(122,184,255,0.18); color: var(--accent); border-color: rgba(122,184,255,0.30); }
.job-status-done    { background: rgba(95,208,124,0.15); color: var(--good); border-color: rgba(95,208,124,0.30); }
.job-status-error   { background: rgba(239,106,106,0.15); color: var(--bad); border-color: rgba(239,106,106,0.30); }
.job-status-idle    { /* default */ }
.job-meta { display: flex; gap: 0.75rem; font-size: 0.8em; flex-wrap: wrap; }
.job-bar {
  width: 100%; height: 10px; appearance: none; -webkit-appearance: none;
  border: 0; border-radius: 99px; overflow: hidden; background: var(--panel-2);
}
.job-bar::-webkit-progress-bar { background: var(--panel-2); border-radius: 99px; }
.job-bar::-webkit-progress-value {
  background: linear-gradient(90deg, var(--accent), var(--accent-3));
  border-radius: 99px;
}
.job-bar::-moz-progress-bar {
  background: linear-gradient(90deg, var(--accent), var(--accent-3));
  border-radius: 99px;
}
.job-counters { font-size: 0.85em; }
.job-run-form { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 0.3rem 0 0; }
.job-run-form .small { font-size: 0.78em; }
.job-running-summary {
  margin: 0.5rem 0 0.75rem;
  padding: 0.55rem 0.85rem;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 6px;
  font-size: 0.88em; display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap;
}
.badge {
  display: inline-block; font-size: 0.78em; font-weight: 600;
  padding: 0.18rem 0.55rem; border-radius: 99px;
  background: var(--panel-2); color: var(--muted); border: 1px solid var(--border);
  text-decoration: none;
}
.badge-running {
  background: rgba(122,184,255,0.18); color: var(--accent);
  border-color: rgba(122,184,255,0.30);
}
.badge-running:hover { filter: brightness(1.15); }
.job-log-details > summary { cursor: pointer; font-size: 0.85em; color: var(--muted); }
.job-log-tail {
  margin: 0.4rem 0 0;
  padding: 0.55rem 0.7rem;
  max-height: 280px; overflow: auto;
  background: var(--code-bg); color: var(--code-fg);
  border: 1px solid var(--border); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78em; line-height: 1.4;
  white-space: pre-wrap; word-break: break-all;
}

/* /threat-intel feeds table — content varies wildly (one-word
   categories, full feed URLs, multi-paragraph descriptions). Per-column
   policy:
   - Narrow content (Vendor, ID, Category, Status, Indicators, Actions,
     Last scraped): `col-tight` / `col-date` → shrink to content + no
     wrap. The `width: 1%` trick tells the table-layout pass to give
     these columns just enough width and donate the remainder to the
     flexible columns.
   - Flexible content (Description, URL, Result): wrap aggressively
     so the table fits the viewport. The URL <code> needs an explicit
     override of the global `table.data td code { nowrap }` rule. */
table.ti-feeds-table {
  table-layout: auto;
  width: 100%;
}
table.ti-feeds-table th,
table.ti-feeds-table td {
  word-break: break-word;
  overflow-wrap: anywhere;
}
table.ti-feeds-table td code {
  white-space: normal;
  word-break: break-all;
}
table.ti-feeds-table td.col-tight,
table.ti-feeds-table th.col-tight,
table.ti-feeds-table td.col-date,
table.ti-feeds-table th.col-date {
  white-space: nowrap;
  word-break: keep-all;
  overflow-wrap: normal;
  width: 1%;
  /* The global `table.data td:nth-child(2) { min-width: 280px }` rule
     (added for the /threats Title column) would otherwise force the
     ID cell — which is the 2nd <td> in this table — to 280 px. Reset
     it so col-tight actually shrinks to content. */
  min-width: 0;
}

/* Vendor grouping in the /threat-intel feeds table. The vendor cell
   spans every row of its group (rowspan); the start-of-group row gets
   a subtle accent-tinted top border so the visual grouping reads at a
   glance even when the table is long. */
table.ti-feeds-table td.vendor-cell {
  background: linear-gradient(180deg, rgba(122,184,255,0.06), transparent 60%),
              var(--panel-2);
  border-right: 1px solid var(--border);
  vertical-align: top;
  font-size: 0.95em;
  white-space: nowrap;
  word-break: keep-all;
  width: 1%;
}
table.ti-feeds-table tr.vendor-group-start > td {
  border-top: 2px solid rgba(122,184,255,0.30);
}
.vendor-count-badge {
  display: inline-flex; align-items: center; gap: 0.15rem;
  margin-left: 0.4rem;
  padding: 0.05rem 0.5rem;
  background: rgba(122,184,255,0.18);
  border: 1px solid rgba(122,184,255,0.35);
  border-radius: 99px;
  color: var(--accent);
  font-size: 0.78em; font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.vendor-count-badge:hover { filter: brightness(1.15); }

/* Shared feeds-list modal (used on /threat-intel for vendor groups and
   on /threat-hunt for per-indicator feed corroboration). */
.feeds-modal {
  width: min(720px, 90vw);
  max-height: 80vh;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 12px;
  padding: 1rem 1.25rem;
  box-shadow: 0 18px 64px rgba(0,0,0,0.55);
}
.feeds-modal::backdrop {
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(2px);
}
.feeds-modal > header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; margin-bottom: 0.5rem;
}
.feeds-modal > header h3 { margin: 0; font-size: 1rem; }
.feeds-modal-list { list-style: none; padding: 0; margin: 0; max-height: 60vh; overflow: auto; }
.feeds-modal-list li {
  padding: 0.5rem 0.4rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.92em;
  word-break: break-all;
}
.feeds-modal-list li:last-child { border-bottom: 0; }
.feeds-modal-list a { color: var(--accent); }

/* Threat-intel classification: per-box toggles. Lets the user hide
   per-type boxes they don't care about. State persists in localStorage. */
.stat-selector { margin: 0.5rem 0 0.75rem; }
.stat-selector > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85em;
}
.stat-toggles {
  display: flex; flex-wrap: wrap; gap: 0.4rem 0.9rem;
  margin-top: 0.4rem;
  padding: 0.6rem 0.8rem;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.stat-toggles label {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-size: 0.85em; color: var(--text);
  cursor: pointer;
}
.stat-toggles input[type="checkbox"] { accent-color: var(--accent); }

/* Threat-intel row actions: three icons on one line, Edit pops the form
   open below in-flow. Reused for any table row where horizontal action
   icons make more sense than stacked buttons. */
.ti-actions {
  display: flex; flex-direction: row; gap: 0.4rem; align-items: center;
  flex-wrap: nowrap;
}
button.icon-btn, summary.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; padding: 0;
  font-size: 1.05rem; line-height: 1;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  cursor: pointer;
  list-style: none;  /* hide <details> marker on <summary> */
}
summary.icon-btn::-webkit-details-marker { display: none; }
summary.icon-btn::marker { content: ""; }
button.icon-btn:hover, summary.icon-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
button.icon-btn.icon-btn-danger { color: var(--bad); }
button.icon-btn.icon-btn-danger:hover { border-color: var(--bad); background: rgba(239,106,106,0.10); }
details.icon-popup[open] > summary.icon-btn {
  background: var(--accent-2); color: white; border-color: var(--accent-2);
}
/* When the edit popup is open, drop the form below the icon row so it
   doesn't disrupt the table cell. Keeps the three icons on one line. */
.icon-popup-form {
  margin-top: 0.5rem;
  background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 0.75rem;
}

/* Remediation batch progress bar (admin /sources). */
.batch-progress {
  margin: 0.5rem 0 1rem;
  padding: 0.75rem 1rem;
  background:
    linear-gradient(180deg, rgba(122,184,255,0.08), transparent 80%),
    var(--panel);
  border: 1px solid rgba(122,184,255,0.25);
  border-radius: 8px;
  box-shadow: 0 4px 18px rgba(0,0,0,0.30);
}
.batch-progress-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem; margin-bottom: 0.5rem;
}
.batch-progress-label { display: flex; align-items: center; gap: 0.55rem; }
.batch-progress progress {
  width: 100%; height: 14px; appearance: none; -webkit-appearance: none;
  border: 0; border-radius: 99px; overflow: hidden;
  background: var(--panel-2);
}
.batch-progress progress::-webkit-progress-bar {
  background: var(--panel-2); border-radius: 99px;
}
.batch-progress progress::-webkit-progress-value {
  background: linear-gradient(90deg, var(--accent), var(--accent-3));
  border-radius: 99px;
  transition: width 0.3s ease;
}
.batch-progress progress::-moz-progress-bar {
  background: linear-gradient(90deg, var(--accent), var(--accent-3));
  border-radius: 99px;
}
.batch-spinner {
  display: inline-block; width: 12px; height: 12px;
  border-radius: 50%;
  border: 2px solid rgba(122,184,255,0.25);
  border-top-color: var(--accent);
  animation: batch-spin 0.9s linear infinite;
}
@keyframes batch-spin {
  to { transform: rotate(360deg); }
}

/* Dashboard global IP map. Light base from Esri Light Gray Canvas;
   the #apex-ip-map background colour matches the tile background so
   the tile load-in is invisible. */
#apex-ip-map { background: #e8ecef; }
.map-legend {
  display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
  padding: 0.55rem 0.9rem; font-size: 0.85rem; color: var(--muted);
  border-top: 1px solid rgba(255,255,255,0.05);
}
.map-legend .lg-dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  vertical-align: middle;
}
.map-legend .lg-critical { background: #dc2626; }
.map-legend .lg-high     { background: #f97316; }
.map-legend .lg-medium   { background: #eab308; }
.map-legend .lg-low      { background: #3b82f6; }
.map-legend .lg-info     { background: #9ca3af; }
/* Toggle pills — buttons that switch the Leaflet layer-group on/off
   for that severity. `aria-pressed` is the source of truth; we style
   off-state with reduced opacity and a strikethrough on the label. */
.sev-toggle {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 0.35rem;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 99px;
  padding: 0.18rem 0.6rem; font-size: 0.8rem; line-height: 1.4;
  transition: opacity 0.12s ease, filter 0.12s ease;
}
.sev-toggle:hover { filter: brightness(1.2); }
.sev-toggle[aria-pressed="false"] {
  opacity: 0.45; filter: grayscale(0.6);
}
.sev-toggle[aria-pressed="false"] .sev-name { text-decoration: line-through; }
.sev-toggle .sev-count {
  font-variant-numeric: tabular-nums; font-size: 0.72rem;
  color: var(--muted); padding: 0 0.32rem;
  background: rgba(255,255,255,0.06); border-radius: 99px;
}
.legend-actions { display: inline-flex; gap: 0.3rem; margin-left: 0.4rem; }
.legend-actions .ghost.small {
  font-size: 0.72rem; padding: 0.15rem 0.55rem;
}
.leaflet-popup-content { color: #111; font-family: inherit; }
.leaflet-container a { color: #2563eb; }

/* Resolved-IP chip in /threat-hunt — clickable button (opens geo modal)
   showing the IP value with a leading 🌍. Sits inline so multiple chips
   stack neatly in a tight column. */
.ip-chip {
  display: inline-flex; align-items: center; gap: 0.15rem;
  cursor: pointer; vertical-align: middle;
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 99px;
  padding: 0.1rem 0.5rem; margin: 0.1rem 0.18rem 0.1rem 0;
  font-size: 0.78rem; line-height: 1.4;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.ip-chip:hover { filter: brightness(1.18); }
.ip-chip code { background: transparent; padding: 0; font-size: inherit; }

/* Geo modal — re-uses .vt-modal layout, adds key/value list */
.kv {
  display: grid; grid-template-columns: 9rem 1fr; gap: 0.35rem 0.8rem;
  margin: 0; font-size: 0.92rem;
}
.kv dt { color: var(--muted); }
.kv dd { margin: 0; word-break: break-all; }

/* CVE detail page extras. .json-block renders the raw cvelistV5 record
   as a scrollable pre-formatted block; .ref-list is borderless with a
   snippet under each link; .inline-label keeps the ingest / fetch
   inline forms aligned. */
.json-block {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.6rem 0.8rem;
  overflow-x: auto;
  max-height: 520px;
  font-size: 0.82em;
  white-space: pre;
}
.ref-list { list-style: none; padding-left: 0; margin: 0.5rem 0; }
.ref-list li { padding: 0.45rem 0; border-bottom: 1px dashed var(--border); }
.ref-list li:last-child { border-bottom: none; }
.ref-list .snippet { margin: 0.25rem 0 0; font-size: 0.88em; }
.inline-label { display: inline-flex; align-items: center; gap: 0.35rem; margin-right: 0.5rem; }

/* Dashboard CVE tile — sits inline with the other .stat KPI cards.
   Wider (min-width 380px) so the four per-year chips fit on one row;
   flex-wrap on .stats means it drops to its own row on narrow viewports. */
.stat-cve { min-width: 380px; padding: 0.9rem 1.1rem; }
.stat-cve-headline {
  display: block; text-decoration: none; color: inherit;
}
.stat-cve-headline .num {
  display: block; font-size: 1.75rem; font-weight: 700; color: var(--accent);
}
.stat-cve-headline .label { color: var(--muted); font-size: 0.9em; }
.stat-cve-years {
  display: grid; gap: 0.45rem; margin-top: 0.6rem;
  grid-template-columns: repeat(4, 1fr);
}
.stat-cve-year {
  display: block; background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 5px; padding: 0.4rem 0.55rem; text-decoration: none;
  color: inherit; text-align: center; transition: border-color 0.12s;
}
.stat-cve-year:hover { border-color: var(--accent, #66ff66); }
.stat-cve-year .y-num { display: block; font-size: 1rem; font-weight: 600; }
.stat-cve-year .y-label { color: var(--muted); font-size: 0.75em; }
.stat-cve-foot { margin-top: 0.5rem; font-size: 0.8em; }

/* APEX HUB Assistant — two-column chat layout. Conversation list on
   the left, active conversation + input on the right. Drops to a
   stacked layout on narrow viewports. */
.assistant-layout {
  display: grid; grid-template-columns: 260px 1fr; gap: 1.25rem;
  margin-top: 1rem;
}
@media (max-width: 720px) {
  .assistant-layout { grid-template-columns: 1fr; }
}
.assistant-sidebar {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 0.75rem 0.85rem;
  height: fit-content;
}
.assistant-sidebar-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 0.4rem;
}
.assistant-sidebar-head h3 { margin: 0; font-size: 0.95rem; }
.assistant-conv-list { list-style: none; padding: 0; margin: 0; }
.assistant-conv-item {
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.45rem 0.55rem; border-radius: 6px;
  border: 1px solid transparent;
}
.assistant-conv-item:hover { background: var(--panel-2); }
.assistant-conv-item.is-active {
  border-color: var(--accent, #66ff66);
  background: var(--panel-2);
}
.assistant-conv-item a {
  flex: 1; text-decoration: none; color: inherit; min-width: 0;
}
.assistant-conv-title {
  font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
.assistant-main {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 0.85rem 1rem;
  min-height: 480px; display: flex; flex-direction: column;
}
.assistant-head h2 { margin: 0 0 0.2rem; }
.assistant-messages {
  flex: 1; display: flex; flex-direction: column; gap: 0.85rem;
  margin: 0.75rem 0 0.5rem; overflow-y: auto;
}
.assistant-msg {
  border: 1px solid var(--border); border-radius: 8px;
  padding: 0.6rem 0.85rem;
}
.assistant-msg-user { background: var(--panel-2); }
.assistant-msg-assistant { background: var(--panel); }
.assistant-msg-role {
  text-transform: uppercase; font-size: 0.7em; letter-spacing: 0.08em;
  color: var(--muted); margin-bottom: 0.3rem;
}
.assistant-msg-body p { margin: 0.25rem 0; }
.assistant-tools { margin-top: 0.5rem; }
.assistant-tools .json-block { max-height: 200px; }
.assistant-input {
  display: flex; gap: 0.5rem; margin-top: 0.6rem;
  align-items: flex-end;
}
.assistant-input textarea {
  flex: 1; padding: 0.55rem 0.7rem;
  background: var(--panel-2); color: inherit;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: inherit; font-size: 0.95rem; resize: vertical;
}
.assistant-empty h2 { margin-top: 0.25rem; }
.assistant-examples { margin-top: 1rem; }
.assistant-examples ul { margin: 0.4rem 0 0 1.1rem; padding: 0; }
.json-block.small { font-size: 0.72em; max-height: 220px; }

/* Floating APEX HUB Assistant widget — bottom-right chat bubble + slide-up panel.
   Rendered on every page from base.html for signed-in users. */
.apex-assist {
  position: fixed; bottom: 18px; right: 18px; z-index: 9000;
  font-family: inherit;
}
.apex-assist-toggle {
  width: 54px; height: 54px; border-radius: 50%;
  background: var(--accent, #66ff66); color: var(--on-accent);
  border: none; cursor: pointer; font-size: 1.5rem;
  box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  transition: transform 0.15s;
}
.apex-assist-toggle:hover { transform: scale(1.05); }
.apex-assist-panel {
  position: absolute; bottom: 68px; right: 0;
  width: 380px; max-width: calc(100vw - 36px);
  height: 520px; max-height: calc(100vh - 120px);
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 12px 36px rgba(0,0,0,0.4);
  display: flex; flex-direction: column; overflow: hidden;
  /* Animated collapse / expand. Default state is collapsed (scaled to 0
     from the bottom-right corner) so the floating button stands alone
     until the user clicks. Transition both transform + opacity so the
     panel fades in as it scales up. */
  transform-origin: bottom right;
  transition: transform 0.18s ease-out, opacity 0.18s ease-out;
}
.apex-assist-collapsed .apex-assist-panel {
  transform: scale(0.85) translateY(8px);
  opacity: 0;
  pointer-events: none;
}
.apex-assist-expanded .apex-assist-panel {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}
/* Subtle pulse on the toggle when collapsed so it's discoverable */
.apex-assist-collapsed .apex-assist-toggle {
  animation: apex-assist-bob 4s ease-in-out infinite;
}
@keyframes apex-assist-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
}
.apex-assist-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 0.55rem 0.75rem; border-bottom: 1px solid var(--border);
  background: var(--panel-2);
}
.apex-assist-head-actions {
  display: flex; align-items: center; gap: 0.4rem;
}
.apex-assist-messages {
  flex: 1; padding: 0.6rem 0.75rem; overflow-y: auto;
  display: flex; flex-direction: column; gap: 0.55rem;
}
.apex-assist-msg {
  padding: 0.5rem 0.7rem; border-radius: 8px;
  font-size: 0.92rem; line-height: 1.4;
}
.apex-assist-msg p { margin: 0; }
.apex-assist-msg-user {
  background: var(--panel-2); align-self: flex-end;
  max-width: 88%;
}
.apex-assist-msg-assistant {
  background: rgba(102,255,102,0.06);
  border: 1px solid rgba(102,255,102,0.15);
  align-self: flex-start; max-width: 95%;
}
.apex-assist-msg-pending { opacity: 0.7; }
.apex-assist-form {
  display: flex; gap: 0.45rem; padding: 0.55rem 0.75rem;
  border-top: 1px solid var(--border);
}
.apex-assist-form textarea {
  flex: 1; padding: 0.45rem 0.6rem;
  background: var(--panel-2); color: inherit;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: inherit; font-size: 0.92rem; resize: none;
}
.apex-assist-foot { margin: 0 0.75rem 0.5rem; font-size: 0.75em; }

/* Maximize modal — full-screen overlay using <dialog>. The browser
   handles scrim + Esc-to-close; we just size and theme it. */
.apex-assist-modal {
  width: min(960px, 92vw);
  height: min(82vh, 820px);
  padding: 0;
  background: var(--panel);
  color: inherit;
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 24px 60px rgba(0,0,0,0.55);
}
.apex-assist-modal::backdrop {
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(2px);
}
.apex-assist-modal[open] {
  display: flex; flex-direction: column;
}
.apex-assist-modal-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 0.65rem 0.9rem;
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
}
.apex-assist-modal-messages {
  flex: 1; padding: 0.9rem 1.1rem; overflow-y: auto;
  display: flex; flex-direction: column; gap: 0.6rem;
}
.apex-assist-modal-messages .apex-assist-msg {
  font-size: 0.95rem; line-height: 1.5;
  max-width: 78%;
}

/* Payload Analyzer — static analysis console. Two-card layout (input
   + results), severity-tagged findings cards. Reuses the .sev-* palette
   from the main app so analysts see the same color cues across pages. */
.payload-analyzer {
  display: flex; flex-direction: column; gap: 1.1rem;
  margin: 1rem 0;
}
.payload-input-row {
  display: flex; align-items: center; gap: 0.75rem;
  margin-bottom: 0.55rem; flex-wrap: wrap;
}
.payload-analyzer textarea#pa-input {
  width: 100%; padding: 0.6rem 0.75rem;
  background: var(--panel-2); color: inherit;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: "JetBrains Mono", ui-monospace, "Cascadia Mono", "Source Code Pro", Menlo, monospace;
  font-size: 0.88rem; resize: vertical;
}
.payload-actions {
  display: flex; gap: 0.6rem; align-items: center;
  margin-top: 0.6rem; flex-wrap: wrap;
}
.payload-summary {
  display: flex; flex-direction: column; gap: 0.3rem;
  margin: 0.35rem 0 0.45rem;
}
.payload-summary-row { display: flex; gap: 0.45rem; align-items: center; flex-wrap: wrap; }
.payload-findings {
  display: flex; flex-direction: column; gap: 0.65rem;
}
.payload-finding {
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 0.7rem 0.9rem;
}
.payload-finding header {
  display: flex; align-items: center; gap: 0.55rem;
  margin-bottom: 0.35rem;
}
.payload-finding header strong { font-size: 0.95rem; }
.payload-finding p { margin: 0.2rem 0; }
.payload-finding-snippet {
  background: rgba(0,0,0,0.25); border: 1px solid var(--border);
  border-radius: 5px; padding: 0.45rem 0.65rem;
  font-size: 0.8em; overflow-x: auto; white-space: pre-wrap;
  word-break: break-all; margin: 0.4rem 0;
}

/* Payload Analyzer — AI analysis section (signed-in users). */
.payload-ai-status {
  display: flex; align-items: center; gap: 0.6rem; margin-top: 0.8rem;
}
.payload-ai-output {
  margin-top: 0.9rem; padding-top: 0.8rem;
  border-top: 1px solid var(--border);
}
.payload-ai-output > :first-child { margin-top: 0; }
.payload-ai-output h2 {
  font-size: 1.06rem; margin: 1.15rem 0 0.45rem; color: var(--accent);
}
.payload-ai-output h3 { font-size: 0.98rem; margin: 0.9rem 0 0.35rem; }
.payload-ai-output pre {
  background: var(--code-bg); color: var(--code-fg);
  padding: 0.7rem 0.9rem; border-radius: 8px; overflow-x: auto;
}
.payload-ai-output code {
  background: var(--code-bg); color: var(--code-fg);
  padding: 0.08rem 0.32rem; border-radius: 4px; font-size: 0.9em;
}
.payload-ai-output pre code { padding: 0; background: none; }
.payload-ai-ref-note {
  background: rgba(255,61,110,0.14); color: var(--critical);
  box-shadow: inset 0 0 0 1px rgba(255,61,110,0.40);
  padding: 0.55rem 0.8rem; border-radius: 8px;
  margin-bottom: 0.9rem; font-size: 0.92rem;
}
.payload-ai-limit {
  display: inline-block;
  background: rgba(243,182,100,0.16); color: var(--warn);
  box-shadow: inset 0 0 0 1px rgba(243,182,100,0.42);
  padding: 0.5rem 0.8rem; border-radius: 8px; font-size: 0.92rem;
}

/* Payload Analyzer — headline verdict banner in the Summary card. */
.payload-verdict {
  display: inline-block; font-size: 1.05rem; font-weight: 700;
  padding: 0.45rem 0.9rem; border-radius: 8px; margin-bottom: 0.55rem;
}
.payload-verdict-critical,
.payload-verdict-high {
  background: rgba(255,61,110,0.16); color: var(--critical);
  box-shadow: inset 0 0 0 1px rgba(255,61,110,0.45);
}
.payload-verdict-medium {
  background: rgba(243,182,100,0.16); color: var(--warn);
  box-shadow: inset 0 0 0 1px rgba(243,182,100,0.40);
}
.payload-verdict-low {
  background: rgba(95,208,124,0.16); color: var(--good);
  box-shadow: inset 0 0 0 1px rgba(95,208,124,0.40);
}
.payload-verdict-info {
  background: var(--panel-2); color: var(--muted);
  box-shadow: inset 0 0 0 1px var(--border);
}

/* Severity edge accents on the finding card border-left so analysts can
   scan a long list by color. */
.payload-finding-critical { border-left: 4px solid var(--critical, #ff3d6e); }
.payload-finding-high     { border-left: 4px solid var(--bad, #ef6a6a); }
.payload-finding-medium   { border-left: 4px solid var(--warn, #f3b664); }
.payload-finding-low      { border-left: 4px solid var(--good, #5fd07c); }
.payload-finding-info     { border-left: 4px solid #9ca3af; }

/* Threat detail — per-IOC enrichment cards (IOC database / Threat Hunt
   corroboration / Details From VirusTotal). Each indicator is a native
   <details> so a threat with many IOCs stays scannable. */
.ioc-card {
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel); margin: 0.5rem 0;
}
.ioc-card > summary {
  padding: 0.5rem 0.75rem; cursor: pointer;
  display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;
}
.ioc-card > summary code { word-break: break-all; }
.ioc-card[open] > summary { border-bottom: 1px solid var(--border); }
.ioc-card-body { padding: 0.25rem 0.9rem 0.9rem; }
.ioc-card-body h4 {
  margin: 0.9rem 0 0.3rem; font-size: 0.95rem;
  border-bottom: 1px solid var(--border); padding-bottom: 0.2rem;
}
.ioc-card-body h5 {
  margin: 0.7rem 0 0.2rem; font-size: 0.74rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.vt-detail-table { width: auto; }
.vt-detail-table td:first-child {
  white-space: nowrap; color: var(--muted); width: 1%;
}
.vt-detail-table td code { word-break: break-all; }
.vt-names {
  columns: 2; gap: 1.25rem; font-size: 0.85em;
  margin: 0.2rem 0; padding-left: 1.1rem;
}
.vt-names li code { word-break: break-all; }

/* Circular wait spinner — shown next to the "searching for remediations"
   message while an auto-queued agent search is in flight. */
.spinner {
  display: inline-block; width: 1em; height: 1em;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: apex-spin 0.8s linear infinite;
  vertical-align: -0.15em; margin-right: 0.4em;
}
@keyframes apex-spin { to { transform: rotate(360deg); } }

/* Pulsing glow for the "please wait…" remediation-search message. */
.glow-text {
  animation: apex-glow 1.7s ease-in-out infinite;
  font-weight: 600;
}
@keyframes apex-glow {
  0%, 100% { color: var(--text); text-shadow: 0 0 4px var(--accent-glow); }
  50% {
    color: var(--accent);
    text-shadow: 0 0 10px var(--accent), 0 0 22px var(--accent-glow);
  }
}

/* In-progress remediation-search banner — spinner + message. */
.search-progress { display: flex; align-items: center; gap: 0.6rem; }
.search-progress .spinner {
  width: 1.3em; height: 1.3em; flex-shrink: 0; margin-right: 0;
}

/* Payload Analyzer — captured-payload preview cell. Clamps a snippet of
   (escaped, inert) malicious content so it can't blow out the table. */
.payload-preview {
  display: block; max-width: 40ch;
  white-space: pre-wrap; word-break: break-all;
  font-size: 0.78em; max-height: 4.5em; overflow: hidden;
}
/* Admin captured-payloads — full (escaped, inert) payload body. */
.payload-full {
  white-space: pre-wrap; word-break: break-all;
  max-height: 24em; overflow: auto; margin-top: 0.4rem;
}
.payload-findings-list { list-style: none; padding-left: 0; margin: 0.3rem 0; }
.payload-findings-list li {
  margin: 0.4rem 0; padding: 0.35rem 0.5rem;
  border-left: 3px solid var(--border); background: var(--panel-2);
}

/* Detail pages (Threat / CVE / IOC / Threat Hunt) stack their content
   as a column of <section class="card"> blocks. These rules make each
   card a uniform self-contained panel with a flush <h2> title, an
   accent underline, and a tactical-SOC top-edge accent band coloured
   by the section's --page-accent (so /threats cards glow red, /cves
   glow purple, etc). See threat_detail.html, cve_detail.html,
   ioc_detail.html, threat_hunt.html. */
section.card {
  margin: 0 0 1rem; padding: 1rem 1.2rem;
  position: relative;
  box-shadow: 0 2px 10px rgba(0,0,0,0.28);
  overflow: hidden;
}
[data-theme="light"] section.card { box-shadow: 0 2px 10px rgba(31, 95, 196, 0.08); }
section.card::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--page-accent), transparent 80%);
  opacity: 0.95;
  pointer-events: none;
}
section.card > h2:first-child,
section.card > .section-head:first-child > h2,
section.card > details.collapsible-section:first-child > summary > h2 {
  margin-top: 0;
  padding-bottom: 0.5rem;
  margin-bottom: 0.75rem;
  border-bottom: 1px solid var(--border);
  font-size: 1.15rem;
  letter-spacing: 0.01em;
  color: var(--page-accent);
  text-shadow: 0 0 18px var(--page-accent-glow);
}
[data-theme="light"] section.card > h2:first-child,
[data-theme="light"] section.card > .section-head:first-child > h2,
[data-theme="light"] section.card > details.collapsible-section:first-child > summary > h2 {
  text-shadow: none;
}
section.card > .section-head:first-child {
  margin-top: 0;
  margin-bottom: 0.75rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}
section.card > .section-head:first-child > h2 {
  border-bottom: none;
  padding-bottom: 0;
  margin-bottom: 0;
}
/* Inside a card, paragraphs shouldn't be muted by default — the older
   .card p rule was for the cards-grid item style. Restore prose color
   for body text inside detail-page cards. */
section.card > p,
section.card > .desc,
section.card > dl,
section.card > details > p,
section.card > details > .desc { color: var(--text); }
section.card p.muted,
section.card .muted { color: var(--muted); }

/* Collapsible card body — wraps Raw JSON, long Affected lists, etc.
   The <summary> swallows the click; we strip the default disclosure
   triangle and emit our own chevron flush to the title. */
details.collapsible-section > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
details.collapsible-section > summary::-webkit-details-marker { display: none; }
details.collapsible-section > summary::marker { content: ""; }
details.collapsible-section > summary > h2 {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
}
details.collapsible-section > summary > h2::after {
  content: "▸";
  color: var(--muted);
  font-size: 0.85em;
  transition: transform 0.15s ease;
  margin-left: auto;
}
details.collapsible-section[open] > summary > h2::after {
  transform: rotate(90deg);
}

/* ============================================================
   APEX command-center shell
   Left sidebar (vertical nav, brand, user card, theme toggle) +
   main pane (sticky topbar with search + clock, then page
   content). Replaces the legacy horizontal .topbar / .global-search
   blocks; the legacy rules for those classes are now orphan but
   harmless since the markup no longer emits them.
   ============================================================ */

.apex-shell {
  display: grid;
  grid-template-columns: 220px 1fr;
  min-height: 100vh;
}

.apex-sidebar {
  background: rgba(8, 16, 31, 0.6);
  border-right: 1px solid var(--border);
  padding: 24px 0 16px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  backdrop-filter: blur(20px);
  z-index: 5;
}
[data-theme="light"] .apex-sidebar {
  background: rgba(255, 255, 255, 0.78);
}

.apex-sidebar::-webkit-scrollbar { width: 6px; }
.apex-sidebar::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.apex-sidebar::-webkit-scrollbar-track { background: transparent; }

/* ---- Brand at the top of the sidebar ---- */
.apex-brand {
  padding: 0 24px 22px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 22px;
}
.apex-brand-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: inherit;
}
.apex-brand-link:hover { text-decoration: none; }
.apex-brand-mark {
  width: 28px; height: 28px;
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.apex-brand-mark svg { display: block; width: 100%; height: 100%; }
.apex-brand-word {
  font-family: var(--apex-font-display);
  font-size: 26px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--text);
}
.apex-brand-sub {
  margin-top: 6px;
  font-size: 9.5px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 500;
}

/* ---- Section labels (Operations / Admin) ---- */
.apex-nav-label {
  padding: 0 24px;
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 10px;
  margin-top: 6px;
}

/* ---- Nav items ---- */
.apex-nav {
  list-style: none;
  margin: 0 0 14px;
  padding: 0 12px;
}
.apex-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  margin-bottom: 1px;
  border-radius: 6px;
  color: var(--muted);
  font-family: var(--apex-font-body);
  font-size: 13px;
  font-weight: 400;
  text-decoration: none;
  position: relative;
  transition: background 0.15s ease, color 0.15s ease;
}
.apex-nav-item:hover {
  background: var(--panel-2);
  color: var(--text);
  text-decoration: none;
}
.apex-nav-item.is-active {
  background: var(--accent-glow);
  color: var(--page-accent, var(--accent));
}
.apex-nav-item.is-active::before {
  content: '';
  position: absolute;
  left: -12px;
  top: 50%;
  transform: translateY(-50%);
  width: 2px;
  height: 18px;
  background: var(--page-accent, var(--accent));
  border-radius: 0 2px 2px 0;
}
.apex-nav-ic {
  width: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  opacity: 0.85;
  flex-shrink: 0;
}

/* ---- Sidebar foot: user card + theme toggle ---- */
.apex-sidebar-foot {
  margin-top: auto;
  padding: 14px 12px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.apex-user-card {
  padding: 12px 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.apex-user-label {
  font-family: var(--apex-font-mono);
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}
.apex-user-email {
  font-family: var(--apex-font-mono);
  font-size: 11px;
  color: var(--text);
  word-break: break-all;
  line-height: 1.4;
}
.apex-user-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 2px;
}
.apex-user-signout {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 3px 8px;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.apex-user-signout:hover { color: var(--text); border-color: var(--accent); }
.apex-user-card-signin { text-align: center; }
.apex-sidebar-foot .theme-toggle {
  margin: 0;
  align-self: flex-start;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ---- Main pane ---- */
.apex-main-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;       /* allow grid child to shrink and contain children */
  min-height: 100vh;
}
.apex-topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 28px;
  border-bottom: 1px solid var(--border);
  background: rgba(8, 16, 31, 0.65);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 4;
}
[data-theme="light"] .apex-topbar {
  background: rgba(255, 255, 255, 0.85);
}
.apex-search {
  flex: 0 1 1040px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: border-color 0.15s ease;
  position: relative;
}
.apex-search:focus-within { border-color: var(--accent); }
.apex-search-ic { color: var(--muted); flex-shrink: 0; }
.apex-search-input {
  flex: 1;
  background: transparent;
  border: 0;
  outline: none;
  font-family: var(--apex-font-mono);
  font-size: 12px;
  color: var(--text);
  min-width: 0;
}
.apex-search-input::placeholder { color: var(--muted); }
.apex-kbd {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 2px 6px;
  border-radius: 3px;
}
.apex-search-btn {
  font-family: var(--apex-font-mono);
  font-size: 11px;
  padding: 4px 10px;
  margin: 0;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.apex-topbar-spacer { flex: 1; }
.apex-clock {
  font-family: var(--apex-font-mono);
  font-size: 12px;
  color: var(--text);
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.apex-clock-tz { color: var(--muted); margin-left: 6px; font-size: 11px; }

/* Theme toggle living in the topbar (right of the clock).
   Compact 32×32 square so it visually balances the clock and
   doesn't push the layout. */
.apex-topbar-theme {
  margin: 0 0 0 12px;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  border-radius: 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  flex-shrink: 0;
}
.apex-topbar-theme:hover { border-color: var(--accent); }

/* ---- Main content padding ---- */
.apex-main {
  padding: 28px 32px 48px;
  min-width: 0;
}

/* ---- Responsive collapse (mobile / narrow) ---- */
@media (max-width: 960px) {
  .apex-shell { grid-template-columns: 1fr; }
  .apex-sidebar {
    position: static;
    height: auto;
    border-right: none;
    border-bottom: 1px solid var(--border);
    flex-direction: column;
  }
  .apex-sidebar-foot { padding-top: 8px; }
  .apex-topbar { padding: 12px 18px; }
  .apex-main { padding: 20px 18px 40px; }
}

/* ============================================================
   APEX shared component library
   Page-agnostic building blocks modeled on design/reference.html.
   Used by index.html (dashboard hero) and progressively rolled
   out to the rest of the templates.
   ============================================================ */

/* ---- Page header (greeting + threat-level meter) ---- */
.apex-page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 28px;
  flex-wrap: wrap;
}
.apex-page-title {
  font-family: var(--apex-font-display);
  font-weight: 400;
  font-size: 38px;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0;
}
.apex-page-title em {
  font-style: italic;
  color: var(--accent);
}
.apex-page-sub {
  margin: 10px 0 0;
  color: var(--muted);
  font-size: 13px;
  max-width: 720px;
}
.apex-page-meta {
  text-align: right;
}
.apex-page-meta-label {
  font-family: var(--apex-font-mono);
  font-size: 9px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
}
.apex-page-meta-value {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--apex-font-mono);
  font-size: 18px;
  letter-spacing: 0.05em;
  color: var(--warn);
}
.apex-page-meta-value.critical { color: var(--critical); }
.apex-page-meta-value.warning  { color: var(--warn); }
.apex-page-meta-value.accent   { color: var(--accent); }
.apex-page-meta-value.success  { color: var(--good); }
.apex-page-meta-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 12px currentColor;
}

/* ---- Panel (the universal container) ---- */
.apex-panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  margin: 0 0 20px;
}
.apex-panel-header {
  padding: 16px 22px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.apex-panel-title {
  font-family: var(--apex-font-body);
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
}
.apex-panel-title-sub {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 0.1em;
}
.apex-panel-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.apex-panel-body {
  padding: 18px 22px 22px;
}
.apex-panel-body.flush { padding: 0; }
/* Override .apex-panel-body padding helpers used by certain pages */
.apex-panel-body.tight { padding: 10px 14px; }

/* ---- Chip (filter / state toggle) ---- */
.apex-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--apex-font-mono);
  font-size: 10px;
  padding: 4px 10px;
  border-radius: 4px;
  background: var(--panel-2);
  color: var(--muted);
  border: 1px solid transparent;
  cursor: pointer;
  letter-spacing: 0.05em;
  text-decoration: none;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.apex-chip:hover { border-color: var(--border); color: var(--text); text-decoration: none; }
.apex-chip.is-active { background: var(--accent-glow); color: var(--accent); border-color: transparent; }

/* ---- KPI card ---- */
.apex-kpi {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
  position: relative;
  overflow: hidden;
  transition: border-color 0.2s ease;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.apex-kpi:hover { border-color: var(--border-strong, var(--accent-2)); }
.apex-kpi-label {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.apex-kpi-trend {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 3px;
  letter-spacing: 0;
}
.apex-kpi-trend.up      { background: var(--critical-dim, rgba(232,93,93,0.12)); color: var(--critical); }
.apex-kpi-trend.down    { background: rgba(111,207,151,0.12); color: var(--good); }
.apex-kpi-trend.flat    { background: var(--panel-2); color: var(--muted); }
.apex-kpi-trend.accent  { background: rgba(91,200,230,0.15); color: var(--accent); }
.apex-kpi-value {
  font-family: var(--apex-font-display);
  font-weight: 400;
  font-size: 46px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text);
}
.apex-kpi-value.critical { color: var(--critical); }
.apex-kpi-value.warning  { color: var(--warn); }
.apex-kpi-value.accent   { color: var(--accent); }
.apex-kpi-value.success  { color: var(--good); }
.apex-kpi-detail {
  font-family: var(--apex-font-mono);
  font-size: 11px;
  color: var(--muted);
}
.apex-kpi-spark {
  position: absolute;
  right: 16px;
  bottom: 14px;
  width: 80px;
  height: 28px;
  opacity: 0.55;
  pointer-events: none;
}

/* ---- Live feed item ---- */
.apex-feed { padding: 6px 0; }
.apex-feed-item {
  padding: 14px 22px;
  border-bottom: 1px solid var(--border);
  position: relative;
  cursor: pointer;
  transition: background 0.15s ease;
}
.apex-feed-item:hover { background: var(--panel-2); }
.apex-feed-item:last-child { border-bottom: none; }
.apex-feed-item::before {
  content: '';
  position: absolute;
  left: 0; top: 14px; bottom: 14px;
  width: 2px;
  background: transparent;
}
.apex-feed-item.sev-critical::before,
.apex-feed-item.crit::before  { background: var(--critical); }
.apex-feed-item.sev-high::before,
.apex-feed-item.warn::before  { background: var(--warn); }
.apex-feed-item.sev-medium::before,
.apex-feed-item.info::before  { background: var(--accent); }
.apex-feed-item.sev-low::before { background: var(--good); }

.apex-feed-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
  gap: 8px;
}
.apex-feed-type {
  font-family: var(--apex-font-mono);
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
}
.apex-feed-time {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  color: var(--muted);
}
.apex-feed-ioc {
  font-family: var(--apex-font-mono);
  font-size: 12px;
  color: var(--text);
  margin-bottom: 6px;
  word-break: break-all;
  line-height: 1.4;
}
.apex-feed-source {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  color: var(--muted);
  gap: 8px;
}

/* ---- Confidence meter (used in feed items, IOC tables) ---- */
.apex-confidence {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.apex-confidence-bar {
  width: 40px;
  height: 3px;
  background: var(--panel-2);
  border-radius: 2px;
  overflow: hidden;
}
.apex-confidence-fill {
  height: 100%;
  background: var(--good);
  border-radius: 2px;
}
.apex-confidence-fill.warn { background: var(--warn); }
.apex-confidence-fill.crit { background: var(--critical); }
.apex-confidence-num {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  color: var(--muted);
}

/* ---- Threat actor row ---- */
.apex-actor-list { padding: 6px 0; }
.apex-actor {
  padding: 14px 22px;
  display: grid;
  grid-template-columns: 32px 1fr auto 80px;
  gap: 14px;
  align-items: center;
  border-bottom: 1px solid var(--border);
  transition: background 0.15s ease;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}
.apex-actor:hover { background: var(--panel-2); text-decoration: none; }
.apex-actor:last-child { border-bottom: none; }
.apex-actor-rank {
  font-family: var(--apex-font-display);
  font-style: italic;
  font-size: 20px;
  color: var(--muted);
  text-align: center;
  line-height: 1;
}
.apex-actor-name {
  font-family: var(--apex-font-mono);
  font-size: 12px;
  color: var(--text);
  font-weight: 500;
}
.apex-actor-tags {
  margin-top: 4px;
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.apex-actor-tag {
  font-family: var(--apex-font-mono);
  font-size: 9px;
  padding: 1px 5px;
  border-radius: 2px;
  background: var(--panel-2);
  color: var(--muted);
  letter-spacing: 0.05em;
}
.apex-actor-count {
  font-family: var(--apex-font-mono);
  font-size: 13px;
  color: var(--text);
  text-align: right;
  line-height: 1;
}
.apex-actor-count-sub {
  font-family: var(--apex-font-mono);
  font-size: 9px;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-top: 3px;
  text-align: right;
}
.apex-actor-spark { width: 80px; height: 24px; }

/* ---- MITRE ATT&CK coverage heatmap ---- */
.apex-mitre {
  padding: 20px 22px;
}
.apex-mitre-grid {
  display: grid;
  grid-template-columns: repeat(14, 1fr);
  gap: 3px;
}
.apex-mitre-tactic { text-align: center; min-width: 0; }
.apex-mitre-tactic-name {
  font-family: var(--apex-font-body);
  font-size: 8.5px;
  color: var(--muted);
  margin-bottom: 4px;
  letter-spacing: 0.02em;
  height: 30px;
  line-height: 1.15;
  overflow: hidden;
}
.apex-mitre-cells {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.apex-mitre-cell {
  width: 100%;
  aspect-ratio: 1.3;
  border-radius: 2px;
  /* Filler / empty-column cell (no technique exists in this
     slot). Kept almost-invisible so the heatmap's grid is
     visible but the empty cells don't compete with real data. */
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.04);
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
  position: relative;
  display: block;
  text-decoration: none;
}
.apex-mitre-cell:hover {
  transform: scale(1.4);
  z-index: 2;
  box-shadow: 0 0 0 1px var(--accent), 0 4px 12px rgba(0, 0, 0, 0.4);
}
/* Less → more gradient. Each step is visually distinct so a
   glance at the heatmap immediately conveys activity volume.
   - l0: technique exists, 0 observations (dim cool)
   - l1: 1-4   observations  (success green)
   - l2: 5-14  observations  (cool cyan)
   - l3: 15-49 observations  (warning amber)
   - l4: 50+   observations  (critical red + soft glow) */
.apex-mitre-cell.l0 { background: rgba(138, 154, 181, 0.18); border-color: rgba(138, 154, 181, 0.30); }
.apex-mitre-cell.l1 { background: rgba(111, 207, 151, 0.55); border-color: rgba(111, 207, 151, 0.75); }
.apex-mitre-cell.l2 { background: rgba( 91, 200, 230, 0.65); border-color: rgba( 91, 200, 230, 0.85); }
.apex-mitre-cell.l3 { background: rgba(242, 177,  74, 0.80); border-color: rgba(242, 177,  74, 0.95); }
.apex-mitre-cell.l4 { background: rgba(232,  93,  93, 0.92); border-color: rgba(232,  93,  93, 1.00); box-shadow: 0 0 10px rgba(232, 93, 93, 0.55); }

/* Light theme — same less→more ramp, darker base hues so the
   gradient still reads on a light background. */
[data-theme="light"] .apex-mitre-cell    { background: rgba(0, 0, 0, 0.05); border-color: rgba(0, 0, 0, 0.08); }
[data-theme="light"] .apex-mitre-cell.l0 { background: rgba(75, 86, 104, 0.22); border-color: rgba(75, 86, 104, 0.40); }
[data-theme="light"] .apex-mitre-cell.l1 { background: rgba( 21, 128, 61, 0.55); border-color: rgba( 21, 128, 61, 0.75); }
[data-theme="light"] .apex-mitre-cell.l2 { background: rgba( 14, 126,198, 0.55); border-color: rgba( 14, 126,198, 0.75); }
[data-theme="light"] .apex-mitre-cell.l3 { background: rgba(178, 120, 43, 0.75); border-color: rgba(178, 120, 43, 0.90); }
[data-theme="light"] .apex-mitre-cell.l4 { background: rgba(190,  23, 72, 0.85); border-color: rgba(190,  23, 72, 1.00); }
.apex-mitre-foot {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--apex-font-mono);
  font-size: 10px;
  color: var(--muted);
  gap: 12px;
  flex-wrap: wrap;
}
.apex-mitre-scale {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.apex-mitre-scale-cell {
  width: 14px;
  height: 10px;
  border-radius: 2px;
}

/* ---- Generic grids that line up KPI cards / panel rows ---- */
.apex-kpi-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
@media (max-width: 1200px) {
  .apex-kpi-row { grid-template-columns: repeat(2, 1fr); }
}
.apex-canvas-row {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 16px;
  margin-bottom: 24px;
}
@media (max-width: 1200px) {
  .apex-canvas-row { grid-template-columns: 1fr; }
}
.apex-bottom-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 1200px) {
  .apex-bottom-row { grid-template-columns: 1fr; }
}

/* ---- Buttons that exist inside .apex-panel-actions ---- */
.apex-panel-actions .apex-chip + .apex-chip { margin-left: 2px; }

/* ---- Atmosphere — subtle radial gradients that match the
   reference's command-center vibe. Active by default, neutralised
   under the light theme. ---- */
.apex-main-pane { position: relative; }
.apex-main-pane::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 80% 50% at 15% 0%,  rgba(91,200,230,0.05), transparent 60%),
    radial-gradient(ellipse 60% 40% at 90% 100%, rgba(242,177,74,0.035), transparent 60%);
  pointer-events: none;
  z-index: 0;
}
[data-theme="light"] .apex-main-pane::before { display: none; }
/* Stack only the actual content children above the ::before
   atmosphere — explicit selectors so overlays (ai-jobs-overlay,
   <dialog>, assistant widget) keep their own position: fixed /
   position: absolute and don't get pulled into document flow. */
.apex-main-pane > .apex-topbar,
.apex-main-pane > .apex-main { position: relative; z-index: 1; }

/* ============================================================
   Legacy-class → APEX-panel chrome compatibility
   Detail pages (threat_detail, cve_detail, ioc_detail) and most
   admin pages use <section class="card"> ... <h2>...</h2> ...
   </section> as their containment pattern. Rather than rewrite
   every template, we re-skin .card to mirror .apex-panel so the
   whole app picks up uniform chrome.
   ============================================================ */

.apex-main section.card,
.apex-main .card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px 22px;
  margin: 0 0 20px;
  box-shadow: none;
}
.apex-main section.card > h2:first-child,
.apex-main .card > h2:first-child {
  margin: 0 0 14px;
  padding: 0 0 12px;
  border-bottom: 1px solid var(--border);
  font-family: var(--apex-font-body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text);
}
.apex-main section.card > h2:first-child::after,
.apex-main .card > h2:first-child::after {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  margin-left: 10px;
  background: var(--page-accent, var(--accent));
  vertical-align: middle;
  box-shadow: 0 0 8px var(--page-accent, var(--accent));
  opacity: 0.7;
}

/* Breadcrumb — restrained and mono. */
.apex-main .breadcrumb {
  font-family: var(--apex-font-mono);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin: 0 0 16px;
  text-transform: uppercase;
}
.apex-main .breadcrumb a {
  color: var(--muted);
  text-decoration: none;
}
.apex-main .breadcrumb a:hover { color: var(--accent); }
.apex-main .breadcrumb code {
  font-family: var(--apex-font-mono);
  color: var(--text);
  background: transparent;
  padding: 0;
}

/* Filter bar — used on list pages (threats, cves, iocs,
   hunt). Make it a flex row of inputs that visually belongs
   inside .apex-panel-body. */
.apex-main .filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 0 0 16px;
}
.apex-main .filter-bar input[type="text"],
.apex-main .filter-bar select,
.apex-main .filter-bar input:not([type]) {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 7px 10px;
  border-radius: 6px;
  font-family: var(--apex-font-mono);
  font-size: 12px;
  outline: none;
  transition: border-color 0.15s ease;
}
.apex-main .filter-bar input:focus,
.apex-main .filter-bar select:focus { border-color: var(--accent); }
.apex-main .filter-bar input[type="text"] { min-width: 240px; flex: 1 1 240px; max-width: 360px; }
.apex-main .filter-bar button,
.apex-main .filter-bar .ghost {
  padding: 7px 14px;
  font-family: var(--apex-font-mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: 6px;
}
.apex-main .filter-bar button.primary,
.apex-main .filter-bar button[type="submit"] {
  background: var(--accent);
  color: var(--on-accent);
  border: 1px solid transparent;
  font-weight: 600;
  cursor: pointer;
}
.apex-main .filter-bar button.primary:hover { filter: brightness(1.08); border-color: transparent; }

/* Subtitle / muted page descriptors */
.apex-main p.subtitle {
  color: var(--muted);
  font-size: 13px;
  margin: 0 0 16px;
  max-width: 720px;
}

/* Actions bar (used on detail pages above the main panel) */
.apex-main .actions-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin: 0 0 18px;
}
.apex-main .actions-bar button.primary,
.apex-main .actions-bar a.primary {
  background: var(--accent);
  color: var(--on-accent);
  border: 1px solid transparent;
  padding: 7px 14px;
  border-radius: 6px;
  font-family: var(--apex-font-mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.apex-main .actions-bar a.primary:hover { filter: brightness(1.08); text-decoration: none; }

/* Pager — turn the existing .pager into a row of chips */
.apex-main .pager {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.apex-main .pager a,
.apex-main .pager .ghost {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  padding: 4px 10px;
  border-radius: 4px;
  background: var(--panel-2);
  color: var(--muted);
  border: 1px solid transparent;
  letter-spacing: 0.05em;
  text-decoration: none;
}
.apex-main .pager a:hover { border-color: var(--border-strong, var(--border)); color: var(--text); }
.apex-main .pager .disabled { opacity: 0.4; }
.apex-main .pager span:not(.ghost):not(.disabled) {
  font-family: var(--apex-font-mono);
  font-size: 10px;
  color: var(--text);
  padding: 4px 10px;
  background: var(--accent-glow);
  color: var(--accent);
  border-radius: 4px;
  letter-spacing: 0.05em;
}

/* Data tables: when they appear inside .apex-panel-body.flush
   we want them flush with the panel edges, no double border. */
.apex-main .apex-panel-body.flush > table.data {
  border: 0;
  border-radius: 0;
  margin: 0;
}

/* Severity stat tiles for the threat-origin map panel.
   Same panel, same visual concept (colored dots + glow) as
   the legend it replaces — but big enough to read at a glance. */
.apex-map-stats {
  position: absolute;
  left: 22px;
  bottom: 18px;
  display: flex;
  gap: 10px;
  z-index: 2;
}
.apex-map-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 14px;
  min-width: 84px;
  background: rgba(8, 16, 31, 0.72);
  border: 1px solid var(--border);
  border-radius: 8px;
  backdrop-filter: blur(8px);
}
[data-theme="light"] .apex-map-stat {
  background: rgba(255, 255, 255, 0.82);
}
.apex-map-stat-head {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--apex-font-mono);
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.apex-map-stat-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 8px currentColor;
  flex-shrink: 0;
}
.apex-map-stat-num {
  font-family: var(--apex-font-display);
  font-weight: 400;
  font-size: 26px;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--text);
}
.apex-map-stat-crit .apex-map-stat-dot,
.apex-map-stat-crit .apex-map-stat-num { color: var(--critical); }
.apex-map-stat-warn .apex-map-stat-dot,
.apex-map-stat-warn .apex-map-stat-num { color: var(--warn); }
.apex-map-stat-acc .apex-map-stat-dot,
.apex-map-stat-acc .apex-map-stat-num  { color: var(--accent); }

/* Embedded top-source-countries table — overlaid on the
   Threat Origin Map's top-right. Compact: 10 rows of country
   code + name + threat count + a bar that visualises rank
   share. Reads more like an inset HUD than a regular data
   table. */
.apex-map-countries {
  position: absolute;
  right: 22px;
  top: 18px;
  width: 280px;
  max-height: calc(100% - 36px);
  padding: 10px 12px;
  background: rgba(8, 16, 31, 0.78);
  border: 1px solid var(--border);
  border-radius: 8px;
  backdrop-filter: blur(8px);
  z-index: 2;
  overflow: hidden;
}
[data-theme="light"] .apex-map-countries {
  background: rgba(255, 255, 255, 0.85);
}
.apex-map-countries-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--apex-font-mono);
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.apex-map-countries-link {
  color: var(--muted);
  text-decoration: none;
  font-size: 12px;
  line-height: 1;
}
.apex-map-countries-link:hover { color: var(--accent); }
.apex-map-countries-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--apex-font-mono);
  font-size: 10.5px;
}
.apex-map-countries-table tr { line-height: 1; }
.apex-map-countries-table td {
  padding: 4px 4px;
  vertical-align: middle;
  border: none;
  background: transparent;
}
.apex-map-countries-rank {
  width: 16px;
  color: var(--muted);
  text-align: right;
  padding-right: 6px !important;
}
.apex-map-countries-code {
  color: var(--accent);
  font-weight: 600;
  width: 32px;
}
.apex-map-countries-name {
  color: var(--text);
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.apex-map-countries-num {
  color: var(--text);
  font-weight: 600;
  text-align: right;
  width: 38px;
  padding-right: 6px !important;
}
.apex-map-countries-bar {
  width: 56px;
  padding-left: 4px !important;
}
.apex-map-countries-bar > span {
  display: block;
  height: 3px;
  border-radius: 2px;
  background: var(--accent);
}
