:root {
  --bg: #0f1320; --panel: #171c2e; --line: #2a3149; --txt: #e6e9f2;
  --muted: #9aa3bd; --accent: #4f8cff;
  --crit: #e5484d; --high: #f76808; --med: #f5a623; --low: #3e9b4f; --unk: #6b7280;
  font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--txt); }
header {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 20px; border-bottom: 1px solid var(--line); background: var(--panel);
}
header h1 { font-size: 18px; margin: 0; font-weight: 650; }
.badge { margin-left: auto; color: var(--muted); font-size: 13px;
  border: 1px solid var(--line); padding: 3px 8px; border-radius: 6px; }
main { max-width: 980px; margin: 0 auto; padding: 18px 20px 60px; }
section { margin-bottom: 16px; }
.config { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
input, textarea {
  background: var(--panel); border: 1px solid var(--line); color: var(--txt);
  border-radius: 8px; padding: 8px 10px; font-size: 14px;
}
textarea { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }
.row { display: flex; align-items: center; gap: 10px; margin: 8px 0; }
.spacer { flex: 1; }
button {
  background: var(--panel); color: var(--txt); border: 1px solid var(--line);
  border-radius: 8px; padding: 8px 14px; font-size: 14px; cursor: pointer;
}
button.primary { background: var(--accent); border-color: var(--accent); font-weight: 600; }
.resultsbar { display: flex; align-items: center; gap: 10px; margin: 4px 0 -4px; }
.resultsummary { color: var(--muted); font-size: 13px; }
button:disabled { opacity: .6; cursor: default; }
label.file { flex-direction: row; align-items: center; cursor: pointer;
  border: 1px dashed var(--line); padding: 6px 10px; border-radius: 8px; color: var(--txt); }
label.file input { display: none; }
.status { padding: 10px 12px; border-radius: 8px; font-size: 13px; border: 1px solid var(--line); }
.status.ok { border-color: #2f6b3a; background: #16241a; }
.status.warn { border-color: #7a5a14; background: #261f10; }
.status.err { border-color: #7a2326; background: #261314; }

.comp { border: 1px solid var(--line); border-radius: 10px; margin-bottom: 10px; background: var(--panel); overflow: hidden; }
.comp summary { display: flex; gap: 10px; align-items: center; padding: 10px 12px; cursor: pointer; flex-wrap: wrap; }
/* flex items default to min-width:auto and will NOT shrink below their
   content, so one long unbroken purl/cpe pushes the row out of the card.
   min-width:0 lets them shrink; overflow-wrap:anywhere lets the token
   break mid-string (it also shrinks the cell's min-content width, which
   is what keeps the findings TABLE inside the card too). */
.comp summary > * { min-width: 0; }
.cid { font-weight: 600; overflow-wrap: anywhere; }
.ident { color: var(--muted); font-size: 13px; overflow-wrap: anywhere; }
.vcount { margin-left: auto; color: var(--muted); font-size: 13px; flex-shrink: 0; }
.st { font-size: 11px; padding: 2px 7px; border-radius: 999px; border: 1px solid var(--line); text-transform: uppercase; letter-spacing: .03em; flex-shrink: 0; white-space: nowrap; }
.st-matched { color: #ffd7d7; border-color: var(--crit); }
.st-matched_no_vulns { color: #c9f0d2; border-color: var(--low); }
.st-unresolved, .st-version_parse_error { color: var(--muted); }
.st-ambiguous { color: var(--med); border-color: var(--med); }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 7px 12px; border-top: 1px solid var(--line); vertical-align: top; overflow-wrap: anywhere; }
/* scalar cells (severity/assurance/cvss/epss/confidence): never wrap --
   wrapping is for prose and long identifiers, not badges and numbers */
td.num { white-space: nowrap; overflow-wrap: normal; }
/* header labels are short words; the blanket anywhere-wrap above must
   not break them mid-word (CVSS/EPSS/Sources were wrapping) */
th { white-space: nowrap; overflow-wrap: normal; }
th { color: var(--muted); font-weight: 500; }
/* ID column: sized to a long CVE (CVE-2024-123456); GHSA-length ids wrap
   once instead of stretching the column, so the field reads the same
   width on every row. The alias line is capped in JS (+N more). */
th.col-id { width: 16ch; }
.vid { font-family: ui-monospace, monospace; overflow-wrap: anywhere; }
.aka { display: block; color: var(--muted); font-size: 11px; overflow-wrap: anywhere; }
.ver { font-family: ui-monospace, monospace; color: var(--muted); }
.ver em, .ident em { color: var(--accent); font-style: normal; }
.sev { font-size: 11px; padding: 2px 7px; border-radius: 6px; color: #fff;
       white-space: nowrap; display: inline-block; min-width: 4ch;
       text-align: center; }
.sev-critical { background: var(--crit); }
.sev-high { background: var(--high); }
.sev-medium { background: var(--med); color: #1a1a1a; }
.sev-low { background: var(--low); }
.sev-unknown { background: var(--unk); }

/* Assurance tier -- how much weight a finding carries on its own. Deliberately
   NOT colour-coded like severity: this is a statement about evidence quality,
   not danger, and a red "review" would read as "worse vulnerability" when it
   only means "look before forwarding". */
.assur { font-size: 11px; padding: 2px 7px; border-radius: 6px;
         border: 1px solid var(--line); color: var(--muted);
         white-space: nowrap; }
.assur-maintainer { border-color: var(--low); color: var(--low); font-weight: 600; }
.assur-auto_forward { border-color: var(--txt); color: var(--txt); }
.assur-review { border-style: dashed; }

/* Inline with the action button; the explanation lives in title= so the row
   stays one line. help cursor signals there is something to hover. */
label.check { display: inline-flex; align-items: center; gap: 6px;
              cursor: help; white-space: nowrap; font-size: 13px;
              color: var(--muted); margin-right: 12px; }
label.check input { width: auto; margin: 0; cursor: pointer; }
label.check:hover { color: var(--txt); }

footer { border-top: 1px solid var(--line); color: var(--muted); padding: 14px 20px; text-align: center; }
footer code { color: var(--txt); }

/* single-component fields + token badge */
.fields { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 8px 0; }
.fields label { font-size: 13px; }
.fields input { width: 100%; }
.tokenrow { display: flex; align-items: center; gap: 8px; }
.tokenrow input { flex: 1; }
.tokbadge { font-size: 12px; white-space: nowrap; color: var(--muted); }
.tokbadge.ok { color: var(--low); }
.tokbadge.bad { color: var(--crit); }
.input > strong { display: block; margin-bottom: 6px; }

.reason { padding: 8px 12px; color: var(--muted); font-size: 13px; border-top: 1px solid var(--line); }

/* ambiguous candidate picker + raw JSON view */
.cands { padding: 8px 12px; }
.cands small { color: var(--muted); }
.cands table { margin-top: 6px; }
.cands td { padding: 5px 12px; }
.cands a { color: var(--accent); text-decoration: none; font-weight: 600; }
.summary .ver, summary .ver { color: var(--muted); font-family: ui-monospace, monospace; }
details.raw { margin: 6px 12px 10px; }
details.raw > summary { cursor: pointer; color: var(--muted); font-size: 12px; padding: 4px 0; }
details.raw pre { background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
  padding: 10px; overflow: auto; font-size: 12px; max-height: 360px; }

/* remediation / distro-backport "patched" annotation */
.patched { display: inline-block; font-size: 11px; padding: 2px 7px; border-radius: 6px;
  background: var(--low); color: #fff; font-weight: 600; }
.fixsrc { display: block; color: var(--muted); font-size: 11px; margin-top: 2px;
  font-family: ui-monospace, monospace; }
/* a backport-patched vuln is reported but not actually affecting -> dim it */
tr.is-patched td { opacity: .6; }
tr.is-patched .vid { text-decoration: line-through; }
/* auto-applied distro patches: collapsed group, clearly "resolved" */
details.patched-group { margin: 6px 12px 10px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--bg); }
details.patched-group > summary { cursor: pointer; color: var(--low);
  font-size: 12px; padding: 7px 12px; font-weight: 600; }

/* candidate confidence (tier confidence halved by ambiguity) */
.cands .cconf { color: var(--muted); font-size: 11px; white-space: nowrap; }

/* flag-for-review button (summary row) */
.flagbtn {
  margin-left: auto; border: 1px solid var(--muted); background: transparent;
  color: var(--muted); border-radius: 4px; font-size: 11px; padding: 1px 7px;
  cursor: pointer;
}
.flagbtn:hover { color: var(--txt); border-color: var(--txt); }
.flagbtn.flagged { color: #d99014; border-color: #d99014; cursor: default; }

/* product-group marker: vendor variants whose vulns were unioned */
.grp { color: #7fb0ff; font-size: 12px; }

/* input-vs-matched identity grid (expanded component view) */
.identgrid { display: flex; gap: 24px; padding: 8px 12px; border-top: 1px solid var(--line);
  font-size: 12px; flex-wrap: wrap; }
.identcol { min-width: 240px; flex: 1; }
.identcol h4 { margin: 0 0 4px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); }
.identcol .kv { display: flex; gap: 8px; padding: 1px 0; }
.identcol .k { color: var(--muted); min-width: 80px; }
.identcol .v { word-break: break-all; }
.identcol .kv.minor .v, .identcol .kv.minor .k { color: var(--muted); font-size: 11px; }

/* matched-package marker in the summary row */
.pkg { color: var(--muted); }

/* ---- component identity quality banner ---- */
.qualitybar {
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  padding: .45rem .7rem; margin: .4rem 0; border-radius: 6px;
  /* the page theme is DARK: any light panel must pin its own DARK text,
     or it inherits the page's light text and reads as blank */
  background: #dbe8fa; border: 1px solid #a9c7ef; color: #16304d;
}
.qscore { font-weight: 600; padding: .1rem .5rem; border-radius: 4px; }
.q-high   { background: #e6f4ea; color: #137333; }
.q-medium { background: #fef7e0; color: #b06000; }
.q-low    { background: #fce8e6; color: #c5221f; }
.qcounts.ok   { color: #137333; }
.qcounts.warn { color: #b06000; font-weight: 600; }
.qrelease { color: #1a56a8; }
.qtime { margin-left: auto; color: #40587a; }

/* ---- per-component identification ---- */
.identline { display: flex; flex-wrap: wrap; gap: .35rem; margin: .3rem 0 0; }
.idchip {
  font-size: .75rem; padding: .05rem .45rem; border-radius: 999px;
  background: #eef1f4; color: #444; border: 1px solid #dde3e8;
  max-width: 100%; overflow-wrap: anywhere;
}
.idchip.rel { background: #e8f0fe; color: #1a56a8; border-color: #c6dafc; }
.idchip.fam { background: #fef7e0; color: #b06000; border-color: #f5e6b8; }
.idchip.withheld { background: #f3e8fd; color: #6a1b9a; border-color: #e1cff5; }
.conflict {
  margin: .35rem 0 0; padding: .35rem .6rem; border-radius: 4px;
  background: #fce8e6; color: #a50e0e; border: 1px solid #f5c6c0;
  font-size: .85rem;
}
.profile { margin: .25rem 0 0; color: #666; font-size: .8rem; font-style: italic; }
.hintpick {
  display: flex; gap: .4rem; align-items: center; flex-wrap: wrap;
  margin: .4rem 0 0; padding: .4rem .6rem; border-radius: 4px;
  background: #fff8e6; border: 1px dashed #e0c877; color: #5c4a12;
}
.hintpick input { background: #fff; color: #222; border-color: #d9c88a; }
.hintpick input { width: 11rem; }
