/*
 * Author: Tim Rice <tim.j.rice@hackrange.com>
 * Part of nextgen-dast. See README.md for license and overall architecture.
 *
 * Modern dark theme: near-black canvas, slightly raised cards with soft
 * borders + radius, pill buttons, and a left sidebar layout. Severity
 * colors are themed via CSS custom properties set per-deployment in
 * base.html so the branding admin can override without touching this file.
 */

:root {
  /* Canvas + surfaces. The two-step "panel above bg" pattern gives cards
     a subtle lift without leaning on heavy shadows. */
  --bg:        #0a0b0d;
  --panel:     #14161a;
  --panel-2:   #1b1e23;
  --elevated:  #1f242b;
  --border:    rgba(255, 255, 255, .07);
  --border-strong: rgba(255, 255, 255, .12);

  /* Text */
  --text:      #e6e8ec;
  --text-soft: #c2c7cf;
  --muted:     #7a828d;
  --muted-2:   #5b6168;

  /* Brand + accents — overridden per-deployment via the branding system. */
  --accent:    #5fb3d7;
  --accent-2:  #4a9fc4;
  --green:     #61c08f;
  --red:       #e87060;
  --yellow:    #e4b757;
  --orange:    #e08a4f;

  /* Layout */
  --sidebar-w: 240px;
  --radius-card:   14px;
  --radius-input:  10px;
  --radius-pill:   9999px;
}

/* ---- Light theme palette ------------------------------------------ */
/* Activated when the body carries class="theme-light". The default
   :root dark values stay in place; this rule re-binds the CSS
   variables for the light variant so every existing component
   (cards, severity dots, brand accents, typeahead popup, etc.)
   inherits the new colors without any per-component changes.

   Severity colors stay the same regardless of theme so a critical
   on the dashboard still reads as critical at a glance — the
   accessibility win of consistent severity mapping outweighs the
   slight aesthetic mismatch. */
body.theme-light {
  --bg:        #f6f7f9;
  --panel:     #ffffff;
  --panel-2:   #eef0f4;
  --elevated:  #e3e7ed;
  --border:    rgba(15, 23, 42, .09);
  --border-strong: rgba(15, 23, 42, .18);

  --text:      #111827;
  --text-soft: #1f2937;
  --muted:     #4b5563;
  --muted-2:   #9ca3af;
}
/* Anchor color in the light palette uses the brand primary (blue)
   rather than the secondary accent (which is green by default).
   The previous rule (`color: var(--accent-2)`) was what made the
   Re-scan button render as green-on-blue: anchors inheriting the
   green link color while the .button background painted the
   primary blue. Hover stays on the secondary so the anchor still
   has a visible state change. */
body.theme-light a        { color: var(--accent); }
body.theme-light a:hover  { color: var(--accent-2); }
/* `<a class="button">` (Re-scan, Save, …) MUST keep the button's
   contrasting text color regardless of the theme's link rules.
   `body.theme-light a.button` has higher specificity than
   `body.theme-light a`, so it wins the cascade. Without this rule
   the anchor link color leaks into the button text, producing the
   green-on-blue Re-scan bug. */
body.theme-light a.button,
body.theme-light a.button:hover { color: #07111a; }
body.theme-light a.button.ghost,
body.theme-light a.button.ghost:hover { color: var(--text); }
/* Form controls in the light palette need a visible default fill so
   inputs and selects don't blend into the page background. Border
   stays the existing strong-border variable for consistency. */
body.theme-light input[type="text"],
body.theme-light input[type="search"],
body.theme-light input[type="password"],
body.theme-light input[type="number"],
body.theme-light input[type="email"],
body.theme-light input[type="url"],
body.theme-light textarea,
body.theme-light select {
  background: var(--panel);
}
/* Scrollbar styling for both themes — keep them subtle and matched
   to the surrounding panel color. */
body.theme-light ::-webkit-scrollbar { width: 10px; height: 10px; }
body.theme-light ::-webkit-scrollbar-track { background: var(--panel-2); }
body.theme-light ::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 5px;
}

/* ---- Theme toggle page (radio + swatch row) ----------------------- */
.theme-option {
  display: flex; gap: .9em; align-items: center;
  padding: .9em 1em; margin-bottom: .6em;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-card);
  background: var(--panel);
  cursor: pointer;
}
.theme-option:hover { border-color: var(--accent); }
.theme-option input[type="radio"] { margin: 0; }
.theme-swatch {
  display: inline-block; width: 36px; height: 36px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  flex-shrink: 0;
}
.theme-swatch-dark  { background: linear-gradient(135deg,#0a0b0d,#1b1e23); }
.theme-swatch-light { background: linear-gradient(135deg,#ffffff,#e9ecf1); }
.theme-meta { display: flex; flex-direction: column; gap: .15em; }

/* ---- Grade badge (A-F letter on Assessments tables) --------------- */
/* Dedicated traffic-light palette so an A is unambiguously green and
   an F is unambiguously red, decoupled from the severity color
   scheme used elsewhere on the dashboard. Each tier uses a translucent
   fill (so it reads as a chip, not a solid block) plus a stronger
   foreground color for the letter itself. The exact hex values
   match the standard 2.3 contrast bar against both the dark and
   light theme panels. */
.grade-badge {
  display: inline-block;
  min-width: 1.4em;
  padding: .15em .55em;
  font-weight: 700;
  font-size: .95em;
  text-align: center;
  border-radius: var(--radius-pill);
  letter-spacing: .02em;
  border: 1px solid transparent;
}
.grade-badge.grade-a {
  color: #1f7a3a;
  background: rgba(45, 138, 79, 0.18);
  border-color: rgba(45, 138, 79, 0.45);
}
.grade-badge.grade-b {
  color: #4a8c5a;
  background: rgba(123, 196, 127, 0.20);
  border-color: rgba(123, 196, 127, 0.45);
}
.grade-badge.grade-c {
  color: #b07e0e;
  background: rgba(212, 160, 23, 0.22);
  border-color: rgba(212, 160, 23, 0.50);
}
.grade-badge.grade-d {
  color: #b8451e;
  background: rgba(224, 138, 79, 0.22);
  border-color: rgba(224, 138, 79, 0.50);
}
.grade-badge.grade-f {
  color: #ffffff;
  background: rgba(192, 57, 43, 0.78);
  border-color: rgba(107, 31, 31, 0.95);
}
.grade-badge.grade-none {
  color: var(--muted);
  background: transparent;
  border-color: var(--border);
}
/* Light theme — slightly stronger fills so the chip reads on
   white-ish panels. Letter color stays the same. */
body.theme-light .grade-badge.grade-a {
  background: rgba(45, 138, 79, 0.14);
}
body.theme-light .grade-badge.grade-b {
  background: rgba(123, 196, 127, 0.18);
}
body.theme-light .grade-badge.grade-c {
  background: rgba(212, 160, 23, 0.20);
}
body.theme-light .grade-badge.grade-d {
  background: rgba(224, 138, 79, 0.22);
}

* { box-sizing: border-box; }

html, body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, system-ui, "Segoe UI", "Inter", sans-serif;
  margin: 0;
  padding: 0;
  font-size: 14px;
  line-height: 1.5;
  font-feature-settings: "ss01", "cv11"; /* nicer numerals where supported */
  -webkit-font-smoothing: antialiased;
}

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

/* Code / pre baseline styling. Unified across themes -- the same
   subtle panel-on-text look in both dark and light mode so code
   reads as a callout without dominating the page. The CSS
   variables `--code-bg` / `--code-fg` / `--code-border` track the
   surrounding theme automatically (panel-2 / text / border are
   already re-bound by `body.theme-light`), so the code block sits
   one shade off the surrounding card in either palette. */
code, pre {
  font-family: ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;
  font-size: .92em;
}
:root {
  --code-bg:     var(--panel-2);
  --code-fg:     var(--text);
  --code-border: var(--border-strong);
}
code {
  background: var(--code-bg);
  color: var(--code-fg);
  border: 1px solid var(--code-border);
  padding: .08em .32em;
  border-radius: 3px;
}
pre {
  background: var(--code-bg);
  color: var(--code-fg);
  border: 1px solid var(--code-border);
  padding: .85em 1em;
  border-radius: 6px;
  overflow-x: auto;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}
pre code {
  background: transparent;
  border: 0;
  padding: 0;
  border-radius: 0;
  color: inherit;
}

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

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

aside.sidebar {
  background: var(--panel);
  border-right: 1px solid var(--border);
  padding: 1.2em 0.9em 1em;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}
/* Logo stacked above the company name and centered horizontally inside
   the sidebar column. flex-direction:column gives the image its own
   row; align-items:center centers the logo and the name underneath it.
   text-align:center handles the inline-text alignment on the company
   name so a long name still reads centered when it wraps. */
aside.sidebar .brand {
  display: flex; flex-direction: column; align-items: center;
  gap: .35em;
  padding: .2em .4em .8em;
  font-weight: 700;
  color: var(--text);
  font-size: 14px;
  letter-spacing: -.01em;
  text-align: center;
}
/* With the logo on its own row we can give it more vertical room than
   the previous inline 22px cap. Width is capped at the sidebar's
   content area so a wide banner image scales down proportionally
   instead of overflowing; object-fit:contain preserves aspect ratio.
   The !important rules defeat any user-uploaded <img width=...>
   attribute or cached older stylesheet. */
aside.sidebar .brand img {
  height: auto !important;
  max-height: 56px !important;
  width: auto !important;
  max-width: 100% !important;
  object-fit: contain;
  flex-shrink: 0;
  display: block;
}

aside.sidebar .cta {
  display: flex; align-items: center; justify-content: center; gap: .4em;
  background: var(--accent);
  color: #07111a;
  font-weight: 700;
  border-radius: var(--radius-pill);
  padding: .55em 1em;
  margin: .35em .25em 1.2em;
  text-decoration: none;
  transition: background-color .12s ease;
}
aside.sidebar .cta:hover { background: var(--accent-2); color: #07111a;
                           text-decoration: none; }

aside.sidebar .nav-section {
  font-size: .72em;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--muted-2);
  padding: 1em .8em .35em;
}

aside.sidebar nav { display: flex; flex-direction: column; gap: 1px; }
aside.sidebar nav a {
  display: flex; align-items: center; gap: .6em;
  padding: .5em .8em;
  border-radius: 8px;
  color: var(--text-soft);
  font-size: .92em;
  font-weight: 500;
  transition: background-color .12s, color .12s;
}
aside.sidebar nav a:hover {
  background: var(--panel-2);
  color: var(--text);
  text-decoration: none;
}
aside.sidebar nav a.active {
  background: var(--panel-2);
  color: var(--text);
}
/* Inline-SVG icons. Default size applies anywhere the svg.icon class
   appears (nav rows, the CTA, inline buttons). Without this universal
   rule an unsized <svg> renders at its intrinsic size and blows the
   layout up — that was the "crazy light-blue triangle" in the CTA. */
.icon {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  opacity: .85;
  display: inline-block;
  vertical-align: middle;
}
aside.sidebar nav a.active .icon,
aside.sidebar nav a:hover .icon { opacity: 1; }
aside.sidebar .cta .icon { opacity: 1; color: inherit; }

aside.sidebar .sidebar-footer {
  margin-top: auto;
  padding-top: 1em;
  border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 1px;
}
aside.sidebar .user-pill {
  display: flex; align-items: center; gap: .55em;
  padding: .55em .8em;
  margin-top: .3em;
  font-size: .9em;
  color: var(--text-soft);
}
aside.sidebar .user-pill .avatar {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: #07111a;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: .82em;
}
aside.sidebar .user-pill .username { font-weight: 600; color: var(--text); }
aside.sidebar .user-pill .role { font-size: .78em; color: var(--muted); }
aside.sidebar form.signout { margin: .25em .25em 0; }
aside.sidebar form.signout button {
  width: 100%;
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-soft);
  font-weight: 500;
  border-radius: 8px;
  padding: .35em .6em;
  font-size: .82em;
  cursor: pointer;
}
aside.sidebar form.signout button:hover {
  border-color: var(--text-soft);
  color: var(--text);
}
aside.sidebar .build-tag {
  font-size: .72em;
  color: var(--muted-2);
  padding: .8em .8em 0;
  letter-spacing: .04em;
}

/* Mobile: collapse sidebar to top bar. */
@media (max-width: 800px) {
  .app { grid-template-columns: 1fr; }
  aside.sidebar {
    position: relative;
    height: auto;
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding: .8em;
  }
  aside.sidebar nav { flex-direction: row; flex-wrap: wrap; }
  aside.sidebar .sidebar-footer { display: none; }
}

/* ---- Main column ---------------------------------------------------- */

main.main {
  padding: 1.6em 1.8em 2.4em;
  /* No max-width: let the main column fill the viewport up to the
     edge of the sidebar. The 1400 px cap previously left blank
     space on the right of any monitor wider than ~1640 px (sidebar
     + content + scrollbar). Cards and tables already cap their own
     readable widths internally where it matters; the grid and the
     assessments table specifically benefit from the extra room. */
}
main.main h1 {
  font-weight: 700;
  font-size: 1.7em;
  letter-spacing: -.015em;
  margin: 0 0 .6em;
  color: var(--text);
}
main.main h2 {
  font-weight: 600;
  font-size: 1em;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .07em;
  margin: 0 0 .8em;
}
main.main h3 { font-weight: 600; font-size: 1em; color: var(--text); margin: 0 0 .4em; }

/* Classification banner (when set) */
.classification-banner {
  background: var(--red);
  color: #fff;
  text-align: center;
  font-weight: 700;
  padding: .25em;
  font-size: .8em;
  letter-spacing: .08em;
}

/* ---- Cards ---------------------------------------------------------- */

section, .card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 1.2em 1.4em;
  margin-bottom: 1.2em;
}
section.bare, .card.bare {
  background: transparent; border: 0; padding: 0;
}
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: .8em;
}
.card-header h2 { margin: 0; }

.grid       { display: grid; gap: 1.1em; grid-template-columns: 1fr 1fr; }
.grid-3     { display: grid; gap: 1.1em; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1100px) { .grid-3 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 800px)  { .grid, .grid-3 { grid-template-columns: 1fr; } }

/* ---- Tables --------------------------------------------------------- */

table { width: 100%; border-collapse: collapse; font-size: .92em; }
th, td {
  padding: .55em .7em;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
th {
  font-weight: 600;
  color: var(--muted);
  font-size: .76em;
  text-transform: uppercase;
  letter-spacing: .06em;
}
tbody tr:hover { background: rgba(255,255,255,.02); }
td.url {
  font-family: ui-monospace, Menlo, monospace;
  font-size: .85em;
  word-break: break-all;
  max-width: 50ch;
}

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

form { display: flex; flex-direction: column; gap: .7em; }
label { display: flex; flex-direction: column; gap: .25em; font-size: .9em;
        color: var(--text-soft); }
label.check { flex-direction: row; align-items: center; gap: .5em; }

input, select, textarea {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  padding: .55em .7em;
  border-radius: var(--radius-input);
  font-size: 14px;
  font-family: inherit;
  transition: border-color .12s, background-color .12s;
}
input:hover, select:hover, textarea:hover { border-color: var(--muted); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--elevated);
}
textarea { font-family: ui-monospace, Menlo, monospace; min-height: 5em; }

button, .button {
  cursor: pointer;
  background: var(--accent);
  color: #07111a;
  font-weight: 600;
  border: 0;
  padding: .55em 1.1em;
  font-size: 14px;
  font-family: inherit;
  border-radius: var(--radius-input);
  transition: background-color .12s, opacity .12s;
}
button:hover, .button:hover { background: var(--accent-2); }
button:disabled { opacity: .45; cursor: not-allowed; }
button.warn { background: var(--red); color: #fff; }
button.warn:hover { background: #d35a4a; }
button.ghost, .button.ghost {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text);
  font-weight: 500;
}
button.ghost:hover, .button.ghost:hover {
  background: var(--panel-2);
  border-color: var(--muted);
}
button.link, .button.link {
  background: transparent; padding: 0; color: var(--accent); font-weight: 500;
  border: 0;
}

dl { display: grid; grid-template-columns: max-content 1fr; gap: .35em 1em; margin: 0; }
dt { color: var(--muted); }
dd { margin: 0; word-break: break-all; }

/* ---- Status pills + badges ----------------------------------------- */

.badge {
  display: inline-flex; align-items: center; gap: .35em;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  font-size: .76em;
  font-weight: 600;
  background: var(--panel-2);
  color: var(--text-soft);
  border: 1px solid var(--border);
  letter-spacing: .01em;
}
.badge.warn      { background: rgba(228,183,87,.12); color: var(--yellow); border-color: transparent; }
.badge.red       { background: rgba(232,112,96,.13); color: var(--red); border-color: transparent; }
.badge.running   { background: rgba(95,179,215,.13); color: var(--accent); border-color: transparent; }
.badge.queued    { background: rgba(122,130,141,.16); color: var(--muted); border-color: transparent; }
.badge.consolidating { background: rgba(95,179,215,.13); color: var(--accent); border-color: transparent; }
.badge.done,
.badge.finished  { background: rgba(97,192,143,.14); color: var(--green); border-color: transparent; }
.badge.error     { background: rgba(232,112,96,.18); color: var(--red); border-color: transparent; }
.badge.cancelled,
.badge.killed,
.badge.deleting  { background: rgba(122,130,141,.16); color: var(--muted); border-color: transparent; }

/* Severity rendering — text + dot, not blocky background, so screen-reader
   users still get the word and color-blind users still get the label. */
.sev,
.badge.sev-critical, .badge.sev-high, .badge.sev-medium,
.badge.sev-low,      .badge.sev-info {
  background: transparent;
  border: 0;
  padding: 0 .15em;
  font-weight: 700;
  font-size: .82em;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.sev-critical, .badge.sev-critical { color: var(--sev-critical); }
.sev-high,     .badge.sev-high     { color: var(--sev-high); }
.sev-medium,   .badge.sev-medium   { color: var(--sev-medium); }
.sev-low,      .badge.sev-low      { color: var(--sev-low); }
.sev-info,     .badge.sev-info     { color: var(--sev-info); }

/* Severity dot used in the dashboard / pip rows. */
.sev-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: .35em;
}
.sev-dot.sev-critical { background: var(--sev-critical); }
.sev-dot.sev-high     { background: var(--sev-high); }
.sev-dot.sev-medium   { background: var(--sev-medium); }
.sev-dot.sev-low      { background: var(--sev-low); }
.sev-dot.sev-info     { background: var(--sev-info); }

/* ---- Dashboard primitives ------------------------------------------ */

.kpi-strip {
  display: flex; align-items: center; gap: 1.6em;
  padding: 1em 1.4em;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  margin-bottom: 1.2em;
  flex-wrap: wrap;
}
.kpi {
  display: flex; align-items: baseline; gap: .55em;
  font-size: .95em;
  color: var(--text-soft);
}
.kpi .v { font-size: 1.45em; font-weight: 700; color: var(--text); letter-spacing: -.01em; }
.kpi .lbl { font-size: .85em; color: var(--muted); }
.kpi .delta.up   { color: var(--red); }
.kpi .delta.down { color: var(--green); }

/* Pip row used inside cards (severity counts, time-to-fix tiles, etc.) */
.pip-row { display: flex; gap: .55em; flex-wrap: wrap; }
.pip {
  flex: 1; min-width: 88px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: .55em .7em;
  text-align: left;
}
.pip .lbl { font-size: .72em; color: var(--muted); text-transform: uppercase;
            letter-spacing: .07em; margin-bottom: .15em; }
.pip .n { font-size: 1.45em; font-weight: 700; color: var(--text); line-height: 1; }
.pip .sub { font-size: .78em; color: var(--muted); margin-top: .2em; }

.muted { color: var(--muted); }
.small { font-size: .85em; }
.ok    { color: var(--green); }
.err   { color: var(--red); }

/* Logs / pre blocks. Inherit the code-block palette set above so
   dark mode renders black + terminal green and light mode stays
   subtle. Override only the things that are log-specific (max-
   height + smaller font + tighter break rule). */
pre.log {
  background: var(--code-bg);
  color: var(--code-fg);
  border: 1px solid var(--code-border);
  border-radius: 10px;
  padding: .9em 1em;
  overflow: auto;
  max-height: 60vh;
  font-size: 12px;
  white-space: pre-wrap;
  word-break: break-all;
}

/* Footer (rarely used now — main info lives in the sidebar). */
footer {
  border-top: 1px solid var(--border);
  padding: 1em;
  text-align: center;
  color: var(--muted);
  font-size: .82em;
}

/* ---- Findings workspace (assessment_detail) ----------------------- */
/*
 * Three-column layout: filterable list (left) + selected finding's
 * detail (middle) + AT A GLANCE metadata + actions (right). Each
 * column is independently scrollable so the workspace fills the
 * viewport without the page itself scrolling.
 */
.fw {
  display: grid;
  grid-template-columns: 380px minmax(0, 1fr) 320px;
  gap: 1.1em;
  /* Fill the viewport minus the page header (h1 + KPI strip ~ 180px). */
  height: calc(100vh - 220px);
  min-height: 540px;
}
@media (max-width: 1200px) {
  .fw { grid-template-columns: 340px minmax(0, 1fr); }
  .fw .fw-aside { display: none; }
}
@media (max-width: 900px) {
  .fw { grid-template-columns: 1fr; height: auto; }
  .fw-list, .fw-detail { max-height: 60vh; }
}

.fw-list, .fw-detail, .fw-aside {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.fw-detail, .fw-aside { padding: 1.2em 1.4em; overflow-y: auto; }

.fw-list-toolbar {
  padding: .7em .8em;
  border-bottom: 1px solid var(--border);
  display: flex; gap: .4em; flex-wrap: wrap; align-items: center;
}
.fw-list-toolbar .tabs { display: flex; gap: .15em; }
.fw-list-toolbar .tabs a {
  padding: .35em .75em;
  border-radius: var(--radius-pill);
  font-size: .82em;
  font-weight: 500;
  color: var(--text-soft);
  text-decoration: none;
}
.fw-list-toolbar .tabs a:hover { background: var(--panel-2); text-decoration: none; }
.fw-list-toolbar .tabs a.active { background: var(--panel-2); color: var(--text); }

.fw-list-toolbar select,
.fw-list-toolbar input[type=search] {
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: .35em .55em;
  border-radius: 8px;
  font-size: .85em;
}
.fw-list-toolbar input[type=search] { flex: 1; min-width: 100px; }

.fw-list-items {
  overflow-y: auto;
  flex: 1;
  /* leave room for the bulk-action bar at the bottom (which is
     `position: sticky` inside this scroll container). */
}
.fw-item {
  display: flex; gap: .55em; align-items: flex-start;
  padding: .7em .9em;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background-color .12s;
  position: relative;
}
.fw-item:hover { background: var(--panel-2); }
.fw-item.active {
  background: var(--panel-2);
}
.fw-item.active::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; background: var(--accent);
}
.fw-item input[type=checkbox] {
  margin-top: .25em; cursor: pointer; flex-shrink: 0;
  accent-color: var(--accent);
}
.fw-item .fi-body { min-width: 0; flex: 1; }
.fw-item .fi-title {
  font-size: .9em; font-weight: 500; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.fw-item .fi-meta {
  display: flex; gap: .55em; align-items: center; flex-wrap: wrap;
  font-size: .76em; color: var(--muted); margin-top: .3em;
}
.fw-item.is-fp { opacity: .55; }

.fw-bulk-bar {
  position: sticky; bottom: 0;
  background: var(--elevated);
  border-top: 1px solid var(--border-strong);
  padding: .65em .8em;
  display: flex; gap: .5em; align-items: center; flex-wrap: wrap;
}
.fw-bulk-bar[hidden] { display: none; }
.fw-bulk-bar .count {
  font-size: .85em; font-weight: 600; color: var(--text);
  margin-right: auto;
}
.fw-bulk-bar button { padding: .3em .8em; font-size: .82em; }

/* Detail pane */
.fw-detail .detail-head {
  display: flex; align-items: flex-start; gap: 1em;
  padding-bottom: .8em; margin-bottom: 1em;
  border-bottom: 1px solid var(--border);
}
.fw-detail .detail-head .sev-label {
  display: block; font-size: .82em; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  margin-bottom: .25em;
}
.fw-detail .detail-head h2 {
  margin: 0; color: var(--text); text-transform: none; letter-spacing: 0;
  font-size: 1.2em; font-weight: 600;
}
.fw-detail .detail-head .head-chips {
  display: flex; gap: .35em; margin-top: .4em; flex-wrap: wrap;
}
.fw-detail h3.section {
  font-size: .8em; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); margin: 1.4em 0 .4em; font-weight: 600;
}
.fw-detail .empty {
  display: flex; align-items: center; justify-content: center;
  height: 100%; color: var(--muted); font-size: .9em;
}

/* Aside (AT A GLANCE) */
.fw-aside .aside-section {
  font-size: .72em; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); margin: 1.1em 0 .4em; font-weight: 600;
}
.fw-aside .aside-section:first-child { margin-top: 0; }
.fw-aside .aside-row {
  display: flex; justify-content: space-between; gap: .6em;
  padding: .25em 0; font-size: .85em;
}
.fw-aside .aside-row .lbl { color: var(--muted); }
.fw-aside .aside-row .val { color: var(--text); text-align: right;
                             word-break: break-word; max-width: 60%; }
.fw-aside .action-btn {
  display: flex; align-items: center; gap: .55em; width: 100%;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  padding: .55em .8em;
  margin: .35em 0 0;
  border-radius: 10px;
  font-size: .88em; font-weight: 500;
  text-align: left; cursor: pointer;
  transition: background-color .12s, border-color .12s;
}
.fw-aside .action-btn:hover {
  background: var(--elevated); border-color: var(--muted);
}
.fw-aside .action-btn.primary {
  background: var(--accent); color: #07111a; border-color: transparent;
  font-weight: 600;
}
.fw-aside .action-btn.primary:hover { background: var(--accent-2); }
.fw-aside .action-btn.warn {
  background: transparent; color: var(--red); border-color: var(--red);
}
.fw-aside .action-btn.warn:hover { background: rgba(232,112,96,.1); }

/* Page header for the assessment workspace */
.fw-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1em; flex-wrap: wrap;
  margin-bottom: 1em;
}
.fw-header .title { display: flex; flex-direction: column; gap: .15em; }
.fw-header h1 { margin: 0; }
.fw-header .subtitle { color: var(--muted); font-size: .9em;
                       display: flex; gap: .55em; align-items: center;
                       flex-wrap: wrap; }
.fw-header .actions { display: flex; gap: .5em; flex-wrap: wrap; }

/* ---- Dashboard trend chart ----------------------------------------- */
/* Layout: y-axis-labels | (svg + crosshair + x-axis-row) | y-axis-labels.
   The numbers live outside the SVG because the chart uses
   preserveAspectRatio="none" to fill the available width, which would
   otherwise stretch the text into unreadable smears. */
.trend-grid {
  display: grid;
  grid-template-columns: 2.4em 1fr 2.4em;
  gap: .55em;
  align-items: stretch;
  margin: .8em 0 .6em;
  position: relative;
}
.trend-yaxis {
  display: flex; flex-direction: column; justify-content: space-between;
  font-size: 11px; color: var(--muted);
  padding: 2px 0;
  text-align: right;
  height: 200px;
}
.trend-yaxis-right { text-align: left; }
.trend-svg-wrap {
  position: relative;
  height: 200px;
  cursor: crosshair;
}
.trend-svg {
  width: 100%; height: 100%; display: block;
}
.trend-xaxis {
  display: flex; justify-content: space-between;
  font-size: 11px; color: var(--muted);
  margin-top: 4px;
}
.trend-crosshair {
  position: absolute;
  top: 0; bottom: 0;
  width: 1px;
  background: rgba(255,255,255,.18);
  pointer-events: none;
  transform: translateX(-0.5px);
}
.trend-tooltip {
  position: absolute;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: .55em .7em;
  font-size: 12px;
  color: var(--text);
  pointer-events: none;
  white-space: nowrap;
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
  z-index: 20;
  min-width: 130px;
}
.trend-tooltip .tt-date {
  color: var(--muted); font-size: 11px; margin-bottom: 2px;
}
.trend-tooltip .tt-total {
  font-weight: 700; font-size: 14px; margin-bottom: 4px;
}
.trend-tooltip .tt-row {
  display: grid;
  grid-template-columns: 12px 1fr auto;
  align-items: center;
  gap: .4em;
  padding: 1px 0;
}
.trend-tooltip .tt-label { color: var(--muted); }
.trend-tooltip .tt-n { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---- Custom typeahead (used by trend filter and assessments table) -- */
/* flex-direction: row is intentional and load-bearing — there is a
   global `form { display: flex; flex-direction: column; }` rule
   higher up in this file (~line 313). Without an explicit row
   override here, `<form class="typeahead">` would inherit the
   column direction from the global rule and stack the search
   input, dropdowns, and Apply button vertically. The global rule
   exists because most forms in this app are vertical config
   panels; the typeahead filter is the exception. */
.typeahead {
  position: relative;
  display: flex; flex-direction: row;
  gap: .4em; align-items: center; flex-wrap: wrap;
}
.typeahead-input {
  width: 240px; font-size: .85em;
}
/* Wraps the search input + its suggestion <ul> in a dedicated
   positioning context. Without this, the absolutely-positioned
   suggestion popup anchors to the form (the closest positioned
   ancestor), which was fine when the input sat at the form's left
   edge but gives the wrong anchor now that the input lives at the
   right edge after dropdowns + Apply. The popup needs to drop
   directly under the input regardless of where the input sits in
   the row. */
.typeahead-wrap {
  position: relative;
  display: inline-block;
}
.typeahead-apply {
  padding: .35em .75em; font-size: .82em;
}
.typeahead-suggest {
  position: absolute;
  top: calc(100% + 4px); left: 0;
  margin: 0; padding: 4px 0;
  list-style: none;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  /* Match the input's actual rendered width (whatever the consuming
     form sized it to) so the popup never looks narrower than its
     anchor. The min-width keeps the popup readable when the input
     itself is unusually narrow. */
  width: 100%;
  min-width: 220px;
  max-height: 240px;
  overflow-y: auto;
  z-index: 30;
  box-shadow: 0 8px 22px rgba(0,0,0,.5);
}
.typeahead-suggest li {
  padding: .35em .7em;
  font-size: .88em;
  cursor: pointer;
  color: var(--text);
}
.typeahead-suggest li:hover,
.typeahead-suggest li.active {
  background: var(--panel);
  color: var(--text);
}

/* ---- Assessments filter bar ---------------------------------------- */
/* The filter row groups the FQDN search, the status dropdown, the
   page-size dropdown, and the Apply button. The default .typeahead
   rule sets flex-wrap: wrap, but we want all four controls to stay
   on a single row aligned with each other; let the parent
   .card-header wrap the WHOLE form below the h2 when the viewport
   is too narrow, but never split the controls themselves. */
.assessments-filter.typeahead {
  flex-wrap: nowrap;
  gap: .5em;
  /* Children flow naturally left-to-right: status dropdown,
     size dropdown, search wrap, Apply button, clear link. No
     margin tricks needed; the search wrap takes the slack
     between the dropdowns and Apply via flex-grow below. */
}
.assessments-filter .typeahead-wrap {
  /* Let the search wrap absorb spare horizontal space so the
     row stays neat on wider viewports. The input itself caps at
     its declared width, but the wrapper stretches and the input
     can grow with it via the rule below. */
  flex: 1 1 auto;
  min-width: 220px;
}
.assessments-filter .typeahead-input {
  /* Wider than the trend-chart filter input because customer FQDNs
     in the assessments table are routinely 30+ characters and were
     getting truncated visually inside a 200-px field. The input
     fills its wrapper (which grows via flex above) up to a 480 px
     ceiling so the row stays balanced rather than letting the
     search field eat half the page on a wide viewport. */
  width: 100%;
  min-width: 240px;
  max-width: 480px;
  box-sizing: border-box;
}
/* select.ghost wasn't styled before -- the existing rule only covered
   button.ghost / .button.ghost. Match the visual weight (border,
   color, padding, font-size, radius, height) so the dropdowns line
   up cleanly with the input on the left and the Apply button on
   the right. */
.assessments-filter select.ghost,
.trend-filter select.ghost {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text);
  font-family: inherit;
  font-weight: 500;
  font-size: .85em;
  padding: .35em .55em;
  border-radius: var(--radius-input);
  line-height: 1.2;
}
.assessments-filter select.ghost:hover,
.trend-filter select.ghost:hover {
  background: var(--panel-2);
  border-color: var(--muted);
}
/* Card headers were strict justify-content: space-between with no
   wrap, which on narrow viewports left the form overflowing past
   the h2. Allow the WHOLE form to drop below the heading when it
   doesn't fit, but keep the form's own children on one row. */
.card-header { flex-wrap: wrap; gap: .6em; }

/* ---- Sortable column headers (Assessments table) ------------------- */
/* Header cells become inline-block links so the arrow indicator and
   the label sit on the same baseline; hover lights up the muted
   arrow so the user can see which columns are clickable. */
table.sortable-table th .col-sort {
  color: var(--text);
  text-decoration: none;
  display: inline-flex;
  align-items: baseline;
  gap: .35em;
  white-space: nowrap;
}
table.sortable-table th .col-sort:hover {
  color: var(--accent);
}
table.sortable-table th .col-sort.active .sort-arrow {
  color: var(--accent);
}
table.sortable-table th .sort-arrow {
  font-size: .78em;
  line-height: 1;
}

/* ---- Pagination footer (Assessments table) ------------------------- */
.pagination {
  margin-top: .85em;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.pagination .pager {
  display: inline-flex; gap: .15em;
}
.pagination .pager a,
.pagination .pager .disabled {
  padding: .15em .55em;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 1em;
  text-decoration: none;
  color: var(--text);
  background: var(--panel-2);
}
.pagination .pager a:hover { border-color: var(--accent); color: var(--accent); }
.pagination .pager .disabled { opacity: .35; }

/* Markdown rendering for LLM-emitted finding description / remediation.
   Scoped to .markdown-body so it doesn't collide with the rest of the
   app, where <code> in flowing prose has different styling needs. The
   target audience is a security analyst reading a PoC — readability of
   curl/bash blocks and bullet lists is the priority. */
.markdown-body { line-height: 1.55; }
.markdown-body p { margin: 0 0 .7em; }
.markdown-body p:last-child { margin-bottom: 0; }
.markdown-body ul, .markdown-body ol { margin: .3em 0 .8em 1.4em; padding: 0; }
.markdown-body li { margin: .15em 0; }
.markdown-body h1, .markdown-body h2, .markdown-body h3,
.markdown-body h4, .markdown-body h5, .markdown-body h6 {
  margin: 1em 0 .35em;
  line-height: 1.25;
}
/* Inline code inside markdown bodies inherits the global code
   styling (above) plus a tiny vertical-padding nudge so it sits
   nicely on a line of prose. We don't re-declare bg/fg/border
   here so the dark/light parity holds across plain `code` and
   markdown-rendered code. */
.markdown-body code {
  padding: .12em .35em;
}
.markdown-body pre {
  margin: .5em 0 .9em;
  border-left: 3px solid var(--accent);
  font-size: .92em;
}
.markdown-body pre code {
  display: block;
  font-size: 1em;
}
.markdown-body blockquote {
  margin: .6em 0;
  padding: .3em .9em;
  color: var(--muted, #555);
  border-left: 3px solid var(--border, #d8dadd);
  background: transparent;
}
.markdown-body table { border-collapse: collapse; margin: .6em 0; }
.markdown-body th, .markdown-body td {
  border: 1px solid var(--border, #d8dadd);
  padding: .35em .6em;
  text-align: left;
}
.markdown-body th { background: var(--panel-2, #f4f5f7); }
